예제 #1
0
        public void PointD_DistanceReturns2ForToPointsPlacedVertically()
        {
            PointD p1 = new PointD(3, 4);
            PointD p2 = new PointD(3, 6);

            Assert.AreEqual(2, p1.Distance(p2));
        }
예제 #2
0
        public void PointD_DistanceReturns5ForToInclinedPoints()
        {
            PointD p1 = new PointD(0, 0);
            PointD p2 = new PointD(4, 3);

            Assert.AreEqual(5, p1.Distance(p2));
        }
        private void ChangeSunDiskData(PointD ptCurrMousePosition)
        {
            if (ptMouseDown != ptCurrMousePosition) // not just click
            {
                switch (currMouseActionRegime)
                {
                case MouseActionsRegime.Nothing:
                    break;

                case MouseActionsRegime.DrawingSunDisk:
                    sunDiskPositionAndSize = new RoundData(ptMouseDown.X, ptMouseDown.Y,
                                                           ptMouseDown.Distance(ptCurrMousePosition));

                    break;

                case MouseActionsRegime.MovingSunDisk:
                    sunDiskPositionAndSize.DCenterX = sunDiskPositionAndSizeBeforeMovingResizing.DCenterX + (ptCurrMousePosition.X - ptMouseDown.X);
                    sunDiskPositionAndSize.DCenterY = sunDiskPositionAndSizeBeforeMovingResizing.DCenterY + (ptCurrMousePosition.Y - ptMouseDown.Y);

                    break;

                case MouseActionsRegime.ResizingSunDisk:
                    sunDiskPositionAndSize.DRadius =
                        ptCurrMousePosition.Distance(sunDiskPositionAndSize.pointDCircleCenter());

                    break;

                default:
                    break;
                }
            }
        }
예제 #4
0
        public void PointD_DistanceReturns1ForToPointsPlacedHorizontally()
        {
            PointD p1 = new PointD(3, 4);
            PointD p2 = new PointD(4, 4);

            Assert.AreEqual(1, p1.Distance(p2));
        }
예제 #5
0
        private void Fire(ScannedRobotEvent e, double absoluteBearing)
        {
            absoluteBearing = MyBot.HeadingRadians + e.BearingRadians;
            //Finding the heading and heading change.
            double enemyHeading       = e.HeadingRadians;
            double enemyHeadingChange = enemyHeading - _oldEnemyHeading;

            _oldEnemyHeading = enemyHeading;

            // Circular Targeting http://robowiki.net/wiki/Circular_Targeting

            /*This method of targeting is know as circular targeting; you assume your enemy will
             * keep moving with the same speed and turn rate that he is using at fire time.The
             * base code comes from the wiki.
             */
            double deltaTime  = 0;
            double predictedX = MyBot.X + e.Distance * Math.Sin(absoluteBearing);
            double predictedY = MyBot.Y + e.Distance * Math.Cos(absoluteBearing);
            PointD point      = new PointD(MyBot.X, MyBot.Y);

            while ((++deltaTime) * _bulletSpeed < point.Distance(predictedX, predictedY))
            {
                //Add the movement we think our enemy will make to our enemy's current X and Y
                predictedX += Math.Sin(enemyHeading) * e.Velocity;
                predictedY += Math.Cos(enemyHeading) * e.Velocity;


                //Find our enemy's heading changes.
                enemyHeading += enemyHeadingChange;

                //If our predicted coordinates are outside the walls, put them 18 distance units away from the walls as we know
                //that that is the closest they can get to the wall (Bots are non-rotating 36*36 squares).
                predictedX = Math.Max(Math.Min(predictedX, MyBot.BattleFieldWidth - 18), 18);
                predictedY = Math.Max(Math.Min(predictedY, MyBot.BattleFieldHeight - 18), 18);
            }

            //Find the bearing of our predicted coordinates from us.
            double aim = Utils.NormalAbsoluteAngle(Math.Atan2(predictedX - MyBot.X, predictedY - MyBot.Y));

            var bullerPower = 400 / e.Distance;

            //Aim and fire.
            MyBot.SetTurnGunRightRadians(Utils.NormalRelativeAngle(aim - MyBot.GunHeadingRadians));

            MyBot.SetFire(bullerPower);

            MyBot.SetTurnRadarRightRadians(Utils.NormalRelativeAngle(absoluteBearing - MyBot.RadarHeadingRadians) * 2);
        }
예제 #6
0
 /// <summary>
 /// Determines whether the testing point is inside the circle.
 /// </summary>
 /// <param name="pt">The testing point.</param>
 /// <param name="theCircle">The circle.</param>
 /// <returns>System.Int32:
 /// -1 => pt is outside the circle
 /// 0 => pt is at the circle margin
 /// 1 => pt is inside the circle
 /// default (for empty circle data) is outside
 /// </returns>
 public static int IsPointInsideCircle(this PointD pt, RoundData theCircle, double marginDetectorPrecision = 2.0d)
 {
     if (theCircle.IsNull)
     {
         return(-1);                  // default is outside
     }
     if (PointD.Distance(pt, theCircle.pointDCircleCenter()) < theCircle.DRadius)
     {
         return(1);
     }
     if (Math.Abs(PointD.Distance(pt, theCircle.pointDCircleCenter()) - theCircle.DRadius) <= marginDetectorPrecision)
     {
         return(0);
     }
     return(-1);
 }
