Ejemplo n.º 1
0
        /// <summary>
        /// Algorithm to find a minimal bounding rectangle (MBR) such that the MBR corresponds to a rectangle
        /// with smallest possible area completely enclosing the polygon.
        /// <para>From 'A Fast Algorithm for Generating a Minimal Bounding Rectangle' by Lennert D. Den Boer.</para>
        /// </summary>
        /// <param name="polygon">
        /// Polygon P is assumed to be both simple and convex, and to contain no duplicate (coincident) vertices.
        /// The vertices of P are assumed to be in strict cyclic sequential order, either clockwise or
        /// counter-clockwise relative to the origin P0.
        /// </param>
        internal static PdfRectangle ParametricPerpendicularProjection(IReadOnlyList <PdfPoint> polygon)
        {
            if (polygon == null || polygon.Count == 0)
            {
                throw new ArgumentException("ParametricPerpendicularProjection(): polygon cannot be null and must contain at least one point.");
            }

            if (polygon.Count < 4)
            {
                if (polygon.Count == 1)
                {
                    return(new PdfRectangle(polygon[0], polygon[0]));
                }
                else if (polygon.Count == 2)
                {
                    return(new PdfRectangle(polygon[0], polygon[1]));
                }
                else
                {
                    PdfPoint p3 = polygon[0].Add(polygon[1].Subtract(polygon[2]));
                    return(new PdfRectangle(p3, polygon[1], polygon[0], polygon[2]));
                }
            }

            PdfPoint[] MBR = new PdfPoint[0];

            double Amin = double.MaxValue;
            double tmin = 1;
            double tmax = 0;
            double smax = 0;
            int    j    = 1;
            int    k    = 0;
            int    l    = -1;

            PdfPoint Q  = new PdfPoint();
            PdfPoint R0 = new PdfPoint();
            PdfPoint R1 = new PdfPoint();
            PdfPoint u  = new PdfPoint();

            int nv = polygon.Count;

            while (true)
            {
                var Pk = polygon[k];

                PdfPoint v = polygon[j].Subtract(Pk);
                double   r = 1.0 / v.DotProduct(v);

                for (j = 0; j < nv; j++)
                {
                    if (j == k)
                    {
                        continue;
                    }
                    PdfPoint Pj = polygon[j];
                    u = Pj.Subtract(Pk);
                    double   t  = u.DotProduct(v) * r;
                    PdfPoint Pt = new PdfPoint(t * v.X + Pk.X, t * v.Y + Pk.Y);
                    u = Pt.Subtract(Pj);
                    double s = u.DotProduct(u);

                    if (t < tmin)
                    {
                        tmin = t;
                        R0   = Pt;
                    }

                    if (t > tmax)
                    {
                        tmax = t;
                        R1   = Pt;
                    }

                    if (s > smax)
                    {
                        smax = s;
                        Q    = Pt;
                        l    = j;
                    }
                }

                if (l == -1)
                {
                    // All points are colinear - rectangle has no area (need more tests)
                    var bottomLeft = polygon.OrderBy(p => p.X).ThenBy(p => p.Y).First();
                    var topRight   = polygon.OrderByDescending(p => p.Y).OrderByDescending(p => p.X).First();
                    return(new PdfRectangle(bottomLeft, topRight, bottomLeft, topRight));
                }

                PdfPoint PlMinusQ = polygon[l].Subtract(Q);
                PdfPoint R2       = R1.Add(PlMinusQ);
                PdfPoint R3       = R0.Add(PlMinusQ);
                u = R1.Subtract(R0);
                double A = u.DotProduct(u) * smax;

                if (A < Amin)
                {
                    Amin = A;
                    MBR  = new[] { R0, R1, R2, R3 };
                }

                k++;
                j = k;

                if (j == nv)
                {
                    j = 0;
                }

                if (k == nv)
                {
                    break;
                }
            }

            return(new PdfRectangle(MBR[2], MBR[3], MBR[1], MBR[0]));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Algorithm to find a minimal bounding rectangle (MBR) such that the MBR corresponds to a rectangle
        /// with smallest possible area completely enclosing the polygon.
        /// <para>From 'A Fast Algorithm for Generating a Minimal Bounding Rectangle' by Lennert D. Den Boer.</para>
        /// </summary>
        /// <param name="polygon">
        /// Polygon P is assumed to be both simple and convex, and to contain no duplicate (coincident) vertices.
        /// The vertices of P are assumed to be in strict cyclic sequential order, either clockwise or
        /// counter-clockwise relative to the origin P0.
        /// </param>
        private static PdfRectangle ParametricPerpendicularProjection(IReadOnlyList <PdfPoint> polygon)
        {
            if (polygon == null || polygon.Count == 0)
            {
                throw new ArgumentException("ParametricPerpendicularProjection(): polygon cannot be null and must contain at least one point.", nameof(polygon));
            }
            else if (polygon.Count == 1)
            {
                return(new PdfRectangle(polygon[0], polygon[0]));
            }
            else if (polygon.Count == 2)
            {
                return(new PdfRectangle(polygon[0], polygon[1]));
            }

            PdfPoint[] MBR = new PdfPoint[0];

            double Amin = double.PositiveInfinity;
            int    j    = 1;
            int    k    = 0;

            PdfPoint Q  = new PdfPoint();
            PdfPoint R0 = new PdfPoint();
            PdfPoint R1 = new PdfPoint();
            PdfPoint u  = new PdfPoint();

            while (true)
            {
                PdfPoint Pk = polygon[k];
                PdfPoint v  = polygon[j].Subtract(Pk);
                double   r  = 1.0 / v.DotProduct(v);

                double tmin = 1;
                double tmax = 0;
                double smax = 0;
                int    l    = -1;

                for (j = 0; j < polygon.Count; j++)
                {
                    PdfPoint Pj = polygon[j];
                    u = Pj.Subtract(Pk);
                    double   t  = u.DotProduct(v) * r;
                    PdfPoint Pt = new PdfPoint(t * v.X + Pk.X, t * v.Y + Pk.Y);
                    u = Pt.Subtract(Pj);
                    double s = u.DotProduct(u);

                    if (t < tmin)
                    {
                        tmin = t;
                        R0   = Pt;
                    }

                    if (t > tmax)
                    {
                        tmax = t;
                        R1   = Pt;
                    }

                    if (s > smax)
                    {
                        smax = s;
                        Q    = Pt;
                        l    = j;
                    }
                }

                if (l != -1)
                {
                    PdfPoint PlMinusQ = polygon[l].Subtract(Q);
                    PdfPoint R2       = R1.Add(PlMinusQ);
                    PdfPoint R3       = R0.Add(PlMinusQ);

                    u = R1.Subtract(R0);

                    double A = u.DotProduct(u) * smax;

                    if (A < Amin)
                    {
                        Amin = A;
                        MBR  = new[] { R0, R1, R2, R3 };
                    }
                }

                k++;
                j = k + 1;

                if (j == polygon.Count)
                {
                    j = 0;
                }
                if (k == polygon.Count)
                {
                    break;
                }
            }

            return(new PdfRectangle(MBR[2], MBR[3], MBR[1], MBR[0]));
        }