Esempio n. 1
0
            public Quadrant GetChildContaining(GeoCoordinates coordinates)
            {
                double subWidth  = Bounds.width / 2;
                double subHeight = Bounds.height / 2;

                if (coordinates.Longitude >= Bounds.x + subWidth)
                {
                    if (coordinates.Latitude >= Bounds.y + subHeight)
                    {
                        return(children[0]);
                    }
                    else
                    {
                        return(children[3]);
                    }
                }
                else
                {
                    if (coordinates.Latitude >= Bounds.y + subHeight)
                    {
                        return(children[1]);
                    }
                    else
                    {
                        return(children[2]);
                    }
                }
            }
Esempio n. 2
0
 internal Element(T data, GeoCoordinates coordinates)
 {
     Data               = data;
     Coordinates        = coordinates;
     isBusy             = 0;
     isMarkedForRemoval = 0;
 }
Esempio n. 3
0
        public IElement InsertElement(T data, GeoCoordinates coordinates)
        {
            rootNode.Lock.EnterUpgradeableLock();

            Quadrant targetQuadrant = FindAndLockTargetLeafQuadrant(rootNode, coordinates);

            targetQuadrant.Lock.EnterExclusiveLock();

            Element element = new Element(data, coordinates);

            targetQuadrant.Data.Add(element);
            elementsToNodes[element] = targetQuadrant;

            ++count;

            // If the quadrant now contains too much data, mark it as a candidate
            // for subdivision.
            if (targetQuadrant.Data.Count > maxLeafCapacity && targetQuadrant.SubdivisionLevel < maxSubdivisionLevel)
            {
                candidatesForSubdivide.TryAdd(targetQuadrant);
            }

            targetQuadrant.Lock.ExitExclusiveLock();
            targetQuadrant.Lock.ExitUpgradeableLock();

            return(element);
        }