예제 #7
0
        private static int FindNextClosest(List <PathDefWithClosed> Paths)
        {
            QuadTreeNode Root = new QuadTreeNode();

            PolyLineSet.Bounds B = new PolyLineSet.Bounds();
            for (int i = 0; i < Paths.Count; i++)
            {
                if (Paths[i].Closed == false)
                {
                    B.FitPoint(Paths[i].Vertices.First());
                    B.FitPoint(Paths[i].Vertices.Last());
                }
            }

            Root.xstart = B.TopLeft.X - 10;
            Root.xend   = B.BottomRight.X + 10;
            Root.ystart = B.TopLeft.Y - 10;
            Root.yend   = B.BottomRight.Y + 10;

            for (int i = 0; i < Paths.Count; i++)
            {
                if (Paths[i].Closed == false)
                {
                    Root.Insert(new SegmentEndContainer()
                    {
                        PathID = i, Point = Paths[i].Vertices.First(), Side = SideEnum.Start
                    }, 5);
                    Root.Insert(new SegmentEndContainer()
                    {
                        PathID = i, Point = Paths[i].Vertices.Last(), Side = SideEnum.End
                    }, 5);
                }
            }
            RectangleF R = new RectangleF();

            R.Width  = 3;
            R.Height = 3;

            for (int i = 0; i < Paths.Count; i++)
            {
                var P = Paths[i];
                if (P.Closed == false)
                {
                    var PF  = P.Vertices[0];
                    var PF2 = P.Vertices[1];

                    var PathDir = PF - PF2;// MathHelpers.Difference(PF, PF2);
                    PathDir.Normalize();

                    R.X = (float)(P.Vertices.First().X - 1.5);
                    R.Y = (float)(P.Vertices.First().Y - 1.5);
                    int    startmatch      = -1;
                    int    endmatch        = -1;
                    double closestdistance = B.Width() + B.Height();
                    Root.CallBackInside(R, delegate(QuadTreeItem QI)
                    {
                        var S = QI as SegmentEndContainer;
                        if (S.PathID == i)
                        {
                            return(true);
                        }
                        if (P.Width != Paths[S.PathID].Width)
                        {
                            return(true);
                        }
                        PointD Dir2;
                        if (S.Side == SideEnum.Start)
                        {
                            var S2 = Paths[S.PathID].Vertices[1];
                            Dir2   = S2 - S.Point;
                            Dir2.Normalize();
                        }
                        else
                        {
                            var S2 = Paths[S.PathID].Vertices[Paths[S.PathID].Vertices.Count() - 2];
                            Dir2   = S2 - S.Point;
                            Dir2.Normalize();
                        }

                        double dotted = Dir2.Dot(PathDir);
                        var D         = PointD.Distance(S.Point, PF);
                        if (D < 1.0)
                        {
                            //  D -= dotted * 3.0;
                            if (D < closestdistance)
                            {
                                closestdistance = D;
                                if (S.Side == SideEnum.Start)
                                {
                                    startmatch = S.PathID;
                                }
                                else
                                {
                                    endmatch = S.PathID;
                                }
                            }
                        }
                        return(true);
                    });

                    if (startmatch > -1 || endmatch > -1)
                    {
                        if (endmatch > -1)
                        {
                            if (closestdistance > 0)
                            {
                                Paths[endmatch].Vertices.Remove(Paths[endmatch].Vertices.Last());
                            }
                            Paths[endmatch].Vertices.AddRange(Paths[i].Vertices);
                            if (Paths[endmatch].Vertices.First() == Paths[endmatch].Vertices.Last())
                            {
                                Console.WriteLine("closed path with {0} points during stage 4a", Paths[endmatch].Vertices.Count());
                                Paths[endmatch].Closed = true;
                            }
                            Paths.Remove(Paths[i]);
                            // Console.WriteLine(" 4a");
                            return(1);
                        }
                        if (startmatch > -1)
                        {
                            Paths[i].Vertices.Reverse();
                            if (closestdistance > 0)
                            {
                                Paths[i].Vertices.Remove(Paths[i].Vertices.Last());
                            }
                            Paths[i].Vertices.AddRange(Paths[startmatch].Vertices);
                            if (Paths[i].Vertices.First() == Paths[i].Vertices.Last())
                            {
                                Console.WriteLine("closed path with {0} points during stage 4b", Paths[i].Vertices.Count());
                                Paths[i].Closed = true;
                            }
                            Paths.Remove(Paths[startmatch]);
                            //Console.WriteLine(" 4b");

                            return(1);
                        }
                    }

                    PF              = P.Vertices.Last();
                    R.X             = (float)(P.Vertices.First().X - 1.5);
                    R.Y             = (float)(P.Vertices.First().Y - 1.5);
                    startmatch      = -1;
                    endmatch        = -1;
                    closestdistance = B.Width() + B.Height();
                    Root.CallBackInside(R, delegate(QuadTreeItem QI)
                    {
                        var S = QI as SegmentEndContainer;
                        if (S.PathID == i)
                        {
                            return(true);
                        }
                        if (P.Width != Paths[S.PathID].Width)
                        {
                            return(true);
                        }

                        var D = PointD.Distance(S.Point, PF);
                        if (D < 1.0 && D < closestdistance)
                        {
                            closestdistance = D;
                            if (S.Side == SideEnum.Start)
                            {
                                startmatch = S.PathID;
                            }
                            else
                            {
                                endmatch = S.PathID;
                            }
                        }
                        return(true);
                    });

                    if (startmatch > -1 || endmatch > -1)
                    {
                        if (endmatch > -1)
                        {
                            Paths[i].Vertices.Reverse();
                            if (closestdistance > 0)
                            {
                                Paths[endmatch].Vertices.Remove(Paths[endmatch].Vertices.Last());
                            }
                            Paths[endmatch].Vertices.AddRange(Paths[i].Vertices);
                            if (Paths[endmatch].Vertices.First() == Paths[endmatch].Vertices.Last())
                            {
                                Console.WriteLine("closed path with {0} points during stage 4c", Paths[endmatch].Vertices.Count());
                                Paths[endmatch].Closed = true;
                            }
                            Paths.Remove(Paths[i]);
                            //  Console.WriteLine(" 4c");

                            return(1);
                        }
                        if (startmatch > -1)
                        {
                            if (closestdistance > 0)
                            {
                                Paths[i].Vertices.Remove(Paths[i].Vertices.Last());
                            }
                            Paths[i].Vertices.AddRange(Paths[startmatch].Vertices);
                            if (Paths[i].Vertices.First() == Paths[i].Vertices.Last())
                            {
                                Console.WriteLine("closed path with {0} points during stage 4d", Paths[i].Vertices.Count());
                                Paths[i].Closed = true;
                            }
                            Paths.Remove(Paths[startmatch]);
                            // Console.WriteLine(" 4d");

                            return(1);
                        }
                    }
                }
            }

            return(0);
        }
