/** * Calculate error distance, between last through this to next, * if this node is removed. This metric provides for Douglas-Peuker * thinning. * * @param last Point previous in time to this node * @param node This node * @param next Point succeeding this node * * @return Distance error if this node is thinned */ static unsigned distance_metric(const TracePoint& last, const TracePoint& node, const TracePoint& next) { const int d_this = last.flat_distance(node) + node.flat_distance(next); const int d_rem = last.flat_distance(next); return abs(d_this - d_rem); }
TraceDelta(const TracePoint &p_last, const TracePoint &p, const TracePoint &p_next) :point(p), elim_time(time_metric(p_last, p, p_next)), elim_distance(distance_metric(p_last, p, p_next)), delta_distance(p.flat_distance(p_last)) { assert(elim_distance != null_delta); }
TriangleSecondLeg::Result TriangleSecondLeg::Calculate(const TracePoint &c, unsigned best) const { // this is a heuristic to remove invalid triangles // we do as much of this in flat projection for speed const unsigned df_2 = b.flat_distance(c); const unsigned df_3 = c.flat_distance(a); const unsigned df_total = df_1+df_2+df_3; // require some distance! if (df_total<20) { return Result(0, 0); } // no point scanning if worst than best if (df_total<= best) { return Result(0, 0); } const unsigned shortest = min(df_1, min(df_2, df_3)); // require all legs to have distance if (!shortest) { return Result(0, 0); } if (is_fai && (shortest*4<df_total)) { // fails min < 25% worst-case rule! return Result(0, 0); } const unsigned d = df_3+df_2; // without FAI rules, allow any triangle if (!is_fai) { return Result(d, df_total); } if (shortest*25>=df_total*7) { // passes min > 28% rule, // this automatically means we pass max > 45% worst-case return Result(d, df_total); } const unsigned longest = max(df_1, max(df_2, df_3)); if (longest*20>df_total*9) { // fails max > 45% worst-case rule! return Result(0, 0); } // passed basic tests, now detailed ones // find accurate min leg distance fixed leg(0); if (df_1 == shortest) { leg = a.get_location().distance(b.get_location()); } else if (df_2 == shortest) { leg = b.get_location().distance(c.get_location()); } else if (df_3 == shortest) { leg = c.get_location().distance(a.get_location()); } // estimate total distance by scaling. // this is a slight approximation, but saves having to do // three accurate distance calculations. const fixed d_total((df_total*leg)/shortest); if (d_total>=fixed(500000)) { // long distance, ok that it failed 28% rule return Result(d, df_total); } return Result(0, 0); }
TriangleSecondLeg(bool _fai, const TracePoint &_a, const TracePoint &_b) :is_fai(_fai), a(_a), b(_b), df_1(a.flat_distance(b)) {}
void update(const TracePoint &p_last, const TracePoint &p_next) { elim_time = time_metric(p_last, point, p_next); elim_distance = distance_metric(p_last, point, p_next); delta_distance = point.flat_distance(p_last); }