GetBoundingRectangle() public static method

Get bounding rectangle of the specified list of points.
public static GetBoundingRectangle ( IEnumerable cloud, IntPoint &minXY, IntPoint &maxXY ) : void
cloud IEnumerable Collection of points to get bounding rectangle for.
minXY AForge.IntPoint Point comprised of smallest X and Y coordinates.
maxXY AForge.IntPoint Point comprised of biggest X and Y coordinates.
return void
Beispiel #1
0
        /// <summary>
        /// Check if the specified set of points form a circle shape.
        /// </summary>
        ///
        /// <param name="edgePoints">Shape's points to check.</param>
        /// <param name="center">Receives circle's center on successful return.</param>
        /// <param name="radius">Receives circle's radius on successful return.</param>
        ///
        /// <returns>Returns <see langword="true"/> if the specified set of points form a
        /// circle shape or <see langword="false"/> otherwise.</returns>
        ///
        /// <remarks><para><note>Circle shape must contain at least 8 points to be recognized.
        /// The method returns <see langword="false"/> always, of number of points in the specified
        /// shape is less than 8.</note></para></remarks>
        ///
        public bool IsCircle(List <IntPoint> edgePoints, out Point center, out float radius)
        {
            // make sure we have at least 8 points for curcle shape
            if (edgePoints.Count < 8)
            {
                center = new Point(0, 0);
                radius = 0;
                return(false);
            }

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

            PointsCloud.GetBoundingRectangle(edgePoints, out minXY, out maxXY);
            // get cloud's size
            IntPoint cloudSize = maxXY - minXY;

            // calculate center point
            center = minXY + (Point)cloudSize / 2;

            radius = ((float)cloudSize.X + cloudSize.Y) / 4;

            // calculate mean distance between provided edge points and estimated circle’s edge
            float meanDistance = 0;

            for (int i = 0, n = edgePoints.Count; i < n; i++)
            {
                meanDistance += (float)Math.Abs(center.DistanceTo(edgePoints[i]) - radius);
            }
            meanDistance /= edgePoints.Count;

            float maxDitance = Math.Max(minAcceptableDistortion,
                                        ((float)cloudSize.X + cloudSize.Y) / 2 * relativeDistortionLimit);

            return(meanDistance <= maxDitance);
        }
Beispiel #2
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);
        }
Beispiel #3
0
        /// <summary>
        /// Check if a shape specified by the set of points fits a convex polygon
        /// specified by the set of corners.
        /// </summary>
        ///
        /// <param name="edgePoints">Shape's points to check.</param>
        /// <param name="corners">Corners of convex polygon to check fitting into.</param>
        ///
        /// <returns>Returns <see langword="true"/> if the specified shape fits
        /// the specified convex polygon or <see langword="false"/> otherwise.</returns>
        ///
        /// <remarks><para>The method checks if the set of specified points form the same shape
        /// as the set of provided corners.</para></remarks>
        ///
        public bool CheckIfPointsFitShape(List <IntPoint> edgePoints, List <IntPoint> corners)
        {
            int cornersCount = corners.Count;

            // lines coefficients (for representation as y(x)=k*x+b)
            float[] k      = new float[cornersCount];
            float[] b      = new float[cornersCount];
            float[] div    = new float[cornersCount]; // precalculated divisor
            bool[]  isVert = new bool[cornersCount];

            for (int i = 0; i < cornersCount; i++)
            {
                IntPoint currentPoint = corners[i];
                IntPoint nextPoint    = (i + 1 == cornersCount) ? corners[0] : corners[i + 1];

                if (!(isVert[i] = nextPoint.X == currentPoint.X))
                {
                    k[i]   = (float)(nextPoint.Y - currentPoint.Y) / (nextPoint.X - currentPoint.X);
                    b[i]   = currentPoint.Y - k[i] * currentPoint.X;
                    div[i] = (float)Math.Sqrt(k[i] * k[i] + 1);
                }
            }

            // calculate distances between edge points and polygon sides
            float meanDistance = 0;

            for (int i = 0, n = edgePoints.Count; i < n; i++)
            {
                float minDistance = float.MaxValue;

                for (int j = 0; j < cornersCount; j++)
                {
                    float distance = 0;

                    if (!isVert[j])
                    {
                        distance = (float)Math.Abs((k[j] * edgePoints[i].X + b[j] - edgePoints[i].Y) / div[j]);
                    }
                    else
                    {
                        distance = Math.Abs(edgePoints[i].X - corners[j].X);
                    }

                    if (distance < minDistance)
                    {
                        minDistance = distance;
                    }
                }

                meanDistance += minDistance;
            }
            meanDistance /= edgePoints.Count;

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

            PointsCloud.GetBoundingRectangle(corners, out minXY, out maxXY);
            IntPoint rectSize = maxXY - minXY;

            float maxDitance = Math.Max(minAcceptableDistortion,
                                        ((float)rectSize.X + rectSize.Y) / 2 * relativeDistortionLimit);

            return(meanDistance <= maxDitance);
        }