예제 #8
0
        private static List <PathDefWithClosed> StripOverlaps(List <PathDefWithClosed> Paths)
        {
            List <PathDefWithClosed> Res  = new List <PathDefWithClosed>();
            QuadTreeNode             Root = new QuadTreeNode();

            PolyLineSet.Bounds B = new PolyLineSet.Bounds();
            for (int i = 0; i < Paths.Count; i++)
            {
                if (Paths[i].Closed == false)
                {
                    foreach (var a in Paths[i].Vertices)
                    {
                        B.FitPoint(a);
                    }
                }
                else
                {
                    Res.Add(Paths[i]);
                }
            }

            Root.xstart = B.TopLeft.X - 10;
            Root.xend   = B.BottomRight.X + 10;
            Root.ystart = B.TopLeft.Y - 10;
            Root.yend   = B.BottomRight.Y + 10;
            RectangleF QueryRect = new RectangleF();

            QueryRect.Width  = 3;
            QueryRect.Height = 3;
            List <PathDefWithClosed> ToDelete = new List <PathDefWithClosed>();

            for (int i = 0; i < Paths.Count; i++)
            {
                if (Paths[i].Closed == false)
                {
                    int nearcount = 0;
                    foreach (var a in Paths[i].Vertices)
                    {
                        QueryRect.X = (float)a.X - 1.5f;
                        QueryRect.Y = (float)a.Y - 1.5f;

                        Root.CallBackInside(QueryRect, delegate(QuadTreeItem QI)
                        {
                            var S = QI as SegmentEndContainer;
                            if (S.Point == a)
                            {
                                nearcount++;
                            }
                            else
                            {
                                if (PointD.Distance(a, S.Point) < 0.001)
                                {
                                    nearcount++;
                                }
                            }
                            return(true);
                        }
                                            );
                    }

                    int max = Math.Max(4, (Paths[i].Vertices.Count * 50) / 100);

                    if (nearcount <= max)
                    {
                        foreach (var a in Paths[i].Vertices)
                        {
                            Root.Insert(new SegmentEndContainer()
                            {
                                PathID = i, Point = a, Side = SideEnum.Start
                            }, 8);
                        }
                        Res.Add(Paths[i]);
                    }
                    else
                    {
                        Res.Add(Paths[i]);
                        Console.WriteLine("{4}: {0} out of {1}/{2}/{3}", nearcount, max, Paths[i].Vertices.Count, (Paths[i].Vertices.Count * 90) / 100, i);
                        Console.WriteLine("{0}: skipped!", i);
                    }
                }
            }
            return(Res);
        }
