/// <summary> /// Does the rendering logic /// </summary> /// <param name="map">Map instance</param> public override void Render(IMapContext map) { if (IsMeasureToolOn && map.MousePosition != null) { double coeff = map.DiagonalCoefficient(); List <PointF> points = new List <PointF>(); for (int f = 0; f <= 10; f++) { CrdsHorizontal h = Angle.Intermediate(map.MousePosition, MeasureOrigin, f / 10.0); points.Add(map.Project(h)); if (Angle.Separation(h, map.Center) > map.ViewAngle * coeff) { break; } } if (points.Count > 1) { map.Graphics.DrawCurve(new Pen(map.GetColor(Color.White)), points.ToArray()); double angle = Angle.Separation(map.MousePosition, MeasureOrigin); PointF p = map.Project(map.MousePosition); map.Graphics.DrawString(Formatters.MeasuredAngle.Format(angle), fontAngleValue, new SolidBrush(map.GetColor(Color.White)), p.X + 5, p.Y + 5); } } }
/// <summary> /// Renders constellation borders on the map /// </summary> private void RenderBorders(IMapContext map) { PointF p1, p2; CrdsHorizontal h1, h2; var borders = constellationsCalc.ConstBorders; bool isGround = settings.Get <bool>("Ground"); double coeff = map.DiagonalCoefficient(); Pen penBorder = new Pen(map.GetColor("ColorConstBorders")); foreach (var block in borders) { for (int i = 0; i < block.Count - 1; i++) { h1 = block.ElementAt(i).Horizontal; h2 = block.ElementAt(i + 1).Horizontal; if ((!isGround || h1.Altitude >= 0 || h2.Altitude >= 0) && Angle.Separation(map.Center, h1) < 90 * coeff && Angle.Separation(map.Center, h2) < 90 * coeff) { p1 = map.Project(h1); p2 = map.Project(h2); var points = map.SegmentScreenIntersection(p1, p2); if (points.Length == 2) { map.Graphics.DrawLine(penBorder, points[0], points[1]); } } } } }
public override void Render(IMapContext map) { Graphics g = map.Graphics; bool isGround = settings.Get <bool>("Ground"); bool showNovae = settings.Get("Stars") && settings.Get <bool>("Novae"); if (!showNovae) { return; } var novae = calc.Novae.Where(m => Angle.Separation(map.Center, m.Horizontal) < map.ViewAngle); if (isGround) { novae = novae.Where(m => m.Horizontal.Altitude >= 0); } var font = SystemFonts.DefaultFont; var brush = new SolidBrush(map.Schema == ColorSchema.White ? Color.Black : Color.White); foreach (var star in novae) { float diam = map.GetPointSize(star.Mag); if ((int)diam > 0) { PointF p = map.Project(star.Horizontal); if (!map.IsOutOfScreen(p)) { if (map.Schema == ColorSchema.White) { g.FillEllipse(Brushes.White, p.X - diam / 2 - 1, p.Y - diam / 2 - 1, diam + 2, diam + 2); } g.FillEllipse(brush, p.X - diam / 2, p.Y - diam / 2, diam, diam); map.AddDrawnObject(star); } } } if (settings.Get <bool>("StarsLabels") && settings.Get <bool>("NovaeLabels") && map.ViewAngle <= limitAllNames) { brushStarNames = new SolidBrush(map.GetColor("ColorStarsLabels")); foreach (var nova in novae) { float diam = map.GetPointSize(nova.Mag); if ((int)diam > 0) { PointF p = map.Project(nova.Horizontal); if (!map.IsOutOfScreen(p)) { DrawStarName(map, p, nova, diam); } } } } }
/// <summary> /// Gets drawing rotation of image, measured clockwise from /// a point oriented to top of the screen towards North ecliptic pole point /// </summary> /// <param name="ecl">Ecliptical coordinates of a central point of a body.</param> /// <returns></returns> public static float GetRotationTowardsEclipticPole(this IMapContext map, CrdsEcliptical ecl) { // Coordinates of center of a body (image) to be rotated PointF p = map.Project(ecl.ToEquatorial(map.Epsilon).ToHorizontal(map.GeoLocation, map.SiderealTime)); // Point directed to North ecliptic pole PointF pNorth = map.Project((ecl + new CrdsEcliptical(0, 1)).ToEquatorial(map.Epsilon).ToHorizontal(map.GeoLocation, map.SiderealTime)); // Clockwise rotation return(LineInclinationY(p, pNorth)); }
/// <summary> /// Gets drawing rotation of image, measured clockwise from /// a point oriented to top of the screen towards North celestial pole point /// </summary> /// <param name="eq">Equatorial coordinates of a central point of a body.</param> /// <returns></returns> public static float GetRotationTowardsNorth(this IMapContext map, CrdsEquatorial eq) { // Coordinates of center of a body (image) to be rotated PointF p = map.Project(eq.ToHorizontal(map.GeoLocation, map.SiderealTime)); // Point directed to North celestial pole PointF pNorth = map.Project((eq + new CrdsEquatorial(0, 1)).ToHorizontal(map.GeoLocation, map.SiderealTime)); // Clockwise rotation return(LineInclinationY(p, pNorth)); }
private void DrawLabels(IMapContext map, Track track) { var brushLabel = new SolidBrush(track.Color); double trackStep = track.Step; double stepLabels = track.LabelsStep.TotalDays; double coeff = map.DiagonalCoefficient(); int each = (int)(stepLabels / trackStep); double jd = track.From; for (int i = 0; i < track.Points.Count; i++) { if (i % each == 0 || i == track.Points.Count - 1) { var tp = track.Points[i]; double ad = Angle.Separation(tp.Horizontal, map.Center); if (ad < map.ViewAngle * coeff) { PointF p = map.Project(tp.Horizontal); if (!map.IsOutOfScreen(p)) { map.Graphics.FillEllipse(brushLabel, p.X - 2, p.Y - 2, 4, 4); map.DrawObjectCaption(fontLabel, brushLabel, Formatters.DateTime.Format(new Date(jd, map.GeoLocation.UtcOffset)), p, 4); } } } jd += trackStep; } }
public static float Rotate(this IMapContext map, PointF p, CrdsEquatorial eq, double PA) { // Point directed to North celestial pole PointF pNorth = map.Project((eq + new CrdsEquatorial(0, 1)).ToHorizontal(map.GeoLocation, map.SiderealTime)); // Clockwise rotation float inc = LineInclinationY(p, pNorth); if (map.IsInverted) { inc = -90 - inc; } float rotation = (float)(inc - (map.IsMirrored ? -1 : 1) * PA); if (map.IsInverted) { rotation = 90 - rotation; } map.Graphics.TranslateTransform(p.X, p.Y); map.Graphics.RotateTransform(rotation); return(rotation); }
private void DrawHalo(IMapContext map) { int size = (int)(map.DayLightFactor * 100); float sunSize = map.GetDiskSize(sun.Semidiameter); int alpha = (int)(map.DayLightFactor * (1 - sunSize / (2 * size)) * 255); if (settings.Get <bool>("Ground") && size > 0 && alpha > 0 && 2 * size > sunSize) { bool isEclipse = sun.Horizontal.Altitude > 0 && map.DayLightFactor < 1; using (var halo = new GraphicsPath()) { PointF p = map.Project(sun.Horizontal); halo.AddEllipse(p.X - size, p.Y - size, 2 * size, 2 * size); Region reg = new Region(halo); using (GraphicsPath gpMoon = new GraphicsPath()) { if (isEclipse) { PointF pMoon = map.Project(moon.Horizontal); float szMoon = map.GetDiskSize(moon.Semidiameter, 10) / 2; gpMoon.AddEllipse(pMoon.X - szMoon, pMoon.Y - szMoon, 2 * szMoon, 2 * szMoon); reg.Exclude(gpMoon); } var brush = new PathGradientBrush(halo); brush.CenterPoint = p; brush.CenterColor = Color.FromArgb(alpha, clrSunDaylight); brush.SurroundColors = new Color[] { Color.Transparent }; map.Graphics.FillRegion(brush, reg); if (isEclipse) { map.Graphics.FillPath(new SolidBrush(Color.FromArgb((int)(alpha * map.DayLightFactor), brush.CenterColor)), gpMoon); } } } } }
protected virtual GraphicsPath DrawOutline(IMapContext map, ICollection <CelestialPoint> outline) { using (GraphicsPath gp = new GraphicsPath(FillMode.Winding)) { for (int i = 0; i < outline.Count - 1; i++) { var h1 = outline.ElementAt(i).Horizontal; var h2 = outline.ElementAt(i + 1).Horizontal; PointF p1, p2; p1 = map.Project(h1); p2 = map.Project(h2); gp.AddLine(p1, p2); } map.Graphics.DrawPath(Renderer.penOutlineSolid, gp); return(gp); } }
public override void Render(IMapContext map) { Graphics g = map.Graphics; bool isGround = settings.Get <bool>("Ground"); bool isLabels = settings.Get <bool>("StarsLabels"); Brush brushNames = new SolidBrush(map.GetColor("ColorStarsLabels")); if (map.MagLimit > 8 && settings.Get <bool>("Stars") && settings.Get <bool>("Tycho2")) { Brush brushStar = GetColor(map); PrecessionalElements pe = Precession.ElementsFK5(map.JulianDay, Date.EPOCH_J2000); var eq0 = map.Center.ToEquatorial(map.GeoLocation, map.SiderealTime); CrdsEquatorial eq = Precession.GetEquatorialCoordinates(eq0, pe); SkyContext context = new SkyContext(map.JulianDay, map.GeoLocation); tycho2.LockedStar = map.LockedObject as Tycho2Star; tycho2.SelectedStar = map.SelectedObject as Tycho2Star; var stars = tycho2.GetStars(context, eq, map.ViewAngle, m => MagFilter(map, m)); foreach (var star in stars) { if (!isGround || star.Horizontal.Altitude > 0) { PointF p = map.Project(star.Horizontal); if (!map.IsOutOfScreen(p)) { float size = map.GetPointSize(star.Magnitude); if (map.Schema == ColorSchema.White) { g.FillEllipse(Brushes.White, p.X - size / 2 - 1, p.Y - size / 2 - 1, size + 2, size + 2); } g.FillEllipse(brushStar, p.X - size / 2, p.Y - size / 2, size, size); if (isLabels && map.ViewAngle < 1 && size > 3) { map.DrawObjectCaption(fontNames, brushNames, star.ToString(), p, size); } map.AddDrawnObject(star); } } } } }
private void DrawHorizontalPoles(IMapContext map) { if (settings.Get <bool>("LabelHorizontalPoles")) { for (int i = 0; i < 2; i++) { if (Angle.Separation(horizontalPoles[i], map.Center) < map.ViewAngle) { PointF p = map.Project(horizontalPoles[i]); map.Graphics.DrawXCross(penGridHorizontal, p, 3); map.Graphics.DrawString(horizontalLabels[i], SystemFonts.DefaultFont, penGridHorizontal.Brush, p.X + 5, p.Y + 5); } } } }
public override void Render(IMapContext map) { Graphics g = map.Graphics; bool isGround = settings.Get <bool>("Ground"); bool showMeteors = settings.Get("Meteors"); bool onlyActive = settings.Get("MeteorsOnlyActive"); bool showLabels = settings.Get("MeteorsLabels"); int activityClassLimit = 4; if (!showMeteors) { return; } var meteors = calc.GetCelestialObjects().Where(m => Angle.Separation(map.Center, m.Horizontal) < map.ViewAngle); if (isGround) { meteors = meteors.Where(m => m.Horizontal.Altitude >= 0); } if (onlyActive) { meteors = meteors.Where(m => m.IsActive); } meteors = meteors.Where(m => m.ActivityClass <= activityClassLimit); var color = map.GetColor("ColorMeteors"); var pen = new Pen(color); var brush = new SolidBrush(color); var font = settings.Get <Font>("MeteorsLabelsFont"); foreach (var meteor in meteors) { PointF p = map.Project(meteor.Horizontal); if (!map.IsOutOfScreen(p)) { g.DrawXCross(pen, p, 5); map.AddDrawnObject(meteor); if (showLabels) { map.DrawObjectCaption(font, brush, meteor.Name, p, 10); } } } }
private void DrawEquatorialPoles(IMapContext map) { if (settings.Get <bool>("LabelEquatorialPoles")) { double coeff = map.DiagonalCoefficient(); for (int i = 0; i < 2; i++) { var h = GridEquatorial.ToHorizontal(polePoints[i], map); if (Angle.Separation(h, map.Center) < map.ViewAngle * coeff) { PointF p = map.Project(h); map.Graphics.DrawXCross(penGridEquatorial, p, 3); map.Graphics.DrawString(equatorialLabels[i], SystemFonts.DefaultFont, penGridEquatorial.Brush, p.X + 5, p.Y + 5); } } } }
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); } }
/// <summary> /// Renders constellations labels on the map /// </summary> private void RenderConstLabels(IMapContext map) { var constellations = constellationsCalc.ConstLabels; bool isGround = settings.Get <bool>("Ground"); double coeff = map.DiagonalCoefficient(); StringFormat format = new StringFormat(); format.LineAlignment = StringAlignment.Center; format.Alignment = StringAlignment.Center; int fontSize = Math.Min((int)(800 / map.ViewAngle), 32); Font font = new Font(FontFamily.GenericSansSerif, fontSize); LabelType labelType = settings.Get <LabelType>("ConstLabelsType"); Brush brushLabel = new SolidBrush(map.GetColor("ColorConstLabels")); foreach (var c in constellations) { var h = c.Horizontal; if ((!isGround || h.Altitude > 0) && Angle.Separation(map.Center, h) < map.ViewAngle * coeff) { var p = map.Project(h); var constellation = GetConstellation(c.Code); string label; switch (labelType) { case LabelType.InternationalCode: label = constellation.Code; break; case LabelType.LocalName: label = constellation.LocalName; break; case LabelType.InternationalName: default: label = constellation.LatinName; break; } map.Graphics.DrawString(label, font, brushLabel, p, format); } } }
private void DrawEquinoxLabels(IMapContext map) { if (settings.Get <bool>("LabelEquinoxPoints")) { for (int i = 0; i < 2; i++) { var h = LineEcliptic.ToHorizontal(LineEcliptic.Column(equinoxRA[i]).ElementAt(0), map); if (Angle.Separation(h, map.Center) < map.ViewAngle) { PointF p = map.Project(h); var hint = map.Graphics.TextRenderingHint; map.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias; map.Graphics.DrawStringOpaque(equinoxLabels[i], fontEquinoxLabel, penLineEcliptic.Brush, new SolidBrush(map.GetSkyColor()), p); map.Graphics.TextRenderingHint = hint; } } } }
public override void Render(IMapContext map) { if (settings.Get <bool>("MilkyWay")) { int alpha = Math.Min((int)(k * map.ViewAngle + b), 255); if (alpha > maxAlpha) { var smoothing = map.Graphics.SmoothingMode; map.Graphics.SmoothingMode = SmoothingMode.None; if (map.Schema == ColorSchema.Day) { alpha = (int)(alpha * (1 - map.DayLightFactor)); } for (int i = 0; i < milkyWayCalc.MilkyWay.Count(); i++) { var points = new List <PointF>(); for (int j = 0; j < milkyWayCalc.MilkyWay[i].Count; j++) { var h = milkyWayCalc.MilkyWay[i][j].Horizontal; double ad = Angle.Separation(h, map.Center); // 130 degrees value limit has been chosen experimentally if (ad < 130) { points.Add(map.Project(h)); } } if (points.Count >= 3) { Color color = Color.FromArgb(alpha, map.GetColor("ColorMilkyWay")); map.Graphics.FillPolygon(new SolidBrush(color), points.ToArray(), FillMode.Winding); } } map.Graphics.SmoothingMode = smoothing; } } }
private void DrawEquinoxLabels(IMapContext map) { if (settings.Get <bool>("LabelEquinoxPoints")) { double coeff = map.DiagonalCoefficient(); for (int i = 0; i < 2; i++) { var h = LineEcliptic.ToHorizontal(LineEcliptic.Column(equinoxRA[i]).ElementAt(0), map); if (Angle.Separation(h, map.Center) < map.ViewAngle * coeff) { PointF p = map.Project(h); var hint = map.Graphics.TextRenderingHint; map.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias; map.Graphics.DrawStringOpaque(equinoxLabels[i], fontEquinoxLabel, penLineEcliptic.Brush, Brushes.Black, p); map.Graphics.TextRenderingHint = hint; } } } }
public override void Render(IMapContext map) { if (ascom.IsConnected) { try { var hor = ascom.Position.ToHorizontal(map.GeoLocation, map.SiderealTime); var p = map.Project(hor); var color = map.GetColor("TelescopeMarkerColor"); Pen marker = new Pen(color, 2); marker.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; float r = 16; float a0 = (float)(Math.PI / 4); for (double a = 0; a < 2 * Math.PI; a += Math.PI / 2) { float x0 = p.X + (r / 2) * (float)Math.Cos(a + a0); float y0 = p.Y + (r / 2) * (float)Math.Sin(a + a0); float x1 = p.X + r * (float)Math.Cos(a + a0); float y1 = p.Y + r * (float)Math.Sin(a + a0); map.Graphics.DrawLine(marker, new PointF(x0, y0), new PointF(x1, y1)); } map.Graphics.DrawEllipse(marker, p.X - 16, p.Y - 16, 32, 32); if (settings.Get("TelescopeMarkerLabel")) { var font = settings.Get <Font>("TelescopeMarkerFont"); var brush = new SolidBrush(map.GetColor("TelescopeMarkerColor")); map.Graphics.DrawString(ascom.TelescopeName, font, brush, new PointF(p.X + 16 * 0.8f, p.Y + 16 * 0.8f)); } } catch (Exception ex) { Trace.TraceError($"Rendering error in {nameof(TelescopeRenderer)}: {ex}"); } } }
public static void Rotate(this IMapContext map, PointF p, CrdsEcliptical ecl) { // Point directed to North ecliptic pole PointF pNorth = map.Project((ecl + new CrdsEcliptical(0, 1)).ToEquatorial(map.Epsilon).ToHorizontal(map.GeoLocation, map.SiderealTime)); // Clockwise rotation float inc = LineInclinationY(p, pNorth); if (map.IsInverted) { inc = -90 - inc; } float rotation = (float)inc; if (map.IsInverted) { rotation = 90 - rotation; } map.Graphics.TranslateTransform(p.X, p.Y); map.Graphics.RotateTransform(rotation); }
private void DrawLunarNodes(IMapContext map) { if (settings.Get <bool>("LabelLunarNodes")) { double ascNode = LunarEphem.TrueAscendingNode(map.JulianDay); for (int i = 0; i < 2; i++) { var h = LineEcliptic.ToHorizontal(new GridPoint(ascNode + (i > 0 ? 180 : 0), 0), map); if (Angle.Separation(h, map.Center) < map.ViewAngle) { PointF p = map.Project(h); var hint = map.Graphics.TextRenderingHint; map.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias; map.Graphics.FillEllipse(penLineEcliptic.Brush, p.X - 1.5f, p.Y - 1.5f, 3, 3); map.Graphics.DrawStringOpaque(nodesLabels[i], fontNodeLabel, penLineEcliptic.Brush, new SolidBrush(map.GetSkyColor()), p); map.Graphics.TextRenderingHint = hint; } } } }
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); } } } }
public override void Render(IMapContext map) { Graphics g = map.Graphics; var allComets = cometsCalc.Comets; bool isGround = settings.Get("Ground"); bool useTextures = settings.Get("PlanetsTextures"); bool drawComets = settings.Get("Comets"); bool drawLabels = settings.Get("AsteroidsLabels"); Brush brushNames = new SolidBrush(map.GetColor("ColorCometsLabels")); if (drawComets) { var comets = allComets.Where(a => Angle.Separation(map.Center, a.Horizontal) < map.ViewAngle); foreach (var c in comets) { float diam = map.GetDiskSize(c.Semidiameter); if (diam > 5) { double ad = Angle.Separation(c.Horizontal, map.Center); if ((!isGround || c.Horizontal.Altitude + c.Semidiameter / 3600 > 0) && ad < map.ViewAngle + c.Semidiameter / 3600) { PointF p = map.Project(c.Horizontal); PointF t = map.Project(c.TailHorizontal); double tail = map.DistanceBetweenPoints(p, t); if (diam > 5 || tail > 10) { using (var gpComet = new GraphicsPath()) { double rotation = Math.Atan2(t.Y - p.Y, t.X - p.X) + Math.PI / 2; gpComet.StartFigure(); // tail is long enough if (tail > diam) { gpComet.AddArc(p.X - diam / 2, p.Y - diam / 2, diam, diam, (float)Angle.ToDegrees(rotation), 180); gpComet.AddLines(new PointF[] { gpComet.PathPoints[gpComet.PathPoints.Length - 1], t, gpComet.PathPoints[0] }); } // draw coma only else { gpComet.AddEllipse(p.X - diam / 2, p.Y - diam / 2, diam, diam); } gpComet.CloseAllFigures(); using (var brushComet = new PathGradientBrush(gpComet)) { brushComet.CenterPoint = p; int alpha = 100; if (c.Magnitude >= map.MagLimit) { alpha -= (int)(100 * (c.Magnitude - map.MagLimit) / c.Magnitude); } brushComet.CenterColor = map.GetColor(Color.FromArgb(alpha, colorComet)); brushComet.SurroundColors = gpComet.PathPoints.Select(pp => Color.Transparent).ToArray(); g.FillPath(brushComet, gpComet); } } if (drawLabels) { var font = settings.Get <Font>("CometsLabelsFont"); map.DrawObjectCaption(font, brushNames, c.Name, p, diam); } map.AddDrawnObject(c); } } } } } }
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); } } } }
private void RenderEarthShadow(IMapContext map) { // here and below suffixes meanings are: "M" = Moon, "P" = penumbra, "U" = umbra // angular distance from center of map to earth shadow center double ad = Angle.Separation(moon.EarthShadowCoordinates, map.Center); // semidiameter of penumbra in seconds of arc double sdP = moon.EarthShadow.PenumbraRadius * 6378.0 / 1738.0 * moon.Semidiameter; bool isGround = settings.Get <bool>("Ground"); double coeff = map.DiagonalCoefficient(); if ((!isGround || moon.EarthShadowCoordinates.Altitude + sdP / 3600 > 0) && ad < coeff * map.ViewAngle + sdP / 3600) { PointF p = map.Project(moon.EarthShadowCoordinates); PointF pMoon = map.Project(moon.Horizontal); // size of penumbra, in pixels float szP = map.GetDiskSize(sdP); // size of umbra, in pixels float szU = szP / (float)moon.EarthShadow.Ratio; // size of Moon, in pixels float szM = map.GetDiskSize(moon.Semidiameter); // fraction of the penumbra ring (without umbra part) float fr = 1 - szU / szP; // do not render on large view angle if (szM >= 10) { // if eclipse takes place if (Angle.Separation(moon.Horizontal, moon.EarthShadowCoordinates) <= sdP / 3600) { var gpM = new GraphicsPath(); var gpP = new GraphicsPath(); var gpU = new GraphicsPath(); gpP.AddEllipse(p.X - szP / 2, p.Y - szP / 2, szP, szP); gpU.AddEllipse(p.X - szU / 2, p.Y - szU / 2, szU, szU); gpM.AddEllipse(pMoon.X - szM / 2 - 0.5f, pMoon.Y - szM / 2 - 0.5f, szM + 1, szM + 1); var brushP = new PathGradientBrush(gpP); brushP.CenterPoint = p; brushP.CenterColor = clrPenumbraGrayDark; brushP.SurroundColors = new Color[] { clrPenumbraTransp }; var blendP = new ColorBlend(); blendP.Colors = new Color[] { clrPenumbraTransp, clrPenumbraTransp, clrPenumbraGrayLight, clrPenumbraGrayDark, clrPenumbraGrayDark }; blendP.Positions = new float[] { 0, fr / 2, fr * 0.95f, fr, 1 }; brushP.InterpolationColors = blendP; var brushU = new PathGradientBrush(gpU); brushU.CenterColor = clrUmbraRed; brushU.SurroundColors = new Color[] { clrUmbraGray }; brushU.Blend.Factors = new float[] { 0, 0.8f, 1 }; brushU.Blend.Positions = new float[] { 0, 0.8f, 1 }; var regionP = new Region(gpP); var regionU = new Region(gpU); regionP.Exclude(regionU); regionP.Intersect(gpM); regionU.Intersect(gpM); map.Graphics.FillRegion(brushP, regionP); map.Graphics.FillRegion(brushU, regionU); } // outline circles if (settings.Get <bool>("EarthShadowOutline") && map.ViewAngle > 0.5) { var brush = new SolidBrush(map.GetColor(clrShadowOutline)); var pen = new Pen(brush) { DashStyle = DashStyle.Dot }; map.Graphics.TranslateTransform(p.X, p.Y); map.Graphics.DrawEllipse(pen, -szP / 2, -szP / 2, szP, szP); map.Graphics.DrawEllipse(pen, -szU / 2, -szU / 2, szU, szU); map.Graphics.ResetTransform(); if (map.ViewAngle <= 10) { map.DrawObjectCaption(fontShadowLabel, brush, Text.Get("EarthShadow.Label"), p, szP); } } } } }
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); } }
public override void Render(IMapContext map) { double coeff = map.DiagonalCoefficient(); if (settings.Get <bool>("Ground")) { const int POINTS_COUNT = 64; PointF[] hor = new PointF[POINTS_COUNT]; double step = 2 * map.ViewAngle / (POINTS_COUNT - 1); SolidBrush brushGround = new SolidBrush(map.GetColor(colorGroundNight, colorGroundDay)); // Bottom part of ground shape for (int i = 0; i < POINTS_COUNT; i++) { var h = new CrdsHorizontal(map.Center.Azimuth - map.ViewAngle + step * i, 0); hor[i] = map.Project(h); } if (hor[0].X >= 0) { hor[0].X = -1; } if (hor[POINTS_COUNT - 1].X <= map.Width) { hor[POINTS_COUNT - 1].X = map.Width + 1; } if (hor.Any(h => !map.IsOutOfScreen(h))) { GraphicsPath gp = new GraphicsPath(); gp.AddCurve(hor); gp.AddLines(new PointF[] { new PointF(map.Width + 1, map.Height + 1), new PointF(-1, map.Height + 1) }); map.Graphics.FillPath(brushGround, gp); } else if (map.Center.Altitude <= 0) { map.Graphics.FillRectangle(brushGround, 0, 0, map.Width, map.Height); } // Top part of ground shape if (map.Center.Altitude > 0) { for (int i = 0; i < POINTS_COUNT; i++) { var h = new CrdsHorizontal(map.Center.Azimuth - map.ViewAngle - step * i, 0); hor[i] = map.Project(h); } if (hor.Count(h => !map.IsOutOfScreen(h)) > 2) { GraphicsPath gp = new GraphicsPath(); gp.AddCurve(hor); gp.AddLines(new PointF[] { new PointF(map.Width + 1, -1), new PointF(-1, -1), }); map.Graphics.FillPath(brushGround, gp); } } } if (map.Schema == ColorSchema.White || (!settings.Get <bool>("Ground") && settings.Get <bool>("HorizonLine"))) { const int POINTS_COUNT = 64; PointF[] hor = new PointF[POINTS_COUNT]; double step = 2 * map.ViewAngle / (POINTS_COUNT - 1); for (int i = 0; i < POINTS_COUNT; i++) { var h = new CrdsHorizontal(map.Center.Azimuth - map.ViewAngle + step * i, 0); hor[i] = map.Project(h); } if (hor[0].X >= 0) { hor[0].X = -1; } if (hor[POINTS_COUNT - 1].X <= map.Width) { hor[POINTS_COUNT - 1].X = map.Width + 1; } if (hor.Any(h => !map.IsOutOfScreen(h))) { Pen penHorizonLine = new Pen(map.GetColor("ColorHorizon"), 2); map.Graphics.DrawCurve(penHorizonLine, hor); } } if (settings.Get <bool>("LabelCardinalDirections")) { Brush brushCardinalLabels = new SolidBrush(map.GetColor("ColorCardinalDirections")); StringFormat format = new StringFormat() { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Center }; for (int i = 0; i < cardinalDirections.Length; i++) { var h = new CrdsHorizontal(i * 360 / cardinalDirections.Length, 0); if (Angle.Separation(h, map.Center) < map.ViewAngle * coeff) { PointF p = map.Project(h); p.Y += fontCardinalLabels[i % 2].Height; using (var gp = new GraphicsPath()) { map.Graphics.DrawString(Text.Get($"CardinalDirections.{cardinalDirections[i]}"), fontCardinalLabels[i % 2], brushCardinalLabels, p, format); } } } } }
public override void Render(IMapContext map) { Graphics g = map.Graphics; var allComets = cometsCalc.Comets; bool isGround = settings.Get("Ground"); bool useTextures = settings.Get("PlanetsTextures"); bool drawComets = settings.Get("Comets"); bool drawLabels = settings.Get("CometsLabels"); bool drawAll = settings.Get <bool>("CometsDrawAll"); decimal drawAllMagLimit = settings.Get <decimal>("CometsDrawAllMagLimit"); bool drawLabelMag = settings.Get <bool>("CometsLabelsMag"); Brush brushNames = new SolidBrush(map.GetColor("ColorCometsLabels")); var font = settings.Get <Font>("CometsLabelsFont"); if (drawComets) { var comets = allComets.Where(a => Angle.Separation(map.Center, a.Horizontal) < map.ViewAngle); foreach (var c in comets) { float diam = map.GetDiskSize(c.Semidiameter); float size = map.GetPointSize(c.Magnitude); // if "draw all" setting is enabled, draw comets brighter than limit if (drawAll && size < 1 && c.Magnitude <= (float)drawAllMagLimit) { size = 1; } string label = drawLabelMag ? $"{c.Name} {Formatters.Magnitude.Format(c.Magnitude)}" : c.Name; if (diam > 5) { double ad = Angle.Separation(c.Horizontal, map.Center); if ((!isGround || c.Horizontal.Altitude + c.Semidiameter / 3600 > 0) && ad < map.ViewAngle + c.Semidiameter / 3600) { PointF p = map.Project(c.Horizontal); PointF t = map.Project(c.TailHorizontal); double tail = map.DistanceBetweenPoints(p, t); if (diam > 5 || tail > 10) { using (var gpComet = new GraphicsPath()) { double rotation = Math.Atan2(t.Y - p.Y, t.X - p.X) + Math.PI / 2; gpComet.StartFigure(); // tail is long enough if (tail > diam) { gpComet.AddArc(p.X - diam / 2, p.Y - diam / 2, diam, diam, (float)Angle.ToDegrees(rotation), 180); gpComet.AddLines(new PointF[] { gpComet.PathPoints[gpComet.PathPoints.Length - 1], t, gpComet.PathPoints[0] }); } // draw coma only else { gpComet.AddEllipse(p.X - diam / 2, p.Y - diam / 2, diam, diam); } gpComet.CloseAllFigures(); using (var brushComet = new PathGradientBrush(gpComet)) { brushComet.CenterPoint = p; int alpha = 100; if (c.Magnitude >= map.MagLimit) { alpha -= (int)(100 * (c.Magnitude - map.MagLimit) / c.Magnitude); } brushComet.CenterColor = map.GetColor(Color.FromArgb(alpha, colorComet)); brushComet.SurroundColors = gpComet.PathPoints.Select(pp => Color.Transparent).ToArray(); g.FillPath(brushComet, gpComet); } } if (drawLabels) { map.DrawObjectCaption(font, brushNames, label, p, diam); } map.AddDrawnObject(c); } } } else if ((int)size > 0) { PointF p = map.Project(c.Horizontal); if (!map.IsOutOfScreen(p)) { g.FillEllipse(new SolidBrush(map.GetColor(Color.White)), p.X - size / 2, p.Y - size / 2, size, size); if (drawLabels) { map.DrawObjectCaption(font, brushNames, label, p, size); } map.AddDrawnObject(c); continue; } } } } }
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 DrawGrid(IMapContext map, Pen penGrid, CelestialGrid grid) { bool isAnyPoint = false; // Azimuths for (int j = 0; j < grid.Columns; j++) { var segments = grid.Column(j) .Select(p => Angle.Separation(grid.ToHorizontal(p, map), map.Center) < map.ViewAngle ? p : null) .Split(p => p == null, true); foreach (var segment in segments) { for (int k = 0; k < 2; k++) { if (segment.First().RowIndex > 1) { segment.Insert(0, grid[segment.First().RowIndex - 1, j]); } } for (int k = 0; k < 2; k++) { if (segment.Last().RowIndex < grid.Rows - 2) { segment.Add(grid[segment.Last().RowIndex + 1, j]); } } PointF[] refPoints = new PointF[2]; for (int k = 0; k < 2; k++) { var coord = grid.FromHorizontal(map.Center, map); coord.Longitude = segment[0].Longitude; coord.Latitude += -map.ViewAngle + k * (map.ViewAngle * 2); coord.Latitude = Math.Min(coord.Latitude, 80); coord.Latitude = Math.Max(coord.Latitude, -80); var refHorizontal = grid.ToHorizontal(coord, map); refPoints[k] = map.Project(refHorizontal); } DrawGroupOfPoints(map, penGrid, segment.Select(s => map.Project(grid.ToHorizontal(s, map))).ToArray(), refPoints); isAnyPoint = true; } } // Altitude circles for (int i = 0; i < grid.Rows; i++) { var segments = grid.Row(i) .Select(p => Angle.Separation(grid.ToHorizontal(p, map), map.Center) < map.ViewAngle ? p : null) .Split(p => p == null, true).ToList(); // segment that starts with point "0 degrees" var seg0 = segments.FirstOrDefault(s => s.First().ColumnIndex == 0); // segment that ends with point "345 degrees" var seg23 = segments.FirstOrDefault(s => s.Last().ColumnIndex == 23); // join segments into one if (seg0 != null && seg23 != null && seg0 != seg23) { segments.Remove(seg0); seg23.AddRange(seg0); } foreach (var segment in segments) { if (segment.Count == 24) { map.Graphics.DrawClosedCurve(penGrid, segment.Select(s => map.Project(grid.ToHorizontal(s, map))).ToArray()); } else { for (int k = 0; k < 2; k++) { int col = segment.First().ColumnIndex; if (col == 0) { segment.Insert(0, grid[i, 23]); } else { segment.Insert(0, grid[i, col - 1]); } } for (int k = 0; k < 2; k++) { int col = segment.Last().ColumnIndex; if (col < 23) { segment.Add(grid[i, col + 1]); } else if (col == 23) { segment.Add(grid[i, 0]); } } PointF[] refPoints = new PointF[2]; for (int k = 0; k < 2; k++) { var coord = grid.FromHorizontal(map.Center, map); coord.Longitude += -map.ViewAngle + k * (map.ViewAngle * 2); coord.Latitude = segment[0].Latitude; var refHorizontal = grid.ToHorizontal(coord, map); refPoints[k] = map.Project(refHorizontal); } if (!map.IsOutOfScreen(refPoints[0]) || !map.IsOutOfScreen(refPoints[1])) { refPoints = map.LineScreenIntersection(refPoints[0], refPoints[1]); } DrawGroupOfPoints(map, penGrid, segment.Select(s => map.Project(grid.ToHorizontal(s, map))).ToArray(), refPoints); } isAnyPoint = true; } } // Special case: there are no points visible // on the screen at the current position and zoom. // Then we select one point that is closest to screen senter. if (!isAnyPoint) { GridPoint closestPoint = grid.Points.OrderBy(p => Angle.Separation(grid.ToHorizontal(p, map), map.Center)).First(); { var segment = new List <GridPoint>(); segment.Add(closestPoint); int i = closestPoint.RowIndex; for (int k = 0; k < 2; k++) { int col = segment.First().ColumnIndex; if (col == 0) { segment.Insert(0, grid[i, 23]); } else { segment.Insert(0, grid[i, col - 1]); } } for (int k = 0; k < 2; k++) { int col = segment.Last().ColumnIndex; if (col < 23) { segment.Add(grid[i, col + 1]); } else if (col == 23) { segment.Add(grid[i, 0]); } } PointF[] refPoints = new PointF[2]; for (int k = 0; k < 2; k++) { var coord = grid.FromHorizontal(map.Center, map); coord.Longitude += -map.ViewAngle + k * (map.ViewAngle * 2); coord.Latitude = segment[0].Latitude; var refHorizontal = grid.ToHorizontal(coord, map); refPoints[k] = map.Project(refHorizontal); } if (!map.IsOutOfScreen(refPoints[0]) || !map.IsOutOfScreen(refPoints[1])) { refPoints = map.LineScreenIntersection(refPoints[0], refPoints[1]); } DrawGroupOfPoints(map, penGrid, segment.Select(s => map.Project(grid.ToHorizontal(s, map))).ToArray(), refPoints); } { var segment = new List <GridPoint>(); segment.Add(closestPoint); int j = closestPoint.ColumnIndex; for (int k = 0; k < 2; k++) { if (segment.First().RowIndex > 1) { segment.Insert(0, grid[segment.First().RowIndex - 1, j]); } } for (int k = 0; k < 2; k++) { if (segment.Last().RowIndex < grid.Rows - 2) { segment.Add(grid[segment.Last().RowIndex + 1, j]); } } PointF[] refPoints = new PointF[2]; for (int k = 0; k < 2; k++) { var coord = grid.FromHorizontal(map.Center, map); coord.Longitude = segment[0].Longitude; coord.Latitude += -map.ViewAngle + k * (map.ViewAngle * 2); coord.Latitude = Math.Min(coord.Latitude, 80); coord.Latitude = Math.Max(coord.Latitude, -80); var refHorizontal = grid.ToHorizontal(coord, map); refPoints[k] = map.Project(refHorizontal); } DrawGroupOfPoints(map, penGrid, segment.Select(s => map.Project(grid.ToHorizontal(s, map))).ToArray(), refPoints); } } }