예제 #1
0
        /// <summary>
        /// Computes whether the given coordinate is on the boundary of the polygon.
        /// </summary>
        /// <param name="shell">The polygon shell.</param>
        /// <param name="coordinate">The coordinate to check.</param>
        /// <param name="precisionModel">The precision model.</param>
        /// <returns><c>true</c> if the coordinate is on the boundary of the polygon; otherwise, <c>false</c>.</returns>
        /// <exception cref="System.ArgumentNullException">The shell is null.</exception>
        private static Boolean ComputeOnBoundary(IEnumerable <Coordinate> shell, Coordinate coordinate, PrecisionModel precisionModel)
        {
            IEnumerator <Coordinate> enumerator = shell.GetEnumerator();

            if (!enumerator.MoveNext())
            {
                return(false);
            }

            Coordinate current = enumerator.Current, next;

            while (enumerator.MoveNext())
            {
                next = enumerator.Current;

                if (LineAlgorithms.Contains(current, next, coordinate, precisionModel))
                {
                    return(true);
                }

                current = next;
            }

            return(false);
        }
        /// <summary>
        /// Removes any points in the polygon which are collinear with its nearest neighbors.
        /// </summary>
        /// <param name="polygon">The polygon to search for collinear points</param>
        private Polygon RemoveCollinearPoints(Polygon polygon)
        {
            if (polygon.Count <= 3)
            {
                return(polygon);
            }

            Polygon result = new Polygon();

            for (int i = 0; i < polygon.Count; i++)
            {
                Microsoft.Xna.Framework.Vector2 prev    = polygon.At(i - 1);
                Microsoft.Xna.Framework.Vector2 current = polygon[i];
                Microsoft.Xna.Framework.Vector2 next    = polygon.At(i + 1);

                // Skip adding this point to the result if it is collinear with its neighbors.
                if (LineAlgorithms.AreCollinear(prev, current, next))
                {
                    continue;
                }

                result.Add(current);
            }

            return(result);
        }
예제 #3
0
            /// <summary>
            /// Gets the intersection type between the two given sweep line segments.
            /// </summary>
            /// <param name="x">First sweep line segment.</param>
            /// <param name="y">Second sweep line segment.</param>
            /// <returns>The type of intersection that exists between the two sweep line segments, considering the position of the sweepline.</returns>
            public SweepLineIntersection GetIntersection(SweepLineSegment x, SweepLineSegment y)
            {
                IList <Coordinate> intersections = LineAlgorithms.Intersection(x.LeftCoordinate, x.RightCoordinate,
                                                                               y.LeftCoordinate, y.RightCoordinate,
                                                                               _precisionModel);

                if (intersections.Count == 0)
                {
                    return(SweepLineIntersection.NotExists);
                }

                if (intersections[0].X < _sweepLinePosition)
                {
                    return(SweepLineIntersection.Passed);
                }

                if (intersections[0].X > _sweepLinePosition)
                {
                    return(SweepLineIntersection.NotPassed);
                }

                return((_intersections.Contains(Tuple.Create(x, y)) || _intersections.Contains(Tuple.Create(y, x)))
                    ? SweepLineIntersection.Passed
                    : SweepLineIntersection.NotPassed);
            }
예제 #4
0
        public void LineAlgorithmsCentroidTest()
        {
            // valid lines
            Assert.AreEqual(new Coordinate(4.5, 6.5), LineAlgorithms.Centroid(new Coordinate(2, 5), new Coordinate(7, 8)));
            Assert.AreEqual(new Coordinate(5, 51), LineAlgorithms.Centroid(new BasicLineString(new[] { new Coordinate(5, 2), new Coordinate(5, 100) })));


            // invalid line
            Assert.IsFalse(LineAlgorithms.Centroid(new Coordinate(Double.NaN, 5), new Coordinate(7, 8)).IsValid);


            // valid line string
            List <Coordinate> lineString = new List <Coordinate>
            {
                new Coordinate(1, 1), new Coordinate(1, 3),
                new Coordinate(1, 7)
            };

            Assert.AreEqual(new Coordinate(1, 4), LineAlgorithms.Centroid(lineString));


            // valid lines with fixed precision
            PrecisionModel precision = new PrecisionModel(0.001);

            Assert.AreEqual(new Coordinate(22000, 19000), LineAlgorithms.Centroid(new Coordinate(23000, 16000), new Coordinate(20000, 22000), precision));
            Assert.AreEqual(new Coordinate(434898000, 461826000), LineAlgorithms.Centroid(new Coordinate(864325000, 96041000), new Coordinate(5470000, 827611000), precision));


            // valid lines at given fixed precision
            Assert.AreEqual(new Coordinate(22000, 19000), LineAlgorithms.Centroid(new Coordinate(23654, 16412), new Coordinate(19530, 22009), precision));
            Assert.AreEqual(new Coordinate(434898000, 461826000), LineAlgorithms.Centroid(new Coordinate(864325203, 96041202), new Coordinate(5470432, 827611534), precision));
        }
        /// <summary>
        /// Simplifies a segment of the line string.
        /// </summary>
        /// <param name="startIndex">The starting index of the segment.</param>
        /// <param name="endIndex">The ending index of the segment.</param>
        protected void SimplifySegment(Int32 startIndex, Int32 endIndex)
        {
            if (endIndex <= startIndex + 1) // the segment is a line
            {
                return;
            }

            Double maxDistance = 0;
            Int32  maxIndex    = startIndex;

            // find the most distant coordinate from the line between the starting and ending coordinates
            for (Int32 coordinateIndex = startIndex + 1; coordinateIndex < endIndex; coordinateIndex++)
            {
                Double distance = LineAlgorithms.Distance(_source[startIndex], _source[endIndex], _source[coordinateIndex], PrecisionModel);

                if (distance > maxDistance)
                {
                    maxIndex    = coordinateIndex;
                    maxDistance = distance;
                }
            }

            if (maxDistance <= _delta) // the distance is smaller than the delta, the all coordinates should be removed
            {
                return;
            }

            // recursively simplify both segments
            _marks[maxIndex] = true;
            SimplifySegment(startIndex, maxIndex);
            SimplifySegment(maxIndex, startIndex);
        }
예제 #6
0
        public void Line_Side()
        {
            LineAlgorithms.SideOf(Vector2.Zero, Vector2.UnitY, Vector2.UnitX).Should().Be(1);

            LineAlgorithms.SideOf(Vector2.Zero, Vector2.UnitX + Vector2.UnitY,
                                  Vector2.UnitY).Should().BeApproximately(-MathF.Sqrt(0.5f), 1e-6f);
        }
        /// <summary>
        /// Returns true if on is a reflex vertex. The polygon must be ordered in CCW for this to work properly.
        /// </summary>
        /// <param name="prev"></param>
        /// <param name="on"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        private bool IsReflex(Microsoft.Xna.Framework.Vector2 prev, Microsoft.Xna.Framework.Vector2 on, Microsoft.Xna.Framework.Vector2 next)
        {
            // YOGESH: Added following condition of collinearity
            if (LineAlgorithms.AreCollinear(prev, on, next))
            {
                return(false);
            }

            return(Right(prev, on, next));
        }
예제 #8
0
        public void Line_SegmentIntersectionLowSymmetry()
        {
            var result = LineAlgorithms.LineSegmentIntersection(
                new Vector2(704, 336), new Vector2(569, 299),
                new Vector2(436, 218), new Vector2(446, 357));

            result.Should().NotBeNull();
            Vector2X.Equals(result.IntersectionPoint, new Vector2(439.269f, 263.444f), 1e-3f).Should().BeTrue(
                "Intersection was not in correct position.");
        }
예제 #9
0
        public void Line_SegmentIntersectionParallel()
        {
            var result = LineAlgorithms.LineSegmentIntersection(
                Vector2.UnitX,
                -Vector2.UnitX,
                Vector2.UnitX + Vector2.UnitY,
                -Vector2.UnitX + Vector2.UnitY);

            result.Should().BeNull();
        }
예제 #10
0
        public void Line_SegmentIntersectionHighSymmetry()
        {
            var result = LineAlgorithms.LineSegmentIntersection(
                Vector2.UnitX,
                -Vector2.UnitX,
                Vector2.UnitY,
                -Vector2.UnitY);

            result.Should().NotBeNull();
            result.U1.Should().BeApproximately(0.5f, 0.0001f);
            result.U2.Should().BeApproximately(0.5f, 0.0001f);
            Vector2X.Equals(Vector2.Zero, result.IntersectionPoint).Should().BeTrue("Lines should intersect at origin");
        }
        /// <summary>
        /// Checks whether the given coordinate is on the shell.
        /// </summary>
        private void CheckBoundary()
        {
            IsOnBoundary = false;

            for (Int32 coordIndex = 0; coordIndex < _shell.Count - 1 || (coordIndex < _shell.Count && _shell[0] != _shell[_shell.Count - 1]); coordIndex++)
            {
                if (LineAlgorithms.Contains(_shell[coordIndex], _shell[(coordIndex + 1) % _shell.Count], _coordinate, PrecisionModel))
                {
                    IsOnBoundary = true;
                    break;
                }
            }
        }