예제 #9
0
        private static int FindNextClosest(List <PathDefWithClosed> Paths)
        {
            QuadTreeNode Root = new QuadTreeNode();
            Bounds       B    = new Bounds();

            for (int i = 0; i < Paths.Count; i++)
            {
                if (Paths[i].Closed == false)
                {
                    B.FitPoint(Paths[i].Points.First());
                    B.FitPoint(Paths[i].Points.Last());
                }
            }

            Root.xstart = B.TopLeft.X - 10;
            Root.xend   = B.BottomRight.X + 10;
            Root.ystart = B.TopLeft.Y - 10;
            Root.yend   = B.BottomRight.Y + 10;

            for (int i = 0; i < Paths.Count; i++)
            {
                if (Paths[i].Closed == false)
                {
                    Root.Insert(new SegmentEndContainer()
                    {
                        PathID = i, Point = Paths[i].Points.First(), Side = SideEnum.Start
                    }, 4);
                    Root.Insert(new SegmentEndContainer()
                    {
                        PathID = i, Point = Paths[i].Points.Last(), Side = SideEnum.End
                    }, 4);
                }
            }
            RectangleF R = new RectangleF();

            R.Width  = 30;
            R.Height = 30;

            for (int i = 0; i < Paths.Count; i++)
            {
                var P = Paths[i];
                if (P.Closed == false)
                {
                    var PF = P.Points.First();
                    R.X = (float)(P.Points.First().X - 15);
                    R.Y = (float)(P.Points.First().Y - 15);
                    int    startmatch      = -1;
                    int    endmatch        = -1;
                    double closestdistance = B.Width() + B.Height();
                    Root.CallBackInside(R, delegate(QuadTreeItem QI)
                    {
                        var S = QI as SegmentEndContainer;
                        if (S.PathID == i)
                        {
                            return(true);
                        }
                        var D = PointD.Distance(S.Point, PF);
                        if (D < 1.0 && D < closestdistance)
                        {
                            closestdistance = D;
                            if (S.Side == SideEnum.Start)
                            {
                                startmatch = S.PathID;
                            }
                            else
                            {
                                endmatch = S.PathID;
                            }
                        }
                        return(true);
                    });

                    if (startmatch > -1 || endmatch > -1)
                    {
                        if (endmatch > -1)
                        {
                            Paths[endmatch].Points.Remove(Paths[endmatch].Points.Last());
                            Paths[endmatch].Points.AddRange(Paths[i].Points);
                            if (Paths[endmatch].Points.First() == Paths[endmatch].Points.Last())
                            {
                                //   Console.WriteLine("closed path with {0} points during stage 4a", Paths[endmatch].Points.Count());
                                Paths[endmatch].Closed = true;
                            }
                            Paths.Remove(Paths[i]);
                            // Console.WriteLine(" 4a");
                            return(1);
                        }
                        if (startmatch > -1)
                        {
                            Paths[i].Points.Reverse();
                            Paths[i].Points.Remove(Paths[i].Points.Last());
                            Paths[i].Points.AddRange(Paths[startmatch].Points);
                            if (Paths[i].Points.First() == Paths[i].Points.Last())
                            {
                                // Console.WriteLine("closed path with {0} points during stage 4b", Paths[i].Points.Count());
                                Paths[i].Closed = true;
                            }
                            Paths.Remove(Paths[startmatch]);
                            //Console.WriteLine(" 4b");

                            return(1);
                        }
                    }

                    PF              = P.Points.Last();
                    R.X             = (float)(P.Points.First().X - 0.5);
                    R.Y             = (float)(P.Points.First().Y - 0.5);
                    startmatch      = -1;
                    endmatch        = -1;
                    closestdistance = B.Width() + B.Height();
                    Root.CallBackInside(R, delegate(QuadTreeItem QI)
                    {
                        var S = QI as SegmentEndContainer;
                        if (S.PathID == i)
                        {
                            return(true);
                        }
                        var D = PointD.Distance(S.Point, PF);
                        if (D < 1.0 && D < closestdistance)
                        {
                            closestdistance = D;
                            if (S.Side == SideEnum.Start)
                            {
                                startmatch = S.PathID;
                            }
                            else
                            {
                                endmatch = S.PathID;
                            }
                        }
                        return(true);
                    });

                    if (startmatch > -1 || endmatch > -1)
                    {
                        if (endmatch > -1)
                        {
                            Paths[i].Points.Reverse();
                            Paths[endmatch].Points.Remove(Paths[endmatch].Points.Last());
                            Paths[endmatch].Points.AddRange(Paths[i].Points);
                            if (Paths[endmatch].Points.First() == Paths[endmatch].Points.Last())
                            {
                                // Console.WriteLine("closed path with {0} points during stage 4c", Paths[endmatch].Points.Count());
                                Paths[endmatch].Closed = true;
                            }
                            Paths.Remove(Paths[i]);
                            //  Console.WriteLine(" 4c");

                            return(1);
                        }
                        if (startmatch > -1)
                        {
                            Paths[i].Points.Remove(Paths[i].Points.Last());
                            Paths[i].Points.AddRange(Paths[startmatch].Points);
                            if (Paths[i].Points.First() == Paths[i].Points.Last())
                            {
                                // Console.WriteLine("closed path with {0} points during stage 4d", Paths[i].Points.Count());
                                Paths[i].Closed = true;
                            }
                            Paths.Remove(Paths[startmatch]);
                            // Console.WriteLine(" 4d");

                            return(1);
                        }
                    }
                }
            }

            return(0);
        }
