static inline bool projection_on_segment(Point const& subject, Point const& p, Point const& q) { typedef Point vector_type; typedef typename geometry::coordinate_type<Point>::type coordinate_type; vector_type v = q; vector_type w = subject; subtract_point(v, p); subtract_point(w, p); coordinate_type const zero = coordinate_type(); coordinate_type const c1 = dot_product(w, v); if (c1 < zero) { return false; } coordinate_type const c2 = dot_product(v, v); if (c2 < c1) { return false; } return true; }
inline calculation_type apply(Point const& p, PointOfSegment const& p1, PointOfSegment const& p2) const { assert_dimension_equal<Point, PointOfSegment>(); /* Algorithm [p1: (x1,y1), p2: (x2,y2), p: (px,py)] VECTOR v(x2 - x1, y2 - y1) VECTOR w(px - x1, py - y1) c1 = w . v c2 = v . v b = c1 / c2 RETURN POINT(x1 + b * vx, y1 + b * vy) */ // v is multiplied below with a (possibly) FP-value, so should be in FP // For consistency we define w also in FP fp_vector_type v, w; geometry::convert(p2, v); geometry::convert(p, w); subtract_point(v, p1); subtract_point(w, p1); Strategy strategy; boost::ignore_unused_variable_warning(strategy); calculation_type const zero = calculation_type(); fp_type const c1 = dot_product(w, v); if (c1 <= zero) { return strategy.apply(p, p1); } fp_type const c2 = dot_product(v, v); if (c2 <= c1) { return strategy.apply(p, p2); } // See above, c1 > 0 AND c2 > c1 so: c2 != 0 fp_type const b = c1 / c2; fp_strategy_type fp_strategy = strategy::distance::services::get_similar < Strategy, Point, fp_point_type >::apply(strategy); fp_point_type projected; geometry::convert(p1, projected); multiply_value(v, b); add_point(projected, v); //std::cout << "distance " << dsv(p) << " .. " << dsv(projected) << std::endl; return fp_strategy.apply(p, projected); }
inline return_type operator()(P const& p, Segment const& s) const { assert_dimension_equal<P, Segment>(); /* Algorithm POINT v(x2 - x1, y2 - y1); POINT w(px - x1, py - y1); c1 = w . v c2 = v . v b = c1 / c2 RETURN POINT(x1 + b * vx, y1 + b * vy); */ typedef typename boost::remove_const < typename point_type<Segment>::type >::type segment_point_type; segment_point_type v, w; // TODO // ASSUMPTION: segment // SOLVE THIS USING OTHER FUNCTIONS using get<,> copy_coordinates(s.second, v); copy_coordinates(p, w); subtract_point(v, s.first); subtract_point(w, s.first); Strategy strategy; coordinate_type c1 = dot_product(w, v); if (c1 <= 0) { return strategy(p, s.first); } coordinate_type c2 = dot_product(v, v); if (c2 <= c1) { return strategy(p, s.second); } // Even in case of char's, we have to turn to a point<double/float> // because of the division. coordinate_type b = c1 / c2; // Note that distances with integer coordinates do NOT work because // - the project point is integer // - if we solve that, the used distance_strategy cannot handle double points segment_point_type projected; copy_coordinates(s.first, projected); multiply_value(v, b); add_point(projected, v); return strategy(p, projected); }
inline return_type apply(Point const& p, PointOfSegment const& p1, PointOfSegment const& p2) const { assert_dimension_equal<Point, PointOfSegment>(); /* Algorithm POINT v(x2 - x1, y2 - y1); POINT w(px - x1, py - y1); c1 = w . v c2 = v . v b = c1 / c2 RETURN POINT(x1 + b * vx, y1 + b * vy); */ // Take here the first point type. It should have a default constructor. // That is not required for the second point type. Point v, w; copy_coordinates(p2, v); copy_coordinates(p, w); subtract_point(v, p1); subtract_point(w, p1); Strategy strategy; coordinate_type zero = coordinate_type(); coordinate_type c1 = dot_product(w, v); if (c1 <= zero) { return strategy.apply(p, p1); } coordinate_type c2 = dot_product(v, v); if (c2 <= c1) { return strategy.apply(p, p2); } // Even in case of char's, we have to turn to a point<double/float> // because of the division. typedef typename geometry::select_most_precise<coordinate_type, double>::type divisor_type; divisor_type b = c1 / c2; // Note that distances with integer coordinates do NOT work because // - the project point is integer // - if we solve that, the used distance_strategy cannot handle double points PointOfSegment projected; copy_coordinates(p1, projected); multiply_value(v, b); add_point(projected, v); return strategy.apply(p, projected); }
static inline Vector create_vector(Point1 const& p1, Point2 const& p2) { Vector v; convert(p1, v); subtract_point(v, p2); return v; }
inline bool operator()(const segment<const PS>& s, state_type& state) const { /* Algorithm: For each segment: begin dx = x2 - x1; dy = y2 - y1; sx = x2 + x1; sy = y2 + y1; mx = dx * sy; my = sx * dy; sum_mx += mx; sum_my += my; sum_msx += mx * sx; sum_msy += my * sy; end; return POINT(0.5 * sum_msx / sum_mx, 0.5 * sum_msy / sum_my); */ PS diff = s.second, sum = s.second; subtract_point(diff, s.first); add_point(sum, s.first); // We might create an arithmatic operation for this. PS m; get<0>(m) = get<0>(diff) * get<1>(sum); get<1>(m) = get<0>(sum) * get<1>(diff); add_point(state.sum_m, m); multiply_point(m, sum); add_point(state.sum_ms, m); return true; }
inline void experimental_elliptic_plane(Point3d const& p1, Point3d const& p2, Point3d & v1, Point3d & v2, Point3d & origin, Point3d & normal, Spheroid const& spheroid) { typedef typename coordinate_type<Point3d>::type coord_t; Point3d xy1 = projected_to_xy(p1, spheroid); Point3d xy2 = projected_to_xy(p2, spheroid); // origin = (xy1 + xy2) / 2 origin = xy1; add_point(origin, xy2); multiply_value(origin, coord_t(0.5)); // v1 = p1 - origin v1 = p1; subtract_point(v1, origin); // v2 = p2 - origin v2 = p2; subtract_point(v2, origin); normal = cross_product(v1, v2); }
static inline int elliptic_side_value(Point3d1 const& origin, Point3d1 const& norm, Point3d2 const& pt) { typedef typename coordinate_type<Point3d1>::type calc_t; calc_t c0 = 0; // vector oposite to pt - origin // only for the purpose of assigning origin Point3d1 vec = origin; subtract_point(vec, pt); calc_t d = dot_product(norm, vec); // since the vector is opposite the signs are opposite return math::equals(d, c0) ? 0 : d < c0 ? 1 : -1; // d > 0 }