From 59d2d227d9a13b352f20367a20572ed74fe0bf0d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 18 Mar 2016 11:23:25 +0100 Subject: [PATCH] Directly re-use IfcMappedItem triangulated elements when not using world coordinates --- src/ifcconvert/ColladaSerializer.cpp | 22 ++- src/ifcconvert/ColladaSerializer.h | 7 +- src/ifcgeom/IfcGeom.h | 7 + src/ifcgeom/IfcGeomElement.h | 20 +-- src/ifcgeom/IfcGeomFunctions.cpp | 151 ++++++++++++++---- src/ifcgeom/IfcGeomHelpers.cpp | 91 ++++++++++- src/ifcgeom/IfcGeomIterator.h | 226 +++++++++++++++++++++------ 7 files changed, 418 insertions(+), 106 deletions(-) diff --git a/src/ifcconvert/ColladaSerializer.cpp b/src/ifcconvert/ColladaSerializer.cpp index 042eb1647d..8dfa39a0c4 100644 --- a/src/ifcconvert/ColladaSerializer.cpp +++ b/src/ifcconvert/ColladaSerializer.cpp @@ -19,10 +19,12 @@ #ifdef WITH_OPENCOLLADA -#include - #include "ColladaSerializer.h" +#include + +#include + std::string collada_id(const std::string& s) { std::string id; id.reserve(s.size()); @@ -254,7 +256,7 @@ void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_n asset.add(); } -void ColladaSerializer::ColladaExporter::write(const std::string& unique_id, const std::string& type, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& faces, const std::vector& edges, const std::vector& material_ids, const std::vector& _materials) { +void ColladaSerializer::ColladaExporter::write(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& faces, const std::vector& edges, const std::vector& material_ids, const std::vector& _materials) { std::vector material_references; for (std::vector::const_iterator it = _materials.begin(); it != _materials.end(); ++it) { const IfcGeom::Material& material = *it; @@ -263,21 +265,25 @@ void ColladaSerializer::ColladaExporter::write(const std::string& unique_id, con } material_references.push_back(collada_id(material.name())); } - deferreds.push_back(DeferredObject(unique_id, type, matrix, vertices, normals, faces, edges, material_ids, _materials, material_references)); + deferreds.push_back(DeferredObject(unique_id, representation_id, type, matrix, vertices, normals, faces, edges, material_ids, _materials, material_references)); } void ColladaSerializer::ColladaExporter::endDocument() { // In fact due the XML based nature of Collada and its dependency on library nodes, // only at this point all objects are written to the stream. materials.write(); + std::set geometries_written; for (std::vector::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) { - const std::string object_name = it->unique_id + "-representation"; - geometries.write(object_name, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials); + if (geometries_written.find(it->representation_id) != geometries_written.end()) { + continue; + } + geometries_written.insert(it->representation_id); + geometries.write(it->representation_id, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials); } geometries.close(); for (std::vector::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) { const std::string object_name = it->unique_id; - scene.add(object_name, object_name, object_name + "-representation", it->material_references, it->matrix); + scene.add(object_name, object_name, it->representation_id, it->material_references, it->matrix); } scene.write(); stream.endDocument(); @@ -293,7 +299,7 @@ void ColladaSerializer::writeHeader() { void ColladaSerializer::write(const IfcGeom::TriangulationElement* o) { const IfcGeom::Representation::Triangulation& mesh = o->geometry(); - exporter.write(o->unique_id(), o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials()); + exporter.write(o->unique_id(), "representation-" + boost::lexical_cast(o->geometry().id()), o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials()); } void ColladaSerializer::finalize() { diff --git a/src/ifcconvert/ColladaSerializer.h b/src/ifcconvert/ColladaSerializer.h index cf3a35e733..b8e5059e62 100644 --- a/src/ifcconvert/ColladaSerializer.h +++ b/src/ifcconvert/ColladaSerializer.h @@ -111,7 +111,7 @@ private: }; class DeferredObject { public: - std::string unique_id, type; + std::string unique_id, representation_id, type; std::vector matrix; std::vector vertices; std::vector normals; @@ -120,10 +120,11 @@ private: std::vector material_ids; std::vector materials; std::vector material_references; - DeferredObject(const std::string& unique_id, const std::string& type, const std::vector& matrix, const std::vector& vertices, + DeferredObject(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& faces, const std::vector& edges, const std::vector& material_ids, const std::vector& materials, const std::vector& material_references) : unique_id(unique_id) + , representation_id(representation_id) , type(type) , matrix(matrix) , vertices(vertices) @@ -151,7 +152,7 @@ private: std::vector deferreds; virtual ~ColladaExporter() {} void startDocument(const std::string& unit_name, float unit_magnitude); - void write(const std::string& unique_id, const std::string& type, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& faces, const std::vector& edges, const std::vector& material_ids, const std::vector& materials); + void write(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& faces, const std::vector& edges, const std::vector& material_ids, const std::vector& materials); void endDocument(); }; ColladaExporter exporter; diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 7fff6d189c..86d97302b1 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -142,6 +142,10 @@ public: bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&); void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed); + bool is_identity_transform(IfcUtil::IfcBaseClass*); + + IfcSchema::IfcRelVoidsElement::list::ptr find_openings(IfcSchema::IfcProduct* product); + std::pair initializeUnits(IfcSchema::IfcUnitAssignment*); IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*); @@ -149,6 +153,9 @@ public: template IfcGeom::BRepElement

