Esempio n. 1
0
        /// <summary>
        /// Finds the item in this tree which is nearest to the given <paramref name="item"/>,
        /// using <see cref="IItemDistance{Envelope,TItem}"/> as the distance metric.
        /// A Branch-and-Bound tree traversal algorithm is used
        /// to provide an efficient search.
        /// <para/>
        /// The query <paramref name="item"/> does <b>not</b> have to be
        /// contained in the tree, but it does
        /// have to be compatible with the <paramref name="itemDist"/>
        /// distance metric.
        /// </summary>
        /// <param name="env">The envelope of the query item</param>
        /// <param name="item">The item to find the nearest neighbour of</param>
        /// <param name="itemDist">A distance metric applicable to the items in this tree and the query item</param>
        /// <returns>The nearest item in this tree</returns>
        public TItem NearestNeighbour(Envelope env, TItem item, IItemDistance <Envelope, TItem> itemDist)
        {
            var bnd = new ItemBoundable <Envelope, TItem>(env, item);
            var bp  = new BoundablePair <TItem>(Root, bnd, itemDist);

            return(NearestNeighbour(bp)[0]);
        }
Esempio n. 2
0
        private void Expand(IBoundable <Envelope, TItem> bndComposite, IBoundable <Envelope, TItem> bndOther, bool isFlipped,
                            PriorityQueue <BoundablePair <TItem> > priQ, double minDistance)
        {
            var children = ((AbstractNode <Envelope, TItem>)bndComposite).ChildBoundables;

            foreach (var child in children)
            {
                BoundablePair <TItem> bp;
                if (isFlipped)
                {
                    bp = new BoundablePair <TItem>(bndOther, child, _itemDistance);
                }
                else
                {
                    bp = new BoundablePair <TItem>(child, bndOther, _itemDistance);
                }

                // only add to queue if this pair might contain the closest points
                // MD - it's actually faster to construct the object rather than called distance(child, bndOther)!
                if (bp.Distance < minDistance)
                {
                    priQ.Add(bp);
                }
            }
        }