예제 #10
0
        protected unsafe void eraseSmooth(ImageSurface surf, Context g, PointD start, PointD end)
        {
            int rad = (int)(BrushWidth / 2.0) + 1;
            //Premultiply with alpha value
            byte bk_col_a  = (byte)(PintaCore.Palette.SecondaryColor.A * 255.0);
            byte bk_col_r  = (byte)(PintaCore.Palette.SecondaryColor.R * bk_col_a);
            byte bk_col_g  = (byte)(PintaCore.Palette.SecondaryColor.G * bk_col_a);
            byte bk_col_b  = (byte)(PintaCore.Palette.SecondaryColor.B * bk_col_a);
            int  num_steps = (int)start.Distance(end) / rad + 1;

            //Initialize lookup table when first used (to prevent slower startup of the application)
            initLookupTable();

            for (int step = 0; step < num_steps; step++)
            {
                PointD pt = Utility.Lerp(start, end, (float)step / num_steps);
                int    x = (int)pt.X, y = (int)pt.Y;

                Gdk.Rectangle surface_rect = new Gdk.Rectangle(0, 0, surf.Width, surf.Height);
                Gdk.Rectangle brush_rect = new Gdk.Rectangle(x - rad, y - rad, 2 * rad, 2 * rad);
                Gdk.Rectangle dest_rect = Gdk.Rectangle.Intersect(surface_rect, brush_rect);

                if ((dest_rect.Width > 0) && (dest_rect.Height > 0))
                {
                    //Allow Clipping through a temporary surface
                    using (ImageSurface tmp_surface = copySurfacePart(surf, dest_rect)) {
                        for (int iy = dest_rect.Top; iy < dest_rect.Bottom; iy++)
                        {
                            ColorBgra *srcRowPtr = tmp_surface.GetRowAddressUnchecked(iy - dest_rect.Top);
                            int        dy        = ((iy - y) * LUT_Resolution) / rad;
                            if (dy < 0)
                            {
                                dy = -dy;
                            }
                            byte[] lut_factor_row = lut_factor [dy];

                            for (int ix = dest_rect.Left; ix < dest_rect.Right; ix++)
                            {
                                ColorBgra col = *srcRowPtr;
                                int       dx  = ((ix - x) * LUT_Resolution) / rad;
                                if (dx < 0)
                                {
                                    dx = -dx;
                                }

                                int force = lut_factor_row [dx];
                                //Note: premultiplied alpha is used!
                                if (mouse_button == 3)
                                {
                                    col.A = (byte)((col.A * force + bk_col_a * (255 - force)) / 255);
                                    col.R = (byte)((col.R * force + bk_col_r * (255 - force)) / 255);
                                    col.G = (byte)((col.G * force + bk_col_g * (255 - force)) / 255);
                                    col.B = (byte)((col.B * force + bk_col_b * (255 - force)) / 255);
                                }
                                else
                                {
                                    col.A = (byte)(col.A * force / 255);
                                    col.R = (byte)(col.R * force / 255);
                                    col.G = (byte)(col.G * force / 255);
                                    col.B = (byte)(col.B * force / 255);
                                }
                                *srcRowPtr = col;
                                srcRowPtr++;
                            }
                        }
                        //Draw the final result on the surface
                        pasteSurfacePart(g, tmp_surface, dest_rect);
                    }
                }
            }
        }
