mirror of https://github.com/CGAL/cgal
961 lines
33 KiB
C
Executable File
961 lines
33 KiB
C
Executable File
#include <CGAL/config.h> // needed for the LONGNAME flag
|
|
#include <CGAL/Cartesian.h>
|
|
|
|
#ifndef CGAL_PLANAR_MAP_2
|
|
#include <CGAL/Planar_map_2.h>
|
|
#endif
|
|
|
|
//#include <CGAL/Pm_with_intersections.h>
|
|
|
|
#include <CGAL/Arr_2_bases.h>
|
|
#include <CGAL/Pm_default_dcel.h>
|
|
#include <CGAL/Arr_segment_traits_2.h>
|
|
#include <CGAL/Arrangement_2.h>
|
|
|
|
#include <CGAL/Bop_default_dcel.h>
|
|
#include <CGAL/Map_overlay_default_notifier.h>
|
|
#include <CGAL/Map_overlay.h>
|
|
#include <CGAL/Boolean_operations_2.h>
|
|
#include <CGAL/IO/Arr_iostream.h>
|
|
#include <CGAL/sweep_to_construct_planar_map_2.h>
|
|
|
|
// Quotient is included anyway, because it is used to read
|
|
// data files. Quotient can read both integers and fractions.
|
|
// leda rational will only read fractions.
|
|
#include <CGAL/Quotient.h>
|
|
|
|
#include <list>
|
|
#include <string>
|
|
#include <fstream>
|
|
#include <cstdlib>
|
|
|
|
// Making sure test doesn't fail if LEDA is not installed
|
|
#if ! defined(CGAL_USE_LEDA) && \
|
|
(CGAL_ARR_TEST_TRAITS == CGAL_POLYLINE_LEDA_TRAITS || \
|
|
CGAL_ARR_TEST_TRAITS == CGAL_SEGMENT_LEDA_TRAITS || \
|
|
CGAL_ARR_TEST_TRAITS == CGAL_SEGMENT_CIRCLE_TRAITS)
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
std::cout << "A try to run test with LEDA traits but LEDA is not installed.";
|
|
std::cout << std::endl;
|
|
std::cout << "Test is not performed.";
|
|
std::cout << std::endl;
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
|
|
#include <CGAL/leda_rational.h>
|
|
|
|
#include <CGAL/Polygon_2.h>
|
|
#include <LEDA/polygon.h>
|
|
|
|
// Choose traits
|
|
#include <CGAL/Arr_leda_segment_traits_2.h>
|
|
|
|
// Quotient is included anyway, because it is used to read
|
|
// data files. Quotient can read both integers and fractions.
|
|
// leda rational will only read fractions.
|
|
//nclude <CGAL/Quotient.h>
|
|
|
|
|
|
class Boolean_operations_test {
|
|
struct Face_with_counter : public CGAL::Arr_2_face_base {
|
|
Face_with_counter() : CGAL::Arr_2_face_base(), counter(-1) {}
|
|
int counter;
|
|
};
|
|
|
|
public:
|
|
//typedef CGAL::Quotient<int> NT;
|
|
typedef leda_rational NT;
|
|
typedef CGAL::Cartesian<NT> R;
|
|
typedef CGAL::Arr_segment_traits_2<R> Traits;
|
|
|
|
typedef Traits::Point_2 Point;
|
|
typedef Traits::X_monotone_curve_2 X_curve;
|
|
typedef Traits::Curve_2 Curve;
|
|
|
|
typedef CGAL::Polygon_traits_2<R> Polygon_traits;
|
|
typedef std::list<Point> Polygon_Container;
|
|
typedef CGAL::Polygon_2<Polygon_traits, Polygon_Container> Polygon;
|
|
typedef std::list<Polygon> Polygon_list;
|
|
|
|
typedef CGAL::Bop_default_dcel<Traits> Dcel;
|
|
typedef CGAL::Planar_map_2<Dcel, Traits> Planar_map;
|
|
typedef CGAL::Planar_map_with_intersections_2<Planar_map> Pmwx;
|
|
typedef CGAL::Map_overlay_default_notifier<Planar_map>
|
|
MapOverlay_change_notification;
|
|
typedef CGAL::Map_overlay_2<Planar_map,MapOverlay_change_notification>
|
|
MapOverlay;
|
|
typedef CGAL::Boolean_operations_2<MapOverlay> Bops;
|
|
|
|
typedef Planar_map::Ccb_halfedge_circulator Ccb_halfedge_circulator;
|
|
typedef Planar_map::Ccb_halfedge_const_circulator
|
|
Ccb_halfedge_const_circulator;
|
|
typedef Planar_map::Face_handle Face_handle;
|
|
typedef Planar_map::Vertex_iterator Vertex_iterator;
|
|
typedef Planar_map::Face_iterator Face_iterator;
|
|
typedef Planar_map::Holes_iterator Holes_iterator;
|
|
typedef Planar_map::Holes_const_iterator Holes_const_iterator;
|
|
typedef Planar_map::Face Face;
|
|
typedef Planar_map::Halfedge Halfedge;
|
|
typedef Planar_map::Vertex Vertex;
|
|
|
|
typedef Bops::Faces_container Faces_container;
|
|
typedef Bops::Halfedges_container Halfedges_container;
|
|
typedef Bops::Vertices_container Vertices_container;
|
|
|
|
//typedef CGAL::Planar_map_with_intersections_2<Planar_map> Pmwx;
|
|
|
|
typedef CGAL::Arr_base_node<X_curve> Base_node;
|
|
typedef CGAL::Pm_dcel<CGAL::Arr_2_vertex_base<Point>,
|
|
CGAL::Arr_2_halfedge_base<Base_node >,
|
|
Face_with_counter > Arr_Dcel;
|
|
typedef CGAL::Arrangement_2<Arr_Dcel,Traits,Base_node > Arrangement;
|
|
|
|
typedef CGAL::Pm_walk_along_line_point_location<Planar_map> PmWalkPL;
|
|
typedef CGAL::Pm_naive_point_location<Planar_map> PmNaivePL;
|
|
|
|
|
|
private:
|
|
template <class Point>
|
|
class less_xy {
|
|
public:
|
|
|
|
inline bool operator()(const Point& p1, const Point& p2) const
|
|
{
|
|
return CGAL::compare_lexicographically_xy(p1,p2) == CGAL::SMALLER;
|
|
}
|
|
};
|
|
|
|
//------------------------------------ Boolean operations functions.
|
|
|
|
//generalized face_diff function, to acount for overlaps.
|
|
int face_diff (Arrangement::Ccb_halfedge_circulator circ) {
|
|
Traits t;
|
|
int diff = 0;
|
|
Arrangement::Overlap_circulator oc = circ->overlap_edges();
|
|
do {
|
|
if (circ->source()->point() == t.curve_source(oc->curve()) )
|
|
diff--; //we're inside, going outside
|
|
else
|
|
diff++;
|
|
} while (++oc != circ->overlap_edges());
|
|
|
|
return diff;
|
|
}
|
|
|
|
// covering_DFS will compute for each face in how many polygons it is.
|
|
// It is a recursive DFS function and will be called with the unbounded
|
|
// face after its counter has been initialized to 0.
|
|
void covering_DFS(Arrangement::Face_handle f) {
|
|
Arrangement::Ccb_halfedge_circulator start,circ;
|
|
|
|
// Do a recursive step for all neighbours, if any exists.
|
|
if (f->does_outer_ccb_exist()) {
|
|
start = circ = f->outer_ccb();
|
|
do {
|
|
if (circ->twin()->face()->counter < 0) {
|
|
int diff = face_diff(circ);
|
|
circ->twin()->face()->counter = (f->counter + diff);
|
|
covering_DFS(circ->twin()->face());
|
|
}
|
|
} while (++circ != start);
|
|
}
|
|
|
|
// Do a recursive step for all holes, if any exists.
|
|
Arrangement::Holes_iterator hit = f->holes_begin();
|
|
for (; Arrangement::Holes_iterator(hit)!=
|
|
Arrangement::Holes_iterator(f->holes_end()); ++hit) {
|
|
start = circ = (*hit);
|
|
do {
|
|
if (circ->twin()->face()->counter < 0) {
|
|
int diff = face_diff(circ);
|
|
circ->twin()->face()->counter = (f->counter + diff);
|
|
covering_DFS(circ->twin()->face());
|
|
}
|
|
} while (++circ != start);
|
|
}
|
|
}
|
|
|
|
// Construct the arrangement that will use for calculating the intersection.
|
|
void insert_polygons(Arrangement &arr, Polygon_list &in_poly_list)
|
|
{
|
|
Polygon::Edge_const_iterator it;
|
|
Arrangement::Curve_iterator ci;
|
|
Polygon_list::iterator plit;
|
|
|
|
// for each polygon in list
|
|
for (plit = in_poly_list.begin(); plit != in_poly_list.end(); ++plit) {
|
|
|
|
// Make sure polygons are oriented counterclockwise
|
|
// to satisfy assumption in DFS function
|
|
if ( ! plit->is_counterclockwise_oriented())
|
|
plit->reverse_orientation();
|
|
|
|
// insert polygon to arrangement
|
|
for (it = plit->edges_begin(); it != plit->edges_end(); ++it)
|
|
{
|
|
ci = arr.insert(*it);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
// Convert faces of the arrangement that are in the intersection
|
|
// to polygons.
|
|
void polygons_from_faces(Arrangement& arr,
|
|
std::list<Face_iterator>& face_it_list,
|
|
Polygon_list& poly_list)
|
|
{
|
|
std::list<Face_iterator>::iterator lit;
|
|
//Pmwx::Ccb_halfedge_circulator cc;
|
|
Polygon poly;
|
|
|
|
for (lit = face_it_list.begin(); lit != face_it_list.end(); ++lit) {
|
|
|
|
poly.erase(poly.vertices_begin(), poly.vertices_end());
|
|
Arrangement::Ccb_halfedge_circulator cc=(*lit)->outer_ccb();
|
|
do {
|
|
poly.push_back(cc->curve().source());
|
|
} while (++cc != (*lit)->outer_ccb());
|
|
poly_list.push_back(poly);
|
|
}
|
|
}*/
|
|
|
|
// performs the extraction of data out of the processed arrangement
|
|
// if covering = 0, will perform union
|
|
// otherwise, if there are n polygons in the arrangement and covering == n
|
|
// then will perform intersection
|
|
template <class OutputIterator>
|
|
void get_faces_with_covering(OutputIterator faces,
|
|
Arrangement& arr,
|
|
int covering)
|
|
{
|
|
Arrangement::Face_handle uf = arr.unbounded_face();
|
|
uf->counter = 0;
|
|
covering_DFS(uf);
|
|
|
|
//"collecting" the union boundary faces.
|
|
for(Arrangement::Face_iterator fit = arr.faces_begin();
|
|
fit!=arr.faces_end(); ++fit) {
|
|
|
|
// if the face is covered by 'covering'
|
|
if (fit->counter == covering) {
|
|
//unions.push_back(fit);
|
|
*faces = fit;
|
|
++faces;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class InputIterator1, class InputIterator2, class Container>
|
|
void get_points_below_vertex_with_covering(InputIterator1 points_begin,
|
|
InputIterator1 points_end,
|
|
InputIterator2 polygons_begin,
|
|
InputIterator2 polygons_end,
|
|
Container& points,
|
|
int covering)
|
|
{
|
|
for (InputIterator1 p_iter=points_begin; p_iter!= points_end; ++p_iter){
|
|
int num_vertices_above=0;
|
|
for (InputIterator2 poly_iter=polygons_begin; poly_iter!=polygons_end;
|
|
++poly_iter){
|
|
bool found=false;
|
|
for (Polygon::Vertex_const_iterator v_iter=poly_iter->vertices_begin();
|
|
v_iter != poly_iter->vertices_end() && !found; ++v_iter){
|
|
// *e_iter is CGAL Segment.
|
|
if (*v_iter == *p_iter)
|
|
found=true;
|
|
}
|
|
if (found)
|
|
++num_vertices_above;
|
|
}
|
|
|
|
//cout << *p_iter <<" is below "<< num_vertices_above <<" vertices"
|
|
//<<endl;
|
|
|
|
if (num_vertices_above==covering)
|
|
points.insert(*p_iter);
|
|
else { // removing that point from points, if it exists
|
|
typename Container::iterator iter = points.find(*p_iter);
|
|
if (iter != points.end())
|
|
points.erase(iter);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class InputIterator1, class InputIterator2, class Container>
|
|
void get_points_below_edge_with_covering(InputIterator1 points_begin,
|
|
InputIterator1 points_end,
|
|
InputIterator2 polygons_begin,
|
|
InputIterator2 polygons_end,
|
|
Container& points,
|
|
int covering)
|
|
{
|
|
Traits traits;
|
|
|
|
for (InputIterator1 p_iter=points_begin; p_iter!= points_end; ++p_iter){
|
|
int num_edges_above=0;
|
|
for (InputIterator2 poly_iter=polygons_begin; poly_iter!=polygons_end;
|
|
++poly_iter){
|
|
bool found=false;
|
|
for (Polygon::Edge_const_iterator e_iter=poly_iter->edges_begin();
|
|
e_iter != poly_iter->edges_end() && !found; ++e_iter){
|
|
// *e_iter is CGAL Segment.
|
|
Curve cv(*e_iter);
|
|
if (traits.curve_compare_y_at_x(cv,*p_iter) == Traits::ON_CURVE)
|
|
found=true;
|
|
}
|
|
if (found)
|
|
++num_edges_above;
|
|
}
|
|
|
|
//cout << *p_iter <<" is below "<< num_edges_above <<" edges"<<endl;
|
|
|
|
if (num_edges_above==covering)
|
|
points.insert(*p_iter);
|
|
else { // removing that point from points, if it exists
|
|
typename Container::iterator iter = points.find(*p_iter);
|
|
if (iter != points.end())
|
|
points.erase(iter);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class InputIterator, class Container>
|
|
void get_points_below_halfedge(InputIterator halfedges_begin,
|
|
InputIterator halfedges_end,
|
|
Container& points)
|
|
{
|
|
InputIterator iter=halfdges_begin;
|
|
for ( ;halfedge_iter!=halfedge_end; ++halfedge_iter, ++halfedge_iter){
|
|
points.insert(halfedge_iter->source()->point());
|
|
points.insert(halfedge_iter->target()->point());
|
|
}
|
|
|
|
}
|
|
|
|
// we can use this function, instead of computing exact covering, since
|
|
// there are not isolated vertices in our structures. Hence if a vertex is
|
|
// below a face - it has to be connected to at least one edge.
|
|
template <class InputIterator1, class InputIterator2,class Container>
|
|
void get_points_below_faces(InputIterator1 points_begin,
|
|
InputIterator1 points_end,
|
|
InputIterator2 faces_begin,
|
|
InputIterator2 faces_end,
|
|
Container& points)
|
|
{
|
|
std::set<Point,less_xy<Point> > endpoints(points_begin, points_end);
|
|
|
|
for (InputIterator2 face_iter=faces_begin; face_iter!=faces_end;
|
|
++face_iter){
|
|
if ((*face_iter)->does_outer_ccb_exist()){
|
|
Arrangement::Ccb_halfedge_circulator circ=(*face_iter)->outer_ccb();
|
|
do {
|
|
// inserting the point only if it's an end point.
|
|
if (endpoints.find(circ->source()->point()) != endpoints.end())
|
|
points.insert(circ->source()->point());
|
|
} while (++circ != (*face_iter)->outer_ccb());
|
|
}
|
|
|
|
Arrangement::Holes_iterator hit = (*face_iter)->holes_begin();
|
|
for ( ;hit!= (*face_iter)->holes_end(); ++hit) {
|
|
Arrangement::Ccb_halfedge_circulator circ = (*hit);
|
|
do {
|
|
if (endpoints.find(circ->source()->point()) != endpoints.end())
|
|
points.insert(circ->source()->point());
|
|
} while (++circ != *hit);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This function is written for the symmetric difference.
|
|
// the two former functions: get_points_below_vertex_with_covering and
|
|
// get_points_below_edge_with_covering could have return a point inside a
|
|
// polygon since this check was not perfromed. Here we clean such points.
|
|
template <class InputIterator, class Container>
|
|
void remove_points_below_faces(InputIterator polygons_begin,
|
|
InputIterator polygons_end,
|
|
Container& points)
|
|
{
|
|
for (typename Container::iterator p_iter=points.begin();
|
|
p_iter!=points.end(); ){
|
|
InputIterator poly_iter;
|
|
for (poly_iter=polygons_begin; poly_iter!=polygons_end; ++poly_iter){
|
|
if (poly_iter->has_on_bounded_side(*p_iter)){
|
|
points.erase(p_iter++);
|
|
break;
|
|
}
|
|
}
|
|
if (poly_iter==polygons_end)
|
|
++p_iter;
|
|
}
|
|
}
|
|
|
|
template <class InputIterator1, class InputIterator2,class OutputIterator>
|
|
void get_vertices_with_covering(InputIterator1 polygons_begin,
|
|
InputIterator1 polygons_end,
|
|
InputIterator2 faces_begin,
|
|
InputIterator2 faces_end,
|
|
OutputIterator vertices,
|
|
const Arrangement& arr,
|
|
int covering)
|
|
{
|
|
std::set<Point,less_xy<Point> > endpoints;
|
|
std::set<Point,less_xy<Point> > covering_endpoints;
|
|
//std::set<Point,less_xy<Point> > common_endpoints;
|
|
// holds equal endpoints from different polygons.
|
|
|
|
std::list<Point> intersections;
|
|
|
|
// inserting to common points the endpoints which have covering number of
|
|
// vertices above.
|
|
for (InputIterator1 poly_iter=polygons_begin;
|
|
poly_iter != polygons_end; ++poly_iter){
|
|
for (Polygon::Vertex_iterator v_iter=poly_iter->vertices_begin();
|
|
v_iter!=poly_iter->vertices_end(); ++v_iter)
|
|
endpoints.insert(*v_iter);
|
|
}
|
|
|
|
get_points_below_vertex_with_covering(endpoints.begin(),endpoints.end(),
|
|
polygons_begin,polygons_end,
|
|
covering_endpoints,covering);
|
|
|
|
get_points_below_edge_with_covering(endpoints.begin(),endpoints.end(),
|
|
polygons_begin,polygons_end,
|
|
covering_endpoints,covering);
|
|
|
|
for (Arrangement::Vertex_const_iterator v_iter=arr.vertices_begin();
|
|
v_iter!=arr.vertices_end(); ++v_iter){
|
|
if (endpoints.find(v_iter->point()) == endpoints.end()) // intersection
|
|
intersections.push_back(v_iter->point());
|
|
}
|
|
|
|
if (covering > 1){ // intersection or union.
|
|
get_points_below_faces(endpoints.begin(),endpoints.end(),
|
|
faces_begin, faces_end,
|
|
covering_endpoints);
|
|
|
|
std::copy(covering_endpoints.begin(),covering_endpoints.end(),vertices);
|
|
std::copy(intersections.begin(),intersections.end(),vertices);
|
|
}
|
|
|
|
else if (covering == 1) { // symmetric difference.
|
|
remove_points_below_faces(polygons_begin,polygons_end,covering_endpoints);
|
|
std::copy(covering_endpoints.begin(),covering_endpoints.end(),vertices);
|
|
}
|
|
}
|
|
|
|
// The interface for an intersection function
|
|
template <class OutputIterator>
|
|
void intersect_polygons(Arrangement arr,
|
|
OutputIterator faces)
|
|
{
|
|
//insert_polygons(arr, in_poly_list);
|
|
|
|
// faces with a covering two are faces that are in the intersection
|
|
// of the two polygons.
|
|
//get_faces_with_covering(arr, faces, in_poly_list.size());
|
|
|
|
//polygons_from_faces(arr, face_it_list, out_poly_list);
|
|
|
|
//if (begin == faces) return 0; else return 1;
|
|
}
|
|
|
|
//----------------------------------- compating Planar_map features
|
|
class Equal_Halfedge {
|
|
public:
|
|
Equal_Halfedge(const Arrangement::Halfedge& h) : h_(h) {}
|
|
|
|
bool operator()(const Halfedge& halfedge) const
|
|
{
|
|
|
|
Traits traits;
|
|
|
|
/* // for debugging!
|
|
cout<<"("<<CGAL::to_double(h_.curve().source().x())<<","
|
|
<< CGAL::to_double(h_.curve().source().y())<<") ";
|
|
cout<<"("<<CGAL::to_double(h_.curve().target().x())<<","
|
|
<< CGAL::to_double(h_.curve().target().y())<<") "<<endl;
|
|
|
|
cout<<"("<<CGAL::to_double(halfedge.curve().source().x())
|
|
<<","<< CGAL::to_double(halfedge.curve().source().y())<<") ";
|
|
cout<<"("<<CGAL::to_double(halfedge.curve().target().x())
|
|
<<","<< CGAL::to_double(halfedge.curve().target().y())<<") "<<endl;
|
|
cout<<endl;
|
|
// end debugging. */
|
|
|
|
return ((h_.curve() == halfedge.curve() ||
|
|
traits.curve_opposite(h_.curve()) == halfedge.curve()) &&
|
|
h_.source()->point() == halfedge.source()->point() &&
|
|
h_.target()->point() == halfedge.target()->point());
|
|
}
|
|
|
|
private:
|
|
const Arrangement::Halfedge& h_;
|
|
};
|
|
|
|
class Equal_Ccb {
|
|
public:
|
|
Equal_Ccb(Arrangement::Ccb_halfedge_const_circulator outer_ccb1_) :
|
|
outer_ccb1(outer_ccb1_) {}
|
|
|
|
bool operator()(Ccb_halfedge_const_circulator outer_ccb2) const
|
|
{
|
|
Arrangement::Ccb_halfedge_const_circulator circ1=outer_ccb1;
|
|
Ccb_halfedge_const_circulator circ2=outer_ccb2;
|
|
|
|
unsigned int size1=0,size2=0;
|
|
do {
|
|
// for debugging!
|
|
/*cout<<"("<<CGAL::to_double(circ1->curve().source().x())<<","<<
|
|
CGAL::to_double(circ1->curve().source().y())<<") ";
|
|
cout<<"("<<CGAL::to_double(circ1->curve().target().x())<<","<<
|
|
CGAL::to_double(circ1->curve().target().y())<<") "<<endl;*/
|
|
|
|
++size1;
|
|
} while (++circ1 != outer_ccb1);
|
|
|
|
do {
|
|
// for debugging!
|
|
/*cout<<"("<<CGAL::to_double(circ2->curve().source().x())<<","<<
|
|
CGAL::to_double(circ2->curve().source().y())<<") ";
|
|
cout<<"("<<CGAL::to_double(circ2->curve().target().x())<<","<<
|
|
CGAL::to_double(circ2->curve().target().y())<<") "<<endl;*/
|
|
|
|
++size2;
|
|
} while (++circ2 != outer_ccb2);
|
|
|
|
//CGAL_For_all(circ1, outer_ccb1) { ++size1; } // does not compile.
|
|
//CGAL_For_all(circ2, outer_ccb2) { ++size2; }
|
|
|
|
if (size1 != size2)
|
|
return false;
|
|
|
|
//if (CGAL::circulator_size(outer_ccb1) != // Dees not compile!
|
|
// CGAL::circulator_size(outer_ccb2) )
|
|
// return false;
|
|
|
|
Arrangement::Ccb_halfedge_const_circulator ccb1 = outer_ccb1;
|
|
Ccb_halfedge_const_circulator ccb2 = outer_ccb2;
|
|
|
|
do {
|
|
if ( Equal_Halfedge(*ccb1)(*ccb2) )
|
|
break;
|
|
} while (++ccb1 != outer_ccb1);
|
|
|
|
if ( !Equal_Halfedge(*ccb1)(*ccb2) )
|
|
return false; // did not find the first halfedge.
|
|
|
|
// now ccb1 plays as the new starting point of outer_ccb1.
|
|
do {
|
|
if (! Equal_Halfedge(*ccb1)(*ccb2) )
|
|
return false;
|
|
++ccb1;
|
|
} while (++ccb2 != outer_ccb2);
|
|
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
Arrangement::Ccb_halfedge_const_circulator outer_ccb1;
|
|
};
|
|
|
|
class Equal_Face {
|
|
public:
|
|
Equal_Face(const Arrangement::Face& f1_)
|
|
: f1(f1_) {}
|
|
|
|
bool operator()(const Face& f2) const
|
|
{
|
|
if (std::distance(f1.holes_begin(),f1.holes_end()) !=
|
|
std::distance(f2.holes_begin(),f2.holes_end()) )
|
|
return false;
|
|
|
|
for (Arrangement::Holes_const_iterator holes_iter1 =
|
|
f1.holes_begin();
|
|
holes_iter1 != f1.holes_end(); ++holes_iter1) {
|
|
|
|
Equal_Ccb pred(*holes_iter1);
|
|
Holes_const_iterator iter = std::find_if(f2.holes_begin(),
|
|
f2.holes_end(),
|
|
pred);
|
|
|
|
if (iter == f2.holes_end())
|
|
return false;
|
|
}
|
|
|
|
if (f1.is_unbounded()) {
|
|
if (f2.is_unbounded())
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
if (f2.is_unbounded()) {
|
|
if (f1.is_unbounded())
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// f1 and f2 are bounded.
|
|
|
|
Equal_Ccb pred(f1.outer_ccb());
|
|
|
|
return ( pred(f2.outer_ccb()) );
|
|
}
|
|
private:
|
|
const Arrangement::Face& f1;
|
|
};
|
|
|
|
template <class InputIterator1, class InputIterator2>
|
|
void compare_vertices(InputIterator1 begin1, InputIterator1 end1,
|
|
InputIterator2 begin2, InputIterator2 end2)
|
|
{
|
|
// for debugging:
|
|
cout<<"vertices sizes:"<<std::distance(begin1,end1)<<" "
|
|
<< std::distance(begin2,end2) <<endl;
|
|
|
|
//for (InputIterator1 iter1=begin1; iter1!=end1; ++iter1)
|
|
//cout << CGAL::to_double(iter1->x()) << " "<<
|
|
// CGAL::to_double(iter1->y()) << endl;
|
|
|
|
//for (InputIterator2 iter2=begin2; iter2!=end2; ++iter2)
|
|
// cout << CGAL::to_double(iter2->x()) << " "<<
|
|
// CGAL::to_double(iter2->y()) << endl;
|
|
// end degugging.
|
|
|
|
CGAL_assertion(std::distance(begin1,end1) ==
|
|
std::distance(begin2,end2));
|
|
|
|
for (InputIterator1 iter1=begin1; iter1!= end1; ++iter1)
|
|
CGAL_assertion(std::find(begin2,end2,*iter1) != end2);
|
|
|
|
}
|
|
|
|
template <class InputIterator1, class InputIterator2>
|
|
void compare_faces(InputIterator1 begin1, InputIterator1 end1,
|
|
InputIterator2 begin2, InputIterator2 end2)
|
|
{
|
|
std::list<Arrangement::Face> faces1;
|
|
std::list<Face> faces2;
|
|
|
|
for (InputIterator1 iter1 = begin1; iter1 != end1; ++iter1){
|
|
faces1.push_back(*(*iter1));
|
|
}
|
|
|
|
for (InputIterator2 iter2 = begin2; iter2 != end2; ++iter2)
|
|
faces2.push_back(*(*iter2));
|
|
|
|
// asserting both contianers have the same size of faces.
|
|
CGAL_assertion(faces1.size() == faces2.size());
|
|
|
|
for (std::list<Arrangement::Face>::iterator face_iter = faces1.begin();
|
|
face_iter != faces1.end(); ++face_iter)
|
|
{
|
|
Equal_Face pred(*face_iter);
|
|
std::list<Face>::iterator f = std::find_if(faces2.begin(),
|
|
faces2.end(),
|
|
pred);
|
|
|
|
// asserting every face of faces1 is found in faces2.
|
|
CGAL_assertion(f != faces2.end());
|
|
|
|
faces2.erase(f);
|
|
}
|
|
|
|
// asserting we have covered all faces from faces2.
|
|
CGAL_assertion(faces2.empty());
|
|
}
|
|
|
|
void check_intersection(const Bops& bop,
|
|
const Polygon& polygon1,
|
|
const Polygon& polygon2)
|
|
{
|
|
Polygon_list polygons;
|
|
polygons.push_back(polygon1);
|
|
polygons.push_back(polygon2);
|
|
|
|
//Bops bop(pm1, pm2);
|
|
|
|
Faces_container bops_faces;
|
|
Halfedges_container bops_halfedges;
|
|
Vertices_container bops_vertices;
|
|
|
|
bop.intersection(bops_faces,bops_halfedges,bops_vertices);
|
|
|
|
std::list<Arrangement::Face_iterator> faces;
|
|
Arrangement arr;
|
|
insert_polygons(arr,polygons);
|
|
get_faces_with_covering(std::back_inserter(faces),arr,polygons.size());
|
|
|
|
cout<<"Face sizes:"<<faces.size()<<" "<<bops_faces.size()<<endl;
|
|
|
|
compare_faces(faces.begin(), faces.end(),
|
|
bops_faces.begin(), bops_faces.end());
|
|
|
|
std::cout << "Intersection: Faces --- O.K "<< std::endl;
|
|
|
|
std::list<Point> points;
|
|
|
|
get_vertices_with_covering(polygons.begin(),
|
|
polygons.end(),
|
|
faces.begin(),
|
|
faces.end(),
|
|
std::back_inserter(points),
|
|
arr,
|
|
polygons.size());
|
|
|
|
std::set<Point, less_xy<Point> > set_points(points.begin(), points.end());
|
|
std::list<Point> bops_points;
|
|
for (Vertices_container::iterator iter=bops_vertices.begin();
|
|
iter!=bops_vertices.end(); ++iter)
|
|
bops_points.push_back((*iter)->point());
|
|
|
|
compare_vertices(set_points.begin(), set_points.end(),
|
|
bops_points.begin(), bops_points.end());
|
|
|
|
std::cout << "Intersection: Vertices --- O.K "<< std::endl;
|
|
//compare_halfedges(halfedges.begin(), halfedges.end(),
|
|
// bops_halfedges.begin(), bops_halfedges.end());
|
|
}
|
|
|
|
void check_union(const Bops &bop,
|
|
const Polygon& polygon1,
|
|
const Polygon& polygon2)
|
|
{
|
|
Polygon_list polygons;
|
|
polygons.push_back(polygon1);
|
|
polygons.push_back(polygon2);
|
|
|
|
//Bops bop(pm1, pm2);
|
|
|
|
Faces_container bops_faces;
|
|
Halfedges_container bops_halfedges;
|
|
Vertices_container bops_vertices;
|
|
|
|
bop.Union(bops_faces,bops_halfedges,bops_vertices);
|
|
|
|
std::list<Arrangement::Face_iterator> union_faces[2];
|
|
// faces[0] will contain the symmetric diff faces, and faces[1] will
|
|
// contain the intersection faces.
|
|
Arrangement arr;
|
|
insert_polygons(arr,polygons);
|
|
|
|
// For union we have to define all covers which are not 0.
|
|
unsigned int i=1;
|
|
for ( ; i <= polygons.size(); ++i)
|
|
get_faces_with_covering(std::back_inserter(union_faces[i-1]),arr,i);
|
|
|
|
std::list<Arrangement::Face_iterator> faces(union_faces[0].begin(),
|
|
union_faces[0].end());
|
|
std::copy(union_faces[1].begin(), union_faces[1].end(),
|
|
std::back_inserter(faces));
|
|
|
|
cout<<"Faces sizes:"<<faces.size()<<" "<<bops_faces.size()<<endl;
|
|
|
|
compare_faces(faces.begin(), faces.end(),
|
|
bops_faces.begin(), bops_faces.end());
|
|
|
|
std::cout << "Union: Faces --- O.K "<< std::endl;
|
|
|
|
std::list<Point> points;
|
|
//std::set<Point,less_xy<Point> > union_points;
|
|
for (i=1; i <= polygons.size(); ++i) {
|
|
get_vertices_with_covering(polygons.begin(),
|
|
polygons.end(),
|
|
union_faces[i-1].begin(),
|
|
union_faces[i-1].end(),
|
|
std::back_inserter(points),
|
|
arr,
|
|
i);
|
|
|
|
//for ( std::list<Point>::iterator p_iter
|
|
}
|
|
|
|
std::set<Point, less_xy<Point> > set_points(points.begin(), points.end());
|
|
|
|
std::list<Point> bops_points;
|
|
for (Vertices_container::iterator iter=bops_vertices.begin();
|
|
iter!=bops_vertices.end(); ++iter)
|
|
bops_points.push_back((*iter)->point());
|
|
|
|
compare_vertices(set_points.begin(), set_points.end(),
|
|
bops_points.begin(), bops_points.end());
|
|
|
|
std::cout << "Union: Vertices --- O.K "<< std::endl;
|
|
//compare_halfedges(halfedges.begin(), halfedges.end(),
|
|
// bops_halfedges.begin(), bops_halfedges.end());
|
|
|
|
}
|
|
|
|
void check_symmetric_difference(const Bops &bop,
|
|
const Polygon& polygon1,
|
|
const Polygon& polygon2)
|
|
{
|
|
Polygon_list polygons;
|
|
polygons.push_back(polygon1);
|
|
polygons.push_back(polygon2);
|
|
|
|
//Bops bop(pm1, pm2);
|
|
|
|
Faces_container bops_faces;
|
|
Halfedges_container bops_halfedges;
|
|
Vertices_container bops_vertices;
|
|
|
|
bop.symmetric_difference(bops_faces,bops_halfedges,bops_vertices);
|
|
|
|
std::list<Arrangement::Face_iterator> faces;
|
|
Arrangement arr;
|
|
insert_polygons(arr,polygons);
|
|
|
|
// For symmetric difference we have to define all covers to be 1.
|
|
get_faces_with_covering(std::back_inserter(faces), arr, 1);
|
|
|
|
cout<<"Face sizes:"<<faces.size()<<" "<<bops_faces.size()<<endl;
|
|
|
|
compare_faces(faces.begin(), faces.end(),
|
|
bops_faces.begin(), bops_faces.end());
|
|
|
|
std::cout << "Symmetric Difference: Faces --- O.K "<< std::endl;
|
|
|
|
std::list<Point> points;
|
|
|
|
get_vertices_with_covering(polygons.begin(),
|
|
polygons.end(),
|
|
faces.begin(),
|
|
faces.end(),
|
|
std::back_inserter(points),
|
|
arr,
|
|
1);
|
|
|
|
std::set<Point, less_xy<Point> > set_points(points.begin(), points.end());
|
|
std::list<Point> bops_points;
|
|
for (Vertices_container::iterator iter=bops_vertices.begin();
|
|
iter!=bops_vertices.end(); ++iter)
|
|
bops_points.push_back((*iter)->point());
|
|
|
|
compare_vertices(set_points.begin(), set_points.end(),
|
|
bops_points.begin(), bops_points.end());
|
|
|
|
std::cout << "Symmetric Difference: Vertices --- O.K "<< std::endl;
|
|
//compare_halfedges(halfedges.begin(), halfedges.end(),
|
|
// bops_halfedges.begin(), bops_halfedges.end());
|
|
|
|
}
|
|
|
|
//------------------------------- Scanning input functnions
|
|
int get_next_int(std::ifstream& file)
|
|
{
|
|
int num = 0;
|
|
//NT result(INT_MAX);
|
|
std::string s;
|
|
char c = 0;
|
|
|
|
//file.set_ascii_mode();
|
|
while (file)
|
|
{
|
|
// try to convert next token to integer
|
|
file >> c;
|
|
|
|
if (c=='#') // comment
|
|
{
|
|
std::getline(file, s);
|
|
}
|
|
else // an integer number.
|
|
{
|
|
file.putback(c);
|
|
|
|
file >> num;
|
|
return num;
|
|
}
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
void read_file_build_creator(std::ifstream & file, Pmwx & pm)
|
|
{
|
|
// read number of curves
|
|
unsigned int num_curves = get_next_int(file);
|
|
|
|
cout<<"num_curves="<<num_curves<<endl;
|
|
|
|
std::list<Curve> curves;
|
|
//Curve curr_curve;
|
|
// read curves (test specific)
|
|
int x1,y1,x2,y2;
|
|
while (num_curves--) {
|
|
//file >> curr_curve;
|
|
file >>x1 >>y1 >> x2>> y2;
|
|
|
|
Point p1(x1,y1), p2(x2,y2);
|
|
curves.push_back(Curve(p1,p2));
|
|
}
|
|
|
|
pm.insert(curves.begin(), curves.end());
|
|
}
|
|
|
|
public:
|
|
|
|
void start(char * filename)
|
|
{
|
|
std::ifstream file(filename);
|
|
|
|
PmWalkPL pl_walk1, pl_walk2;
|
|
Pmwx pm1(&pl_walk1), pm2(&pl_walk2);
|
|
|
|
read_file_build_creator(file, pm1);
|
|
read_file_build_creator(file, pm2);
|
|
|
|
pm1.unbounded_face()->set_ignore_bop(false);
|
|
pm2.unbounded_face()->set_ignore_bop(false);
|
|
|
|
Polygon polygon1, polygon2;
|
|
|
|
for (Vertex_iterator v_iter1=pm1.vertices_begin();
|
|
v_iter1!=pm1.vertices_end(); ++v_iter1)
|
|
polygon1.push_back(v_iter1->point());
|
|
|
|
for (Vertex_iterator v_iter2=pm2.vertices_begin();
|
|
v_iter2!=pm2.vertices_end(); ++v_iter2)
|
|
polygon2.push_back(v_iter2->point());
|
|
|
|
Faces_container bops_faces;
|
|
Halfedges_container bops_halfedges;
|
|
Vertices_container bops_vertices;
|
|
|
|
//bop.intersection(bops_faces,bops_halfedges,bops_vertices);
|
|
//cout<<"intersetion: bops_faces.size() "<<bops_faces.size()<<endl;
|
|
|
|
Bops bop(pm1, pm2);
|
|
check_intersection(bop,polygon1,polygon2);
|
|
|
|
//bop.Union(bops_faces,bops_halfedges,bops_vertices);
|
|
//cout<<"union: bops_faces.size() "<<bops_faces.size()<<endl;
|
|
|
|
check_union(bop,polygon1,polygon2);
|
|
|
|
check_symmetric_difference(bop,polygon1,polygon2);
|
|
}
|
|
};
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
|
|
Boolean_operations_test test;
|
|
|
|
if (argc < 1 || argc > 2) {
|
|
std::cout << "usage: test data_file" << std::endl;
|
|
std::exit(1);
|
|
}
|
|
|
|
test.start(argv[1]);
|
|
return 0;
|
|
}
|
|
|
|
#endif // CGAL_ARR_TEST_LEDA_CONFLICT
|