Ejemplo n.º 1
0
        /// <summary>
        /// Finds all intersections between the specified line segments, using a brute force
        /// algorithm and given the specified epsilon for coordinate comparisons.</summary>
        /// <param name="lines">
        /// An <see cref="Array"/> containing the <see cref="LineD"/> instances to intersect.
        /// </param>
        /// <param name="epsilon">
        /// The maximum absolute difference at which two coordinates should be considered equal.
        /// </param>
        /// <returns>
        /// A lexicographically sorted <see cref="Array"/> containing a <see cref="MultiLinePoint"/>
        /// for every point of intersection between the <paramref name="lines"/>.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="lines"/> is a null reference.</exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="epsilon"/> is equal to or less than zero.</exception>
        /// <remarks>
        /// <b>FindSimple</b> is identical with the basic <see cref="FindSimple(LineD[])"/> overload
        /// but uses the specified <paramref name="epsilon"/> to determine intersections between the
        /// specified <paramref name="lines"/> and to combine nearby intersections.</remarks>

        public static MultiLinePoint[] FindSimple(LineD[] lines, double epsilon)
        {
            if (lines == null)
            {
                ThrowHelper.ThrowArgumentNullException("lines");
            }
            if (epsilon <= 0.0)
            {
                ThrowHelper.ThrowArgumentOutOfRangeException(
                    "epsilon", epsilon, Strings.ArgumentNotPositive);
            }

            var crossings = new BraidedTree <PointD, EventPoint>(
                (a, b) => PointDComparerY.CompareEpsilon(a, b, epsilon));

            for (int i = 0; i < lines.Length - 1; i++)
            {
                for (int j = i + 1; j < lines.Length; j++)
                {
                    var crossing = lines[i].Intersect(lines[j], epsilon);

                    if (crossing.Exists)
                    {
                        PointD p = crossing.Shared.Value;
                        BraidedTreeNode <PointD, EventPoint> node;
                        crossings.TryAddNode(p, new EventPoint(p), out node);
                        node._value.TryAddLines(i, crossing.First, j, crossing.Second);
                    }
                }
            }

            return(EventPoint.Convert(crossings.Values));
        }
Ejemplo n.º 2
0
        /// <overloads>
        /// Finds all intersections between the specified line segments, using a brute force
        /// algorithm.</overloads>
        /// <summary>
        /// Finds all intersections between the specified line segments, using a brute force
        /// algorithm and exact coordinate comparisons.</summary>
        /// <param name="lines">
        /// An <see cref="Array"/> containing the <see cref="LineD"/> instances to intersect.
        /// </param>
        /// <returns>
        /// A lexicographically sorted <see cref="Array"/> containing a <see cref="MultiLinePoint"/>
        /// for every point of intersection between the <paramref name="lines"/>.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="lines"/> is a null reference.</exception>
        /// <remarks><para>
        /// <b>FindSimple</b> performs a pairwise intersection of every <paramref name="lines"/>
        /// element with every other element. The runtime is therefore always O(n^2), regardless of
        /// the number of intersections found.
        /// </para><para>
        /// However, the constant factor is low and O(n^2) intersections are found in optimal time
        /// because <b>FindSimple</b> performs no additional work to avoid testing for possible
        /// intersections. For a small number of <paramref name="lines"/> (n &lt; 50),
        /// <b>FindSimple</b> usually beats the sweep line algorithm implemented by <see
        /// cref="Find"/> regardless of the number of intersections.</para></remarks>

        public static MultiLinePoint[] FindSimple(LineD[] lines)
        {
            if (lines == null)
            {
                ThrowHelper.ThrowArgumentNullException("lines");
            }

            var crossings = new BraidedTree <PointD, EventPoint>(PointDComparerY.CompareExact);

            for (int i = 0; i < lines.Length - 1; i++)
            {
                for (int j = i + 1; j < lines.Length; j++)
                {
                    var crossing = lines[i].Intersect(lines[j]);

                    if (crossing.Exists)
                    {
                        PointD p = crossing.Shared.Value;
                        BraidedTreeNode <PointD, EventPoint> node;
                        crossings.TryAddNode(p, new EventPoint(p), out node);
                        node._value.TryAddLines(i, crossing.First, j, crossing.Second);
                    }
                }
            }

            return(EventPoint.Convert(crossings.Values));
        }
