protected async override Task <TripDetectionContext> ProcessInternal(TripDetectionContext input) { var filteredPoints = input.FilteredOrderedPoints; if (!filteredPoints.Any()) { return(input); } // Inject a stop segment at the beginning input.TripSegments.Insert(0, new StoppedSegment(GenerateFakePoints(filteredPoints.First()))); var timeSinceLastReading = DateTimeUtils.DifferenceInMilliseconds( filteredPoints.Last().DeviceTimestampUtc, DateTimeUtils.CurrentTimeInMillseconds()) / 1000; // If time since the last reading exceeds the threshold, add a stopped // segment at the end of the stream if (timeSinceLastReading > this.minimumSecondsBeforeTailInjection) { input.TripSegments.Add(new StoppedSegment(GenerateFakePoints(filteredPoints.Last()))); } return(input); }
protected async override Task OnProcessCalled(TripDetectionContext input) { var locationIds = input.TripLegCandidates.Select(t => t.LastStoppedSegment.StartLocationId); var locations = await this.locationRepository.GetAsync(locationIds); interestingLocationIds = locations .Where(l => l.InterestLevel >= this.minimumInterestLevel) .Select(l => l.Id); }
protected override Task <TripDetectionContext> ProcessInternal(TripDetectionContext input) { var oldSegments = input.TripSegments; var newSegments = new List <TripSegmentBase>(); foreach (var segment in oldSegments) { if (!segment.IsMovingSegment) { newSegments.Add(segment); continue; } var lastIndex = 0; for (int i = 0; i < segment.Points.Count - 1; i++) { var currentPoint = segment.Points[i]; var nextPoint = segment.Points[i + 1]; var distance = MathUtils.DistanceInMeters(currentPoint, nextPoint); var timeDifferenceMs = DateTimeUtils.DifferenceInMilliseconds(currentPoint.DeviceTimestampUtc, nextPoint.DeviceTimestampUtc); if (distance > this.minimumBlackoutDistance || timeDifferenceMs / 1000 > this.minimumBlackoutTime) { newSegments.Add(new MovingSegment(segment.Points.Skip(lastIndex).Take(i - lastIndex).ToList())); newSegments.Add(new StoppedSegment(new List <TrackingPoint> { segment.Points[i], segment.Points[i + 1] })); lastIndex = i + 1; } } var remainingPointList = segment.Points.Skip(lastIndex).ToList(); if (remainingPointList.Any()) { newSegments.Add(new MovingSegment(remainingPointList)); } } input.TripSegments = newSegments; return(Task.FromResult(input)); }
public async override Task <IEnumerable <Trip> > Process(TripDetectionContext input, ILogger logger) { var savedTrips = new List <Trip>(); var locationIdsToGeocode = new HashSet <int>(); logger.LogDebugSerialize("Recieved trips {0}", input.ResultantTrips); foreach (var trip in input.ResultantTrips) { var savedTrip = await this.tripRepository.AddAsync(trip); var points = input.OriginalPoints.Where(p => p.TripId == trip.Id); await trackingPointRepository.AssignPointsToTripAsync(savedTrip.Id, points); logger.LogDebugSerialize("Assigned points {1} to trip {0}", points, trip); savedTrips.Add(savedTrip); foreach (var leg in trip.TripLegs) { locationIdsToGeocode.Add(leg.StartLocationId); locationIdsToGeocode.Add(leg.EndLocationId); } } var locations = (await this.locationRepository.GetAllAsync()) .Where(l => locationIdsToGeocode.Contains(l.Id) && l.Address == "Auto-Generated") .ToList(); //Batch reverse geocode var geocodeFeed = new GeocodeFeed() { Entities = locations.Select((l, i) => new GeocodeEntity() { ReverseGeocodeRequest = new ReverseGeocodeRequest() { Location = new GeodataLocation(l.Latitude, l.Longitude) }, Id = i.ToString() }).ToList() }; if (locations.Count > 0) { var geocodeManager = new BatchGeocodeManager(); var res = await geocodeManager.Geocode(geocodeFeed, bingMapsKey); var locationsDict = new Dictionary <int, Location>(); if (res.Succeeded != null) { logger.LogDebugSerialize("Reverse Geocode result (Succeeded)", res.Succeeded); foreach (var entity in res.Succeeded.Entities) { var loc = locations[int.Parse(entity.Id)]; loc.Address = entity.GeocodeResponse.First <GeocodeResponse>().Address.FormattedAddress; loc.Name = entity.GeocodeResponse.First <GeocodeResponse>().Name; locationsDict.Add(loc.Id, loc); } await locationRepository.UpdateAsync(locationsDict); } else { logger.LogDebugSerialize("Reverse Geocode result (Failed)", res.Failed); logger.LogDebugSerialize("Reverse Geocode result (Errors)", res.Error); } } logger.LogDebugSerialize("Saved trips output", savedTrips); return(savedTrips); }
protected async override Task <TripDetectionContext> ProcessInternal(TripDetectionContext input) { var tripSegments = new List <TripSegmentBase>(); foreach (var segment in input.TripSegments) { if (!segment.IsMovingSegment) { tripSegments.Add(segment); continue; } var currentStopCluster = new StoppedSegment(); var currentMovingCluster = new MovingSegment(); State previousState = State.Stopped; State currentState = State.Unknown; var points = segment.Points; currentStopCluster.Points.Add(points.First()); // Loop over points and extract segments for (var i = 1; i < points.Count - 1; i++) { var previousTrackingPoint = points[i - 1]; var currentTrackingPoint = points[i]; var nextTrackingPoint = points[i + 1]; double cumulativeAngle = 0; for (int j = i - this.arcWindowSize / 2; j <= i + this.arcWindowSize / 2; j++) { if (j >= 0 && j < points.Count) { cumulativeAngle += MathUtils.AngleBetweenPoints(points[j], points[i]); } } cumulativeAngle /= this.arcWindowSize; double calculatedSpeed = MathUtils.AverageSpeed(previousTrackingPoint, currentTrackingPoint, nextTrackingPoint); currentState = (calculatedSpeed <= this.maximumDwellSpeed && cumulativeAngle > this.minimumAngleDifference) ? State.Stopped : State.Moving; if (currentState == State.Moving) { currentMovingCluster.Points.Add(currentTrackingPoint); if (previousState == State.Stopped) { if (currentStopCluster.GetDurationInSeconds() < this.minimumDwellTime) { tripSegments.Add(new MovingSegment(currentStopCluster.Points)); } else { currentStopCluster.Points.Add(currentTrackingPoint); tripSegments.Add(currentStopCluster); } currentStopCluster = new StoppedSegment(); } } if (currentState == State.Stopped) { currentStopCluster.Points.Add(currentTrackingPoint); if (previousState == State.Moving) { currentMovingCluster.Points.Add(currentTrackingPoint); tripSegments.Add(currentMovingCluster); currentMovingCluster = new MovingSegment(); } } previousState = currentState; } // Add the last segment to the list of segments including the last // unprocessed point if (currentStopCluster.Points.Any()) { currentStopCluster .Points .Add(points[points.Count - 1]); tripSegments.Add(currentStopCluster); } else if (currentMovingCluster.Points.Any()) { currentMovingCluster .Points .Add(points[points.Count - 1]); tripSegments.Add(currentMovingCluster); } } input.TripSegments = tripSegments; return(input); }