diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 9f80843bb6..93947879ea 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -29,14 +29,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid*, cgal_s bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); -// for (const double &coordinate: xyz) std::cout << coordinate << " "; -// std::cout << std::endl; if (xyz.size() == 3) { point = new Kernel::Point_3(xyz[0], xyz[1], xyz[2]); -// std::cout << *point << std::endl; return true; } else { - point = new Kernel::Point_3(); - return false; + throw std::runtime_error("Point without 3 coordinates"); } } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index 08577a7866..73232096a5 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -169,213 +169,42 @@ bool IfcGeom::CgalKernel::convert_face(const IfcBaseClass* l, cgal_face_t& r) { bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face) { IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds(); + + int num_outer_bounds = 0; + + for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { + IfcSchema::IfcFaceBound* bound = *it; + if (bound->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; + } -// Handle(Geom_Surface) face_surface; -// const bool is_face_surface = l->is(IfcSchema::Type::IfcFaceSurface); -// -// if (is_face_surface) { -// IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l; -// fs->FaceSurface(); -// // FIXME: Surfaces are interpreted as a TopoDS_Shape -// TopoDS_Shape surface_shape; -// if (!convert_shape(fs->FaceSurface(), surface_shape)) return false; -// -// // FIXME: Assert this obtaines the only face -// TopExp_Explorer exp(surface_shape, TopAbs_FACE); -// if (!exp.More()) return false; -// -// TopoDS_Face surface = TopoDS::Face(exp.Current()); -// face_surface = BRep_Tool::Surface(surface); -// } -// -// const int num_bounds = bounds->size(); -// int num_outer_bounds = 0; -// -// for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { -// IfcSchema::IfcFaceBound* bound = *it; -// if (bound->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; -// } -// -// // The number of outer bounds should be one according to the schema. Also Open Cascade -// // expects this, but it is not strictly checked. Regardless, if the number is greater, -// // the face will still be processed as long as there are no holes. A compound of faces -// // is returned in that case. -// if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) { -// Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); -// return false; -// } -// -// TopoDS_Compound compound; -// BRep_Builder builder; -// if (num_outer_bounds > 1) { -// builder.MakeCompound(compound); -// } -// -// TopTools_DataMapOfShapeInteger wire_senses; -// -// // The builder is initialized on the heap because of the various different moments -// // of initialization depending on the configuration of surfaces and boundaries. -// BRepBuilderAPI_MakeFace* mf = 0; -// -// bool success = false; -// int processed = 0; -// -// for (int process_interior = 0; process_interior <= 1; ++process_interior) { - for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { - IfcSchema::IfcFaceBound* bound = *it; - IfcSchema::IfcLoop* loop = bound->Bound(); + if (num_outer_bounds != 1) { + Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); + return false; + } + + cgal_face_t mf = new CgalFace(); -// bool same_sense = bound->Orientation(); -// const bool is_interior = -// !bound->is(IfcSchema::Type::IfcFaceOuterBound) && -// (num_bounds > 1) && -// (num_outer_bounds < num_bounds); -// -// // The exterior face boundary is processed first -// if (is_interior == !process_interior) continue; -// - cgal_wire_t wire; - if (!convert_wire(loop, wire)) { - Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); -// delete mf; - return false; - } + for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { + IfcSchema::IfcFaceBound* bound = *it; + IfcSchema::IfcLoop* loop = bound->Bound(); -// if (!same_sense) { -// wire.Reverse(); -// } -// -// wire_senses.Bind(wire.Oriented(TopAbs_FORWARD), same_sense ? TopAbs_FORWARD : TopAbs_REVERSED); -// -// bool flattened_wire = false; -// -// if (!mf) { -// process_wire: -// -// if (face_surface.IsNull()) { -// mf = new BRepBuilderAPI_MakeFace(wire); -// } else { -// /// @todo check necessity of false here -// mf = new BRepBuilderAPI_MakeFace(face_surface, wire, false); -// } -// -// if (mf->IsDone()) { -// TopoDS_Face outer_face_bound = mf->Face(); -// -// // In case of (non-planar) face surface, p-curves need to be computed. -// // For planar faces, Open Cascade generates p-curves on the fly. -// if (!face_surface.IsNull()) { -// TopExp_Explorer exp(outer_face_bound, TopAbs_EDGE); -// for (; exp.More(); exp.Next()) { -// const TopoDS_Edge& edge = TopoDS::Edge(exp.Current()); -// ShapeFix_Edge fix_edge; -// fix_edge.FixAddPCurve(edge, outer_face_bound, false, getValue(GV_PRECISION)); -// } -// } -// -// if (BRepCheck_Face(outer_face_bound).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) { -// wire.Reverse(); -// same_sense = !same_sense; -// delete mf; -// if (face_surface.IsNull()) { -// mf = new BRepBuilderAPI_MakeFace(wire); -// } else { -// mf = new BRepBuilderAPI_MakeFace(face_surface, wire); -// } -// ShapeFix_Face fix(mf->Face()); -// fix.FixOrientation(); -// outer_face_bound = fix.Face(); -// } -// -// if (num_outer_bounds > 1) { -// builder.Add(compound, outer_face_bound); -// delete mf; mf = 0; -// } else if (num_bounds > 1) { -// // Reinitialize the builder to the outer face -// // bound in order to add holes more robustly. -// delete mf; -// // TODO: What about the face_surface? -// mf = new BRepBuilderAPI_MakeFace(outer_face_bound); -// } else { -// face = outer_face_bound; -// success = true; -// } -// } else { -// const bool non_planar = mf->Error() == BRepBuilderAPI_NotPlanar; -// delete mf; -// if (!non_planar || flattened_wire || !flatten_wire(wire)) { -// Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound->entity); -// return false; -// } else { -// Logger::Message(Logger::LOG_ERROR, "Flattening face boundary", bound->entity); -// flattened_wire = true; -// goto process_wire; -// } -// } -// -// } else { -// mf->Add(wire); -// } -// processed ++; + const bool is_interior = !bound->is(IfcSchema::Type::IfcFaceOuterBound); + + cgal_wire_t wire; + if (!convert_wire(loop, wire)) { + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); + delete mf; + return false; } -// } -// -// if (!success) { -// success = processed == num_bounds; -// if (success) { -// if (num_outer_bounds > 1) { -// face = compound; -// } else { -// success = success && mf->IsDone(); -// if (success) { -// face = mf->Face(); -// } -// -// ShapeFix_Face sfs(TopoDS::Face(face)); -// TopTools_DataMapOfShapeListOfShape wire_map; -// sfs.FixOrientation(wire_map); -// -// TopoDS_Iterator jt(face, false); -// for (; jt.More(); jt.Next()) { -// const TopoDS_Wire& w = TopoDS::Wire(jt.Value()); -// if (wire_map.IsBound(w)) { -// const TopTools_ListOfShape& shapes = wire_map.Find(w); -// TopTools_ListIteratorOfListOfShape it(shapes); -// for (; it.More(); it.Next()) { -// // Apparently the wire got reversed, so register it with opposite orientation in the map -// wire_senses.Bind(it.Value(), wire_senses.Find(w) == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD); -// } -// } -// } -// -// face = TopoDS::Face(sfs.Face()); -// } -// } -// } -// -// if (success) { -// // If the wires are reversed the face needs to be reversed as well in order -// // to maintain the counter-clock-wise ordering of the bounding wire's vertices. -// if (num_bounds == 1 || true) { -// bool all_reversed = true; -// TopoDS_Iterator jt(face, false); -// for (; jt.More(); jt.Next()) { -// const TopoDS_Wire& w = TopoDS::Wire(jt.Value()); -// if (!wire_senses.IsBound(w.Oriented(TopAbs_FORWARD)) || (w.Orientation() == wire_senses.Find(w.Oriented(TopAbs_FORWARD)))) { -// all_reversed = false; -// } -// } -// -// if (all_reversed) { -// face.Reverse(); -// } -// } -// -// ShapeFix_ShapeTolerance FTol; -// FTol.SetTolerance(face, getValue(GV_PRECISION), TopAbs_FACE); -// } -// -// delete mf; + + if (!is_interior) { + mf->outer = wire; + } else { + mf->inner.push_back(wire); + } + } + + face = mf; return true; } @@ -387,30 +216,29 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { cgal_point_t pnt; IfcGeom::CgalKernel::convert(*it, pnt); -// std::cout << *pnt << std::endl; polygon->push_back(*pnt); } // A loop should consist of at least three vertices - int original_count = polygon->size(); + std::size_t original_count = polygon->size(); if (original_count < 3) { Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); return false; } -// // Remove 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); -// -// int count = polygon.Length(); -// if (original_count - count != 0) { -// std::stringstream ss; ss << (original_count - count) << " edges removed for:"; -// Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity); -// } -// -// if (count < 3) { -// Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); -// return false; -// } + + 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(), l->entity); + } + + if (count < 3) { + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); + return false; + } result = polygon; return true; diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 377a2687fb..dc3cdbd9b7 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -44,12 +44,18 @@ if ( it != cache.T.end() ) { e = it->second; return true; } typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; -typedef CGAL::Polyhedron_3 *cgal_shape_t; -typedef std::vector *cgal_face_t; -typedef std::vector *cgal_wire_t; -typedef std::vector *cgal_curve_t; typedef Kernel::Aff_transformation_3 *cgal_placement_t; typedef Kernel::Point_3 *cgal_point_t; +typedef std::vector *cgal_curve_t; +typedef std::vector *cgal_wire_t; + +struct CgalFace { + cgal_wire_t outer; + std::vector inner; +}; + +typedef CgalFace *cgal_face_t; +typedef CGAL::Polyhedron_3 *cgal_shape_t; namespace IfcGeom {