Ejemplo n.º 3
0
        /// <overloads>
        /// Initializes a new instance of the <see cref="BraidedTreeNode{TKey, TValue}"/> class.
        /// </overloads>
        /// <summary>
        /// Initializes a new instance of the <see cref="BraidedTreeNode{TKey, TValue}"/> class with
        /// the specified tree structure.</summary>
        /// <param name="tree">
        /// The <see cref="BraidedTree{TKey, TValue}"/> that contains the <see
        /// cref="BraidedTreeNode{TKey, TValue}"/>.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="tree"/> is a null reference.</exception>
        /// <remarks>
        /// <see cref="Priority"/> is set to -1.0. The <see cref="Key"/> property remains at its
        /// default value, which is a null reference if <typeparamref name="TKey"/> is a reference
        /// type. Use this constructor only for the <see cref="BraidedTree{TKey, TValue}.RootNode"/>
        /// of the specified <paramref name="tree"/>.</remarks>

        internal BraidedTreeNode(BraidedTree <TKey, TValue> tree)
        {
            if (tree == null)
            {
                ThrowHelper.ThrowArgumentNullException("tree");
            }

            _tree     = tree;
            _next     = _previous = this;
            _priority = -1.0;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Removes the <see cref="BraidedTreeNode{TKey, TValue}"/>, which must be a leaf node, from
        /// the tree structure.</summary>
        /// <remarks><para>
        /// <b>RemoveTree</b> sets the <see cref="Left"/> or <see cref="Right"/> reference of the
        /// <see cref="Parent"/> node, whichever matches the current instance, to a null reference,
        /// and updates the chains of <see cref="Previous"/> and <see cref="Next"/> references to
        /// exclude the current instance.
        /// </para><para>
        /// All <see cref="BraidedTreeNode{TKey, TValue}"/> references of the current instance are
        /// reset to default values, as with <see cref="Clear"/>. Moreover, <b>RemoveTree</b> sets
        /// the <see cref="Tree"/> property to a null reference.</para></remarks>

        internal void RemoveTree()
        {
            Debug.Assert(_left == null && _right == null);

            if (_parent._left == this)
            {
                _parent._left = null;
            }
            else
            {
                Debug.Assert(_parent._right == this);
                _parent._right = null;
            }

            _parent = null;
            RemoveList();
            _tree = null;
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="BraidedTreeNode{TKey, TValue}"/> class with
        /// the specified tree structure, key and value.</summary>
        /// <param name="tree">
        /// The <see cref="BraidedTree{TKey, TValue}"/> that contains the <see
        /// cref="BraidedTreeNode{TKey, TValue}"/>.</param>
        /// <param name="key">
        /// The key of the <see cref="BraidedTreeNode{TKey, TValue}"/>.</param>
        /// <param name="value">
        /// The value of the <see cref="BraidedTreeNode{TKey, TValue}"/>.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="tree"/> or <paramref name="key"/> is a null reference.</exception>
        /// <exception cref="KeyMismatchException">
        /// <paramref name="value"/> is an <see cref="IKeyedValue{TKey}"/> instance whose <see
        /// cref="KeyValuePair{TKey, TValue}.Key"/> differs from the specified <paramref
        /// name="key"/>.</exception>
        /// <remarks>
        /// <see cref="Priority"/> is set to a random value in the open interval [0, 1).</remarks>

        internal BraidedTreeNode(BraidedTree <TKey, TValue> tree, TKey key, TValue value)
        {
            if (tree == null)
            {
                ThrowHelper.ThrowArgumentNullException("tree");
            }

            if (value is IKeyedValue <TKey> )
            {
                CollectionsUtility.ValidateKey(Key, value);
            }
            else if (key == null)
            {
                ThrowHelper.ThrowArgumentNullException("key");
            }

            _tree     = tree;
            _next     = _previous = this;
            _priority = tree.Random.NextDouble();
            Key       = key; _value = value;
        }
Ejemplo n.º 6
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);
        }
Ejemplo n.º 7
0
            /// <summary>
            /// Initializes a new instance of the <see cref="Status"/> class.</summary>

            internal Status()
            {
                Crossings = new List <EventPoint>();
                Schedule  = new BraidedTree <PointD, EventPoint>(PointDComparerY.CompareExact);
                SweepLine = new BraidedTree <Int32, Int32>(CompareLines);
            }