GetFurthestPointsFromLine() public static method

Find two furthest points from the specified line.

The method finds two furthest points from the specified line, where one point is on one side from the line and the second point is on another side from the line.

public static GetFurthestPointsFromLine ( IEnumerable cloud, IntPoint linePoint1, IntPoint linePoint2, IntPoint &furthestPoint1, IntPoint &furthestPoint2 ) : void
cloud IEnumerable Collection of points to search furthest points in.
linePoint1 AForge.IntPoint First point forming the line.
linePoint2 AForge.IntPoint Second point forming the line.
furthestPoint1 AForge.IntPoint First found furthest point.
furthestPoint2 AForge.IntPoint Second found furthest point (which is on the /// opposite side from the line compared to the );
return void
Example #1
0
        /// <summary>
        /// Find corners of quadrilateral or triangular area, which contains the specified collection of points.
        /// </summary>
        ///
        /// <param name="cloud">Collection of points to search quadrilateral for.</param>
        ///
        /// <returns>Returns a list of 3 or 4 points, which are corners of the quadrilateral or
        /// triangular area filled by specified collection of point. The first point in the list
        /// is the point with lowest X coordinate (and with lowest Y if there are several points
        /// with the same X value). The corners are provided in counter clockwise order
        /// (<a href="http://en.wikipedia.org/wiki/Cartesian_coordinate_system">Cartesian
        /// coordinate system</a>).</returns>
        ///
        /// <remarks><para>The method makes an assumption that the specified collection of points
        /// form some sort of quadrilateral/triangular area. With this assumption it tries to find corners
        /// of the area.</para>
        ///
        /// <para><note>The method does not search for <b>bounding</b> quadrilateral/triangular area,
        /// where all specified points are <b>inside</b> of the found quadrilateral/triangle. Some of the
        /// specified points potentially may be outside of the found quadrilateral/triangle, since the
        /// method takes corners only from the specified collection of points, but does not calculate such
        /// to form true bounding quadrilateral/triangle.</note></para>
        ///
        /// <para>See <see cref="QuadrilateralRelativeDistortionLimit"/> property for additional information.</para>
        /// </remarks>
        ///
        public static List <IntPoint> FindQuadrilateralCorners(IEnumerable <IntPoint> cloud)
        {
            // quadrilateral's corners
            List <IntPoint> corners = new List <IntPoint>( );

            // get bounding rectangle of the points list
            IntPoint minXY, maxXY;

            PointsCloud.GetBoundingRectangle(cloud, out minXY, out maxXY);
            // get cloud's size
            IntPoint cloudSize = maxXY - minXY;
            // calculate center point
            IntPoint center = minXY + cloudSize / 2;
            // acceptable deviation limit
            float distortionLimit = quadrilateralRelativeDistortionLimit * (cloudSize.X + cloudSize.Y) / 2;

            // get the furthest point from (0,0)
            IntPoint point1 = PointsCloud.GetFurthestPoint(cloud, center);
            // get the furthest point from the first point
            IntPoint point2 = PointsCloud.GetFurthestPoint(cloud, point1);

            corners.Add(point1);
            corners.Add(point2);

            // get two furthest points from line
            IntPoint point3, point4;
            float    distance3, distance4;

            PointsCloud.GetFurthestPointsFromLine(cloud, point1, point2,
                                                  out point3, out distance3, out point4, out distance4);

            // ideally points 1 and 2 form a diagonal of the
            // quadrilateral area, and points 3 and 4 form another diagonal

            // but if one of the points (3 or 4) is very close to the line
            // connecting points 1 and 2, then it is one the same line ...
            // which means corner was not found.
            // in this case we deal with a trapezoid or triangle, where
            // (1-2) line is one of it sides.

            // another interesting case is when both points (3) and (4) are
            // very close the (1-2) line. in this case we may have just a flat
            // quadrilateral.

            if (
                ((distance3 >= distortionLimit) && (distance4 >= distortionLimit)) ||

                ((distance3 < distortionLimit) && (distance3 != 0) &&
                 (distance4 < distortionLimit) && (distance4 != 0)))
            {
                // don't add one of the corners, if the point is already in the corners list
                // (this may happen when both #3 and #4 points are very close to the line
                // connecting #1 and #2)
                if (!corners.Contains(point3))
                {
                    corners.Add(point3);
                }
                if (!corners.Contains(point4))
                {
                    corners.Add(point4);
                }
            }
            else
            {
                // it seems that we deal with kind of trapezoid,
                // where point 1 and 2 are on the same edge

                IntPoint tempPoint = (distance3 > distance4) ? point3 : point4;

                // try to find 3rd point
                PointsCloud.GetFurthestPointsFromLine(cloud, point1, tempPoint,
                                                      out point3, out distance3, out point4, out distance4);

                bool thirdPointIsFound = false;

                if ((distance3 >= distortionLimit) && (distance4 >= distortionLimit))
                {
                    if (point4.DistanceTo(point2) > point3.DistanceTo(point2))
                    {
                        point3 = point4;
                    }

                    thirdPointIsFound = true;
                }
                else
                {
                    PointsCloud.GetFurthestPointsFromLine(cloud, point2, tempPoint,
                                                          out point3, out distance3, out point4, out distance4);

                    if ((distance3 >= distortionLimit) && (distance4 >= distortionLimit))
                    {
                        if (point4.DistanceTo(point1) > point3.DistanceTo(point1))
                        {
                            point3 = point4;
                        }

                        thirdPointIsFound = true;
                    }
                }

                if (!thirdPointIsFound)
                {
                    // failed to find 3rd edge point, which is away enough from the temp point.
                    // this means that the clound looks more like triangle
                    corners.Add(tempPoint);
                }
                else
                {
                    corners.Add(point3);

                    // try to find 4th point
                    float tempDistance;

                    PointsCloud.GetFurthestPointsFromLine(cloud, point1, point3,
                                                          out tempPoint, out tempDistance, out point4, out distance4);

                    if ((distance4 >= distortionLimit) && (tempDistance >= distortionLimit))
                    {
                        if (tempPoint.DistanceTo(point2) > point4.DistanceTo(point2))
                        {
                            point4 = tempPoint;
                        }
                    }
                    else
                    {
                        PointsCloud.GetFurthestPointsFromLine(cloud, point2, point3,
                                                              out tempPoint, out tempDistance, out point4, out distance4);

                        if ((tempPoint.DistanceTo(point1) > point4.DistanceTo(point1)) &&
                            (tempPoint != point2) && (tempPoint != point3))
                        {
                            point4 = tempPoint;
                        }
                    }

                    if ((point4 != point1) && (point4 != point2) && (point4 != point3))
                    {
                        corners.Add(point4);
                    }
                }
            }

            // put the point with lowest X as the first
            for (int i = 1, n = corners.Count; i < n; i++)
            {
                if ((corners[i].X < corners[0].X) ||
                    ((corners[i].X == corners[0].X) && (corners[i].Y < corners[0].Y)))
                {
                    IntPoint temp = corners[i];
                    corners[i] = corners[0];
                    corners[0] = temp;
                }
            }


            // sort other points in counter clockwise order
            float k1 = (corners[1].X != corners[0].X) ?
                       ((float)(corners[1].Y - corners[0].Y) / (corners[1].X - corners[0].X)) :
                       ((corners[1].Y > corners[0].Y) ? float.PositiveInfinity : float.NegativeInfinity);

            float k2 = (corners[2].X != corners[0].X) ?
                       ((float)(corners[2].Y - corners[0].Y) / (corners[2].X - corners[0].X)) :
                       ((corners[2].Y > corners[0].Y) ? float.PositiveInfinity : float.NegativeInfinity);

            if (k2 < k1)
            {
                IntPoint temp = corners[1];
                corners[1] = corners[2];
                corners[2] = temp;

                float tk = k1;
                k1 = k2;
                k2 = tk;
            }

            if (corners.Count == 4)
            {
                float k3 = (corners[3].X != corners[0].X) ?
                           ((float)(corners[3].Y - corners[0].Y) / (corners[3].X - corners[0].X)) :
                           ((corners[3].Y > corners[0].Y) ? float.PositiveInfinity : float.NegativeInfinity);

                if (k3 < k1)
                {
                    IntPoint temp = corners[1];
                    corners[1] = corners[3];
                    corners[3] = temp;

                    float tk = k1;
                    k1 = k3;
                    k3 = tk;
                }
                if (k3 < k2)
                {
                    IntPoint temp = corners[2];
                    corners[2] = corners[3];
                    corners[3] = temp;

                    float tk = k2;
                    k2 = k3;
                    k3 = tk;
                }
            }

            return(corners);
        }