/// <summary> /// Aggregates a route by remove information useless to the generation of routing instructions. /// </summary> /// <param name="route"></param> /// <returns></returns> public AggregatedPoint Aggregate(Route route) { // create the enumerator. var enumerator = new AggregatedPointEnumerator(route); AggregatedRoutePoint previous = null; AggregatedRoutePoint current = null; AggregatedRoutePoint next = null; AggregatedPoint previousPoint = null; AggregatedArc previousArc = null; AggregatedPoint p = null; // loop over all aggregated points. while (enumerator.MoveNext()) { // get the next point. next = enumerator.Current; // process this.Process(route, previous, current, next, ref p, ref previousArc, ref previousPoint); // make the next, current and the current previous. previous = current; current = next; next = null; } // process once more, the current current has not been processed. this.Process(route, previous, current, next, ref p, ref previousArc, ref previousPoint); return(p); }
/// <summary> /// Processes a part of the route. /// </summary> private void Process(Route route, AggregatedRoutePoint previous, AggregatedRoutePoint current, AggregatedRoutePoint next, ref AggregatedPoint p, ref AggregatedArc previousArc, ref AggregatedPoint previousPoint) { // process the current point. if (current != null) { if (previous == null) { // point is always significant, it is the starting point! // create point. p = new AggregatedPoint(); p.Angle = null; p.ArcsNotTaken = null; p.Location = new GeoCoordinate(current.Segment.Latitude, current.Segment.Longitude); p.Points = new List <PointPoi>(); p.SegmentIdx = current.SegmentIndex; if (current.Segment.Points != null) { foreach (var routePoint in current.Segment.Points) { var poi = new PointPoi(); poi.Name = routePoint.Name; poi.Tags = routePoint.Tags.ConvertTo(); poi.Location = new GeoCoordinate(routePoint.Latitude, routePoint.Longitude); poi.Angle = null; // there is no previous point; no angle is specified. p.Points.Add(poi); } } previousPoint = p; } else { // test if point is significant. var nextArc = this.CreateArcAndPoint(route, previous, current, next); // test if the next point is significant. if (previousArc == null) { // this arc is always significant; it is the first arc. previousPoint.Next = nextArc; previousArc = nextArc; } else { // there is a previous arc; a test can be done if the current point is significant. if (this.IsSignificant(previousArc, nextArc)) { // the arc is significant; append it to the previous arc. previousArc.Next.Next = nextArc; previousArc = nextArc; previousPoint = nextArc.Next; } else { // if the arc is not significant compared to the previous one, the previous one can extend until the next point. // THIS IS THE AGGREGATION STEP! // add distance. var distanceToNext = previousArc.Next.Location.DistanceReal(nextArc.Next.Location); previousArc.Distance = previousArc.Distance + distanceToNext; // set point. previousArc.Next = nextArc.Next; } } } } }
/// <summary> /// Generates an arc and it's next point from the current aggregated point. /// </summary> /// <param name="route"></param> /// <param name="previous"></param> /// <param name="current"></param> /// <param name="next"></param> /// <returns></returns> internal AggregatedArc CreateArcAndPoint(Route route, AggregatedRoutePoint previous, AggregatedRoutePoint current, AggregatedRoutePoint next) { // create the arc. var a = new AggregatedArc(); a.Name = current.Segment.Name; a.Names = current.Segment.Names.ConvertTo(); a.Tags = current.Segment.Tags.ConvertToTagsCollection(); a.Vehicle = string.IsNullOrWhiteSpace(route.Vehicle) ? current.Segment.Vehicle : route.Vehicle; if (previous != null) { var previousCoordinate = new GeoCoordinate(previous.Segment.Latitude, previous.Segment.Longitude); var currentCoordinate = new GeoCoordinate(current.Segment.Latitude, current.Segment.Longitude); var distance = previousCoordinate.DistanceReal(currentCoordinate); a.Distance = distance; } // create the point. var p = new AggregatedPoint(); p.Location = new GeoCoordinate(current.Segment.Latitude, current.Segment.Longitude); p.Points = new List <PointPoi>(); p.SegmentIdx = current.SegmentIndex; if (previous != null && next != null && next.Segment != null) { var previousCoordinate = new GeoCoordinate(previous.Segment.Latitude, previous.Segment.Longitude); var nextCoordinate = new GeoCoordinate(next.Segment.Latitude, next.Segment.Longitude); p.Angle = RelativeDirectionCalculator.Calculate(previousCoordinate, p.Location, nextCoordinate); } if (current.Segment.SideStreets != null && current.Segment.SideStreets.Length > 0) { p.ArcsNotTaken = new List <KeyValuePair <RelativeDirection, AggregatedArc> >(); foreach (var sideStreet in current.Segment.SideStreets) { var side = new AggregatedArc(); side.Name = sideStreet.Name; side.Names = sideStreet.Names.ConvertTo(); side.Tags = sideStreet.Tags.ConvertToTagsCollection(); RelativeDirection sideDirection = null; if (previous != null) { var previousCoordinate = new GeoCoordinate(previous.Segment.Latitude, previous.Segment.Longitude); var nextCoordinate = new GeoCoordinate(sideStreet.Latitude, sideStreet.Longitude); sideDirection = RelativeDirectionCalculator.Calculate(previousCoordinate, p.Location, nextCoordinate); } p.ArcsNotTaken.Add(new KeyValuePair <RelativeDirection, AggregatedArc>(sideDirection, side)); } } if (current.Segment.Points != null) { foreach (var routePoint in current.Segment.Points) { var poi = new PointPoi(); poi.Name = routePoint.Name; poi.Tags = routePoint.Tags.ConvertTo(); poi.Location = new GeoCoordinate(routePoint.Latitude, routePoint.Longitude); var previousCoordinate = new GeoCoordinate(previous.Segment.Latitude, previous.Segment.Longitude); var currentCoordinate = new GeoCoordinate(current.Segment.Latitude, current.Segment.Longitude); poi.Angle = RelativeDirectionCalculator.Calculate(previousCoordinate, currentCoordinate, poi.Location); p.Points.Add(poi); } } // link the arc to the point. a.Next = p; return(a); }