예제 #11
0
        /// <summary>
        /// Calculates the given index's segment end point data.
        /// </summary>
        /// <param name="currentIndex">The index of the ControlPoint to calculate the segment end point data of.</param>
        /// <param name="nextIndex">The index of the next ControlPoint.</param>
        /// <param name="lineEndPoint">The end point of the line prior to the given ControlPoint's index.</param>
        /// <param name="cornerEndPoint">The end point of the rounded corner at the given ControlPoint's index.</param>
        private void calculateSegmentEndPoints(int currentIndex, out int nextIndex, out PointD lineEndPoint, out PointD cornerEndPoint)
        {
            //Determine the positions of the current, next, and double next ControlPoints.

            nextIndex = currentIndex + 1;

            if (nextIndex >= ControlPoints.Count)
            {
                nextIndex = 0;
            }

            int doubleNextIndex = nextIndex + 1;

            if (doubleNextIndex >= ControlPoints.Count)
            {
                doubleNextIndex = 0;
            }

            PointD currentPosition    = ControlPoints[currentIndex].Position;
            PointD nextPosition       = ControlPoints[nextIndex].Position;
            PointD doubleNextPosition = ControlPoints[doubleNextIndex].Position;

            //Calculate the distance between the current and next point and the next and double next point.
            double currentDistance = currentPosition.Distance(nextPosition);
            double nextDistance    = nextPosition.Distance(doubleNextPosition);

            //Calculate the smaller of the two distances.
            double minDistance = Math.Min(currentDistance, nextDistance);

            //The radius value used can change between ControlPoints depending on their proximity to each other.
            double currentRadius = Radius;

            //Reduce the radius according to the distance between adjacent ControlPoints if necessary.
            if (currentRadius > minDistance / 2d)
            {
                currentRadius = minDistance / 2d;
            }

            //Calculate the current offset ratio, which is the ratio of the radius to the distance between the current and next points.

            double currentOffsetRatio;

            //Prevent a divide by 0 error.
            if (currentDistance <= 0d)
            {
                currentOffsetRatio = 0d;
            }
            else
            {
                currentOffsetRatio = currentRadius / currentDistance;

                if (currentOffsetRatio > 1d)
                {
                    currentOffsetRatio = 1d;
                }
            }

            //Calculate the next offset ratio, which is the ratio of the radius to the distance between the next and double next points.

            double nextOffsetRatio;

            //Prevent a divide by 0 error.
            if (nextDistance <= 0d)
            {
                nextOffsetRatio = 0d;
            }
            else
            {
                nextOffsetRatio = currentRadius / nextDistance;

                if (nextOffsetRatio > 1d)
                {
                    nextOffsetRatio = 1d;
                }
            }

            //Calculate the end point of the straight line before the rounded corner.
            lineEndPoint = new PointD(nextPosition.X - (nextPosition.X - currentPosition.X) * currentOffsetRatio,
                                      nextPosition.Y - (nextPosition.Y - currentPosition.Y) * currentOffsetRatio);

            //Calculate the end point of the rounded corner after the straight line.
            cornerEndPoint = new PointD(nextPosition.X + (doubleNextPosition.X - nextPosition.X) * nextOffsetRatio,
                                        nextPosition.Y + (doubleNextPosition.Y - nextPosition.Y) * nextOffsetRatio);
        }
        /// <summary>
        /// Gets the local minimums distribution.
        /// </summary>
        /// <param name="dmFieldData">The dm field data.</param>
        /// <param name="dimensionNumber">The dimension number:
        /// 1 - rows (angle)
        /// 2 - columns (distance)
        /// </param>
        /// <returns>DenseMatrix.</returns>
        //public static DenseMatrix GetLocalMinimumsDistribution(DenseMatrix dmFieldData, PointD sunCenterPoint, PointD imageCenterPoint, double imageRadius, int imageHeight, double imageCircleCropFactor = 0.9d, int dimensionNumber = 1)
        public static List <Point3D> GetLocalMinimumsDistribution(DenseMatrix dmFieldData, RoundData sunDiskData, RoundData imageRoundData, int imageHeight, double imageCircleCropFactor = 0.9d)
        {
            // DenseMatrix dmFieldminimumsData = DenseMatrix.Create(dmFieldData.RowCount, dmFieldData.ColumnCount, 0.0d);
            List <Point3D> lRetPoints = new List <Point3D>();

            double     imageRadius      = imageRoundData.DRadius;
            PointD     imageCenterPoint = imageRoundData.pointDCircleCenter();
            PointPolar imageCenterPointRelatedToSunCenter = new PointPolar(imageCenterPoint - sunDiskData.pointDCircleCenter(), true);
            double     distanceSunCenterToImageCenter     = PointD.Distance(imageCenterPoint, sunDiskData.pointDCircleCenter());


            #region // obsolete
            //if (dimensionNumber == 1)
            //{
            #endregion // obsolete
            for (int i = 0; i < dmFieldData.RowCount; i++)
            {
                bool itsTheCropCase = false;
                //если направлени на кроп кадра - то не берем в расмотрение
                double currentAngle = ((double)i / (double)(dmFieldData.RowCount - 1)) * 2.0d * Math.PI;

                LineDescription2D line, lineMargin;
                if (currentAngle < Math.PI)
                {
                    //верхняя половина, смотрим направление на y=0.0d
                    line = new LineDescription2D(sunDiskData.pointDCircleCenter(),
                                                 new Vector2D(Math.Cos(currentAngle), -Math.Sin(currentAngle)));
                    lineMargin = new LineDescription2D(new PointD(0.0d, 0.0d), new Vector2D(1.0d, 0.0d));
                }
                else
                {
                    line = new LineDescription2D(sunDiskData.pointDCircleCenter(),
                                                 new Vector2D(Math.Cos(currentAngle), Math.Sin(currentAngle)));
                    lineMargin = new LineDescription2D(new PointD(0.0d, imageHeight), new Vector2D(1.0d, 0.0d));
                }

                PointD crossPointD = LineDescription2D.CrossPoint(line, lineMargin);
                if (crossPointD.Distance(imageCenterPoint) < imageRadius)
                {
                    itsTheCropCase = true;
                }

                #region // obsolete
                //double yMargin = 0.0d;
                //double xMargin = sunCenterPoint.X + (yMargin - sunCenterPoint.Y) / Math.Tan(currentAngle);
                //double dx = xMargin - imageCenterPoint.X;
                //double dy = yMargin - imageCenterPoint.Y;
                //if (Math.Sqrt(dx * dx + dy * dy) < imageRadius) itsTheCropCase = true;
                #endregion // obsolete

                #region    //obsolete
                //else
                //{
                //    //нижняя половина, смотрим направление на y=imageHeight
                //    double yMargin = (double)imageHeight;
                //    double xMargin = sunCenterPoint.X + (yMargin - sunCenterPoint.Y) / Math.Tan(currentAngle);
                //    double dx = xMargin - imageCenterPoint.X;
                //    double dy = yMargin - imageCenterPoint.Y;
                //    if (Math.Sqrt(dx * dx + dy * dy) < imageRadius) itsTheCropCase = true;
                //}
                #endregion //obsolete
                //Если слишком близко к краю изображения - тоже исключаем. Минимум должен лежать не ближе, например, 1/15



                //DenseMatrix dmSlicedDataMatrix = (DenseMatrix)dmFieldData.SubMatrix(i, 1, 0, dmFieldData.ColumnCount);
                DenseVector dvRowDataVector = (DenseVector)dmFieldData.EnumerateRows().ElementAt(i);
                #region // debug plotting
                //dvRowDataVector.SaveVectorDataAsImagePlot(
                //    "D:\\_gulevlab\\SkyImagesAnalysis_appData\\patent-samples\\result.2015-03-24\\img-2014-09-20T16-03-58devID1\\dvRowDataVector-plot-image-" +
                //    i.ToString("D03") + "-step1.png");
                #endregion // debug plotting
                dvRowDataVector.MapIndexedInplace((idx, x) => ((x == 0.0d) || (idx < sunDiskData.DRadius * 1.5d)) ? (1.0d) : (x));
                #region    // debug plotting
                //dvRowDataVector.SaveVectorDataAsImagePlot(
                //    "D:\\_gulevlab\\SkyImagesAnalysis_appData\\patent-samples\\result.2015-03-24\\img-2014-09-20T16-03-58devID1\\dvRowDataVector-plot-image-" +
                //    i.ToString("D03") + "-step2.png");
                #endregion // debug plotting
                double phiFromImageCenterToDirection = imageCenterPointRelatedToSunCenter.Phi - currentAngle;
                double distanceToImageMargin         = distanceSunCenterToImageCenter * Math.Cos(phiFromImageCenterToDirection) +
                                                       Math.Sqrt(imageRadius * imageRadius -
                                                                 distanceSunCenterToImageCenter * distanceSunCenterToImageCenter *
                                                                 Math.Sin(phiFromImageCenterToDirection) *
                                                                 Math.Sin(phiFromImageCenterToDirection));
                dvRowDataVector.MapIndexedInplace(
                    (idx, x) => ((double)idx / distanceToImageMargin >= imageCircleCropFactor) ? (1.0d) : (x));
                #region // debug plotting
                //dvRowDataVector.SaveVectorDataAsImagePlot(
                //    "D:\\_gulevlab\\SkyImagesAnalysis_appData\\patent-samples\\result.2015-03-24\\img-2014-09-20T16-03-58devID1\\dvRowDataVector-plot-image-" +
                //    i.ToString("D03") + "-step3.png");
                #endregion // debug plotting
                double minValue      = dvRowDataVector.Minimum();
                int    minValueIndex = dvRowDataVector.MinimumIndex();

                //if (!itsTheCropCase) dmFieldminimumsData[i, minValueIndex] = minValue;
                if ((!itsTheCropCase) && ((double)minValueIndex > sunDiskData.DRadius))
                {
                    lRetPoints.Add(new Point3D(currentAngle, minValueIndex, minValue));
                }
                else
                {
                    continue;
                }
            }

            #region // obsolete
            //}
            //else if (dimensionNumber == 2)
            //{
            //    for (int i = 0; i < dmFieldData.ColumnCount; i++)
            //    {
            //        DenseMatrix dmSlicedDataMatrix = (DenseMatrix)dmFieldData.SubMatrix(0, dmFieldData.RowCount, i, 1);
            //        DenseVector dvSlicedDataVector = DenseVector.OfEnumerable(dmSlicedDataMatrix.Values);
            //        dvSlicedDataVector.MapInplace(new Func<double, double>(x => (x == 0.0d) ? (1.0d) : (x)));
            //        double minValue = dvSlicedDataVector.Minimum();
            //        int minValueIndex = dvSlicedDataVector.MinimumIndex();
            //        dmFieldminimumsData[minValueIndex, i] = minValue;
            //    }
            //}
            #endregion // obsolete

            //return dmFieldminimumsData;
            return(lRetPoints);
        }
        /// <summary>
        /// Cartesians to polar.
        /// </summary>
        /// <param name="dmData">input densematrix data.</param>
        /// <param name="centerPoint">The center point of new polar system - in old cartesian coordinate system.</param>
        /// <param name="dmMask">The mask matrix.</param>
        /// <param name="angleGridNodesCount">The angle grid nodes count.</param>
        /// <returns>MathNet.Numerics.LinearAlgebra.Double.DenseMatrix.</returns>
        /// todo: регулировать размер сетки для свертки по гауссу
        public static DenseMatrix CartesianToPolar(DenseMatrix dmData, PointD centerPoint, DenseMatrix dmMask, int angleGridNodesCount = 144)
        {
            double angleValueDiff = 2 * Math.PI / (angleGridNodesCount - 1);



            DenseMatrix dmDistances = DenseMatrix.Create(dmData.RowCount, dmData.ColumnCount,
                                                         (r, c) => centerPoint.Distance(new PointD(c, r)));

            dmDistances = (DenseMatrix)dmDistances.PointwiseMultiply(dmMask);
            double      maxDistance        = dmDistances.Values.Maximum();
            int         distanceNodesCount = Convert.ToInt32(maxDistance) + 1;
            DenseMatrix dmCountOfElementsSummedToThePolarPointValue = DenseMatrix.Create(angleGridNodesCount,
                                                                                         distanceNodesCount, 0.0d);


            DenseMatrix dmAngles = DenseMatrix.Create(dmData.RowCount, dmData.ColumnCount,
                                                      (row, column) =>
            {
                double dx = (double)column - centerPoint.X;
                double dy = (double)row - centerPoint.Y;
                double r  = dmDistances[row, column];
                if (r == 0.0d)
                {
                    return(0.0d);
                }
                double cosPhi = dx / r;
                double phi    = Math.Acos(cosPhi);
                if (dy > 0)
                {
                    phi = 2.0d * Math.PI - phi;
                }
                return(phi);
            });

            dmAngles = (DenseMatrix)dmAngles.PointwiseMultiply(dmMask);


            DenseMatrix dmOutData = DenseMatrix.Create(angleGridNodesCount, distanceNodesCount, 0.0d);

            //Vector2D vCenterPoint = new Vector2D(centerPoint);
            //DenseMatrix dmSmoothed = dmData.Conv2(StandardConvolutionKernels.gauss, 7);
            //int cartesianRowCount = dmSmoothed.RowCount;
            //int cartesianColCount = dmSmoothed.ColumnCount;
            //DenseMatrix dmOutData = DenseMatrix.Create(angleGridNodesCount, distanceNodesCount, (row, col) =>
            //{
            //    PointPolar ptPolCurrPoint = new PointPolar((double) col, (double) row*angleValueDiff);
            //    PointD ptdCurrPoint = (ptPolCurrPoint.PointD() + vCenterPoint).ToPointD();
            //    int cartesianRow = Convert.ToInt32(ptdCurrPoint.Y);
            //    int cartesianCol = Convert.ToInt32(ptdCurrPoint.X);
            //    if ((cartesianRow < 0) || (cartesianRow >= cartesianRowCount) || (cartesianCol < 0) ||
            //        (cartesianCol >= cartesianColCount))
            //    {
            //        return 0.0d;
            //    }
            //    else
            //        return dmSmoothed[cartesianRow, cartesianCol];
            //});


            for (int cartesianRow = 0; cartesianRow < dmData.RowCount; cartesianRow++)
            {
                for (int cartesianCol = 0; cartesianCol < dmData.ColumnCount; cartesianCol++)
                {
                    double currAngle    = dmAngles[cartesianRow, cartesianCol];
                    double currDistance = dmDistances[cartesianRow, cartesianCol];
                    if (dmMask[cartesianRow, cartesianCol] == 0.0d)
                    {
                        continue;
                    }
                    int angleRow    = Convert.ToInt32(currAngle / angleValueDiff);
                    int distanceCol = Convert.ToInt32(currDistance);
                    dmOutData[angleRow, distanceCol] += dmData[cartesianRow, cartesianCol];
                    if (dmMask[cartesianRow, cartesianCol] > 0.0d)
                    {
                        dmCountOfElementsSummedToThePolarPointValue[angleRow, distanceCol] += 1.0d;
                    }
                }
            }

            dmCountOfElementsSummedToThePolarPointValue.MapInplace(x => (x == 0.0d) ? (0.0d) : (1.0d / x));

            dmOutData = (DenseMatrix)dmOutData.PointwiseMultiply(dmCountOfElementsSummedToThePolarPointValue);
            dmOutData.MapInplace(x => (x == 0.0d) ? (1.0d) : (x));


            //сгладим
            foreach (Tuple <int, MathNet.Numerics.LinearAlgebra.Vector <double> > tplRowVectorAndIndex in dmOutData.EnumerateRowsIndexed())
            {
                DenseVector currVector         = (DenseVector)tplRowVectorAndIndex.Item2;
                DenseVector currVectorSmoothed = currVector.Conv(StandardConvolutionKernels.gauss, 5);
                // и восстановим краевые значения
                for (int i = 0; i < 5; i++)
                {
                    currVectorSmoothed[i] = currVector[i];
                    currVectorSmoothed[currVectorSmoothed.Count - i - 1] = currVector[currVector.Count - i - 1];
                }

                dmOutData.SetRow(tplRowVectorAndIndex.Item1, currVectorSmoothed.ToArray());
            }


            return(dmOutData);
        }