Example #1
0
        /// <summary>
        /// Gets nearest point on the curve (or the line) to the provided point.
        /// </summary>
        /// <param name="points">Points of the curve (or the line)</param>
        /// <param name="p0">Some point to find the nearest one on the curve (on the line), i.e. projection.</param>
        /// <returns>Nearest point on the curve (or the line), i.e. projection of the point p0.</returns>
        private PointF GetProjectedPoint(IMapContext map, PointF[] points, PointF p0)
        {
            PointF[] nearest = points.OrderBy(n => map.DistanceBetweenPoints(n, p0)).Take(2).ToArray();

            PointF p1 = nearest[0];
            PointF p2 = nearest[1];

            PointF e1  = new PointF(p2.X - p1.X, p2.Y - p1.Y);
            PointF e2  = new PointF(p0.X - p1.X, p0.Y - p1.Y);
            double val = e1.X * e2.X + e1.Y * e2.Y;
            double len = e1.X * e1.X + e1.Y * e1.Y;
            PointF p   = new PointF((float)(p1.X + val * e1.X / len),
                                    (float)(p1.Y + val * e1.Y / len));

            return(p);
        }
Example #2
0
        /// <summary>
        /// Shifts all points of the curve (or line) to the ancor point.
        /// </summary>
        /// <param name="points">Points of the curve (or line)</param>
        /// <param name="p0">Ancor point. All curve or line points will be corrected,
        /// so the shifted curve (or line) will intersect the ancor point.</param>
        /// <returns>Corrected points of the curve (or line)</returns>
        private PointF[] ShiftToAncorPoint(IMapContext map, PointF[] points, PointF p0)
        {
            if (p0 != PointF.Empty)
            {
                PointF proj = GetProjectedPoint(map, points, p0);

                if (map.DistanceBetweenPoints(proj, p0) > 1)
                {
                    float dx = p0.X - proj.X;
                    float dy = p0.Y - proj.Y;

                    points = points.Select(p => new PointF(p.X + dx, p.Y + dy)).ToArray();
                }
            }

            return(points);
        }
Example #3
0
        /// <summary>
        /// Performs a correction of inverse projection.
        /// Checks that horizontal coordinates of a point are correct,
        /// and in case if not correct, applies iterative algorithm for searching correct values.
        /// </summary>
        /// <param name="p">Point to check</param>
        /// <param name="hor">Horizontal coordinates of the point</param>
        /// <returns>Corrected horizontal coordinates</returns>
        private CrdsHorizontal CorrectInverse(PointF p, CrdsHorizontal hor)
        {
            PointF pLeftEdge  = Project(new CrdsHorizontal(Map.Center.Azimuth - 90, hor.Altitude));
            PointF pRightEdge = Project(new CrdsHorizontal(Map.Center.Azimuth + 90, hor.Altitude));

            PointF pEdge;

            if (p.X < Map.Width / 2.0)
            {
                pEdge = pLeftEdge;
            }
            else
            {
                pEdge = pRightEdge;
            }

            Point origin = new Point((int)(Map.Width / 2.0), (int)(Map.Height / 2.0));

            double edgeToCenter = Map.DistanceBetweenPoints(origin, pEdge);

            double currentToCenter = Map.DistanceBetweenPoints(origin, p);

            bool correctionNeeded = Math.Abs(Map.Center.Altitude) == 90 || currentToCenter > edgeToCenter;

            if (correctionNeeded)
            {
                // projected coordinates of a horizontal grid pole (zenith or nadir point)
                PointF pole = Project(new CrdsHorizontal(0, 90 * (Map.Center.Altitude > 0 ? 1 : -1)));

                double angleWhole = 360 - Map.AngleBetweenVectors(pole, pLeftEdge, pRightEdge);

                double angleLeft = Map.AngleBetweenVectors(pole, p, pLeftEdge);

                double angleRight = Map.AngleBetweenVectors(pole, p, pRightEdge);

                int shiftSign = angleLeft < angleRight ? -1 : 1;

                int poleFix = 1;
                if (Map.Center.Altitude == 90 && pole.Y < p.Y)
                {
                    poleFix = -1;
                }
                else if (Map.Center.Altitude == -90 && pole.Y > p.Y)
                {
                    poleFix = -1;
                }

                double poleAngle = Math.Min(angleLeft, angleRight);

                double azimuthShift = poleAngle / angleWhole * 180;

                PointF pCorrected = new PointF(0, 0);

                double distOriginal  = Map.DistanceBetweenPoints(p, pEdge);
                double distCorrected = 0;

                int iterations = 0;

                do
                {
                    hor = new CrdsHorizontal(Angle.To360(Map.Center.Azimuth + shiftSign * 90 + poleFix * shiftSign * azimuthShift), hor.Altitude);

                    // corrected coordinates of a projected point
                    pCorrected = Project(hor);

                    distCorrected = Map.DistanceBetweenPoints(pCorrected, pEdge);

                    if (distCorrected > 0)
                    {
                        azimuthShift *= distOriginal / distCorrected;
                    }
                    iterations++;
                }while (Map.DistanceBetweenPoints(p, pCorrected) > 2 && iterations < 5);
            }

            return(hor);
        }
Example #4
0
        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);
                            }
                        }
                    }
                }
            }
        }
