Exemple #1
0
        /**
         * Evaluates the plane where all points are contained. If it does not exist, it returns {@code null}.
         */
        public static Plane3d Plane(IList <Point3d> points, bool robust = true, double epsilon = MathUtils.EPSILON)
        {
            if (points.Count < 3)
            {
                // Poligono degenerado.
                return(null);
            }

            IPolyEnumerator <Point3d> eFirst = NewEnumerator(points, 0, robust, epsilon);
            IPolyEnumerator <Point3d> e1     = eFirst.Clone();

            IPolyEnumerator <Point3d> e2 = e1.Clone();

            e2.Next();
            if (e2.Equals(eFirst))
            {
                // Poligono degenerado.
                return(null);
            }

            IPolyEnumerator <Point3d> e3 = e2.Clone();

            e3.Next();
            while (!e3.Equals(eFirst) && AlignmentPoints(e1.Point, e2.Point, e3.Point))
            {
                e3.Next();
            }
            if (e3.Equals(eFirst))
            {
                // Poligono degenerado.
                return(null);
            }

            Plane3d plane = Plane3d.NewOrthonormal(e1.Point, e2.Point, e3.Point);

            IPolyEnumerator <Point3d> e4 = e3.Clone();

            e4.Next();
            while (!e4.Equals(eFirst))
            {
                if (plane.WhichSide(e4.Point) != PlaneSide.Middle)
                {
                    // Se ha encontrado un punto que no esta en el plano.
                    return(null);
                }

                e4.Next();
            }

            // Se ha terminado correctamente.
            return(plane);
        }
Exemple #2
0
        /**
         * Area del poligono con signo.
         * <p>
         * {@link http://paulbourke.net/geometry/polyarea/}
         *
         * @param points Puntos del poligono.
         * @return Area (con signo).
         */
        public static double SignedArea(IList <Point2d> points, bool robust = true, double epsilon = MathUtils.EPSILON)
        {
            if (points.Count < 3)
            {
                return(0);
            }

            double area = 0;

            IPolyEnumerator <Point2d> eFirst = NewEnumerator(points, 0, robust, epsilon);
            IPolyEnumerator <Point2d> e      = eFirst.Clone();

            IPolyEnumerator <Point2d> eNext = e.Clone();

            eNext.Next();
            if (eNext.Equals(eFirst))
            {
                return(0);
            }

            do
            {
                area += e.Point.X * eNext.Point.Y - e.Point.Y * eNext.Point.X;
                e.Next();
                eNext.Next();
            }while (!e.Equals(eFirst));

            return(area / 2);
        }
Exemple #3
0
        /**
         * Indica si el punto está en el borde del poligono.
         */
        public static bool PointInEdge(IList <Point2d> points, Point2d p, bool robust = true, double epsilon = MathUtils.EPSILON)
        {
            double epsilon2 = epsilon * epsilon;

            DistPointSegment2 dist = new DistPointSegment2();

            dist.Point = p;

            IPolyEnumerator <Point2d> eFirst = NewEnumerator(points, 0, robust, epsilon);
            IPolyEnumerator <Point2d> e      = eFirst.Clone();

            IPolyEnumerator <Point2d> eNext = e.Clone();

            eNext.Next();
            if (eNext.Equals(eFirst))
            {
                return(false);
            }

            do
            {
                dist.Segment = new Segment2(e.Point, eNext.Point);
                if (dist.CalcDistance2().EpsilonEquals(0, epsilon2))
                {
                    return(true);
                }

                e.Next();
                eNext.Next();
            }while (!e.Equals(eFirst));

            return(false);
        }
