2019-09-01 16:29:00 +02:00
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
2020-06-11 20:51:08 +02:00
# define _USE_MATH_DEFINES
# include <cmath>
2017-01-16 11:53:11 +01:00
# include "CgalKernel.h"
2019-09-01 16:29:00 +02:00
# include "../../../ifcparse/IfcLogger.h"
# include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h"
2019-09-25 15:30:11 +02:00
# include <CGAL/minkowski_sum_3.h>
2020-07-29 12:21:30 +02:00
# include <CGAL/exceptions.h>
2019-09-25 15:30:11 +02:00
2019-09-01 16:29:00 +02:00
using namespace ifcopenshell : : geometry ;
using namespace ifcopenshell : : geometry : : kernels ;
void CgalKernel : : remove_duplicate_points_from_loop ( cgal_wire_t & polygon ) {
std : : set < cgal_point_t > points ;
for ( int i = 0 ; i < polygon . size ( ) ; + + i ) {
if ( points . count ( polygon [ i ] ) ) {
polygon . erase ( polygon . begin ( ) + i ) ;
- - i ;
} else points . insert ( polygon [ i ] ) ;
}
}
2020-01-21 16:26:00 +01:00
CGAL : : Polyhedron_3 < Kernel_ > ifcopenshell : : geometry : : utils : : create_polyhedron ( std : : list < cgal_face_t > & face_list ) {
2019-09-01 16:29:00 +02:00
// Naive creation
CGAL : : Polyhedron_3 < Kernel_ > polyhedron ;
PolyhedronBuilder builder ( & face_list ) ;
polyhedron . delegate ( builder ) ;
// Stitch edges
// std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
CGAL : : Polygon_mesh_processing : : stitch_borders ( polyhedron ) ;
2020-07-29 12:01:19 +02:00
polyhedron . normalize_border ( ) ;
if ( ! polyhedron . is_valid ( false , 1 ) ) {
2019-09-01 16:29:00 +02:00
Logger : : Message ( Logger : : LOG_ERROR , " create_polyhedron: Polyhedron not valid! " ) ;
// std::ofstream fresult;
// fresult.open("/Users/ken/Desktop/invalid.off");
// fresult << polyhedron << std::endl;
// fresult.close();
return CGAL : : Polyhedron_3 < Kernel_ > ( ) ;
} if ( polyhedron . is_closed ( ) ) {
2020-07-29 12:21:30 +02:00
try {
if ( ! CGAL : : Polygon_mesh_processing : : is_outward_oriented ( polyhedron ) ) {
CGAL : : Polygon_mesh_processing : : reverse_face_orientations ( polyhedron ) ;
}
} catch ( CGAL : : Failure_exception & e ) {
Logger : : Message ( Logger : : LOG_ERROR , e ) ;
2019-01-18 15:19:00 +01:00
}
2019-09-01 16:29:00 +02:00
}
// std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
return polyhedron ;
}
2020-01-21 16:26:00 +01:00
CGAL : : Polyhedron_3 < Kernel_ > ifcopenshell : : geometry : : utils : : create_polyhedron ( const CGAL : : Nef_polyhedron_3 < Kernel_ > & nef_polyhedron ) {
2019-09-01 16:29:00 +02:00
if ( nef_polyhedron . is_simple ( ) ) {
try {
CGAL : : Polyhedron_3 < Kernel_ > polyhedron ;
nef_polyhedron . convert_to_polyhedron ( polyhedron ) ;
return polyhedron ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Conversion from Nef to polyhedron failed! " ) ;
return CGAL : : Polyhedron_3 < Kernel_ > ( ) ;
}
} else {
Logger : : Message ( Logger : : LOG_ERROR , " Nef polyhedron not simple: cannot create polyhedron! " ) ;
return CGAL : : Polyhedron_3 < Kernel_ > ( ) ;
}
2019-01-18 15:19:00 +01:00
}
2020-01-21 16:26:00 +01:00
CGAL : : Nef_polyhedron_3 < Kernel_ > ifcopenshell : : geometry : : utils : : create_nef_polyhedron ( std : : list < cgal_face_t > & face_list ) {
2019-09-01 16:29:00 +02:00
CGAL : : Polyhedron_3 < Kernel_ > polyhedron = create_polyhedron ( face_list ) ;
CGAL : : Polygon_mesh_processing : : triangulate_faces ( polyhedron ) ;
CGAL : : Nef_polyhedron_3 < Kernel_ > nef_polyhedron ;
try {
nef_polyhedron = CGAL : : Nef_polyhedron_3 < Kernel_ > ( polyhedron ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Conversion to Nef polyhedron failed! " ) ;
2020-01-21 16:26:00 +01:00
}
return nef_polyhedron ;
2019-01-18 15:19:00 +01:00
}
2020-01-21 16:26:00 +01:00
CGAL : : Nef_polyhedron_3 < Kernel_ > ifcopenshell : : geometry : : utils : : create_nef_polyhedron ( CGAL : : Polyhedron_3 < Kernel_ > & polyhedron ) {
2020-07-23 12:14:20 +02:00
// @todo needed?
polyhedron . normalize_border ( ) ;
if ( polyhedron . is_valid ( false , 3 ) & & polyhedron . is_closed ( ) ) {
2020-01-26 13:58:02 +01:00
// @todo is it necessary to triangulat?
2019-09-01 16:29:00 +02:00
CGAL : : Polygon_mesh_processing : : triangulate_faces ( polyhedron ) ;
CGAL : : Nef_polyhedron_3 < Kernel_ > nef_polyhedron ;
try {
nef_polyhedron = CGAL : : Nef_polyhedron_3 < Kernel_ > ( polyhedron ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Conversion to Nef polyhedron failed! " ) ;
2020-01-21 16:26:00 +01:00
}
return nef_polyhedron ;
2017-01-16 11:53:11 +01:00
} else {
2019-09-01 16:29:00 +02:00
Logger : : Message ( Logger : : LOG_ERROR , " Polyhedron not valid: cannot create Nef polyhedron! " ) ;
return CGAL : : Nef_polyhedron_3 < Kernel_ > ( ) ;
2017-01-16 11:53:11 +01:00
}
}
2019-09-01 16:29:00 +02:00
bool CgalKernel : : convert ( const taxonomy : : shell * l , cgal_shape_t & shape ) {
auto faces = l - > children_as < taxonomy : : face > ( ) ;
std : : list < cgal_face_t > face_list ;
for ( auto & f : faces ) {
bool success = false ;
cgal_face_t face ;
try {
success = convert ( f , face ) ;
} catch ( . . . ) { }
if ( ! success ) {
Logger : : Message ( Logger : : LOG_WARNING , " Failed to convert face: " , f - > instance ) ;
continue ;
}
// std::cout << "Face in ConnectedFaceSet: " << std::endl;
// for (auto &point: face.outer) {
// std::cout << "\tPoint(" << point << ")" << std::endl;
// }
face_list . push_back ( face ) ;
}
2020-01-21 16:26:00 +01:00
shape = utils : : create_polyhedron ( face_list ) ;
2019-09-01 16:29:00 +02:00
return true ;
2017-01-16 11:53:11 +01:00
}
2019-09-01 16:29:00 +02:00
bool CgalKernel : : convert ( const taxonomy : : face * face , cgal_face_t & result ) {
auto bounds = face - > children_as < taxonomy : : loop > ( ) ;
int num_outer_bounds = 0 ;
for ( auto & bound : bounds ) {
if ( bound - > external . get_value_or ( false ) ) num_outer_bounds + + ;
}
if ( num_outer_bounds ! = 1 ) {
Logger : : Message ( Logger : : LOG_ERROR , " Invalid configuration of boundaries for: " , face - > instance ) ;
return false ;
}
cgal_face_t mf ;
for ( auto & bound : bounds ) {
const bool is_interior = ! bound - > external . get_value_or ( false ) ;
cgal_wire_t wire ;
if ( ! convert ( bound , wire ) ) {
Logger : : Message ( Logger : : LOG_ERROR , " Failed to process face boundary loop " , bound - > instance ) ;
return false ;
}
if ( ! is_interior ) {
mf . outer = wire ;
} else {
mf . inner . push_back ( wire ) ;
}
}
result = mf ;
// std::cout << "Face: " << std::endl;
// for (auto &point: face.outer) {
// std::cout << "\tPoint(" << point << ")" << std::endl;
// }
return true ;
2017-01-16 11:53:11 +01:00
}
2019-01-18 16:43:38 +01:00
2019-09-24 15:46:50 +02:00
namespace {
2020-06-11 20:48:35 +02:00
// @todo obsolete?
2019-09-24 15:46:50 +02:00
bool convert_curve ( CgalKernel * kernel , const taxonomy : : item * curve , cgal_wire_t & builder ) {
if ( curve - > kind ( ) = = taxonomy : : EDGE ) {
auto e = ( taxonomy : : edge * ) curve ;
if ( true | | e - > basis = = nullptr ) {
if ( builder . empty ( ) ) {
const auto & p = boost : : get < taxonomy : : point3 > ( e - > start ) ;
2020-06-11 20:48:35 +02:00
cgal_point_t pnt ( ( * p . components ) ( 0 ) , ( * p . components ) ( 1 ) , ( * p . components ) ( 2 ) ) ;
2019-09-24 15:46:50 +02:00
builder . push_back ( pnt ) ;
}
const auto & p = boost : : get < taxonomy : : point3 > ( e - > end ) ;
2020-06-11 20:48:35 +02:00
cgal_point_t pnt ( ( * p . components ) ( 0 ) , ( * p . components ) ( 1 ) , ( * p . components ) ( 2 ) ) ;
2019-09-24 15:46:50 +02:00
builder . push_back ( pnt ) ;
} else if ( e - > basis - > kind ( ) = = taxonomy : : CIRCLE ) {
// @todo
} else if ( e - > basis - > kind ( ) = = taxonomy : : ELLIPSE ) {
} else {
throw std : : runtime_error ( " Not implemented basis kind " ) ;
}
} else if ( curve - > kind ( ) = = taxonomy : : LOOP ) {
const auto & edges = ( ( taxonomy : : loop * ) curve ) - > children ;
for ( auto & c : edges ) {
convert_curve ( kernel , c , builder ) ;
}
} else {
throw std : : runtime_error ( " Not implemented curve " ) ;
}
}
}
2020-06-11 20:51:08 +02:00
namespace {
typedef std : : pair < double , double > parameter_range ;
static const parameter_range unbounded = {
- std : : numeric_limits < double > : : infinity ( ) ,
+ std : : numeric_limits < double > : : infinity ( )
} ;
void evaluate_curve ( const taxonomy : : line & c , double u , taxonomy : : point3 & p ) {
Eigen : : Vector4d xy { u , 0 , 0 , 1. } ;
* p . components = ( * c . matrix . components * xy ) . head < 3 > ( ) ;
}
void evaluate_curve ( const taxonomy : : circle & c , double u , taxonomy : : point3 & p ) {
Eigen : : Vector4d xy { c . radius * std : : cos ( u ) , c . radius * std : : sin ( u ) , 0 , 1. } ;
* p . components = ( * c . matrix . components * xy ) . head < 3 > ( ) ;
}
void evaluate_curve ( const taxonomy : : ellipse & c , double u , taxonomy : : point3 & p ) {
Eigen : : Vector4d xy { c . radius * std : : cos ( u ) , c . radius2 * std : : sin ( u ) , 0 , 1. } ;
* p . components = ( * c . matrix . components * xy ) . head < 3 > ( ) ;
}
// ----
void project_onto_curve ( const taxonomy : : line & c , const taxonomy : : point3 & p , double & u ) {
u = ( c . matrix . components - > inverse ( ) * p . components - > homogeneous ( ) ) ( 0 ) ;
}
void project_onto_curve ( const taxonomy : : circle & c , const taxonomy : : point3 & p , double & u ) {
Eigen : : Vector2d xy = ( c . matrix . components - > inverse ( ) * p . components - > homogeneous ( ) ) . head < 2 > ( ) ;
u = std : : atan2 ( xy ( 1 ) , xy ( 0 ) ) ;
}
void project_onto_curve ( const taxonomy : : ellipse & c , const taxonomy : : point3 & p , double & u ) {
Eigen : : Vector2d xy = ( c . matrix . components - > inverse ( ) * p . components - > homogeneous ( ) ) . head < 2 > ( ) ;
u = std : : atan2 ( xy ( 1 ) , xy ( 0 ) ) ;
}
struct point_projection_visitor_ {
taxonomy : : point3 p ;
double u ;
2020-07-15 13:48:42 +00:00
typedef void result_type ;
2020-06-11 20:51:08 +02:00
void operator ( ) ( const taxonomy : : line & c ) {
project_onto_curve ( c , p , u ) ;
}
void operator ( ) ( const taxonomy : : circle & c ) {
project_onto_curve ( c , p , u ) ;
}
void operator ( ) ( const taxonomy : : ellipse & c ) {
project_onto_curve ( c , p , u ) ;
}
void operator ( ) ( const taxonomy : : item & c ) {
throw std : : runtime_error ( " Point projection not implemented on this geometry type " ) ;
}
} ;
struct point_projection_visitor {
taxonomy : : item * curve ;
double u ;
2020-07-15 13:48:42 +00:00
typedef void result_type ;
2020-06-11 20:51:08 +02:00
void operator ( ) ( const taxonomy : : point3 & p ) {
point_projection_visitor_ v { p } ;
dispatch_curve_creation < point_projection_visitor_ > : : dispatch ( curve , v ) ;
u = v . u ;
}
void operator ( ) ( const double & u ) {
this - > u = u ;
}
} ;
struct cgal_curve_creation_visitor {
static const int FULL_CIRCLE_NUM_SEGMENTS = 32 ;
parameter_range param ;
std : : vector < taxonomy : : point3 > points ;
cgal_curve_creation_visitor ( ) : param ( unbounded ) { }
cgal_curve_creation_visitor ( const parameter_range & p ) : param ( p ) { }
void operator ( ) ( const taxonomy : : line & l ) {
if ( param = = unbounded ) {
throw std : : runtime_error ( " Cannot represent infinite line segment " ) ;
}
taxonomy : : point3 start , end ;
evaluate_curve ( l , param . first , start ) ;
evaluate_curve ( l , param . second , end ) ;
points . push_back ( start ) ;
points . push_back ( end ) ;
}
template < typename T >
void evaluate_conic ( const T & t ) {
double a , b ;
if ( param = = unbounded ) {
a = 0. ;
b = 2 * M_PI ;
} else {
std : : tie ( a , b ) = param ;
}
2020-07-25 09:12:39 +02:00
a = std : : fmod ( a , 2 * M_PI ) ;
b = std : : fmod ( b , 2 * M_PI ) ;
if ( b < a ) {
b + = 2 * M_PI ;
}
2020-06-11 20:51:08 +02:00
int num_segments = ( int ) std : : ceil ( std : : fabs ( a - b ) / ( 2 * M_PI ) * FULL_CIRCLE_NUM_SEGMENTS ) ;
double du = ( b - a ) / num_segments ;
taxonomy : : point3 P ;
// @nb for loop is not inclusive of the both end points
evaluate_curve ( t , a , P ) ;
points . push_back ( P ) ;
for ( int i = 1 ; i < num_segments ; + + i ) {
double u = a + du * i ;
evaluate_curve ( t , u , P ) ;
points . push_back ( P ) ;
}
evaluate_curve ( t , b , P ) ;
points . push_back ( P ) ;
}
void operator ( ) ( const taxonomy : : circle & c ) {
evaluate_conic ( c ) ;
}
void operator ( ) ( const taxonomy : : ellipse & e ) {
evaluate_conic ( e ) ;
}
void operator ( ) ( const taxonomy : : trimmed_curve & e ) {
2020-07-26 15:35:10 +02:00
point_projection_visitor v1 { e . basis } , v2 { e . basis } ;
2020-06-11 20:51:08 +02:00
boost : : apply_visitor ( v1 , e . start ) ;
boost : : apply_visitor ( v2 , e . end ) ;
2020-07-25 09:12:39 +02:00
if ( ! e . orientation . get_value_or ( true ) ) {
std : : swap ( v1 . u , v2 . u ) ;
}
2020-06-11 20:51:08 +02:00
cgal_curve_creation_visitor v ( { v1 . u , v2 . u } ) ;
dispatch_curve_creation < cgal_curve_creation_visitor > : : dispatch ( e . basis , v ) ;
this - > points = v . points ;
2020-07-26 17:17:01 +02:00
if ( ! e . orientation . get_value_or ( true ) ) {
std : : reverse ( this - > points . begin ( ) , this - > points . end ( ) ) ;
}
2020-06-11 20:51:08 +02:00
}
void operator ( ) ( const taxonomy : : item & e ) {
throw std : : runtime_error ( " Not supported " ) ;
}
} ;
void convert_curve ( taxonomy : : item * i , std : : vector < taxonomy : : point3 > & points ) {
cgal_curve_creation_visitor v ;
dispatch_curve_creation < cgal_curve_creation_visitor > : : dispatch ( i , v ) ;
points = v . points ;
}
// @nb mutates a
void extend_wire ( std : : vector < taxonomy : : point3 > & a , const std : : vector < taxonomy : : point3 > & b ) {
if ( a . empty ( ) ) {
a = b ;
2020-07-29 11:14:45 +02:00
return ;
2020-06-11 20:51:08 +02:00
}
if ( b . empty ( ) ) {
return ;
}
double d = ( * a . back ( ) . components - * b . front ( ) . components ) . norm ( ) ;
size_t offset = d < 1.e-5 ? 1 : 0 ;
a . insert ( a . end ( ) , b . begin ( ) + offset , b . end ( ) ) ;
}
}
2020-09-01 12:22:10 +02:00
# include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
# include <CGAL/box_intersection_d.h>
# include <vector>
# include <fstream>
typedef CGAL : : Box_intersection_d : : Box_with_handle_d < double , 3 , int * > Box ;
namespace {
void loop_to_segments ( const cgal_wire_t & wire , std : : vector < Kernel_ : : Segment_3 > & segments ) {
for ( int i = 0 ; i < wire . size ( ) ; + + i ) {
int j = ( i + 1 ) % wire . size ( ) ;
segments . emplace_back ( wire [ i ] , wire [ j ] ) ;
}
}
struct intersection_collector {
2020-09-02 15:16:37 +02:00
2020-09-01 12:22:10 +02:00
const std : : vector < Kernel_ : : Segment_3 > & segments ;
int num_self_intersections = 0 ;
2020-09-02 15:16:37 +02:00
explicit intersection_collector ( const std : : vector < Kernel_ : : Segment_3 > & s )
: segments ( s )
{ }
2020-09-01 12:22:10 +02:00
void operator ( ) ( const Box & a , const Box & b ) {
int aid = * a . handle ( ) ;
int bid = * b . handle ( ) ;
if ( aid > bid ) {
std : : swap ( aid , bid ) ;
}
if ( ( ( aid + 1 ) = = bid ) | | ( ( aid = = 0 ) & & ( bid = ( segments . size ( ) - 1 ) ) ) ) {
// consecutive segments.
return ;
}
auto s0 = segments [ aid ] ;
auto s1 = segments [ bid ] ;
if ( CGAL : : do_intersect ( s0 , s1 ) ) {
num_self_intersections + + ;
}
}
} ;
bool do_segments_intersect ( const std : : vector < Kernel_ : : Segment_3 > & segments ) {
std : : vector < Box > boxes ;
std : : vector < int > handles ( segments . size ( ) ) ;
std : : iota ( handles . begin ( ) , handles . end ( ) , 0 ) ;
for ( auto it = segments . begin ( ) ; it ! = segments . end ( ) ; + + it ) {
boxes . push_back ( Box ( it - > bbox ( ) , & * ( handles . begin ( ) + std : : distance ( segments . begin ( ) , it ) ) ) ) ;
}
2020-09-02 15:16:37 +02:00
intersection_collector x ( segments ) ;
2020-09-01 12:22:10 +02:00
CGAL : : box_self_intersection_d ( boxes . begin ( ) , boxes . end ( ) , x ) ;
return ! ! x . num_self_intersections ;
}
}
2019-09-01 16:29:00 +02:00
bool CgalKernel : : convert ( const taxonomy : : loop * loop , cgal_wire_t & result ) {
// @todo only implement polygonal loops
auto edges = loop - > children_as < taxonomy : : edge > ( ) ;
std : : vector < taxonomy : : point3 > points ;
for ( auto & e : edges ) {
2020-07-29 11:14:45 +02:00
std : : vector < taxonomy : : point3 > edge ;
2019-09-01 16:29:00 +02:00
if ( e - > basis ) {
2020-07-25 09:12:39 +02:00
convert_curve ( e , edge ) ;
if ( ! e - > orientation_2 . get_value_or ( true ) ) {
std : : reverse ( edge . begin ( ) , edge . end ( ) ) ;
}
2020-06-11 20:51:08 +02:00
} else {
2020-07-29 11:14:45 +02:00
edge = {
2020-06-11 20:51:08 +02:00
boost : : get < taxonomy : : point3 > ( e - > start ) ,
boost : : get < taxonomy : : point3 > ( e - > end )
2020-07-29 11:14:45 +02:00
} ;
2019-09-01 16:29:00 +02:00
}
2020-07-29 11:14:45 +02:00
extend_wire ( points , edge ) ;
2020-06-11 20:51:08 +02:00
}
if ( points . size ( ) > = 2 ) {
// the edges -> <p0, ... pn> conversion left us with a duplicate global begin,end point.
double d = ( * points . back ( ) . components - * points . front ( ) . components ) . norm ( ) ;
2020-07-29 11:14:45 +02:00
if ( d < 1.e-5 ) {
points . erase ( points . end ( ) - 1 ) ;
} else {
Logger : : Warning ( " Loop not closed " , loop - > instance ) ;
}
2019-09-01 16:29:00 +02:00
}
// Parse and store the points in a sequence
cgal_wire_t polygon = std : : vector < Kernel_ : : Point_3 > ( ) ;
for ( auto & p : points ) {
2020-06-11 20:51:08 +02:00
cgal_point_t pnt ( ( * p . components ) ( 0 ) , ( * p . components ) ( 1 ) , ( * p . components ) ( 2 ) ) ;
2019-09-01 16:29:00 +02:00
polygon . push_back ( pnt ) ;
}
// A loop should consist of at least three vertices
std : : size_t original_count = polygon . size ( ) ;
if ( original_count < 3 ) {
Logger : : Message ( Logger : : LOG_ERROR , " Not enough edges for: " , loop - > instance ) ;
return false ;
}
// Remove points that are too close to one another
remove_duplicate_points_from_loop ( polygon ) ;
std : : size_t count = polygon . size ( ) ;
if ( original_count - count ! = 0 ) {
std : : stringstream ss ; ss < < ( original_count - count ) < < " edges removed for: " ;
Logger : : Message ( Logger : : LOG_WARNING , ss . str ( ) , loop - > instance ) ;
}
2020-09-01 12:22:10 +02:00
std : : vector < Kernel_ : : Segment_3 > segments ;
loop_to_segments ( polygon , segments ) ;
if ( do_segments_intersect ( segments ) ) {
Logger : : Message ( Logger : : LOG_WARNING , " Skipping self-intersecting loop " , loop - > instance ) ;
return false ;
}
2020-07-26 17:17:01 +02:00
/*
std::wcerr << "[" << std::endl;
for (auto& p : polygon) {
std::wcerr << " (" << CGAL::to_double(p.cartesian(0)) << ", " << CGAL::to_double(p.cartesian(1)) << ", " << CGAL::to_double(p.cartesian(2)) << ")," << std::endl;
}
std::wcerr << "]" << std::endl;
*/
2019-09-01 16:29:00 +02:00
if ( count < 3 ) {
Logger : : Message ( Logger : : LOG_ERROR , " Not enough edges for: " , loop - > instance ) ;
return false ;
}
result = polygon ;
// std::cout << "PolyLoop: " << std::endl;
// for (auto &point: polygon) {
// std::cout << "\tPoint(" << point << ")" << std::endl;
// }
return true ;
2019-01-25 14:25:34 +01:00
}
2019-09-01 16:29:00 +02:00
bool CgalKernel : : convert_impl ( const taxonomy : : shell * shell , ifcopenshell : : geometry : : ConversionResults & results ) {
cgal_shape_t shape ;
if ( ! convert ( shell , shape ) ) {
return false ;
}
results . emplace_back ( ConversionResult (
shell - > instance - > data ( ) . id ( ) ,
shell - > matrix ,
new CgalShape ( shape ) ,
shell - > surface_style
) ) ;
return true ;
2019-01-19 12:39:47 +01:00
}
2019-09-24 15:46:50 +02:00
bool CgalKernel : : convert_impl ( const taxonomy : : extrusion * extrusion , ifcopenshell : : geometry : : ConversionResults & results ) {
cgal_shape_t shape ;
if ( ! convert ( extrusion , shape ) ) {
return false ;
}
results . emplace_back ( ConversionResult (
extrusion - > instance - > data ( ) . id ( ) ,
extrusion - > matrix ,
new CgalShape ( shape ) ,
extrusion - > surface_style
) ) ;
return true ;
}
2020-09-13 17:15:46 +02:00
bool CgalKernel : : process_extrusion ( const cgal_face_t & bottom_face , const taxonomy : : direction3 & direction , double height , cgal_shape_t & shape ) {
2019-09-24 15:46:50 +02:00
std : : list < cgal_face_t > face_list ;
face_list . push_back ( bottom_face ) ;
2020-09-13 17:15:46 +02:00
auto & fs = * direction . components ;
cgal_direction_t dir ( fs ( 0 ) , fs ( 1 ) , fs ( 2 ) ) ;
2019-09-24 15:46:50 +02:00
for ( std : : vector < Kernel_ : : Point_3 > : : const_iterator current_vertex = bottom_face . outer . begin ( ) ;
current_vertex ! = bottom_face . outer . end ( ) ;
+ + current_vertex ) {
std : : vector < Kernel_ : : Point_3 > : : const_iterator next_vertex = current_vertex ;
+ + next_vertex ;
if ( next_vertex = = bottom_face . outer . end ( ) ) {
next_vertex = bottom_face . outer . begin ( ) ;
} cgal_face_t side_face ;
side_face . outer . push_back ( * next_vertex ) ;
side_face . outer . push_back ( * current_vertex ) ;
side_face . outer . push_back ( * current_vertex + height * dir ) ;
side_face . outer . push_back ( * next_vertex + height * dir ) ;
face_list . push_back ( side_face ) ;
}
cgal_face_t top_face ;
for ( std : : vector < Kernel_ : : Point_3 > : : const_reverse_iterator vertex = bottom_face . outer . rbegin ( ) ;
vertex ! = bottom_face . outer . rend ( ) ;
+ + vertex ) {
top_face . outer . push_back ( * vertex + height * dir ) ;
} face_list . push_back ( top_face ) ;
if ( bottom_face . inner . empty ( ) ) {
2020-01-21 16:26:00 +01:00
shape = utils : : create_polyhedron ( face_list ) ;
2019-09-24 15:46:50 +02:00
// if (has_position) for (auto &vertex : vertices(shape)) vertex->point() = vertex->point().transform(trsf);
return true ;
}
2020-01-21 16:26:00 +01:00
CGAL : : Nef_polyhedron_3 < Kernel_ > nef_shape = utils : : create_nef_polyhedron ( face_list ) ;
2019-09-24 15:46:50 +02:00
// Inner
// TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction
for ( auto & inner : bottom_face . inner ) {
// std::cout << "Inner wire" << std::endl;
face_list . clear ( ) ;
cgal_face_t hole_bottom_face ;
hole_bottom_face . outer = inner ;
remove_duplicate_points_from_loop ( hole_bottom_face . outer ) ;
face_list . push_back ( hole_bottom_face ) ;
for ( std : : vector < Kernel_ : : Point_3 > : : const_iterator current_vertex = inner . begin ( ) ;
current_vertex ! = inner . end ( ) ;
+ + current_vertex ) {
std : : vector < Kernel_ : : Point_3 > : : const_iterator next_vertex = current_vertex ;
+ + next_vertex ;
if ( next_vertex = = inner . end ( ) ) {
next_vertex = inner . begin ( ) ;
} cgal_face_t hole_side_face ;
hole_side_face . outer . push_back ( * next_vertex ) ;
hole_side_face . outer . push_back ( * current_vertex ) ;
hole_side_face . outer . push_back ( * current_vertex + height * dir ) ;
hole_side_face . outer . push_back ( * next_vertex + height * dir ) ;
face_list . push_back ( hole_side_face ) ;
}
cgal_face_t hole_top_face ;
for ( std : : vector < Kernel_ : : Point_3 > : : const_reverse_iterator vertex = inner . rbegin ( ) ;
vertex ! = inner . rend ( ) ;
+ + vertex ) {
hole_top_face . outer . push_back ( * vertex + height * dir ) ;
} face_list . push_back ( hole_top_face ) ;
try {
2020-01-21 16:26:00 +01:00
nef_shape - = utils : : create_nef_polyhedron ( face_list ) ;
2019-09-24 15:46:50 +02:00
} catch ( . . . ) {
2020-09-13 17:15:46 +02:00
Logger : : Message ( Logger : : LOG_ERROR , " IfcExtrudedAreaSolid: cannot subtract opening for: " ) ;
2019-09-24 15:46:50 +02:00
return false ;
}
}
/*if (has_position) {
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
nef_shape.transform(trsf);
}*/
try {
nef_shape . convert_to_polyhedron ( shape ) ;
return true ;
} catch ( . . . ) {
2020-09-13 17:15:46 +02:00
Logger : : Message ( Logger : : LOG_ERROR , " IfcExtrudedAreaSolid: cannot convert Nef to polyhedron for: " ) ;
return false ;
}
}
bool CgalKernel : : convert ( const taxonomy : : extrusion * extrusion , cgal_shape_t & shape ) {
const double & height = extrusion - > depth ;
if ( height < precision_ ) {
Logger : : Message ( Logger : : LOG_ERROR , " Non-positive extrusion height encountered for: " , extrusion - > instance ) ;
return false ;
}
cgal_face_t bottom_face ;
if ( ! convert ( & extrusion - > basis , bottom_face ) ) {
2019-09-24 15:46:50 +02:00
return false ;
}
2020-09-13 17:15:46 +02:00
return process_extrusion ( bottom_face , extrusion - > direction , extrusion - > depth , shape ) ;
2019-09-25 15:30:11 +02:00
}
2020-01-21 16:26:00 +01:00
CGAL : : Polyhedron_3 < Kernel_ > ifcopenshell : : geometry : : utils : : create_cube ( double d ) {
2019-09-25 15:30:11 +02:00
cgal_face_t bottom_face ;
bottom_face . outer . push_back ( Kernel_ : : Point_3 ( - d , - d , - d ) ) ;
bottom_face . outer . push_back ( Kernel_ : : Point_3 ( + d , - d , - d ) ) ;
bottom_face . outer . push_back ( Kernel_ : : Point_3 ( + d , + d , - d ) ) ;
bottom_face . outer . push_back ( Kernel_ : : Point_3 ( - d , + d , - d ) ) ;
cgal_direction_t dir ( 0 , 0 , 2 * d ) ;
std : : list < cgal_face_t > face_list = { bottom_face } ;
for ( std : : vector < Kernel_ : : Point_3 > : : const_iterator current_vertex = bottom_face . outer . begin ( ) ;
current_vertex ! = bottom_face . outer . end ( ) ;
+ + current_vertex )
{
std : : vector < Kernel_ : : Point_3 > : : const_iterator next_vertex = current_vertex ;
+ + next_vertex ;
if ( next_vertex = = bottom_face . outer . end ( ) ) {
next_vertex = bottom_face . outer . begin ( ) ;
}
cgal_face_t side_face ;
2020-01-21 16:26:00 +01:00
side_face . outer . push_back ( * next_vertex ) ;
side_face . outer . push_back ( * current_vertex ) ;
side_face . outer . push_back ( * current_vertex + dir ) ;
side_face . outer . push_back ( * next_vertex + dir ) ;
face_list . push_back ( side_face ) ;
}
cgal_face_t top_face ;
for ( std : : vector < Kernel_ : : Point_3 > : : const_reverse_iterator vertex = bottom_face . outer . rbegin ( ) ;
vertex ! = bottom_face . outer . rend ( ) ;
+ + vertex )
{
top_face . outer . push_back ( * vertex + dir ) ;
}
face_list . push_back ( top_face ) ;
return create_polyhedron ( face_list ) ;
}
CGAL : : Polyhedron_3 < Kernel_ > ifcopenshell : : geometry : : utils : : create_cube ( const Kernel_ : : Point_3 & lower , const Kernel_ : : Point_3 & upper ) {
cgal_face_t bottom_face ;
2020-04-03 15:05:50 +00:00
auto a0 = lower . cartesian ( 0 ) ;
auto a1 = lower . cartesian ( 1 ) ;
auto a2 = lower . cartesian ( 2 ) ;
2020-01-21 16:26:00 +01:00
2020-04-03 15:05:50 +00:00
auto b0 = upper . cartesian ( 0 ) ;
auto b1 = upper . cartesian ( 1 ) ;
auto b2 = upper . cartesian ( 2 ) ;
2020-01-21 16:26:00 +01:00
bottom_face . outer . push_back ( Kernel_ : : Point_3 ( a0 , a1 , a2 ) ) ;
bottom_face . outer . push_back ( Kernel_ : : Point_3 ( b0 , a1 , a2 ) ) ;
bottom_face . outer . push_back ( Kernel_ : : Point_3 ( b0 , b1 , a2 ) ) ;
bottom_face . outer . push_back ( Kernel_ : : Point_3 ( a0 , b1 , a2 ) ) ;
cgal_direction_t dir ( 0 , 0 , b2 - a2 ) ;
std : : list < cgal_face_t > face_list = { bottom_face } ;
for ( std : : vector < Kernel_ : : Point_3 > : : const_iterator current_vertex = bottom_face . outer . begin ( ) ;
current_vertex ! = bottom_face . outer . end ( ) ;
+ + current_vertex )
{
std : : vector < Kernel_ : : Point_3 > : : const_iterator next_vertex = current_vertex ;
+ + next_vertex ;
if ( next_vertex = = bottom_face . outer . end ( ) ) {
next_vertex = bottom_face . outer . begin ( ) ;
}
cgal_face_t side_face ;
2019-09-25 15:30:11 +02:00
side_face . outer . push_back ( * next_vertex ) ;
side_face . outer . push_back ( * current_vertex ) ;
side_face . outer . push_back ( * current_vertex + dir ) ;
side_face . outer . push_back ( * next_vertex + dir ) ;
face_list . push_back ( side_face ) ;
}
cgal_face_t top_face ;
for ( std : : vector < Kernel_ : : Point_3 > : : const_reverse_iterator vertex = bottom_face . outer . rbegin ( ) ;
vertex ! = bottom_face . outer . rend ( ) ;
+ + vertex )
{
top_face . outer . push_back ( * vertex + dir ) ;
}
face_list . push_back ( top_face ) ;
return create_polyhedron ( face_list ) ;
}
2019-10-06 19:03:31 +02:00
bool CgalKernel : : thin_solid ( const CGAL : : Nef_polyhedron_3 < Kernel_ > & a , CGAL : : Nef_polyhedron_3 < Kernel_ > & result ) {
// @todo this should be possible as a minkowski sum of facet & cube. rather than a set of boolean ops.
auto a_nonconst = a ;
auto ax = CGAL : : minkowski_sum_3 ( a_nonconst , precision_cube_ ) ;
auto x = ax - a ;
result = x ;
return true ;
auto yxy = CGAL : : minkowski_sum_3 ( x , precision_cube_ ) ;
auto y = yxy * a ;
auto zyz = CGAL : : minkowski_sum_3 ( y , precision_cube_ ) ;
result = yxy * zyz ;
return true ;
}
2019-09-25 15:30:11 +02:00
bool CgalKernel : : preprocess_boolean_operand ( const IfcUtil : : IfcBaseClass * log_reference , const cgal_shape_t & shape_const , CGAL : : Nef_polyhedron_3 < Kernel_ > & result , bool dilate ) {
cgal_shape_t shape = shape_const ;
if ( ! shape . is_valid ( ) ) {
Logger : : Message ( Logger : : LOG_ERROR , " Conversion to Nef will fail. Invalid geometry: " , log_reference ) ;
return false ;
}
if ( ! shape . is_closed ( ) ) {
// TODO: There can be substractions to remove parts of non-volumetric objects. Maybe iterate over all faces of an entity and put them in a Nef_polyhedron_3 through Boolean union? Highly inefficient but maybe desirable...
Logger : : Message ( Logger : : LOG_ERROR , " Subtraction of openings not supported for non-closed geometry: " , log_reference ) ;
return false ;
}
bool success = false ;
try {
success = CGAL : : Polygon_mesh_processing : : triangulate_faces ( shape ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Triangulation of geometry crashed: " , log_reference ) ;
return false ;
}
if ( ! success ) {
Logger : : Message ( Logger : : LOG_ERROR , " Triangulation of geometry failed: " , log_reference ) ;
return false ;
}
if ( CGAL : : Polygon_mesh_processing : : does_self_intersect ( shape ) ) {
Logger : : Message ( Logger : : LOG_ERROR , " Conversion to Nef will fail. Self-intersecting geometry: " , log_reference ) ;
return false ;
}
try {
result = CGAL : : Nef_polyhedron_3 < Kernel_ > ( shape ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Could not convert geometry to Nef: " , log_reference ) ;
return false ;
}
2019-10-06 09:11:44 +02:00
if ( dilate ) {
2019-09-25 15:30:11 +02:00
try {
// @todo don't dilate in 3 dimensions but only in the XY plane, orthogonal to wall axis.
result = CGAL : : minkowski_sum_3 ( result , precision_cube_ ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Could not dilate boolean operand " , log_reference ) ;
return false ;
}
}
try {
cgal_shape_t convert_back ;
result . convert_to_polyhedron ( convert_back ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_WARNING , " Final conversion will likely fail. Could not convert geometry from Nef: " , log_reference ) ;
}
return true ;
}
namespace {
bool convert_placement ( const ifcopenshell : : geometry : : taxonomy : : matrix4 & place , cgal_placement_t & trsf ) {
2020-06-11 20:48:35 +02:00
const auto & m = * place . components ;
2019-09-25 15:30:11 +02:00
// @todo check
trsf = cgal_placement_t (
m ( 0 , 0 ) , m ( 0 , 1 ) , m ( 0 , 2 ) , m ( 0 , 3 ) ,
m ( 1 , 0 ) , m ( 1 , 1 ) , m ( 1 , 2 ) , m ( 1 , 3 ) ,
m ( 2 , 0 ) , m ( 2 , 1 ) , m ( 2 , 2 ) , m ( 2 , 3 ) ) ;
return true ;
}
}
2020-09-13 17:15:46 +02:00
# include <CGAL/Nef_nary_union_3.h>
2019-09-25 15:30:11 +02:00
2020-09-13 17:15:46 +02:00
# define add_condition(x) for(auto& op : ops) { if (!(x)) return false; }
namespace {
CGAL : : Polygon_2 < Kernel_ > loop_to_polygon_2 ( taxonomy : : loop * loop ) {
CGAL : : Polygon_2 < Kernel_ > polygon ;
auto edges = loop - > children_as < taxonomy : : edge > ( ) ;
for ( auto & e : edges ) {
auto & p = boost : : get < taxonomy : : point3 > ( e - > start ) ;
CGAL : : Point_2 < Kernel_ > pnt ( ( * p . components ) ( 0 ) , ( * p . components ) ( 1 ) ) ;
polygon . push_back ( pnt ) ;
}
return polygon ;
}
CGAL : : Polygon_2 < Kernel_ > wire_to_polygon_2 ( cgal_wire_t & w ) {
CGAL : : Polygon_2 < Kernel_ > polygon ;
for ( auto & p : w ) {
CGAL : : Point_2 < Kernel_ > pnt ( p . cartesian ( 0 ) , p . cartesian ( 1 ) ) ;
polygon . push_back ( pnt ) ;
}
return polygon ;
}
}
bool CgalKernel : : process_as_2d_polygon ( const taxonomy : : boolean_result * br , std : : list < CGAL : : Polygon_2 < Kernel_ > > & loops , double & z0 , double & z1 ) {
// @todo can also be for other boolean operations, just depth/matrix operands are different
if ( br - > operation ! = taxonomy : : boolean_result : : SUBTRACTION ) {
return false ;
}
auto & ops = br - > children ;
std : : vector < taxonomy : : extrusion * > extrusions ;
std : : transform ( ops . begin ( ) , ops . end ( ) , std : : back_inserter ( extrusions ) , [ ] ( taxonomy : : item * op ) {
taxonomy : : extrusion * nptr = nullptr ;
if ( op - > kind ( ) ! = taxonomy : : COLLECTION ) return nptr ;
auto cl = ( taxonomy : : collection * ) op ;
if ( ( cl ) - > children . size ( ) ! = 1 ) return nptr ;
if ( cl - > children [ 0 ] - > kind ( ) = = taxonomy : : COLLECTION ) {
cl = ( taxonomy : : collection * ) cl - > children [ 0 ] ;
if ( ( cl ) - > children . size ( ) ! = 1 ) return nptr ;
}
if ( cl - > children [ 0 ] - > kind ( ) ! = taxonomy : : EXTRUSION ) return nptr ;
auto ex = ( taxonomy : : extrusion * ) cl - > children [ 0 ] ;
return ex ;
} ) ;
if ( std : : find ( extrusions . begin ( ) , extrusions . end ( ) , nullptr ) ! = extrusions . end ( ) ) {
return false ;
}
// op[i].matrix[2,0:3] = <0 0 1>
Eigen : : Vector3d Z ( 0. , 0. , 1. ) ;
if ( std : : find_if ( extrusions . begin ( ) , extrusions . end ( ) , [ & Z ] ( taxonomy : : extrusion * ex ) {
auto & m = * ex - > matrix . components ;
return std : : abs ( 1. - std : : abs ( m . col ( 2 ) . head < 3 > ( ) . dot ( Z ) ) ) > 1.e-5 ;
} ) ! = extrusions . end ( ) ) {
return false ;
}
// | op[i].matrix[2,0:3] . op[i].direction | = 1
if ( std : : find_if ( extrusions . begin ( ) , extrusions . end ( ) , [ ] ( taxonomy : : extrusion * ex ) {
auto & d = * ex - > direction . components ;
auto & m = * ex - > matrix . components ;
return std : : abs ( 1. - std : : abs ( m . col ( 2 ) . head < 3 > ( ) . dot ( d ) ) ) > 1.e-5 ;
} ) ! = extrusions . end ( ) ) {
return false ;
}
// op[0].depth <= op[i..n].depth
const auto & op_0_depth = extrusions [ 0 ] - > depth ;
if ( std : : find_if ( extrusions . begin ( ) + 1 , extrusions . end ( ) , [ & op_0_depth ] ( taxonomy : : extrusion * ex ) {
return op_0_depth > ex - > depth ;
} ) ! = extrusions . end ( ) ) {
return false ;
}
const auto & op_0_matrix_2_3 = ( * extrusions [ 0 ] - > matrix . components ) ( 2 , 3 ) ;
if ( std : : find_if ( extrusions . begin ( ) + 1 , extrusions . end ( ) , [ & op_0_matrix_2_3 ] ( taxonomy : : extrusion * ex ) {
return op_0_matrix_2_3 < ( * ex - > matrix . components ) ( 2 , 3 ) ;
} ) ! = extrusions . end ( ) ) {
return false ;
}
std : : vector < cgal_wire_t > wires ;
try {
std : : transform ( extrusions . begin ( ) , extrusions . end ( ) , std : : back_inserter ( wires ) , [ this ] ( taxonomy : : extrusion * ex ) {
if ( ex - > basis . children . size ( ) = = 1 & & ex - > basis . children [ 0 ] - > kind ( ) = = taxonomy : : LOOP ) {
auto l = ( taxonomy : : loop * ) ex - > basis . children [ 0 ] ;
cgal_wire_t w ;
cgal_placement_t trsf ;
convert_placement ( ex - > matrix , trsf ) ;
if ( convert ( l , w ) ) {
for ( auto & p : w ) {
p = p . transform ( trsf ) ;
}
return w ;
}
}
throw std : : runtime_error ( " failed to convert to polygon " ) ;
} ) ;
} catch ( std : : runtime_error & ) {
return false ;
}
for ( auto it = wires . begin ( ) ; it ! = wires . end ( ) ; + + it ) {
auto & w = * it ;
auto op = ( taxonomy : : geom_item * ) ( * ( ops . begin ( ) + std : : distance ( wires . begin ( ) , it ) ) ) ;
cgal_placement_t trsf ;
convert_placement ( op - > matrix , trsf ) ;
for ( auto & p : w ) {
p = trsf . transform ( p ) ;
}
}
loops . clear ( ) ;
std : : transform ( wires . begin ( ) , wires . end ( ) , std : : back_inserter ( loops ) , wire_to_polygon_2 ) ;
z0 = op_0_matrix_2_3 ;
z1 = z0 + extrusions [ 0 ] - > depth * ( * extrusions [ 0 ] - > direction . components ) ( 2 ) ;
if ( z1 < z0 ) {
std : : swap ( z0 , z1 ) ;
}
return true ;
}
# include <CGAL/Polygon_set_2.h>
# include <CGAL/Boolean_set_operations_2.h>
# include <CGAL/Arr_vertical_decomposition_2.h>
# include <CGAL/Polygon_vertical_decomposition_2.h>
# include <CGAL/Polygon_triangulation_decomposition_2.h>
2019-09-25 15:30:11 +02:00
bool CgalKernel : : convert_impl ( const taxonomy : : boolean_result * br , ifcopenshell : : geometry : : ConversionResults & results ) {
2020-09-13 17:15:46 +02:00
double z0 , z1 ;
std : : list < CGAL : : Polygon_2 < Kernel_ > > loops ;
if ( process_as_2d_polygon ( br , loops , z0 , z1 ) ) {
auto first_item_style = ( ( taxonomy : : geom_item * ) br - > children [ 0 ] ) - > surface_style ;
std : : list < CGAL : : Polygon_with_holes_2 < Kernel_ > > pwhs ;
auto it = loops . begin ( ) ;
const auto & p = * it ;
CGAL : : Polygon_with_holes_2 < Kernel_ > pwh ( p , + + it , loops . end ( ) ) ;
CGAL : : Gps_segment_traits_2 < Kernel_ > traits ;
if ( false & & ! CGAL : : are_holes_and_boundary_pairwise_disjoint ( pwh , traits ) ) {
// this is very slow.
// the check is also slow...
CGAL : : Polygon_set_2 < Kernel_ > result ;
auto it = loops . begin ( ) ;
result . insert ( * it + + ) ;
for ( ; it ! = loops . end ( ) ; + + it ) {
result . difference ( * it ) ;
}
result . polygons_with_holes ( std : : back_inserter ( pwhs ) ) ;
} else {
pwhs . push_back ( pwh ) ;
}
#if 0
CGAL::Polygon_vertical_decomposition_2<Kernel_> decompositor;
#else
CGAL : : Polygon_triangulation_decomposition_2 < Kernel_ > decompositor ;
# endif
std : : list < CGAL : : Polygon_2 < Kernel_ > > decom_polies ;
for ( auto & pwh : pwhs ) {
decompositor ( pwh , std : : back_inserter ( decom_polies ) ) ;
}
std : : transform ( decom_polies . begin ( ) , decom_polies . end ( ) , std : : back_inserter ( results ) , [ this , & br , & z0 , & z1 , & first_item_style ] ( const CGAL : : Polygon_2 < Kernel_ > & p2 ) {
cgal_face_t f ;
std : : transform (
p2 . vertices_begin ( ) ,
p2 . vertices_end ( ) ,
std : : back_inserter ( f . outer ) ,
[ ] ( const CGAL : : Point_2 < Kernel_ > & p ) {
return CGAL : : Point_3 < Kernel_ > ( p . cartesian ( 0 ) , p . cartesian ( 1 ) , 0 ) ;
}
) ;
cgal_shape_t shp ;
taxonomy : : direction3 d ( 0 , 0 , 1 ) ;
process_extrusion ( f , d , z1 - z0 , shp ) ;
for ( auto it = shp . vertices_begin ( ) ; it ! = shp . vertices_end ( ) ; + + it ) {
auto p = it - > point ( ) ;
it - > point ( ) = cgal_point_t ( p . cartesian ( 0 ) , p . cartesian ( 1 ) , p . cartesian ( 2 ) + z0 ) ;
}
return ConversionResult (
br - > instance - > data ( ) . id ( ) ,
br - > matrix ,
new CgalShape ( shp ) ,
br - > surface_style . diffuse ? br - > surface_style : first_item_style
) ;
} ) ;
Logger : : Notice ( " Processed boolean operation as 2d arrangement " ) ;
return true ;
}
2019-09-25 15:30:11 +02:00
bool first = true ;
CGAL : : Nef_polyhedron_3 < Kernel_ > a ;
2020-09-13 17:15:46 +02:00
CGAL : : Nef_nary_union_3 < CGAL : : Nef_polyhedron_3 < Kernel_ > > second_operand_collector ;
size_t second_operand_collector_size = 0 ;
2019-09-25 15:30:11 +02:00
taxonomy : : style first_item_style ;
for ( auto & c : br - > children ) {
// AbstractKernel::convert(c, results);
// continue;
ifcopenshell : : geometry : : ConversionResults cr ;
// @todo half-space detection
AbstractKernel : : convert ( c , cr ) ;
if ( first & & br - > operation = = taxonomy : : boolean_result : : SUBTRACTION ) {
first_item_style = ( ( taxonomy : : geom_item * ) c ) - > surface_style ;
if ( ! first_item_style . diffuse & & c - > kind ( ) = = taxonomy : : COLLECTION ) {
first_item_style = ( ( taxonomy : : geom_item * ) ( ( taxonomy : : collection * ) c ) - > children [ 0 ] ) - > surface_style ;
}
}
for ( auto it = cr . begin ( ) ; it ! = cr . end ( ) ; + + it ) {
const cgal_shape_t & entity_shape_unlocated ( ( ( CgalShape * ) it - > Shape ( ) ) - > shape ( ) ) ;
cgal_shape_t entity_shape ( entity_shape_unlocated ) ;
2020-06-11 20:48:35 +02:00
if ( ! it - > Placement ( ) . components - > isIdentity ( ) ) {
2019-09-25 15:30:11 +02:00
cgal_placement_t trsf ;
convert_placement ( it - > Placement ( ) , trsf ) ;
for ( auto & vertex : vertices ( entity_shape ) ) {
if ( false ) {
auto x = CGAL : : to_double ( vertex - > point ( ) . x ( ) ) ;
auto y = CGAL : : to_double ( vertex - > point ( ) . y ( ) ) ;
auto z = CGAL : : to_double ( vertex - > point ( ) . z ( ) ) ;
std : : wcout < < x < < " " < < y < < " " < < z < < std : : endl ;
}
vertex - > point ( ) = vertex - > point ( ) . transform ( trsf ) ;
if ( false ) {
auto x = CGAL : : to_double ( vertex - > point ( ) . x ( ) ) ;
auto y = CGAL : : to_double ( vertex - > point ( ) . y ( ) ) ;
auto z = CGAL : : to_double ( vertex - > point ( ) . z ( ) ) ;
std : : wcout < < x < < " " < < y < < " " < < z < < std : : endl ;
}
}
}
CGAL : : Nef_polyhedron_3 < Kernel_ > nef ;
2020-09-13 17:15:46 +02:00
if ( ! preprocess_boolean_operand ( c - > instance , entity_shape , nef ,
2019-09-25 15:30:11 +02:00
// Dilate boolean subtraction operands
2020-09-13 17:15:46 +02:00
( ! first & & br - > operation = = taxonomy : : boolean_result : : SUBTRACTION ) ) )
{
continue ;
}
2019-09-25 15:30:11 +02:00
if ( first ) {
a = nef ;
} else {
if ( br - > operation = = taxonomy : : boolean_result : : SUBTRACTION ) {
2020-09-13 17:15:46 +02:00
second_operand_collector . add_polyhedron ( nef ) ;
second_operand_collector_size + + ;
// a -= nef;
2019-09-25 15:30:11 +02:00
} else if ( br - > operation = = taxonomy : : boolean_result : : INTERSECTION ) {
a * = nef ;
} else if ( br - > operation = = taxonomy : : boolean_result : : UNION ) {
a + = nef ;
}
}
}
first = false ;
}
2020-09-13 17:15:46 +02:00
if ( br - > operation = = taxonomy : : boolean_result : : SUBTRACTION & & second_operand_collector_size ) {
a - = second_operand_collector . get_union ( ) ;
}
2019-10-06 19:03:31 +02:00
cgal_shape_t a_poly , b_poly ;
// CGAL::Nef_polyhedron_3<Kernel_> b;
// thin_solid(a, b);
2019-09-25 15:30:11 +02:00
try {
a . convert_to_polyhedron ( a_poly ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Could not convert geometry with openings from Nef: " , br - > instance ) ;
return false ;
}
results . emplace_back ( ConversionResult (
br - > instance - > data ( ) . id ( ) ,
br - > matrix ,
new CgalShape ( a_poly ) ,
br - > surface_style . diffuse ? br - > surface_style : first_item_style
) ) ;
return true ;
2019-09-24 15:46:50 +02:00
}