2011-09-08 00:04:59 +04:00
# ifdef ENABLE_CGAL
# include "cgalutils.h"
# include "polyset.h"
# include "printutils.h"
2013-10-31 08:45:00 +04:00
# include "Polygon2d.h"
2013-11-25 09:28:26 +04:00
# include "polyset-utils.h"
2013-12-16 03:27:25 +04:00
# include "grid.h"
2012-10-28 21:37:27 +04:00
2011-09-08 00:04:59 +04:00
# include "cgal.h"
2013-11-24 04:52:03 +04:00
# include <CGAL/convex_hull_3.h>
2011-11-09 07:48:56 +04:00
2012-10-28 21:37:27 +04:00
# include <map>
2013-10-31 08:45:00 +04:00
# include <boost/foreach.hpp>
2012-10-28 21:37:27 +04:00
2013-12-02 10:48:22 +04:00
namespace CGALUtils {
bool applyHull ( const Geometry : : ChildList & children , CGAL_Polyhedron & result )
{
// Collect point cloud
std : : list < CGAL_Polyhedron : : Vertex : : Point_3 > points ;
CGAL_Polyhedron P ;
BOOST_FOREACH ( const Geometry : : ChildItem & item , children ) {
const shared_ptr < const Geometry > & chgeom = item . second ;
const CGAL_Nef_polyhedron * N = dynamic_cast < const CGAL_Nef_polyhedron * > ( chgeom . get ( ) ) ;
if ( N ) {
if ( ! N - > p3 - > is_simple ( ) ) {
PRINT ( " Hull() currently requires a valid 2-manifold. Please modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export " ) ;
}
else {
2013-12-14 20:15:19 +04:00
bool err = true ;
std : : string errmsg ( " " ) ;
try {
err = nefworkaround : : convert_to_Polyhedron < CGAL_Kernel3 > ( * ( N - > p3 ) , P ) ;
// N->p3->convert_to_Polyhedron(P);
}
catch ( const CGAL : : Failure_exception & e ) {
err = true ;
errmsg = std : : string ( e . what ( ) ) ;
}
if ( err ) {
PRINT ( " ERROR: CGAL NefPolyhedron->Polyhedron conversion failed. " ) ;
if ( errmsg ! = " " ) PRINTB ( " ERROR: %s " , errmsg ) ;
} else {
std : : transform ( P . vertices_begin ( ) , P . vertices_end ( ) , std : : back_inserter ( points ) ,
boost : : bind ( static_cast < const CGAL_Polyhedron : : Vertex : : Point_3 & ( CGAL_Polyhedron : : Vertex : : * ) ( ) const > ( & CGAL_Polyhedron : : Vertex : : point ) , _1 ) ) ;
}
2013-12-02 10:48:22 +04:00
}
}
else {
const PolySet * ps = dynamic_cast < const PolySet * > ( chgeom . get ( ) ) ;
BOOST_FOREACH ( const PolySet : : Polygon & p , ps - > polygons ) {
BOOST_FOREACH ( const Vector3d & v , p ) {
points . push_back ( CGAL_Polyhedron : : Vertex : : Point_3 ( v [ 0 ] , v [ 1 ] , v [ 2 ] ) ) ;
}
}
}
}
if ( points . size ( ) > 0 ) {
// Apply hull
if ( points . size ( ) > 3 ) {
CGAL : : convex_hull_3 ( points . begin ( ) , points . end ( ) , result ) ;
return true ;
}
}
return false ;
}
/*!
Modifies target by applying op to target and src :
target = target [ op ] src
*/
void applyBinaryOperator ( CGAL_Nef_polyhedron & target , const CGAL_Nef_polyhedron & src , OpenSCADOperator op )
{
if ( target . getDimension ( ) ! = 2 & & target . getDimension ( ) ! = 3 ) {
assert ( false & & " Dimension of Nef polyhedron must be 2 or 3 " ) ;
}
if ( src . isEmpty ( ) ) return ; // Empty polyhedron. This can happen for e.g. square([0,0])
if ( target . isEmpty ( ) & & op ! = OPENSCAD_UNION ) return ; // empty op <something> => empty
if ( target . getDimension ( ) ! = src . getDimension ( ) ) return ; // If someone tries to e.g. union 2d and 3d objects
CGAL : : Failure_behaviour old_behaviour = CGAL : : set_error_behaviour ( CGAL : : THROW_EXCEPTION ) ;
try {
switch ( op ) {
case OPENSCAD_UNION :
if ( target . isEmpty ( ) ) target = src . copy ( ) ;
else target + = src ;
break ;
case OPENSCAD_INTERSECTION :
target * = src ;
break ;
case OPENSCAD_DIFFERENCE :
target - = src ;
break ;
case OPENSCAD_MINKOWSKI :
target . minkowski ( src ) ;
break ;
default :
PRINTB ( " ERROR: Unsupported CGAL operator: %d " , op ) ;
}
}
catch ( const CGAL : : Failure_exception & e ) {
// union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad and testdata/scad/bugs/issue204.scad
std : : string opstr = op = = OPENSCAD_UNION ? " union " : op = = OPENSCAD_INTERSECTION ? " intersection " : op = = OPENSCAD_DIFFERENCE ? " difference " : op = = OPENSCAD_MINKOWSKI ? " minkowski " : " UNKNOWN " ;
2013-12-16 03:27:25 +04:00
PRINTB ( " CGAL error in CGALUtils::applyBinaryOperator %s: %s " , opstr % e . what ( ) ) ;
2013-12-02 10:48:22 +04:00
// Errors can result in corrupt polyhedrons, so put back the old one
target = src ;
}
CGAL : : set_error_behaviour ( old_behaviour ) ;
}
CGAL_Nef_polyhedron project ( const CGAL_Nef_polyhedron & N , bool cut )
{
logstream log ( 5 ) ;
CGAL_Nef_polyhedron nef_poly ( 2 ) ;
if ( N . getDimension ( ) ! = 3 ) return nef_poly ;
CGAL_Nef_polyhedron newN ;
if ( cut ) {
CGAL : : Failure_behaviour old_behaviour = CGAL : : set_error_behaviour ( CGAL : : THROW_EXCEPTION ) ;
try {
CGAL_Nef_polyhedron3 : : Plane_3 xy_plane = CGAL_Nef_polyhedron3 : : Plane_3 ( 0 , 0 , 1 , 0 ) ;
newN . p3 . reset ( new CGAL_Nef_polyhedron3 ( N . p3 - > intersection ( xy_plane , CGAL_Nef_polyhedron3 : : PLANE_ONLY ) ) ) ;
}
catch ( const CGAL : : Failure_exception & e ) {
2013-12-16 03:27:25 +04:00
PRINTB ( " CGALUtils::project during plane intersection: %s " , e . what ( ) ) ;
2013-12-02 10:48:22 +04:00
try {
PRINT ( " Trying alternative intersection using very large thin box: " ) ;
std : : vector < CGAL_Point_3 > pts ;
// dont use z of 0. there are bugs in CGAL.
double inf = 1e8 ;
double eps = 0.001 ;
CGAL_Point_3 minpt ( - inf , - inf , - eps ) ;
CGAL_Point_3 maxpt ( inf , inf , eps ) ;
CGAL_Iso_cuboid_3 bigcuboid ( minpt , maxpt ) ;
for ( int i = 0 ; i < 8 ; i + + ) pts . push_back ( bigcuboid . vertex ( i ) ) ;
CGAL_Polyhedron bigbox ;
CGAL : : convex_hull_3 ( pts . begin ( ) , pts . end ( ) , bigbox ) ;
CGAL_Nef_polyhedron3 nef_bigbox ( bigbox ) ;
newN . p3 . reset ( new CGAL_Nef_polyhedron3 ( nef_bigbox . intersection ( * N . p3 ) ) ) ;
}
catch ( const CGAL : : Failure_exception & e ) {
2013-12-16 03:27:25 +04:00
PRINTB ( " CGAL error in CGALUtils::project during bigbox intersection: %s " , e . what ( ) ) ;
2013-12-02 10:48:22 +04:00
}
}
if ( ! newN . p3 | | newN . p3 - > is_empty ( ) ) {
CGAL : : set_error_behaviour ( old_behaviour ) ;
PRINT ( " WARNING: projection() failed. " ) ;
return nef_poly ;
}
log < < OpenSCAD : : svg_header ( 480 , 100000 ) < < " \n " ;
try {
ZRemover zremover ;
CGAL_Nef_polyhedron3 : : Volume_const_iterator i ;
CGAL_Nef_polyhedron3 : : Shell_entry_const_iterator j ;
CGAL_Nef_polyhedron3 : : SFace_const_handle sface_handle ;
for ( i = newN . p3 - > volumes_begin ( ) ; i ! = newN . p3 - > volumes_end ( ) ; + + i ) {
log < < " <!-- volume. mark: " < < i - > mark ( ) < < " --> \n " ;
for ( j = i - > shells_begin ( ) ; j ! = i - > shells_end ( ) ; + + j ) {
log < < " <!-- shell. mark: " < < i - > mark ( ) < < " --> \n " ;
sface_handle = CGAL_Nef_polyhedron3 : : SFace_const_handle ( j ) ;
newN . p3 - > visit_shell_objects ( sface_handle , zremover ) ;
log < < " <!-- shell. end. --> \n " ;
}
log < < " <!-- volume end. --> \n " ;
}
nef_poly . p2 = zremover . output_nefpoly2d ;
} catch ( const CGAL : : Failure_exception & e ) {
2013-12-16 03:27:25 +04:00
PRINTB ( " CGAL error in CGALUtils::project while flattening: %s " , e . what ( ) ) ;
2013-12-02 10:48:22 +04:00
}
log < < " </svg> \n " ;
CGAL : : set_error_behaviour ( old_behaviour ) ;
}
// In projection mode all the triangles are projected manually into the XY plane
else {
PolySet * ps3 = N . convertToPolyset ( ) ;
if ( ! ps3 ) return nef_poly ;
const Polygon2d * poly = PolysetUtils : : project ( * ps3 ) ;
// FIXME: Convert back to Nef2 and delete poly?
/* if (nef_poly.isEmpty()) {
nef_poly . p2 . reset ( new CGAL_Nef_polyhedron2 ( plist . begin ( ) , plist . end ( ) , CGAL_Nef_polyhedron2 : : INCLUDED ) ) ;
}
else {
( * nef_poly . p2 ) + = CGAL_Nef_polyhedron2 ( plist . begin ( ) , plist . end ( ) , CGAL_Nef_polyhedron2 : : INCLUDED ) ;
}
*/
delete ps3 ;
}
return nef_poly ;
}
} ;
2013-12-15 07:12:01 +04:00
bool createPolySetFromPolyhedron ( const CGAL_Polyhedron & p , PolySet & ps )
2011-09-08 00:04:59 +04:00
{
2013-12-15 07:12:01 +04:00
bool err = false ;
2011-09-08 00:04:59 +04:00
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 ( ) ) ;
2013-12-15 07:12:01 +04:00
ps . append_poly ( ) ;
ps . append_vertex ( x1 , y1 , z1 ) ;
ps . append_vertex ( x2 , y2 , z2 ) ;
ps . append_vertex ( x3 , y3 , z3 ) ;
2011-09-08 00:04:59 +04:00
} while ( hc ! = hc_end ) ;
}
2013-12-15 07:12:01 +04:00
return err ;
2011-09-08 00:04:59 +04:00
}
# 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 ) ;
2013-12-16 03:27:25 +04:00
typedef boost : : tuple < double , double , double > BuilderVertex ;
typedef std : : map < BuilderVertex , size_t > BuilderMap ;
BuilderMap vertices ;
std : : vector < size_t > indices ( 3 ) ;
// Estimating same # of vertices as polygons (very rough)
B . begin_surface ( ps . polygons . size ( ) , ps . polygons . size ( ) ) ;
int pidx = 0 ;
printf ( " polyhedron(triangles=[ " ) ;
BOOST_FOREACH ( const PolySet : : Polygon & p , ps . polygons ) {
if ( pidx + + > 0 ) printf ( " , " ) ;
indices . clear ( ) ;
BOOST_FOREACH ( const Vector3d & v , p ) {
size_t idx ;
BuilderVertex bv = boost : : make_tuple ( v [ 0 ] , v [ 1 ] , v [ 2 ] ) ;
if ( vertices . count ( bv ) > 0 ) indices . push_back ( vertices [ bv ] ) ;
else {
indices . push_back ( vertices . size ( ) ) ;
vertices [ bv ] = vertices . size ( ) ;
B . add_vertex ( CGALPoint ( v [ 0 ] , v [ 1 ] , v [ 2 ] ) ) ;
2011-09-08 00:04:59 +04:00
}
}
2013-12-16 03:27:25 +04:00
B . begin_facet ( ) ;
printf ( " [ " ) ;
int fidx = 0 ;
BOOST_FOREACH ( size_t i , indices ) {
B . add_vertex_to_facet ( i ) ;
if ( fidx + + > 0 ) printf ( " , " ) ;
printf ( " %ld " , i ) ;
2011-09-08 00:04:59 +04:00
}
2013-12-16 03:27:25 +04:00
printf ( " ] " ) ;
B . end_facet ( ) ;
2011-09-08 00:04:59 +04:00
}
B . end_surface ( ) ;
2013-12-16 03:27:25 +04:00
printf ( " ], \n " ) ;
printf ( " points=[ " ) ;
int vidx = 0 ;
for ( int vidx = 0 ; vidx < vertices . size ( ) ; vidx + + ) {
if ( vidx > 0 ) printf ( " , " ) ;
const BuilderMap : : const_iterator it =
std : : find_if ( vertices . begin ( ) , vertices . end ( ) ,
boost : : bind ( & BuilderMap : : value_type : : second , _1 ) = = vidx ) ;
printf ( " [%g,%g,%g] " , it - > first . get < 0 > ( ) , it - > first . get < 1 > ( ) , it - > first . get < 2 > ( ) ) ;
}
printf ( " ]); \n " ) ;
2011-09-08 00:04:59 +04:00
}
} ;
2013-12-15 07:12:01 +04:00
bool createPolyhedronFromPolySet ( const PolySet & ps , CGAL_Polyhedron & p )
2011-09-08 00:04:59 +04:00
{
2013-12-15 07:12:01 +04:00
bool err = false ;
2011-09-08 00:04:59 +04:00
CGAL : : Failure_behaviour old_behaviour = CGAL : : set_error_behaviour ( CGAL : : THROW_EXCEPTION ) ;
try {
CGAL_Build_PolySet builder ( ps ) ;
2013-12-15 07:12:01 +04:00
p . delegate ( builder ) ;
2011-09-08 00:04:59 +04:00
}
2012-10-09 04:49:02 +04:00
catch ( const CGAL : : Assertion_exception & e ) {
2013-12-16 03:27:25 +04:00
PRINTB ( " CGAL error in CGALUtils::createPolyhedronFromPolySet: %s " , e . what ( ) ) ;
2013-12-15 07:12:01 +04:00
err = true ;
2011-09-08 00:04:59 +04:00
}
2011-11-27 02:31:11 +04:00
CGAL : : set_error_behaviour ( old_behaviour ) ;
2013-12-15 07:12:01 +04:00
return err ;
2011-09-08 00:04:59 +04:00
}
2012-10-21 21:10:06 +04:00
CGAL_Iso_cuboid_3 bounding_box ( const CGAL_Nef_polyhedron3 & N )
{
2013-03-10 06:28:43 +04:00
CGAL_Iso_cuboid_3 result ( 0 , 0 , 0 , 0 , 0 , 0 ) ;
2012-10-21 21:10:06 +04:00
CGAL_Nef_polyhedron3 : : Vertex_const_iterator vi ;
std : : vector < CGAL_Nef_polyhedron3 : : Point_3 > points ;
2012-10-28 17:56:23 +04:00
// can be optimized by rewriting bounding_box to accept vertices
2012-10-21 21:10:06 +04:00
CGAL_forall_vertices ( vi , N )
points . push_back ( vi - > point ( ) ) ;
if ( points . size ( ) )
result = CGAL : : bounding_box ( points . begin ( ) , points . end ( ) ) ;
return result ;
}
2012-10-28 17:56:23 +04:00
CGAL_Iso_rectangle_2e bounding_box ( const CGAL_Nef_polyhedron2 & N )
2012-10-21 21:10:06 +04:00
{
2013-03-10 06:28:43 +04:00
CGAL_Iso_rectangle_2e result ( 0 , 0 , 0 , 0 ) ;
2012-10-28 17:56:23 +04:00
CGAL_Nef_polyhedron2 : : Explorer explorer = N . explorer ( ) ;
2012-10-21 21:10:06 +04:00
CGAL_Nef_polyhedron2 : : Explorer : : Vertex_const_iterator vi ;
2012-10-28 17:56:23 +04:00
std : : vector < CGAL_Point_2e > points ;
// can be optimized by rewriting bounding_box to accept vertices
2012-10-21 21:10:06 +04:00
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 ;
}
2012-10-16 05:17:12 +04:00
2013-03-11 06:35:30 +04:00
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 ( ) ;
2013-05-24 21:58:52 +04:00
CGAL_Nef_polyhedron2 : : Explorer : : Point point2d ( CGAL : : to_double ( point3d . x ( ) ) ,
CGAL : : to_double ( point3d . y ( ) ) ) ;
2013-03-11 06:35:30 +04:00
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 " ;
}
2013-11-21 10:25:15 +04:00
static CGAL_Nef_polyhedron * createNefPolyhedronFromPolySet ( const PolySet & ps )
2013-10-31 08:45:00 +04:00
{
2013-11-21 10:25:15 +04:00
if ( ps . empty ( ) ) return new CGAL_Nef_polyhedron ( ps . is2d ? 2 : 3 ) ;
2013-10-31 08:45:00 +04:00
if ( ps . is2d )
{
#if 0
// This version of the code causes problems in some cases.
// Example testcase: import_dxf("testdata/polygon8.dxf");
//
typedef std : : list < CGAL_Nef_polyhedron2 : : Point > point_list_t ;
typedef point_list_t : : iterator point_list_it ;
std : : list < point_list_t > pdata_point_lists ;
std : : list < std : : pair < point_list_it , point_list_it > > pdata ;
Grid2d < CGAL_Nef_polyhedron2 : : Point > grid ( GRID_COARSE ) ;
2013-12-16 06:53:24 +04:00
2013-10-31 08:45:00 +04:00
for ( int i = 0 ; i < ps . polygons . size ( ) ; i + + ) {
pdata_point_lists . push_back ( point_list_t ( ) ) ;
for ( int j = 0 ; j < ps . polygons [ i ] . size ( ) ; j + + ) {
double x = ps . polygons [ i ] [ j ] . x ;
double y = ps . polygons [ i ] [ j ] . y ;
CGAL_Nef_polyhedron2 : : Point p ;
if ( grid . has ( x , y ) ) {
p = grid . data ( x , y ) ;
} else {
p = CGAL_Nef_polyhedron2 : : Point ( x , y ) ;
grid . data ( x , y ) = p ;
}
pdata_point_lists . back ( ) . push_back ( p ) ;
}
pdata . push_back ( std : : make_pair ( pdata_point_lists . back ( ) . begin ( ) ,
pdata_point_lists . back ( ) . end ( ) ) ) ;
}
CGAL_Nef_polyhedron2 N ( pdata . begin ( ) , pdata . end ( ) , CGAL_Nef_polyhedron2 : : POLYGONS ) ;
2013-11-21 10:25:15 +04:00
return new CGAL_Nef_polyhedron ( N ) ;
2013-10-31 08:45:00 +04:00
# endif
#if 0
// This version of the code works fine but is pretty slow.
//
CGAL_Nef_polyhedron2 N ;
Grid2d < CGAL_Nef_polyhedron2 : : Point > grid ( GRID_COARSE ) ;
for ( int i = 0 ; i < ps . polygons . size ( ) ; i + + ) {
std : : list < CGAL_Nef_polyhedron2 : : Point > plist ;
for ( int j = 0 ; j < ps . polygons [ i ] . size ( ) ; j + + ) {
double x = ps . polygons [ i ] [ j ] . x ;
double y = ps . polygons [ i ] [ j ] . y ;
CGAL_Nef_polyhedron2 : : Point p ;
if ( grid . has ( x , y ) ) {
p = grid . data ( x , y ) ;
} else {
p = CGAL_Nef_polyhedron2 : : Point ( x , y ) ;
grid . data ( x , y ) = p ;
}
plist . push_back ( p ) ;
}
N + = CGAL_Nef_polyhedron2 ( plist . begin ( ) , plist . end ( ) , CGAL_Nef_polyhedron2 : : INCLUDED ) ;
}
2013-11-21 10:25:15 +04:00
return new CGAL_Nef_polyhedron ( N ) ;
2013-10-31 08:45:00 +04:00
# endif
# if 1
// This version of the code does essentially the same thing as the 2nd
// version but merges some triangles before sending them to CGAL. This adds
// complexity but speeds up things..
//
struct PolyReducer
{
Grid2d < int > grid ;
std : : map < std : : pair < int , int > , std : : pair < int , int > > edge_to_poly ;
std : : map < int , CGAL_Nef_polyhedron2 : : Point > points ;
typedef std : : map < int , std : : vector < int > > PolygonMap ;
PolygonMap polygons ;
int poly_n ;
void add_edges ( int pn )
{
for ( unsigned int j = 1 ; j < = this - > polygons [ pn ] . size ( ) ; j + + ) {
int a = this - > polygons [ pn ] [ j - 1 ] ;
int b = this - > polygons [ pn ] [ j % this - > polygons [ pn ] . size ( ) ] ;
if ( a > b ) { a = a ^ b ; b = a ^ b ; a = a ^ b ; }
if ( this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . first = = 0 )
this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . first = pn ;
else if ( this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . second = = 0 )
this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . second = pn ;
else
abort ( ) ;
}
}
void del_poly ( int pn )
{
for ( unsigned int j = 1 ; j < = this - > polygons [ pn ] . size ( ) ; j + + ) {
int a = this - > polygons [ pn ] [ j - 1 ] ;
int b = this - > polygons [ pn ] [ j % this - > polygons [ pn ] . size ( ) ] ;
if ( a > b ) { a = a ^ b ; b = a ^ b ; a = a ^ b ; }
if ( this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . first = = pn )
this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . first = 0 ;
if ( this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . second = = pn )
this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . second = 0 ;
}
this - > polygons . erase ( pn ) ;
}
PolyReducer ( const PolySet & ps ) : grid ( GRID_COARSE ) , poly_n ( 1 )
{
int point_n = 1 ;
for ( size_t i = 0 ; i < ps . polygons . size ( ) ; i + + ) {
for ( size_t j = 0 ; j < ps . polygons [ i ] . size ( ) ; j + + ) {
double x = ps . polygons [ i ] [ j ] [ 0 ] ;
double y = ps . polygons [ i ] [ j ] [ 1 ] ;
if ( this - > grid . has ( x , y ) ) {
int idx = this - > grid . data ( x , y ) ;
// Filter away two vertices with the same index (due to grid)
// This could be done in a more general way, but we'd rather redo the entire
// grid concept instead.
std : : vector < int > & poly = this - > polygons [ this - > poly_n ] ;
if ( std : : find ( poly . begin ( ) , poly . end ( ) , idx ) = = poly . end ( ) ) {
poly . push_back ( this - > grid . data ( x , y ) ) ;
}
} else {
this - > grid . align ( x , y ) = point_n ;
this - > polygons [ this - > poly_n ] . push_back ( point_n ) ;
this - > points [ point_n ] = CGAL_Nef_polyhedron2 : : Point ( x , y ) ;
point_n + + ;
}
}
if ( this - > polygons [ this - > poly_n ] . size ( ) > = 3 ) {
add_edges ( this - > poly_n ) ;
this - > poly_n + + ;
}
else {
this - > polygons . erase ( this - > poly_n ) ;
}
}
}
int merge ( int p1 , int p1e , int p2 , int p2e )
{
for ( unsigned int i = 1 ; i < this - > polygons [ p1 ] . size ( ) ; i + + ) {
int j = ( p1e + i ) % this - > polygons [ p1 ] . size ( ) ;
this - > polygons [ this - > poly_n ] . push_back ( this - > polygons [ p1 ] [ j ] ) ;
}
for ( unsigned int i = 1 ; i < this - > polygons [ p2 ] . size ( ) ; i + + ) {
int j = ( p2e + i ) % this - > polygons [ p2 ] . size ( ) ;
this - > polygons [ this - > poly_n ] . push_back ( this - > polygons [ p2 ] [ j ] ) ;
}
del_poly ( p1 ) ;
del_poly ( p2 ) ;
add_edges ( this - > poly_n ) ;
return this - > poly_n + + ;
}
void reduce ( )
{
std : : deque < int > work_queue ;
BOOST_FOREACH ( const PolygonMap : : value_type & i , polygons ) {
work_queue . push_back ( i . first ) ;
}
while ( ! work_queue . empty ( ) ) {
int poly1_n = work_queue . front ( ) ;
work_queue . pop_front ( ) ;
if ( this - > polygons . find ( poly1_n ) = = this - > polygons . end ( ) ) continue ;
for ( unsigned int j = 1 ; j < = this - > polygons [ poly1_n ] . size ( ) ; j + + ) {
int a = this - > polygons [ poly1_n ] [ j - 1 ] ;
int b = this - > polygons [ poly1_n ] [ j % this - > polygons [ poly1_n ] . size ( ) ] ;
if ( a > b ) { a = a ^ b ; b = a ^ b ; a = a ^ b ; }
if ( this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . first ! = 0 & &
this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . second ! = 0 ) {
int poly2_n = this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . first +
this - > edge_to_poly [ std : : pair < int , int > ( a , b ) ] . second - poly1_n ;
int poly2_edge = - 1 ;
for ( unsigned int k = 1 ; k < = this - > polygons [ poly2_n ] . size ( ) ; k + + ) {
int c = this - > polygons [ poly2_n ] [ k - 1 ] ;
int d = this - > polygons [ poly2_n ] [ k % this - > polygons [ poly2_n ] . size ( ) ] ;
if ( c > d ) { c = c ^ d ; d = c ^ d ; c = c ^ d ; }
if ( a = = c & & b = = d ) {
poly2_edge = k - 1 ;
continue ;
}
int poly3_n = this - > edge_to_poly [ std : : pair < int , int > ( c , d ) ] . first +
this - > edge_to_poly [ std : : pair < int , int > ( c , d ) ] . second - poly2_n ;
if ( poly3_n < 0 )
continue ;
if ( poly3_n = = poly1_n )
goto next_poly1_edge ;
}
work_queue . push_back ( merge ( poly1_n , j - 1 , poly2_n , poly2_edge ) ) ;
goto next_poly1 ;
}
next_poly1_edge : ;
}
next_poly1 : ;
}
}
CGAL_Nef_polyhedron2 * toNef ( )
{
CGAL_Nef_polyhedron2 * N = new CGAL_Nef_polyhedron2 ;
BOOST_FOREACH ( const PolygonMap : : value_type & i , polygons ) {
std : : list < CGAL_Nef_polyhedron2 : : Point > plist ;
for ( unsigned int j = 0 ; j < i . second . size ( ) ; j + + ) {
int p = i . second [ j ] ;
plist . push_back ( points [ p ] ) ;
}
* N + = CGAL_Nef_polyhedron2 ( plist . begin ( ) , plist . end ( ) , CGAL_Nef_polyhedron2 : : INCLUDED ) ;
}
return N ;
}
} ;
PolyReducer pr ( ps ) ;
pr . reduce ( ) ;
2013-11-21 10:25:15 +04:00
return new CGAL_Nef_polyhedron ( pr . toNef ( ) ) ;
2013-10-31 08:45:00 +04:00
# endif
#if 0
// This is another experimental version. I should run faster than the above,
// is a lot simpler and has only one known weakness: Degenerate polygons, which
// get repaired by GLUTess, might trigger a CGAL crash here. The only
// known case for this is triangle-with-duplicate-vertex.dxf
// FIXME: If we just did a projection, we need to recreate the border!
if ( ps . polygons . size ( ) > 0 ) assert ( ps . borders . size ( ) > 0 ) ;
CGAL_Nef_polyhedron2 N ;
Grid2d < CGAL_Nef_polyhedron2 : : Point > grid ( GRID_COARSE ) ;
for ( int i = 0 ; i < ps . borders . size ( ) ; i + + ) {
std : : list < CGAL_Nef_polyhedron2 : : Point > plist ;
for ( int j = 0 ; j < ps . borders [ i ] . size ( ) ; j + + ) {
double x = ps . borders [ i ] [ j ] . x ;
double y = ps . borders [ i ] [ j ] . y ;
CGAL_Nef_polyhedron2 : : Point p ;
if ( grid . has ( x , y ) ) {
p = grid . data ( x , y ) ;
} else {
p = CGAL_Nef_polyhedron2 : : Point ( x , y ) ;
grid . data ( x , y ) = p ;
}
plist . push_back ( p ) ;
}
// FIXME: If a border (path) has a duplicate vertex in dxf,
// the CGAL_Nef_polyhedron2 constructor will crash.
N ^ = CGAL_Nef_polyhedron2 ( plist . begin ( ) , plist . end ( ) , CGAL_Nef_polyhedron2 : : INCLUDED ) ;
}
2013-11-21 10:25:15 +04:00
return new CGAL_Nef_polyhedron ( N ) ;
2013-10-31 08:45:00 +04:00
# endif
}
else // not (this->is2d)
{
CGAL_Nef_polyhedron3 * N = NULL ;
2013-12-16 06:53:24 +04:00
bool plane_error = false ;
2013-10-31 08:45:00 +04:00
CGAL : : Failure_behaviour old_behaviour = CGAL : : set_error_behaviour ( CGAL : : THROW_EXCEPTION ) ;
try {
2013-12-16 06:53:24 +04:00
CGAL_Polyhedron P ;
bool err = createPolyhedronFromPolySet ( ps , P ) ;
if ( ! err ) N = new CGAL_Nef_polyhedron3 ( P ) ;
}
catch ( const CGAL : : Assertion_exception & e ) {
if ( std : : string ( e . what ( ) ) . find ( " Plane_constructor " ) ! = std : : string : : npos ) {
if ( std : : string ( e . what ( ) ) . find ( " has_on " ) ! = std : : string : : npos ) {
PRINT ( " PolySet has nonplanar faces. Attempting alternate construction " ) ;
plane_error = true ;
}
} else {
PRINTB ( " CGAL error in CGAL_Nef_polyhedron3(): %s " , e . what ( ) ) ;
2013-10-31 08:45:00 +04:00
}
}
2013-12-16 06:53:24 +04:00
if ( plane_error ) try {
PolySet ps2 ;
CGAL_Polyhedron P ;
PolysetUtils : : tessellate_faces ( ps , ps2 ) ;
bool err = createPolyhedronFromPolySet ( ps2 , P ) ;
if ( ! err ) N = new CGAL_Nef_polyhedron3 ( P ) ;
}
2013-10-31 08:45:00 +04:00
catch ( const CGAL : : Assertion_exception & e ) {
2013-12-16 06:53:24 +04:00
PRINTB ( " Alternate construction failed. CGAL error in CGAL_Nef_polyhedron3(): %s " , e . what ( ) ) ;
2013-10-31 08:45:00 +04:00
}
CGAL : : set_error_behaviour ( old_behaviour ) ;
2013-11-21 10:25:15 +04:00
return new CGAL_Nef_polyhedron ( N ) ;
2013-10-31 08:45:00 +04:00
}
2013-11-21 10:25:15 +04:00
return NULL ;
2013-10-31 08:45:00 +04:00
}
2013-11-21 10:25:15 +04:00
static CGAL_Nef_polyhedron * createNefPolyhedronFromPolygon2d ( const Polygon2d & polygon )
2013-10-31 08:45:00 +04:00
{
shared_ptr < PolySet > ps ( polygon . tessellate ( ) ) ;
return createNefPolyhedronFromPolySet ( * ps ) ;
}
2013-11-21 10:25:15 +04:00
CGAL_Nef_polyhedron * createNefPolyhedronFromGeometry ( const Geometry & geom )
2013-10-31 08:45:00 +04:00
{
const PolySet * ps = dynamic_cast < const PolySet * > ( & geom ) ;
if ( ps ) {
return createNefPolyhedronFromPolySet ( * ps ) ;
}
else {
const Polygon2d * poly2d = dynamic_cast < const Polygon2d * > ( & geom ) ;
if ( poly2d ) return createNefPolyhedronFromPolygon2d ( * poly2d ) ;
}
2013-12-22 10:43:08 +04:00
assert ( false & & " createNefPolyhedronFromGeometry(): Unsupported geometry type " ) ;
2013-11-21 10:25:15 +04:00
return NULL ;
2013-10-31 08:45:00 +04:00
}
2011-09-08 00:04:59 +04:00
# endif /* ENABLE_CGAL */