示例#1
0
 /// <summary>
 /// Creates coordinate in between two trace points to smooth line
 /// </summary>
 /// <returns>double array containing lng/lat</returns>
 private double[] pointAtDistanceAndBearing(TracePoint tracePoint, double distance, double bearing)
 {
     return(_ruler.Destination(
                new double[] { tracePoint.Longitude, tracePoint.Latitude }
                , distance
                , bearing
                ));
 }
示例#2
0
        /// <summary>
        /// Extract probes according to ProbeExtractorOptions.
        /// </summary>
        /// <param name="trace">List of trace points</param>
        /// <returns>List of probes. Empty list if no trace point matched the options.</returns>
        public List <Probe> ExtractProbes(List <TracePoint> trace)
        {
            int tracePntCnt = trace.Count;

            long[]   durations = new long[tracePntCnt - 1];
            double[] distances = new double[tracePntCnt - 1];
            double[] speeds    = new double[tracePntCnt - 1];
            double[] bearings  = new double[tracePntCnt - 1];

            for (int i = 1; i < tracePntCnt; i++)
            {
                TracePoint current   = trace[i];
                TracePoint previous  = trace[i - 1];
                int        insertIdx = i - 1;

                durations[insertIdx] = (current.Timestamp - previous.Timestamp) / 1000;                 //seconds

                double[] currLocation = new double[] { current.Longitude, current.Latitude };
                double[] prevLocation = new double[] { previous.Longitude, previous.Latitude };
                distances[insertIdx] = _ruler.Distance(currLocation, prevLocation);
                speeds[insertIdx]    = distances[insertIdx] / durations[insertIdx] * 3600;              //kph

                double bearing = _ruler.Bearing(prevLocation, currLocation);
                bearings[insertIdx] = bearing < 0 ? 360 + bearing : bearing;
            }

            List <Probe> probes = new List <Probe>();

            // 1st pass: iterate trace points and determine if they are good
            // bail early if !_options.OutputBadProbes
            bool negativeDuration = false;

            for (int i = 1; i < speeds.Length; i++)
            {
                //assume tracpoint is good
                bool isGood = true;
                if (negativeDuration)
                {
                    // if trace already has a negative duration, then all probes are bad
                    isGood = false;
                }
                else if (durations[i] < 0)
                {
                    // if a trace has negative duration, the trace is likely noisy
                    // bail, if we don't want bad probes
                    if (!_options.OutputBadProbes)
                    {
                        return(new List <Probe>());
                    }

                    negativeDuration = true;
                    isGood           = false;
                }
                else if (durations[i] < _options.MinTimeBetweenProbes)
                {
                    // if shorter than the minTimeBetweenProbes, filter.
                    isGood = false;
                }
                else if (durations[i] > _options.MaxDurationRatioJump * durations[i - 1])
                {
                    // if not a gradual decrease in sampling frequency, it's most likely a signal jump
                    isGood = false;
                }
                else if (speeds[i] - speeds[i - 1] > _options.MaxAcceleration * durations[i])
                {
                    // if accelerating faster than maxAcceleration, it's most likely a glitch
                    isGood = false;
                }
                else if (speeds[i - 1] - speeds[i] > _options.MaxDeceleration * durations[i])
                {
                    // if decelerating faster than maxDeceleration, it's most likely a glitch
                    isGood = false;
                }
                else
                {
                    bool isForwardDirection = compareBearing(bearings[i - 1], bearings[i], 89, false);
                    if (!isForwardDirection)
                    {
                        isGood = false;
                    }
                }

                if (isGood || _options.OutputBadProbes)
                {
                    double[] coords = pointAtDistanceAndBearing(
                        trace[i - 1]
                        , distances[i] / 2
                        , bearings[i]
                        );

                    probes.Add(new Probe()
                    {
                        Latitude  = coords[1],
                        Longitude = coords[0],
                        StartTime = trace[i].Timestamp,
                        Duration  = durations[i],
                        Distance  = distances[i],
                        Speed     = speeds[i],
                        Bearing   = bearings[i],
                        IsGood    = isGood
                    });
                }
            }

            // if too few good probes, drop entire trace
            if (!_options.OutputBadProbes && probes.Count < _options.MinProbes)
            {
                return(new List <Probe>());
            }

            // MinProbes can be 0, return
            if (probes.Count == 0 && _options.MinProbes == 0)
            {
                return(new List <Probe>());
            }


            // 2nd pass

            // require at least two probes
            if (probes.Count > 1)
            {
                // check first probe in a trace against the average of first two good probes
                var avgSpeed    = (probes[0].Speed + probes[1].Speed) / 2;
                var avgDistance = (probes[0].Distance + probes[1].Distance) / 2;
                var avgDuration = (probes[0].Duration + probes[1].Duration) / 2;
                var avgBearing  = averageAngle(probes[0].Bearing, probes[1].Bearing);

                bool good = true;

                if (negativeDuration)
                {
                    if (!_options.OutputBadProbes)
                    {
                        return(new List <Probe>());
                    }

                    negativeDuration = true;
                    good             = false;

                    // if a trace has negative duration, the trace is likely noisy
                }
                else if (durations[0] < 0)
                {
                    good = false;
                }
                else if (durations[0] < _options.MinTimeBetweenProbes)
                {
                    // if shorter than the minTimeBetweenProbes, filter.
                    good = false;
                }
                else if (distances[0] > _options.MaxDistanceRatioJump * avgDistance)
                {
                    // if not a gradual increase in distance, it's most likely a signal jump
                    good = false;
                }
                else if (durations[0] > _options.MaxDurationRatioJump * avgDuration)
                {
                    // if not a gradual decrease in sampling frequency, it's most likely a signal jump
                    good = false;
                }
                else if (avgSpeed - speeds[0] > _options.MaxAcceleration * durations[0])
                {
                    // if accelerating faster than maxAcceleration, it's most likely a glitch
                    good = false;
                }
                else if (speeds[0] - avgSpeed > _options.MaxDeceleration * durations[0])
                {
                    // if decelerating faster than maxDeceleration, it's most likely a glitch
                    good = false;
                }
                else
                {
                    // if in reverse direction, it's most likely signal jump
                    bool isForwardDirection = compareBearing(bearings[0], avgBearing, 89, false);
                    if (!isForwardDirection)
                    {
                        good = false;
                    }
                }

                if (good || _options.OutputBadProbes)
                {
                    double[] coords = pointAtDistanceAndBearing(
                        trace[0]
                        , distances[0]
                        , bearings[0]
                        );

                    probes.Insert(
                        0,
                        new Probe()
                    {
                        Latitude  = coords[1],
                        Longitude = coords[0],
                        StartTime = trace[0].Timestamp,
                        Duration  = durations[0],
                        Distance  = distances[0],
                        Speed     = speeds[0],
                        Bearing   = bearings[0],
                        IsGood    = good
                    }
                        );
                }
            }

            return(probes);
        }