예제 #12
0
            /// <summary>
            /// Registers a passed intersection point by the sweep line between the two given arguments.
            /// </summary>
            /// <remarks>
            /// The position of the sweep line is updated when necessary.
            /// </remarks>
            /// <param name="x">First sweep line segment.</param>
            /// <param name="y">Second sweep line segment.</param>
            public void PassIntersection(SweepLineSegment x, SweepLineSegment y)
            {
                Intersection intersection = LineAlgorithms.Intersection(x.LeftCoordinate, x.RightCoordinate, y.LeftCoordinate, y.RightCoordinate, this.precisionModel);

                if (intersection == null)
                {
                    return;
                }

                if (intersection.Coordinate.X > this.sweepLinePosition)
                {
                    this.sweepLinePosition = intersection.Coordinate.X;
                    this.intersections.Clear();
                }

                this.intersections.Add(Tuple.Create(x, y));
                this.intersections.Add(Tuple.Create(y, x));
            }
        /// <summary>
        /// Partitions a polygon by triangles.
        /// </summary>
        public void Compute()
        {
            // source: http://www.codeproject.com/Articles/8238/Polygon-Triangulation-in-C

            _result = new List <Coordinate[]>();

            IList <Coordinate> shell     = new List <Coordinate>(_shell);
            IList <Coordinate> nextShell = new List <Coordinate>(shell);

            Coordinate[] triangle;

            Int32 coordinateCount = shell.Count - 1;
            Int32 coordinateIndex = 1;

            while (shell.Count != 4)
            {
                Coordinate centroid = LineAlgorithms.Centroid(shell[(shell.Count + coordinateIndex - 1) % coordinateCount],
                                                              shell[(shell.Count + coordinateIndex + 1) % coordinateCount], PrecisionModel);
                nextShell.Remove(nextShell[coordinateIndex]);
                if (WindingNumberAlgorithm.IsInsidePolygon(shell, centroid, PrecisionModel) && !ShamosHoeyAlgorithm.Intersects(nextShell, PrecisionModel))
                {
                    triangle = new Coordinate[3]
                    {
                        shell[(coordinateCount + coordinateIndex - 1) % coordinateCount],
                        shell[coordinateIndex],
                        shell[(coordinateCount + coordinateIndex + 1) % coordinateCount]
                    };
                    _result.Add(triangle);
                    shell.Remove(shell[coordinateIndex]);
                    coordinateIndex = 1;
                    coordinateCount--;
                }
                else
                {
                    coordinateIndex = (coordinateIndex + 1) % (shell.Count - 1);
                    nextShell       = new List <Coordinate>(shell);
                }
            }
            triangle = new Coordinate[3] {
                shell[0], shell[1], shell[2]
            };
            _result.Add(triangle);
            _hasResult = true;
        }
예제 #14
0
        /// <summary>
        /// Simplifies a segment of the line string.
        /// </summary>
        /// <param name="startIndex">The starting index of the segment.</param>
        /// <param name="endIndex">The ending index of the segment.</param>
        private void SimplifySegment(Int32 startIndex, Int32 endIndex)
        {
            if (this.Source[startIndex] == null || this.Source[endIndex] == null)
            {
                return;
            }

            if (endIndex <= startIndex + 1) // the segment is a line
            {
                return;
            }

            Double maxDistance = 0;
            Int32  maxIndex    = startIndex;

            // find the most distant coordinate from the line between the starting and ending coordinates
            for (Int32 coordinateIndex = startIndex + 1; coordinateIndex < endIndex; coordinateIndex++)
            {
                if (this.Source[coordinateIndex] == null)
                {
                    continue;
                }

                Double distance = LineAlgorithms.Distance(this.Source[startIndex], this.Source[endIndex], this.Source[coordinateIndex], this.PrecisionModel);

                if (distance > maxDistance)
                {
                    maxIndex    = coordinateIndex;
                    maxDistance = distance;
                }
            }

            if (maxDistance <= this.delta)
            {
                // the distance is smaller than the delta, all coordinates should be removed
                return;
            }

            // recursively simplify both segments
            this.marks[maxIndex] = true;
            this.SimplifySegment(startIndex, maxIndex);
            this.SimplifySegment(maxIndex, startIndex);
        }
예제 #15
0
        /// <summary>
        /// Partitions a polygon by triangles.
        /// </summary>
        public void Compute()
        {
            this.result = new List <Coordinate[]>();

            List <Coordinate> shell     = new List <Coordinate>(this.Source);
            List <Coordinate> nextShell = new List <Coordinate>(this.Source);

            Coordinate[] triangle;

            Int32 coordinateCount = shell.Count - 1;
            Int32 coordinateIndex = 1;

            while (shell.Count != 4)
            {
                Coordinate centroid = LineAlgorithms.Centroid(shell[(shell.Count + coordinateIndex - 1) % coordinateCount], shell[(shell.Count + coordinateIndex + 1) % coordinateCount], this.PrecisionModel);
                nextShell.Remove(nextShell[coordinateIndex]);
                if (!WindingNumberAlgorithm.InExterior(shell, centroid, this.PrecisionModel) && !ShamosHoeyAlgorithm.Intersects(nextShell, this.PrecisionModel))
                {
                    triangle = new Coordinate[3]
                    {
                        shell[(coordinateCount + coordinateIndex - 1) % coordinateCount],
                        shell[coordinateIndex],
                        shell[(coordinateCount + coordinateIndex + 1) % coordinateCount]
                    };
                    this.result.Add(triangle);
                    shell.Remove(shell[coordinateIndex]);
                    coordinateIndex = 1;
                    coordinateCount--;
                }
                else
                {
                    coordinateIndex = (coordinateIndex + 1) % (shell.Count - 1);
                    nextShell       = new List <Coordinate>(shell);
                }
            }

            triangle = new Coordinate[3] {
                shell[0], shell[1], shell[2]
            };
            this.result.Add(triangle);
            this.hasResult = true;
        }
예제 #16
0
        public void LineAlgorithmsCoincidesTest()
        {
            // coinciding lines
            Coordinate       firstCoordinate  = new Coordinate(1, 1);
            CoordinateVector firstVector      = new CoordinateVector(0, 2);
            Coordinate       secondCoordinate = new Coordinate(1, 1);
            CoordinateVector secondVector     = new CoordinateVector(0, 4);

            Assert.IsTrue(LineAlgorithms.Coincides(firstCoordinate, firstVector, secondCoordinate, secondVector));

            firstCoordinate  = new Coordinate(2, 5);
            firstVector      = new CoordinateVector(0, 1);
            secondCoordinate = new Coordinate(2, 4);
            secondVector     = new CoordinateVector(0, 4);
            Assert.IsTrue(LineAlgorithms.Coincides(firstCoordinate, firstVector, secondCoordinate, secondVector));

            firstCoordinate  = new Coordinate(15, 7);
            firstVector      = new CoordinateVector(9, 5);
            secondCoordinate = new Coordinate(15, 7);
            secondVector     = new CoordinateVector(9, 5);
            Assert.IsTrue(LineAlgorithms.Coincides(firstCoordinate, firstVector, secondCoordinate, secondVector));

            firstCoordinate  = new Coordinate(2, 4);
            firstVector      = new CoordinateVector(3, -1);
            secondCoordinate = new Coordinate(14, 0);
            secondVector     = new CoordinateVector(3, -1);
            Assert.IsTrue(LineAlgorithms.Coincides(firstCoordinate, firstVector, secondCoordinate, secondVector));


            // not coinciding lines
            firstCoordinate  = new Coordinate(1, 1);
            firstVector      = new CoordinateVector(0, 1);
            secondCoordinate = new Coordinate(1, 1);
            secondVector     = new CoordinateVector(1, 0);
            Assert.IsFalse(LineAlgorithms.Coincides(firstCoordinate, firstVector, secondCoordinate, secondVector));

            firstCoordinate  = new Coordinate(2, 5);
            firstVector      = new CoordinateVector(0, 1);
            secondCoordinate = new Coordinate(2, 4);
            secondVector     = new CoordinateVector(4, 0);
            Assert.IsFalse(LineAlgorithms.Coincides(firstCoordinate, firstVector, secondCoordinate, secondVector));
        }
예제 #17
0
            /// <summary>
            /// Registers a passed intersection point by the sweep line between the two given arguments.
            /// </summary>
            /// <remarks>
            /// The position of the sweep line is updated when necessary.
            /// </remarks>
            /// <param name="x">First sweep line segment.</param>
            /// <param name="y">Second sweep line segment.</param>
            public void PassIntersection(SweepLineSegment x, SweepLineSegment y)
            {
                IList <Coordinate> intersections = LineAlgorithms.Intersection(x.LeftCoordinate, x.RightCoordinate,
                                                                               y.LeftCoordinate, y.RightCoordinate,
                                                                               _precisionModel);

                if (intersections.Count == 0)
                {
                    return;
                }

                if (intersections[0].X > _sweepLinePosition)
                {
                    _sweepLinePosition = intersections[0].X;
                    _intersections.Clear();
                }

                _intersections.Add(Tuple.Create(x, y));
                _intersections.Add(Tuple.Create(y, x));
            }
