diff --git a/Cartesian_kernel/include/CGAL/Cartesian/function_objects.h b/Cartesian_kernel/include/CGAL/Cartesian/function_objects.h index 737a52dfc14..8b0153f03e1 100644 --- a/Cartesian_kernel/include/CGAL/Cartesian/function_objects.h +++ b/Cartesian_kernel/include/CGAL/Cartesian/function_objects.h @@ -3278,6 +3278,8 @@ namespace CartesianKernelFunctors { { typedef typename K::Point_2 Point_2; typedef typename K::Line_2 Line_2; + typedef typename K::Segment_2 Segment_2; + typedef typename K::Triangle_2 Triangle_2; public: typedef Point_2 result_type; @@ -3289,6 +3291,14 @@ namespace CartesianKernelFunctors { line_project_pointC2(l.a(), l.b(), l.c(), p.x(), p.y(), x, y); return construct_point_2(x, y); } + + Point_2 + operator()(const Segment_2& s, const Point_2& p) const + { return CommonKernelFunctors::Construct_projected_point_2()(s, p, K()); } + + Point_2 + operator()(const Triangle_2& t, const Point_2& p) const + { return CommonKernelFunctors::Construct_projected_point_2()(t, p, K()); } }; diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index 084a6578913..7efc0509023 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -2872,6 +2872,204 @@ namespace CommonKernelFunctors { { return v.rep().cartesian_end(); } + }; template + class Construct_projected_point_2 + { + bool + is_inside_triangle_2_aux( + const typename K::Point_2& p1, + const typename K::Point_2& p2, + const typename K::Point_2& q, + typename K::Point_2& result, + bool& outside, + const K& k) + { + typedef typename K::Vector_2 Vector_2; + typedef typename K::FT FT; + + typename K::Construct_vector_2 vector = + k.construct_vector_2_object(); + typename K::Construct_projected_point_2 projection = + k.construct_projected_point_2_object(); + typename K::Construct_line_2 line = + k.construct_line_2_object(); + typename K::Compute_scalar_product_2 scalar_product = + k.compute_scalar_product_2_object(); + typename K::Construct_direction_2 direction = + k.construct_direction_2_object(); + typename K::Construct_perpendicular_direction_2 perpendicular = + k.construct_perpendicular_direction_2_object(); + + // Check whether the point is cw or ccw with the triangle side (p1,p2) + Vector_2 orth = vector(p1, p2); + + if (scalar_product(vector(p1, q), vector(perpendicular(direction(orth), CGAL::COUNTERCLOCKWISE))) < FT(0)) + { + if (scalar_product(vector(p1, q), vector(p1, p2)) >= FT(0) + && scalar_product(vector(p2, q), vector(p2, p1)) >= FT(0)) + { + result = projection(line(p1, p2), q); + return true; + } + outside = true; + } + + return false; + } + + /** + * Returns the nearest point of p1,p2,p3 from origin + * @param origin the origin point + * @param p1 the first point + * @param p2 the second point + * @param p3 the third point + * @param k the kernel + * @return the nearest point from origin + */ + typename K::Point_2 + nearest_point_2(const typename K::Point_2& origin, + const typename K::Point_2& p1, + const typename K::Point_2& p2, + const typename K::Point_2& p3, + const K& k) + { + typedef typename K::FT FT; + + typename K::Compute_squared_distance_2 sq_distance = + k.compute_squared_distance_2_object(); + + const FT dist_origin_p1 = sq_distance(origin, p1); + const FT dist_origin_p2 = sq_distance(origin, p2); + const FT dist_origin_p3 = sq_distance(origin, p3); + + if (dist_origin_p2 >= dist_origin_p1 + && dist_origin_p3 >= dist_origin_p1) + { + return p1; + } + if (dist_origin_p3 >= dist_origin_p2) + { + return p2; + } + + return p3; + } + + /** + * @brief returns true if p is inside triangle t. If p is not inside t, + * result is the nearest point of t from p. + * @param p the reference point + * @param t the triangle + * @param result if p is not inside t, the nearest point of t from p + * @param k the kernel + * @return true if p is inside t + */ + bool + is_inside_triangle_2(const typename K::Point_2& p, + const typename K::Triangle_2& t, + typename K::Point_2& result, + const K& k) + { + typedef typename K::Point_2 Point_2; + + typename K::Construct_vertex_2 vertex_on = + k.construct_vertex_2_object(); + + const Point_2& t0 = vertex_on(t, 0); + const Point_2& t1 = vertex_on(t, 1); + const Point_2& t2 = vertex_on(t, 2); + + bool outside = false; + if (is_inside_triangle_2_aux(t0, t1, p, result, outside, k) + || is_inside_triangle_2_aux(t1, t2, p, result, outside, k) + || is_inside_triangle_2_aux(t2, t0, p, result, outside, k)) + { + return false; + } + + if (outside) + { + result = nearest_point_2(p, t0, t1, t2, k); + return false; + } + else + { + return true; + } + } + + public: + typename K::Point_2 + operator()(const typename K::Triangle_2& triangle, + const typename K::Point_2& origin, + const K& k) + { + typedef typename K::Point_2 Point_2; + typename K::Construct_vertex_2 vertex_on; + typename K::Construct_segment_2 segment; + + // Check if triangle is degenerated to call segment operator. + const Point_2& t0 = vertex_on(triangle, 0); + const Point_2& t1 = vertex_on(triangle, 1); + const Point_2& t2 = vertex_on(triangle, 2); + + if (t0 == t1) + return (*this)(segment(t1, t2), origin, k); + if (t1 == t2) + return (*this)(segment(t2, t0), origin, k); + if (t2 == t0) + return (*this)(segment(t0, t1), origin, k); + + Point_2 moved_point; + bool inside = is_inside_triangle_2(origin, triangle, moved_point, k); + + // If proj is inside triangle, return it + if (inside) + { + return origin; + } + + // Else return the constructed point + return moved_point; + } + + typename K::Point_2 + operator()(const typename K::Segment_2& s, + const typename K::Point_2& query, + const K& k) { + + typename K::Construct_vector_2 vector = + k.construct_vector_2_object(); + + typename K::Compute_scalar_product_2 scalar_product = + k.compute_scalar_product_2_object(); + + typename K::Construct_scaled_vector_2 scaled_vector = + k.construct_scaled_vector_2_object(); + + const typename K::Point_2& a = s.source(); + const typename K::Point_2& b = s.target(); + const typename K::Vector_2 d = vector(a, b); + + typename K::FT sqlen = scalar_product(d, d); + + // Degenerate segment + if (is_zero(sqlen)) + return a; + + const typename K::Vector_2 p = vector(a, query); + + typename K::FT proj = (scalar_product(p, d)) / sqlen; + + if (!is_positive(proj)) + return a; + + if (proj >= 1.0) + return b; + + typename K::Construct_point_2 construct_point_2; + return construct_point_2(a + scaled_vector(d, proj)); + } }; template