// Calculate the distance between // Node 'stopPosition' and the segment p1 --> p2, where p1 -> p2 is a subset of a way. private double FindDistanceToSegment(Coordinate stopPosition, Coordinate p1, Coordinate p2, out Coordinate closest) { double dx = p2.Lon - p1.Lon; double dy = p2.Lat - p1.Lat; if ((dx == 0) && (dy == 0)) { // It's a point not a line segment. closest = p1; dx = stopPosition.Lon - p1.Lon; dy = stopPosition.Lat - p1.Lat; //return Math.Sqrt(dx * dx + dy * dy); return(stopPosition.GreatCircleDistance(closest)); } // Calculate the t that minimizes the distance. double t = ((stopPosition.Lon - p1.Lon) * dx + (stopPosition.Lat - p1.Lat) * dy) / (dx * dx + dy * dy); // See if this represents one of the segment's // end points or a point in the middle. if (t < 0) { closest = new Coordinate(p1.Lat, p1.Lon); dx = stopPosition.Lon - p1.Lon; dy = stopPosition.Lat - p1.Lat; } else if (t > 1) { closest = new Coordinate(p2.Lat, p2.Lon); dx = stopPosition.Lon - p2.Lon; dy = stopPosition.Lat - p2.Lat; } else { closest = new Coordinate(p1.Lat + t * dy, p1.Lon + t * dx); dx = stopPosition.Lon - closest.Lon; dy = stopPosition.Lat - closest.Lat; } // For linear geometry return Math.Sqrt(dx * dx + dy * dy); // For earth geography below return(stopPosition.GreatCircleDistance(closest)); }
/// <summary> /// Test whether coordinate values are within a close enough distance to each other. /// </summary> /// <param name="v1"></param> /// <param name=""></param> /// <returns></returns> private bool CloseEnough(Coordinate c1, Coordinate c2) { // Some generating programs don't snap them together. double Epsilon = 5.0; // Max allowable mismatch, in meters var distance = c1.GreatCircleDistance(c2); return(distance < Epsilon); }
/// <summary> /// Parse JSON serialized route coordinate array /// </summary> /// <param name="db"></param> /// <param name="route"></param> /// <param name="jsonShapes"></param> private void SaveNewRouteShape(TrolleyTrackerContext db, Route route, string jsonShapes) { JavaScriptSerializer jss = new JavaScriptSerializer(); jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() }); dynamic shapeData = jss.Deserialize(jsonShapes, typeof(object)) as dynamic; Coordinate lastCoordinate = null; var totalDistance = 0.0; int sequence = 0; int nodeCount = shapeData.Length; for (int i = 0; i < nodeCount; i++) { var node = shapeData[i]; var lon = Convert.ToDouble(node.Lon); var lat = Convert.ToDouble(node.Lat); var thisCoordinate = new Coordinate(lat, lon); double distance = 0.0; if (lastCoordinate != null) { distance = thisCoordinate.GreatCircleDistance(lastCoordinate); } lastCoordinate = thisCoordinate; totalDistance += distance; // Add new point if not duplicated (some shape editors create duplicate nodes) if (distance > 0.0) { var dbShape = new TrolleyTracker.Models.Shape(); dbShape.Lat = lat; dbShape.Lon = lon; dbShape.RouteID = route.ID; dbShape.Sequence = sequence; dbShape.DistanceTraveled = totalDistance; sequence++; db.Shapes.Add(dbShape); } } db.SaveChanges(); }
private void FindNewStops(List <Stop> routeStops, ref List <Stop> newStops, ref List <Stop> oldStops) { double Epsilon = 20.0; // Max distance in meters for matching stop newStops = new List <Stop>(); oldStops = new List <Stop>(); List <Stop> dbStopsList = null; using (var db = new TrolleyTrackerContext()) { dbStopsList = (from s in db.Stops select s).ToList(); } foreach (var testStop in routeStops) { var testCoordinate = new Coordinate(testStop.Lat, testStop.Lon); bool match = false; foreach (var dbStop in dbStopsList) { var dbCoordinate = new Coordinate(dbStop.Lat, dbStop.Lon); if (dbCoordinate.GreatCircleDistance(testCoordinate) < Epsilon) { // Stop already exists nearby match = true; break; } } if (match) { oldStops.Add(testStop); } else { newStops.Add(testStop); } } }
public ActionResult Create(FormCollection collection) { try { Coordinate lastCoordinate = null; var strRouteID = collection.Get("RouteID"); // Parse Geo-JSON formatted route coordinates var jsonShapes = collection.Get("JSONText"); if (jsonShapes != null && strRouteID != null) { int routeID = Convert.ToInt32(strRouteID); using (var db = new TrolleyTracker.Models.TrolleyTrackerContext()) { RemoveOldShape(routeID, db); JavaScriptSerializer jss = new JavaScriptSerializer(); jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() }); dynamic shapeData = jss.Deserialize(jsonShapes, typeof(object)) as dynamic; var features = shapeData.features; var geometryBlock = features[0]; var geometry = geometryBlock["geometry"]; var geoJSONtype = geometry["type"]; var coordinates = geometry["coordinates"]; int segmentCount = coordinates.Count; if (geoJSONtype == "LineString") segmentCount = 1; int sequence = 0; double totalDistance = 0.0; for (int seg = 0; seg < segmentCount; seg++) { var coordArray = coordinates[seg]; if (geoJSONtype == "LineString") coordArray = coordinates; int nodeCount = coordArray.Count; for (int i = 0; i < nodeCount; i++) { var node = coordArray[i]; var strLon = node[0]; var strLat = node[1]; var lon = Convert.ToDouble(strLon); var lat = Convert.ToDouble(strLat); var thisCoordinate = new Coordinate(0, lat, lon, null); double distance = 0.0; if (lastCoordinate != null) { distance = thisCoordinate.GreatCircleDistance(lastCoordinate); } lastCoordinate = thisCoordinate; totalDistance += distance; var dbShape = new TrolleyTracker.Models.Shape(); dbShape.Lat = lat; dbShape.Lon = lon; dbShape.RouteID = routeID; dbShape.Sequence = sequence; dbShape.DistanceTraveled = totalDistance; sequence++; db.Shapes.Add(dbShape); } } db.SaveChanges(); var assignStops = new AssignStopsToRoutes(); assignStops.UpdateStopsForRoute(db, routeID); } } return RedirectToAction("Index"); } catch { return View(); } }
private static void UpdateStopTime(Trolley trolley) { UpdateStopList(); // See if trolley has moved far enough to justify a full stop distance check var currentLocation = new Coordinate((double)trolley.CurrentLat, (double)trolley.CurrentLon); if (currentLocation.GreatCircleDistance(lastReportedLocation[trolley.Number]) > MinMoveDistance) { CheckForStopInRange(trolley, currentLocation); lastReportedLocation[trolley.Number] = currentLocation; } }
/// <summary> /// Check for stop proximity - try to minimize number of polled stops /// - First preference is the previous stop /// Then loop through all stops /// </summary> /// <param name="trolley"></param> /// <param name="currentLocation"></param> private static void CheckForStopInRange(Trolley trolley, Coordinate currentLocation) { //var lastStopID = -1; if (lastStopIDByTrolley.ContainsKey(trolley.Number) ) { var stopID = lastStopIDByTrolley[trolley.Number]; var stopSummary = stopSummaries[stopID]; if (currentLocation.GreatCircleDistance(new Coordinate(stopSummary.Lat, stopSummary.Lon)) < StopRadiusCheck) { // Still within stop zone return; } } foreach(var stopID in stopSummaries.Keys) { var stopSummary = stopSummaries[stopID]; if (currentLocation.GreatCircleDistance(new Coordinate(stopSummary.Lat, stopSummary.Lon)) < StopRadiusCheck) { // Found new stop zone if (stopSummary.LastTrolleyArrivalTime.ContainsKey(trolley.Number)) { stopSummary.LastTrolleyArrivalTime[trolley.Number] = UTCToLocalTime.LocalTimeFromUTC(DateTime.UtcNow); } else { stopSummary.LastTrolleyArrivalTime.Add(trolley.Number, UTCToLocalTime.LocalTimeFromUTC(DateTime.UtcNow)); } lastStopIDByTrolley.Add(trolley.Number, stopSummary.ID); return; } } // Not currently in any stop zone if (lastStopIDByTrolley.ContainsKey(trolley.Number)) { lastStopIDByTrolley.Remove(trolley.Number); } }
public ActionResult Create(FormCollection collection) { try { Coordinate lastCoordinate = null; var strRouteID = collection.Get("RouteID"); // Parse Geo-JSON formatted route coordinates var jsonShapes = collection.Get("JSONText"); if (jsonShapes != null && strRouteID != null) { int routeID = Convert.ToInt32(strRouteID); using (var db = new TrolleyTracker.Models.TrolleyTrackerContext()) { RemoveOldShape(routeID, db); JavaScriptSerializer jss = new JavaScriptSerializer(); jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() }); dynamic shapeData = jss.Deserialize(jsonShapes, typeof(object)) as dynamic; var features = shapeData.features; var geometryBlock = features[0]; var geometry = geometryBlock["geometry"]; var geoJSONtype = geometry["type"]; var coordinates = geometry["coordinates"]; int segmentCount = coordinates.Count; if (geoJSONtype == "LineString") { segmentCount = 1; } int sequence = 0; double totalDistance = 0.0; for (int seg = 0; seg < segmentCount; seg++) { var coordArray = coordinates[seg]; if (geoJSONtype == "LineString") { coordArray = coordinates; } int nodeCount = coordArray.Count; for (int i = 0; i < nodeCount; i++) { var node = coordArray[i]; var strLon = node[0]; var strLat = node[1]; var lon = Convert.ToDouble(strLon); var lat = Convert.ToDouble(strLat); var thisCoordinate = new Coordinate(lat, lon); double distance = 0.0; if (lastCoordinate != null) { distance = thisCoordinate.GreatCircleDistance(lastCoordinate); } lastCoordinate = thisCoordinate; totalDistance += distance; var dbShape = new TrolleyTracker.Models.Shape(); dbShape.Lat = lat; dbShape.Lon = lon; dbShape.RouteID = routeID; dbShape.Sequence = sequence; dbShape.DistanceTraveled = totalDistance; sequence++; db.Shapes.Add(dbShape); } } db.SaveChanges(); var assignStops = new AssignStopsToRoutes(); assignStops.UpdateStopsForRoute(db, routeID); var route = db.Routes.Find(routeID); logger.Info($"Modified route shape of '{route.Description}' - '{route.LongName}'"); } } return(RedirectToAction("Index")); } catch (Exception ex) { ViewBag.Message = "Shape save exception"; logger.Error(ex, "Exception saving route shape"); ViewBag.RouteID = new SelectList(db.Routes, "ID", "ShortName"); return(View()); } }
// Calculate the distance between // Node 'stopPosition' and the segment p1 --> p2, where p1 -> p2 is a subset of a way. private double FindDistanceToSegment(Coordinate stopPosition, Coordinate p1, Coordinate p2, out Coordinate closest) { double dx = p2.Lon - p1.Lon; double dy = p2.Lat - p1.Lat; if ((dx == 0) && (dy == 0)) { // It's a point not a line segment. closest = p1; dx = stopPosition.Lon - p1.Lon; dy = stopPosition.Lat - p1.Lat; //return Math.Sqrt(dx * dx + dy * dy); return stopPosition.GreatCircleDistance(closest); } // Calculate the t that minimizes the distance. double t = ((stopPosition.Lon - p1.Lon) * dx + (stopPosition.Lat - p1.Lat) * dy) / (dx * dx + dy * dy); // See if this represents one of the segment's // end points or a point in the middle. if (t < 0) { closest = new Coordinate(p1.Lat, p1.Lon); dx = stopPosition.Lon - p1.Lon; dy = stopPosition.Lat - p1.Lat; } else if (t > 1) { closest = new Coordinate(p2.Lat, p2.Lon); dx = stopPosition.Lon - p2.Lon; dy = stopPosition.Lat - p2.Lat; } else { closest = new Coordinate(p1.Lat + t * dy, p1.Lon + t * dx); dx = stopPosition.Lon - closest.Lon; dy = stopPosition.Lat - closest.Lat; } // For linear geometry return Math.Sqrt(dx * dx + dy * dy); // For earth geography below return stopPosition.GreatCircleDistance(closest); }