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);
        }
Exemple #3
0
        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);
        }