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]); } } }
internal Element(T data, GeoCoordinates coordinates) { Data = data; Coordinates = coordinates; isBusy = 0; isMarkedForRemoval = 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); }
/// <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())); } }
/// <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); }
/// <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)))); }
/// <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); }
/// <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))); }
static LatLng ToGoogleLatLng(this GeoCoordinates coords) { return(new LatLng(coords.Latitude, coords.Longitude)); }
public bool Contains(GeoCoordinates coordinates) { return(GeoRectUtils.GeoContains(Bounds, coordinates)); }
/// <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); }
public GeoSegment(GeoCoordinates p1, GeoCoordinates p2) { Endpoint1 = p1; Endpoint2 = p2; }
/// <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); }