* create_brep_for_representation_and_product(const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); + template + IfcGeom::BRepElement

* create_brep_for_processed_representation(const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::BRepElement

*); + const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item); template std::pair get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) { diff --git a/src/ifcgeom/IfcGeomElement.h b/src/ifcgeom/IfcGeomElement.h index c65d890a94..e69ea09e9f 100644 --- a/src/ifcgeom/IfcGeomElement.h +++ b/src/ifcgeom/IfcGeomElement.h @@ -107,16 +107,14 @@ namespace IfcGeom { template class BRepElement : public Element

{ private: - Representation::BRep* _geometry; + boost::shared_ptr _geometry; public: + const boost::shared_ptr& geometry_pointer() const { return _geometry; } const Representation::BRep& geometry() const { return *_geometry; } - BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const gp_Trsf& trsf, Representation::BRep* geometry) + BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const gp_Trsf& trsf, const boost::shared_ptr& geometry) : Element

(geometry->settings(),id,parent_id,name,type,guid,context,trsf) , _geometry(geometry) {} - virtual ~BRepElement() { - delete _geometry; - } private: BRepElement(const BRepElement& other); BRepElement& operator=(const BRepElement& other); @@ -125,16 +123,18 @@ namespace IfcGeom { template class TriangulationElement : public Element

{ private: - Representation::Triangulation

* _geometry; + boost::shared_ptr< Representation::Triangulation

> _geometry; public: const Representation::Triangulation

& geometry() const { return *_geometry; } + const boost::shared_ptr< Representation::Triangulation

>& geometry_pointer() const { return _geometry; } TriangulationElement(const BRepElement

& shape_model) : Element

(shape_model) - , _geometry(new Representation::Triangulation

(shape_model.geometry())) + , _geometry(boost::shared_ptr>(new Representation::Triangulation

(shape_model.geometry()))) + {} + TriangulationElement(const Element

& element, const boost::shared_ptr>& geometry) + : Element

(element) + , _geometry(geometry) {} - virtual ~TriangulationElement() { - delete _geometry; - } private: TriangulationElement(const TriangulationElement& other); TriangulationElement& operator=(const TriangulationElement& other); diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 14dd47230f..d2c8a21d7f 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -128,11 +128,13 @@ bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, T } builder.Perform(); shape = builder.SewedShape(); - try { - ShapeFix_Solid sf_solid; - sf_solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); - shape = sf_solid.SolidFromShell(TopoDS::Shell(shape)); - } catch(...) {} + if (shape.ShapeType() == TopAbs_SHELL) { + try { + ShapeFix_Solid sf_solid; + sf_solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); + shape = sf_solid.SolidFromShell(TopoDS::Shell(shape)); + } catch(...) {} + } return true; } @@ -1050,8 +1052,40 @@ void IfcGeom::Kernel::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, T w = builder.Wire(); } +IfcSchema::IfcRelVoidsElement::list::ptr IfcGeom::Kernel::find_openings(IfcSchema::IfcProduct* product) { + + IfcSchema::IfcRelVoidsElement::list::ptr openings(new IfcSchema::IfcRelVoidsElement::list); + if ( product->is(IfcSchema::Type::IfcElement) && !product->is(IfcSchema::Type::IfcOpeningElement) ) { + IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; + openings = element->HasOpenings(); + } + + // Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements? + IfcSchema::IfcObjectDefinition* obdef = product->as(); + for (;;) { +#ifdef USE_IFC4 + IfcSchema::IfcRelAggregates::list::ptr decomposes = obdef->Decomposes(); + for ( IfcSchema::IfcRelAggregates::list::it it = decomposes->begin(); it != decomposes->end(); ++ it ) { +#else + IfcSchema::IfcRelDecomposes::list::ptr decomposes = obdef->Decomposes(); + if (decomposes->size() != 1) break; + +#endif + IfcSchema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->RelatingObject(); + if ( rel_obdef->is(IfcSchema::Type::IfcElement) && !rel_obdef->is(IfcSchema::Type::IfcOpeningElement) ) { + IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)rel_obdef; + openings->push(element->HasOpenings()); + } + + obdef = rel_obdef; + } + + return openings; +} + template IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_product(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) { + IfcGeom::Representation::BRep* shape; IfcGeom::IfcRepresentationShapeItems shapes; @@ -1077,28 +1111,7 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_pro // Does the IfcElement have any IfcOpenings? // Note that openings for IfcOpeningElements are not processed - IfcSchema::IfcRelVoidsElement::list::ptr openings; - if ( product->is(IfcSchema::Type::IfcElement) && !product->is(IfcSchema::Type::IfcOpeningElement) ) { - IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; - openings = element->HasOpenings(); - } - // Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements? - if ( product->is(IfcSchema::Type::IfcBuildingElementPart ) ) { - IfcSchema::IfcBuildingElementPart* part = (IfcSchema::IfcBuildingElementPart*)product; -#ifdef USE_IFC4 - IfcSchema::IfcRelAggregates::list::ptr decomposes = part->Decomposes(); - for ( IfcSchema::IfcRelAggregates::list::it it = decomposes->begin(); it != decomposes->end(); ++ it ) { -#else - IfcSchema::IfcRelDecomposes::list::ptr decomposes = part->Decomposes(); - for ( IfcSchema::IfcRelDecomposes::list::it it = decomposes->begin(); it != decomposes->end(); ++ it ) { -#endif - IfcSchema::IfcObjectDefinition* obdef = (*it)->RelatingObject(); - if ( obdef->is(IfcSchema::Type::IfcElement) ) { - IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)obdef; - openings->push(element->HasOpenings()); - } - } - } + IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product); const std::string product_type = IfcSchema::Type::ToString(product->type()); ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type); @@ -1155,7 +1168,47 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_pro guid, context_string, trsf, - shape + boost::shared_ptr(shape) + ); +} + +template +IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_processed_representation(const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::BRepElement

* brep) { + + int parent_id = -1; + try { + IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product); + if (parent_object) { + parent_id = parent_object->entity->id(); + } + } catch (...) {} + + const std::string name = product->hasName() ? product->Name() : ""; + const std::string guid = product->GlobalId(); + + gp_Trsf trsf; + try { + convert(product->ObjectPlacement(),trsf); + } catch (...) {} + + std::string context_string = ""; + if (representation->hasRepresentationIdentifier()) { + context_string = representation->RepresentationIdentifier(); + } else if (representation->ContextOfItems()->hasContextType()) { + context_string = representation->ContextOfItems()->ContextType(); + } + + const std::string product_type = IfcSchema::Type::ToString(product->type()); + + return new BRepElement

