From f04c83fb1568ac3cd2cb78f559daf9761dda9774 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Wed, 18 Jan 2017 12:33:33 +0200 Subject: [PATCH] casting_2: added pullout_direction_single_mold_translation --- .../single_mold_translational_casting.cpp | 77 +- .../Set_movable_separability_2/star.dat | 2 + .../Set_movable_separability_2/trapezoid.dat | 2 + .../Set_movable_separability_2/triangle.dat | 2 + .../Circle_arrangment.h | 702 +++++++++--------- .../CGAL/Set_movable_separability_2/Utils.h | 70 ++ ...tion_single_mold_translational_casting_2.h | 115 +-- ...ions_single_mold_translational_casting_2.h | 212 ++++-- ...dges_single_mold_translational_casting_2.h | 180 ++--- ...t_directions_single_mold_translational.cpp | 128 ++++ 10 files changed, 911 insertions(+), 579 deletions(-) create mode 100644 Set_movable_separability_2/examples/Set_movable_separability_2/star.dat create mode 100644 Set_movable_separability_2/examples/Set_movable_separability_2/trapezoid.dat create mode 100644 Set_movable_separability_2/examples/Set_movable_separability_2/triangle.dat create mode 100644 Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h mode change 100644 => 100755 Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h mode change 100644 => 100755 Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h mode change 100644 => 100755 Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h create mode 100644 Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp index 3fb52cebfcf..4eda2901905 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp @@ -4,10 +4,14 @@ #include #include #include +#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; typedef Kernel::Direction_2 Direction_2; +typedef Kernel::Vector_2 Vector_2; +typedef Kernel::Point_2 Point_2; typedef std::pair Direction_range; typedef std::pair Top_edge; @@ -21,27 +25,78 @@ int main(int argc, char* argv[]) const char* filename = (argc > 1) ? argv[1] : "polygon.dat"; std::ifstream input_file(filename); if (! input_file.is_open()) { - std::cerr << "Failed to open the " << filename << std::endl; - return -1; + std::cerr << "Failed to open the " << filename << std::endl; + return -1; } input_file >> pgn; input_file.close(); auto poly_orientation = pgn.orientation(); std::list top_edges; - SMS::top_edges_single_mold_translational_casting_2 - (pgn, std::back_inserter(top_edges)); + + //example for top_edges_single_mold_translational_casting_2 + SMS::top_edges_single_mold_translational_casting_2 + (pgn, std::back_inserter(top_edges)); if (top_edges.empty()) std::cout << "The polygon is not castable!" << std::endl; else { - std::cout << "There are " << top_edges.size() << " top edges:" << std::endl; - for (const auto& top_edge : top_edges) { - std::cout << "Edge number: " << top_edge.first << std::endl - << "\tEdge: "<< pgn.edge(top_edge.first) << std::endl - << "\tPullout directions from: "<< top_edge.second.first - << " to " << top_edge.second.second - << std::endl<< std::endl; + std::cout << "There are " << top_edges.size() << " top edges:" << std::endl; + for (const auto& top_edge : top_edges) { + std::cout << "Edge number: " << top_edge.first << std::endl + << "\tEdge: "<< pgn.edge(top_edge.first) << std::endl + << "\tPullout directions from: "<< top_edge.second.first + << " to " << top_edge.second.second + << std::endl<< std::endl; + } + } + std::cout << "-----------------------------------"<< std::endl; + + //example for pullout_directions_single_mold_translational_casting_2 + int index =0; + for (auto e_it = pgn.edges_begin(); e_it != pgn.edges_end(); ++e_it, ++index) + + { + + std::pair > res = SMS::pullout_directions_single_mold_translational_casting_2(pgn,e_it); + if (res.first) + { + std::cout << "The polygon is castable using edge "<(*e_it, poly_orientation); + Direction_2 d = segment_outer_circle.first; + d= d.perpendicular(CGAL::CLOCKWISE); + bool res = SMS::is_pullout_direction_single_mold_translational_casting_2(pgn,e_it,d); + std::cout << "The polygon is "<<(res?"":"not ") <<"castable using edge "< + res = SMS::is_pullout_direction_single_mold_translational_casting_2(pgn,d); + if (res.first) + { + std::cout << "The polygon is castable in direction d ("< -class Circle_arrangment { - typedef typename Kernel::Direction_2 Point; - typedef std::pair Arc; + template + class Circle_arrangment { + typedef typename Kernel::Direction_2 Point; + typedef std::pair Arc; - /* Legend: - * Point = Represented as Direction_2. It is the intersection between the - * fitting Direction_2 and the unit circle - * - * Arc = Represented as a pair of points. clockwise arc between the first - * point and the second point. (each of its sides might be open or closed) - */ + /* Legend: + * Point = Represented as Direction_2. It is the intersection between the + * fitting Direction_2 and the unit circle + * + * Arc = Represented as a pair of points. clockwise arc between the first + * point and the second point. (each of its sides might be open or closed) + */ - /*! \fn bool is_open_direction_contained_in_arc(point p, bool is_counterclockwise, Arc A) - * Checks whether an open epsilon area clockwise/counterclockwise from a point - * p is contained in an arc s. - * \param[in] p a point . - * \param[in] is_counterclockwise true: we care about the counterclockwise - * epsilon area of p. false: same with clockwise - * \param[in] A an Arc that should contain the epsilon area - */ - bool is_open_direction_contained_in_arc(const Point p, - const bool is_counterclockwise, - const Arc A) const - { - if ((is_counterclockwise && (p == A.second)) || - (!is_counterclockwise && (p == A.first))) - return false; - auto cc_in_between = m_kernel.counterclockwise_in_between_2_object(); - return !cc_in_between(p, A.first, A.second); - } + /*! \fn bool is_open_direction_contained_in_arc(point p, bool is_counterclockwise, Arc A) + * Checks whether an open epsilon area clockwise/counterclockwise from a point + * p is contained in an arc s. + * \param[in] p a point . + * \param[in] is_counterclockwise true: we care about the counterclockwise + * epsilon area of p. false: same with clockwise + * \param[in] A an Arc that should contain the epsilon area + */ + bool is_open_direction_contained_in_arc(const Point p, + const bool is_counterclockwise, + const Arc A) const + { + if ((is_counterclockwise && (p == A.second)) || + (!is_counterclockwise && (p == A.first))) + return false; + auto cc_in_between = m_kernel.counterclockwise_in_between_2_object(); + return !cc_in_between(p, A.first, A.second); + } - /*! \fn bool is_a_contained_in_b(bool is_a_start_closed,bool is_a_end_closed, arc A, arc B) - * \brief checks whether an arc A is contained in an arc B - * \param[in] is_a_start_closed - do A contains its start point (clockwise) - * \param[in] is_a_end_closed - do A contains its end point (clockwise) - * \param[in] A - an arc - * \param[in] B - an *open* arc - */ - bool is_a_contained_in_b(const bool is_a_start_closed, - const bool is_a_end_closed, - const Arc A,const Arc B) const - { - //A is closed, B is open and they share an vertex -> A not contained in B - if ((is_a_start_closed &&(A.first == B.first)) || - (is_a_end_closed && (A.second == B.second))) - return false; - if ((A.first == B.second) || (B.first == A.second)) return false; - auto cc_in_between = m_kernel.counterclockwise_in_between_2_object(); - return (!cc_in_between(A.first, B.first, B.second) && - !cc_in_between(A.second, B.first, B.second) && - !cc_in_between(A.first, B.first, A.second)); - } + /*! \fn bool is_a_contained_in_b(bool is_a_start_closed,bool is_a_end_closed, arc A, arc B) + * \brief checks whether an arc A is contained in an arc B + * \param[in] is_a_start_closed - do A contains its start point (clockwise) + * \param[in] is_a_end_closed - do A contains its end point (clockwise) + * \param[in] A - an arc + * \param[in] B - an *open* arc + */ + bool is_a_contained_in_b(const bool is_a_start_closed, + const bool is_a_end_closed, + const Arc A,const Arc B) const + { + //A is closed, B is open and they share an vertex -> A not contained in B + if ((is_a_start_closed &&(A.first == B.first)) || + (is_a_end_closed && (A.second == B.second))) + return false; + if ((A.first == B.second) || (B.first == A.second)) return false; + auto cc_in_between = m_kernel.counterclockwise_in_between_2_object(); + return (!cc_in_between(A.first, B.first, B.second) && + !cc_in_between(A.second, B.first, B.second) && + !cc_in_between(A.first, B.first, A.second)); + } - /*! \Circle_arrangment_edge - * This class represents a cells (a point or an arc) of depth 0,1,2+ in the - * Circle_arrangment where depth the number of inserted open half-circles - * inserted that cover this cell - * This edge (cell) is described by the first point of the edge (clockwise). - * The last point can be deduced by the next instance of - * Circle_arrangment_edge in the list in Circle_arrangment - * this class also keeps the cell depth. - */ - class Circle_arrangment_edge { - public: - bool m_start_is_closed; + /*! \Circle_arrangment_edge + * This class represents a cells (a point or an arc) of depth 0,1,2+ in the + * Circle_arrangment where depth the number of inserted open half-circles + * inserted that cover this cell + * This edge (cell) is described by the first point of the edge (clockwise). + * The last point can be deduced by the next instance of + * Circle_arrangment_edge in the list in Circle_arrangment + * this class also keeps the cell depth. + */ + class Circle_arrangment_edge { + public: + bool m_start_is_closed; - Point m_edge_start_angle; // the end is the start of the next edge + Point m_edge_start_angle; // the end is the start of the next edge - uint8_t m_count; // no. of outer circles that cover the edge (0/1/2+) + uint8_t m_count; // no. of outer circles that cover the edge (0/1/2+) - size_t m_edge_index; // the index of the polygon edge the open - // half-circle of which covers this cell. - // only relevant if m_count ==1 + size_t m_edge_index; // the index of the polygon edge the open + // half-circle of which covers this cell. + // only relevant if m_count ==1 - /*! \ctor Circle_arrangment_edge(point edge_start_angle, size_t edge_index, bool start_is_closed,bool set_count_to_one=true) - * Creates a new edge (Arc), this edge count must be 0 or 1 - * \param[in] edge_start_angle the first point of the arc (clockwise) - * \param[in] edge_index the index of the polygon edge who's open - * half-circle covers this cell - only relevant if m_count == 1 - * \param[in] start_is_closed - is the point edge_start_angle contained in - * this cell - * \param[in] set_count_to_one to set the m_count to one (or zero if this - * var is false) - */ - Circle_arrangment_edge(const Point edge_start_angle, - const size_t edge_index, - const bool start_is_closed, - const bool set_count_to_one = true) - { - this->m_start_is_closed = start_is_closed; - this->m_edge_start_angle = edge_start_angle; - this->m_count = (int) set_count_to_one; - this->m_edge_index = edge_index; - } + /*! \ctor Circle_arrangment_edge(point edge_start_angle, size_t edge_index, bool start_is_closed,bool set_count_to_one=true) + * Creates a new edge (Arc), this edge count must be 0 or 1 + * \param[in] edge_start_angle the first point of the arc (clockwise) + * \param[in] edge_index the index of the polygon edge who's open + * half-circle covers this cell - only relevant if m_count == 1 + * \param[in] start_is_closed - is the point edge_start_angle contained in + * this cell + * \param[in] set_count_to_one to set the m_count to one (or zero if this + * var is false) + */ + Circle_arrangment_edge(const Point edge_start_angle, + const size_t edge_index, + const bool start_is_closed, + const bool set_count_to_one = true) + { + this->m_start_is_closed = start_is_closed; + this->m_edge_start_angle = edge_start_angle; + this->m_count = (int) set_count_to_one; + this->m_edge_index = edge_index; + } - /*! \fn void plusplus(size_t edge_index) - * Adds new polygon edge who's open half-circle covers this cell - * \param[in] edge_index - the index of this edge - * increase the edge m_count by one (if it is 2+, it will stay 2+) - * set this new edge to be the one covers the cell if the m_count was zero - * before. (only relevant if now m_count == 1) - */ - void plusplus(const size_t edge_index) - { - if (this->m_count ==0) { - this->m_edge_index = edge_index; - this->m_count = 1; - } - else if(this->m_count ==1) this->m_count = 2; - } - bool is_covered() { return m_count == 2; } - }; + /*! \fn void plusplus(size_t edge_index) + * Adds new polygon edge who's open half-circle covers this cell + * \param[in] edge_index - the index of this edge + * increase the edge m_count by one (if it is 2+, it will stay 2+) + * set this new edge to be the one covers the cell if the m_count was zero + * before. (only relevant if now m_count == 1) + */ + void plusplus(const size_t edge_index) + { + if (this->m_count ==0) { + this->m_edge_index = edge_index; + this->m_count = 1; + } + else if(this->m_count ==1) this->m_count = 2; + } + bool is_covered() { return m_count == 2; } + }; - typedef typename std::list Circle_edges; + typedef typename std::list Circle_edges; - //! The kernel to use. - const Kernel& m_kernel; + //! The kernel to use. + const Kernel& m_kernel; - Circle_edges m_edges; + Circle_edges m_edges; - /*! \fn void insert_if_legal(const Circle_edge_iterator cur_it, - * const Circle_edge_iterator next_it, - * const struct Circle_arrangment_edge &edge) - * Adds new edge to the arrangement if it won't create some empty edges - * \param[in] cur_it iterator to the edge before where the new edge should be - * inserted - * \param[in] next_it iterator to the edge after where the new edge should be - * inserted - * \param[in] edge the new edge that should be inserted - * - * Notice that next_it is redundant since it can be deduced from cur_it. - * But it was easier for me to just send it as well. - */ - template - void insert_if_legal(const InputIterator cur_it, - InputIterator next_it, - const struct Circle_arrangment_edge& edge) - { - if (((edge.m_start_is_closed && !next_it->m_start_is_closed) || - (edge.m_edge_start_angle != next_it->m_edge_start_angle)) && - ((cur_it->m_start_is_closed && !edge.m_start_is_closed) || - (edge.m_edge_start_angle != cur_it->m_edge_start_angle))) - { - m_edges.insert(next_it, edge); - return; - } - } + /*! \fn void insert_if_legal(const Circle_edge_iterator cur_it, + * const Circle_edge_iterator next_it, + * const struct Circle_arrangment_edge &edge) + * Adds new edge to the arrangement if it won't create some empty edges + * \param[in] cur_it iterator to the edge before where the new edge should be + * inserted + * \param[in] next_it iterator to the edge after where the new edge should be + * inserted + * \param[in] edge the new edge that should be inserted + * + * Notice that next_it is redundant since it can be deduced from cur_it. + * But it was easier for me to just send it as well. + */ + template + void insert_if_legal(const InputIterator cur_it, + InputIterator next_it, + const struct Circle_arrangment_edge& edge) + { + if (((edge.m_start_is_closed && !next_it->m_start_is_closed) || + (edge.m_edge_start_angle != next_it->m_edge_start_angle)) && + ((cur_it->m_start_is_closed && !edge.m_start_is_closed) || + (edge.m_edge_start_angle != cur_it->m_edge_start_angle))) + { + m_edges.insert(next_it, edge); + return; + } + } - /*! \fn void merge_adjacent_2_edges_and_remove_empty() - * \brief merge all the arcs that are adjacent and of depth 2+ - * it doesn't merge the first and last ones since it is easier this way. - */ - void merge_adjacent_2_edges_and_remove_empty() - { - bool in_two_edge(false); - for (auto it = m_edges.begin(); it != m_edges.end();) { - if (it->is_covered()) { - if (in_two_edge) { - it = m_edges.erase(it); - continue; - } - in_two_edge = true; - } - else { - in_two_edge = false; - } - ++it; - } - } + /*! \fn void merge_adjacent_2_edges_and_remove_empty() + * \brief merge all the arcs that are adjacent and of depth 2+ + * it doesn't merge the first and last ones since it is easier this way. + */ + void merge_adjacent_2_edges_and_remove_empty() + { + bool in_two_edge(false); + for (auto it = m_edges.begin(); it != m_edges.end();) { + if (it->is_covered()) { + if (in_two_edge) { + it = m_edges.erase(it); + continue; + } + in_two_edge = true; + } + else { + in_two_edge = false; + } + ++it; + } + } -public: - /*! \ctor Circle_arrangment(arc first_segment_outer_circle) - * Creates an arrangement on circle with two edges the one covered by - * first_segment_outer_circle and the other one - * \param[in] first_segment_outer_circle the outer circle of the first segment - * of the polygon. - * Notice that you might consider implementing the ctor as an full circle of - * depth 0, but it was much easier for me to ignore the case where the all - * circle is a single arc, so I choose this implementation. - */ - Circle_arrangment(const Kernel& kernel, const Arc first_segment_outer_circle) : - m_kernel(kernel) - { - m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, - 0, false)); - m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, - 0, true, false)); - } - - /*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index) - * Updates the arrangement in respect to a new segment outer open circle - * \param[in] segment_outer_circle - the outer circle of the current segment of - * the polygon. - * \param[in] edge_index this segment id - * This is the main funtion of this code. It separates the cells in which the - * endpoints of the new arc is contained to two parts and increase m_count - * for all the cells that the new arc covers. In the end the function - * merge_adjacent_2_edges_and_remove_empty is called to remove redundant cells - */ - void add_segment_outer_circle(const Arc segment_outer_circle, - const size_t edge_index) - { - Arc edge; - bool is_start_closed_segment = m_edges.begin()->m_start_is_closed; - bool is_end_closed_segment ; - edge.first = m_edges.begin()->m_edge_start_angle; - //edge.second ; - auto next_it = m_edges.begin(); - auto it = m_edges.begin(); - bool done = false; - while (!done) { - it = next_it; - next_it = it; - ++next_it; - if (next_it == m_edges.end()) { - done = true; - next_it = m_edges.begin(); - } - - is_start_closed_segment =it->m_start_is_closed; - is_end_closed_segment = !next_it->m_start_is_closed; - edge.first = it->m_edge_start_angle; - edge.second =next_it->m_edge_start_angle; - - if (it->m_count == 2) continue; - if (is_a_contained_in_b(is_start_closed_segment, is_end_closed_segment, - edge, segment_outer_circle)) + public: + /*! \ctor Circle_arrangment(arc first_segment_outer_circle) + * Creates an arrangement on circle with two edges the one covered by + * first_segment_outer_circle and the other one + * \param[in] first_segment_outer_circle the outer circle of the first segment + * of the polygon. + * Notice that you might consider implementing the ctor as an full circle of + * depth 0, but it was much easier for me to ignore the case where the all + * circle is a single arc, so I choose this implementation. + */ + Circle_arrangment(const Kernel& kernel, const Arc first_segment_outer_circle) : + m_kernel(kernel) { - it->plusplus(edge_index); - continue; + m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, + 0, false)); + m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, + 0, true, false)); } - bool is_start_contained = - is_open_direction_contained_in_arc(segment_outer_circle.first, true, - edge); - bool is_end_contained = - is_open_direction_contained_in_arc(segment_outer_circle.second, false, - edge); - // o~~~~~~~~~~~~o = new arc - // ?------------? = "old" arc (the edge from the array) - if (is_start_contained) { - if (is_end_contained) { - auto cc_in_between = m_kernel.counterclockwise_in_between_2_object(); - bool isordered = !cc_in_between(segment_outer_circle.second, - segment_outer_circle.first, - edge.second); - if (isordered) { - // o~~~~~~~~~~~~o - // ?-----------------------? - // __________________________ - // ?----c - // o~-~-~-~-~-~-o - // c-----? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = false; - edge2.m_edge_start_angle = segment_outer_circle.first; - edge2.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge2); - struct Circle_arrangment_edge edge3 = *it; - edge3.m_start_is_closed = true; - edge3.m_edge_start_angle = segment_outer_circle.second; - this->insert_if_legal(it,next_it,edge3); - } - else { - // ...~~~~~~~~~o o~~~~~~~~~~... (round) - // ?-----------? - // __________________________ - // ?~-~o - // c---c - // o-~-? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = true; - edge2.m_edge_start_angle = segment_outer_circle.second; - this->insert_if_legal(it, next_it, edge2); - struct Circle_arrangment_edge edge3 = *it; - edge3.m_start_is_closed = false; - edge3.m_edge_start_angle = segment_outer_circle.first; - edge3.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge3); - it->plusplus(edge_index); - } - } - else { - // o~~~~~~~~~~~~o - // ?-----------? - //_____________________ - // ?----c - // o-~-~-~? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = false; - edge2.m_edge_start_angle = segment_outer_circle.first; - edge2.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge2); - } - } - else { - if (is_end_contained) { - // o~~~~~~~~~~~~o - // ?------------? - //_____________________ - // ?-~-~-~-o - // c----? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = true; - edge2.m_edge_start_angle = segment_outer_circle.second; - it->plusplus(edge_index); - this->insert_if_legal(it, next_it, edge2); - } - //else - no intersection, do noting - } - } - merge_adjacent_2_edges_and_remove_empty(); - } + + /*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index) + * Updates the arrangement in respect to a new segment outer open circle + * \param[in] segment_outer_circle - the outer circle of the current segment of + * the polygon. + * \param[in] edge_index this segment id + * This is the main funtion of this code. It separates the cells in which the + * endpoints of the new arc is contained to two parts and increase m_count + * for all the cells that the new arc covers. In the end the function + * merge_adjacent_2_edges_and_remove_empty is called to remove redundant cells + */ + void add_segment_outer_circle(const Arc segment_outer_circle, + const size_t edge_index) + { + Arc edge; + bool is_start_closed_segment = m_edges.begin()->m_start_is_closed; + bool is_end_closed_segment ; + edge.first = m_edges.begin()->m_edge_start_angle; + //edge.second ; + auto next_it = m_edges.begin(); + auto it = m_edges.begin(); + bool done = false; + while (!done) { + it = next_it; + next_it = it; + ++next_it; + if (next_it == m_edges.end()) { + done = true; + next_it = m_edges.begin(); + } + + is_start_closed_segment =it->m_start_is_closed; + is_end_closed_segment = !next_it->m_start_is_closed; + edge.first = it->m_edge_start_angle; + edge.second =next_it->m_edge_start_angle; + + if (it->m_count == 2) continue; + if (is_a_contained_in_b(is_start_closed_segment, is_end_closed_segment, + edge, segment_outer_circle)) + { + it->plusplus(edge_index); + continue; + } + bool is_start_contained = + is_open_direction_contained_in_arc(segment_outer_circle.first, true, + edge); + bool is_end_contained = + is_open_direction_contained_in_arc(segment_outer_circle.second, false, + edge); + // o~~~~~~~~~~~~o = new arc + // ?------------? = "old" arc (the edge from the array) + if (is_start_contained) { + if (is_end_contained) { + auto cc_in_between = m_kernel.counterclockwise_in_between_2_object(); + bool isordered = !cc_in_between(segment_outer_circle.second, + segment_outer_circle.first, + edge.second); + if (isordered) { + // o~~~~~~~~~~~~o + // ?-----------------------? + // __________________________ + // ?----c + // o~-~-~-~-~-~-o + // c-----? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = false; + edge2.m_edge_start_angle = segment_outer_circle.first; + edge2.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge2); + struct Circle_arrangment_edge edge3 = *it; + edge3.m_start_is_closed = true; + edge3.m_edge_start_angle = segment_outer_circle.second; + this->insert_if_legal(it,next_it,edge3); + } + else { + // ...~~~~~~~~~o o~~~~~~~~~~... (round) + // ?-----------? + // __________________________ + // ?~-~o + // c---c + // o-~-? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = true; + edge2.m_edge_start_angle = segment_outer_circle.second; + this->insert_if_legal(it, next_it, edge2); + struct Circle_arrangment_edge edge3 = *it; + edge3.m_start_is_closed = false; + edge3.m_edge_start_angle = segment_outer_circle.first; + edge3.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge3); + it->plusplus(edge_index); + } + } + else { + // o~~~~~~~~~~~~o + // ?-----------? + //_____________________ + // ?----c + // o-~-~-~? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = false; + edge2.m_edge_start_angle = segment_outer_circle.first; + edge2.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge2); + } + } + else { + if (is_end_contained) { + // o~~~~~~~~~~~~o + // ?------------? + //_____________________ + // ?-~-~-~-o + // c----? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = true; + edge2.m_edge_start_angle = segment_outer_circle.second; + it->plusplus(edge_index); + this->insert_if_legal(it, next_it, edge2); + } + //else - no intersection, do noting + } + } + merge_adjacent_2_edges_and_remove_empty(); + } #if 0 - // debug function - void printArrangement() - { - for (auto it = m_edges.begin(); it != m_edges.end(); ++it) { - if (it->m_start_is_closed) std::cout<<")["; - else std::cout << "]("; - std::cout << it->m_edge_start_angle; - std::cout << ","<<(int)it->m_count; - } - std::cout << "\n\n"; - } + // debug function + void printArrangement() + { + for (auto it = m_edges.begin(); it != m_edges.end(); ++it) { + if (it->m_start_is_closed) std::cout<<")["; + else std::cout << "]("; + std::cout << it->m_edge_start_angle; + std::cout << ","<<(int)it->m_count; + } + std::cout << "\n\n"; + } #endif - /*! \fn void get_all_1_edges(OutputIterator oi) - * Insert to oi all the cells in depth 1 i.e. the cells that represent legal - * pullout directions - * \param[in, out] oi the output iterator to put the cells in - * Puts in oi var of type pair > foreach valid top edge. - * Should only be called after all of the polygon edges where inserted. - */ - template - OutputIterator get_all_1_edges(OutputIterator oi) - { - for (auto it = m_edges.begin(); it != m_edges.end();) { - if ((*it).m_count == 1) { - std::pair edge; - edge.first = (*it).m_edge_index; - edge.second.first = (*it).m_edge_start_angle; - ++it; - edge.second.second = - (*((it == m_edges.end()) ? m_edges.begin() : (it))).m_edge_start_angle; - *oi++ = edge; - } - else - { - ++it; - } - } - return oi; - } + /*! \fn void get_all_1_edges(OutputIterator oi) + * Insert to oi all the cells in depth 1 i.e. the cells that represent legal + * pullout directions + * \param[in, out] oi the output iterator to put the cells in + * Puts in oi var of type pair > foreach valid top edge. + * Should only be called after all of the polygon edges where inserted. + */ + template + OutputIterator get_all_1_edges(OutputIterator oi) + { + for (auto it = m_edges.begin(); it != m_edges.end();) { + if ((*it).m_count == 1) { + std::pair edge; + edge.first = (*it).m_edge_index; + edge.second.first = (*it).m_edge_start_angle; + ++it; + edge.second.second = + (*((it == m_edges.end()) ? m_edges.begin() : (it))).m_edge_start_angle; + *oi++ = edge; + } + else + { + ++it; + } + } + return oi; + } - /*! \fn bool all_is_covered_twice() - * Before running this run merge_adjacent_2_edges_and_remove_empty() or - * add_segment_outer_circle() which calls - * merge_adjacent_2_edges_and_remove_empty(). - * - * The funtions checks that the whole circle is a single cell, which can - * happen only if this cell is of depth 2, so there is no need to check the - * depth as well. - * \return if all of the arrangement is in depth 2+ - */ - bool all_is_covered_twice() { return m_edges.size() == 1; } -}; + /*! \fn bool all_is_covered_twice() + * Before running this run merge_adjacent_2_edges_and_remove_empty() or + * add_segment_outer_circle() which calls + * merge_adjacent_2_edges_and_remove_empty(). + * + * The funtions checks that the whole circle is a single cell, which can + * happen only if this cell is of depth 2, so there is no need to check the + * depth as well. + * \return if all of the arrangement is in depth 2+ + */ + bool all_is_covered_twice() { return m_edges.size() == 1; } + }; -} // end of namespace internal -} // end of namespace Set_movable_separability_2 + } // end of namespace internal + } // end of namespace Set_movable_separability_2 } // end of namespace CGAL #endif diff --git a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h new file mode 100644 index 00000000000..f1323435ec6 --- /dev/null +++ b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h @@ -0,0 +1,70 @@ +/* + * utils.h + * + * Created on: Jan 17, 2017 + * Author: root + */ + +#ifndef SET_MOVABLE_SEPARABILITY_2_INCLUDE_CGAL_SET_MOVABLE_SEPARABILITY_2_UTILS_H_ +#define SET_MOVABLE_SEPARABILITY_2_INCLUDE_CGAL_SET_MOVABLE_SEPARABILITY_2_UTILS_H_ +#include +#include + + +namespace CGAL { +namespace Set_movable_separability_2 { +namespace internal { + +/*! \fn std::pair get_segment_outer_circle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) + * \param[in] seg the polygon segment + * \param[in] orientation the orientation of the segment (and the polygon). + * if CLOCKWISE then the outer half circle is to the left. + * \return the open outer half-circle of the edge. + */ +template +inline std::pair +get_segment_outer_circle(const typename Kernel::Segment_2 seg, + const CGAL::Orientation orientation) +{ + typename Kernel::Direction_2 forward( seg); + typename Kernel::Direction_2 backward(-forward); + return (orientation == CGAL::Orientation::CLOCKWISE) ? + std::make_pair(backward, forward) : std::make_pair(forward, backward); +} + +template +bool is_any_edge_colinear(const CGAL::Polygon_2& pgn) +{ + typedef typename CGAL::Point_2 Point_2; + typedef typename CGAL::Polygon_2 Polygon_2; + typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; + Vertex_const_iterator vci = pgn.vertices_begin(); + Point_2 firstVar = *(vci++); + Point_2 secondVar = *(vci++); + Point_2 thirdVar = *(vci++); + for (; vci != pgn.vertices_end(); ++vci) { + firstVar = secondVar; + secondVar = thirdVar; + thirdVar = *vci; + if (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + } + vci = pgn.vertices_begin(); + firstVar = secondVar; + secondVar = thirdVar; + thirdVar = *(vci++); + if(CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + + firstVar = secondVar; + secondVar = thirdVar; + thirdVar = *(vci++); + if (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + + return false; +} +} // end of namespace internal +} // end of namespace Set_movable_separability_2 +} // end of namespace CGAL + + + +#endif /* SET_MOVABLE_SEPARABILITY_2_INCLUDE_CGAL_SET_MOVABLE_SEPARABILITY_2_UTILS_H_ */ diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h old mode 100644 new mode 100755 index 28297d0c617..49f86e14871 --- a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -20,6 +20,7 @@ #include #include #include + namespace CGAL { namespace Set_movable_separability_2 { @@ -43,35 +44,34 @@ namespace Set_movable_separability_2 { * does not have three consecutive collinear vertices. */ template -bool -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) { - //NOT CHECKED AT ALL - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!is_any_edge_colinear(pgn)); + //NOT CHECKED AT ALL + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!is_any_edge_colinear(pgn)); - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - get_segment_outer_circle(*e_it++, poly_orientation); + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + get_segment_outer_circle(*e_it++, poly_orientation); - ++edge_index; - auto cc_in_between = traits.counterclockwise_in_between_2_object(); + ++edge_index; + auto cc_in_between = traits.counterclockwise_in_between_2_object(); - for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { - segment_outer_circle = - get_segment_outer_circle(*e_it, poly_orientation); - bool isordered = !cc_in_between(segment_outer_circle.second, - d, - segment_outer_circle.first); - if (isordered == (edge_index==i)) - { - return false; - } - } + for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { + segment_outer_circle = + get_segment_outer_circle(*e_it, poly_orientation); + bool isordered = !cc_in_between(segment_outer_circle.second, + d, + segment_outer_circle.first); + if (isordered == (edge_index==i)) + { + return false; + } + } return true; } @@ -79,8 +79,7 @@ is_pullout_direction_single_mold_translational_casting_2 /*! */ template -bool -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d) { @@ -101,55 +100,57 @@ is_pullout_direction_single_mold_translational_casting_2 * * \param[in] pgn the input polygon. * \param[in] d the pullout direction - * \return pair + * \return pair * * \pre `png` must be non-degenerate (has at least 3 vertices),simple, and * does not have three consecutive collinear vertices. */ #define MAX_SIZE_T (std::numeric_limits::max()) + template -std::pair +std::pair is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) { + //NOT CHECKED AT ALL + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!is_any_edge_colinear(pgn)); - //NOT CHECKED AT ALL - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!is_any_edge_colinear(pgn)); - - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - get_segment_outer_circle(*e_it++, poly_orientation); - ++edge_index; - auto cc_in_between = traits.counterclockwise_in_between_2_object(); - size_t top_edge= MAX_SIZE_T; - for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { - segment_outer_circle = - get_segment_outer_circle(*e_it, poly_orientation); - bool isordered = !cc_in_between(segment_outer_circle.second, - d, - segment_outer_circle.first); - if (!isordered) //unlikely - this if must be true atleast once for any polygon - add ref to paper - { - if(top_edge==MAX_SIZE_T) - { - top_edge= edge_index; - } - else - return std::make_pair(false, MAX_SIZE_T); - } - } - CGAL_postcondition(top_edge!=MAX_SIZE_T); + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + get_segment_outer_circle(*e_it++, poly_orientation); + ++edge_index; + auto cc_in_between = traits.counterclockwise_in_between_2_object(); + size_t top_edge= MAX_SIZE_T; + for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { + segment_outer_circle = + get_segment_outer_circle(*e_it, poly_orientation); + bool isordered = !cc_in_between(segment_outer_circle.second, + d, + segment_outer_circle.first); + if (!isordered) //unlikely - this if must be true atleast once for any polygon - add ref to paper + { + if(top_edge==MAX_SIZE_T) + { + top_edge= edge_index; + } + else + return std::make_pair(false, MAX_SIZE_T); + } + } + CGAL_postcondition(top_edge!=MAX_SIZE_T); return std::make_pair(true, top_edge); } /*! */ template -bool is_pullout_direction_single_mold_translational_casting_2 +std::pair +is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d) { diff --git a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h old mode 100644 new mode 100755 index 2effe20f58d..d70c1636e10 --- a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -22,58 +22,174 @@ namespace CGAL { -namespace Set_movable_separability_2 { + namespace Set_movable_separability_2 { -/*! Given a simple polygon and an edge of the polygon, this function determines - * whether a cavity (of a mold in the plane) that has the shape of the polygon - * can be used so that the polygon could be casted in the mold with the input - * edge being the top edge and then pulled out of the mold without colliding - * into the mold (but possibly sliding along the mold surface). If the polygon - * is castable this way, the function computes the closed range of pull - * directions. - * - * The type that substitutes the template parameter `%CastingTraits_2` must be - * a model of the concept `CastingTraits_2`. - * - * \param[in] pgn the input polygon. - * \param[in] i the index of an edge in pgn. - * \return a pair of elements, where the first is a Boolean that indicates - * whether the input edge is a valid top edge, and the second - * is a closed range of pull-out directions represented as a pair - * of the extreme directions in the range. If the input edge is not - * a valid top edge, the range is nondeterministic. - * - * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and - * does not have three consecutive collinear vertices. - */ -template -std::pair > -pullout_directions_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i, CastingTraits_2& traits) -{ - typedef CastingTraits_2 Casting_traits_2; - typename Casting_traits_2::Direction_2 d1, d2; - return std::make_pair(false, std::make_pair(d1, d2)); -} + /*! Same as below with the additional traits argument. + * \param[in] traits the traits to use. + * + * algorithm: + * this function implements a very simple algorithm... it just keep at any stage the current + * intersection in [firstClockwise,secondClockwise]. + * When a new semicircle appear the possible cases are as such: + * (let f:=firstClockwise, s:=secondClockwise, a:=newSemicircleFirstClockwise , b:=newSemicircleSecondClockwise) + * REMEBER THAT THIS ARE SEGMENTS ON A CIRCLE! NOT ON A LINE! + * 1. [f,s] contained in [a,b] + * f s * f s * f s * f s + * a b * a b * a b * a b + * _________________ * _________________ * _________________* _________________ + * f s * f s * f s * f s + * %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + * 2. a contained in (f,s] and b is not / or in other words / s in [a,b) and f is not in [a,b] (it is enough to ask if s is in [a,b] since fs+ab is less than 2*pi) + * f s * f s + * a b * a b + * _________________ * _________________ + * f s * fs + * %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + * 3. b contained in [f,s) and a is not / or in other words / f in (a,b] and s is not in [a,b] (it is enough to ask if f is in [a,b] since fs is shorter the ab) + * f s * f s + * a b * a b + * _________________ * _________________ + * f s * fs + * %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + * 4. no intersection between [f,s] and [a,b] / case a: or in other words / f,s are not in [a,b] + * f s * f s + * b a * b a + * _________________ * _________________ + * NO INTERSECTION! * NO INTERSECTION! (the only case in which this is possible is if (f,s) was not changes, and then (f,s) is an open arc) + * %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + * 5. Illegal cases + * f s * f s + * a b * b a + * __________________* __________________ + * THIS CASE CANT HAPPEN!! [a,b] is an semicircle, and (f,s) is a semicircle or less + */ + template + std::pair > + pullout_directions_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn, const typename CGAL::Polygon_2::Edge_const_iterator& i, CastingTraits_2& traits) + { + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!internal::is_any_edge_colinear(pgn)); + CGAL_precondition(pgn.size()>i); + CGAL::Orientation poly_orientation = pgn.orientation(); -template -std::pair > -/*! Same as above with the additional traits argument. - * \param[in] pgn the input polygon. - * \param[in] i the index of an edge in pgn. - * \param[in] traits the traits to use. - */ -pullout_directions_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i) -{ - CastingTraits_2 traits; - return pullout_directions_single_mold_translational_casting_2(pgn, i, traits); -} + typedef CastingTraits_2 Casting_traits_2; + typename Casting_traits_2::Direction_2 clockFirst, clockSecond; //the returned range is [clockFirst,clockSecond] -} // end of namespace Set_movable_separability_2 + + auto segment_outer_circle = + internal::get_segment_outer_circle(*i, poly_orientation); + clockFirst=segment_outer_circle.first; + clockSecond=segment_outer_circle.second; + //well theoretically, this is a bug since the current intersection is currently (clockFirst,clockSecond) + //and not [clockFirst,clockSecond].. but this edges will surly change since we are in a polygon + + bool isRangeSmallerThanSemicircle=false; + auto cc_in_between = traits.counterclockwise_in_between_2_object(); + + for (auto e_it = pgn.edges_begin(); e_it != pgn.edges_end(); ++e_it) { + if(e_it==i) continue; + //std::cout<<"f "<(*e_it, poly_orientation); + // std::cout<<"a "<castable this way, the function computes the closed range of pull + * directions. + * + * The type that substitutes the template parameter `%CastingTraits_2` must be + * a model of the concept `CastingTraits_2`. + * + * \param[in] pgn the input polygon. + * \param[in] i the index of an edge in pgn. + * \return a pair of elements, where the first is a Boolean that indicates + * whether the input edge is a valid top edge, and the second + * is a closed range of pull-out directions represented as a pair + * of the extreme directions in the range. If the input edge is not + * a valid top edge, the range is nondeterministic. + * a pair of Directions is build this way [firstClockwise,secondClockwise] + * + * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. + */ + template + std::pair > + pullout_directions_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn, + + const typename CGAL::Polygon_2::Edge_const_iterator& i) + { + + CastingTraits_2 traits; + return pullout_directions_single_mold_translational_casting_2(pgn, i, traits); + } + + + + } // end of namespace Set_movable_separability_2 } // end of namespace CGAL #endif diff --git a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h old mode 100644 new mode 100755 index a2c3bdb9d52..7e95756cf15 --- a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h @@ -25,127 +25,83 @@ #include #include "Set_movable_separability_2/Circle_arrangment.h" +#include "Set_movable_separability_2/Utils.h" namespace CGAL { -namespace Set_movable_separability_2 { + namespace Set_movable_separability_2 { -/* Legend: - * point = Represented as Direction_2. It is the intersection between the - * fitting Direction_2 and the unit circle - * - * Arc = Represented as A pair of point. clockwise arc between the first - * point and the second point. (each of its sides might be open or closed) - * - * SegmentOuterCircle = Arc that represent all the directions that points - * out from the polygon if it start from the - * fitting segment. This arc is always open half circle. - */ + /* Legend: + * point = Represented as Direction_2. It is the intersection between the + * fitting Direction_2 and the unit circle + * + * Arc = Represented as A pair of point. clockwise arc between the first + * point and the second point. (each of its sides might be open or closed) + * + * SegmentOuterCircle = Arc that represent all the directions that points + * out from the polygon if it start from the + * fitting segment. This arc is always open half circle. + */ -/*! \fn std::pair get_segment_outer_circle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) - * \param[in] seg the polygon segment - * \param[in] orientation the orientation of the segment (and the polygon). - * if CLOCKWISE then the outer half circle is to the left. - * \return the open outer half-circle of the edge. - */ -template -inline std::pair -get_segment_outer_circle(const typename Kernel::Segment_2 seg, - const CGAL::Orientation orientation) -{ - typename Kernel::Direction_2 forward( seg); - typename Kernel::Direction_2 backward(-forward); - return (orientation == CGAL::Orientation::CLOCKWISE) ? - std::make_pair(backward, forward) : std::make_pair(forward, backward); -} + /*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) + * \param[in] pgn the input polygon that we want to check if is castable or not. + * \param[in,out] oi the output iterator to put the top edges in + * \param[in] kernel the kernel to use. + * \return all the possible top edges of the polygon and there pullout direction + * a pair of Directions is build this way [firstClockwise,secondClockwise] + * (with no rotation) + */ + template + OutputIterator + top_edges_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn, OutputIterator oi, Kernel& kernel) + { + /* Legend + * point = Represented as Direction_2. It is the intersection between the + * fitting Direction_2 and the unit circle + * + * arc = Represented as A pair of point. clockwise arc between the first + * point and the second point. (each of its sides might be open or closed) + */ + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!internal::is_any_edge_colinear(pgn)); -template -bool is_any_edge_colinear(const CGAL::Polygon_2& pgn) -{ - typedef typename CGAL::Point_2 Point_2; - typedef typename CGAL::Polygon_2 Polygon_2; - typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; - Vertex_const_iterator vci = pgn.vertices_begin(); - Point_2 firstVar = *(vci++); - Point_2 secondVar = *(vci++); - Point_2 thirdVar = *(vci++); - for (; vci != pgn.vertices_end(); ++vci) { - firstVar = secondVar; - secondVar = thirdVar; - thirdVar = *vci; - if (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; - } - vci = pgn.vertices_begin(); - firstVar = secondVar; - secondVar = thirdVar; - thirdVar = *(vci++); - if(CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + internal::get_segment_outer_circle(*e_it++, poly_orientation); + internal::Circle_arrangment circle_arrangment(kernel, + segment_outer_circle); - firstVar = secondVar; - secondVar = thirdVar; - thirdVar = *(vci++); - if (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + ++edge_index; + for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { + segment_outer_circle = + internal::get_segment_outer_circle(*e_it, poly_orientation); + circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); + if (circle_arrangment.all_is_covered_twice()) return oi; + } + circle_arrangment.get_all_1_edges(oi); + return oi; + } - return false; -} + /*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) + * \param[in] pgn the input polygon that we want to check if is castable or not. + * \param[in,out] oi the output iterator to put the top edges in + * \return all the possible top edges of the polygon and there pullout direction + * a pair of Directions is build this way [firstClockwise,secondClockwise] + * (with no rotation) + */ + template + OutputIterator + top_edges_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn, OutputIterator oi) + { + Kernel kernel; + return top_edges_single_mold_translational_casting_2(pgn, oi, kernel); + } -/*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) - * \param[in] pgn the input polygon that we want to check if is castable or not. - * \param[in,out] oi the output iterator to put the top edges in - * \param[in] kernel the kernel to use. - * \return all the possible top edges of the polygon and there pullout direction - * (with no rotation) - */ -template -OutputIterator -top_edges_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, OutputIterator oi, Kernel& kernel) -{ - /* Legend - * point = Represented as Direction_2. It is the intersection between the - * fitting Direction_2 and the unit circle - * - * arc = Represented as A pair of point. clockwise arc between the first - * point and the second point. (each of its sides might be open or closed) - */ - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!is_any_edge_colinear(pgn)); - - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - get_segment_outer_circle(*e_it++, poly_orientation); - internal::Circle_arrangment circle_arrangment(kernel, - segment_outer_circle); - - ++edge_index; - for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { - segment_outer_circle = - get_segment_outer_circle(*e_it, poly_orientation); - circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); - if (circle_arrangment.all_is_covered_twice()) return oi; - } - circle_arrangment.get_all_1_edges(oi); - return oi; -} - -/*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) - * \param[in] pgn the input polygon that we want to check if is castable or not. - * \param[in,out] oi the output iterator to put the top edges in - * \return all the possible top edges of the polygon and there pullout direction - * (with no rotation) - */ -template -OutputIterator -top_edges_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, OutputIterator oi) -{ - Kernel kernel; - return top_edges_single_mold_translational_casting_2(pgn, oi, kernel); -} - -} // end of namespace Set_movable_separability_2 + } // end of namespace Set_movable_separability_2 } // end of namespace CGAL #endif diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp b/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp new file mode 100644 index 00000000000..ff332b4223a --- /dev/null +++ b/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef CGAL::Polygon_2 Polygon_2; +typedef Kernel::Direction_2 Direction_2; +typedef Kernel::Point_2 Point_2; + +typedef std::pair Direction_range; +typedef std::pair Top_edge; + +namespace SMS = CGAL::Set_movable_separability_2; + +struct Top_edge_comparer { + bool operator()(const Top_edge& a, const Top_edge& b) + { + auto facet_a = a.first; + const auto& d1_a = a.second.first; + const auto& d2_a = a.second.second; + auto facet_b = b.first; + const auto& d1_b = b.second.first; + const auto& d2_b = b.second.second; + + if (a.first < b.first) return true; + if (a.first > b.first) return false; + if (a.second.first < b.second.first) return true; + if (a.second.first > b.second.first) return false; + return a.second.second < b.second.second; + } +}; + +bool test_one_file(std::ifstream& inp) +{ + Polygon_2 pgn; + inp >> pgn; + // std::cout << pgn << std::endl; + + std::vector top_edges; + SMS::top_edges_single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); + + size_t exp_num_top_edges; + inp >> exp_num_top_edges; + // std::cout << "Exp. no. of top facets: " << exp_num_top_edges << std::endl; + std::vector exp_top_edges(exp_num_top_edges); + for (auto& top_edge : exp_top_edges) { + size_t facet; + Direction_2 d1, d2; + inp >> facet >> d1 >> d2; + // std::cout << facet << " " << d1 << " " << d2 << std::endl; + top_edge = std::make_pair(facet, std::make_pair(d1, d2)); + } + + std::sort(top_edges.begin(), top_edges.end(), Top_edge_comparer()); + std::sort(exp_top_edges.begin(), exp_top_edges.end(), Top_edge_comparer()); + + if (top_edges.size() != exp_top_edges.size()) { + std::cerr << "Number of facets: " + << "obtain: " << top_edges.size() + << ", expected: " << exp_top_edges.size() + << std::endl; + return false; + } + auto exp_it = exp_top_edges.begin(); + size_t i(0); + for (auto it = top_edges.begin(); it != top_edges.end(); ++it, ++exp_it) { + auto facet = it->first; + const auto& d1 = it->second.first; + const auto& d2 = it->second.second; + auto exp_facet = exp_it->first; + const auto& exp_d1 = exp_it->second.first; + const auto& exp_d2 = exp_it->second.second; + if ((facet != exp_facet) || (d1 != exp_d1) || (d2 != exp_d2)) { + std::cerr << "Top edge[" << i++ << "]: " + << "obtained: " << facet << " " << d1 << " " << d2 + << ", expected: " << exp_facet << " " << exp_d1 << " " << exp_d2 + << std::endl; + return false; + } + } + return true; +} + +int main(int argc, char* argv[]) +{ + if (argc < 2) { + std::cerr << "Missing input file" << std::endl; + return -1; + } + + int success = 0; + for (size_t i = 1; i < argc; ++i) { + std::string str(argv[i]); + if (str.empty()) continue; + + auto itr = str.end(); + --itr; + while (itr != str.begin()) { + auto tmp = itr; + --tmp; + if (!isspace(*itr)) break; + str.erase(itr); + itr = tmp; + } + if (str.size() <= 1) continue; + std::ifstream inp(str.c_str()); + if (!inp.is_open()) { + std::cerr << "Failed to open " << str << std::endl; + return -1; + } + if (! test_one_file(inp)) { + std::cout << str << ": ERROR" << std::endl; + ++success; + } + else std::cout << str << ": succeeded" << std::endl; + inp.close(); + } + + return success; +}