예제 #18
0
            /// <summary>
            /// Gets the intersection type between the two given sweep line segments.
            /// </summary>
            /// <param name="x">First sweep line segment.</param>
            /// <param name="y">Second sweep line segment.</param>
            /// <returns>The type of intersection that exists between the two sweep line segments, considering the position of the sweep line.</returns>
            public SweepLineIntersection GetIntersection(SweepLineSegment x, SweepLineSegment y)
            {
                Intersection intersection = LineAlgorithms.Intersection(x.LeftCoordinate, x.RightCoordinate, y.LeftCoordinate, y.RightCoordinate, this.precisionModel);

                if (intersection == null || intersection.Type == IntersectionType.None)
                {
                    return(SweepLineIntersection.NotExists);
                }

                if (intersection.Coordinate.X < this.sweepLinePosition)
                {
                    return(SweepLineIntersection.Passed);
                }

                if (intersection.Coordinate.X > this.sweepLinePosition)
                {
                    return(SweepLineIntersection.NotPassed);
                }

                return((this.intersections.Contains(Tuple.Create(x, y)) || this.intersections.Contains(Tuple.Create(y, x))) ? SweepLineIntersection.Passed : SweepLineIntersection.NotPassed);
            }
예제 #19
0
        private Microsoft.Xna.Framework.Vector2 LineSegmentPointNearestOrigin(Microsoft.Xna.Framework.Vector2 start, Microsoft.Xna.Framework.Vector2 end)
        {
            var delta = end - start;
            var perp  = new Vector2(delta.Y, -delta.X);

            if (delta.LengthSquared() < Tolerance)
            {
                return(start);
            }

            var intersection = LineAlgorithms.LineSegmentIntersection(
                start, end, Vector2.Zero, perp);

            if (intersection.WithinFirstSegment)
            {
                return(intersection.IntersectionPoint);
            }

            return(start.LengthSquared() < end.LengthSquared()
                                ? start
                                : end);
        }
예제 #20
0
        /// <summary>
        /// Processes the intersection event.
        /// </summary>
        /// <param name="intersectionEvent">The intersection event.</param>
        private void ProcessIntersectionEvent(IntersectionEvent intersectionEvent)
        {
            SweepLineSegment segment;
            Intersection     intersection;

            /*
             * segment order before intersection: segmentBelow <-> segmentAbove <-> segment <-> segmentAboveAbove
             * segment order after intersection:  segmentBelow <-> segment <-> segmentAbove <-> segmentAboveAbove
             */
            segment = intersectionEvent.Above;
            SweepLineSegment segmentAbove = intersectionEvent.Below;

            // dandle closing intersection points when segments (partially) overlap each other
            if (intersectionEvent.IsClosing)
            {
                if (!this.sweepLine.IsAdjacent(segment.Edge, segmentAbove.Edge))
                {
                    this.intersections.Add(intersectionEvent.Vertex);
                    this.edgeIndexes.Add(Tuple.Create(Math.Min(segment.Edge, segmentAbove.Edge),
                                                      Math.Max(segment.Edge, segmentAbove.Edge)));
                }
            }

            // it is possible that the previously detected intersection point is not a real intersection, because a new segment started between them,
            // therefore a repeated check is necessary to carry out
            else if (this.sweepLine.Add(intersectionEvent))
            {
                if (!this.sweepLine.IsAdjacent(segment.Edge, segmentAbove.Edge))
                {
                    this.intersections.Add(intersectionEvent.Vertex);
                    this.edgeIndexes.Add(Tuple.Create(Math.Min(segment.Edge, segmentAbove.Edge),
                                                      Math.Max(segment.Edge, segmentAbove.Edge)));

                    intersection = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate, segmentAbove.LeftCoordinate, segmentAbove.RightCoordinate, this.PrecisionModel);

                    if (intersection.Type == IntersectionType.Interval)
                    {
                        IntersectionEvent newIntersectionEvent = new IntersectionEvent
                        {
                            Vertex    = intersection.End,
                            Below     = segment,
                            Above     = segmentAbove,
                            IsClosing = true,
                        };
                        this.eventQueue.Add(newIntersectionEvent);
                    }
                }

                if (segmentAbove.Above != null)
                {
                    intersection = LineAlgorithms.Intersection(segmentAbove.LeftCoordinate, segmentAbove.RightCoordinate, segmentAbove.Above.LeftCoordinate, segmentAbove.Above.RightCoordinate, this.PrecisionModel);

                    if (intersection != null && intersection.Coordinate.X >= intersectionEvent.Vertex.X)
                    {
                        IntersectionEvent newIntersectionEvent = new IntersectionEvent
                        {
                            Vertex = intersection.Coordinate,
                            Below  = segmentAbove,
                            Above  = segmentAbove.Above
                        };
                        if (!this.eventQueue.Contains(newIntersectionEvent))
                        {
                            this.eventQueue.Add(newIntersectionEvent);
                        }
                    }
                }

                if (segment.Below != null)
                {
                    intersection = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate, segment.Below.LeftCoordinate, segment.Below.RightCoordinate, this.PrecisionModel);

                    if (intersection != null && intersection.Coordinate.X >= intersectionEvent.Vertex.X)
                    {
                        IntersectionEvent newIntersectionEvent = new IntersectionEvent
                        {
                            Vertex = intersection.Coordinate,
                            Below  = segment.Below,
                            Above  = segment
                        };
                        if (!this.eventQueue.Contains(newIntersectionEvent))
                        {
                            this.eventQueue.Add(newIntersectionEvent);
                        }
                    }
                }
            }
        }
예제 #21
0
        public void LineAlgorithmsDistanceTest()
        {
            // distance of a line and a coordinate
            Coordinate lineStart  = new Coordinate(0, 1);
            Coordinate lineEnd    = new Coordinate(100, 1);
            Coordinate coordinate = new Coordinate(1, 1);

            Assert.AreEqual(0, LineAlgorithms.Distance(lineStart, lineEnd, coordinate));

            lineStart  = new Coordinate(0, 1);
            lineEnd    = new Coordinate(100, 1);
            coordinate = new Coordinate(1, 7);
            Assert.AreEqual(6, LineAlgorithms.Distance(lineStart, lineEnd, coordinate));

            lineStart  = new Coordinate(5, 7);
            lineEnd    = new Coordinate(5, 70);
            coordinate = new Coordinate(5, 6);
            Assert.AreEqual(1, LineAlgorithms.Distance(lineStart, lineEnd, coordinate));

            lineStart  = new Coordinate(5, 7);
            lineEnd    = new Coordinate(5, 70);
            coordinate = new Coordinate(4, 7);
            Assert.AreEqual(1, LineAlgorithms.Distance(lineStart, lineEnd, coordinate));

            lineStart  = new Coordinate(0, 0);
            lineEnd    = new Coordinate(2, -3);
            coordinate = new Coordinate(2, 1);
            Assert.AreEqual(2.22, Math.Round(LineAlgorithms.Distance(lineStart, lineEnd, coordinate), 2));


            // distance of two lines
            lineStart = new Coordinate(0, 0);
            lineEnd   = new Coordinate(100, 0);
            Coordinate secondLineStart = new Coordinate(0, 0);
            Coordinate secondLineEnd   = new Coordinate(0, 100);

            Assert.AreEqual(0, LineAlgorithms.Distance(lineStart, lineEnd, secondLineStart, secondLineEnd));

            lineStart       = new Coordinate(0, 0);
            lineEnd         = new Coordinate(100, 0);
            secondLineStart = new Coordinate(0, 1);
            secondLineEnd   = new Coordinate(100, 1);
            Assert.AreEqual(1, LineAlgorithms.Distance(lineStart, lineEnd, secondLineStart, secondLineEnd));

            lineStart       = new Coordinate(2, 4);
            lineEnd         = new Coordinate(5, 3);
            secondLineStart = new Coordinate(6, 2);
            secondLineEnd   = new Coordinate(6, 6);
            Assert.AreEqual(1, LineAlgorithms.Distance(lineStart, lineEnd, secondLineStart, secondLineEnd));

            lineStart       = new Coordinate(1, 1);
            lineEnd         = new Coordinate(1, 4);
            secondLineStart = new Coordinate(4, 2);
            secondLineEnd   = new Coordinate(0, 2);
            Assert.AreEqual(0, LineAlgorithms.Distance(lineStart, lineEnd, secondLineStart, secondLineEnd));


            // distance of an infinite line and a point
            lineStart = new Coordinate(1, 1);
            CoordinateVector coordinateVector = new CoordinateVector(0, 1);

            coordinate = new Coordinate(2, 1500);
            Assert.AreEqual(1, LineAlgorithms.Distance(lineStart, coordinateVector, coordinate));

            lineStart        = new Coordinate(1, 1);
            coordinateVector = new CoordinateVector(0, 1);
            coordinate       = new Coordinate(1, 1500);
            Assert.AreEqual(0, LineAlgorithms.Distance(lineStart, coordinateVector, coordinate));

            lineStart        = new Coordinate(1, 1);
            coordinateVector = new CoordinateVector(0, 1);
            coordinate       = new Coordinate(0, -100);
            Assert.AreEqual(1, LineAlgorithms.Distance(lineStart, coordinateVector, coordinate));

            lineStart        = new Coordinate(2, 4);
            coordinateVector = new CoordinateVector(-3, 1);
            coordinate       = new Coordinate(14, 0);
            Assert.AreEqual(0, LineAlgorithms.Distance(lineStart, coordinateVector, coordinate));

            lineStart        = new Coordinate(2, 4);
            coordinateVector = new CoordinateVector(-3, 1);
            coordinate       = new Coordinate(5, 3);
            Assert.AreEqual(0, LineAlgorithms.Distance(lineStart, coordinateVector, coordinate));
        }
