diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 38f9e0d457..d0d6be43bc 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -25,14 +25,17 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); - if (xyz.size() == 3) { + if (xyz.size() < 4) { point = Kernel::Point_3(xyz.size() ? (xyz[0]*getValue(GV_LENGTH_UNIT)) : 0.0f, xyz.size() > 1 ? (xyz[1]*getValue(GV_LENGTH_UNIT)) : 0.0f, xyz.size() > 2 ? (xyz[2]*getValue(GV_LENGTH_UNIT)) : 0.0f); // std::cout << "Converted Point(" << point << ")" << std::endl; return true; } else { - throw std::runtime_error("Point without 3 coordinates"); + std::cout << "Point("; + for (auto &coordinate: xyz) std::cout << coordinate << " "; + std::cout << ")"; + throw std::runtime_error("Could not parse point"); } } @@ -50,7 +53,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_ // IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf) cgal_point_t o; cgal_direction_t axis = Kernel::Vector_3(0,0,1); - cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); // TODO: Put identity for now. Check? + cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); IfcGeom::CgalKernel::convert(l->Location(),o); bool hasRef = l->hasRefDirection(); if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); @@ -59,7 +62,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_ Kernel::Vector_3 y = CGAL::cross_product(Kernel::Vector_3(0.0, 0.0, 1.0), refDirection); trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), 0.0, o.cartesian(0), refDirection.cartesian(1), y.cartesian(1), 0.0, o.cartesian(1), - 0.0, y.cartesian(2), 1.0, 0.0); + 0.0, 0.0, 1.0, 0.0); // CACHE(IfcAxis2Placement3D,l,trsf) return true; @@ -69,7 +72,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ // IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf) cgal_point_t o; cgal_direction_t axis = Kernel::Vector_3(0,0,1); - cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); // TODO: Put identity for now. Check? + cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); IfcGeom::CgalKernel::convert(l->Location(),o); bool hasRef = l->hasRefDirection(); if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis); @@ -144,3 +147,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p // CACHE(IfcObjectPlacement,l,trsf) return true; } + +bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face) { + face.outer = wire; + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index b163696066..afbb9db9f5 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -34,14 +34,24 @@ SHAPES(IfcRepresentation); // IfcFacetedBrepWithVoids included // IfcAdvancedBrepWithVoids included SHAPES(IfcManifoldSolidBrep); +SHAPES(IfcMappedItem); SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); +SHAPE(IfcCsgSolid); +SHAPE(IfcBlock); +SHAPE(IfcBooleanResult); +SHAPE(IfcSphere); +SHAPE(IfcRectangularPyramid); +SHAPE(IfcRightCircularCylinder); +SHAPE(IfcRightCircularCone); +FACE(IfcArbitraryClosedProfileDef); FACE(IfcFace); FACE(IfcRectangleProfileDef); WIRE(IfcPolyLoop); +WIRE(IfcPolyline); CLASS(IfcCartesianPoint,cgal_point_t); CLASS(IfcDirection,cgal_direction_t); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 6cd88a434b..7c4e64337f 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -1,5 +1,15 @@ #include "CgalKernel.h" +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, cgal_face_t& face) { + cgal_wire_t wire; + if ( ! convert_wire(l->OuterCurve(),wire) ) return false; + + cgal_face_t f; + bool success = convert_wire_to_face(wire, f); + if (success) face = f; + return success; +} + bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cgal_face_t& face) { const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT); const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index b8efaf7f18..95fe301e15 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -32,6 +32,58 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv return false; } +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionResults& shapes) { + cgal_placement_t gtrsf; + IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget(); + if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); +// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); + return false; + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) { + cgal_placement_t trsf; + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); +// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); + gtrsf = trsf; + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { + cgal_placement_t trsf_2d; + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); +// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d); + gtrsf = (cgal_placement_t) trsf_2d; + } + IfcSchema::IfcRepresentationMap* map = l->MappingSource(); + IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin(); + cgal_placement_t trsf; + if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); + } else { + cgal_placement_t trsf_2d; + IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d); + trsf = trsf_2d; + } + // TODO: Check + gtrsf = trsf * gtrsf; + + const IfcGeom::SurfaceStyle* mapped_item_style = get_style(l); + + const size_t previous_size = shapes.size(); + bool b = convert_shapes(map->MappedRepresentation(), shapes); + + for (size_t i = previous_size; i < shapes.size(); ++ i ) { + IfcGeom::CgalPlacement place(gtrsf); + shapes[i].prepend(&place); + + // Apply styles assigned to the mapped item only if on + // a more granular level no styles have been applied + if (!shapes[i].hasStyle()) { + shapes[i].setStyle(mapped_item_style); + } + } + + return b; +} + bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal_shape_t &shape) { const double height = l->Depth() * getValue(GV_LENGTH_UNIT); if (height < getValue(GV_PRECISION)) { @@ -90,7 +142,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; shape = polyhedron; @@ -138,3 +190,589 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ shape = polyhedron; return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCsgSolid* l, cgal_shape_t& shape) { + return convert_shape(l->TreeRootExpression(), shape); +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& shape) { + const double dx = l->XLength() * getValue(GV_LENGTH_UNIT); + const double dy = l->YLength() * getValue(GV_LENGTH_UNIT); + const double dz = l->ZLength() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + // x = 0 + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, dz)); + + // x = dx + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + + // y = 0 + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + + // y = dy + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, dz)); + + // z = 0 + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + + // z = dz + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_shape_t& shape) { + + cgal_shape_t s1, s2; + ConversionResults items1, items2; + cgal_wire_t boundary_wire; + IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand(); + IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand(); + bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid); + + if ( shape_type(operand1) == ST_SHAPELIST ) { + Logger::Message(Logger::LOG_ERROR, "s1: ST_SHAPELIST Unsupported", operand1->entity); +// if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) { + return false; +// } + } else if ( shape_type(operand1) == ST_SHAPE ) { + if ( ! convert_shape(operand1, s1) ) { + return false; + } +// TopoDS_Solid temp_solid; +// s1 = ensure_fit_for_subtraction(s1, temp_solid); + } else { + Logger::Message(Logger::LOG_ERROR, "s1: Invalid representation item for boolean operation", operand1->entity); + return false; + } + +// const double first_operand_volume = shape_volume(s1); +// if ( first_operand_volume <= ALMOST_ZERO ) +// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity); + + bool shape2_processed = false; + if ( shape_type(operand2) == ST_SHAPELIST ) { + Logger::Message(Logger::LOG_ERROR, "s2: ST_SHAPELIST Unsupported", operand1->entity); +// shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true); + } else if ( shape_type(operand2) == ST_SHAPE ) { + shape2_processed = convert_shape(operand2,s2); + if (shape2_processed && !is_halfspace) { +// TopoDS_Solid temp_solid; +// s2 = ensure_fit_for_subtraction(s2, temp_solid); + } + } else { + Logger::Message(Logger::LOG_ERROR, "s2: Invalid representation item for boolean operation", operand2->entity); + } + + if (!shape2_processed) { +// shape = s1; + Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity); +// return true; + } + +// if (!is_halfspace) { +// const double second_operand_volume = shape_volume(s2); +// if ( second_operand_volume <= ALMOST_ZERO ) +// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity); +// } + + const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); + + CGAL_precondition(s1.is_valid() && s1.is_closed()); + CGAL::Nef_polyhedron_3 nef1(s1); + if (!nef1.is_simple()) { + Logger::Message(Logger::LOG_ERROR, "s1: Not simple Nef?", operand1->entity); + return false; + } + + CGAL_precondition(s2.is_valid() && s2.is_closed()); + CGAL::Nef_polyhedron_3 nef2(s2); + if (!nef2.is_simple()) { + Logger::Message(Logger::LOG_ERROR, "s2: Not simple Nef?", operand2->entity); + return false; + } + +// std::ofstream f1; +// f1.open("/Users/ken/Desktop/s1.off"); +// f1 << s1 << std::endl; +// f1.close(); +// std::ofstream f2; +// f2.open("/Users/ken/Desktop/s2.off"); +// f2 << s2 << std::endl; +// f2.close(); + + if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { + +// std::cout << "Difference" << std::endl; + CGAL::Nef_polyhedron_3 nef_result = nef1-nef2; + if (!nef_result.is_simple()) { + std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + return false; + } + cgal_shape_t result; + nef_result.convert_to_polyhedron(result); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); + shape = result; + return true; + + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { + +// std::cout << "Union" << std::endl; + CGAL::Nef_polyhedron_3 nef_result = nef1+nef2; + if (!nef_result.is_simple()) { + std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + return false; + } + cgal_shape_t result; + nef_result.convert_to_polyhedron(result); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); + shape = result; + return true; + + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { + +// std::cout << "Intersection" << std::endl; + CGAL::Nef_polyhedron_3 nef_result = nef1*nef2; + if (!nef_result.is_simple()) { + std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + return false; + } + cgal_shape_t result; + nef_result.convert_to_polyhedron(result); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); + shape = result; + return true; + + } + + return false; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& shape) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + + // Make icosahedron + float golden_ratio = (1.0+sqrtf(5.0))/2.0; + float normalising_factor = sqrtf(golden_ratio*golden_ratio+1.0); + std::vector icosahedron_vertices; + icosahedron_vertices.push_back(Kernel::Point_3(-1.0/normalising_factor, golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3( 1.0/normalising_factor, golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3(-1.0/normalising_factor, -golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3( 1.0/normalising_factor, -golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, -1.0/normalising_factor, golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, 1.0/normalising_factor, golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, -1.0/normalising_factor, -golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, 1.0/normalising_factor, -golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3( golden_ratio/normalising_factor, 0.0, -1.0/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3( golden_ratio/normalising_factor, 0.0, 1.0/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(-golden_ratio/normalising_factor, 0.0, -1.0/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(-golden_ratio/normalising_factor, 0.0, 1.0/normalising_factor)); + + std::list face_list; + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[1]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[5]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[11]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[10]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[7]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[4]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[2]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[6]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[8]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[9]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + + // TODO: Refine icosahedron to create icosphere + const unsigned int refinements = 3; + for (unsigned int current_refinement = 0; current_refinement < refinements; ++current_refinement) { + std::list refined_face_list; + for (auto &face: face_list) { + Kernel::Point_3 vertex0 = face.outer[0]; + Kernel::Point_3 vertex1 = face.outer[1]; + Kernel::Point_3 vertex2 = face.outer[2]; + + Kernel::Point_3 midpoint01 = CGAL::midpoint(vertex0, vertex1); + Kernel::Point_3 midpoint12 = CGAL::midpoint(vertex1, vertex2); + Kernel::Point_3 midpoint20 = CGAL::midpoint(vertex2, vertex0); + + double midpoint01_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint01, Kernel::Point_3(0, 0, 0)))); + midpoint01 = Kernel::Point_3(midpoint01.x()/midpoint01_distance_to_origin, + midpoint01.y()/midpoint01_distance_to_origin, + midpoint01.z()/midpoint01_distance_to_origin); + double midpoint12_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint12, Kernel::Point_3(0, 0, 0)))); + midpoint12 = Kernel::Point_3(midpoint12.x()/midpoint12_distance_to_origin, + midpoint12.y()/midpoint12_distance_to_origin, + midpoint12.z()/midpoint12_distance_to_origin); + double midpoint20_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint20, Kernel::Point_3(0, 0, 0)))); + midpoint20 = Kernel::Point_3(midpoint20.x()/midpoint20_distance_to_origin, + midpoint20.y()/midpoint20_distance_to_origin, + midpoint20.z()/midpoint20_distance_to_origin); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(vertex0); + refined_face_list.back().outer.push_back(midpoint01); + refined_face_list.back().outer.push_back(midpoint20); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(vertex1); + refined_face_list.back().outer.push_back(midpoint12); + refined_face_list.back().outer.push_back(midpoint01); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(vertex2); + refined_face_list.back().outer.push_back(midpoint20); + refined_face_list.back().outer.push_back(midpoint12); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(midpoint01); + refined_face_list.back().outer.push_back(midpoint12); + refined_face_list.back().outer.push_back(midpoint20); + } face_list = refined_face_list; + } + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + polyhedron.delegate(builder); + +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/sphere.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); + + // 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); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = Kernel::Point_3(vertex->point().x()*r, + vertex->point().y()*r, + vertex->point().z()*r).transform(trsf); + } + +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/sphere.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); + + shape = polyhedron; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cgal_shape_t& shape) { + const double dx = l->XLength() * getValue(GV_LENGTH_UNIT); + const double dy = l->YLength() * getValue(GV_LENGTH_UNIT); + const double dz = l->Height() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + // Base + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + + // Lateral faces + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, cgal_shape_t& shape) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + const double h = l->Height() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + const int segments = 25; + + // Base + face_list.push_back(cgal_face_t()); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } + + // Side faces + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + int next_segment = (current_segment+1)%segments; + double next_angle = next_segment*2.0*3.141592653589793/((double)segments); + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(next_angle), r*sin(next_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), h)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(next_angle), r*sin(next_angle), h)); + } + + // Top + face_list.push_back(cgal_face_t()); + for (int current_segment = segments-1; current_segment >= 0; --current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), h)); + } + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal_shape_t& shape) { + const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT); + const double h = l->Height() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + const int segments = 25; + + // Base + face_list.push_back(cgal_face_t()); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } + + // Side faces + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + int next_segment = (current_segment+1)%segments; + double next_angle = next_segment*2.0*3.141592653589793/((double)segments); + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(next_angle), r*sin(next_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, h)); + } + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index 56e43432c3..c6d8820c65 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -18,7 +18,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& return false; } - // TODO: Remove repeated points (and points that are too close to one another?) + // TODO: Remove repeated points and points that are too close to one another // remove_duplicate_points_from_loop(polygon, true); std::size_t count = polygon.size(); @@ -41,3 +41,21 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyline* l, cgal_wire_t& result) { + IfcSchema::IfcCartesianPoint::list::ptr points = l->Points(); + + // Parse and store the points in a sequence + cgal_wire_t polygon = std::vector(); + for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { + cgal_point_t pnt; + IfcGeom::CgalKernel::convert(*it, pnt); + polygon.push_back(pnt); + } + + // TODO: Remove points that are too close to one another + // remove_duplicate_points_from_loop(polygon, false); + + result = polygon; + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 4e82272375..748fd4fbb3 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -47,6 +47,7 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include #include #include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; @@ -130,6 +131,8 @@ namespace IfcGeom { bool convert_wire(const IfcUtil::IfcBaseClass* L, cgal_wire_t& result); bool convert_curve(const IfcUtil::IfcBaseClass* L, cgal_curve_t& result); bool convert_face(const IfcUtil::IfcBaseClass* L, cgal_face_t& result); + + bool convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face); // bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes);