inline return_type apply(Point const& p, PointOfSegment const& sp1, PointOfSegment const& sp2) const { // http://williams.best.vwh.net/avform.htm#XTE return_type d1 = m_strategy.apply(sp1, p); // Actually, calculation of d2 not necessary if we know that the projected point is on the great circle... return_type d2 = m_strategy.apply(sp2, p); return_type crs_AD = course(sp1, p); return_type crs_AB = course(sp1, sp2); return_type XTD = m_radius * geometry::math::abs(asin(sin(d1 / m_radius) * sin(crs_AD - crs_AB))); #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " " << crs_AD * geometry::math::r2d << std::endl; std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " " << crs_AB * geometry::math::r2d << std::endl; std::cout << "XTD: " << XTD << " d1: " << d1 << " d2: " << d2 << std::endl; #endif // Return shortest distance, either to projected point on segment sp1-sp2, or to sp1, or to sp2 return return_type((std::min)((std::min)(d1, d2), XTD)); }
inline return_type apply(Point const& p, PointOfSegment const& sp1, PointOfSegment const& sp2) const { // http://williams.best.vwh.net/avform.htm#XTE return_type d1 = m_strategy.apply(sp1, p); return_type d3 = m_strategy.apply(sp1, sp2); if (geometry::math::equals(d3, 0.0)) { // "Degenerate" segment, return either d1 or d2 return d1; } return_type d2 = m_strategy.apply(sp2, p); return_type crs_AD = course(sp1, p); return_type crs_AB = course(sp1, sp2); return_type crs_BA = crs_AB - geometry::math::pi<return_type>(); return_type crs_BD = course(sp2, p); return_type d_crs1 = crs_AD - crs_AB; return_type d_crs2 = crs_BD - crs_BA; // d1, d2, d3 are in principle not needed, only the sign matters return_type projection1 = cos( d_crs1 ) * d1 / d3; return_type projection2 = cos( d_crs2 ) * d2 / d3; #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " " << crs_AD * geometry::math::r2d << std::endl; std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " " << crs_AB * geometry::math::r2d << std::endl; std::cout << "Course " << dsv(sp2) << " to " << dsv(p) << " " << crs_BD * geometry::math::r2d << std::endl; std::cout << "Projection AD-AB " << projection1 << " : " << d_crs1 * geometry::math::r2d << std::endl; std::cout << "Projection BD-BA " << projection2 << " : " << d_crs2 * geometry::math::r2d << std::endl; #endif if(projection1 > 0.0 && projection2 > 0.0) { return_type XTD = m_radius * geometry::math::abs( asin( sin( d1 / m_radius ) * sin( d_crs1 ) )); #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK std::cout << "Projection ON the segment" << std::endl; std::cout << "XTD: " << XTD << " d1: " << d1 << " d2: " << d2 << std::endl; #endif // Return shortest distance, projected point on segment sp1-sp2 return return_type(XTD); } else { #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK std::cout << "Projection OUTSIDE the segment" << std::endl; #endif // Return shortest distance, project either on point sp1 or sp2 return return_type( (std::min)( d1 , d2 ) ); } }
static inline void consider(iterator_type begin, iterator_type end, return_type const& max_dist, int& n, distance_strategy_type const& ps_distance_strategy) { std::size_t size = end - begin; // size must be at least 3 // because we want to consider a candidate point in between if (size <= 2) { #ifdef GL_DEBUG_DOUGLAS_PEUCKER if (begin != end) { std::cout << "ignore between " << dsv(begin->p) << " and " << dsv((end - 1)->p) << " size=" << size << std::endl; } std::cout << "return because size=" << size << std::endl; #endif return; } iterator_type last = end - 1; #ifdef GL_DEBUG_DOUGLAS_PEUCKER std::cout << "find between " << dsv(begin->p) << " and " << dsv(last->p) << " size=" << size << std::endl; #endif // Find most far point, compare to the current segment //geometry::segment<Point const> s(begin->p, last->p); return_type md(-1.0); // any value < 0 iterator_type candidate; for(iterator_type it = begin + 1; it != last; ++it) { return_type dist = ps_distance_strategy.apply(it->p, begin->p, last->p); #ifdef GL_DEBUG_DOUGLAS_PEUCKER std::cout << "consider " << dsv(it->p) << " at " << double(dist) << ((dist > max_dist) ? " maybe" : " no") << std::endl; #endif if (dist > md) { md = dist; candidate = it; } } // If a point is found, set the include flag // and handle segments in between recursively if (md > max_dist) { #ifdef GL_DEBUG_DOUGLAS_PEUCKER std::cout << "use " << dsv(candidate->p) << std::endl; #endif candidate->included = true; n++; consider(begin, candidate + 1, max_dist, n, ps_distance_strategy); consider(candidate, end, max_dist, n, ps_distance_strategy); } }