예제 #22
0
            /// <summary>
            /// Compares two <see cref="SweepLineSegment" /> instances and returns a value indicating whether one is less than, equal to, or greater than the other.
            /// </summary>
            /// <remarks>
            /// The comparator applies a above-below relationship between the arguments, where a "greater" segment is above the another one.
            /// </remarks>
            /// <param name="first">The first <see cref="SweepLineSegment" /> to compare.</param>
            /// <param name="second">The second <see cref="SweepLineSegment" /> to compare.</param>
            /// <returns>A signed integer that indicates the relative values of <paramref name="first" /> and <paramref name="second" />.</returns>
            /// <exception cref="System.InvalidOperationException">Cannot compare non-overlapping sweep line segments.</exception>
            public Int32 Compare(SweepLineSegment first, SweepLineSegment second)
            {
                // Comparing non-overlapping segments is not supported.
                if (first.RightCoordinate.X < second.LeftCoordinate.X || first.LeftCoordinate.X > second.RightCoordinate.X)
                {
                    throw new InvalidOperationException("Cannot compare non-overlapping sweep line segments.");
                }

                // The segments intersect.
                SweepLineIntersection intersection = GetIntersection(first, second);

                if (intersection != SweepLineIntersection.NotExists)
                {
                    CoordinateVector xDiff     = first.RightCoordinate - first.LeftCoordinate;
                    Double           xGradient = xDiff.X == 0 ? Double.MaxValue : xDiff.Y / xDiff.X;

                    CoordinateVector yDiff     = second.RightCoordinate - second.LeftCoordinate;
                    Double           yGradient = yDiff.X == 0 ? Double.MaxValue : yDiff.Y / yDiff.X;

                    Int32 result = yGradient.CompareTo(xGradient);
                    if (result == 0)
                    {
                        result = first.LeftCoordinate.X.CompareTo(second.LeftCoordinate.X);
                    }
                    if (result == 0)
                    {
                        result = second.LeftCoordinate.Y.CompareTo(first.LeftCoordinate.Y);
                    }
                    if (result == 0)
                    {
                        result = first.RightCoordinate.X.CompareTo(second.RightCoordinate.X);
                    }
                    if (result == 0)
                    {
                        result = second.RightCoordinate.Y.CompareTo(first.RightCoordinate.Y);
                    }
                    if (result == 0)
                    {
                        result = second.Edge.CompareTo(first.Edge);
                    }
                    if (intersection == SweepLineIntersection.Passed)
                    {
                        result *= -1;
                    }
                    return(result);
                }

                // The segments do not intersect.
                if (first.LeftCoordinate.X < second.LeftCoordinate.X)
                {
                    Double[]           verticalCollection = new[] { first.LeftCoordinate.Y, first.RightCoordinate.Y };
                    var                verticalLineStart  = new Coordinate(second.LeftCoordinate.X, verticalCollection.Min());
                    var                verticalLineEnd    = new Coordinate(second.LeftCoordinate.X, verticalCollection.Max());
                    IList <Coordinate> startIntersections = LineAlgorithms.Intersection(first.LeftCoordinate, first.RightCoordinate,
                                                                                        verticalLineStart, verticalLineEnd,
                                                                                        _precisionModel);

                    // due to precision tolerance degeneracy we might not found the intersection
                    return(startIntersections.Count > 0
                        ? startIntersections[0].Y.CompareTo(second.LeftCoordinate.Y)
                        : ((first.LeftCoordinate.Y + first.RightCoordinate.Y) / 2.0).CompareTo(second.LeftCoordinate.Y));
                }

                if (first.LeftCoordinate.X > second.LeftCoordinate.X)
                {
                    Double[]           verticalCollection = new[] { second.LeftCoordinate.Y, second.RightCoordinate.Y };
                    var                verticalLineStart  = new Coordinate(first.LeftCoordinate.X, verticalCollection.Min());
                    var                verticalLineEnd    = new Coordinate(first.LeftCoordinate.X, verticalCollection.Max());
                    IList <Coordinate> startIntersections = LineAlgorithms.Intersection(verticalLineStart, verticalLineEnd,
                                                                                        second.LeftCoordinate, second.RightCoordinate,
                                                                                        _precisionModel);

                    return(startIntersections.Count > 0
                        ? first.LeftCoordinate.Y.CompareTo(startIntersections[0].Y)
                        : first.LeftCoordinate.Y.CompareTo((second.LeftCoordinate.Y + second.RightCoordinate.Y) / 2.0));
                }

                // first.LeftCoordinate.X == second.LeftCoordinate.X
                return(first.LeftCoordinate.Y.CompareTo(second.LeftCoordinate.Y));
            }