( + product->entity->id(), + parent_id, + name, + product_type, + guid, + context_string, + trsf, + brep->geometry_pointer() ); } @@ -1217,6 +1270,9 @@ IfcSchema::IfcObjectDefinition* IfcGeom::Kernel::get_decomposing_entity(IfcSchem template IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and_product(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); template IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and_product(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); +template IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_processed_representation(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::BRepElement* brep); +template IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_processed_representation(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::BRepElement* brep); + std::pair IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUnitAssignment* unit_assignment) { // Set default units, set length to meters, angles to undefined setValue(IfcGeom::Kernel::GV_LENGTH_UNIT, 1.0); @@ -1301,3 +1357,42 @@ const IfcSchema::IfcRepresentationItem* IfcGeom::Kernel::find_item_carrying_styl return item; } + +bool IfcGeom::Kernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { + IfcSchema::IfcAxis2Placement2D* ax2d; + IfcSchema::IfcAxis2Placement3D* ax3d; + + IfcSchema::IfcCartesianTransformationOperator2D* op2d; + IfcSchema::IfcCartesianTransformationOperator3D* op3d; + IfcSchema::IfcCartesianTransformationOperator2DnonUniform* op2dnonu; + IfcSchema::IfcCartesianTransformationOperator3DnonUniform* op3dnonu; + + if((op2dnonu = l->as()) != 0) { + gp_GTrsf2d gtrsf2d; + convert(op2dnonu, gtrsf2d); + return gtrsf2d.Form() == gp_Identity; + } else if ((op2d = l->as()) != 0) { + gp_Trsf2d trsf2d; + convert(op2d, trsf2d); + return trsf2d.Form() == gp_Identity; + } else if((op3dnonu = l->as()) != 0) { + gp_GTrsf gtrsf; + convert(op3dnonu, gtrsf); + return gtrsf.Form() == gp_Identity; + } else if ((op3d = l->as()) != 0) { + gp_Trsf trsf; + convert(op3d, trsf); + return trsf.Form() == gp_Identity; + } else if((ax2d = l->as()) != 0) { + gp_Trsf2d trsf2d; + convert(ax2d, trsf2d); + return trsf2d.Form() == gp_Identity; + } else if ((ax3d = l->as()) != 0) { + gp_Trsf trsf; + convert(ax3d, trsf); + return trsf.Form() == gp_Identity; + } else { + throw IfcParse::IfcException("Invalid valuation for IfcAxis2Placement / IfcCartesianTransformationOperator"); + } +} + diff --git a/src/ifcgeom/IfcGeomHelpers.cpp b/src/ifcgeom/IfcGeomHelpers.cpp index 8b6ef76eac..29851a2627 100644 --- a/src/ifcgeom/IfcGeomHelpers.cpp +++ b/src/ifcgeom/IfcGeomHelpers.cpp @@ -77,6 +77,53 @@ #include "../ifcgeom/IfcGeom.h" +// Helper functions (re)set gp_(G)Trsf(2d) forms explicitly to 'Identity' +// so that it can be easily identified in the IfcMappedItem processing + +// For axis placements detect equality early in order for the +// relatively computionaly expensive gp_Trsf calculation to be skipped +template +bool axis_equal(const T& a, const T& b, double tolerance); +template <> +bool axis_equal(const gp_Ax3& a, const gp_Ax3& b, double tolerance) { + if (!a.Location().IsEqual(b.Location(), tolerance)) return false; + // Note that the tolerance below is angular, above is linear. Since architectural + // objects are about 1m'ish in scale, it should be somewhat equivalent. Besides, + // this is mostly a filter for NULL or default values in the placements. + if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false; + if (!a.XDirection().IsEqual(b.XDirection(), tolerance)) return false; + if (!a.YDirection().IsEqual(b.YDirection(), tolerance)) return false; + return true; +} + +bool axis_equal(const gp_Ax2d& a, const gp_Ax2d& b, double tolerance) { + if (!a.Location().IsEqual(b.Location(), tolerance)) return false; + if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false; + return true; +} + +template struct dimension_count {}; +template <> struct dimension_count { static const int n = 2; }; +template <> struct dimension_count { static const int n = 2; }; +template <> struct dimension_count < gp_Trsf > { static const int n = 3; }; +template <> struct dimension_count < gp_GTrsf > { static const int n = 3; }; + +template +bool is_identity(const T& t, double tolerance) { + // Note the {1, n+1} range due to Open Cascade's 1-based indexing + // Note the {1, n+2} range due to the translation part of the matrix + for (int i = 1; i < dimension_count::n + 2; ++i) { + for (int j = 1; j < dimension_count::n + 1; ++j) { + const double iden_value = i == j ? 1. : 0.; + const double trsf_value = t.Value(j, i); + if (fabs(trsf_value - iden_value) > tolerance) { + return false; + } + } + } + return true; +} + bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) { IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point) std::vector xyz = l->Coordinates(); @@ -120,7 +167,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& gp_Ax3 ax3; if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection); else ax3 = gp_Ax3(o,axis); - trsf.SetTransformation(ax3, gp_Ax3(gp_Pnt(),gp_Dir(0,0,1),gp_Dir(1,0,0))); + + if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) { + trsf.SetTransformation(ax3, gp::XOY()); + } + CACHE(IfcAxis2Placement3D,l,trsf) return true; } @@ -147,9 +198,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato if ( l->hasAxis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3); gp_Ax3 ax3 (origin,axis3,axis1); if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse(); - trsf.SetTransformation(ax3); - trsf.Invert(); - if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale()); + + if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) { + trsf.SetTransformation(ax3); + trsf.Invert(); + } + + if (l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.)) { + trsf.SetScaleFactor(l->Scale()); + } + CACHE(IfcCartesianTransformationOperator3D,l,trsf) return true; } @@ -183,7 +241,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato } trsf.Invert(); - if ( l->hasScale() ) trsf.SetScaleFactor(l->Scale()); + if ( l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.) ) trsf.SetScaleFactor(l->Scale()); + + if (is_identity(trsf, getValue(GV_PRECISION))) { + trsf = gp_Trsf2d(); + } + CACHE(IfcCartesianTransformationOperator2D,l,trsf) return true; } @@ -211,6 +274,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato gtrsf.SetValue(2,2,scale2); gtrsf.SetValue(3,3,scale3); gtrsf.PreMultiply(trsf); + + if (is_identity(gtrsf, getValue(GV_PRECISION))) { + gtrsf = gp_GTrsf(); + } + CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf) return true; } @@ -247,6 +315,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato gtrsf.SetValue(1,1,scale1); gtrsf.SetValue(2,2,scale2); gtrsf.Multiply(trsf); + + if (is_identity(gtrsf, getValue(GV_PRECISION))) { + gtrsf = gp_GTrsf2d(); + } + CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf) return true; } @@ -274,8 +347,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d if ( l->hasRefDirection() ) IfcGeom::Kernel::convert(l->RefDirection(),V); - gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()),gp_Dir2d(V.X(),V.Y())); - trsf.SetTransformation(axis,gp_Ax2d()); + gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()), gp_Dir2d(V.X(),V.Y())); + + if (!axis_equal(axis, gp_Ax2d(), getValue(GV_PRECISION))) { + trsf.SetTransformation(axis, gp_Ax2d()); + } + CACHE(IfcAxis2Placement2D,l,trsf) return true; } diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index ecef8225c8..7e294f260a 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -291,6 +291,8 @@ namespace IfcGeom { ++ done; } + std::set mapped_representations_processed; + BRepElement

* create_shape_model_for_next_entity() { for (;;) { IfcSchema::IfcRepresentation* representation; @@ -305,47 +307,147 @@ namespace IfcGeom { // Has the list of IfcProducts for this representation been initialized? if (!ifcproducts) { - IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation(); ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list); IfcSchema::IfcProduct::list::ptr unfiltered_products(new IfcSchema::IfcProduct::list); - for ( IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it ) { - if ( (*it)->is(IfcSchema::Type::IfcProductDefinitionShape) ) { - IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it; - unfiltered_products->push(pds->ShapeOfProduct()); - } else { - // http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm - // IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards. - // It will be changed into an ABSTRACT supertype in future releases of IFC. + { + IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation(); - // IfcProductRepresentation also lacks the INVERSE relation to IfcProduct - // Let's find the IfcProducts that reference the IfcProductRepresentation anyway - unfiltered_products->push((*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as()); + for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) { + if ((*it)->is(IfcSchema::Type::IfcProductDefinitionShape)) { + IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it; + unfiltered_products->push(pds->ShapeOfProduct()); + } + else { + // http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm + // IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards. + // It will be changed into an ABSTRACT supertype in future releases of IFC. + + // IfcProductRepresentation also lacks the INVERSE relation to IfcProduct + // Let's find the IfcProducts that reference the IfcProductRepresentation anyway + unfiltered_products->push((*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as()); + } } + } - // Filter the products based on the set of entities being included or excluded for - // processing. The set is iterated over te able to filter on subtypes. - for ( IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt ) { - bool found = false; - for (std::set::const_iterator kt = entities_to_include_or_exclude.begin(); kt != entities_to_include_or_exclude.end(); ++kt) { - if ((*jt)->is(*kt)) { - found = true; - break; + const int repid = representation->entity->id(); + + bool has_openings = false; + for (IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it) { + if (kernel.find_openings(*it)->size()) { + has_openings = true; + break; + } + } + + const bool process_maps_for_current_representation = (!has_openings || settings.disable_opening_subtractions()); + bool representation_processed_as_mapped_item = false; + + IfcSchema::IfcRepresentation* representation_mapped_to = 0; + + if (process_maps_for_current_representation) { + IfcSchema::IfcRepresentationItem::list::ptr items = representation->Items(); + if (items->size() == 1) { + IfcSchema::IfcRepresentationItem* item = *items->begin(); + if (item->is(IfcSchema::Type::IfcMappedItem)) { + if (item->StyledByItem()->size() == 0) { + IfcSchema::IfcMappedItem* mapped_item = item->as(); + if (kernel.is_identity_transform(mapped_item->MappingTarget())) { + IfcSchema::IfcRepresentationMap* map = mapped_item->MappingSource(); + if (kernel.is_identity_transform(map->MappingOrigin())) { + representation_mapped_to = map->MappedRepresentation(); + IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation_mapped_to->OfProductRepresentation(); + + bool all_product_without_openings = true; + IfcSchema::IfcProduct::list::ptr products; + + for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) { + IfcSchema::IfcProduct::list::ptr products_of_prodrep = (*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as(); + products->push(products_of_prodrep); + for (IfcSchema::IfcProduct::list::it jt = products_of_prodrep->begin(); jt != products_of_prodrep->end(); ++jt) { + if (kernel.find_openings(*jt)->size() > 0 && !settings.disable_opening_subtractions()) { + all_product_without_openings = false; + break; + } + } + } + + if (all_product_without_openings) { + representation_processed_as_mapped_item = true; + } + } + } } } - if (found == include_entities_in_processing) { - ifcproducts->push(*jt); - } + } + } + + if (representation_mapped_to) { + if (mapped_representations_processed.find(representation_mapped_to) != mapped_representations_processed.end()) { + _nextShape(); + continue; } + mapped_representations_processed.insert(representation_mapped_to); } - // Does this representation have any IfcProducts? - if (!ifcproducts->size()) { + + if (representation_processed_as_mapped_item) { _nextShape(); continue; } + + IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap(); + + if (process_maps_for_current_representation && maps->size() == 1) { + IfcSchema::IfcRepresentationMap* map = *maps->begin(); + if (kernel.is_identity_transform(map->MappingOrigin())) { + IfcSchema::IfcMappedItem::list::ptr items = map->MapUsage(); + for (IfcSchema::IfcMappedItem::list::it it = items->begin(); it != items->end(); ++it) { + IfcSchema::IfcMappedItem* item = *it; + if (item->StyledByItem()->size() != 0) continue; + + if (!kernel.is_identity_transform(item->MappingTarget())) { + continue; + } + + IfcSchema::IfcRepresentation::list::ptr reps = item->entity->getInverse(IfcSchema::Type::IfcRepresentation, -1)->as(); + for (IfcSchema::IfcRepresentation::list::it jt = reps->begin(); jt != reps->end(); ++jt) { + IfcSchema::IfcRepresentation* rep = *jt; + if (rep->Items()->size() != 1) continue; + IfcSchema::IfcProductRepresentation::list::ptr prodreps = rep->OfProductRepresentation(); + for (IfcSchema::IfcProductRepresentation::list::it kt = prodreps->begin(); kt != prodreps->end(); ++kt) { + IfcSchema::IfcProduct::list::ptr prods = (*kt)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as(); + for (IfcSchema::IfcProduct::list::it lt = prods->begin(); lt != prods->end(); ++lt) { + if (kernel.find_openings(*lt)->size() == 0 || settings.disable_opening_subtractions()) { + if (!unfiltered_products->contains(*lt)) { + unfiltered_products->push(*lt); + } + } + } + } + } + } + } + } + + // Filter the products based on the set of entities being included or excluded for + // processing. The set is iterated over to able to filter on subtypes. + for ( IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt ) { + bool found = false; + for (std::set::const_iterator kt = entities_to_include_or_exclude.begin(); kt != entities_to_include_or_exclude.end(); ++kt) { + if ((*jt)->is(*kt)) { + found = true; + break; + } + } + if (found == include_entities_in_processing) { + ifcproducts->push(*jt); + } + } + ifcproduct_iterator = ifcproducts->begin(); } + // Have we reached the end of our list of IfcProducts? if ( ifcproduct_iterator == ifcproducts->end() ) { _nextShape(); @@ -353,8 +455,13 @@ namespace IfcGeom { } IfcSchema::IfcProduct* product = *ifcproduct_iterator; - - BRepElement

* element = kernel.create_brep_for_representation_and_product

(settings, representation, product); + + BRepElement

* element; + if (ifcproduct_iterator == ifcproducts->begin()) { + element = kernel.create_brep_for_representation_and_product

(settings, representation, product); + } else { + element = kernel.create_brep_for_processed_representation(settings, representation, product, current_shape_model); + } if ( !element ) { _nextShape(); @@ -365,9 +472,7 @@ namespace IfcGeom { } } - public: - - bool next() { + void free_shapes() { // Free all possible representations of the current geometrical entity delete current_triangulation; current_triangulation = 0; @@ -375,7 +480,11 @@ namespace IfcGeom { current_serialization = 0; delete current_shape_model; current_shape_model = 0; - + } + + public: + + bool next() { // Increment the iterator over the list of products using the current // shape representation if (ifcproducts) { @@ -429,23 +538,45 @@ namespace IfcGeom { } bool create() { + bool success = true; + + IfcGeom::BRepElement

* next_shape_model = 0; + IfcGeom::SerializedElement

* next_serialization = 0; + IfcGeom::TriangulationElement

* next_triangulation = 0; + try { - current_shape_model = create_shape_model_for_next_entity(); + next_shape_model = create_shape_model_for_next_entity(); } catch (...) {} - if (!current_shape_model) return false; - if (settings.use_brep_data()) { - try { - current_serialization = new SerializedElement

(*current_shape_model); - } catch (...) {} - return !!current_serialization; - } else if (!settings.disable_triangulation()) { - try { - current_triangulation = new TriangulationElement

(*current_shape_model); - } catch (...) {} - return !!current_triangulation; + + if (next_shape_model) { + if (settings.use_brep_data()) { + try { + next_serialization = new SerializedElement

(*next_shape_model); + } catch (...) { + success = false; + } + } else if (!settings.disable_triangulation()) { + try { + if (ifcproduct_iterator == ifcproducts->begin() || settings.use_world_coords()) { + next_triangulation = new TriangulationElement

(*next_shape_model); + } else { + next_triangulation = new TriangulationElement

(*next_shape_model, current_triangulation->geometry_pointer()); + } + } catch (...) { + success = false; + } + } } else { - return true; + success = false; } + + free_shapes(); + + current_shape_model = next_shape_model; + current_serialization = next_serialization; + current_triangulation = next_triangulation; + + return success; } private: void _initialize() { @@ -503,12 +634,7 @@ namespace IfcGeom { delete ifc_file; } - delete current_triangulation; - current_triangulation = 0; - delete current_serialization; - current_serialization = 0; - delete current_shape_model; - current_shape_model = 0; + free_shapes(); } }; }