openscad/src/cgalutils.cc

230 lines
6.9 KiB
C++

#ifdef ENABLE_CGAL
#include "cgalutils.h"
#include "polyset.h"
#include "printutils.h"
#include "cgal.h"
#include <map>
PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p)
{
PolySet *ps = new PolySet();
typedef CGAL_Polyhedron::Vertex Vertex;
typedef CGAL_Polyhedron::Vertex_const_iterator VCI;
typedef CGAL_Polyhedron::Facet_const_iterator FCI;
typedef CGAL_Polyhedron::Halfedge_around_facet_const_circulator HFCC;
for (FCI fi = p.facets_begin(); fi != p.facets_end(); ++fi) {
HFCC hc = fi->facet_begin();
HFCC hc_end = hc;
Vertex v1, v2, v3;
v1 = *VCI((hc++)->vertex());
v3 = *VCI((hc++)->vertex());
do {
v2 = v3;
v3 = *VCI((hc++)->vertex());
double x1 = CGAL::to_double(v1.point().x());
double y1 = CGAL::to_double(v1.point().y());
double z1 = CGAL::to_double(v1.point().z());
double x2 = CGAL::to_double(v2.point().x());
double y2 = CGAL::to_double(v2.point().y());
double z2 = CGAL::to_double(v2.point().z());
double x3 = CGAL::to_double(v3.point().x());
double y3 = CGAL::to_double(v3.point().y());
double z3 = CGAL::to_double(v3.point().z());
ps->append_poly();
ps->append_vertex(x1, y1, z1);
ps->append_vertex(x2, y2, z2);
ps->append_vertex(x3, y3, z3);
} while (hc != hc_end);
}
return ps;
}
#undef GEN_SURFACE_DEBUG
class CGAL_Build_PolySet : public CGAL::Modifier_base<CGAL_HDS>
{
public:
typedef CGAL_HDS::Vertex::Point CGALPoint;
const PolySet &ps;
CGAL_Build_PolySet(const PolySet &ps) : ps(ps) { }
void operator()(CGAL_HDS& hds)
{
CGAL_Polybuilder B(hds, true);
std::vector<CGALPoint> vertices;
Grid3d<int> vertices_idx(GRID_FINE);
for (size_t i = 0; i < ps.polygons.size(); i++) {
const PolySet::Polygon *poly = &ps.polygons[i];
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
if (!vertices_idx.has(p[0], p[1], p[2])) {
vertices_idx.data(p[0], p[1], p[2]) = vertices.size();
vertices.push_back(CGALPoint(p[0], p[1], p[2]));
}
}
}
B.begin_surface(vertices.size(), ps.polygons.size());
#ifdef GEN_SURFACE_DEBUG
printf("=== CGAL Surface ===\n");
#endif
for (size_t i = 0; i < vertices.size(); i++) {
const CGALPoint &p = vertices[i];
B.add_vertex(p);
#ifdef GEN_SURFACE_DEBUG
printf("%d: %f %f %f\n", i, p.x().to_double(), p.y().to_double(), p.z().to_double());
#endif
}
for (size_t i = 0; i < ps.polygons.size(); i++) {
const PolySet::Polygon *poly = &ps.polygons[i];
std::map<int,int> fc;
bool facet_is_degenerated = false;
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
int v = vertices_idx.data(p[0], p[1], p[2]);
if (fc[v]++ > 0)
facet_is_degenerated = true;
}
if (!facet_is_degenerated)
B.begin_facet();
#ifdef GEN_SURFACE_DEBUG
printf("F:");
#endif
for (size_t j = 0; j < poly->size(); j++) {
const Vector3d &p = poly->at(j);
#ifdef GEN_SURFACE_DEBUG
printf(" %d (%f,%f,%f)", vertices_idx.data(p[0], p[1], p[2]), p[0], p[1], p[2]);
#endif
if (!facet_is_degenerated)
B.add_vertex_to_facet(vertices_idx.data(p[0], p[1], p[2]));
}
#ifdef GEN_SURFACE_DEBUG
if (facet_is_degenerated)
printf(" (degenerated)");
printf("\n");
#endif
if (!facet_is_degenerated)
B.end_facet();
}
#ifdef GEN_SURFACE_DEBUG
printf("====================\n");
#endif
B.end_surface();
#undef PointKey
}
};
CGAL_Polyhedron *createPolyhedronFromPolySet(const PolySet &ps)
{
CGAL_Polyhedron *P = NULL;
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
P = new CGAL_Polyhedron;
CGAL_Build_PolySet builder(ps);
P->delegate(builder);
}
catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in CGAL_Build_PolySet: %s", e.what());
delete P;
P = NULL;
}
CGAL::set_error_behaviour(old_behaviour);
return P;
}
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N )
{
CGAL_Iso_cuboid_3 result(0,0,0,0,0,0);
CGAL_Nef_polyhedron3::Vertex_const_iterator vi;
std::vector<CGAL_Nef_polyhedron3::Point_3> points;
// can be optimized by rewriting bounding_box to accept vertices
CGAL_forall_vertices( vi, N )
points.push_back( vi->point() );
if (points.size())
result = CGAL::bounding_box( points.begin(), points.end() );
return result;
}
CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N )
{
CGAL_Iso_rectangle_2e result(0,0,0,0);
CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator vi;
std::vector<CGAL_Point_2e> points;
// can be optimized by rewriting bounding_box to accept vertices
for ( vi = explorer.vertices_begin(); vi != explorer.vertices_end(); ++vi )
if ( explorer.is_standard( vi ) )
points.push_back( explorer.point( vi ) );
if (points.size())
result = CGAL::bounding_box( points.begin(), points.end() );
return result;
}
void ZRemover::visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
{
log << " <!-- ZRemover Halffacet visit. Mark: " << hfacet->mark() << " -->\n";
if ( hfacet->plane().orthogonal_direction() != this->up ) {
log << " <!-- ZRemover down-facing half-facet. skipping -->\n";
log << " <!-- ZRemover Halffacet visit end-->\n";
return;
}
// possible optimization - throw out facets that are vertically oriented
CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator fci;
int contour_counter = 0;
CGAL_forall_facet_cycles_of( fci, hfacet ) {
if ( fci.is_shalfedge() ) {
log << " <!-- ZRemover Halffacet cycle begin -->\n";
CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(fci), cend(c1);
std::vector<CGAL_Nef_polyhedron2::Explorer::Point> contour;
CGAL_For_all( c1, cend ) {
CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->target()->point();
CGAL_Nef_polyhedron2::Explorer::Point point2d(CGAL::to_double(point3d.x()),
CGAL::to_double(point3d.y()));
contour.push_back( point2d );
}
if (contour.size()==0) continue;
log << " <!-- is_simple_2:" << CGAL::is_simple_2( contour.begin(), contour.end() ) << " --> \n";
tmpnef2d.reset( new CGAL_Nef_polyhedron2( contour.begin(), contour.end(), boundary ) );
if ( contour_counter == 0 ) {
log << " <!-- contour is a body. make union(). " << contour.size() << " points. -->\n" ;
*(output_nefpoly2d) += *(tmpnef2d);
} else {
log << " <!-- contour is a hole. make intersection(). " << contour.size() << " points. -->\n";
*(output_nefpoly2d) *= *(tmpnef2d);
}
/*log << "\n<!-- ======== output tmp nef: ==== -->\n"
<< OpenSCAD::dump_svg( *tmpnef2d ) << "\n"
<< "\n<!-- ======== output accumulator: ==== -->\n"
<< OpenSCAD::dump_svg( *output_nefpoly2d ) << "\n";*/
contour_counter++;
} else {
log << " <!-- ZRemover trivial facet cycle skipped -->\n";
}
log << " <!-- ZRemover Halffacet cycle end -->\n";
}
log << " <!-- ZRemover Halffacet visit end -->\n";
}
#endif /* ENABLE_CGAL */