예제 #23
0
        public void LineAlgorithmsIntersectsTest()
        {
            // coinciding lines
            Coordinate firstLineStart  = new Coordinate(1, 1);
            Coordinate firstLineEnd    = new Coordinate(4, 1);
            Coordinate secondLineStart = new Coordinate(1, 1);
            Coordinate secondLineEnd   = new Coordinate(4, 1);

            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // parallel lines
            firstLineStart  = new Coordinate(1.3, 1.3);
            firstLineEnd    = new Coordinate(1.3, 4.3);
            secondLineStart = new Coordinate(2.3, 1.3);
            secondLineEnd   = new Coordinate(2.3, 4.3);
            Assert.IsFalse(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // intersecting lines
            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(1, 4);
            secondLineStart = new Coordinate(4, 2);
            secondLineEnd   = new Coordinate(0, 2);
            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(4, 4);
            secondLineStart = new Coordinate(1, 4);
            secondLineEnd   = new Coordinate(4, 1);
            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(2, 2);
            firstLineEnd    = new Coordinate(2, 8);
            secondLineStart = new Coordinate(2, 5);
            secondLineEnd   = new Coordinate(2, 10);
            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(2, 2);
            firstLineEnd    = new Coordinate(2, 8);
            secondLineStart = new Coordinate(2, 1);
            secondLineEnd   = new Coordinate(2, 8);
            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(7, 7);
            firstLineEnd    = new Coordinate(7, 7);
            secondLineStart = new Coordinate(7, 7);
            secondLineEnd   = new Coordinate(7, 7);
            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // not intersecting lines
            firstLineStart  = new Coordinate(2, 2);
            firstLineEnd    = new Coordinate(2, 8);
            secondLineStart = new Coordinate(2.1, 1);
            secondLineEnd   = new Coordinate(10, 8);
            Assert.IsFalse(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(2, 2);
            firstLineEnd    = new Coordinate(2, 8);
            secondLineStart = new Coordinate(1, 8.001);
            secondLineEnd   = new Coordinate(10, 8.001);
            Assert.IsFalse(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // internally intersecting lines
            firstLineStart  = new Coordinate(1, 4);
            firstLineEnd    = new Coordinate(4, 1);
            secondLineStart = new Coordinate(3, 2);
            secondLineEnd   = new Coordinate(2, 3);
            Assert.IsTrue(LineAlgorithms.InternalIntersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 4);
            firstLineEnd    = new Coordinate(4, 1);
            secondLineStart = new Coordinate(3, 2);
            secondLineEnd   = new Coordinate(3, 2);
            Assert.IsTrue(LineAlgorithms.InternalIntersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 4);
            firstLineEnd    = new Coordinate(4, 1);
            secondLineStart = new Coordinate(1, 2);
            secondLineEnd   = new Coordinate(200, 3);
            Assert.IsTrue(LineAlgorithms.InternalIntersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 4);
            firstLineEnd    = new Coordinate(4, 1);
            secondLineStart = new Coordinate(1, 2);
            secondLineEnd   = new Coordinate(200, 3);
            Assert.IsTrue(LineAlgorithms.InternalIntersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // not internally intersecting lines
            firstLineStart  = new Coordinate(0, 0);
            firstLineEnd    = new Coordinate(0, 1000.33);
            secondLineStart = new Coordinate(1000.33, 200);
            secondLineEnd   = new Coordinate(0, 0);
            Assert.IsFalse(LineAlgorithms.InternalIntersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(100, 1);
            secondLineStart = new Coordinate(1, 4);
            secondLineEnd   = new Coordinate(1, 1);
            Assert.IsFalse(LineAlgorithms.InternalIntersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // intersecting infinite lines
            firstLineStart = new Coordinate(2, 5);
            CoordinateVector firstVector = new CoordinateVector(0, 1);

            secondLineStart = new Coordinate(2, 4);
            CoordinateVector secondVector = new CoordinateVector(4, 0);

            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstVector, secondLineStart, secondVector));

            firstLineStart  = new Coordinate(2, 4);
            firstVector     = new CoordinateVector(-3, 1);
            secondLineStart = new Coordinate(5, 3);
            secondVector    = new CoordinateVector(-3, 1);
            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstVector, secondLineStart, secondVector));

            firstLineStart  = new Coordinate(1, 1);
            firstVector     = new CoordinateVector(0, 1);
            secondLineStart = new Coordinate(1, 1);
            secondVector    = new CoordinateVector(1, 0);
            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstVector, secondLineStart, secondVector));

            firstLineStart  = new Coordinate(1, 1);
            firstVector     = new CoordinateVector(0, 1);
            secondLineStart = new Coordinate(2, 2);
            secondVector    = new CoordinateVector(0, 1);
            Assert.IsTrue(LineAlgorithms.IsParallel(firstLineStart, firstVector, secondLineStart, secondVector));
            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstVector, secondLineStart, secondVector));
        }
        /// <summary>
        /// Decomposes a concave polygon into a set of convex polygons.
        /// </summary>
        /// <param name="polygon"></param>
        /// <returns></returns>
        public IReadOnlyList <Polygon> BuildConvexDecomposition(Polygon polygon)
        {
            //We force it to CCW as it is a precondition in this algorithm.
            polygon = ForceCounterClockWise(polygon);

            List <Polygon> list = new List <Polygon>();

            // YOGESH : Convex Partition can not happen if there are less than 3, ie 2,1 vertices
            if (polygon.Count < 3)
            {
                return(list);
            }

            double d = 0.0;
            double lowerDist, upperDist;

            Microsoft.Xna.Framework.Vector2 p;
            Microsoft.Xna.Framework.Vector2 lowerInt = new Microsoft.Xna.Framework.Vector2();
            Microsoft.Xna.Framework.Vector2 upperInt = new Microsoft.Xna.Framework.Vector2();             // intersection points
            int     lowerIndex = 0, upperIndex = 0;
            Polygon lowerPoly, upperPoly;

            // Go thru all Verices until  we  find  a  reflex  vertex  i.
            // Extend  the  edges incident at i until they hit an edge
            // Find BEST vertex within the range, that the partitioning chord

            // A polygon can be broken into convex regions by eliminating all reflex vertices
            // Eliminating two reflex vertices with one diagonal is better than eliminating just one
            // A reflex vertex can only be removed if the diagonal connecting to it is within the range given by extending its neighbouring edges;
            // otherwise, its angle is only reduced
            for (int i = 0; i < polygon.Count; i++)
            {
                Microsoft.Xna.Framework.Vector2 prev = polygon.At(i - 1);
                Microsoft.Xna.Framework.Vector2 on   = polygon.At(i);
                Microsoft.Xna.Framework.Vector2 next = polygon.At(i + 1);

                if (IsReflex(prev, on, next))
                {
                    lowerDist = double.MaxValue;
                    upperDist = double.MaxValue;

                    for (int j = 0; j < polygon.Count; j++)
                    {
                        // YOGESH: if any of j line's endpoints matches with reflex i, skip
                        if ((i == j) ||
                            (i == NormalizeIndex(j - 1, polygon.Count)) ||
                            (i == NormalizeIndex(j + 1, polygon.Count)))
                        {
                            continue;                             // no self and prev and next, for testing
                        }

                        // testing incoming edge:
                        // if line coming into i vertex (i-1 to i) has j vertex of the test-line on left
                        // AND have j-i on right, then they will be intersecting
                        Microsoft.Xna.Framework.Vector2 iPrev = polygon.At(i - 1);
                        Microsoft.Xna.Framework.Vector2 iSelf = polygon.At(i);
                        Microsoft.Xna.Framework.Vector2 jSelf = polygon.At(j);
                        Microsoft.Xna.Framework.Vector2 jPrev = polygon.At(j - 1);

                        bool leftOK  = Left(iPrev, iSelf, jSelf);
                        bool rightOK = Right(iPrev, iSelf, jPrev);

                        bool leftOnOK  = LineAlgorithms.AreCollinear(iPrev, iSelf, jSelf); // YOGESH: cached into variables for better debugging
                        bool rightOnOK = LineAlgorithms.AreCollinear(iPrev, iSelf, jPrev); // YOGESH: cached into variables for better debugging

                        if (leftOnOK || rightOnOK)                                         // YOGESH: Checked "ON" condition as well, collinearity
                        {
                            // lines are colinear, they can not be overlapping as polygon is simple
                            // find closest point which is not internal to incoming line i , i -1
                            d = Microsoft.Xna.Framework.Vector2.DistanceSquared(iSelf, jSelf);

                            // this lower* is the point got from incoming edge into the i vertex,
                            // lowerInt incoming edge intersection point
                            // lowerIndex incoming edge intersection edge
                            if (d < lowerDist)
                            {
                                // keep only the closest intersection
                                lowerDist  = d;
                                lowerInt   = jSelf;
                                lowerIndex = j - 1;
                            }

                            d = Microsoft.Xna.Framework.Vector2.DistanceSquared(iSelf, jPrev);

                            // this lower* is the point got from incoming edge into the i vertex,
                            // lowerInt incoming edge intersection point
                            // lowerIndex incoming edge intersection edge
                            if (d < lowerDist)
                            {
                                // keep only the closest intersection
                                lowerDist  = d;
                                lowerInt   = jPrev;
                                lowerIndex = j;
                            }
                        }
                        else if (leftOK && rightOK)                         // YOGESH: Intersection in-between. Bayazit had ON condition in built here, which I have taken care above.
                        {
                            // find the point of intersection
                            var intersection = LineAlgorithms.LineSegmentIntersection(
                                polygon.At(i - 1), polygon.At(i), polygon.At(j), polygon.At(j - 1))
                                               ?.IntersectionPoint;

                            if (intersection != null)
                            {
                                p = intersection.Value;

                                // make sure it's inside the poly,
                                if (Right(polygon.At(i + 1), polygon.At(i), p))
                                {
                                    d = Microsoft.Xna.Framework.Vector2.DistanceSquared(polygon.At(i), p);

                                    // this lower* is the point got from incoming edge into the i vertex,
                                    // lowerInt incoming edge intersection point
                                    // lowerIndex incoming edge intersection edge
                                    if (d < lowerDist)
                                    {
                                        // keep only the closest intersection
                                        lowerDist  = d;
                                        lowerInt   = p;
                                        lowerIndex = j;
                                    }
                                }
                            }
                        }

                        // testing outgoing edge:
                        // if line outgoing from i vertex (i to i+1) has j vertex of the test-line on right
                        // AND has j+1 on left, they they will be intersecting
                        Microsoft.Xna.Framework.Vector2 iNext = polygon.At(i + 1);
                        Microsoft.Xna.Framework.Vector2 jNext = polygon.At(j + 1);

                        bool leftOKn  = Left(iNext, iSelf, jNext);
                        bool rightOKn = Right(iNext, iSelf, jSelf);

                        bool leftOnOKn  = LineAlgorithms.AreCollinear(iNext, iSelf, jNext);                        // YOGESH: cached into variables for better debugging
                        bool rightOnOKn = LineAlgorithms.AreCollinear(iNext, iSelf, jSelf);

                        if (leftOnOKn || rightOnOKn)                        // YOGESH: Checked "ON" condition as well, collinearity
                        {
                            // lines are colinear, they can not be overlapping as polygon is simple
                            // find closest point which is not internal to incoming line i , i -1
                            d = Microsoft.Xna.Framework.Vector2.DistanceSquared(iSelf, jNext);

                            // this upper* is the point got from outgoing edge into the i vertex,
                            // upperInt outgoing edge intersection point
                            // upperIndex outgoing edge intersection edge
                            if (d < upperDist)
                            {
                                // keep only the closest intersection
                                upperDist  = d;
                                upperInt   = jNext;
                                upperIndex = j + 1;
                            }

                            d = Microsoft.Xna.Framework.Vector2.DistanceSquared(polygon.At(i), polygon.At(j));

                            // this upper* is the point got from outgoing edge into the i vertex,
                            // upperInt outgoing edge intersection point
                            // upperIndex outgoing edge intersection edge
                            if (d < upperDist)
                            {
                                // keep only the closest intersection
                                upperDist  = d;
                                upperInt   = jSelf;
                                upperIndex = j;
                            }
                        }
                        else if (leftOKn && rightOKn)                         // YOGESH: Intersection in-between. Bayazit had ON condition in built here, which I have taken care above.
                        {
                            var intersection = LineAlgorithms.LineSegmentIntersection(
                                polygon.At(i + 1), polygon.At(i), polygon.At(j), polygon.At(j + 1))
                                               ?.IntersectionPoint;

                            if (intersection != null)
                            {
                                p = intersection.Value;

                                if (Left(polygon.At(i - 1), polygon.At(i), p))
                                {
                                    d = Microsoft.Xna.Framework.Vector2.DistanceSquared(polygon.At(i), p);

                                    // this upper* is the point got from outgoing edge from the i vertex,
                                    // upperInt outgoing edge intersection point
                                    // upperIndex outgoing edge intersection edge
                                    if (d < upperDist)
                                    {
                                        upperDist  = d;
                                        upperIndex = j;
                                        upperInt   = p;
                                    }
                                }
                            }
                        }
                    }

                    // YOGESH: If no vertices in the range, lets not choose midpoint but closet point of that segment
                    //// if there are no vertices to connect to, choose a point in the middle
                    if (lowerIndex == (upperIndex + 1) % polygon.Count)
                    {
                        Microsoft.Xna.Framework.Vector2 sp = ((lowerInt + upperInt) / 2);

                        lowerPoly = polygon.CopyRange(i, upperIndex);
                        lowerPoly.Add(sp);
                        upperPoly = polygon.CopyRange(lowerIndex, i);
                        upperPoly.Add(sp);
                    }
                    else
                    {
                        //find vertex to connect to
                        double highestScore = 0, bestIndex = lowerIndex;
                        while (upperIndex < lowerIndex)
                        {
                            upperIndex += polygon.Count;
                        }

                        // go throuh all the vertices between the range of lower and upper
                        for (int j = lowerIndex; j <= upperIndex; ++j)
                        {
                            if (CanSee(polygon, i, j))
                            {
                                double score = 1 / (Microsoft.Xna.Framework.Vector2.DistanceSquared(polygon.At(i), polygon.At(j)) + 1);

                                // if another vertex is Reflex, choosing it has highest score
                                Microsoft.Xna.Framework.Vector2 prevj = polygon.At(j - 1);
                                Microsoft.Xna.Framework.Vector2 onj   = polygon.At(j);
                                Microsoft.Xna.Framework.Vector2 nextj = polygon.At(j + 1);

                                if (IsReflex(prevj, onj, nextj))
                                {
                                    if (RightOrOn(polygon.At(j - 1), polygon.At(j), polygon.At(i)) &&
                                        LeftOrOn(polygon.At(j + 1), polygon.At(j), polygon.At(i)))
                                    {
                                        score += 3;
                                    }
                                    else
                                    {
                                        score += 2;
                                    }
                                }
                                else
                                {
                                    score += 1;
                                }
                                if (score > highestScore)
                                {
                                    bestIndex    = j;
                                    highestScore = score;
                                }
                            }
                        }

                        // YOGESH : Pending: if there are 2 vertices as 'bestIndex', its better to disregard both and put midpoint (M case)
                        lowerPoly = polygon.CopyRange(i, (int)bestIndex);
                        upperPoly = polygon.CopyRange((int)bestIndex, i);
                    }

                    // solve smallest poly first (SAW in Bayazit's C++ code)
                    if (lowerPoly.Count < upperPoly.Count)
                    {
                        list.AddRange(BuildConvexDecomposition(lowerPoly));
                        list.AddRange(BuildConvexDecomposition(upperPoly));
                    }
                    else
                    {
                        list.AddRange(BuildConvexDecomposition(upperPoly));
                        list.AddRange(BuildConvexDecomposition(lowerPoly));
                    }

                    return(list);
                }
            }

            // polygon is already convex
            if (polygon.Count > MaxPolygonVertices)
            {
                lowerPoly = polygon.CopyRange(0, polygon.Count / 2);
                upperPoly = polygon.CopyRange(polygon.Count / 2, 0);
                list.AddRange(BuildConvexDecomposition(lowerPoly));
                list.AddRange(BuildConvexDecomposition(upperPoly));
            }
            else
            {
                list.Add(polygon);
            }

            // The polygons are not guaranteed to be without collinear points. We remove
            // them to be sure.
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = RemoveCollinearPoints(list[i]);
            }

            return(list);
        }
