From a7c7a684ee7fbc1a10c23132d425cc0de1e51f16 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 10 Dec 2018 11:33:54 +0100 Subject: [PATCH] Emit surface genus for representation items --- src/ifcconvert/IfcConvert.cpp | 55 +++++++++++++++++++++--- src/ifcgeom/IfcGeomFunctions.cpp | 18 ++++---- src/ifcgeom/IfcGeomShapes.cpp | 10 ++--- src/ifcgeom/IfcRegister.cpp | 2 +- src/ifcgeom/IfcRepresentationShapeItem.h | 18 ++++---- src/ifcgeom_schema_agnostic/Kernel.cpp | 18 +++++--- src/ifcgeom_schema_agnostic/Kernel.h | 2 +- 7 files changed, 86 insertions(+), 37 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 5cbf2a3989..e2ed533f7b 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -270,7 +270,8 @@ int main(int argc, char** argv) "Not guaranteed to work properly if used with --weld-vertices.") ("default-material-file", po::value(&default_material_filename), "Specifies a material file that describes the material object types will have" - "if an object does not have any specified material in the IFC file."); + "if an object does not have any specified material in the IFC file.") + ("validate", "Checks whether geometrical output conforms to the included explicit quantities."); std::string bounds, offset_str; #ifdef HAVE_ICU @@ -501,6 +502,7 @@ int main(int argc, char** argv) fix_quantities(*ifc_file, no_progress, quiet, stderr_progress); } fs << *ifc_file; + exit_code = EXIT_SUCCESS; } else { Logger::Error("Unable to open output file for writing"); } @@ -1087,15 +1089,18 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std // Capture relationship nodes std::vector relationships; auto IfcRelDefinesByProperties = f.schema()->declaration_by_name("IfcRelDefinesByProperties"); - for (auto& eq : *element_quantities) { - auto rels = eq->data().getInverse(IfcRelDefinesByProperties, -1); - for (auto& rel : *rels) { - relationships.push_back(rel); + if (element_quantities) { + for (auto& eq : *element_quantities) { + auto rels = eq->data().getInverse(IfcRelDefinesByProperties, -1); + for (auto& rel : *rels) { + relationships.push_back(rel); + } } + + // Delete element quantities + delete_reversed(element_quantities); } - // Delete element quantities - delete_reversed(element_quantities); // Delete relationship nodes for (auto& rel : relationships) { @@ -1183,6 +1188,27 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std quantities->push(quantity_area); } + for (auto& part : geom_object->geometry()) { + auto quantity_complex = latebound_access::create(f, "IfcPhysicalComplexQuantity"); + latebound_access::set(quantity_complex, "Name", std::string("Shape validation properties")); + latebound_access::set(quantity_complex, "Discrimination", '#' + boost::lexical_cast(part.ItemId())); + + IfcEntityList::ptr quantities_2(new IfcEntityList); + + int nv = IfcGeom::Kernel::count(part.Shape(), TopAbs_VERTEX, true); + int ne = IfcGeom::Kernel::count(part.Shape(), TopAbs_EDGE, true); + int nf = IfcGeom::Kernel::count(part.Shape(), TopAbs_FACE, true); + + const int euler = nv - ne + nf; + const int genus = (2 - euler) / 2; + + auto quantity_area = latebound_access::create(f, "IfcQuantityCount"); + latebound_access::set(quantity_area, "Name", std::string("Surface genus")); + latebound_access::set(quantity_area, "CountValue", genus); + + latebound_access::set(quantity_complex, "HasQuantities", quantities_2); + } + if (quantities->size()) { quantity = latebound_access::create(f, "IfcElementQuantity"); latebound_access::set(quantity, "OwnerHistory", ownerhist); @@ -1213,4 +1239,19 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std } } } while (++num_created, context_iterator.next()); + + if (!no_progress && quiet) { + for (; old_progress < 100; ++old_progress) { + std::cout << "."; + if (stderr_progress) + std::cerr << "."; + } + std::cout << std::flush; + if (stderr_progress) + std::cerr << std::flush; + } else { + Logger::Status("\rDone writing quantities for " + boost::lexical_cast(num_created) + + " objects "); + } + } diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 0bd94f8124..e430db93e8 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -661,7 +661,7 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons } } - cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(entity_shape, &it3->Style())); + cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(it3->ItemId(), it3->Placement(), entity_shape, &it3->Style())); } return true; @@ -735,7 +735,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, BRepCheck_Analyzer analyser(brep_cut_result); is_valid = analyser.IsValid() != 0; if ( is_valid ) { - cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(brep_cut_result, &it3->Style())); + cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(it3->ItemId(), brep_cut_result, &it3->Style())); } } if ( !is_valid ) { @@ -847,7 +847,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, } } - cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(result, &it3->Style())); + cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(it3->ItemId(), result, &it3->Style())); } return true; } @@ -2442,8 +2442,8 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { TopoDS_Shape a,b; if (split_solid_by_shell(it->Shape(), shells[0], a, b)) { - result.push_back(IfcRepresentationShapeItem(it->Placement(), b, styles[0] ? styles[0] : &it->Style())); - result.push_back(IfcRepresentationShapeItem(it->Placement(), a, styles[1] ? styles[1] : &it->Style())); + result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), b, styles[0] ? styles[0] : &it->Style())); + result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), a, styles[1] ? styles[1] : &it->Style())); } else { continue; } @@ -2485,7 +2485,7 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i for(; it1 != items.end(); ++it1, ++it2) { std::vector::const_iterator it4 = styles.begin(); for (temp_t::value_type::const_iterator it3 = it2->begin(); it3 != it2->end(); ++it3, ++it4) { - result.push_back(IfcRepresentationShapeItem(it1->Placement(), *it3, (*it4) ? (*it4) : &it1->Style())); + result.push_back(IfcRepresentationShapeItem(it1->ItemId(), it1->Placement(), *it3, (*it4) ? (*it4) : &it1->Style())); } } @@ -2505,8 +2505,8 @@ bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, c for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { TopoDS_Shape a,b; if (split_solid_by_surface(it->Shape(), surfaces[1], a, b)) { - result.push_back(IfcRepresentationShapeItem(it->Placement(), b, styles[0] ? styles[0] : &it->Style())); - result.push_back(IfcRepresentationShapeItem(it->Placement(), a, styles[1] ? styles[1] : &it->Style())); + result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), b, styles[0] ? styles[0] : &it->Style())); + result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), a, styles[1] ? styles[1] : &it->Style())); } else { continue; } @@ -2578,7 +2578,7 @@ bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, c for(; it1 != items.end(); ++it1, ++it2) { std::vector::const_iterator it4 = styles.begin(); for (temp_t::value_type::const_iterator it3 = it2->begin(); it3 != it2->end(); ++it3, ++it4) { - result.push_back(IfcRepresentationShapeItem(it1->Placement(), *it3, (*it4) ? (*it4) : &it1->Style())); + result.push_back(IfcRepresentationShapeItem(it1->ItemId(), it1->Placement(), *it3, (*it4) ? (*it4) : &it1->Style())); } } diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index e5628e863b..ea26084fef 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -391,7 +391,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, IfcRepre } } - shape.push_back(IfcRepresentationShapeItem(s, indiv_style ? indiv_style : collective_style)); + shape.push_back(IfcRepresentationShapeItem(l->data().id(), s, indiv_style ? indiv_style : collective_style)); return true; } return false; @@ -405,7 +405,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, IfcR TopoDS_Shape s; const SurfaceStyle* shell_style = get_style(*it); if (convert_shape(*it,s)) { - shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style)); + shapes.push_back(IfcRepresentationShapeItem(l->data().id(), s, shell_style ? shell_style : collective_style)); part_success |= true; } } @@ -469,7 +469,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it); } if (convert_shape(*it,s)) { - shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style)); + shapes.push_back(IfcRepresentationShapeItem(l->data().id(), s, shell_style ? shell_style : collective_style)); } } return true; @@ -725,7 +725,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresen } else { TopoDS_Shape s; if (convert_shape(representation_item,s)) { - shapes.push_back(IfcRepresentationShapeItem(s, get_style(representation_item))); + shapes.push_back(IfcRepresentationShapeItem(l->data().id(), s, get_style(representation_item))); part_succes |= true; } } @@ -752,7 +752,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresenta } else if (element->declaration().is(IfcSchema::IfcSurface::Class())) { style = get_style((IfcSchema::IfcSurface*) element); } - shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style)); + shapes.push_back(IfcRepresentationShapeItem(l->data().id(), s, style ? style : parent_style)); } } return part_succes; diff --git a/src/ifcgeom/IfcRegister.cpp b/src/ifcgeom/IfcRegister.cpp index 514effeeba..08773b09e6 100644 --- a/src/ifcgeom/IfcRegister.cpp +++ b/src/ifcgeom/IfcRegister.cpp @@ -28,7 +28,7 @@ bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationSha if (shape_type(l) != ST_SHAPELIST) { TopoDS_Shape shp; if (convert_shape(l, shp)) { - r.push_back(IfcGeom::IfcRepresentationShapeItem(shp, get_style(l->as()))); + r.push_back(IfcGeom::IfcRepresentationShapeItem(l->data().id(), shp, get_style(l->as()))); return true; } return false; diff --git a/src/ifcgeom/IfcRepresentationShapeItem.h b/src/ifcgeom/IfcRepresentationShapeItem.h index a7885688ca..e78584929c 100644 --- a/src/ifcgeom/IfcRepresentationShapeItem.h +++ b/src/ifcgeom/IfcRepresentationShapeItem.h @@ -31,15 +31,16 @@ namespace IfcGeom { gp_GTrsf placement; TopoDS_Shape shape; const SurfaceStyle* style; + int id; public: - IfcRepresentationShapeItem(const gp_GTrsf& placement, const TopoDS_Shape& shape, const SurfaceStyle* style) - : placement(placement), shape(shape), style(style) {} - IfcRepresentationShapeItem(const gp_GTrsf& placement, const TopoDS_Shape& shape) - : placement(placement), shape(shape), style(0) {} - IfcRepresentationShapeItem(const TopoDS_Shape& shape, const SurfaceStyle* style) - : shape(shape), style(style) {} - IfcRepresentationShapeItem(const TopoDS_Shape& shape) - : shape(shape), style(0) {} + IfcRepresentationShapeItem(int id, const gp_GTrsf& placement, const TopoDS_Shape& shape, const SurfaceStyle* style) + : id(id), placement(placement), shape(shape), style(style) {} + IfcRepresentationShapeItem(int id, const gp_GTrsf& placement, const TopoDS_Shape& shape) + : id(id), placement(placement), shape(shape), style(0) {} + IfcRepresentationShapeItem(int id, const TopoDS_Shape& shape, const SurfaceStyle* style) + : id(id), shape(shape), style(style) {} + IfcRepresentationShapeItem(int id, const TopoDS_Shape& shape) + : id(id), shape(shape), style(0) {} void append(const gp_GTrsf& trsf) { placement.Multiply(trsf); } void prepend(const gp_GTrsf& trsf) { placement.PreMultiply(trsf); } const TopoDS_Shape& Shape() const { return shape; } @@ -47,6 +48,7 @@ namespace IfcGeom { bool hasStyle() const { return style != 0; } const SurfaceStyle& Style() const { return *style; } void setStyle(const SurfaceStyle* style) { this->style = style; } + int ItemId() const { return id; } }; typedef std::vector IfcRepresentationShapeItems; } diff --git a/src/ifcgeom_schema_agnostic/Kernel.cpp b/src/ifcgeom_schema_agnostic/Kernel.cpp index d85c9015ac..06a4e207ce 100644 --- a/src/ifcgeom_schema_agnostic/Kernel.cpp +++ b/src/ifcgeom_schema_agnostic/Kernel.cpp @@ -15,13 +15,19 @@ IfcGeom::Kernel::Kernel(IfcParse::IfcFile* file) { } } -int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t) { - int i = 0; - TopExp_Explorer exp(s, t); - for (; exp.More(); exp.Next()) { - ++i; +int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool unique) { + if (unique) { + TopTools_IndexedMapOfShape map; + TopExp::MapShapes(s, t, map); + return map.Extent(); + } else { + int i = 0; + TopExp_Explorer exp(s, t); + for (; exp.More(); exp.Next()) { + ++i; + } + return i; } - return i; } IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementations() { diff --git a/src/ifcgeom_schema_agnostic/Kernel.h b/src/ifcgeom_schema_agnostic/Kernel.h index 320da2d671..edea2e62a5 100644 --- a/src/ifcgeom_schema_agnostic/Kernel.h +++ b/src/ifcgeom_schema_agnostic/Kernel.h @@ -83,7 +83,7 @@ namespace IfcGeom { return implementation_->convert_placement(item, trsf); } - static int count(const TopoDS_Shape&, TopAbs_ShapeEnum); + static int count(const TopoDS_Shape&, TopAbs_ShapeEnum, bool unique=false); static bool is_manifold(const TopoDS_Shape& a); static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*);