Exemple #4
0
        /**
         * This method tests the orientation of a simple polygon.
         * <p>
         * {@link http://geometryalgorithms.com/Archive/algorithm_0101/algorithm_0101.htm#orientation2D_polygon()}
         * {@link http://geomalgorithms.com/a01-_area.html#orientation2D_polygon%28%29}
         */
        public static Orientation TestOrientation(IList <Point2d> points, bool robust = true, double epsilon = MathUtils.EPSILON)
        {
            int n = points.Count;

            if (n < 3)
            {
                return(Orientation.Degenerate);
            }

            // first find leftmost lowest vertex of the polygon
            int index = FindLeftMost(points, epsilon);
            IPolyEnumerator <Point2d> e = NewEnumerator(points, index, robust, epsilon);

            // test orientation at leftmost vertex
            // ccw <=> the edge leaving is left of the entering edge
            IPolyEnumerator <Point2d> eNext = e.Clone();

            eNext.Next();
            if (eNext.Equals(e))
            {
                return(Orientation.Degenerate);
            }

            IPolyEnumerator <Point2d> ePrev = e.Clone();

            ePrev.Prev();
            if (ePrev.Equals(e))
            {
                return(Orientation.Degenerate);
            }

            switch (Point2d.WhichSide(ePrev.Point, e.Point, eNext.Point))
            {
            case LineSide.Middle:
                return(Orientation.Degenerate);

            case LineSide.Left:
                return(Orientation.CCW);

            case LineSide.Right:
                return(Orientation.CW);

            default:
                throw new IndexOutOfRangeException();
            }

            // Another algorithms:
            // http://www.easywms.com/easywms/?q=en/node/3602
            // http://paulbourke.net/geometry/clockwise/
            // http://paulbourke.net/geometry/polygonmesh/
            //
            // http://www.easywms.com/easywms/?q=en/node/3602
            // http://paulbourke.net/geometry/clockwise/
            // http://paulbourke.net/geometry/polygonmesh/
        }
Exemple #5
0
        /**
         * Indica si un poligo es convexo. Da problemas con poligonos que contengan vertices repetidos.
         */
        public static bool IsConvex(IList <Point2d> points, bool robust = true, double epsilon = MathUtils.EPSILON)
        {
            if (points.Count < 3)
            {
                return(false);
            }

            // Indicadores de giro.
            bool leftTurn = false, rightTurn = false;

            IPolyEnumerator <Point2d> eFirst = NewEnumerator(points, 0, robust, epsilon);
            IPolyEnumerator <Point2d> e1 = eFirst.Clone();

            IPolyEnumerator <Point2d> e2 = e1.Clone();

            e2.Next();
            if (e2.Equals(eFirst))
            {
                return(false);
            }

            IPolyEnumerator <Point2d> e3 = e2.Clone();

            e3.Next();
            if (e3.Equals(eFirst))
            {
                return(false);
            }

            do
            {
                switch (Point2d.WhichSide(e1.Point, e2.Point, e3.Point))
                {
                case LineSide.Left:
                    leftTurn = true;
                    break;

                case LineSide.Right:
                    rightTurn = true;
                    break;
                }

                // Si se ha girado a izquierda y derecha, no es convexo.
                if (leftTurn && rightTurn)
                {
                    return(false);
                }

                e1.Next();
                e2.Next();
                e3.Next();
            }while (!e1.Equals(eFirst));

            // Si no se ha encontrado giro, caso degenerado.
            if (!leftTurn && !rightTurn)
            {
                return(false);
            }

            return(true);
        }
Exemple #6
0
        /**
         * Winding number test for a point in a polygon. http://geomalgorithms.com/a03-_inclusion.html
         * <ul>
         * <li>non extendedAlgorithm: Points on a right-side boundary edge being outside, and ones on a left-side edge being inside.</li>
         * <li>extendedAlgorithm: This algorithm differenciates between inside/outside/on the polygon.<li>
         * </ul>
         */
        public static PointInPoly PointInPolyNonZero(IList <Point2d> points, Point2d p, bool extendedAlgorithm, bool robust = true, double epsilon = MathUtils.EPSILON)
        {
            // the winding number counter
            int wn = 0;

            IPolyEnumerator <Point2d> eFirst = NewEnumerator(points, 0, robust, epsilon);
            IPolyEnumerator <Point2d> e      = eFirst.Clone();

            IPolyEnumerator <Point2d> eNext = e.Clone();

            eNext.Next();
            if (eNext.Equals(eFirst))
            {
                return(PointInPoly.Outside);
            }

            // loop through all edges of the polygon
            do
            {
                // Segmento ab.
                Point2d a = e.Point;
                Point2d b = eNext.Point;

                if (extendedAlgorithm)
                {
                    // Horizontal line.
                    if (a.Y.EpsilonEquals(b.Y, epsilon))
                    {
                        if (p.Y.EpsilonEquals(a.Y, epsilon))
                        {
                            double min, max;
                            if (a.X < b.X)
                            {
                                min = a.X;
                                max = b.X;
                            }
                            else
                            {
                                min = b.X;
                                max = a.X;
                            }

                            if (p.X.EpsilonBetweenClosed(min, max, epsilon))
                            {
                                return(PointInPoly.On);
                            }
                        }
                        // No se cuenta.
                        continue;
                    }
                }

                if (p.Y.EpsilonGE(a.Y, epsilon))
                {
                    // an upward crossing
                    if (p.Y.EpsilonL(b.Y, epsilon))
                    {
                        // P left of edge
                        switch (Point2d.WhichSide(a, b, p, epsilon))
                        {
                        case LineSide.Left:
                            // have a valid up intersect
                            wn++;
                            break;

                        case LineSide.Middle:
                            if (extendedAlgorithm)
                            {
                                return(PointInPoly.On);
                            }
                            break;
                        }
                    }
                }
                else // if (p.Y.EpsilonL(a.Y, epsilon))
                {
                    // a downward crossing
                    if (p.Y.EpsilonGE(b.Y, epsilon))
                    {
                        // P right of edge
                        switch (Point2d.WhichSide(a, b, p, epsilon))
                        {
                        case LineSide.Right:
                            // have a valid down intersect
                            wn--;
                            break;

                        case LineSide.Middle:
                            if (extendedAlgorithm)
                            {
                                return(PointInPoly.On);
                            }
                            break;
                        }
                    }
                }

                e.Next();
                eNext.Next();
            }while (!e.Equals(eFirst));

            // == 0 only if P is outside
            return((wn != 0) ? PointInPoly.Inside : PointInPoly.Outside);
        }
