mirror of https://github.com/CGAL/cgal
casting_2: added pullout_direction_single_mold_translation
This commit is contained in:
parent
9f240310d8
commit
f04c83fb15
|
|
@ -4,10 +4,14 @@
|
||||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||||
#include <CGAL/Polygon_2.h>
|
#include <CGAL/Polygon_2.h>
|
||||||
#include <CGAL/top_edges_single_mold_translational_casting_2.h>
|
#include <CGAL/top_edges_single_mold_translational_casting_2.h>
|
||||||
|
#include <CGAL/pullout_directions_single_mold_translational_casting_2.h>
|
||||||
|
#include <CGAL/is_pullout_direction_single_mold_translational_casting_2.h>
|
||||||
|
|
||||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||||
typedef CGAL::Polygon_2<Kernel> Polygon_2;
|
typedef CGAL::Polygon_2<Kernel> Polygon_2;
|
||||||
typedef Kernel::Direction_2 Direction_2;
|
typedef Kernel::Direction_2 Direction_2;
|
||||||
|
typedef Kernel::Vector_2 Vector_2;
|
||||||
|
typedef Kernel::Point_2 Point_2;
|
||||||
typedef std::pair<Direction_2, Direction_2> Direction_range;
|
typedef std::pair<Direction_2, Direction_2> Direction_range;
|
||||||
typedef std::pair<size_t, Direction_range> Top_edge;
|
typedef std::pair<size_t, Direction_range> Top_edge;
|
||||||
|
|
||||||
|
|
@ -21,27 +25,78 @@ int main(int argc, char* argv[])
|
||||||
const char* filename = (argc > 1) ? argv[1] : "polygon.dat";
|
const char* filename = (argc > 1) ? argv[1] : "polygon.dat";
|
||||||
std::ifstream input_file(filename);
|
std::ifstream input_file(filename);
|
||||||
if (! input_file.is_open()) {
|
if (! input_file.is_open()) {
|
||||||
std::cerr << "Failed to open the " << filename << std::endl;
|
std::cerr << "Failed to open the " << filename << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
input_file >> pgn;
|
input_file >> pgn;
|
||||||
input_file.close();
|
input_file.close();
|
||||||
|
|
||||||
auto poly_orientation = pgn.orientation();
|
auto poly_orientation = pgn.orientation();
|
||||||
std::list<Top_edge> top_edges;
|
std::list<Top_edge> 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())
|
if (top_edges.empty())
|
||||||
std::cout << "The polygon is not castable!" << std::endl;
|
std::cout << "The polygon is not castable!" << std::endl;
|
||||||
else {
|
else {
|
||||||
std::cout << "There are " << top_edges.size() << " top edges:" << std::endl;
|
std::cout << "There are " << top_edges.size() << " top edges:" << std::endl;
|
||||||
for (const auto& top_edge : top_edges) {
|
for (const auto& top_edge : top_edges) {
|
||||||
std::cout << "Edge number: " << top_edge.first << std::endl
|
std::cout << "Edge number: " << top_edge.first << std::endl
|
||||||
<< "\tEdge: "<< pgn.edge(top_edge.first) << std::endl
|
<< "\tEdge: "<< pgn.edge(top_edge.first) << std::endl
|
||||||
<< "\tPullout directions from: "<< top_edge.second.first
|
<< "\tPullout directions from: "<< top_edge.second.first
|
||||||
<< " to " << top_edge.second.second
|
<< " to " << top_edge.second.second
|
||||||
<< std::endl<< std::endl;
|
<< 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<bool, std::pair< Kernel::Direction_2,
|
||||||
|
Kernel::Direction_2> > res = SMS::pullout_directions_single_mold_translational_casting_2(pgn,e_it);
|
||||||
|
if (res.first)
|
||||||
|
{
|
||||||
|
std::cout << "The polygon is castable using edge "<<index<<" in range " << res.second.first
|
||||||
|
<< " to " << res.second.second
|
||||||
|
<< std::endl<< std::endl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cout << "The polygon is not castable using edge "<<index<<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "-----------------------------------"<< std::endl;
|
||||||
|
//example for is_pullout_directions_single_mold_translational_casting_2 that accepts the edge
|
||||||
|
for (auto e_it = pgn.edges_begin(); e_it != pgn.edges_end(); ++e_it, ++index)
|
||||||
|
{
|
||||||
|
auto segment_outer_circle =
|
||||||
|
SMS::internal::get_segment_outer_circle<Kernel>(*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 "<<index<<" in vartical translation ("<<d<<")"<< std::endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
std::cout << "-----------------------------------"<< std::endl;
|
||||||
|
|
||||||
|
//example for is_pullout_directions_single_mold_translational_casting_2 that do not accepts the edge
|
||||||
|
{
|
||||||
|
Vector_2 v (Point_2(0,0),Point_2(1,0));
|
||||||
|
Direction_2 d(v);
|
||||||
|
std::pair<bool, size_t>
|
||||||
|
res = SMS::is_pullout_direction_single_mold_translational_casting_2(pgn,d);
|
||||||
|
if (res.first)
|
||||||
|
{
|
||||||
|
std::cout << "The polygon is castable in direction d ("<<d<<") using edge "<<res.second<<std::endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cout << "The polygon is not castable in direction d ("<<d<<")"<<std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
8
|
||||||
|
-1 0 -7 7 0 1 7 7 1 0 7 -7 0 -1 -7 -7
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
4
|
||||||
|
0 -1 1 0 1 1 0 7
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
3
|
||||||
|
0 0 1 0 1 1
|
||||||
|
|
@ -44,381 +44,381 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
namespace Set_movable_separability_2 {
|
namespace Set_movable_separability_2 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template <typename Kernel>
|
template <typename Kernel>
|
||||||
class Circle_arrangment {
|
class Circle_arrangment {
|
||||||
typedef typename Kernel::Direction_2 Point;
|
typedef typename Kernel::Direction_2 Point;
|
||||||
typedef std::pair<Point, Point> Arc;
|
typedef std::pair<Point, Point> Arc;
|
||||||
|
|
||||||
/* Legend:
|
/* Legend:
|
||||||
* Point = Represented as Direction_2. It is the intersection between the
|
* Point = Represented as Direction_2. It is the intersection between the
|
||||||
* fitting Direction_2 and the unit circle
|
* fitting Direction_2 and the unit circle
|
||||||
*
|
*
|
||||||
* Arc = Represented as a pair of points. clockwise arc between the first
|
* 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)
|
* 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)
|
/*! \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
|
* Checks whether an open epsilon area clockwise/counterclockwise from a point
|
||||||
* p is contained in an arc s.
|
* p is contained in an arc s.
|
||||||
* \param[in] p a point .
|
* \param[in] p a point .
|
||||||
* \param[in] is_counterclockwise true: we care about the counterclockwise
|
* \param[in] is_counterclockwise true: we care about the counterclockwise
|
||||||
* epsilon area of p. false: same with clockwise
|
* epsilon area of p. false: same with clockwise
|
||||||
* \param[in] A an Arc that should contain the epsilon area
|
* \param[in] A an Arc that should contain the epsilon area
|
||||||
*/
|
*/
|
||||||
bool is_open_direction_contained_in_arc(const Point p,
|
bool is_open_direction_contained_in_arc(const Point p,
|
||||||
const bool is_counterclockwise,
|
const bool is_counterclockwise,
|
||||||
const Arc A) const
|
const Arc A) const
|
||||||
{
|
{
|
||||||
if ((is_counterclockwise && (p == A.second)) ||
|
if ((is_counterclockwise && (p == A.second)) ||
|
||||||
(!is_counterclockwise && (p == A.first)))
|
(!is_counterclockwise && (p == A.first)))
|
||||||
return false;
|
return false;
|
||||||
auto cc_in_between = m_kernel.counterclockwise_in_between_2_object();
|
auto cc_in_between = m_kernel.counterclockwise_in_between_2_object();
|
||||||
return !cc_in_between(p, A.first, A.second);
|
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)
|
/*! \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
|
* \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_start_closed - do A contains its start point (clockwise)
|
||||||
* \param[in] is_a_end_closed - do A contains its end point (clockwise)
|
* \param[in] is_a_end_closed - do A contains its end point (clockwise)
|
||||||
* \param[in] A - an arc
|
* \param[in] A - an arc
|
||||||
* \param[in] B - an *open* arc
|
* \param[in] B - an *open* arc
|
||||||
*/
|
*/
|
||||||
bool is_a_contained_in_b(const bool is_a_start_closed,
|
bool is_a_contained_in_b(const bool is_a_start_closed,
|
||||||
const bool is_a_end_closed,
|
const bool is_a_end_closed,
|
||||||
const Arc A,const Arc B) const
|
const Arc A,const Arc B) const
|
||||||
{
|
{
|
||||||
//A is closed, B is open and they share an vertex -> A not contained in B
|
//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)) ||
|
if ((is_a_start_closed &&(A.first == B.first)) ||
|
||||||
(is_a_end_closed && (A.second == B.second)))
|
(is_a_end_closed && (A.second == B.second)))
|
||||||
return false;
|
return false;
|
||||||
if ((A.first == B.second) || (B.first == A.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();
|
auto cc_in_between = m_kernel.counterclockwise_in_between_2_object();
|
||||||
return (!cc_in_between(A.first, B.first, B.second) &&
|
return (!cc_in_between(A.first, B.first, B.second) &&
|
||||||
!cc_in_between(A.second, B.first, B.second) &&
|
!cc_in_between(A.second, B.first, B.second) &&
|
||||||
!cc_in_between(A.first, B.first, A.second));
|
!cc_in_between(A.first, B.first, A.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \Circle_arrangment_edge
|
/*! \Circle_arrangment_edge
|
||||||
* This class represents a cells (a point or an arc) of depth 0,1,2+ in the
|
* 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
|
* Circle_arrangment where depth the number of inserted open half-circles
|
||||||
* inserted that cover this cell
|
* inserted that cover this cell
|
||||||
* This edge (cell) is described by the first point of the edge (clockwise).
|
* This edge (cell) is described by the first point of the edge (clockwise).
|
||||||
* The last point can be deduced by the next instance of
|
* The last point can be deduced by the next instance of
|
||||||
* Circle_arrangment_edge in the list in Circle_arrangment
|
* Circle_arrangment_edge in the list in Circle_arrangment
|
||||||
* this class also keeps the cell depth.
|
* this class also keeps the cell depth.
|
||||||
*/
|
*/
|
||||||
class Circle_arrangment_edge {
|
class Circle_arrangment_edge {
|
||||||
public:
|
public:
|
||||||
bool m_start_is_closed;
|
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
|
size_t m_edge_index; // the index of the polygon edge the open
|
||||||
// half-circle of which covers this cell.
|
// half-circle of which covers this cell.
|
||||||
// only relevant if m_count ==1
|
// 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)
|
/*! \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
|
* 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_start_angle the first point of the arc (clockwise)
|
||||||
* \param[in] edge_index the index of the polygon edge who's open
|
* \param[in] edge_index the index of the polygon edge who's open
|
||||||
* half-circle covers this cell - only relevant if m_count == 1
|
* half-circle covers this cell - only relevant if m_count == 1
|
||||||
* \param[in] start_is_closed - is the point edge_start_angle contained in
|
* \param[in] start_is_closed - is the point edge_start_angle contained in
|
||||||
* this cell
|
* this cell
|
||||||
* \param[in] set_count_to_one to set the m_count to one (or zero if this
|
* \param[in] set_count_to_one to set the m_count to one (or zero if this
|
||||||
* var is false)
|
* var is false)
|
||||||
*/
|
*/
|
||||||
Circle_arrangment_edge(const Point edge_start_angle,
|
Circle_arrangment_edge(const Point edge_start_angle,
|
||||||
const size_t edge_index,
|
const size_t edge_index,
|
||||||
const bool start_is_closed,
|
const bool start_is_closed,
|
||||||
const bool set_count_to_one = true)
|
const bool set_count_to_one = true)
|
||||||
{
|
{
|
||||||
this->m_start_is_closed = start_is_closed;
|
this->m_start_is_closed = start_is_closed;
|
||||||
this->m_edge_start_angle = edge_start_angle;
|
this->m_edge_start_angle = edge_start_angle;
|
||||||
this->m_count = (int) set_count_to_one;
|
this->m_count = (int) set_count_to_one;
|
||||||
this->m_edge_index = edge_index;
|
this->m_edge_index = edge_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \fn void plusplus(size_t edge_index)
|
/*! \fn void plusplus(size_t edge_index)
|
||||||
* Adds new polygon edge who's open half-circle covers this cell
|
* Adds new polygon edge who's open half-circle covers this cell
|
||||||
* \param[in] edge_index - the index of this edge
|
* \param[in] edge_index - the index of this edge
|
||||||
* increase the edge m_count by one (if it is 2+, it will stay 2+)
|
* 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
|
* 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)
|
* before. (only relevant if now m_count == 1)
|
||||||
*/
|
*/
|
||||||
void plusplus(const size_t edge_index)
|
void plusplus(const size_t edge_index)
|
||||||
{
|
{
|
||||||
if (this->m_count ==0) {
|
if (this->m_count ==0) {
|
||||||
this->m_edge_index = edge_index;
|
this->m_edge_index = edge_index;
|
||||||
this->m_count = 1;
|
this->m_count = 1;
|
||||||
}
|
}
|
||||||
else if(this->m_count ==1) this->m_count = 2;
|
else if(this->m_count ==1) this->m_count = 2;
|
||||||
}
|
}
|
||||||
bool is_covered() { return m_count == 2; }
|
bool is_covered() { return m_count == 2; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef typename std::list<struct Circle_arrangment_edge> Circle_edges;
|
typedef typename std::list<struct Circle_arrangment_edge> Circle_edges;
|
||||||
|
|
||||||
//! The kernel to use.
|
//! The kernel to use.
|
||||||
const Kernel& m_kernel;
|
const Kernel& m_kernel;
|
||||||
|
|
||||||
Circle_edges m_edges;
|
Circle_edges m_edges;
|
||||||
|
|
||||||
/*! \fn void insert_if_legal(const Circle_edge_iterator cur_it,
|
/*! \fn void insert_if_legal(const Circle_edge_iterator cur_it,
|
||||||
* const Circle_edge_iterator next_it,
|
* const Circle_edge_iterator next_it,
|
||||||
* const struct Circle_arrangment_edge &edge)
|
* const struct Circle_arrangment_edge &edge)
|
||||||
* Adds new edge to the arrangement if it won't create some empty edges
|
* 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
|
* \param[in] cur_it iterator to the edge before where the new edge should be
|
||||||
* inserted
|
* inserted
|
||||||
* \param[in] next_it iterator to the edge after where the new edge should be
|
* \param[in] next_it iterator to the edge after where the new edge should be
|
||||||
* inserted
|
* inserted
|
||||||
* \param[in] edge the new edge that 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.
|
* 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.
|
* But it was easier for me to just send it as well.
|
||||||
*/
|
*/
|
||||||
template <typename InputIterator>
|
template <typename InputIterator>
|
||||||
void insert_if_legal(const InputIterator cur_it,
|
void insert_if_legal(const InputIterator cur_it,
|
||||||
InputIterator next_it,
|
InputIterator next_it,
|
||||||
const struct Circle_arrangment_edge& edge)
|
const struct Circle_arrangment_edge& edge)
|
||||||
{
|
{
|
||||||
if (((edge.m_start_is_closed && !next_it->m_start_is_closed) ||
|
if (((edge.m_start_is_closed && !next_it->m_start_is_closed) ||
|
||||||
(edge.m_edge_start_angle != next_it->m_edge_start_angle)) &&
|
(edge.m_edge_start_angle != next_it->m_edge_start_angle)) &&
|
||||||
((cur_it->m_start_is_closed && !edge.m_start_is_closed) ||
|
((cur_it->m_start_is_closed && !edge.m_start_is_closed) ||
|
||||||
(edge.m_edge_start_angle != cur_it->m_edge_start_angle)))
|
(edge.m_edge_start_angle != cur_it->m_edge_start_angle)))
|
||||||
{
|
{
|
||||||
m_edges.insert(next_it, edge);
|
m_edges.insert(next_it, edge);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \fn void merge_adjacent_2_edges_and_remove_empty()
|
/*! \fn void merge_adjacent_2_edges_and_remove_empty()
|
||||||
* \brief merge all the arcs that are adjacent and of depth 2+
|
* \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.
|
* it doesn't merge the first and last ones since it is easier this way.
|
||||||
*/
|
*/
|
||||||
void merge_adjacent_2_edges_and_remove_empty()
|
void merge_adjacent_2_edges_and_remove_empty()
|
||||||
{
|
{
|
||||||
bool in_two_edge(false);
|
bool in_two_edge(false);
|
||||||
for (auto it = m_edges.begin(); it != m_edges.end();) {
|
for (auto it = m_edges.begin(); it != m_edges.end();) {
|
||||||
if (it->is_covered()) {
|
if (it->is_covered()) {
|
||||||
if (in_two_edge) {
|
if (in_two_edge) {
|
||||||
it = m_edges.erase(it);
|
it = m_edges.erase(it);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
in_two_edge = true;
|
in_two_edge = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
in_two_edge = false;
|
in_two_edge = false;
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*! \ctor Circle_arrangment(arc first_segment_outer_circle)
|
/*! \ctor Circle_arrangment(arc first_segment_outer_circle)
|
||||||
* Creates an arrangement on circle with two edges the one covered by
|
* Creates an arrangement on circle with two edges the one covered by
|
||||||
* first_segment_outer_circle and the other one
|
* first_segment_outer_circle and the other one
|
||||||
* \param[in] first_segment_outer_circle the outer circle of the first segment
|
* \param[in] first_segment_outer_circle the outer circle of the first segment
|
||||||
* of the polygon.
|
* of the polygon.
|
||||||
* Notice that you might consider implementing the ctor as an full circle of
|
* 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
|
* 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 is a single arc, so I choose this implementation.
|
||||||
*/
|
*/
|
||||||
Circle_arrangment(const Kernel& kernel, const Arc first_segment_outer_circle) :
|
Circle_arrangment(const Kernel& kernel, const Arc first_segment_outer_circle) :
|
||||||
m_kernel(kernel)
|
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))
|
|
||||||
{
|
{
|
||||||
it->plusplus(edge_index);
|
m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first,
|
||||||
continue;
|
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,
|
/*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index)
|
||||||
edge);
|
* Updates the arrangement in respect to a new segment outer open circle
|
||||||
bool is_end_contained =
|
* \param[in] segment_outer_circle - the outer circle of the current segment of
|
||||||
is_open_direction_contained_in_arc(segment_outer_circle.second, false,
|
* the polygon.
|
||||||
edge);
|
* \param[in] edge_index this segment id
|
||||||
// o~~~~~~~~~~~~o = new arc
|
* This is the main funtion of this code. It separates the cells in which the
|
||||||
// ?------------? = "old" arc (the edge from the array)
|
* endpoints of the new arc is contained to two parts and increase m_count
|
||||||
if (is_start_contained) {
|
* for all the cells that the new arc covers. In the end the function
|
||||||
if (is_end_contained) {
|
* merge_adjacent_2_edges_and_remove_empty is called to remove redundant cells
|
||||||
auto cc_in_between = m_kernel.counterclockwise_in_between_2_object();
|
*/
|
||||||
bool isordered = !cc_in_between(segment_outer_circle.second,
|
void add_segment_outer_circle(const Arc segment_outer_circle,
|
||||||
segment_outer_circle.first,
|
const size_t edge_index)
|
||||||
edge.second);
|
{
|
||||||
if (isordered) {
|
Arc edge;
|
||||||
// o~~~~~~~~~~~~o
|
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;
|
||||||
// ?----c
|
//edge.second ;
|
||||||
// o~-~-~-~-~-~-o
|
auto next_it = m_edges.begin();
|
||||||
// c-----?
|
auto it = m_edges.begin();
|
||||||
struct Circle_arrangment_edge edge2 = *it;
|
bool done = false;
|
||||||
edge2.m_start_is_closed = false;
|
while (!done) {
|
||||||
edge2.m_edge_start_angle = segment_outer_circle.first;
|
it = next_it;
|
||||||
edge2.plusplus(edge_index);
|
next_it = it;
|
||||||
this->insert_if_legal(it, next_it, edge2);
|
++next_it;
|
||||||
struct Circle_arrangment_edge edge3 = *it;
|
if (next_it == m_edges.end()) {
|
||||||
edge3.m_start_is_closed = true;
|
done = true;
|
||||||
edge3.m_edge_start_angle = segment_outer_circle.second;
|
next_it = m_edges.begin();
|
||||||
this->insert_if_legal(it,next_it,edge3);
|
}
|
||||||
}
|
|
||||||
else {
|
is_start_closed_segment =it->m_start_is_closed;
|
||||||
// ...~~~~~~~~~o o~~~~~~~~~~... (round)
|
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;
|
||||||
// ?~-~o
|
|
||||||
// c---c
|
if (it->m_count == 2) continue;
|
||||||
// o-~-?
|
if (is_a_contained_in_b(is_start_closed_segment, is_end_closed_segment,
|
||||||
struct Circle_arrangment_edge edge2 = *it;
|
edge, segment_outer_circle))
|
||||||
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);
|
continue;
|
||||||
struct Circle_arrangment_edge edge3 = *it;
|
}
|
||||||
edge3.m_start_is_closed = false;
|
bool is_start_contained =
|
||||||
edge3.m_edge_start_angle = segment_outer_circle.first;
|
is_open_direction_contained_in_arc(segment_outer_circle.first, true,
|
||||||
edge3.plusplus(edge_index);
|
edge);
|
||||||
this->insert_if_legal(it, next_it, edge3);
|
bool is_end_contained =
|
||||||
it->plusplus(edge_index);
|
is_open_direction_contained_in_arc(segment_outer_circle.second, false,
|
||||||
}
|
edge);
|
||||||
}
|
// o~~~~~~~~~~~~o = new arc
|
||||||
else {
|
// ?------------? = "old" arc (the edge from the array)
|
||||||
// o~~~~~~~~~~~~o
|
if (is_start_contained) {
|
||||||
// ?-----------?
|
if (is_end_contained) {
|
||||||
//_____________________
|
auto cc_in_between = m_kernel.counterclockwise_in_between_2_object();
|
||||||
// ?----c
|
bool isordered = !cc_in_between(segment_outer_circle.second,
|
||||||
// o-~-~-~?
|
segment_outer_circle.first,
|
||||||
struct Circle_arrangment_edge edge2 = *it;
|
edge.second);
|
||||||
edge2.m_start_is_closed = false;
|
if (isordered) {
|
||||||
edge2.m_edge_start_angle = segment_outer_circle.first;
|
// o~~~~~~~~~~~~o
|
||||||
edge2.plusplus(edge_index);
|
// ?-----------------------?
|
||||||
this->insert_if_legal(it, next_it, edge2);
|
// __________________________
|
||||||
}
|
// ?----c
|
||||||
}
|
// o~-~-~-~-~-~-o
|
||||||
else {
|
// c-----?
|
||||||
if (is_end_contained) {
|
struct Circle_arrangment_edge edge2 = *it;
|
||||||
// o~~~~~~~~~~~~o
|
edge2.m_start_is_closed = false;
|
||||||
// ?------------?
|
edge2.m_edge_start_angle = segment_outer_circle.first;
|
||||||
//_____________________
|
edge2.plusplus(edge_index);
|
||||||
// ?-~-~-~-o
|
this->insert_if_legal(it, next_it, edge2);
|
||||||
// c----?
|
struct Circle_arrangment_edge edge3 = *it;
|
||||||
struct Circle_arrangment_edge edge2 = *it;
|
edge3.m_start_is_closed = true;
|
||||||
edge2.m_start_is_closed = true;
|
edge3.m_edge_start_angle = segment_outer_circle.second;
|
||||||
edge2.m_edge_start_angle = segment_outer_circle.second;
|
this->insert_if_legal(it,next_it,edge3);
|
||||||
it->plusplus(edge_index);
|
}
|
||||||
this->insert_if_legal(it, next_it, edge2);
|
else {
|
||||||
}
|
// ...~~~~~~~~~o o~~~~~~~~~~... (round)
|
||||||
//else - no intersection, do noting
|
// ?-----------?
|
||||||
}
|
// __________________________
|
||||||
}
|
// ?~-~o
|
||||||
merge_adjacent_2_edges_and_remove_empty();
|
// 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
|
#if 0
|
||||||
// debug function
|
// debug function
|
||||||
void printArrangement()
|
void printArrangement()
|
||||||
{
|
{
|
||||||
for (auto it = m_edges.begin(); it != m_edges.end(); ++it) {
|
for (auto it = m_edges.begin(); it != m_edges.end(); ++it) {
|
||||||
if (it->m_start_is_closed) std::cout<<")[";
|
if (it->m_start_is_closed) std::cout<<")[";
|
||||||
else std::cout << "](";
|
else std::cout << "](";
|
||||||
std::cout << it->m_edge_start_angle;
|
std::cout << it->m_edge_start_angle;
|
||||||
std::cout << ","<<(int)it->m_count;
|
std::cout << ","<<(int)it->m_count;
|
||||||
}
|
}
|
||||||
std::cout << "\n\n";
|
std::cout << "\n\n";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*! \fn void get_all_1_edges(OutputIterator 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
|
* Insert to oi all the cells in depth 1 i.e. the cells that represent legal
|
||||||
* pullout directions
|
* pullout directions
|
||||||
* \param[in, out] oi the output iterator to put the cells in
|
* \param[in, out] oi the output iterator to put the cells in
|
||||||
* Puts in oi var of type pair<size_t, std::pair<Kernel::Direction_2,
|
* Puts in oi var of type pair<size_t, std::pair<Kernel::Direction_2,
|
||||||
* Kernel::Direction_2 > > foreach valid top edge.
|
* Kernel::Direction_2 > > foreach valid top edge.
|
||||||
* Should only be called after all of the polygon edges where inserted.
|
* Should only be called after all of the polygon edges where inserted.
|
||||||
*/
|
*/
|
||||||
template <typename OutputIterator>
|
template <typename OutputIterator>
|
||||||
OutputIterator get_all_1_edges(OutputIterator oi)
|
OutputIterator get_all_1_edges(OutputIterator oi)
|
||||||
{
|
{
|
||||||
for (auto it = m_edges.begin(); it != m_edges.end();) {
|
for (auto it = m_edges.begin(); it != m_edges.end();) {
|
||||||
if ((*it).m_count == 1) {
|
if ((*it).m_count == 1) {
|
||||||
std::pair<size_t, Arc> edge;
|
std::pair<size_t, Arc> edge;
|
||||||
edge.first = (*it).m_edge_index;
|
edge.first = (*it).m_edge_index;
|
||||||
edge.second.first = (*it).m_edge_start_angle;
|
edge.second.first = (*it).m_edge_start_angle;
|
||||||
++it;
|
++it;
|
||||||
edge.second.second =
|
edge.second.second =
|
||||||
(*((it == m_edges.end()) ? m_edges.begin() : (it))).m_edge_start_angle;
|
(*((it == m_edges.end()) ? m_edges.begin() : (it))).m_edge_start_angle;
|
||||||
*oi++ = edge;
|
*oi++ = edge;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return oi;
|
return oi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \fn bool all_is_covered_twice()
|
/*! \fn bool all_is_covered_twice()
|
||||||
* Before running this run merge_adjacent_2_edges_and_remove_empty() or
|
* Before running this run merge_adjacent_2_edges_and_remove_empty() or
|
||||||
* add_segment_outer_circle() which calls
|
* add_segment_outer_circle() which calls
|
||||||
* merge_adjacent_2_edges_and_remove_empty().
|
* merge_adjacent_2_edges_and_remove_empty().
|
||||||
*
|
*
|
||||||
* The funtions checks that the whole circle is a single cell, which can
|
* 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
|
* happen only if this cell is of depth 2, so there is no need to check the
|
||||||
* depth as well.
|
* depth as well.
|
||||||
* \return if all of the arrangement is in depth 2+
|
* \return if all of the arrangement is in depth 2+
|
||||||
*/
|
*/
|
||||||
bool all_is_covered_twice() { return m_edges.size() == 1; }
|
bool all_is_covered_twice() { return m_edges.size() == 1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of namespace internal
|
} // end of namespace internal
|
||||||
} // end of namespace Set_movable_separability_2
|
} // end of namespace Set_movable_separability_2
|
||||||
} // end of namespace CGAL
|
} // end of namespace CGAL
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -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 <CGAL/enum.h>
|
||||||
|
#include <CGAL/Polygon_2.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace CGAL {
|
||||||
|
namespace Set_movable_separability_2 {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
/*! \fn std::pair<typename Kernel::Direction_2,typename Kernel::Direction_2> 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 <typename Kernel>
|
||||||
|
inline std::pair<typename Kernel::Direction_2, typename Kernel::Direction_2>
|
||||||
|
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 <typename Kernel>
|
||||||
|
bool is_any_edge_colinear(const CGAL::Polygon_2<Kernel>& pgn)
|
||||||
|
{
|
||||||
|
typedef typename CGAL::Point_2<Kernel> Point_2;
|
||||||
|
typedef typename CGAL::Polygon_2<Kernel> 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_ */
|
||||||
115
Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h
Normal file → Executable file
115
Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h
Normal file → Executable file
|
|
@ -20,6 +20,7 @@
|
||||||
#include <CGAL/Polygon_2.h>
|
#include <CGAL/Polygon_2.h>
|
||||||
#include <CGAL/enum.h>
|
#include <CGAL/enum.h>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
namespace Set_movable_separability_2 {
|
namespace Set_movable_separability_2 {
|
||||||
|
|
@ -43,35 +44,34 @@ namespace Set_movable_separability_2 {
|
||||||
* does not have three consecutive collinear vertices.
|
* does not have three consecutive collinear vertices.
|
||||||
*/
|
*/
|
||||||
template <typename CastingTraits_2>
|
template <typename CastingTraits_2>
|
||||||
bool
|
bool is_pullout_direction_single_mold_translational_casting_2
|
||||||
is_pullout_direction_single_mold_translational_casting_2
|
|
||||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn, size_t i,
|
(const CGAL::Polygon_2<CastingTraits_2>& pgn, size_t i,
|
||||||
typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits)
|
typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits)
|
||||||
{
|
{
|
||||||
//NOT CHECKED AT ALL
|
//NOT CHECKED AT ALL
|
||||||
CGAL_precondition(pgn.is_simple());
|
CGAL_precondition(pgn.is_simple());
|
||||||
CGAL_precondition(!is_any_edge_colinear(pgn));
|
CGAL_precondition(!is_any_edge_colinear(pgn));
|
||||||
|
|
||||||
auto e_it = pgn.edges_begin();
|
auto e_it = pgn.edges_begin();
|
||||||
size_t edge_index = 0;
|
size_t edge_index = 0;
|
||||||
CGAL::Orientation poly_orientation = pgn.orientation();
|
CGAL::Orientation poly_orientation = pgn.orientation();
|
||||||
auto segment_outer_circle =
|
auto segment_outer_circle =
|
||||||
get_segment_outer_circle<CastingTraits_2>(*e_it++, poly_orientation);
|
get_segment_outer_circle<CastingTraits_2>(*e_it++, poly_orientation);
|
||||||
|
|
||||||
++edge_index;
|
++edge_index;
|
||||||
auto cc_in_between = traits.counterclockwise_in_between_2_object();
|
auto cc_in_between = traits.counterclockwise_in_between_2_object();
|
||||||
|
|
||||||
for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) {
|
for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) {
|
||||||
segment_outer_circle =
|
segment_outer_circle =
|
||||||
get_segment_outer_circle<CastingTraits_2>(*e_it, poly_orientation);
|
get_segment_outer_circle<CastingTraits_2>(*e_it, poly_orientation);
|
||||||
bool isordered = !cc_in_between(segment_outer_circle.second,
|
bool isordered = !cc_in_between(segment_outer_circle.second,
|
||||||
d,
|
d,
|
||||||
segment_outer_circle.first);
|
segment_outer_circle.first);
|
||||||
if (isordered == (edge_index==i))
|
if (isordered == (edge_index==i))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -79,8 +79,7 @@ is_pullout_direction_single_mold_translational_casting_2
|
||||||
/*!
|
/*!
|
||||||
*/
|
*/
|
||||||
template <typename CastingTraits_2>
|
template <typename CastingTraits_2>
|
||||||
bool
|
bool is_pullout_direction_single_mold_translational_casting_2
|
||||||
is_pullout_direction_single_mold_translational_casting_2
|
|
||||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn, size_t i,
|
(const CGAL::Polygon_2<CastingTraits_2>& pgn, size_t i,
|
||||||
typename CastingTraits_2::Direction_2& d)
|
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] pgn the input polygon.
|
||||||
* \param[in] d the pullout direction
|
* \param[in] d the pullout direction
|
||||||
* \return pair<if the polygon can be pullout through some edge with direction d, the edge if the first part is true, else nondeterministic>
|
* \return pair<if the polygon can be pullout through some edge with direction
|
||||||
|
* d, the edge if the first part is true, else nondeterministic>
|
||||||
*
|
*
|
||||||
* \pre `png` must be non-degenerate (has at least 3 vertices),simple, and
|
* \pre `png` must be non-degenerate (has at least 3 vertices),simple, and
|
||||||
* does not have three consecutive collinear vertices.
|
* does not have three consecutive collinear vertices.
|
||||||
*/
|
*/
|
||||||
#define MAX_SIZE_T (std::numeric_limits<size_t>::max())
|
#define MAX_SIZE_T (std::numeric_limits<size_t>::max())
|
||||||
|
|
||||||
template <typename CastingTraits_2>
|
template <typename CastingTraits_2>
|
||||||
std::pair<bool,size_t>
|
std::pair<bool, size_t>
|
||||||
is_pullout_direction_single_mold_translational_casting_2
|
is_pullout_direction_single_mold_translational_casting_2
|
||||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||||
typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits)
|
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
|
auto e_it = pgn.edges_begin();
|
||||||
CGAL_precondition(pgn.is_simple());
|
size_t edge_index = 0;
|
||||||
CGAL_precondition(!is_any_edge_colinear(pgn));
|
CGAL::Orientation poly_orientation = pgn.orientation();
|
||||||
|
auto segment_outer_circle =
|
||||||
auto e_it = pgn.edges_begin();
|
get_segment_outer_circle<CastingTraits_2>(*e_it++, poly_orientation);
|
||||||
size_t edge_index = 0;
|
++edge_index;
|
||||||
CGAL::Orientation poly_orientation = pgn.orientation();
|
auto cc_in_between = traits.counterclockwise_in_between_2_object();
|
||||||
auto segment_outer_circle =
|
size_t top_edge= MAX_SIZE_T;
|
||||||
get_segment_outer_circle<CastingTraits_2>(*e_it++, poly_orientation);
|
for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) {
|
||||||
++edge_index;
|
segment_outer_circle =
|
||||||
auto cc_in_between = traits.counterclockwise_in_between_2_object();
|
get_segment_outer_circle<CastingTraits_2>(*e_it, poly_orientation);
|
||||||
size_t top_edge= MAX_SIZE_T;
|
bool isordered = !cc_in_between(segment_outer_circle.second,
|
||||||
for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) {
|
d,
|
||||||
segment_outer_circle =
|
segment_outer_circle.first);
|
||||||
get_segment_outer_circle<CastingTraits_2>(*e_it, poly_orientation);
|
if (!isordered) //unlikely - this if must be true atleast once for any polygon - add ref to paper
|
||||||
bool isordered = !cc_in_between(segment_outer_circle.second,
|
{
|
||||||
d,
|
if(top_edge==MAX_SIZE_T)
|
||||||
segment_outer_circle.first);
|
{
|
||||||
if (!isordered) //unlikely - this if must be true atleast once for any polygon - add ref to paper
|
top_edge= edge_index;
|
||||||
{
|
}
|
||||||
if(top_edge==MAX_SIZE_T)
|
else
|
||||||
{
|
return std::make_pair(false, MAX_SIZE_T);
|
||||||
top_edge= edge_index;
|
}
|
||||||
}
|
}
|
||||||
else
|
CGAL_postcondition(top_edge!=MAX_SIZE_T);
|
||||||
return std::make_pair(false, MAX_SIZE_T);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CGAL_postcondition(top_edge!=MAX_SIZE_T);
|
|
||||||
return std::make_pair(true, top_edge);
|
return std::make_pair(true, top_edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
*/
|
*/
|
||||||
template <typename CastingTraits_2>
|
template <typename CastingTraits_2>
|
||||||
bool is_pullout_direction_single_mold_translational_casting_2
|
std::pair<bool, size_t>
|
||||||
|
is_pullout_direction_single_mold_translational_casting_2
|
||||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn, size_t i,
|
(const CGAL::Polygon_2<CastingTraits_2>& pgn, size_t i,
|
||||||
typename CastingTraits_2::Direction_2& d)
|
typename CastingTraits_2::Direction_2& d)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
212
Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h
Normal file → Executable file
212
Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h
Normal file → Executable file
|
|
@ -22,58 +22,174 @@
|
||||||
|
|
||||||
namespace CGAL {
|
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 <em>castable</em> 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 <typename CastingTraits_2>
|
|
||||||
std::pair<bool, std::pair<typename CastingTraits_2::Direction_2,
|
|
||||||
typename CastingTraits_2::Direction_2> >
|
|
||||||
pullout_directions_single_mold_translational_casting_2
|
|
||||||
(const CGAL::Polygon_2<CastingTraits_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 <typename CastingTraits_2>
|
||||||
|
std::pair<bool, std::pair<typename CastingTraits_2::Direction_2,
|
||||||
|
typename CastingTraits_2::Direction_2> >
|
||||||
|
pullout_directions_single_mold_translational_casting_2
|
||||||
|
(const CGAL::Polygon_2<CastingTraits_2>& pgn, const typename CGAL::Polygon_2<CastingTraits_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 <typename CastingTraits_2>
|
typedef CastingTraits_2 Casting_traits_2;
|
||||||
std::pair<bool, std::pair<typename CastingTraits_2::Direction_2,
|
typename Casting_traits_2::Direction_2 clockFirst, clockSecond; //the returned range is [clockFirst,clockSecond]
|
||||||
typename CastingTraits_2::Direction_2> >
|
|
||||||
/*! 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<CastingTraits_2>& pgn, size_t i)
|
|
||||||
{
|
|
||||||
CastingTraits_2 traits;
|
|
||||||
return pullout_directions_single_mold_translational_casting_2(pgn, i, traits);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end of namespace Set_movable_separability_2
|
|
||||||
|
auto segment_outer_circle =
|
||||||
|
internal::get_segment_outer_circle<Casting_traits_2>(*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 "<<clockFirst<<" s "<<clockSecond<<std::endl;
|
||||||
|
auto segment_outer_circle =
|
||||||
|
internal::get_segment_outer_circle<Casting_traits_2>(*e_it, poly_orientation);
|
||||||
|
// std::cout<<"a "<<segment_outer_circle.second<<" b "<<segment_outer_circle.first<<std::endl;
|
||||||
|
|
||||||
|
//notice that we are interested in the segment_inner_circle (segment_outer_circle.second,segment_outer_circle.first)
|
||||||
|
if(!isRangeSmallerThanSemicircle)
|
||||||
|
{
|
||||||
|
if(segment_outer_circle.first==clockSecond && segment_outer_circle.second == clockFirst)
|
||||||
|
{
|
||||||
|
// std::cout<<"case 1b"<<std::endl<<std::endl;
|
||||||
|
|
||||||
|
// the arc is the range case 1b
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(segment_outer_circle.first==clockFirst&& segment_outer_circle.second ==clockSecond )
|
||||||
|
{
|
||||||
|
// std::cout<<"case 4b"<<std::endl<<std::endl;
|
||||||
|
|
||||||
|
// the arc the opposite of the range case 4b
|
||||||
|
return std::make_pair(false, std::make_pair(clockFirst, clockSecond));
|
||||||
|
}
|
||||||
|
isRangeSmallerThanSemicircle=true;
|
||||||
|
}
|
||||||
|
bool fBetweenAB = !cc_in_between(clockFirst,segment_outer_circle.second,segment_outer_circle.first);
|
||||||
|
//is true if segment_outer_circle \in [first,clockFirst,clockSecond]
|
||||||
|
bool sBetweenAB = !cc_in_between(clockSecond,segment_outer_circle.second,segment_outer_circle.first);
|
||||||
|
//is true if segment_outer_circle \in [first,clockFirst,clockSecond]
|
||||||
|
if (fBetweenAB && sBetweenAB)
|
||||||
|
{
|
||||||
|
// std::cout<<"case 1"<<std::endl<<std::endl;
|
||||||
|
|
||||||
|
//case 1 //surly not case 4b since [f,s] is less then a semicircle
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!fBetweenAB && sBetweenAB)
|
||||||
|
{
|
||||||
|
// std::cout<<"case 2"<<std::endl<<std::endl;
|
||||||
|
|
||||||
|
//case 2 - return a,s
|
||||||
|
clockFirst = segment_outer_circle.second;
|
||||||
|
}
|
||||||
|
else if(fBetweenAB && !sBetweenAB)
|
||||||
|
{
|
||||||
|
// std::cout<<"case 3"<<std::endl<<std::endl;
|
||||||
|
|
||||||
|
//case 3 - return f,b
|
||||||
|
clockSecond = segment_outer_circle.first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// std::cout<<"case 4a"<<std::endl<<std::endl;
|
||||||
|
|
||||||
|
//case 4a
|
||||||
|
return std::make_pair(false, std::make_pair(clockFirst, clockSecond));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(true, std::make_pair(clockFirst, clockSecond));
|
||||||
|
}
|
||||||
|
/*! 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 <em>castable</em> 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 <typename CastingTraits_2>
|
||||||
|
std::pair<bool, std::pair<typename CastingTraits_2::Direction_2,
|
||||||
|
typename CastingTraits_2::Direction_2> >
|
||||||
|
pullout_directions_single_mold_translational_casting_2
|
||||||
|
(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||||
|
|
||||||
|
const typename CGAL::Polygon_2<CastingTraits_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
|
} // end of namespace CGAL
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
180
Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h
Normal file → Executable file
180
Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h
Normal file → Executable file
|
|
@ -25,127 +25,83 @@
|
||||||
#include <CGAL/enum.h>
|
#include <CGAL/enum.h>
|
||||||
|
|
||||||
#include "Set_movable_separability_2/Circle_arrangment.h"
|
#include "Set_movable_separability_2/Circle_arrangment.h"
|
||||||
|
#include "Set_movable_separability_2/Utils.h"
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
namespace Set_movable_separability_2 {
|
namespace Set_movable_separability_2 {
|
||||||
|
|
||||||
/* Legend:
|
/* Legend:
|
||||||
* point = Represented as Direction_2. It is the intersection between the
|
* point = Represented as Direction_2. It is the intersection between the
|
||||||
* fitting Direction_2 and the unit circle
|
* fitting Direction_2 and the unit circle
|
||||||
*
|
*
|
||||||
* Arc = Represented as A pair of point. clockwise arc between the first
|
* 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)
|
* point and the second point. (each of its sides might be open or closed)
|
||||||
*
|
*
|
||||||
* SegmentOuterCircle = Arc that represent all the directions that points
|
* SegmentOuterCircle = Arc that represent all the directions that points
|
||||||
* out from the polygon if it start from the
|
* out from the polygon if it start from the
|
||||||
* fitting segment. This arc is always open half circle.
|
* fitting segment. This arc is always open half circle.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \fn std::pair<typename Kernel::Direction_2,typename Kernel::Direction_2> get_segment_outer_circle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation)
|
/*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2<Kernel>& pgn, OutputIterator oi)
|
||||||
* \param[in] seg the polygon segment
|
* \param[in] pgn the input polygon that we want to check if is castable or not.
|
||||||
* \param[in] orientation the orientation of the segment (and the polygon).
|
* \param[in,out] oi the output iterator to put the top edges in
|
||||||
* if CLOCKWISE then the outer half circle is to the left.
|
* \param[in] kernel the kernel to use.
|
||||||
* \return the open outer half-circle of the edge.
|
* \return all the possible top edges of the polygon and there pullout direction
|
||||||
*/
|
* a pair of Directions is build this way [firstClockwise,secondClockwise]
|
||||||
template <typename Kernel>
|
* (with no rotation)
|
||||||
inline std::pair<typename Kernel::Direction_2, typename Kernel::Direction_2>
|
*/
|
||||||
get_segment_outer_circle(const typename Kernel::Segment_2 seg,
|
template <typename Kernel, typename OutputIterator>
|
||||||
const CGAL::Orientation orientation)
|
OutputIterator
|
||||||
{
|
top_edges_single_mold_translational_casting_2
|
||||||
typename Kernel::Direction_2 forward( seg);
|
(const CGAL::Polygon_2<Kernel>& pgn, OutputIterator oi, Kernel& kernel)
|
||||||
typename Kernel::Direction_2 backward(-forward);
|
{
|
||||||
return (orientation == CGAL::Orientation::CLOCKWISE) ?
|
/* Legend
|
||||||
std::make_pair(backward, forward) : std::make_pair(forward, backward);
|
* 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 <typename Kernel>
|
auto e_it = pgn.edges_begin();
|
||||||
bool is_any_edge_colinear(const CGAL::Polygon_2<Kernel>& pgn)
|
size_t edge_index = 0;
|
||||||
{
|
CGAL::Orientation poly_orientation = pgn.orientation();
|
||||||
typedef typename CGAL::Point_2<Kernel> Point_2;
|
auto segment_outer_circle =
|
||||||
typedef typename CGAL::Polygon_2<Kernel> Polygon_2;
|
internal::get_segment_outer_circle<Kernel>(*e_it++, poly_orientation);
|
||||||
typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator;
|
internal::Circle_arrangment<Kernel> circle_arrangment(kernel,
|
||||||
Vertex_const_iterator vci = pgn.vertices_begin();
|
segment_outer_circle);
|
||||||
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;
|
++edge_index;
|
||||||
secondVar = thirdVar;
|
for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) {
|
||||||
thirdVar = *(vci++);
|
segment_outer_circle =
|
||||||
if (CGAL::collinear(firstVar, secondVar, thirdVar)) return true;
|
internal::get_segment_outer_circle<Kernel>(*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<Kernel>& 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 <typename Kernel, typename OutputIterator>
|
||||||
|
OutputIterator
|
||||||
|
top_edges_single_mold_translational_casting_2
|
||||||
|
(const CGAL::Polygon_2<Kernel>& 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<Kernel>& pgn, OutputIterator oi)
|
} // end of namespace Set_movable_separability_2
|
||||||
* \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 <typename Kernel, typename OutputIterator>
|
|
||||||
OutputIterator
|
|
||||||
top_edges_single_mold_translational_casting_2
|
|
||||||
(const CGAL::Polygon_2<Kernel>& 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<Kernel>(*e_it++, poly_orientation);
|
|
||||||
internal::Circle_arrangment<Kernel> 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<Kernel>(*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<Kernel>& 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 <typename Kernel, typename OutputIterator>
|
|
||||||
OutputIterator
|
|
||||||
top_edges_single_mold_translational_casting_2
|
|
||||||
(const CGAL::Polygon_2<Kernel>& 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 CGAL
|
} // end of namespace CGAL
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Polygon_2.h>
|
||||||
|
#include <CGAL/top_edges_single_mold_translational_casting_2.h>
|
||||||
|
|
||||||
|
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||||
|
typedef CGAL::Polygon_2<Kernel> Polygon_2;
|
||||||
|
typedef Kernel::Direction_2 Direction_2;
|
||||||
|
typedef Kernel::Point_2 Point_2;
|
||||||
|
|
||||||
|
typedef std::pair<Direction_2, Direction_2> Direction_range;
|
||||||
|
typedef std::pair<size_t, Direction_range> 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_edge> 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<Top_edge> 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;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue