Esempio n. 1
0
            /// <summary>
            /// Adds an intersection <see cref="EventPoint"/> to the <see cref="Schedule"/> if the
            /// two specified <see cref="SweepLine"/> nodes indicate a line crossing.</summary>
            /// <param name="a">
            /// The first <see cref="SweepLine"/> node to examine.</param>
            /// <param name="b">
            /// The second <see cref="SweepLine"/> node to examine.</param>
            /// <param name="e">
            /// The current <see cref="EventPoint"/> which receives a detected crossing that occurs
            /// exactly at the <see cref="Cursor"/>.</param>
            /// <remarks>
            /// If the <see cref="Schedule"/> already contains an <see cref="EventPoint"/> for the
            /// computed intersection, <b>AddCrossing</b> adds the indicated lines to the existing
            /// <see cref="EventPoint"/> if they are not already present.</remarks>

            private void AddCrossing(BraidedTreeNode <Int32, Int32> a,
                                     BraidedTreeNode <Int32, Int32> b, EventPoint e)
            {
                int aIndex = a.Key, bIndex = b.Key;
                LineIntersection c = Lines[aIndex].Intersect(Lines[bIndex]);

                // ignore crossings that involve only start or end points,
                // as those line events have been scheduled during initialization
                if ((c.First == LineLocation.Between && LineIntersection.Contains(c.Second)) ||
                    (LineIntersection.Contains(c.First) && c.Second == LineLocation.Between))
                {
                    // quit if crossing occurs before cursor
                    PointD p      = c.Shared.Value;
                    int    result = PointDComparerY.CompareExact(Cursor, p);
                    if (result > 0)
                    {
                        return;
                    }

                    // update schedule if crossing occurs after cursor
                    if (result < 0)
                    {
                        BraidedTreeNode <PointD, EventPoint> node;
                        Schedule.TryAddNode(p, new EventPoint(p), out node);
                        e = node._value;
                    }

                    // add crossing to current or scheduled event point
                    e.TryAddLines(aIndex, c.First, bIndex, c.Second);
                }
            }
Esempio n. 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);
                }
            }