Exemple #7
0
        /**
         * Crossing number test for a point in a polygon. http://geomalgorithms.com/a03-_inclusion.html
         * <ul>
         * <li>non extendedAlgorithm: Points on a right-side boundary edge being outside, and ones on a left-side edge being inside.</li>
         * <li>extendedAlgorithm: This algorithm differenciates between inside/outside/on the polygon.<li>
         * </ul>
         */
        public static PointInPoly PointInPolyEvenOdd(IList <Point2d> points, Point2d p, bool extendedAlgorithm, bool robust = true, double epsilon = MathUtils.EPSILON)
        {
            // the crossing number counter
            int cn = 0;

            IPolyEnumerator <Point2d> eFirst = NewEnumerator(points, 0, robust, epsilon);
            IPolyEnumerator <Point2d> e      = eFirst.Clone();

            IPolyEnumerator <Point2d> eNext = e.Clone();

            eNext.Next();
            if (eNext.Equals(eFirst))
            {
                return(PointInPoly.Outside);
            }

            // loop through all edges of the polygon
            do
            {
                // Segmento ab.
                Point2d a = e.Point;
                Point2d b = eNext.Point;

                if (extendedAlgorithm)
                {
                    // Horizontal line.
                    if (a.Y.EpsilonEquals(b.Y, epsilon))
                    {
                        if (p.Y.EpsilonEquals(a.Y, epsilon))
                        {
                            double min, max;
                            if (a.X < b.X)
                            {
                                min = a.X;
                                max = b.X;
                            }
                            else
                            {
                                min = b.X;
                                max = a.X;
                            }

                            if (p.X.EpsilonBetweenClosed(min, max, epsilon))
                            {
                                return(PointInPoly.On);
                            }
                        }
                        // No se cuenta.
                        continue;
                    }
                }

                if ((p.Y.EpsilonGE(a.Y, epsilon))
                    ? (p.Y.EpsilonL(b.Y, epsilon))   // an upward crossing
                    : (p.Y.EpsilonGE(b.Y, epsilon))) // a downward crossing
                {
                    // compute the actual edge-ray intersect x-coordinate
                    double vt = (p.Y - a.Y) / (b.Y - a.Y);
                    double x  = a.X + vt * (b.X - a.X);

                    if (p.X.EpsilonEquals(x, epsilon))
                    {
                        if (extendedAlgorithm)
                        {
                            return(PointInPoly.On);
                        }
                    }
                    else if (p.X.EpsilonL(x, epsilon))
                    {
                        // a valid crossing of y=P.Y right of P.X
                        cn++;
                    }
                }

                e.Next();
                eNext.Next();
            }while (!e.Equals(eFirst));

            // 0 = outside, 1 = inside
            // 0 if even (out), and 1 if odd (in)
            return(((cn & 1) == 1) ? PointInPoly.Inside : PointInPoly.Outside);
        }
