Exemplo n.º 1
0
        /// <summary>
        /// Performs the order modifying effect of a possible intersection point between two directly adjacent segments.
        /// </summary>
        /// <remarks>
        /// An intersection event may become invalid if the order of the segments were altered or the intersection point has been already passed by the sweep line since the enqueuing of the event.
        /// This method is safe to be applied for invalid intersections.
        /// </remarks>
        /// <param name="x">First segment.</param>
        /// <param name="y">Second segment.</param>
        /// <returns><c>true</c> if a new, valid intersection point was found and passed between <paramref name="x" /> and <paramref name="y" />; otherwise <c>false</c>.</returns>
        /// <exception cref="InvalidOperationException">Segment <paramref name="x" /> and <paramref name="y" /> do not intersect each other.</exception>
        public Boolean Intersect(SweepLineSegment x, SweepLineSegment y)
        {
            var comparer = ((SweepLineSegmentComparer)_tree.Comparer);
            SweepLineIntersection intersection = comparer.GetIntersection(x, y);

            if (intersection == SweepLineIntersection.NotExists)
            {
                throw new InvalidOperationException("The given segments do not intersect each other.");
            }
            if (intersection == SweepLineIntersection.Passed)
            {
                return(false);
            }

            /*
             * Segment order before intersection: belowBelow <-> below <-> above <-> aboveAbove
             * Segment order after intersection:  belowBelow <-> above <-> below <-> aboveAbove
             */
            SweepLineSegment below, above;

            if (x.Above == y)
            {
                below = x;
                above = y;
            }
            else if (y.Above == x)
            {
                below = y;
                above = x;
            }
            else
            {
                return(false);
            }

            _tree.Remove(x);
            _tree.Remove(y);
            comparer.PassIntersection(x, y);
            _tree.Insert(x);
            _tree.Insert(y);

            SweepLineSegment belowBelow = below.Below;
            SweepLineSegment aboveAbove = above.Above;

            below.Above = aboveAbove;
            below.Below = above;
            above.Below = belowBelow;
            above.Above = below;

            if (belowBelow != null)
            {
                belowBelow.Above = above;
            }
            if (aboveAbove != null)
            {
                aboveAbove.Below = below;
            }

            return(true);
        }
        public void SweepLine_Smoke_Test()
        {
            var lines = new List <Line>(new[]
            {
                new Line(new Point(0, 0), new Point(10, 10)),
                new Line(new Point(5, 0), new Point(5, 10)),
                new Line(new Point(0, 2), new Point(15, 2))
            });

            var expectedIntersections = getExpectedIntersections(lines);
            var actualIntersections   = SweepLineIntersection.FindIntersections(lines).ToList();

            Assert.AreEqual(expectedIntersections.Count, actualIntersections.Count);
        }
        public void SweepLine_Test()
        {
            List <Line> lines = null;

            while (true)
            {
                lines = getRandomLines(3);

                var expectedIntersections = getExpectedIntersections(lines);
                var actualIntersections   = SweepLineIntersection.FindIntersections(lines);

                if (expectedIntersections.Count != actualIntersections.Count)
                {
                }
                // Assert.AreEqual(expectedIntersections.Count, actualIntersections.Count);
            }
        }
Exemplo n.º 4
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));
            }
Exemplo n.º 5
0
        /// <summary>
        /// Performs the order modifying effect of a possible intersection point between two directly adjacent segments.
        /// </summary>
        /// <remarks>
        /// An intersection event may become invalid if the order of the segments were altered or the intersection point has been already passed by the sweep line since the enqueuing of the event.
        /// This method is safe to be applied for invalid intersections.
        /// </remarks>
        /// <param name="x">First segment.</param>
        /// <param name="y">Second segment.</param>
        /// <returns><c>true</c> if a new, valid intersection point was found and passed between <paramref name="x" /> and <paramref name="y" />; otherwise <c>false</c>.</returns>
        /// <exception cref="InvalidOperationException">The segments do not intersect each other.</exception>
        public Boolean Intersect(SweepLineSegment x, SweepLineSegment y)
        {
            if (x == null || y == null)
            {
                return(false);
            }

            SweepLineSegmentComparer comparer     = (SweepLineSegmentComparer)this.tree.Comparer;
            SweepLineIntersection    intersection = comparer.GetIntersection(x, y);

            if (intersection == SweepLineIntersection.NotExists)
            {
                throw new InvalidOperationException(CoreMessages.SegmentsDoNotIntersect);
            }
            if (intersection == SweepLineIntersection.Passed)
            {
                return(false);
            }

            /*
             * Segment order before intersection: belowBelow <-> below <-> above <-> aboveAbove
             * Segment order after intersection:  belowBelow <-> above <-> below <-> aboveAbove
             */
            SweepLineSegment below, above;

            if (x.Above == y)
            {
                below = x;
                above = y;
            }
            else if (y.Above == x)
            {
                below = y;
                above = x;
            }
            else
            {
                return(false);
            }

            this.tree.Remove(x);
            this.tree.Remove(y);
            comparer.PassIntersection(x, y);
            this.tree.Insert(x);
            this.tree.Insert(y);

            SweepLineSegment belowBelow = below.Below;
            SweepLineSegment aboveAbove = above.Above;

            below.Above = aboveAbove;
            below.Below = above;
            above.Below = belowBelow;
            above.Above = below;

            if (belowBelow != null)
            {
                belowBelow.Above = above;
            }
            if (aboveAbove != null)
            {
                aboveAbove.Below = below;
            }

            return(true);
        }