/// <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)); }
/// <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 < 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)); }
/// <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; }
/// <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; }
/// <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; }
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); }
/// <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); }