예제 #25
0
        public void LineAlgorithmsIntersectionTest()
        {
            // coinciding lines
            Coordinate         firstLineStart  = new Coordinate(1, 1);
            Coordinate         firstLineEnd    = new Coordinate(4, 1);
            Coordinate         secondLineStart = new Coordinate(1, 1);
            Coordinate         secondLineEnd   = new Coordinate(4, 1);
            IList <Coordinate> expectedResult  = new List <Coordinate> {
                new Coordinate(1, 1), new Coordinate(4, 1)
            };

            Assert.AreEqual(expectedResult, LineAlgorithms.Intersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // lines intersecting in one point
            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(1, 4);
            secondLineStart = new Coordinate(4, 2);
            secondLineEnd   = new Coordinate(0, 2);
            expectedResult  = new List <Coordinate> {
                new Coordinate(1, 2)
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.Intersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(-1, 6);
            firstLineEnd    = new Coordinate(1, 2);
            secondLineStart = new Coordinate(4, 0);
            secondLineEnd   = new Coordinate(0, 4);
            expectedResult  = new List <Coordinate> {
                new Coordinate(0, 4)
            };

            Assert.AreEqual(expectedResult, LineAlgorithms.Intersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));
            firstLineStart  = new Coordinate(2, 2);
            firstLineEnd    = new Coordinate(2, 2);
            secondLineStart = new Coordinate(2, 2);
            secondLineEnd   = new Coordinate(2, 2);
            expectedResult  = new List <Coordinate> {
                new Coordinate(2, 2)
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.Intersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // lines intersecting in more than one point
            firstLineStart  = new Coordinate(2, 2);
            firstLineEnd    = new Coordinate(2, 8);
            secondLineStart = new Coordinate(2, 5);
            secondLineEnd   = new Coordinate(2, 10);
            expectedResult  = new List <Coordinate> {
                new Coordinate(2, 5), new Coordinate(2, 8)
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.Intersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(4, 1);
            firstLineEnd    = new Coordinate(1, 4);
            secondLineStart = new Coordinate(3, 2);
            secondLineEnd   = new Coordinate(2, 3);
            expectedResult  = new List <Coordinate> {
                new Coordinate(3, 2), new Coordinate(2, 3)
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.Intersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // parallel lines
            firstLineStart  = new Coordinate(1.3, 1.3);
            firstLineEnd    = new Coordinate(1.3, 4.3);
            secondLineStart = new Coordinate(2.3, 1.3);
            secondLineEnd   = new Coordinate(2.3, 4.3);
            expectedResult  = new List <Coordinate> {
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.Intersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // not intersecting lines
            firstLineStart  = new Coordinate(2, 2);
            firstLineEnd    = new Coordinate(2, 8);
            secondLineStart = new Coordinate(2.1, 1);
            secondLineEnd   = new Coordinate(10, 8);
            expectedResult  = new List <Coordinate> {
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.Intersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // coinciding infinite lines
            firstLineStart = new Coordinate(2, 4);
            CoordinateVector firstVector = new CoordinateVector(0, 1);

            secondLineStart = new Coordinate(2, 5);
            CoordinateVector secondVector = new CoordinateVector(0, 4);

            Assert.AreEqual(new Coordinate(2, 4), LineAlgorithms.Intersection(firstLineStart, firstVector, secondLineStart, secondVector));


            // intersecting infinite lines
            firstLineStart  = new Coordinate(1, 2);
            firstVector     = new CoordinateVector(1, -2);
            secondLineStart = new Coordinate(4, 0);
            secondVector    = new CoordinateVector(1, -1);
            Assert.AreEqual(new Coordinate(0, 4), LineAlgorithms.Intersection(firstLineStart, firstVector, secondLineStart, secondVector));

            firstLineStart  = new Coordinate(1, 1);
            firstVector     = new CoordinateVector(0, 1);
            secondLineStart = new Coordinate(1, 1);
            secondVector    = new CoordinateVector(1, 0);
            Assert.AreEqual(new Coordinate(1, 1), LineAlgorithms.Intersection(firstLineStart, firstVector, secondLineStart, secondVector));


            // not intersecting infinite lines
            firstLineStart  = new Coordinate(1, 1);
            firstVector     = new CoordinateVector(0, 1);
            secondLineStart = new Coordinate(2, 2);
            secondVector    = new CoordinateVector(0, 1);
            Assert.IsFalse(LineAlgorithms.Intersection(firstLineStart, firstVector, secondLineStart, secondVector).IsValid);


            // internally intersecting lines
            firstLineStart  = new Coordinate(1, 4);
            firstLineEnd    = new Coordinate(4, 1);
            secondLineStart = new Coordinate(3, 2);
            secondLineEnd   = new Coordinate(2, 3);
            expectedResult  = new List <Coordinate> {
                new Coordinate(3, 2), new Coordinate(2, 3)
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.InternalIntersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 4);
            firstLineEnd    = new Coordinate(4, 1);
            secondLineStart = new Coordinate(1, 2);
            secondLineEnd   = new Coordinate(200, 2);
            expectedResult  = new List <Coordinate> {
                new Coordinate(3, 2)
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.InternalIntersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(10.58, 4);
            firstLineEnd    = new Coordinate(4, 1);
            secondLineStart = new Coordinate(10.58, 4);
            secondLineEnd   = new Coordinate(4, 1);
            expectedResult  = new List <Coordinate> {
                new Coordinate(10.58, 4), new Coordinate(4, 1)
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.InternalIntersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // not internally intersecting lines
            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(10, 1);
            secondLineStart = new Coordinate(1, 4);
            secondLineEnd   = new Coordinate(1, 1);
            expectedResult  = new List <Coordinate> {
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.InternalIntersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));


            // intersecting lines with fixed precision
            PrecisionModel precision = new PrecisionModel(0.001);

            firstLineStart  = new Coordinate(1000, 1000);
            firstLineEnd    = new Coordinate(1000, 4000);
            secondLineStart = new Coordinate(4000, 2000);
            secondLineEnd   = new Coordinate(-2000, 1000);
            expectedResult  = new List <Coordinate> {
                new Coordinate(1000, 2000)
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.Intersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd, precision));

            secondLineEnd  = new Coordinate(-2000, 0);
            expectedResult = new List <Coordinate> {
                new Coordinate(1000, 1000)
            };
            Assert.AreEqual(expectedResult, LineAlgorithms.Intersection(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd, precision));
        }
        /// <summary>
        /// Returns true if vertex j can be seen from vertex i without any obstructions.
        /// </summary>
        /// <param name="polygon"></param>
        /// <param name="i"></param>
        /// <param name="j"></param>
        /// <returns></returns>
        private bool CanSee(Polygon polygon, int i, int j)
        {
            Microsoft.Xna.Framework.Vector2 prev = polygon.At(i - 1);
            Microsoft.Xna.Framework.Vector2 on   = polygon.At(i);
            Microsoft.Xna.Framework.Vector2 next = polygon.At(i + 1);

            if (IsReflex(prev, on, next))
            {
                if (LeftOrOn(polygon.At(i), polygon.At(i - 1), polygon.At(j)) &&
                    RightOrOn(polygon.At(i), polygon.At(i + 1), polygon.At(j)))
                {
                    return(false);
                }
            }
            else
            {
                if (RightOrOn(polygon.At(i), polygon.At(i + 1), polygon.At(j)) ||
                    LeftOrOn(polygon.At(i), polygon.At(i - 1), polygon.At(j)))
                {
                    return(false);
                }
            }

            Microsoft.Xna.Framework.Vector2 prevj = polygon.At(j - 1);
            Microsoft.Xna.Framework.Vector2 onj   = polygon.At(j);
            Microsoft.Xna.Framework.Vector2 nextj = polygon.At(j + 1);

            if (IsReflex(prevj, onj, nextj))
            {
                if (LeftOrOn(polygon.At(j), polygon.At(j - 1), polygon.At(i)) &&
                    RightOrOn(polygon.At(j), polygon.At(j + 1), polygon.At(i)))
                {
                    return(false);
                }
            }
            else
            {
                if (RightOrOn(polygon.At(j), polygon.At(j + 1), polygon.At(i)) ||
                    LeftOrOn(polygon.At(j), polygon.At(j - 1), polygon.At(i)))
                {
                    return(false);
                }
            }

            for (int k = 0; k < polygon.Count; ++k)
            {
                // YOGESH : changed from Line-Line intersection to Segment-Segment Intersection
                Microsoft.Xna.Framework.Vector2 p1 = polygon.At(i);
                Microsoft.Xna.Framework.Vector2 p2 = polygon.At(j);
                Microsoft.Xna.Framework.Vector2 q1 = polygon.At(k);
                Microsoft.Xna.Framework.Vector2 q2 = polygon.At(k + 1);

                // ignore incident edges
                if (p1.Equals(q1) || p1.Equals(q2) || p2.Equals(q1) || p2.Equals(q2))
                {
                    continue;
                }

                var intersection = LineAlgorithms.LineSegmentIntersection(p1, p2, q1, q2);

                if (intersection != null &&
                    intersection.WithinFirstSegment &&
                    intersection.WithinSecondSegment)
                {
                    Microsoft.Xna.Framework.Vector2 intPoint = intersection.IntersectionPoint;

                    // intPoint is not any of the j line then false, else continue. Intersection has to be interior to qualify s 'false' from here
                    if ((!intPoint.Equals(polygon.At(k))) || (!intPoint.Equals(polygon.At(k + 1))))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
예제 #27
0
        public void LineAlgorithmsIsCollinearTest()
        {
            // collinear lines
            Coordinate firstLineStart  = new Coordinate(1, 1);
            Coordinate firstLineEnd    = new Coordinate(4, 1);
            Coordinate secondLineStart = new Coordinate(1, 1);
            Coordinate secondLineEnd   = new Coordinate(4, 1);

            Assert.IsTrue(LineAlgorithms.IsCollinear(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(4, 1);
            secondLineStart = new Coordinate(1, 1);
            secondLineEnd   = new Coordinate(15, 1);
            Assert.IsTrue(LineAlgorithms.IsCollinear(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(16, 1);
            secondLineStart = new Coordinate(15, 1);
            secondLineEnd   = new Coordinate(2, 1);
            Assert.IsTrue(LineAlgorithms.IsCollinear(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(4, 1);
            secondLineStart = new Coordinate(15, 1);
            secondLineEnd   = new Coordinate(1, 1);
            Assert.IsTrue(LineAlgorithms.IsCollinear(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(4, 1);
            secondLineStart = new Coordinate(4, 1);
            secondLineEnd   = new Coordinate(-5, 1);
            Assert.IsTrue(LineAlgorithms.IsCollinear(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(20, 1);
            firstLineEnd    = new Coordinate(250, 1);
            secondLineEnd   = new Coordinate(1000, 1);
            secondLineStart = new Coordinate(250, 1);
            Assert.IsTrue(LineAlgorithms.IsCollinear(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(20, 1);
            firstLineEnd    = new Coordinate(250, 1);
            secondLineStart = new Coordinate(259, 1);
            secondLineEnd   = new Coordinate(1000, 1);
            Assert.IsTrue(LineAlgorithms.IsCollinear(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            // not collinear lines
            firstLineStart  = new Coordinate(20, 1);
            firstLineEnd    = new Coordinate(250, 1);
            secondLineStart = new Coordinate(1, 100);
            secondLineEnd   = new Coordinate(1, 1200);
            Assert.IsFalse(LineAlgorithms.IsCollinear(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(20, 1);
            firstLineEnd    = new Coordinate(250, 1);
            secondLineStart = new Coordinate(250, 1);
            secondLineEnd   = new Coordinate(1000, 2);
            Assert.IsFalse(LineAlgorithms.IsCollinear(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1.2, 1.2);
            firstLineEnd    = new Coordinate(1.2, 7.2);
            secondLineStart = new Coordinate(2.2, 8.2);
            secondLineEnd   = new Coordinate(2.2, 15.2);
            Assert.IsFalse(LineAlgorithms.IsCollinear(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));
        }
예제 #28
0
        public void LineAlgorithmsIsParallelTest()
        {
            // parallel lines
            Coordinate firstLineStart  = new Coordinate(1, 1);
            Coordinate firstLineEnd    = new Coordinate(4, 1);
            Coordinate secondLineStart = new Coordinate(2, 2);
            Coordinate secondLineEnd   = new Coordinate(4, 2);

            Assert.IsTrue(LineAlgorithms.IsParallel(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));
            Assert.IsFalse(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1.2, 1.2);
            firstLineEnd    = new Coordinate(1.2, 7.2);
            secondLineStart = new Coordinate(2.2, 8.2);
            secondLineEnd   = new Coordinate(2.2, 15.2);
            Assert.IsTrue(LineAlgorithms.IsParallel(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));
            Assert.IsFalse(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(1, 7);
            secondLineStart = new Coordinate(1, 1);
            secondLineEnd   = new Coordinate(1, 7);
            Assert.IsTrue(LineAlgorithms.IsParallel(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));
            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            // non parallel lines
            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(1, 7);
            secondLineStart = new Coordinate(2, 1);
            secondLineEnd   = new Coordinate(2.2, 8);
            Assert.IsFalse(LineAlgorithms.IsParallel(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            firstLineStart  = new Coordinate(1, 1);
            firstLineEnd    = new Coordinate(1, 7);
            secondLineStart = new Coordinate(0, 2);
            secondLineEnd   = new Coordinate(10, 2);
            Assert.IsFalse(LineAlgorithms.IsParallel(firstLineStart, firstLineEnd, secondLineStart, secondLineEnd));

            // parallel infinite lines
            firstLineStart = new Coordinate(1, 1);
            CoordinateVector firstVector = new CoordinateVector(0, 1);

            secondLineStart = new Coordinate(2, 2);
            CoordinateVector secondVector = new CoordinateVector(0, 1);

            Assert.IsTrue(LineAlgorithms.IsParallel(firstLineStart, firstVector, secondLineStart, secondVector));

            firstLineStart  = new Coordinate(2, 5);
            firstVector     = new CoordinateVector(0, 1);
            secondLineStart = new Coordinate(2, 4);
            secondVector    = new CoordinateVector(0, 4);
            Assert.IsTrue(LineAlgorithms.Coincides(firstLineStart, firstVector, secondLineStart, secondVector));
            Assert.IsTrue(LineAlgorithms.IsParallel(firstLineStart, firstVector, secondLineStart, secondVector));

            firstLineStart  = new Coordinate(2, 4);
            firstVector     = new CoordinateVector(-3, 1);
            secondLineStart = new Coordinate(5, 3);
            secondVector    = new CoordinateVector(-3, 1);
            Assert.IsTrue(LineAlgorithms.IsParallel(firstLineStart, firstVector, secondLineStart, secondVector));

            // non parallel infinite lines
            firstLineStart  = new Coordinate(1, 1);
            firstVector     = new CoordinateVector(0, 1);
            secondLineStart = new Coordinate(1, 1);
            secondVector    = new CoordinateVector(1, 0);
            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstVector, secondLineStart, secondVector));
            Assert.IsFalse(LineAlgorithms.IsParallel(firstLineStart, firstVector, secondLineStart, secondVector));

            firstLineStart  = new Coordinate(2, 5);
            firstVector     = new CoordinateVector(0, 1);
            secondLineStart = new Coordinate(2, 4);
            secondVector    = new CoordinateVector(4, 0);
            Assert.IsTrue(LineAlgorithms.Intersects(firstLineStart, firstVector, secondLineStart, secondVector));
            Assert.IsFalse(LineAlgorithms.IsParallel(firstLineStart, firstVector, secondLineStart, secondVector));
        }
        /// <summary>
        /// Computes the intersection of one or more line strings.
        /// </summary>
        public void Compute()
        {
            // source: http://geomalgorithms.com/a09-_intersect-3.html

            _intersections = new List <Coordinate>();
            _edgeIndices   = new List <Tuple <Int32, Int32> >();
            Event              currentEvent = _eventQueue.Next();
            SweepLineSegment   segment;
            IList <Coordinate> intersections;

            while (currentEvent != null)
            {
                if (currentEvent is EndPointEvent)
                {
                    EndPointEvent endPointEvent = (EndPointEvent)currentEvent;
                    switch (endPointEvent.Type)
                    {
                    // Left endpoint event: check for possible intersection with below and / or above segments.
                    case EventType.Left:
                        segment = _sweepLine.Add(endPointEvent);
                        if (segment.Above != null)
                        {
                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segment.Above.LeftCoordinate, segment.Above.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0)
                            {
                                IntersectionEvent intersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segment,
                                    Above  = segment.Above
                                };
                                _eventQueue.Add(intersectionEvent);
                            }
                        }
                        if (segment.Below != null)
                        {
                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segment.Below.LeftCoordinate, segment.Below.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0)
                            {
                                IntersectionEvent intersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segment.Below,
                                    Above  = segment
                                };
                                _eventQueue.Add(intersectionEvent);
                            }
                        }
                        break;

                    // Right endpoint event: check for possible intersection of the below and above segments.
                    case EventType.Right:
                        segment = _sweepLine.Search(endPointEvent);
                        if (segment != null)
                        {
                            if (segment.Above != null && segment.Below != null)
                            {
                                intersections = LineAlgorithms.Intersection(segment.Above.LeftCoordinate,
                                                                            segment.Above.RightCoordinate,
                                                                            segment.Below.LeftCoordinate,
                                                                            segment.Below.RightCoordinate,
                                                                            PrecisionModel);

                                if (intersections.Count > 0)
                                {
                                    IntersectionEvent intersectionEvent = new IntersectionEvent
                                    {
                                        Vertex = intersections[0],
                                        Below  = segment.Below,
                                        Above  = segment.Above
                                    };
                                    if (!_eventQueue.Contains(intersectionEvent))
                                    {
                                        _eventQueue.Add(intersectionEvent);
                                    }
                                }
                            }
                            _sweepLine.Remove(segment);
                        }
                        break;
                    }
                }

                // Intersection point event: switch the two concerned segments and check for possible intersection with their below and above segments.
                else if (currentEvent is IntersectionEvent)
                {
                    IntersectionEvent intersectionEvent = (IntersectionEvent)currentEvent;

                    /*
                     * Segment order before intersection: segmentBelow <-> segmentAbove <-> segment <-> segmentAboveAbove
                     * Segment order after intersection:  segmentBelow <-> segment <-> segmentAbove <-> segmentAboveAbove
                     */
                    segment = intersectionEvent.Above;
                    SweepLineSegment segmentAbove = intersectionEvent.Below;

                    // Handle closing intersection points when segments (partially) overlap each other.
                    if (intersectionEvent.IsClose)
                    {
                        if (!_sweepLine.IsAdjacent(segment.Edge, segmentAbove.Edge))
                        {
                            _intersections.Add(currentEvent.Vertex);
                            _edgeIndices.Add(Tuple.Create(Math.Min(segment.Edge, segmentAbove.Edge),
                                                          Math.Max(segment.Edge, segmentAbove.Edge)));
                        }
                    }

                    // It is possible that the previously detected intersection point is not a real intersection, because a new segment started between them,
                    // therefore a repeated check is necessary to carry out.
                    else if (_sweepLine.Add(intersectionEvent))
                    {
                        if (!_sweepLine.IsAdjacent(segment.Edge, segmentAbove.Edge))
                        {
                            _intersections.Add(currentEvent.Vertex);
                            _edgeIndices.Add(Tuple.Create(Math.Min(segment.Edge, segmentAbove.Edge),
                                                          Math.Max(segment.Edge, segmentAbove.Edge)));

                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segmentAbove.LeftCoordinate, segmentAbove.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 1 && !intersections[1].Equals(intersections[0]))
                            {
                                IntersectionEvent newIntersectionEvent = new IntersectionEvent
                                {
                                    Vertex  = intersections[1],
                                    Below   = segment,
                                    Above   = segmentAbove,
                                    IsClose = true,
                                };
                                _eventQueue.Add(newIntersectionEvent);
                            }
                        }

                        if (segmentAbove.Above != null)
                        {
                            intersections = LineAlgorithms.Intersection(segmentAbove.LeftCoordinate, segmentAbove.RightCoordinate,
                                                                        segmentAbove.Above.LeftCoordinate, segmentAbove.Above.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0 && intersections[0].X >= intersectionEvent.Vertex.X)
                            {
                                IntersectionEvent newIntersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segmentAbove,
                                    Above  = segmentAbove.Above
                                };
                                if (!_eventQueue.Contains(newIntersectionEvent))
                                {
                                    _eventQueue.Add(newIntersectionEvent);
                                }
                            }
                        }

                        if (segment.Below != null)
                        {
                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segment.Below.LeftCoordinate, segment.Below.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0 && intersections[0].X >= intersectionEvent.Vertex.X)
                            {
                                IntersectionEvent newIntersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segment.Below,
                                    Above  = segment
                                };
                                if (!_eventQueue.Contains(newIntersectionEvent))
                                {
                                    _eventQueue.Add(newIntersectionEvent);
                                }
                            }
                        }
                    }
                }

                currentEvent = _eventQueue.Next();
            }
            _hasResult = true;
        }
예제 #30
0
        /// <summary>
        /// Processes the end point event.
        /// </summary>
        /// <param name="endPointEvent">The end point event.</param>
        private void ProcessEndPointEvent(EndPointEvent endPointEvent)
        {
            SweepLineSegment segment;
            Intersection     intersection;

            switch (endPointEvent.Type)
            {
            // left endpoint event: check for possible intersection with below and / or above segments
            case EventType.Left:
                segment = this.sweepLine.Add(endPointEvent);

                if (segment.Above != null)
                {
                    intersection = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate, segment.Above.LeftCoordinate, segment.Above.RightCoordinate, this.PrecisionModel);

                    if (intersection != null)
                    {
                        IntersectionEvent intersectionEvent = new IntersectionEvent
                        {
                            Vertex = intersection.Coordinate,
                            Below  = segment,
                            Above  = segment.Above
                        };
                        this.eventQueue.Add(intersectionEvent);
                    }
                }

                if (segment.Below != null)
                {
                    intersection = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate, segment.Below.LeftCoordinate, segment.Below.RightCoordinate, this.PrecisionModel);

                    if (intersection != null)
                    {
                        IntersectionEvent intersectionEvent = new IntersectionEvent
                        {
                            Vertex = intersection.Coordinate,
                            Below  = segment.Below,
                            Above  = segment
                        };
                        this.eventQueue.Add(intersectionEvent);
                    }
                }

                break;

            // right endpoint event: check for possible intersection of the below and above segments
            case EventType.Right:
                segment = this.sweepLine.Search(endPointEvent);

                if (segment != null)
                {
                    if (segment.Above != null && segment.Below != null)
                    {
                        intersection = LineAlgorithms.Intersection(segment.Above.LeftCoordinate, segment.Above.RightCoordinate, segment.Below.LeftCoordinate, segment.Below.RightCoordinate, this.PrecisionModel);

                        if (intersection != null)
                        {
                            IntersectionEvent intersectionEvent = new IntersectionEvent
                            {
                                Vertex = intersection.Coordinate,
                                Below  = segment.Below,
                                Above  = segment.Above
                            };
                            if (!this.eventQueue.Contains(intersectionEvent))
                            {
                                this.eventQueue.Add(intersectionEvent);
                            }
                        }
                    }

                    this.sweepLine.Remove(segment);
                }

                break;
            }
        }