diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 4f0916c454..8365758951 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -116,18 +116,17 @@ bool rename_file(const std::string& old_filename, const std::string& new_filenam static std::stringstream log_stream; void write_log(); -/// @todo Make this a feature of IfcGeom::Iterator instead. struct geom_filter { - bool include; - enum filter_type { ENTITY_TYPE, ENTITY_NAME, ENTITY_GUID, LAYER_NAME }; + geom_filter() : type(UNUSED) {} + enum filter_type { UNUSED, ENTITY_TYPE, ENTITY_NAME, ENTITY_GUID, LAYER_NAME }; filter_type type; std::set values; }; // Specialized classes for knowing which type of filter we are validating within validate(). // Could not figure out easily how else to know it if using single type for both. -struct inclusion_filter : public geom_filter { inclusion_filter() { include = true; } }; -struct exclusion_filter : public geom_filter { exclusion_filter() { include = false; } }; +struct inclusion_filter : public IfcGeom::filter, public geom_filter { inclusion_filter() : filter(true, false) {} }; +struct exclusion_filter : public IfcGeom::filter, public geom_filter { exclusion_filter() : filter(false, false) {} }; int main(int argc, char** argv) { @@ -271,7 +270,6 @@ int main(int argc, char** argv) std::cerr << "[Error] Invalid usage of '" << e.get_option_name() << "': " << e.what() << "\n\n"; print_usage(); return EXIT_FAILURE; - return EXIT_FAILURE; } catch (const std::exception& e) { std::cerr << "[Error] " << e.what() << "\n\n"; print_usage(); @@ -295,18 +293,6 @@ int main(int argc, char** argv) print_usage(); return 1; } - if (include_filter.type == geom_filter::ENTITY_GUID) { - guids = include_filter.values; - } else if (exclude_filter.type == geom_filter::ENTITY_GUID) { - guids = exclude_filter.values; - } - - if (include_filter.type == geom_filter::LAYER_NAME) { - layers = include_filter.values; - } else if (exclude_filter.type == geom_filter::LAYER_NAME) { - layers = exclude_filter.values; - } - const bool verbose = vmap.count("verbose") != 0; const bool weld_vertices = vmap.count("weld-vertices") != 0; const bool use_world_coords = vmap.count("use-world-coords") != 0; @@ -316,10 +302,6 @@ int main(int argc, char** argv) const bool merge_boolean_operands = vmap.count("merge-boolean-operands") != 0; #endif const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0; - bool include_entities = include_filter.type == geom_filter::ENTITY_TYPE && !include_filter.values.empty(); - const bool include_names = include_filter.type == geom_filter::ENTITY_NAME && !include_filter.values.empty(); - const bool include_guids = include_filter.type == geom_filter::ENTITY_GUID && !include_filter.values.empty(); - const bool include_layers = include_filter.type == geom_filter::LAYER_NAME && !include_filter.values.empty(); const bool include_plan = vmap.count("plan") != 0; const bool include_model = vmap.count("model") != 0 || (!include_plan); const bool enable_layerset_slicing = vmap.count("enable-layerset-slicing") != 0; @@ -330,6 +312,7 @@ int main(int argc, char** argv) const bool center_model = vmap.count("center-model") != 0 ; const bool model_offset = vmap.count("model-offset") != 0 ; const bool generate_uvs = vmap.count("generate-uvs") != 0 ; + /// @todo For now traversal is a global option for all filters but we could easily make it filter-specific. const bool traverse = vmap.count("traverse") != 0; #ifdef HAVE_ICU @@ -392,6 +375,67 @@ int main(int argc, char** argv) boost::to_lower(output_extension); + // Set up filters. Entity filter is used always by default. + + IfcGeom::entity_filter entity_filter; + entity_filter.traverse = traverse; + try { + if (include_filter.type == geom_filter::ENTITY_TYPE) { + entity_filter.include = true; + entity_filter.populate(include_filter.values); + } else if (exclude_filter.type == geom_filter::ENTITY_TYPE) { + entity_filter.include = false; + entity_filter.populate(exclude_filter.values); + } + // If no entity names are specified these are the defaults to skip from output + if (entity_filter.values.empty()) { + std::set entities; + entities.insert("IfcSpace"); + if (output_extension == ".svg") { + entity_filter.include = true; + } else { + entities.insert("IfcOpeningElement"); + } + entity_filter.populate(entities); + + Logger::Message(Logger::LOG_NOTICE, entity_filter.include ? "Including" : "Excluding" + + std::string(" by default entities ") + boost::algorithm::join(entities, ", ")); + } + } catch (const IfcParse::IfcException& e) { + std::cout << "[Error] " << e.what() << std::endl; + return 1; + } + + IfcGeom::arg_filter name_filter; + name_filter.traverse = traverse; + if (include_filter.type == geom_filter::ENTITY_NAME) { + name_filter.include = true; + name_filter.populate(include_filter.values); + } else if (exclude_filter.type == geom_filter::ENTITY_NAME) { + name_filter.include = false; + name_filter.populate(exclude_filter.values); + } + + IfcGeom::arg_filter guid_filter; + guid_filter.traverse = traverse; + if (include_filter.type == geom_filter::ENTITY_GUID) { + guid_filter.include = true; + guid_filter.populate(include_filter.values); + } else if (exclude_filter.type == geom_filter::ENTITY_GUID) { + guid_filter.include = false; + guid_filter.populate(include_filter.values); + } + + IfcGeom::layer_filter layer_filter; + layer_filter.traverse = traverse; + if (include_filter.type == geom_filter::LAYER_NAME) { + layer_filter.include = true; + layer_filter.populate(include_filter.values); + } else if (exclude_filter.type == geom_filter::LAYER_NAME) { + layer_filter.include = false; + layer_filter.populate(exclude_filter.values); + } + if (output_extension == ".xml") { int exit_code = 1; try { @@ -482,16 +526,18 @@ int main(int argc, char** argv) IfcGeom::Iterator context_iterator(settings, input_filename); - try { - context_iterator.filter_entities(include_entities, entities, traverse); - } catch (const IfcParse::IfcException& e) { - std::cout << "[Error] " << e.what() << std::endl; - return 1; + if (!guid_filter.values.empty()) { + context_iterator.filters().push_back(boost::ref(guid_filter)); + } + if (!name_filter.values.empty()) { + context_iterator.filters().push_back(boost::ref(name_filter)); + } + if (!entity_filter.values.empty()) { + context_iterator.filters().push_back(boost::ref(entity_filter)); + } + if (!layer_filter.values.empty()) { + context_iterator.filters().push_back(boost::ref(layer_filter)); } - - context_iterator.filter_entity_names(include_names, names, traverse); - context_iterator.filter_entity_guids(include_guids, guids, traverse); - context_iterator.filter_layer_names(include_layers, layers, traverse); if (!serializer->ready()) { write_log(); diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index db4c2a4e51..aecd644e98 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -239,7 +239,7 @@ public: std::pair initializeUnits(IfcSchema::IfcUnitAssignment*); - IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*); + static IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*); static std::map get_layers(IfcSchema::IfcProduct* prod); diff --git a/src/ifcgeom/IfcGeomElement.h b/src/ifcgeom/IfcGeomElement.h index 7d1410c938..820727533a 100644 --- a/src/ifcgeom/IfcGeomElement.h +++ b/src/ifcgeom/IfcGeomElement.h @@ -80,6 +80,7 @@ namespace IfcGeom { std::string _context; std::string _unique_id; Transformation

_transformation; + IfcSchema::IfcProduct* product_; public: int id() const { return _id; } int parent_id() const { return _parent_id; } @@ -89,8 +90,12 @@ namespace IfcGeom { const std::string& context() const { return _context; } const std::string& unique_id() const { return _unique_id; } const Transformation

& transformation() const { return _transformation; } - Element(const ElementSettings& settings, 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) + IfcSchema::IfcProduct* product() const { return product_; } + + Element(const ElementSettings& settings, 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, IfcSchema::IfcProduct *product) : _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf) + , product_(product) { std::ostringstream oss; oss << "product-" << IfcParse::IfcGlobalId(guid).formatted(); @@ -112,8 +117,10 @@ namespace IfcGeom { 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, const boost::shared_ptr& geometry) - : Element

(geometry->settings(),id,parent_id,name,type,guid,context,trsf) + 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, + IfcSchema::IfcProduct* product) + : Element

(geometry->settings(),id,parent_id,name,type,guid,context,trsf, product) , _geometry(geometry) {} private: diff --git a/src/ifcgeom/IfcGeomFilter.h b/src/ifcgeom/IfcGeomFilter.h new file mode 100644 index 0000000000..8c42bacc66 --- /dev/null +++ b/src/ifcgeom/IfcGeomFilter.h @@ -0,0 +1,241 @@ +/******************************************************************************** + * * + * This file is part of IfcOpenShell. * + * * + * IfcOpenShell is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as published by * + * the Free Software Foundation, either version 3.0 of the License, or * + * (at your option) any later version. * + * * + * IfcOpenShell is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * Lesser GNU General Public License for more details. * + * * + * You should have received a copy of the Lesser GNU General Public License * + * along with this program. If not, see . * + * * + ********************************************************************************/ + +/** @file IfcGeomFilter.h + @brief A set of predefined product filters for IfcGeom::Iterator */ + +#ifndef IFCGEOMFILTER_H +#define IFCGEOMFILTER_H + +#include "IfcGeom.h" +#include + +namespace IfcGeom +{ + typedef boost::function filter_t; + + struct filter + { + filter() : include(false), traverse(false) {} + filter(bool incl, bool trav) : include(incl), traverse(trav) {} + /// Should the product be included (true) or excluded (false). + bool include; + /// If traversal requested, traverse to the parents to see if they satisfy the criteria. E.g. we might be looking for + /// children of a storey named "Level 20", or children of entities that have no representation, e.g. IfcCurtainWall. + bool traverse; + + //static bool traverse_match(IfcSchema::IfcProduct* prod, filter_t pred) + //{ + // bool is_match = false; + // IfcSchema::IfcProduct* parent, *current = prod; + // while ((parent = static_cast(IfcGeom::Kernel::get_decomposing_entity(current))) != 0) { + // if (pred(parent)) { + // is_match = true; + // break; + // } + // current = parent; + // } + //} + }; + + struct wildcard_filter : public filter + { + wildcard_filter() : filter(false, false) {} + wildcard_filter(bool include, bool traverse, const std::set& patterns) + : filter(include, traverse) + { + populate(patterns); + } + + std::set values; + + void populate(const std::set& patterns) + { + values.clear(); + foreach(const std::string &pattern, patterns) { + values.insert(wildcard_string_to_regex(pattern)); + } + } + + bool match(const std::string &str) const + { + foreach(const boost::regex& r, values) { + if (boost::regex_match(str, r)) { + return true; + } + } + return false; + } + + static boost::regex wildcard_string_to_regex(std::string str) + { + // Escape all non-"*?" regex special chars + std::string special_chars = "\\^.$|()[]+/"; + foreach(char c, special_chars) { + std::string char_str(1, c); + boost::replace_all(str, char_str, "\\" + char_str); + } + // Convert "*?" to their regex equivalents + boost::replace_all(str, "?", "."); + boost::replace_all(str, "*", ".*"); + return boost::regex(str); + } + }; + + /// @todo Maybe not use template class for this after all. Attribute name would be better + /// than index, but IfcBaseClass doesn't have getArgument(name) (IfcLateBoundEntity would have though). + template + struct arg_filter : public wildcard_filter + { + arg_filter() + { +#ifndef NDEBUG + ClassType dummy(0); + assert(ArgIndex < dummy.getArgumentCount()); +#endif + } + arg_filter(bool include, bool traverse, const std::set& patterns) + : wildcard_filter(include, traverse, patterns) + { + #ifndef NDEBUG + ClassType dummy(0); + assert(ArgIndex < dummy.getArgumentCount()); + #endif + populate(patterns); + } + + ArgType value(IfcSchema::IfcProduct* prod) const + { + Argument *arg = prod->entity->getArgument(ArgIndex); + return !arg->isNull() ? *arg : ArgType(); + } + + bool operator()(IfcSchema::IfcProduct* prod) const + { + bool is_match = match(value(prod)); + if (is_match != include && traverse) { + IfcSchema::IfcProduct* parent, *current = prod; + while ((parent = static_cast(IfcGeom::Kernel::get_decomposing_entity(current))) != 0) { + if (match(value(parent))) { + is_match = true; + break; + } + current = parent; + } + } + return is_match == include; + } + }; + + struct layer_filter : public wildcard_filter + { + layer_filter() {} + layer_filter(bool include, bool traverse, const std::set& patterns) + : wildcard_filter(include, traverse, patterns) + { + } + + bool operator()(IfcSchema::IfcProduct* prod) const + { + bool is_match = false; + std::map layers = IfcGeom::Kernel::get_layers(prod); + std::map::const_iterator lit; + for (lit = layers.begin(); lit != layers.end(); ++lit) { + if (match(lit->first)) { + is_match = true; + break; + } + } + + if (is_match != include && traverse) { + for (lit = layers.begin(); lit != layers.end(); ++lit) { + IfcSchema::IfcProduct* parent, *current = prod; + while ((parent = static_cast(IfcGeom::Kernel::get_decomposing_entity(current))) != 0) { + if (match(lit->first)) { + is_match = true; + break; + } + current = parent; + } + if (is_match) { + break; + } + } + } + + return is_match == include; + } + }; + + struct entity_filter : public filter + { + entity_filter() {} + entity_filter(bool include, bool traverse/*, const std::set& types*/) + : filter(include, traverse) + { + //populate(types); + } + + std::set values; + + void populate(const std::set& types) + { + values.clear(); + foreach(const std::string& type, types) { + IfcSchema::Type::Enum ty; + try { + ty = IfcSchema::Type::FromString(boost::to_upper_copy(type)); + } catch (const IfcParse::IfcException&) { + throw IfcParse::IfcException("'" + type + "' does not name a valid IFC entity"); + } + values.insert(ty); + // TODO: Add child classes so that containment in set can be in O(log n) + } + } + + bool match(IfcSchema::IfcProduct* prod) const + { + // The set is iterated over to able to filter on subtypes. + foreach(IfcSchema::Type::Enum type, values) { + if (prod->is(type)) { + return true; + } + } + return false; + } + + bool operator()(IfcSchema::IfcProduct* prod) const + { + bool is_match = match(prod); + if (is_match != include && traverse) { + IfcSchema::IfcProduct* parent, *current = prod; + while ((parent = static_cast(IfcGeom::Kernel::get_decomposing_entity(current))) != 0) { + if (match(parent)) { + is_match = true; + break; + } + current = parent; + } + } + return is_match == include; + } + }; +} + +#endif diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 956bcedc72..d3007be688 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -1174,7 +1174,8 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_pro guid, context_string, trsf, - boost::shared_ptr(shape) + boost::shared_ptr(shape), + product ); } @@ -1216,7 +1217,8 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_processed_representati guid, context_string, trsf, - brep->geometry_pointer() + brep->geometry_pointer(), + product ); } @@ -1234,7 +1236,7 @@ IfcSchema::IfcObjectDefinition* IfcGeom::Kernel::get_decomposing_entity(IfcSchem } else if ( product->is(IfcSchema::Type::IfcElement ) ) { IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids(); - // Incase of a RelatedBuildingElement parent to the opening element + // In case of a RelatedBuildingElement parent to the opening element if ( fills->size() ) { for ( IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++ it ) { IfcSchema::IfcRelFillsElement* fill = *it; diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index b5e58bcf8d..648a5ca4c6 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -65,7 +65,6 @@ #include #include -#include #include #include @@ -81,6 +80,7 @@ #include "../ifcgeom/IfcGeomMaterial.h" #include "../ifcgeom/IfcGeomIteratorSettings.h" #include "../ifcgeom/IfcRepresentationShapeItem.h" +#include "../ifcgeom/IfcGeomFilter.h" // The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration #ifdef min @@ -125,6 +125,16 @@ namespace IfcGeom { gp_XYZ bounds_min_; gp_XYZ bounds_max_; + std::vector filters_; + + struct filter_match + { + filter_match(IfcSchema::IfcProduct *prod) : product(prod) {} + bool operator()(const filter_t& filter) const { return filter(product); } + + IfcSchema::IfcProduct* product; + }; + void initUnits() { IfcSchema::IfcProject::list::ptr projects = ifc_file->entitiesByType(); if (projects->size() == 1) { @@ -135,67 +145,6 @@ namespace IfcGeom { } } - struct filter - { - /// Should the product be included (true) or excluded (false). - bool include; - /// If traversal requested, traverse to the parents to see if they satisfy the criteria. E.g. we might be looking for - /// children of a storey named "Level 20", or children of entities that have no representation, e.g. IfcCurtainWall. - bool traverse; - }; - - struct wildcard_filter : public filter - { - std::set values; - - void populate(const std::set& patterns) - { - values.clear(); - foreach(const std::string &pattern, patterns) { - values.insert(wildcard_string_to_regex(pattern)); - } - } - - static boost::regex wildcard_string_to_regex(std::string str) - { - // Escape all non-"*?" regex special chars - std::string special_chars = "\\^.$|()[]+/"; - foreach(char c, special_chars) { - std::string char_str(1, c); - boost::replace_all(str, char_str, "\\" + char_str); - } - // Convert "*?" to their regex equivalents - boost::replace_all(str, "?", "."); - boost::replace_all(str, "*", ".*"); - return boost::regex(str); - } - }; - - wildcard_filter name_filter_; - wildcard_filter guid_filter_; - wildcard_filter layer_filter_; - - struct entity_filter : public filter - { - std::set values; - - void populate(const std::set& types) - { - values.clear(); - foreach(const std::string& type, types) { - IfcSchema::Type::Enum ty; - try { - ty = IfcSchema::Type::FromString(boost::to_upper_copy(type)); - } catch (const IfcParse::IfcException&) { - throw IfcParse::IfcException("'" + type + "' does not name a valid IFC entity"); - } - values.insert(ty); - // TODO: Add child classes so that containment in set can be in O(log n) - } - } - }; - entity_filter entity_filter_; - public: bool initialize() { try { @@ -358,37 +307,8 @@ namespace IfcGeom { IfcParse::IfcFile* getFile() const { return ifc_file; } - /// @note Entity names are handled case-insensitively. - void filter_entities(bool include, const std::set& entities, bool traverse) - { - entity_filter_.populate(entities); - entity_filter_.include = include; - entity_filter_.traverse = traverse; - } - - /// @note Arbitrary names or wildcard expressions are handled case-sensitively. - void filter_entity_names(bool include, const std::set& names, bool traverse) - { - name_filter_.populate(names); - name_filter_.include = include; - name_filter_.traverse = traverse; - } - - /// @note GUIDs (wildcard expressions allowed) are handled case-sensitively. - void filter_entity_guids(bool include, const std::set& guids, bool traverse) - { - guid_filter_.populate(guids); - guid_filter_.include = include; - guid_filter_.traverse = traverse; - } - - /// @note Arbitrary names or wildcard expressions are handled case-sensitively. - void filter_layer_names(bool include, const std::set& names, bool traverse) - { - layer_filter_.populate(names); - layer_filter_.include = include; - layer_filter_.traverse = traverse; - } + const std::vector &filters() const { return filters_; } + std::vector &filters() { return filters_; } const gp_XYZ& bounds_min() const { return bounds_min_; } const gp_XYZ& bounds_max() const { return bounds_max_; } @@ -410,17 +330,14 @@ namespace IfcGeom { std::set mapped_representations_processed; - struct shape_model { BRepElement

* element; IfcSchema::IfcProduct* product; }; - - shape_model create_shape_model_for_next_entity() { - shape_model ret = {0}; + BRepElement

* create_shape_model_for_next_entity() { for (;;) { IfcSchema::IfcRepresentation* representation; // Have we reached the end of our list of representations? if ( representation_iterator == representations->end() ) { representations.reset(); - return ret; + return 0; } representation = *representation_iterator; @@ -565,124 +482,7 @@ namespace IfcGeom { // Filter the products based on the set of entities and/or names being included or excluded for processing. for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) { IfcSchema::IfcProduct* prod = *jt; - /// @todo Horrible copy-pasta, refactor. - bool type_found = false; - if (!entity_filter_.values.empty()) { - // The set is iterated over to able to filter on subtypes. - foreach(IfcSchema::Type::Enum type, entity_filter_.values) { - if (prod->is(type)) { - type_found = true; - break; - } - } - - if (type_found != entity_filter_.include && entity_filter_.traverse) { - foreach(IfcSchema::Type::Enum type, entity_filter_.values) { - IfcSchema::IfcProduct* parent, *current = prod; - while ((parent = static_cast(kernel.get_decomposing_entity(current))) != 0) { - if (parent->is(type)) { - type_found = true; - break; - } - current = parent; - } - if (type_found) { - break; - } - } - } - } - - bool name_found = false; - if (!name_filter_.values.empty()) { - foreach(const boost::regex& r, name_filter_.values) { - if (prod->hasName() && boost::regex_match(prod->Name(), r)) { - name_found = true; - break; - } - } - - if (name_found != name_filter_.include && name_filter_.traverse) { - foreach(const boost::regex& r, name_filter_.values) { - IfcSchema::IfcProduct* parent, *current = prod; - while ((parent = static_cast(kernel.get_decomposing_entity(current))) != 0) { - if (parent->hasName() && boost::regex_match(parent->Name(), r)) { - name_found = true; - break; - } - current = parent; - } - if (name_found) { - break; - } - } - } - } - - bool guid_found = false; - if (!guid_filter_.values.empty()) { - foreach(const boost::regex& r, guid_filter_.values) { - if (boost::regex_match(prod->GlobalId(), r)) { - std::cout << prod->GlobalId() << std::endl; - guid_found = true; - break; - } - } - - if (guid_found != guid_filter_.include && guid_filter_.traverse) { - foreach(const boost::regex& r, guid_filter_.values) { - IfcSchema::IfcProduct* parent, *current = prod; - while ((parent = static_cast(kernel.get_decomposing_entity(current))) != 0) { - if (boost::regex_match(parent->GlobalId(), r)) { - guid_found = true; - break; - } - current = parent; - } - if (guid_found) { - break; - } - } - } - } - - bool layer_found = false; - if (!layer_filter_.values.empty()) { - std::map layers = IfcGeom::Kernel::get_layers(prod); - std::map::const_iterator lit; - foreach(const boost::regex& r, layer_filter_.values) { - for (lit = layers.begin(); lit != layers.end(); ++lit) { - if (boost::regex_match(lit->first, r)) { - layer_found = true; - break; - } - } - if (layer_found) { - break; - } - } - - if (layer_found != layer_filter_.include && layer_filter_.traverse) { - foreach(const boost::regex& r, layer_filter_.values) { - for (lit = layers.begin(); lit != layers.end(); ++lit) { - IfcSchema::IfcProduct* parent, *current = prod; - while ((parent = static_cast(kernel.get_decomposing_entity(current))) != 0) { - if (boost::regex_match(lit->first, r)) { - layer_found = true; - break; - } - current = parent; - } - if (layer_found) { - break; - } - } - } - } - } - - if (type_found == entity_filter_.include && name_found == name_filter_.include && - guid_found == guid_filter_.include && layer_found == layer_filter_.include) { + if (boost::all(filters_, filter_match(prod))) { ifcproducts->push(prod); } } @@ -696,24 +496,25 @@ namespace IfcGeom { continue; } - ret.product = *ifcproduct_iterator; + IfcSchema::IfcProduct* product = *ifcproduct_iterator; - Logger::SetProduct(ret.product); + Logger::SetProduct(product); + BRepElement

* element; if (ifcproduct_iterator == ifcproducts->begin() || !settings.get(IteratorSettings::USE_WORLD_COORDS)) { - ret.element = kernel.create_brep_for_representation_and_product

(settings, representation, ret.product); + element = kernel.create_brep_for_representation_and_product

(settings, representation, product); } else { - ret.element = kernel.create_brep_for_processed_representation(settings, representation, ret.product, current_shape_model); + element = kernel.create_brep_for_processed_representation(settings, representation, product, current_shape_model); } Logger::SetProduct(boost::none); - if (!ret.element) { + if (!element) { _nextShape(); continue; } - return ret; + return element; } } @@ -727,19 +528,22 @@ namespace IfcGeom { current_shape_model = 0; } - public: - + public: /// Returns what would be the product for the next shape representation - IfcSchema::IfcProduct* peek_next() const - { - if (ifcproducts && ifcproduct_iterator + 1 != ifcproducts->end()){ - return *(ifcproduct_iterator + 1); - } else { - return 0; - } - } + /// @todo Double-check and test the impl. + //IfcSchema::IfcProduct* peek_next() const + //{ + // if (ifcproducts && ifcproduct_iterator + 1 != ifcproducts->end()){ + // return *(ifcproduct_iterator + 1); + // } else { + // return 0; + // } + //} - /// Moves to the next shape representation and returns the associated product. + /// @todo Would this be as simple as the following code? + //void skip_next() { if (ifcproducts) { ++ifcproduct_iterator; } } + + /// Moves to the next shape representation, create its geometry, and returns the associated product. /// Use get() to retrieve the created geometry. IfcSchema::IfcProduct* next() { // Increment the iterator over the list of products using the current @@ -805,7 +609,7 @@ namespace IfcGeom { } IfcSchema::IfcProduct* create() { - shape_model next_shape_model = {0}; + IfcGeom::BRepElement

* next_shape_model = 0; IfcGeom::SerializedElement

* next_serialization = 0; IfcGeom::TriangulationElement

* next_triangulation = 0; @@ -813,19 +617,19 @@ namespace IfcGeom { next_shape_model = create_shape_model_for_next_entity(); } catch (...) {} - if (next_shape_model.element) { + if (next_shape_model) { if (settings.get(IteratorSettings::USE_BREP_DATA)) { try { - next_serialization = new SerializedElement

(*next_shape_model.element); + next_serialization = new SerializedElement

(*next_shape_model); } catch (...) { Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed."); } } else if (!settings.get(IteratorSettings::DISABLE_TRIANGULATION)) { try { if (ifcproduct_iterator == ifcproducts->begin() || settings.get(IteratorSettings::USE_WORLD_COORDS)) { - next_triangulation = new TriangulationElement

(*next_shape_model.element); + next_triangulation = new TriangulationElement

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

(*next_shape_model.element, current_triangulation->geometry_pointer()); + next_triangulation = new TriangulationElement

(*next_shape_model, current_triangulation->geometry_pointer()); } } catch (...) { Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed."); @@ -835,11 +639,11 @@ namespace IfcGeom { free_shapes(); - current_shape_model = next_shape_model.element; + current_shape_model = next_shape_model; current_serialization = next_serialization; current_triangulation = next_triangulation; - return next_shape_model.product; + return next_shape_model ? next_shape_model->product() : 0; } private: void _initialize() { @@ -847,13 +651,6 @@ namespace IfcGeom { current_shape_model = 0; current_serialization = 0; - // Upon initialisation, the (empty) set of entity names, - // should be excluded, or no products would be processed. - entity_filter_.include = false; - name_filter_.include = false; - guid_filter_.include = false; - layer_filter_.include = false; - unit_name = "METER"; unit_magnitude = 1.f;