private void RenderJupiterShadow(IMapContext map, JupiterMoon moon) { Planet jupiter = planetsCalc.Planets.ElementAt(Planet.JUPITER - 1); float rotation = map.GetRotationTowardsNorth(jupiter.Equatorial) + 360 - (float)jupiter.Appearance.P; float diam = map.GetDiskSize(jupiter.Semidiameter); float diamEquat = diam; float diamPolar = (1 - jupiter.Flattening) * diam; // Jupiter radius, in pixels float sd = diam / 2; // Center of eclipsed moon PointF pMoon = map.Project(moon.Horizontal); // elipsed moon size, in pixels float szB = map.GetDiskSize(moon.Semidiameter); // Center of shadow PointF p = new PointF(-(float)moon.RectangularS.X * sd, (float)moon.RectangularS.Y * sd); map.Graphics.TranslateTransform(pMoon.X, pMoon.Y); map.Graphics.RotateTransform(rotation); var gpM = new GraphicsPath(); var gpU = new GraphicsPath(); gpU.AddEllipse(p.X - diamEquat / 2 - 1, p.Y - diamPolar / 2 - 1, diamEquat + 2, diamPolar + 2); gpM.AddEllipse(-szB / 2 - 0.5f, -szB / 2 - 0.5f, szB + 1, szB + 1); var regionU = new Region(gpU); regionU.Intersect(gpM); if (!regionU.IsEmpty(map.Graphics)) { map.Graphics.FillRegion(new SolidBrush(clrJupiterShadow), regionU); } map.Graphics.ResetTransform(); if (!regionU.IsEmpty(map.Graphics)) { map.DrawObjectCaption(fontShadowLabel, brushShadowLabel, Text.Get("EclipsedByJupiter"), pMoon, szB); } }
public virtual void Draw(IMapContext map, ISettings settings, DeepSky ds) { PointF p = map.Project(ds.Horizontal); float sizeA = GetDiameter(map, ds.SizeA); float sizeB = GetDiameter(map, ds.SizeB); // elliptic object with known size if (sizeB > 0 && sizeB != sizeA) { float diamA = GetDiameter(map, ds.SizeA); if (diamA > 10) { float diamB = GetDiameter(map, ds.SizeB); if (ds.Outline != null && settings.Get <bool>("DeepSkyOutlines")) { DrawOutline(map, ds.Outline); } else { float rotation = map.GetRotationTowardsNorth(ds.Equatorial) + 90 - ds.PA; map.Graphics.TranslateTransform(p.X, p.Y); map.Graphics.RotateTransform(rotation); DrawEllipticObject(map.Graphics, diamA, diamB); map.Graphics.ResetTransform(); } map.AddDrawnObject(ds); if (map.ViewAngle <= Renderer.limitLabels && settings.Get <bool>("DeepSkyLabels")) { var font = settings.Get <Font>("DeepSkyLabelsFont"); map.DrawObjectCaption(font, Renderer.brushCaption, ds.DisplayName, p, Math.Min(diamA, diamB)); } } } // round object else if (sizeA > 0) { float diamA = GetDiameter(map, ds.SizeA); if (diamA > 10) { if (ds.Outline != null && settings.Get <bool>("DeepSkyOutlines")) { DrawOutline(map, ds.Outline); } else { float rotation = map.GetRotationTowardsNorth(ds.Equatorial) + 90 - ds.PA; map.Graphics.TranslateTransform(p.X, p.Y); map.Graphics.RotateTransform(rotation); DrawRoundObject(map.Graphics, diamA); map.Graphics.ResetTransform(); } map.AddDrawnObject(ds); if (map.ViewAngle <= Renderer.limitLabels && settings.Get <bool>("DeepSkyLabels")) { var font = settings.Get <Font>("DeepSkyLabelsFont"); map.DrawObjectCaption(font, Renderer.brushCaption, ds.DisplayName, p, diamA); } } } // point object else { float size = map.GetPointSize(ds.Mag == null ? 15 : ds.Mag.Value); if ((int)size > 0) { if (ds.Outline != null && settings.Get <bool>("DeepSkyOutlines")) { DrawOutline(map, ds.Outline); } else { map.Graphics.TranslateTransform(p.X, p.Y); DrawPointObject(map.Graphics, size); map.Graphics.ResetTransform(); } map.AddDrawnObject(ds); if (map.ViewAngle <= Renderer.limitLabels && settings.Get <bool>("DeepSkyLabels")) { var font = settings.Get <Font>("DeepSkyLabelsFont"); map.DrawObjectCaption(font, Renderer.brushCaption, ds.DisplayName, p, 0); } } } }
public override void Render(IMapContext map) { var frames = settings.Get <List <FovFrame> >("FovFrames").Where(f => f.Enabled); foreach (var frame in frames) { if (frame is CircularFovFrame circularFrame) { float radius = circularFrame.Size * 3600 / 2; float size = map.GetDiskSize(radius); // do not draw frame if its size exceeds screen bounds if (size < Math.Sqrt(map.Width * map.Width + map.Height * map.Height)) { if (frame.Shading > 0 && circularFrame.Size >= map.ViewAngle / 2) { var circle = new GraphicsPath(); circle.AddEllipse(map.Width / 2 - size / 2, map.Height / 2 - size / 2, size, size); var shading = new Region(new RectangleF(0, 0, map.Width, map.Height)); shading.Exclude(circle); int transparency = (int)(frame.Shading / 100f * 255); var solidBrush = new SolidBrush(Color.FromArgb(transparency, map.GetSkyColor())); map.Graphics.FillRegion(solidBrush, shading); } map.Graphics.DrawEllipse(new Pen(frame.Color.GetColor(map.Schema, map.DayLightFactor)), map.Width / 2 - size / 2, map.Height / 2 - size / 2, size, size); float labelWidth = map.Graphics.MeasureString(frame.Label, font).Width; if (labelWidth <= size * 2) { map.Graphics.DrawString(frame.Label, font, new SolidBrush(frame.Color.GetColor(map.Schema, map.DayLightFactor)), new PointF(map.Width / 2, map.Height / 2 + size / 2), format); } } } else if (frame is CameraFovFrame cameraFrame) { float width = map.GetDiskSize(cameraFrame.Width * 3600); float height = map.GetDiskSize(cameraFrame.Height * 3600); // do not draw frame if its size exceeds screen bounds if (Math.Min(width, height) < Math.Sqrt(map.Width * map.Width + map.Height * map.Height)) { var eqCenter = map.Center.ToEquatorial(map.GeoLocation, map.SiderealTime); float angle = map.GetRotationTowardsNorth(eqCenter) + cameraFrame.Rotation; map.Graphics.TranslateTransform(map.Width / 2, map.Height / 2); map.Graphics.RotateTransform(angle); if (frame.Shading > 0 && cameraFrame.Height >= map.ViewAngle / 2) { var rect = new GraphicsPath(); rect.AddRectangle(new RectangleF(-width / 2, -height / 2, width, height)); var shading = new Region(new RectangleF(0, 0, map.Width, map.Height)); shading.Exclude(rect); int transparency = (int)(frame.Shading / 100f * 255); var solidBrush = new SolidBrush(Color.FromArgb(transparency, map.GetSkyColor())); map.Graphics.FillRegion(solidBrush, shading); } map.Graphics.DrawRectangle(new Pen(frame.Color.GetColor(map.Schema, map.DayLightFactor)), -width / 2, -height / 2, width, height); float labelWidth = map.Graphics.MeasureString(frame.Label, font).Width; if (labelWidth <= width * 2) { map.Graphics.DrawString(frame.Label, font, new SolidBrush(frame.Color.GetColor(map.Schema, map.DayLightFactor)), new PointF(0, height / 2), format); } map.Graphics.ResetTransform(); } } } }
private void RenderJupiterMoonShadow(IMapContext map, SizeableCelestialObject eclipsedBody, CrdsRectangular rect = null) { if (rect == null) { rect = new CrdsRectangular(); } // collect moons than can produce a shadow var ecliptingMoons = planetsCalc.JupiterMoons.Where(m => m.RectangularS.Z < rect.Z); if (ecliptingMoons.Any()) { Planet jupiter = planetsCalc.Planets.ElementAt(Planet.JUPITER - 1); float rotation = map.GetRotationTowardsNorth(jupiter.Equatorial) + 360 - (float)jupiter.Appearance.P; // Jupiter radius, in pixels float sd = map.GetDiskSize(jupiter.Semidiameter) / 2; // Center of eclipsed body PointF pBody = map.Project(eclipsedBody.Horizontal); // elipsed body size, in pixels float szB = map.GetDiskSize(eclipsedBody.Semidiameter); foreach (var moon in ecliptingMoons) { // umbra and penumbra radii, in acrseconds var shadow = GalileanMoons.Shadow(jupiter.Ecliptical.Distance, jupiter.DistanceFromSun, moon.Number - 1, moon.RectangularS, rect); // umbra and penumbra size, in pixels float szU = map.GetDiskSize(shadow.Umbra); float szP = map.GetDiskSize(shadow.Penumbra); // coordinates of shadow relative to eclipsed body CrdsRectangular shadowRelative = moon.RectangularS - rect; // Center of shadow PointF p = new PointF((float)shadowRelative.X * sd, -(float)shadowRelative.Y * sd); map.Graphics.TranslateTransform(pBody.X, pBody.Y); map.Graphics.RotateTransform(rotation); // shadow has enough size to be rendered if ((int)szP > 0) { var gpB = new GraphicsPath(); var gpP = new GraphicsPath(); var gpU = new GraphicsPath(); gpU.AddEllipse(p.X - szU / 2, p.Y - szU / 2, szU, szU); gpP.AddEllipse(p.X - szP / 2, p.Y - szP / 2, szP, szP); gpB.AddEllipse(-szB / 2 - 0.5f, -szB / 2 - 0.5f, szB + 1, szB + 1); var regionP = new Region(gpP); regionP.Intersect(gpB); if (!regionP.IsEmpty(map.Graphics)) { float f1 = 1 - (szU + szP) / 2 / szP; float f2 = 1 - szU / szP; var brushP = new PathGradientBrush(gpP); brushP.CenterPoint = p; brushP.CenterColor = clrJupiterMoonShadowLight; brushP.InterpolationColors = new ColorBlend() { Colors = new[] { Color.Transparent, clrJupiterMoonShadowDark, clrJupiterMoonShadowLight, clrJupiterMoonShadowLight }, Positions = new float[] { 0, f1, f2, 1 } }; var regionU = new Region(gpU); regionU.Intersect(gpB); var brushU = new SolidBrush(clrJupiterMoonShadowLight); map.Graphics.FillRegion(brushP, regionP); map.Graphics.FillRegion(brushU, regionU); // outline circles if (settings.Get <bool>("JupiterMoonsShadowOutline") && szP > 20) { map.Graphics.DrawEllipse(penShadowOutline, p.X - (szP + szU) / 4, p.Y - (szP + szU) / 4, (szP + szU) / 2, (szP + szU) / 2); map.Graphics.DrawEllipse(penShadowOutline, p.X - szU / 2, p.Y - szU / 2, szU, szU); PointF[] points = new PointF[] { new PointF(p.X, p.Y) }; map.Graphics.TransformPoints(CoordinateSpace.Page, CoordinateSpace.World, points); map.Graphics.ResetTransform(); map.DrawObjectCaption(fontShadowLabel, brushShadowLabel, moon.ShadowName, points[0], szP); } } } map.Graphics.ResetTransform(); } } }
private void RenderJupiterMoons(IMapContext map, Planet jupiter, IEnumerable <JupiterMoon> moons) { bool isGround = settings.Get <bool>("Ground"); bool useTextures = settings.Get <bool>("UseTextures"); double coeff = map.DiagonalCoefficient(); foreach (var moon in moons) { double ad = Angle.Separation(moon.Horizontal, map.Center); if ((!isGround || moon.Horizontal.Altitude + moon.Semidiameter / 3600 > 0) && ad < coeff * map.ViewAngle + moon.Semidiameter / 3600) { PointF p = map.Project(moon.Horizontal); PointF pJupiter = map.Project(jupiter.Horizontal); float size = map.GetPointSize(moon.Magnitude, 2); float diam = map.GetDiskSize(moon.Semidiameter); // diameter is to small to render moon disk, // but point size caclulated from magnitude is enough to be drawn if (size > diam && (int)size > 0) { // do not draw moon point if eclipsed if (!moon.IsEclipsedByJupiter) { // satellite is distant enough from the Jupiter // but too small to be drawn as disk if (map.DistanceBetweenPoints(p, pJupiter) >= 5) { map.Graphics.TranslateTransform(p.X, p.Y); map.Graphics.FillEllipse(new SolidBrush(map.GetColor(Color.Wheat)), -size / 2, -size / 2, size, size); map.Graphics.ResetTransform(); map.DrawObjectCaption(fontLabel, brushLabel, moon.Name, p, 2); map.AddDrawnObject(moon); } } } // moon should be rendered as disk else if (diam >= size && (int)diam > 0) { float rotation = map.GetRotationTowardsNorth(jupiter.Equatorial) + 360 - (float)jupiter.Appearance.P; map.Graphics.TranslateTransform(p.X, p.Y); map.Graphics.RotateTransform(rotation); if (useTextures) { Image texture = imagesCache.RequestImage($"5-{moon.Number}", new PlanetTextureToken($"5-{moon.Number}", moon.CM, jupiter.Appearance.D), PlanetTextureProvider, map.Redraw); if (texture != null) { map.DrawImage(texture, -diam / 2 * 1.01f, -diam / 2 * 1.01f, diam * 1.01f, diam * 1.01f); DrawVolume(map, diam, 0); } else { map.Graphics.FillEllipse(new SolidBrush(map.GetColor(Color.Wheat)), -diam / 2, -diam / 2, diam, diam); } } else { map.Graphics.FillEllipse(new SolidBrush(map.GetColor(Color.Wheat)), -diam / 2, -diam / 2, diam, diam); if (diam > 2) { map.Graphics.DrawEllipse(new Pen(map.GetSkyColor()), -diam / 2, -diam / 2, diam, diam); } } map.Graphics.ResetTransform(); // render another moon shadows on the moon RenderJupiterMoonShadow(map, moon, moon.RectangularS); // render Jupiter shadow on the moon if (moon.IsEclipsedByJupiter) { RenderJupiterShadow(map, moon); } map.DrawObjectCaption(fontLabel, brushLabel, moon.Name, p, diam); map.AddDrawnObject(moon); } } } }
private void RenderPlanet(IMapContext map, Planet planet) { if (!settings.Get <bool>("Planets")) { return; } if (planet.Number == Planet.JUPITER) { // render moons behind Jupiter var moons = planetsCalc.JupiterMoons.Where(m => m.Rectangular.Z >= 0).OrderByDescending(m => m.Rectangular.Z); RenderJupiterMoons(map, planet, moons); } Graphics g = map.Graphics; double ad = Angle.Separation(planet.Horizontal, map.Center); bool isGround = settings.Get <bool>("Ground"); bool useTextures = settings.Get <bool>("UseTextures"); double coeff = map.DiagonalCoefficient(); if ((!isGround || planet.Horizontal.Altitude + planet.Semidiameter / 3600 > 0) && ad < coeff * map.ViewAngle + planet.Semidiameter / 3600) { float size = map.GetPointSize(planet.Magnitude, maxDrawingSize: 7); float diam = map.GetDiskSize(planet.Semidiameter); // diameter is to small to render as planet disk, // but point size caclulated from magnitude is enough to be drawn if (size > diam && (int)size > 0) { PointF p = map.Project(planet.Horizontal); g.FillEllipse(GetPlanetColor(map, planet.Number), p.X - size / 2, p.Y - size / 2, size, size); map.DrawObjectCaption(fontLabel, brushLabel, planet.Name, p, size); map.AddDrawnObject(planet); } // planet should be rendered as disk else if (diam >= size && (int)diam > 0) { PointF p = map.Project(planet.Horizontal); float rotation = map.GetRotationTowardsNorth(planet.Equatorial) + 360 - (float)planet.Appearance.P; g.TranslateTransform(p.X, p.Y); g.RotateTransform(rotation); DrawRotationAxis(g, diam); if (planet.Number == Planet.SATURN) { var rings = planetsCalc.SaturnRings; double maxSize = Math.Max(map.Width, map.Height); // scale value to convert visible size of ring to screen pixels double scale = 1.0 / 3600 / map.ViewAngle * maxSize / 4; // draw rings by halfs arcs, first half is farther one for (int half = 0; half < 2; half++) { // draw planets textures if (useTextures) { float a = (float)(rings.GetRingSize(0, RingEdge.Outer, RingAxis.Major) * scale); float b = (float)(rings.GetRingSize(0, RingEdge.Outer, RingAxis.Minor) * scale); // half of source image: 0 = top, 1 = bottom int h = (half + (rings.B > 0 ? 0 : 1)) % 2; Image textureRings = imagesCache.RequestImage("Rings", true, t => Image.FromFile("Data\\Rings.png", true), map.Redraw); if (textureRings != null) { map.DrawImage(textureRings, // destination rectangle new RectangleF(-a, -b + h * b, a * 2, b), // source rectangle new RectangleF(0, h * textureRings.Height / 2f, textureRings.Width, textureRings.Height / 2f)); } else { DrawRingsUntextured(g, rings, half, scale); } } // do not use textures else { DrawRingsUntextured(g, rings, half, scale); } // draw planet disk after first half of rings if (half == 0) { DrawPlanetGlobe(map, planet, diam); } } } else { DrawPlanetGlobe(map, planet, diam); } g.ResetTransform(); if (planet.Number <= Planet.MARS) { float phase = (float)planet.Phase * Math.Sign(planet.Elongation); GraphicsPath shadow = GetPhaseShadow(phase, diam + 1, planet.Flattening); // rotation of phase image rotation = map.GetRotationTowardsEclipticPole(planet.Ecliptical); g.TranslateTransform(p.X, p.Y); g.RotateTransform(rotation); g.FillPath(GetShadowBrush(map), shadow); g.ResetTransform(); } map.DrawObjectCaption(fontLabel, brushLabel, planet.Name, p, diam); map.AddDrawnObject(planet); if (planet.Number == Planet.JUPITER) { // render shadows on Jupiter RenderJupiterMoonShadow(map, planet); } } } // render moons over Jupiter if (planet.Number == Planet.JUPITER) { var moons = planetsCalc.JupiterMoons.Where(m => m.Rectangular.Z < 0).OrderByDescending(m => m.Rectangular.Z); RenderJupiterMoons(map, planet, moons); } }
private void RenderMoon(IMapContext map) { if (!settings.Get <bool>("Moon")) { return; } bool isGround = settings.Get <bool>("Ground"); bool useTextures = settings.Get <bool>("MoonTexture"); double ad = Angle.Separation(moon.Horizontal, map.Center); double coeff = map.DiagonalCoefficient(); if ((!isGround || moon.Horizontal.Altitude + moon.Semidiameter / 3600 > 0) && ad < coeff * map.ViewAngle + moon.Semidiameter / 3600.0) { PointF p = map.Project(moon.Horizontal); double inc = map.GetRotationTowardsNorth(moon.Equatorial); // final rotation of drawn image // axis rotation is negated because measured counter-clockwise float axisRotation = (float)(inc - moon.PAaxis); map.Graphics.TranslateTransform(p.X, p.Y); map.Graphics.RotateTransform(axisRotation); // drawing size float size = map.GetDiskSize(moon.Semidiameter, 10); SolidBrush brushMoon = new SolidBrush(map.GetColor(Color.Gray)); if (useTextures && size > 10) { Image textureMoon = imagesCache.RequestImage("Moon", new PlanetTextureToken("Moon", moon.Libration.l, moon.Libration.b), MoonTextureProvider, map.Redraw); if (textureMoon != null) { map.Graphics.FillEllipse(brushMoon, -size / 2, -size / 2, size, size); map.DrawImage(textureMoon, -size / 2, -size / 2, size, size); } else { map.Graphics.FillEllipse(brushMoon, -size / 2, -size / 2, size, size); } } else { // Moon disk map.Graphics.FillEllipse(brushMoon, -size / 2, -size / 2, size, size); } map.Graphics.ResetTransform(); float phase = (float)moon.Phase * Math.Sign(moon.Elongation); float rotation = map.GetRotationTowardsEclipticPole(moon.Ecliptical0); GraphicsPath shadow = GetPhaseShadow(phase, size + 1); // shadowed part of disk map.Graphics.TranslateTransform(p.X, p.Y); map.Graphics.RotateTransform(rotation); map.Graphics.FillPath(GetShadowBrush(map), shadow); map.Graphics.ResetTransform(); if (settings.Get <bool>("MoonLabel")) { map.DrawObjectCaption(fontLabel, brushLabel, moon.Name, p, size); } map.AddDrawnObject(moon); } }
private void RenderSun(IMapContext map) { if (!settings.Get <bool>("Sun")) { return; } bool isGround = settings.Get <bool>("Ground"); bool useTextures = settings.Get <bool>("SunTexture"); double ad = Angle.Separation(sun.Horizontal, map.Center); double coeff = map.DiagonalCoefficient(); Color colorSun = map.GetColor(clrSunNight, clrSunDaylight); if ((!isGround || sun.Horizontal.Altitude + sun.Semidiameter / 3600 > 0) && ad < coeff * map.ViewAngle + sun.Semidiameter / 3600) { PointF p = map.Project(sun.Horizontal); float inc = map.GetRotationTowardsNorth(sun.Equatorial); map.Graphics.TranslateTransform(p.X, p.Y); map.Graphics.RotateTransform(inc); float size = map.GetDiskSize(sun.Semidiameter, 10); if (map.Schema == ColorSchema.Night && useTextures && size > 10) { Date date = new Date(map.JulianDay); DateTime dt = new DateTime(date.Year, date.Month, (int)date.Day, 0, 0, 0, DateTimeKind.Utc); Brush brushSun = new SolidBrush(clrSunNight); Image imageSun = imagesCache.RequestImage("Sun", dt, SunImageProvider, map.Redraw); map.Graphics.FillEllipse(brushSun, -size / 2, -size / 2, size, size); if (imageSun != null) { map.Graphics.DrawImage(imageSun, -size / 2, -size / 2, size, size); } } else { if (map.Schema == ColorSchema.White) { map.Graphics.FillEllipse(Brushes.White, -size / 2, -size / 2, size, size); map.Graphics.DrawEllipse(Pens.Black, -size / 2, -size / 2, size, size); } else { Brush brushSun = new SolidBrush(colorSun); map.Graphics.FillEllipse(brushSun, -size / 2, -size / 2, size, size); } } map.Graphics.ResetTransform(); if (settings.Get <bool>("SunLabel")) { map.DrawObjectCaption(fontLabel, brushLabel, sun.Name, p, size); } map.AddDrawnObject(sun); } }