예제 #1
0
        public void WalkTree()
        {
            const int radius = 3000;
            var       array  = new KeyValuePair <PointD, CloneableType> [2 * radius];

            for (int i = 0; i < array.Length; i++)
            {
                array[i] = new KeyValuePair <PointD, CloneableType>(
                    new PointD(i - radius, radius - i),
                    new CloneableType(String.Format("bar{0:D3} value", i)));
            }

            var tree = new QuadTree <CloneableType>(
                new RectD(-2 * radius, -2 * radius, 4 * radius, 4 * radius));

            Assert.AreEqual(tree, tree.RootNode.Tree);
            Assert.AreEqual(1, tree.Nodes.Count);

            // test adding elements
            foreach (var pair in array)
            {
                tree.Add(pair.Key, pair.Value);
            }
            Assert.AreEqual(array.Length, tree.Count);
            Assert.AreEqual(145, tree.Nodes.Count);

            // test moving elements without hint node
            PointD offset = new PointD(0.1, 0.1);

            foreach (var pair in array)
            {
                tree.Move(pair.Key, pair.Key + offset);
            }

            // test moving elements with hint node
            QuadTreeNode <CloneableType> node = null;

            foreach (var pair in array)
            {
                node = tree.Move(pair.Key + offset, pair.Key, node);
            }

            Assert.AreEqual(array.Length, tree.Count);
            Assert.AreEqual(145, tree.Nodes.Count);

            // test finding elements
            foreach (var pair in array)
            {
                CloneableType value;
                Assert.IsTrue(tree.TryGetValue(pair.Key, out value));
                Assert.AreEqual(pair.Value, value);

                node = tree.FindNode(pair.Key);
                Assert.AreEqual(tree, node.Tree);
                Assert.IsTrue(node.Data.Contains(pair));

                var valueNode = tree.FindNodeByValue(pair.Value);
                Assert.AreEqual(node, valueNode);
            }

            // test finding elements in range
            var range    = new RectD(-radius, 0, 2 * radius, 2 * radius);
            var elements = tree.FindRange(range);

            Assert.AreEqual(radius + 1, elements.Count);

            for (int i = 0; i <= radius; i++)
            {
                CloneableType value;
                Assert.IsTrue(elements.TryGetValue(array[i].Key, out value));
                Assert.AreEqual(array[i].Value, value);
            }

            // compare range search to BraidedTree
            var braidedTree = new BraidedTree <PointD, CloneableType>(PointDComparerY.CompareExact);

            foreach (var pair in array)
            {
                braidedTree.Add(pair);
            }

            // BraidedTree sorts by y-coordinates, so we must restrict x-coordinates
            var braidedElements = braidedTree.FindRange(range.TopLeft, range.BottomRight,
                                                        n => (n.Key.X >= range.Left && n.Key.X <= range.Right));

            Assert.AreEqual(elements.Count, braidedElements.Count);

            foreach (var pair in elements)
            {
                CloneableType value;
                Assert.IsTrue(braidedElements.TryGetValue(pair.Key, out value));
                Assert.AreEqual(pair.Value, value);
            }

            // test element enumeration
            foreach (var pair in tree)
            {
                CloneableType value;
                Assert.IsTrue(braidedTree.TryGetValue(pair.Key, out value));
                Assert.AreEqual(value, pair.Value);
                braidedTree.Remove(pair.Key);
            }
            Assert.AreEqual(0, braidedTree.Count);

            // test removing elements
            foreach (var pair in array)
            {
                Assert.IsTrue(tree.Remove(pair.Key));
            }
            Assert.AreEqual(0, tree.Count);
            Assert.AreEqual(1, tree.Nodes.Count);
        }
예제 #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);
                }
            }