Example #5
0
        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 DrawGroupOfPoints(IMapContext map, Pen penGrid, PointF[] points, PointF[] refPoints)
        {
            // Do not draw figure containing less than 2 points
            if (points.Length < 2)
            {
                return;
            }

            // Two points can be simply drawn as a line
            if (points.Length == 2)
            {
                map.Graphics.DrawLine(penGrid, points[0], points[1]);
                return;
            }

            // Coordinates of the screen center
            var origin = new PointF(map.Width / 2, map.Height / 2);

            // Small radius is a screen diagonal
            double r = Math.Sqrt(map.Width * map.Width + map.Height * map.Height) / 2;

            // From 3 to 5 points. Probably we can straighten curve to line.
            // Apply some calculations to detect conditions when it's possible.
            if (points.Length > 2 && points.Length < 6)
            {
                // Determine start, middle and end points of the curve
                PointF pStart = points[0];
                PointF pMid   = points[points.Length / 2];
                PointF pEnd   = points[points.Length - 1];

                // Get angle between middle and last points of the curve
                double alpha = map.AngleBetweenVectors(pMid, pStart, pEnd);

                double d1 = map.DistanceBetweenPoints(pStart, origin);
                double d2 = map.DistanceBetweenPoints(pEnd, origin);

                // It's almost a straight line
                if (alpha > 179)
                {
                    // Check the at least one last point of the curve
                    // is far enough from the screen center
                    if (d1 > r * 2 || d2 > r * 2)
                    {
                        map.Graphics.DrawLine(penGrid, refPoints[0], refPoints[1]);
                        return;
                    }
                }

                // If both of last points of the line are far enough from the screen center
                // then assume that the curve is an arc of a big circle.
                // Check the curvature of that circle by comparing its radius with small radius
                if (d1 > r * 2 && d2 > r * 2)
                {
                    var R = FindCircleRadius(points);
                    if (R / r > 60)
                    {
                        map.Graphics.DrawLine(penGrid, refPoints[0], refPoints[1]);
                        return;
                    }
                }
            }

            if (points.All(p => map.DistanceBetweenPoints(p, origin) < r * 60))
            {
                // Draw the curve in regular way
                map.Graphics.DrawCurve(penGrid, points);
            }
        }
Example #7
0
        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);
                    }
                }
            }
        }
Example #8
0
        private void DrawTrackSegment(IMapContext map, Pen penGrid, PointF[] points, PointF pBody, int iterationStep = 0)
        {
            iterationStep++;

            // Do not draw figure containing less than 2 points
            if (points.Length < 2)
            {
                return;
            }
            // Two points can be simply drawn as a line
            else if (points.Length == 2)
            {
                points = ShiftToAncorPoint(map, points, pBody);
                map.Graphics.DrawLine(penGrid, points[0], points[1]);
            }
            // interpolation is needed
            else if (points.Length > 2 && points.Length < 20 && iterationStep < 10)
            {
                // Coordinates of the screen center
                var origin = new PointF(map.Width / 2, map.Height / 2);

                // Screen diagonal
                double diag = Math.Sqrt(map.Width * map.Width + map.Height * map.Height);

                float maxX = points.Select(p => Math.Abs(p.X)).Max();
                float maxY = points.Select(p => Math.Abs(p.Y)).Max();

                float f = (float)diag / Math.Max(maxX, maxY);

                var scaledPoints = points.Select(p => new PointF(p.X * f, p.Y * f)).ToArray();

                using (GraphicsPath gp = new GraphicsPath())
                {
                    gp.AddCurve(scaledPoints);
                    gp.Flatten();
                    scaledPoints = gp.PathPoints.Select(p => new PointF(p.X / f, p.Y / f)).ToArray();

                    var segments = scaledPoints.Select(p => map.DistanceBetweenPoints(p, origin) < diag * 3 ? p : PointF.Empty)
                                   .Split(p => p == PointF.Empty, true);

                    foreach (var segment in segments)
                    {
                        var p1 = scaledPoints.Prev(segment.First());
                        var p2 = scaledPoints.Next(segment.Last());

                        List <PointF> newPoints = new List <PointF>(segment);

                        if (p1 != PointF.Empty)
                        {
                            newPoints.Insert(0, p1);
                        }

                        if (p2 != PointF.Empty)
                        {
                            newPoints.Add(p2);
                        }

                        DrawTrackSegment(map, penGrid, newPoints.ToArray(), pBody, iterationStep);
                    }

                    if (!segments.Any())
                    {
                        var p0 = scaledPoints.OrderBy(p => map.DistanceBetweenPoints(p, origin)).First();
                        var p1 = scaledPoints.Prev(p0);
                        var p2 = scaledPoints.Next(p0);

                        List <PointF> newPoints = new List <PointF>();
                        if (p1 != PointF.Empty)
                        {
                            newPoints.Insert(0, p1);
                        }
                        if (p2 != PointF.Empty)
                        {
                            newPoints.Add(p2);
                        }

                        DrawTrackSegment(map, penGrid, newPoints.ToArray(), pBody, iterationStep);
                    }
                }
            }
            // draw the curve in regular way
            else
            {
                map.Graphics.DrawCurve(penGrid, ShiftToAncorPoint(map, points, pBody));
            }
        }