Example #1
0
            /// <summary>
            /// Finds all intersections between the specified line segments, using a sweep line
            /// algorithm.</summary>
            /// <param name="lines">
            /// An <see cref="Array"/> containing the <see cref="LineD"/> segments to intersect.
            /// </param>
            /// <returns>
            /// A lexicographically sorted <see cref="List{T}"/> containing the final <see
            /// cref="EventPoint"/> for every point of intersection between two or more <paramref
            /// name="lines"/>.</returns>
            /// <exception cref="ArgumentException">
            /// <paramref name="lines"/> contains a <see cref="LineD"/> whose <see
            /// cref="LineD.Start"/> and <see cref="LineD.End"/> coordinates are equal.</exception>
            /// <exception cref="ArgumentNullException">
            /// <paramref name="lines"/> is a null reference.</exception>
            /// <exception cref="InvalidOperationException">
            /// <paramref name="lines"/> contains coordinates that caused corruption to an internal
            /// search structure.</exception>
            /// <remarks>
            /// <b>FindCore</b> creates the intermediate output which is further processed by one of
            /// the <see cref="Find"/> overloads.</remarks>

            internal List <EventPoint> FindCore(LineD[] lines)
            {
                BuildSchedule(lines);

                while (Schedule.Count > 0)
                {
                    var node = Schedule.RootNode._next;
                    Schedule.RemoveNode(node);
                    HandleEvent(node._value);
                }

                if (SweepLine.Count > 0)
                {
                    ThrowHelper.ThrowInvalidOperationException(Strings.SearchStructureCorrupted);
                }

                return(Crossings);
            }
Example #2
0
            /// <summary>
            /// Handles the specified <see cref="EventPoint"/> that was just removed from the <see
            /// cref="Schedule"/>.</summary>
            /// <param name="e">
            /// The <see cref="EventPoint"/> to handle.</param>
            /// <remarks>
            /// <b>HandleEvent</b> always updates the <see cref="SweepLine"/>, and possibly the <see
            /// cref="Schedule"/> via <see cref="AddCrossing"/>.</remarks>

            private void HandleEvent(EventPoint e)
            {
                BraidedTreeNode <Int32, Int32> node, previous = null, next = null;

                Cursor = e.Shared;
                bool adding = false;

                // remove end point & crossing nodes
                for (int i = 0; i < e.Locations.Count; i++)
                {
                    switch (e.Locations[i])
                    {
                    case LineLocation.Start:
                        adding = true;
                        break;

                    case LineLocation.End:
                        node = SweepLine.FindNode(e.Lines[i]);
                        if (node == null)
                        {
                            ThrowHelper.ThrowInvalidOperationException(
                                Strings.SearchStructureCorrupted);
                        }

                        // remember surrounding lines
                        previous = node._previous;
                        next     = node._next;
                        SweepLine.RemoveNode(node);
                        break;

                    case LineLocation.Between:
                        if (!SweepLine.Remove(e.Lines[i]))
                        {
                            ThrowHelper.ThrowInvalidOperationException(
                                Strings.SearchStructureCorrupted);
                        }
                        adding = true;
                        break;
                    }
                }

                if (!adding)
                {
                    // intersect remaining neighbors of removed lines
                    if (previous._parent != null && next._parent != null)
                    {
                        AddCrossing(previous, next, e);
                    }

                    // record intersection event
                    var lines = e.Lines;
                    if (lines.Count < 2)
                    {
                        return;
                    }

                    /*
                     * The sweep line algorithm would normally record TWO intersections for
                     * overlapping lines that share the same lexicographic end point: one for the
                     * start point, and one for the end point. So when we encounter an event that
                     * contains only end points, we must check that its line segments arrive from at
                     * least two different directions, and only then record an intersection.
                     */

                    double slope = Slopes[lines[0]];
                    for (int i = 1; i < lines.Count; i++)
                    {
                        if (slope != Slopes[lines[i]])
                        {
                            e.Normalize(Lines);
                            Crossings.Add(e);
                            break;
                        }
                    }

                    return;
                }

                // update remaining sweep line to prepare for insertion
                var root = SweepLine.RootNode;

                for (node = root._next; node != root; node = node._next)
                {
                    int    index = node.Key;
                    double slope = Slopes[index];
                    if (slope != Double.MaxValue)
                    {
                        PointD start = Lines[index].Start;
                        Positions[index] = slope * (Cursor.Y - start.Y) + start.X;
                    }
                }

                // (re-)insert start point & crossing nodes
                previous = next = null;
                for (int i = 0; i < e.Locations.Count; i++)
                {
                    if (e.Locations[i] != LineLocation.End)
                    {
                        int index = e.Lines[i];
                        Positions[index] = Cursor.X;
                        SweepLine.TryAddNode(index, 0, out node);

                        // remember surrounding lines
                        if (previous == null)
                        {
                            previous = node._previous;
                            next     = node._next;
                        }
                    }
                }

                // intersect outermost added lines with existing neighbors
                if (previous._parent != null)
                {
                    AddCrossing(previous, previous._next, e);
                }
                if (next._parent != null)
                {
                    AddCrossing(next._previous, next, e);
                }

                // record intersection event
                if (e.Lines.Count > 1)
                {
                    e.Normalize(Lines);
                    Crossings.Add(e);
                }
            }