// ====================================================================== // // Copyright (c) 1997 The CGAL Consortium // // This software and related documentation is part of an INTERNAL release // of the Computational Geometry Algorithms Library (CGAL). It is not // intended for general use. // // ---------------------------------------------------------------------- // // release : $$ // release_date : $$ // // file : include/CGAL/Pm_segment_traits_2.h // package : Planar_map (5.87) // maintainer : Eyal Flato // source : // revision : // revision_date : // author(s) : Iddo Hanniel // Eyal Flato // Oren Nechushtan // Eti Ezra // Shai Hirsch // Eugene Lipovetsky // Efi Fogel // Ron Wein // // coordinator : Tel-Aviv University (Dan Halperin ) // // Chapter : // ====================================================================== #ifndef CGAL_PM_SEGMENT_TRAITS_2_H #define CGAL_PM_SEGMENT_TRAITS_2_H #include #include CGAL_BEGIN_NAMESPACE template class Pm_segment_traits_2 : public Kernel_ { public: typedef Kernel_ Kernel; // Categories: // #define HAS_LEFT_NOT #if !defined(HAS_LEFT_NOT) typedef Tag_true Has_left_category; #else typedef Tag_false Has_left_category; #endif // Traits objects typedef typename Kernel::Point_2 Point_2; typedef typename Kernel::Segment_2 X_curve_2; // Backward compatability typedef Point_2 Point; typedef X_curve_2 X_curve; // Currently, I leave this in the traits // Maybe we can change the usage inside Planar_map_2 typedef enum { UNDER_CURVE = -1, CURVE_NOT_IN_RANGE = 0, ABOVE_CURVE = 1, ON_CURVE = 2 } Curve_point_status; protected: // Functors: typedef typename Kernel::Is_vertical_2 Is_vertical_2; typedef typename Kernel::Construct_vertex_2 Construct_vertex_2; typedef typename Kernel::Less_x_2 Less_x_2; typedef typename Kernel::Equal_2 Equal_2; typedef CGAL::Counterclockwise_in_between_for_segments_2 Counterclockwise_in_between_2; protected: inline Counterclockwise_in_between_2 counterclockwise_in_between_2_object() const { return Counterclockwise_in_between_2(); } public: // Creation Pm_segment_traits_2() {} // Operations // ---------- /*! compare_x() compares the x-coordinates of two given points * \param p1 the first point * \param p2 the second point * \return LARGER if x(p1) > x(p2), SMALLER if x(p1) < x(p2), or else EQUAL * * \todo replace indirect use compare_x() with compare_x_2() */ Comparison_result compare_x(const Point_2 & p1, const Point_2 & p2) const { return compare_x_2_object()(p1, p2); } /*! compare_xy() compares lexigoraphically the two points by x, then by y. * \param p1 the first point * \param p2 the second point * \return LARGER if x(p1) > x(p2), or if x(p1) = x(p2) and y(p1) > y(p2); * SMALLER if x(p1) < x(p2), or if x(p1) = x(p2) and y(p1) < y(p2); * or else EQUAL */ Comparison_result compare_xy(const Point_2 & p1, const Point_2 & p2) const { return compare_xy_2_object()(p1, p2); } /*! curve_is_vertical() * \param cv the curve * \return true iff the curve is vertical * * \todo replace indirect use curve_is_vertical() with is_vertical_2() */ bool curve_is_vertical(const X_curve_2 & cv) const { return is_vertical_2_object()(cv); } /*! curve_is_in_x_range() * \param cv the curve * \param q the point * \return true if q is in the x range of cv * * \todo Intorduce Is_in_x_range_2() or perhaps Is_in_x_closed_range_2() * in kernel. Currently, this is implemented using existing traits (kernel) * functions (curve_source(), curve_target()) that return the source and * target points by value, which is not as efficient as possible. */ bool curve_is_in_x_range(const X_curve_2 & cv, const Point_2 & q) const { Construct_vertex_2 construct_vertex = construct_vertex_2_object(); const Point_2 & source = construct_vertex(cv, 0); const Point_2 & target = construct_vertex(cv, 1); Less_x_2 less_x = less_x_2_object(); return !((less_x(source, q) && less_x(target, q)) || (less_x(q, source) && less_x(q, target))); } /*! curve_compare_at_x() compares the y-coordinate of two given curves at * the x-coordinate of a given point. * Preconditions: The point q is in the x range of the two curves. * \param cv1 the first curve * \param cv2 the second curve * \param q the point * \return LARGER if cv1(x(q)) > cv2(x(q)), SMALLER if cv1(x(q)) < cv2(x(q), * or else EQUAL. * * \todo replace indirect use curve_compare_at_x() with compare_y_at_x_2() */ Comparison_result curve_compare_at_x(const X_curve_2 & cv1, const X_curve_2 & cv2, const Point_2 & q) const { CGAL_precondition(curve_is_in_x_range(cv1, q)); CGAL_precondition(curve_is_in_x_range(cv2, q)); return compare_y_at_x_2_object()(q, cv1, cv2); } #if !defined(HAS_LEFT_NOT) /*! curve_compare_at_x_left() compares the y value of two curves in an * epsilon environment to the left of the x value of the input point * Preconditions: The point q is in the x range of the two curves, and both * of them must be also be defined to its left. */ Comparison_result curve_compare_at_x_left(const X_curve_2 & cv1, const X_curve_2 & cv2, const Point_2 & q) const { // The two curves must not be vertical. CGAL_precondition(! curve_is_vertical(cv1)); CGAL_precondition(! curve_is_vertical(cv2)); // The two curve must be defined at q and also to its left. CGAL_precondition_code( Construct_vertex_2 construct_vertex = construct_vertex_2_object(); Less_x_2 less_x = less_x_2_object(); const Point_2 & source1 = construct_vertex(cv1, 0); const Point_2 & target1 = construct_vertex(cv1, 1); const Point_2 & source2 = construct_vertex(cv2, 0); const Point_2 & target2 = construct_vertex(cv2, 1); ); CGAL_precondition (less_x(source1, q) || less_x(target1, q)); CGAL_precondition (!(less_x(source1, q) && less_x(target1, q))); CGAL_precondition (less_x(source2, q) || less_x(target2, q)); CGAL_precondition (!(less_x(source2, q) && less_x(target2, q))); // Since the curves are continuous, if they are not equal at q, the same // result also applies to q's left. Comparison_result r = compare_y_at_x_2_object()(q, cv1, cv2); if (r != EQUAL) return r; // and meet at a point with the same x-coordinate as q // compare their derivatives. return compare_slope_2_object()(cv2, cv1); } #else /*! point_reflect_in_x_and_y() reflects the given point about the origin */ Point_2 point_reflect_in_x_and_y(const Point_2 & pt) const { Point_2 org = construct_point_2_object()(ORIGIN); typename Kernel::Vector_2 v = construct_vector_2_object()(pt, org); Point_2 reflected_pt(v); return reflected_pt; } /*! curve_reflect_in_x_and_y reflects the given curve about the origin */ X_curve_2 curve_reflect_in_x_and_y(const X_curve_2 & cv) const { X_curve_2 reflected_cv(point_reflect_in_x_and_y ( cv.source()), point_reflect_in_x_and_y ( cv.target())); return reflected_cv; } #endif /*! curve_compare_at_x_right() compares the y value of two curves in an * epsilon environment to the right of the x value of the input point * Preconditions: The point q is in the x range of the two curves, and both * of them must be also be defined to its right. */ Comparison_result curve_compare_at_x_right(const X_curve_2 & cv1, const X_curve_2 & cv2, const Point_2 & q) const { // The two curves must not be vertical. CGAL_precondition(! curve_is_vertical(cv1)); CGAL_precondition(! curve_is_vertical(cv2)); // The two curve must be defined at q and also to its right. CGAL_precondition_code( Construct_vertex_2 construct_vertex = construct_vertex_2_object(); Less_x_2 less_x = less_x_2_object(); const Point_2 & source1 = construct_vertex(cv1, 0); const Point_2 & target1 = construct_vertex(cv1, 1); const Point_2 & source2 = construct_vertex(cv2, 0); const Point_2 & target2 = construct_vertex(cv2, 1); ); CGAL_precondition (less_x(q, source1) || less_x(q, target1)); CGAL_precondition (!(less_x(q, source1) && less_x(q, target1))); CGAL_precondition (less_x(q, source2) || less_x(q, target2)); CGAL_precondition (!(less_x(q, source2) && less_x(q, target2))); // Since the curves are continuous, if they are not equal at q, the same // result also applies to q's left. Comparison_result r = curve_compare_at_x(cv1, cv2, q); if (r != EQUAL) return r; // and meet at a point with the same x-coordinate as q // compare their derivatives return compare_slope_2_object()(cv1, cv2); } /*! Return the curve-point status of the input objects * \todo Remove curve_get_point_status() from wrapper. Verify that * curve_is_in_x_range() and compare_y_at_x_2() are required in the * traits, and use directly. */ Curve_point_status curve_get_point_status(const X_curve_2 & cv, const Point_2 & p) const { if (!curve_is_in_x_range(cv, p)) return CURVE_NOT_IN_RANGE; Comparison_result res = compare_y_at_x_2_object()(p, cv); return ((res == LARGER) ? ABOVE_CURVE : ((res == SMALLER) ? UNDER_CURVE : ON_CURVE)); } /*! \todo Degenerate cases may not work! Talk with Eyal to fix the actual * code in Pmwx to use the same consisting definitions of * curve_is_between_cw(), counterclockwise_in_between_2_object(), and * the kernel function that is used to implement the later. */ bool curve_is_between_cw(const X_curve_2 & cv, const X_curve_2 & first, const X_curve_2 & second, const Point_2 & point) const { // Notice the change in order of first and second return counterclockwise_in_between_2_object()(point, cv, second, first); } /*! \todo replace indirect use curve_is_same() with equal_2() */ bool curve_is_same(const X_curve_2 & cv1,const X_curve_2 & cv2) const { Equal_2 equal = equal_2_object(); const X_curve_2 & ocv1 = construct_opposite_segment_2_object()(cv1); return equal(cv1, cv2) || equal(ocv1, cv2); } /*! \todo replace indirect use point_is_same() with equal_2() */ bool point_is_same(const Point_2 & p1, const Point_2 & p2) const { return equal_2_object()(p1, p2); } /*! \todo replace indirect use curve_source() with construct_vertex_2() */ Point_2 curve_source(const X_curve_2 & cv) const { return construct_vertex_2_object()(cv, 0); } /*! \todo replace indirect use curve_target() with construct_vertex_2() */ Point_2 curve_target(const X_curve_2 & cv) const { return construct_vertex_2_object()(cv, 1); } }; CGAL_END_NAMESPACE #endif