diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index e9d417a32a..e0da238b8b 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -1514,40 +1514,44 @@ namespace latebound_access { void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { { - auto delete_range = [&f](const IfcParse::IfcFile::type_iterator_range_t& insts) { + auto delete_reversed = [&f](const aggregate_of_instance::ptr& insts) { + if (!insts) { + return; + } // Lists are traversed back to front as the list may be mutated when // instances are removed from the grouping by type. - for (auto it = insts.first; it != insts.second; ++it) { - f.removeEntity(&**it); + for (auto it = insts->end() - 1; it >= insts->begin(); --it) { + IfcUtil::IfcBaseClass* const inst = *it; + f.removeEntity(inst); } }; // Delete quantities auto quantities = f.instances_by_type("IfcPhysicalQuantity"); - for (auto& q : boost::make_iterator_range(quantities)) { - // @todo test iterator invalidation - if (q->declaration().name() == "IfcPhysicalComplexQuantity") { - f.removeEntity(&*q); - } + if (quantities) { + quantities = quantities->filtered({ f.schema()->declaration_by_name("IfcPhysicalComplexQuantity") }); + delete_reversed(quantities); } // Delete complexes - delete_range(f.instances_by_type("IfcPhysicalComplexQuantity")); + delete_reversed(f.instances_by_type("IfcPhysicalComplexQuantity")); auto element_quantities = f.instances_by_type("IfcElementQuantity"); // Capture relationship nodes std::vector relationships; auto IfcRelDefinesByProperties = f.schema()->declaration_by_name("IfcRelDefinesByProperties"); - for (auto& eq : boost::make_iterator_range(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_range(element_quantities); + // Delete element quantities + delete_reversed(element_quantities); + } // Delete relationship nodes diff --git a/src/ifcparse/IfcFile.h b/src/ifcparse/IfcFile.h index 0606f23860..9efc37fbb5 100644 --- a/src/ifcparse/IfcFile.h +++ b/src/ifcparse/IfcFile.h @@ -232,7 +232,7 @@ class IFC_PARSE_API IfcFile { /// IfcWall will also return IfcWallStandardCase entities template typename T::list::ptr instances_by_type() { - auto range = instances_by_type(&T::Class()); + auto range = instances_by_type_range(&T::Class()); typename T::list::ptr vec(new typename T::list); for (auto it = range.first; it != range.second; ++it) { vec->push((*it)->template as()); @@ -242,7 +242,7 @@ class IFC_PARSE_API IfcFile { template typename T::list::ptr instances_by_type_excl_subtypes() { - auto range = instances_by_type_excl_subtypes(&T::Class()); + auto range = instances_by_type_excl_subtypes_range(&T::Class()); typename T::list::ptr vec(new typename T::list); for (auto it = range.first; it != range.second; ++it) { vec->push((*it)->template as()); @@ -253,18 +253,24 @@ class IFC_PARSE_API IfcFile { /// Returns all entities in the file that match the positional argument. /// NOTE: This also returns subtypes of the requested type, for example: /// IfcWall will also return IfcWallStandardCase entities - type_iterator_range_t instances_by_type(const IfcParse::declaration*); + type_iterator_range_t instances_by_type_range(const IfcParse::declaration*); /// Returns all entities in the file that match the positional argument. - type_iterator_range_t instances_by_type_excl_subtypes(const IfcParse::declaration*); + type_iterator_range_t instances_by_type_excl_subtypes_range(const IfcParse::declaration*); /// Returns all entities in the file that match the positional argument. /// NOTE: This also returns subtypes of the requested type, for example: /// IfcWall will also return IfcWallStandardCase entities - type_iterator_range_t instances_by_type(const std::string& type); + type_iterator_range_t instances_by_type_range(const std::string& type); /// Returns all entities in the file that match the positional argument. - type_iterator_range_t instances_by_type_excl_subtypes(const std::string& type); + type_iterator_range_t instances_by_type_excl_subtypes_range(const std::string& type); + + /// Compatibility functions that take the ranges from above and turn into an aggregate + aggregate_of_instance::ptr instances_by_type(const IfcParse::declaration* decl); + aggregate_of_instance::ptr instances_by_type_excl_subtypes(const IfcParse::declaration* decl); + aggregate_of_instance::ptr instances_by_type(const std::string& type); + aggregate_of_instance::ptr instances_by_type_excl_subtypes(const std::string& type); /// Returns all entities in the file that reference the id aggregate_of_instance::ptr instances_by_reference(int id); diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 338f308b30..eb3eca58fd 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -2390,20 +2390,20 @@ void IfcFile::process_deletion_() { batch_deletion_ids_.clear(); } -IfcFile::type_iterator_range_t IfcFile::instances_by_type(const IfcParse::declaration* t) { +IfcFile::type_iterator_range_t IfcFile::instances_by_type_range(const IfcParse::declaration* t) { return bytype_.equal_range(t); } -IfcFile::type_iterator_range_t IfcFile::instances_by_type_excl_subtypes(const IfcParse::declaration* t) { +IfcFile::type_iterator_range_t IfcFile::instances_by_type_excl_subtypes_range(const IfcParse::declaration* t) { return bytype_.equal_range(t); } -IfcFile::type_iterator_range_t IfcFile::instances_by_type(const std::string& t) { - return instances_by_type(schema()->declaration_by_name(t)); +IfcFile::type_iterator_range_t IfcFile::instances_by_type_range(const std::string& t) { + return instances_by_type_range(schema()->declaration_by_name(t)); } -IfcFile::type_iterator_range_t IfcFile::instances_by_type_excl_subtypes(const std::string& t) { - return instances_by_type_excl_subtypes(schema()->declaration_by_name(t)); +IfcFile::type_iterator_range_t IfcFile::instances_by_type_excl_subtypes_range(const std::string& t) { + return instances_by_type_excl_subtypes_range(schema()->declaration_by_name(t)); } aggregate_of_instance::ptr IfcFile::instances_by_reference(int t) { @@ -2623,10 +2623,10 @@ void IfcFile::setDefaultHeaderValues() { std::pair IfcFile::getUnit(const std::string& unit_type) { std::pair return_value(0, 1.); - auto projects = instances_by_type(schema()->declaration_by_name("IfcProject")); + auto projects = instances_by_type_range(schema()->declaration_by_name("IfcProject")); if (std::distance(projects.first, projects.second) == 0) { try { - projects = instances_by_type(schema()->declaration_by_name("IfcContext")); + projects = instances_by_type_range(schema()->declaration_by_name("IfcContext")); } catch (IfcException& e) { } } @@ -2709,7 +2709,31 @@ void IfcParse::IfcFile::build_inverses() { } } +/// Compatibility functions that take the ranges from above and turn into an aggregate +aggregate_of_instance::ptr IfcParse::IfcFile::instances_by_type(const IfcParse::declaration* decl) { + aggregate_of_instance::ptr aggr(new aggregate_of_instance); + for (auto& inst : boost::make_iterator_range(instances_by_type_range(decl))) { + aggr->push(&*inst); + } + return aggr; +} +aggregate_of_instance::ptr IfcParse::IfcFile::instances_by_type_excl_subtypes(const IfcParse::declaration* decl) { + aggregate_of_instance::ptr aggr(new aggregate_of_instance); + for (auto& inst : boost::make_iterator_range(instances_by_type_excl_subtypes_range(decl))) { + aggr->push(&*inst); + } + return aggr; +} +aggregate_of_instance::ptr IfcParse::IfcFile::instances_by_type(const std::string& type) { + return instances_by_type(schema()->declaration_by_name(type)); +} +aggregate_of_instance::ptr IfcParse::IfcFile::instances_by_type_excl_subtypes(const std::string& type) { + return instances_by_type_excl_subtypes(schema()->declaration_by_name(type)); +} + + std::atomic_uint32_t IfcUtil::IfcBaseClass::counter_(0); bool IfcParse::IfcFile::lazy_load_ = true; bool IfcParse::IfcFile::guid_map_ = true; + diff --git a/src/ifcwrap/IfcParseWrapper.i b/src/ifcwrap/IfcParseWrapper.i index 7f7540a386..6e04a5dc2a 100644 --- a/src/ifcwrap/IfcParseWrapper.i +++ b/src/ifcwrap/IfcParseWrapper.i @@ -46,9 +46,9 @@ private: %ignore IfcUtil::IfcBaseClass::is; -%rename("by_id") instance_by_id; -%rename("by_type") instances_by_type; -%rename("by_type_excl_subtypes") instances_by_type_excl_subtypes; +%ignore IfcParse::IfcFile::instance_by_id; +%ignore IfcParse::IfcFile::instances_by_type; +%ignore IfcParse::IfcFile::instances_by_type_excl_subtypes; %rename("file") IfcFile; %ignore IfcParse::IfcFile::addEntity; @@ -185,6 +185,28 @@ IfcUtil::ArgumentType helper_fn_attribute_type(const entity_instance* inst, unsi return $self->instance_by_guid(guid); } + entity_instance by_id(int i) { + return $self->instance_by_id_2(i); + } + + std::vector by_type(const std::string& ty) { + std::vector vec; + auto range = $self->instances_by_type_range(ty); + for (auto& inst : boost::make_iterator_range(range)) { + vec.push_back(inst); + } + return vec; + } + + std::vector by_type_excl_subtypes(const std::string& ty) { + std::vector vec; + auto range = $self->instances_by_type_excl_subtypes_range(ty); + for (auto& inst : boost::make_iterator_range(range)) { + vec.push_back(inst); + } + return vec; + } + entity_instance add(entity_instance& e, int i) { return $self->addEntity(e, i); } @@ -405,13 +427,17 @@ IfcUtil::ArgumentType helper_fn_attribute_type(const entity_instance* inst, unsi } } - void setArgumentAsNull(unsigned int i) { + void setAttribute(unsigned int i, PyObject* obj) { bool is_optional = $self->declaration().as_entity()->attribute_by_index(i)->optional(); + + if () if (is_optional) { self->data().setArgument(i, new IfcWrite::IfcWriteArgument()); } else { throw IfcParse::IfcException("Attribute not set"); } + + IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i); } void setArgumentAsInt(unsigned int i, int v) { diff --git a/src/ifcwrap/utils/typemaps_out.i b/src/ifcwrap/utils/typemaps_out.i index 9c821ed3b5..63d5e72c30 100644 --- a/src/ifcwrap/utils/typemaps_out.i +++ b/src/ifcwrap/utils/typemaps_out.i @@ -1,11 +1,3 @@ -%typemap(out) aggregate_of_instance::ptr { - const unsigned size = $1 ? $1->size() : 0; - $result = PyTuple_New(size); - for (unsigned i = 0; i < size; ++i) { - PyTuple_SetItem($result, i, pythonize((*$1)[i])); - } -} - %typemap(out) IfcUtil::ArgumentType { $result = SWIG_Python_str_FromChar(IfcUtil::ArgumentTypeToString($1)); } @@ -141,7 +133,7 @@ CREATE_VECTOR_TYPEMAP_OUT(int) CREATE_VECTOR_TYPEMAP_OUT(unsigned int) CREATE_VECTOR_TYPEMAP_OUT(double) CREATE_VECTOR_TYPEMAP_OUT(std::string) -// CREATE_VECTOR_TYPEMAP_OUT(IfcGeom::Material) +CREATE_VECTOR_TYPEMAP_OUT(entity_instance) CREATE_VECTOR_TYPEMAP_OUT(IfcParse::attribute const *) CREATE_VECTOR_TYPEMAP_OUT(IfcParse::inverse_attribute const *) CREATE_VECTOR_TYPEMAP_OUT(IfcParse::entity const *) diff --git a/src/serializers/GltfSerializer.cpp b/src/serializers/GltfSerializer.cpp index 1930fd8d09..fac2ed51b0 100644 --- a/src/serializers/GltfSerializer.cpp +++ b/src/serializers/GltfSerializer.cpp @@ -443,14 +443,14 @@ void GltfSerializer::setFile(IfcParse::IfcFile* f) { boost::optional> crs_x_axis; boost::optional> eastings_northings_elevation; - IfcParse::IfcFile::type_iterator_range_t coordops; + aggregate_of_instance::ptr coordops; try { coordops = f->instances_by_type("IfcCoordinateOperation"); } catch (IfcParse::IfcException&) { // Ignored. Schema likely doesn't support IfcCoordinateOperation. } - if (std::distance(coordops.first, coordops.second)) { - for (auto& coordop : boost::make_iterator_range(coordops)) { + if (coordops) { + for (auto& coordop : *coordops) { IfcUtil::IfcBaseClass* source_crs = *coordop->as()->get("SourceCRS"); if (source_crs->declaration().is("IfcGeometricRepresentationContext")) { IfcUtil::IfcBaseClass* target_crs = *coordop->as()->get("TargetCRS"); @@ -486,9 +486,9 @@ void GltfSerializer::setFile(IfcParse::IfcFile* f) { if (!crs_epsg) { auto sites = f->instances_by_type("IfcSite"); - if (std::distance(sites.first, sites.second)) { - auto lat_attr = (*sites.first)->as()->get("RefLatitude"); - auto lon_attr = (*sites.first)->as()->get("RefLongitude"); + if (sites && sites->size() == 1) { + auto lat_attr = (*sites->begin())->as()->get("RefLatitude"); + auto lon_attr = (*sites->begin())->as()->get("RefLongitude"); if (!lat_attr->isNull() && !lon_attr->isNull()) { std::vector lat_dms = *lat_attr; @@ -521,8 +521,8 @@ void GltfSerializer::setFile(IfcParse::IfcFile* f) { auto contexts = f->instances_by_type_excl_subtypes("IfcGeometricRepresentationContext"); - if (std::distance(contexts.first, contexts.second)) { - auto context = (*contexts.first)->as(); + if (contexts && contexts->size() > 0) { + auto context = (*contexts->begin())->as(); auto north_attr = context->get("TrueNorth"); if (!north_attr->isNull()) { IfcUtil::IfcBaseClass* north = *north_attr; diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 8a2f61f0c9..1db8f772da 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -1830,13 +1830,13 @@ void SvgSerializer::addTextAnnotations(const drawing_key& k) { } } - boost::optional annotations; + aggregate_of_instance::ptr annotations; if (file) { annotations = file->instances_by_type("IfcAnnotation"); } if (annotations) { - for (auto& ann_ : boost::make_iterator_range(*annotations)) { - auto ann = ann_->as(); + for (auto& ann_ : *annotations) { + auto ann = (IfcUtil::IfcBaseEntity*) ann_; auto ot = ann->get("ObjectType"); auto nm = ann->get("Name"); @@ -2072,48 +2072,50 @@ void SvgSerializer::finalize() { if (file && storey_height_display_ != SH_NONE && pln && std::abs(pln->Position().Direction().Z()) < 1.e-5) { auto storeys = file->instances_by_type("IfcBuildingStorey"); - const double lu = file->getUnit("LENGTHUNIT").second; - for (auto& s : boost::make_iterator_range(storeys)) { - auto storey = s->as(); - auto a = storey->get("Elevation"); - if (!a->isNull()) { - double elev = *a; - elev *= lu; - auto svg_name = nameElement(storey); + if (storeys) { + const double lu = file->getUnit("LENGTHUNIT").second; + for (auto& s : *storeys) { + auto storey = (IfcUtil::IfcBaseEntity*) s; + auto a = storey->get("Elevation"); + if (!a->isNull()) { + double elev = *a; + elev *= lu; + auto svg_name = nameElement(storey); - gp_Pln elev_pln(gp_Ax3(gp_Pnt(0, 0, elev), gp::DZ(), gp::DX())); - //, pln->Position().XDirection())); - // auto ref_y = pln->Position().YDirection().XYZ().Dot(pln->Position().Location().XYZ()); + gp_Pln elev_pln(gp_Ax3(gp_Pnt(0, 0, elev), gp::DZ(), gp::DX())); + //, pln->Position().XDirection())); + // auto ref_y = pln->Position().YDirection().XYZ().Dot(pln->Position().Location().XYZ()); - double x0, y0, z0, x1, y1, z1; - bnd_.Get(x0, y0, z0, x1, y1, z1); + double x0, y0, z0, x1, y1, z1; + bnd_.Get(x0, y0, z0, x1, y1, z1); - // @todo this is a hack in order to get the auto elevations (which are 0.1 offset from - // the global bounding box) to include the storey height symbols. - x0 -= 0.2; - y0 -= 0.2; - z0 -= 0.2; + // @todo this is a hack in order to get the auto elevations (which are 0.1 offset from + // the global bounding box) to include the storey height symbols. + x0 -= 0.2; + y0 -= 0.2; + z0 -= 0.2; - x1 += 0.2; - y1 += 0.2; - z1 += 0.2; + x1 += 0.2; + y1 += 0.2; + z1 += 0.2; - const double shll = storey_height_line_length_.get_value_or(2.); + const double shll = storey_height_line_length_.get_value_or(2.); - BRepBuilderAPI_MakeFace mf(elev_pln, x0 - shll, x1 + shll, y0 - shll, y1 + shll); - gp_Trsf trsf; - TopoDS_Compound C; - BRep_Builder B; - B.MakeCompound(C); - B.Add(C, mf.Face()); - std::string name; - auto a2 = storey->get("Name"); - if (!a2->isNull()) { - name = (std::string) *a2; + BRepBuilderAPI_MakeFace mf(elev_pln, x0 - shll, x1 + shll, y0 - shll, y1 + shll); + gp_Trsf trsf; + TopoDS_Compound C; + BRep_Builder B; + B.MakeCompound(C); + B.Add(C, mf.Face()); + std::string name; + auto a2 = storey->get("Name"); + if (!a2->isNull()) { + name = (std::string) *a2; + } + write(geometry_data{ + C,{boost::none},trsf,storey,storey,elev,name,nameElement(storey) + }); } - write(geometry_data{ - C,{boost::none},trsf,storey,storey,elev,name,nameElement(storey) - }); } } } @@ -2301,28 +2303,30 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) { file = f; auto storeys = f->instances_by_type("IfcBuildingStorey"); - if (std::distance(storeys.first, storeys.second)) { + if (!storeys || storeys->size() == 0) { auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(file, geometry_settings_); std::vector to_derive_from; to_derive_from.push_back(f->schema()->declaration_by_name("IfcBuilding")); to_derive_from.push_back(f->schema()->declaration_by_name("IfcSite")); for (auto it = to_derive_from.begin(); it != to_derive_from.end(); ++it) { - auto insts = f->instances_by_type(*it); - for (auto& product_ : boost::make_iterator_range(insts)) { - IfcUtil::IfcBaseEntity* product = product_->as(); - if (!product->get("ObjectPlacement")->isNull()) { - auto item = mapping->map(*product->get("ObjectPlacement")); - auto matrix = ifcopenshell::geometry::taxonomy::cast(item); - gp_Trsf trsf; - if (matrix) { - // @todo shouldn't this take into account configurable section height? - setSectionHeight(matrix->translation_part()(3) + 1.); + aggregate_of_instance::ptr insts = f->instances_by_type(*it); + if (insts) { + for (auto jt = insts->begin(); jt != insts->end(); ++jt) { + IfcUtil::IfcBaseEntity* product = (IfcUtil::IfcBaseEntity*) *jt; + if (!product->get("ObjectPlacement")->isNull()) { + auto item = mapping->map(*product->get("ObjectPlacement")); + auto matrix = ifcopenshell::geometry::taxonomy::cast(item); + gp_Trsf trsf; + if (matrix) { + // @todo shouldn't this take into account configurable section height? + setSectionHeight(matrix->translation_part()(3) + 1.); #ifdef TAXONOMY_USE_NAKED_PTR - delete matrix; + delete matrix; #endif - Logger::Warning("No building storeys encountered, used for reference:", product); - return; + Logger::Warning("No building storeys encountered, used for reference:", product); + return; + } } } } @@ -2348,9 +2352,9 @@ void SvgSerializer::setSectionHeightsFromStoreys(double offset) { section_data_.emplace(); auto storeys = file->instances_by_type("IfcBuildingStorey"); const double lu = file->getUnit("LENGTHUNIT").second; - if (std::distance(storeys.first, storeys.second)) { - for (auto& s : boost::make_iterator_range(storeys)) { - auto attr_value = s->as()->get("Elevation"); + if (storeys && storeys->size() > 0) { + for (auto& s : *storeys) { + auto attr_value = ((IfcUtil::IfcBaseEntity*)s)->get("Elevation"); if (!attr_value->isNull()) { double elev; try { @@ -2362,7 +2366,7 @@ void SvgSerializer::setSectionHeightsFromStoreys(double offset) { if (!section_data_->empty()) { boost::get(section_data_->back()).next_elevation = elev * lu; } - section_data_->push_back(horizontal_plan{ s->as(), elev * lu, offset, std::numeric_limits::infinity() }); + section_data_->push_back(horizontal_plan{ (IfcUtil::IfcBaseEntity*)s, elev * lu, offset, std::numeric_limits::infinity() }); } } } else {