Exemple #8
0
        public static PolyChains Sort(IList <Point2d> points, bool robust = true, double epsilon = MathUtils.EPSILON)
        {
            PolyChains pchains = new PolyChains(points);

            // NOTE: it is not necessary to find the leftmost point. It is enough with finding the start of a chain.
            int leftMost = FindLeftMost(points, epsilon);

            pchains.LeftMost = leftMost;

            IPolyEnumerator <Point2d> eFirst = NewEnumerator(points, leftMost, robust, epsilon);
            IPolyEnumerator <Point2d> e      = eFirst.Clone();

            IPolyEnumerator <Point2d> eNext = e.Clone();

            eNext.Next();
            if (eNext.Equals(eFirst))
            {
            }

            IPolyEnumerator <Point2d> first = e.Clone();
            bool?      leftRight            = null;
            bool?      bottomTop            = null;
            List <int> inflectionYPoints    = new List <int>();

            do
            {
                Point2d p     = e.Point;
                Point2d pNext = eNext.Point;
                {
                    bool?nextBT = null;
                    if (pNext.Y.EpsilonG(p.Y))
                    {
                        nextBT = true;
                    }
                    else if (pNext.Y.EpsilonL(p.Y))
                    {
                        nextBT = false;
                    }

                    if (bottomTop == null)
                    {
                        bottomTop = nextBT;
                    }
                    else
                    {
                        if ((nextBT != null) && (bottomTop != nextBT))
                        {
                            inflectionYPoints.Add(e.Index);
                        }
                    }
                }

                {
                    bool?nextLR = null;
                    if (pNext.X.EpsilonG(p.X))
                    {
                        nextLR = true;
                    }
                    else if (pNext.X.EpsilonL(p.X))
                    {
                        nextLR = false;
                    }

                    if (leftRight == null)
                    {
                        leftRight = nextLR;
                    }
                    else
                    {
                        if ((nextLR != null) && (leftRight != nextLR))
                        {
                            pchains.AddChain((bool)leftRight, first, e, inflectionYPoints);

                            first     = e.Clone();
                            leftRight = null;
                            bottomTop = null;
                            inflectionYPoints.Clear();
                        }
                    }
                }

                e.Next();
                eNext.Next();
            }while (!e.Equals(eFirst));

            if (!first.Equals(e))
            {
                pchains.AddChain((leftRight ?? true), first, e, inflectionYPoints);
            }
            return(pchains);

            /*for (int i = 1; i < points.Count + 1; i++)
             * {
             *  Point2d pprev = points[(leftMost + i - 1) % points.Count];
             *  Point2d p = points[(leftMost + i) % points.Count];
             *
             *  {
             *      bool? nextBT = null;
             *      if (p.Y.EpsilonG(pprev.Y))
             *      {
             *          nextBT = true;
             *      }
             *      else if (p.Y.EpsilonL(pprev.Y))
             *      {
             *          nextBT = false;
             *      }
             *
             *      if (bottomTop == null)
             *      {
             *          bottomTop = nextBT;
             *      }
             *      else
             *      {
             *          if ((nextBT != null) && (bottomTop != nextBT))
             *          {
             *              inflectionYPoints.Add(leftMost + i);
             *          }
             *      }
             *  }
             *
             *  {
             *      bool? nextLR = null;
             *      if (p.X.EpsilonG(pprev.X))
             *      {
             *          nextLR = true;
             *      }
             *      else if (p.X.EpsilonL(pprev.X))
             *      {
             *          nextLR = false;
             *      }
             *
             *      if (leftRight == null)
             *      {
             *          leftRight = nextLR;
             *      }
             *      else
             *      {
             *          if ((nextLR != null) && (leftRight != nextLR))
             *          {
             *              pchains.AddChain((bool)leftRight, first, (leftMost + i) - first, inflectionYPoints);
             *
             *              // Rollback
             *              i--;
             *
             *              first = leftMost + i;
             *              leftRight = null;
             *              bottomTop = null;
             *              inflectionYPoints.Clear();
             *          }
             *      }
             *  }
             * }
             *
             * int c = (leftMost + points.Count + 1) - first;
             * if (c > 1)
             * {
             *  pchains.AddChain((leftRight ?? true), first, c, inflectionYPoints);
             * }
             * return pchains;*/
        }