Esempio n. 3
0
        /// <inheritdoc cref="IComparer{T}.Compare"/>
        public int Compare(BoundablePair <TItem> p1, BoundablePair <TItem> p2)
        {
            double distance1 = p1.Distance;
            double distance2 = p2.Distance;

            if (_normalOrder)
            {
                if (distance1 > distance2)
                {
                    return(1);
                }
                if (distance1 == distance2)
                {
                    return(0);
                }

                return(-1);
            }
            else
            {
                if (distance1 > distance2)
                {
                    return(-1);
                }
                else if (distance1 == distance2)
                {
                    return(0);
                }

                return(1);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Finds the two nearest items from this tree
        /// and another tree,
        /// using <see cref="IItemDistance{Envelope, TItem}"/> as the distance metric.
        /// A Branch-and-Bound tree traversal algorithm is used
        /// to provide an efficient search.
        /// The result value is a pair of items,
        /// the first from this tree and the second
        /// from the argument tree.
        /// </summary>
        /// <param name="tree">Another tree</param>
        /// <param name="itemDist">A distance metric applicable to the items in the trees</param>
        /// <returns>The pair of the nearest items, one from each tree or <c>null</c> if no pair of distinct items can be found.</returns>
        public TItem[] NearestNeighbour(STRtree <TItem> tree, IItemDistance <Envelope, TItem> itemDist)
        {
            if (IsEmpty || tree.IsEmpty)
            {
                return(null);
            }
            var bp = new BoundablePair <TItem>(Root, tree.Root, itemDist);

            return(NearestNeighbour(bp));
        }
Esempio n. 5
0
 /// <summary>
 /// Compares two pairs based on their minimum distances
 /// </summary>
 public int CompareTo(BoundablePair <TItem> o)
 {
     if (_distance < o._distance)
     {
         return(-1);
     }
     if (_distance > o._distance)
     {
         return(1);
     }
     return(0);
 }
Esempio n. 6
0
        /// <summary>
        /// Finds the two nearest items in the tree,
        /// using <see cref="IItemDistance{Envelope, TItem}"/> as the distance metric.
        /// A Branch-and-Bound tree traversal algorithm is used
        /// to provide an efficient search.
        /// <para/>
        /// If the tree is empty, the return value is <c>null</c>.
        /// If the tree contains only one item, the return value is a pair containing that item.
        /// If it is required to find only pairs of distinct items,
        /// the <see cref="IItemDistance{T,TItem}"/> function must be <b>anti-reflexive</b>.
        /// </summary>
        /// <param name="itemDist">A distance metric applicable to the items in this tree</param>
        /// <returns>The pair of the nearest items or <c>null</c> if the tree is empty</returns>
        public TItem[] NearestNeighbour(IItemDistance <Envelope, TItem> itemDist)
        {
            if (IsEmpty)
            {
                return(null);
            }

            // if tree has only one item this will return null
            var bp = new BoundablePair <TItem>(Root, Root, itemDist);

            return(NearestNeighbour(bp));
        }
Esempio n. 7
0
        private TItem[] NearestNeighbour(BoundablePair <TItem> initBndPair, double maxDistance, int k)
        {
            double distanceLowerBound = maxDistance;

            // initialize internal structures
            var priQ = new PriorityQueue <BoundablePair <TItem> >();

            // initialize queue
            priQ.Add(initBndPair);

            var kNearestNeighbors = new PriorityQueue <BoundablePair <TItem> >(k, new BoundablePairDistanceComparer <TItem>(false));

            while (!priQ.IsEmpty() && distanceLowerBound >= 0.0)
            {
                // pop head of queue and expand one side of pair
                var bndPair = priQ.Poll();

                double currentDistance = bndPair.Distance;

                /**
                 * If the distance for the first node in the queue
                 * is >= the current maximum distance in the k queue , all other nodes
                 * in the queue must also have a greater distance.
                 * So the current minDistance must be the true minimum,
                 * and we are done.
                 */

                if (currentDistance >= distanceLowerBound)
                {
                    break;
                }

                /**
                 * If the pair members are leaves
                 * then their distance is the exact lower bound.
                 * Update the distanceLowerBound to reflect this
                 * (which must be smaller, due to the test
                 * immediately prior to this).
                 */
                if (bndPair.IsLeaves)
                {
                    // assert: currentDistance < minimumDistanceFound

                    if (kNearestNeighbors.Size < k)
                    {
                        kNearestNeighbors.Add(bndPair);
                    }
                    else
                    {
                        if (kNearestNeighbors.Peek().Distance > currentDistance)
                        {
                            kNearestNeighbors.Poll();
                            kNearestNeighbors.Add(bndPair);
                        }

                        /*
                         * minDistance should be the farthest point in the K nearest neighbor queue.
                         */
                        distanceLowerBound = kNearestNeighbors.Peek().Distance;
                    }
                }
                else
                {
                    // testing - does allowing a tolerance improve speed?
                    // Ans: by only about 10% - not enough to matter

                    /*
                     * double maxDist = bndPair.getMaximumDistance();
                     * if (maxDist * .99 < lastComputedDistance)
                     * return;
                     * //*/

                    /**
                     * Otherwise, expand one side of the pair,
                     * (the choice of which side to expand is heuristically determined)
                     * and insert the new expanded pairs into the queue
                     */
                    bndPair.ExpandToQueue(priQ, distanceLowerBound);
                }
            }
            // done - return items with min distance

            return(GetItems(kNearestNeighbors));
        }
Esempio n. 8
0
        private static TItem[] NearestNeighbour(BoundablePair <TItem> initBndPair, double maxDistance)
        {
            double distanceLowerBound     = maxDistance;
            BoundablePair <TItem> minPair = null;

            // initialize internal structures
            var priQ = new PriorityQueue <BoundablePair <TItem> >();

            // initialize queue
            priQ.Add(initBndPair);

            while (!priQ.IsEmpty() && distanceLowerBound > 0.0)
            {
                // pop head of queue and expand one side of pair
                var    bndPair         = priQ.Poll();
                double currentDistance = bndPair.Distance; //bndPair.GetDistance();

                /**
                 * If the distance for the first node in the queue
                 * is >= the current minimum distance, all other nodes
                 * in the queue must also have a greater distance.
                 * So the current minDistance must be the true minimum,
                 * and we are done.
                 */
                if (currentDistance >= distanceLowerBound)
                {
                    break;
                }

                /**
                 * If the pair members are leaves
                 * then their distance is the exact lower bound.
                 * Update the distanceLowerBound to reflect this
                 * (which must be smaller, due to the test
                 * immediately prior to this).
                 */
                if (bndPair.IsLeaves)
                {
                    // assert: currentDistance < minimumDistanceFound
                    distanceLowerBound = currentDistance;
                    minPair            = bndPair;
                }
                else
                {
                    // testing - does allowing a tolerance improve speed?
                    // Ans: by only about 10% - not enough to matter

                    /*
                     * double maxDist = bndPair.getMaximumDistance();
                     * if (maxDist * .99 < lastComputedDistance)
                     * return;
                     * //*/

                    /**
                     * Otherwise, expand one side of the pair,
                     * (the choice of which side to expand is heuristically determined)
                     * and insert the new expanded pairs into the queue
                     */
                    bndPair.ExpandToQueue(priQ, distanceLowerBound);
                }
            }
            if (minPair != null)
            {
                // done - return items with min distance
                return new[]
                       {
                           ((ItemBoundable <Envelope, TItem>)minPair.GetBoundable(0)).Item,
                           ((ItemBoundable <Envelope, TItem>)minPair.GetBoundable(1)).Item
                       }
            }
            ;
            return(null);
        }
Esempio n. 9
0
 private TItem[] NearestNeighbour(BoundablePair <TItem> initBndPair, int k)
 {
     return(NearestNeighbour(initBndPair, double.PositiveInfinity, k));
 }
Esempio n. 10
0
 private static TItem[] NearestNeighbour(BoundablePair <TItem> initBndPair)
 {
     return(NearestNeighbour(initBndPair, double.PositiveInfinity));
 }
Esempio n. 11
0
        /// <summary>
        /// Finds the two nearest items in the tree,
        /// using <see cref="IItemDistance{Envelope, TItem}"/> as the distance metric.
        /// A Branch-and-Bound tree traversal algorithm is used
        /// to provide an efficient search.
        /// </summary>
        /// <param name="itemDist">A distance metric applicable to the items in this tree</param>
        /// <returns>The pair of the nearest items</returns>
        public TItem[] NearestNeighbour(IItemDistance <Envelope, TItem> itemDist)
        {
            var bp = new BoundablePair <TItem>(Root, Root, itemDist);

            return(NearestNeighbour(bp));
        }
Esempio n. 12
0
        /**
         * Performs a withinDistance search on the tree node pairs.
         * This is a different search algorithm to nearest neighbour.
         * It can utilize the {@link BoundablePair#maximumDistance()} between
         * tree nodes to confirm if two internal nodes must
         * have items closer than the maxDistance,
         * and short-circuit the search.
         *
         * @param initBndPair the initial pair containing the tree root nodes
         * @param maxDistance the maximum distance to search for
         * @return true if two items lie within the given distance
         */
        private bool IsWithinDistance(BoundablePair <TItem> initBndPair, double maxDistance)
        {
            double distanceUpperBound = double.PositiveInfinity;

            // initialize search queue
            var priQ = new PriorityQueue <BoundablePair <TItem> >();

            priQ.Add(initBndPair);

            while (!priQ.IsEmpty())
            {
                // pop head of queue and expand one side of pair
                var bndPair = priQ.Poll();

                double pairDistance = bndPair.Distance;

                /**
                 * If the distance for the first pair in the queue
                 * is > maxDistance, other pairs
                 * in the queue must also have a greater distance.
                 * So can conclude no items are within the distance
                 * and terminate with result = false
                 */
                if (pairDistance > maxDistance)
                {
                    return(false);
                }

                /**
                 * If the maximum distance between the nodes
                 * is less than the maxDistance,
                 * than all items in the nodes must be
                 * closer than the max distance.
                 * Then can terminate with result = true.
                 *
                 * NOTE: using Envelope MinMaxDistance
                 * would provide a tighter bound,
                 * but not much performance improvement has been observed
                 */
                if (bndPair.MaximumDistance() <= maxDistance)
                {
                    return(true);
                }

                /**
                 * If the pair items are leaves
                 * then their actual distance is an upper bound.
                 * Update the distanceUpperBound to reflect this
                 */
                if (bndPair.IsLeaves)
                {
                    // assert: currentDistance < minimumDistanceFound
                    distanceUpperBound = pairDistance;

                    /**
                     * If the items are closer than maxDistance
                     * can terminate with result = true.
                     */
                    if (distanceUpperBound <= maxDistance)
                    {
                        return(true);
                    }
                }
                else
                {
                    /**
                     * Otherwise, expand one side of the pair,
                     * and insert the expanded pairs into the queue.
                     * The choice of which side to expand is determined heuristically.
                     */
                    bndPair.ExpandToQueue(priQ, distanceUpperBound);
                }
            }
            return(false);
        }
Esempio n. 13
0
        /**
         * Tests whether some two items from this tree and another tree
         * lie within a given distance.
         * {@link ItemDistance} is used as the distance metric.
         * A Branch-and-Bound tree traversal algorithm is used
         * to provide an efficient search.
         *
         * @param tree another tree
         * @param itemDist a distance metric applicable to the items in the trees
         * @param maxDistance the distance limit for the search
         * @return true if there are items within the distance
         */
        public bool IsWithinDistance(STRtree <TItem> tree, IItemDistance <Envelope, TItem> itemDist, double maxDistance)
        {
            var bp = new BoundablePair <TItem>(Root, tree.Root, itemDist);

            return(IsWithinDistance(bp, maxDistance));
        }
Esempio n. 14
0
        private static TItem[] NearestNeighbour(BoundablePair <TItem> initBndPair)
        {
            double distanceLowerBound     = double.PositiveInfinity;
            BoundablePair <TItem> minPair = null;

            // initialize search queue
            var priQ = new PriorityQueue <BoundablePair <TItem> >();

            priQ.Add(initBndPair);

            while (!priQ.IsEmpty() && distanceLowerBound > 0.0)
            {
                // pop head of queue and expand one side of pair
                var    bndPair      = priQ.Poll();
                double pairDistance = bndPair.Distance;

                /**
                 * If the distance for the first node in the queue
                 * is >= the current minimum distance, all other nodes
                 * in the queue must also have a greater distance.
                 * So the current minDistance must be the true minimum,
                 * and we are done.
                 */
                if (pairDistance >= distanceLowerBound)
                {
                    break;
                }

                /**
                 * If the pair members are leaves
                 * then their distance is the exact lower bound.
                 * Update the distanceLowerBound to reflect this
                 * (which must be smaller, due to the test
                 * immediately prior to this).
                 */
                if (bndPair.IsLeaves)
                {
                    // assert: currentDistance < minimumDistanceFound
                    distanceLowerBound = pairDistance;
                    minPair            = bndPair;
                }
                else
                {
                    /**
                     * Otherwise, expand one side of the pair,
                     * (the choice of which side to expand is heuristically determined)
                     * and insert the new expanded pairs into the queue
                     */
                    bndPair.ExpandToQueue(priQ, distanceLowerBound);
                }
            }
            if (minPair != null)
            {
                // done - return items with min distance
                return new[] {
                           ((ItemBoundable <Envelope, TItem>)minPair.GetBoundable(0)).Item,
                           ((ItemBoundable <Envelope, TItem>)minPair.GetBoundable(1)).Item
                }
            }
            ;
            return(null);
        }