Beispiel #4
0
        /// <summary>
        /// Check sub type of a convex polygon.
        /// </summary>
        ///
        /// <param name="corners">Corners of the convex polygon to check.</param>
        ///
        /// <returns>Return detected sub type of the specified shape.</returns>
        ///
        /// <remarks><para>The method check corners of a convex polygon detecting
        /// its subtype. Polygon's corners are usually retrieved using <see cref="IsConvexPolygon"/>
        /// method, but can be any list of 3-4 points (only sub types of triangles and
        /// quadrilateral are checked).</para>
        ///
        /// <para>See <see cref="AngleError"/> and <see cref="LengthError"/> properties,
        /// which set acceptable errors for polygon sub type checking.</para>
        /// </remarks>
        ///
        public PolygonSubType CheckPolygonSubType(List <IntPoint> corners)
        {
            PolygonSubType subType = PolygonSubType.Unknown;

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

            PointsCloud.GetBoundingRectangle(corners, out minXY, out maxXY);
            // get cloud's size
            IntPoint cloudSize = maxXY - minXY;

            float maxLengthDiff = lengthError * (cloudSize.X + cloudSize.Y) / 2;

            if (corners.Count == 3)
            {
                // get angles of the triangle
                float angle1 = GeometryTools.GetAngleBetweenVectors(corners[0], corners[1], corners[2]);
                float angle2 = GeometryTools.GetAngleBetweenVectors(corners[1], corners[2], corners[0]);
                float angle3 = GeometryTools.GetAngleBetweenVectors(corners[2], corners[0], corners[1]);

                // check for equilateral triangle
                if ((Math.Abs(angle1 - 60) <= angleError) &&
                    (Math.Abs(angle2 - 60) <= angleError) &&
                    (Math.Abs(angle3 - 60) <= angleError))
                {
                    subType = PolygonSubType.EquilateralTriangle;
                }
                else
                {
                    // check for isosceles triangle
                    if ((Math.Abs(angle1 - angle2) <= angleError) ||
                        (Math.Abs(angle2 - angle3) <= angleError) ||
                        (Math.Abs(angle3 - angle1) <= angleError))
                    {
                        subType = PolygonSubType.IsoscelesTriangle;
                    }

                    // check for rectangled triangle
                    if ((Math.Abs(angle1 - 90) <= angleError) ||
                        (Math.Abs(angle2 - 90) <= angleError) ||
                        (Math.Abs(angle3 - 90) <= angleError))
                    {
                        subType = (subType == PolygonSubType.IsoscelesTriangle) ?
                                  PolygonSubType.RectangledIsoscelesTriangle : PolygonSubType.RectangledTriangle;
                    }
                }
            }
            else if (corners.Count == 4)
            {
                // get angles between 2 pairs of opposite sides
                float angleBetween1stPair = GeometryTools.GetAngleBetweenLines(corners[0], corners[1], corners[2], corners[3]);
                float angleBetween2ndPair = GeometryTools.GetAngleBetweenLines(corners[1], corners[2], corners[3], corners[0]);

                // check 1st pair for parallelism
                if (angleBetween1stPair <= angleError)
                {
                    subType = PolygonSubType.Trapezoid;

                    // check 2nd pair for parallelism
                    if (angleBetween2ndPair <= angleError)
                    {
                        subType = PolygonSubType.Parallelogram;

                        // check angle between adjacent sides
                        if (Math.Abs(GeometryTools.GetAngleBetweenVectors(corners[1], corners[0], corners[2]) - 90) <= angleError)
                        {
                            subType = PolygonSubType.Rectangle;
                        }

                        // get length of 2 adjacent sides
                        float side1Length = (float)corners[0].DistanceTo(corners[1]);
                        float side2Length = (float)corners[0].DistanceTo(corners[3]);

                        if (Math.Abs(side1Length - side2Length) <= maxLengthDiff)
                        {
                            subType = (subType == PolygonSubType.Parallelogram) ?
                                      PolygonSubType.Rhombus : PolygonSubType.Square;
                        }
                    }
                }
                else
                {
                    // check 2nd pair for parallelism - last chence to detect trapezoid
                    if (angleBetween2ndPair <= angleError)
                    {
                        subType = PolygonSubType.Trapezoid;
                    }
                }
            }

            return(subType);
        }