diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index f1006b8680..e178c6d5ec 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -1387,6 +1387,25 @@ bool CgalKernel::process_as_2d_polygon(const std::list + void project_onto_plane(const taxonomy::plane& p, It i, It j, Fn fn) { + auto mi = p.matrix.components->inverse(); + Eigen::Vector4d v; + std::for_each(i, j, [&mi, &v, &fn](const cgal_shape_t& shp) { + for (auto& vv : vertices(shp)) { + auto& p = vv->point(); + v = Eigen::Vector4d(CGAL::to_double(p.cartesian(0)), + CGAL::to_double(p.cartesian(1)), + CGAL::to_double(p.cartesian(2)), + 1.); + v = mi * v; + fn(v.head<3>()); + } + }); + } +} + bool CgalKernel::convert_impl(const taxonomy::boolean_result* br, ifcopenshell::geometry::ConversionResults& results) { double z0, z1; std::list> loops; @@ -1464,22 +1483,93 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result* br, ifcopenshell:: bool first = true; CGAL::Nef_polyhedron_3 a; - CGAL::Nef_nary_union_3> second_operand_collector; size_t second_operand_collector_size = 0; taxonomy::style first_item_style; - std::list>> operands; + std::list>> operands; for (auto& c : br->children) { // AbstractKernel::convert(c, results); // continue; ifcopenshell::geometry::ConversionResults cr; - // @todo half-space detection - AbstractKernel::convert(c, cr); + operands.emplace_back(); + operands.back().first = c->instance; + + if (c->kind() == taxonomy::FACE && c->instance->declaration().is("IfcHalfSpaceSolid") && !first) { + auto face = (taxonomy::face*) c; + + if (face->basis == nullptr || !face->basis->kind() == taxonomy::PLANE) { + return false; + } + + static double inf = std::numeric_limits::infinity(); + static double eps = 1.e-5; + + double uvw_min[3] = { +inf, +inf, +inf }; + double uvw_max[3] = { -inf, -inf, -inf }; + auto& p = *((taxonomy::plane*)face->basis); + project_onto_plane(p, + operands.front().second.begin(), + operands.front().second.end(), + [&uvw_min, &uvw_max](const Eigen::Vector3d& p) { + for (int i = 0; i < 3; ++i) { + if (p(i) < uvw_min[i]) { + uvw_min[i] = p(i); + } + if (p(i) > uvw_max[i]) { + uvw_max[i] = p(i); + } + } + }); + + Kernel_::Point_3 lower(uvw_min[0] - eps, uvw_min[1] - eps, 0.); + Kernel_::Point_3 upper(uvw_max[0] + eps, uvw_max[1] + eps, uvw_max[2] + eps); + cgal_shape_t box = utils::create_cube(lower, upper); + cgal_placement_t pl; + convert_placement(p.matrix, pl); + for (auto& v : vertices(box)) { + v->point() = v->point().transform(pl); + } + + if (!face->children.empty()) { + cgal_face_t f; + if (!convert(face, f)) { + return false; + } + static taxonomy::direction3 z(0, 0, 1); + cgal_shape_t poly; + process_extrusion(f, z, 200, poly); + for (auto& v : vertices(poly)) { + v->point() = Kernel_::Point_3( + v->point().cartesian(0), + v->point().cartesian(1), + v->point().cartesian(2) - 100 + ); + }; + cgal_placement_t trsf; + convert_placement(face->matrix, trsf); + for (auto& v : vertices(poly)) { + v->point() = v->point().transform(trsf); + } + CGAL::Nef_polyhedron_3 poly_nef(poly); + CGAL::Nef_polyhedron_3 box_nef(box); + auto intersection = poly_nef * box_nef; + cgal_shape_t intersection_poly; + intersection.convert_to_polyhedron(intersection_poly); + operands.back().second.push_back(intersection_poly); + } else { + operands.back().second.push_back(box); + } + + continue; + } + + 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) { @@ -1487,8 +1577,6 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result* br, ifcopenshell:: } } - operands.emplace_back(); - 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); @@ -1511,7 +1599,7 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result* br, ifcopenshell:: } } - operands.back().push_back(std::make_pair(c->instance, entity_shape)); + operands.back().second.push_back(entity_shape); } } @@ -1529,10 +1617,11 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result* br, ifcopenshell:: for (auto& li : operands) { - for (auto& entity_shape : li) { + auto entity_instance = li.first; + for (auto& entity_shape : li.second) { CGAL::Nef_polyhedron_3 nef; - if (!preprocess_boolean_operand(entity_shape.first, entity_shape.second, nef, + if (!preprocess_boolean_operand(entity_instance, entity_shape, nef, // Dilate boolean subtraction operands (!first && br->operation == taxonomy::boolean_result::SUBTRACTION))) { diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 4364151cc2..947581fe28 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -98,7 +98,6 @@ namespace kernels { bool process_as_2d_polygon(const taxonomy::boolean_result* br, std::list>& loops, double& z0, double& z1); bool process_as_2d_polygon(const std::list>>& operands, std::list>& loops, double& z0, double& z1); - // virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::boolean_result*, ifcopenshell::geometry::ConversionResults&); diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 8e06f9233f..a9208bbfd4 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1820,7 +1820,8 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcBooleanResult* inst) { taxonomy::item* mapping::map_impl(const IfcSchema::IfcPolygonalBoundedHalfSpace* inst) { auto f = map_impl((IfcSchema::IfcHalfSpaceSolid*) inst); - ((taxonomy::face*)f)->children = ((taxonomy::loop)as(map(inst->PolygonalBoundary()))).children; + ((taxonomy::face*)f)->children = { map(inst->PolygonalBoundary()) }; + ((taxonomy::face*)f)->matrix = as(map(inst->Position())); return f; }