Esempio n. 4
0
        /// <summary>
        /// Computes the distance from the point to the segment. The return
        /// value is in units of sqrt(lat^2 + long^2) in WGS84 coordinates.
        /// </summary>
        /// <returns>The distance to the point in units of sqrt(lat^2 + long^2).</returns>
        /// <param name="point">Point on Earth.</param>
        public double DistanceToPoint(GeoCoordinates point)
        {
            Vector2 p1 = Endpoint1.ToVector2();
            Vector2 p2 = Endpoint2.ToVector2();

            if (CrossesMeridianRightOfP1)
            {
                p2 += new Vector2(360, 0);

                Vector2 pointRepr1 = point.ToVector2();
                Vector2 pointRepr2 = pointRepr1 + new Vector2(360, 0);

                double dist1 = Geometry2d.PointToSegmentDistance(p1, p2, pointRepr1);
                double dist2 = Geometry2d.PointToSegmentDistance(p1, p2, pointRepr2);

                return(Math.Min(dist1, dist2));
            }
            else if (CrossesMeridianLeftOfP1)
            {
                p2 -= new Vector2(360, 0);

                Vector2 pointRepr1 = point.ToVector2();
                Vector2 pointRepr2 = pointRepr1 - new Vector2(360, 0);

                double dist1 = Geometry2d.PointToSegmentDistance(p1, p2, pointRepr1);
                double dist2 = Geometry2d.PointToSegmentDistance(p1, p2, pointRepr2);

                return(Math.Min(dist1, dist2));
            }
            else
            {
                return(Geometry2d.PointToSegmentDistance(p1, p2, point.ToVector2()));
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Finds the leaf quadrant which contains <paramref name="location"/> by
        /// traversing downward starting at <paramref name="initialQuadrant"/> using
        /// upgradeable locks.
        /// </summary>
        /// <returns>The leaf quadrant containing the location. The current thread
        /// will hold an upgradable lock on this quadrant.</returns>
        /// <param name="initialQuadrant">
        /// The quadrant from which to start downward traversal. This must contain
        /// <paramref name="location"/> and the current thread should hold an
        /// upgradeable lock on it. This lock will be released unless this quadrant
        /// happens to be the return value.
        /// </param>
        /// <param name="location">The location for which to find a leaf quadrant.</param>
        Quadrant FindAndLockTargetLeafQuadrant(Quadrant initialQuadrant, GeoCoordinates location)
        {
            Debug.Assert(initialQuadrant.Contains(location));
            Debug.Assert(initialQuadrant.Lock.ThreadOwnsUpgradeableLock);

            Quadrant targetQuadrant = initialQuadrant;

            while (!targetQuadrant.IsLeaf)
            {
                Quadrant next = targetQuadrant.GetChildContaining(location);
                next.Lock.EnterUpgradeableLock();
                targetQuadrant.Lock.ExitUpgradeableLock();

                targetQuadrant = next;
            }

            Debug.Assert(targetQuadrant.Contains(location));

            return(targetQuadrant);
        }
Esempio n. 6
0
        /// <summary>
        /// Computes an overview of the driving route between two points using
        /// the Google Directions API.
        /// </summary>
        /// <exception cref="ApplicationException">Thrown if the Google Maps service
        /// does not return a route for any reason.</exception>
        /// <returns>The route info.</returns>
        /// <param name="apiKey">Google API key.</param>
        /// <param name="origin">Origin.</param>
        /// <param name="destination">Destination.</param>
        /// <param name="waypoints">Waypoints to visit.</param>
        public static async Task <RouteInfo> ComputeApproximateDrivingInfo(
            string apiKey,
            GeoCoordinates origin,
            GeoCoordinates destination,
            params GeoCoordinates[] waypoints)
        {
            DirectionRequest request = new DirectionRequest
            {
                Origin      = origin.ToGoogleLatLng(),
                Destination = destination.ToGoogleLatLng(),
                Mode        = TravelMode.driving,
                Waypoints   = waypoints.Length == 0 ?
                              null : new List <Location>(waypoints.Select(pt => new LatLng(pt.Latitude, pt.Longitude)))
            };

            DirectionRoute route = await GetRouteOrThrow(apiKey, request);

            return(new RouteInfo(
                       route.OverviewPolyline.ToGeoPolyline(),
                       TimeSpan.FromSeconds(
                           route.Legs.Sum(leg => leg.Duration.Value))));
        }
Esempio n. 7
0
        /// <summary>
        /// Checks whether the given geo rectangle contains the geo position.
        /// </summary>
        /// <returns><c>true</c>, if the rectangle contains the position, <c>false</c> otherwise.</returns>
        /// <param name="rect">A valid geo rectangle.</param>
        /// <param name="coordinates">A geo position.</param>
        /// <exception cref="ArgumentException">Thrown if the given rect is not
        /// a valid geo rectangle. See <see cref="IsValidGeoRect(Rect)"/>.</exception>
        public static bool GeoContains(Rect rect, GeoCoordinates coordinates)
        {
            if (!IsValidGeoRect(rect))
            {
                throw new ArgumentException($"Given rectangle {rect} is not a valid geo rectangle.");
            }

            int num = Split(rect, out Rect piece1, out Rect? piece2);

            double x = coordinates.Longitude;
            double y = coordinates.Latitude;

            if (piece1.Contains(x, y))
            {
                return(true);
            }

            if (num > 1 && piece2.Value.Contains(x, y))
            {
                return(true);
            }

            return(false);
        }
Esempio n. 8
0
 /// <summary>
 /// Tests whether the point is within a given distance of the polyline,
 /// where the distance is given by the metric lat^2 + long^2 in WGS84
 /// coordinates (so it doesn't correspond to real distance).
 /// </summary>
 /// <returns><c>true</c>, if point is within distance, <c>false</c> otherwise.</returns>
 /// <param name="point">Point on Earth.</param>
 /// <param name="distance">Distance in units of sqrt(lat^2 + long^2).</param>
 public bool PointWithinDistance(GeoCoordinates point, double distance)
 {
     return(Segments.Any(segment => segment.PointWithinDistance(point, distance)));
 }
Esempio n. 9
0
 static LatLng ToGoogleLatLng(this GeoCoordinates coords)
 {
     return(new LatLng(coords.Latitude, coords.Longitude));
 }
Esempio n. 10
0
 public bool Contains(GeoCoordinates coordinates)
 {
     return(GeoRectUtils.GeoContains(Bounds, coordinates));
 }
Esempio n. 11
0
        /// <summary>
        /// Moves the element to a new position. This will return false and do
        /// nothing if another thread is currently adjusting this element.
        /// </summary>
        /// <returns><c>true</c>, if element was moved, <c>false</c> otherwise.</returns>
        /// <param name="elementRef">Element.</param>
        /// <param name="newCoordinates">New coordinates.</param>
        public bool MoveElement(IElement elementRef, GeoCoordinates newCoordinates)
        {
            Element element = (Element)elementRef;

            if (element.IsMarkedForRemoval)
            {
                return(false);
            }

            if (!element.TrySetBusy())
            {
                return(false);
            }

            // This check has to happen after TrySetBusy() to avoid a race
            // condition with RemoveElement(). After TrySetBusy() succeeds,
            // no other move or remove operation can run on this element,
            // so we are guaranteed not to move the element after it has been
            // removed. If the element will be removed, we just abort the move.
            if (element.IsMarkedForRemoval)
            {
                element.SetNotBusy();
                return(false);
            }

            while (true)
            {
                Quadrant originalQuadrant = GetAndLockQuadrantForElement(element, QuadrantLock.LockType.Shared);

                // Catch tricky issues early.
                Debug.Assert(originalQuadrant.Lock.ThreadOwnsSharedLock);
                Debug.Assert(!originalQuadrant.IsDisconnected);
                Debug.Assert(originalQuadrant.IsLeaf);

                if (originalQuadrant.Contains(newCoordinates))
                {
                    // Case (1): new position is inside the old quadrant. Just change x and y.
                    element.Coordinates = newCoordinates;
                    originalQuadrant.Lock.ExitSharedLock();
                    break;
                }

                // Case (2): new position is inside a new quadrant. Need to move
                // to a new quadrant.

                // The root node should contain all elements, so the above if statement
                // should prevent this assert.
                Debug.Assert(originalQuadrant != rootNode);

                // We have to lock the parent to avoid deadlocking with a join
                // operation if the new quadrant is also a child of the parent.
                if (!SwitchSharedLockToExclusiveLockAndLockParent(originalQuadrant))
                {
                    // If in between releasing the shared lock and acquiring the
                    // exclusive lock the quadrant became disconnected (due to
                    // a join on its parent) or became subdivided, we have to
                    // restart the move.
                    continue;
                }

                Debug.Assert(originalQuadrant.Lock.ThreadOwnsExlusiveLock);
                Debug.Assert(originalQuadrant.Parent.Lock.ThreadOwnsSharedLock);

                // If originalQuadrant was not subdivided or joined (or was
                // subdivided and joined an equal number of times), then element
                // could not have been moved because we set it to busy.
                Debug.Assert(originalQuadrant.Data.Contains(element));

                // Traverse upward to search for the nearest ancestor that contains
                // the new position. No locking is necessary because ancestors
                // cannot be subdivided since they're not leaves, and they cannot
                // be joined because we hold a lock on a child node.
                Quadrant closestContainingAncestor = originalQuadrant.Parent;
                while (!closestContainingAncestor.Contains(newCoordinates))
                {
                    closestContainingAncestor = closestContainingAncestor.Parent;

                    // This only happens if rootNode doesn't contain the new
                    // position, but that cannot happen.
                    Debug.Assert(closestContainingAncestor != null);
                }

                // Traverse downward to target quadrant. Use locking like in an insert operation.

                // It cannot be a leaf node because it is an ancestor node.
                Debug.Assert(!closestContainingAncestor.IsLeaf);

                // Find the leaf quadrant that contains the new coordinates.
                Quadrant targetQuadrant = closestContainingAncestor.GetChildContaining(newCoordinates);
                targetQuadrant.Lock.EnterUpgradeableLock();
                targetQuadrant = FindAndLockTargetLeafQuadrant(targetQuadrant, newCoordinates);
                targetQuadrant.Lock.EnterExclusiveLock();

                // Change the element's coordinates and move it to the new quadrant.
                element.Coordinates = newCoordinates;
                originalQuadrant.Data.Remove(element);
                targetQuadrant.Data.Add(element);
                elementsToNodes[element] = targetQuadrant;

                // If the target quadrant now contains too much data, mark it as a candidate
                // for subdivision.
                if (targetQuadrant.Data.Count > maxLeafCapacity && targetQuadrant.SubdivisionLevel < maxSubdivisionLevel)
                {
                    candidatesForSubdivide.TryAdd(targetQuadrant);
                }

                // If the original quadrant is now nearly empty, mark its parent
                // as a candidate for a join operation.
                if (originalQuadrant.Parent != null && originalQuadrant.Data.Count < minLeafCapacity)
                {
                    candidatesForJoin.TryAdd(originalQuadrant.Parent);
                }

                targetQuadrant.Lock.ExitExclusiveLock();
                targetQuadrant.Lock.ExitUpgradeableLock();

                // Release the locks on the original quadrant and its parent,
                // which were acquired earlier.
                originalQuadrant.Lock.ExitExclusiveLock();
                originalQuadrant.Parent.Lock.ExitSharedLock();
                break;
            }

            element.SetNotBusy();
            return(true);
        }
Esempio n. 12
0
 public GeoSegment(GeoCoordinates p1, GeoCoordinates p2)
 {
     Endpoint1 = p1;
     Endpoint2 = p2;
 }
Esempio n. 13
0
 /// <summary>
 /// Tests whether the point is within a given distance of the segment,
 /// where the distance is given by the metric lat^2 + long^2 in WGS84
 /// coordinates (so it doesn't correspond to real distance).
 /// </summary>
 /// <returns><c>true</c>, if point is within distance, <c>false</c> otherwise.</returns>
 /// <param name="point">Point on Earth.</param>
 /// <param name="distance">Distance in units of sqrt(lat^2 + long^2).</param>
 public bool PointWithinDistance(GeoCoordinates point, double distance)
 {
     return(DistanceToPoint(point) < distance);
 }