diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index b4bb33da01..200c760a8a 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -33,6 +33,7 @@ #include "../serializers/XmlSerializer.h" #include "../serializers/SvgSerializer.h" +#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h" #include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" #include @@ -119,16 +120,9 @@ static std::stringstream log_stream; void write_log(bool); /// @todo make the filters non-global -/* IfcGeom::entity_filter entity_filter; // Entity filter is used always by default. IfcGeom::layer_filter layer_filter; -const std::string NAME_ARG = "Name", GUID_ARG = "GlobalId", DESC_ARG = "Description", TAG_ARG = "Tag"; -boost::array supported_args = { { NAME_ARG, GUID_ARG, DESC_ARG, TAG_ARG } }; -IfcGeom::string_arg_filter guid_filter(IfcSchema::Type::IfcRoot, 0); // IfcRoot.GlobalId -// Note: skipping IfcRoot OwnerHistory, argument index 1 -IfcGeom::string_arg_filter name_filter(IfcSchema::Type::IfcRoot, 2); // IfcRoot.Name -IfcGeom::string_arg_filter desc_filter(IfcSchema::Type::IfcRoot, 3); // IfcRoot.Description -IfcGeom::string_arg_filter tag_filter(IfcSchema::Type::IfcProxy, 8, IfcSchema::Type::IfcElement, 7); // IfcProxy.Tag & IfcElement.Tag +IfcGeom::attribute_filter attribute_filter; struct geom_filter { @@ -151,7 +145,6 @@ struct exclusion_traverse_filter : public geom_filter { exclusion_traverse_filte size_t read_filters_from_file(const std::string&, inclusion_filter&, inclusion_traverse_filter&, exclusion_filter&, exclusion_traverse_filter&); void parse_filter(geom_filter &, const std::vector&); std::vector setup_filters(const std::vector&, const std::string&); -*/ bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, bool no_progress, bool mmap); @@ -179,13 +172,11 @@ int main(int argc, char** argv) double deflection_tolerance; - /* inclusion_filter include_filter; inclusion_traverse_filter include_traverse_filter; exclusion_filter exclude_filter; exclusion_traverse_filter exclude_traverse_filter; std::string filter_filename; - */ po::options_description geom_options("Geometry options"); geom_options.add_options() @@ -232,14 +223,13 @@ int main(int argc, char** argv) ("enable-layerset-slicing", "Specifies whether to enable the slicing of products according " "to their associated IfcMaterialLayerSet.") - /* ("include", po::value(&include_filter)->multitoken(), - "Specifies that the entities that match a specific filtering criteria are to be included in the geometrical output:\n" + "Specifies that the instances that match a specific filtering criteria are to be included in the geometrical output:\n" "1) 'entities': the following list of types should be included. SVG output defaults " "to IfcSpace to be included. The entity names are handled case-insensitively.\n" - "2) 'layers': the entities that are assigned to presentation layers of which names " + "2) 'layers': the instances that are assigned to presentation layers of which names " "match the given values should be included.\n" - "3) 'arg ': the following list of values for that specific argument should be included. " + "3) 'attribute ': products whose value for should be included\n. " "Currently supported arguments are GlobalId, Name, Description, and Tag.\n\n" "The values for 'layers' and 'arg' are handled case-sensitively (wildcards supported)." "--include and --exclude cannot be placed right before input file argument and " @@ -258,8 +248,7 @@ int main(int argc, char** argv) "Specifies a filter file that describes the used filtering criteria. Supported formats " "are '--include=arg GlobalId ...' and 'include arg GlobalId ...'. Spaces and tabs can be used as delimeters." "Multiple filters of same type with different values can be inserted on their own lines. " - "See --include, --include+, --exclude, and --exclude+ for more details."); - */ + "See --include, --include+, --exclude, and --exclude+ for more details.") ("no-normals", "Disables computation of normals. Saves time and file size and is useful " "in instances where you're going to recompute normals for the exported " @@ -490,7 +479,6 @@ int main(int argc, char** argv) return exit_code; } - /* if (!filter_filename.empty()) { size_t num_filters = read_filters_from_file(filter_filename, include_filter, include_traverse_filter, exclude_filter, exclude_traverse_filter); if (num_filters) { @@ -514,14 +502,10 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - if (!entity_filter.values.empty()) { entity_filter.update_description(); Logger::Notice(entity_filter.description); } + if (!entity_filter.entity_names.empty()) { entity_filter.update_description(); Logger::Notice(entity_filter.description); } if (!layer_filter.values.empty()) { layer_filter.update_description(); Logger::Notice(layer_filter.description); } - if (!guid_filter.values.empty()) { guid_filter.update_description(); Logger::Notice(guid_filter.description); } - if (!name_filter.values.empty()) { name_filter.update_description(); Logger::Notice(name_filter.description); } - if (!desc_filter.values.empty()) { desc_filter.update_description(); Logger::Notice(desc_filter.description); } - if (!tag_filter.values.empty()) { tag_filter.update_description(); Logger::Notice(tag_filter.description); } - */ - + if (!attribute_filter.attribute_name.empty()) { attribute_filter.update_description(); Logger::Notice(layer_filter.description); } + SerializerSettings settings; /// @todo Make APPLY_DEFAULT_MATERIALS configurable? Quickly tested setting this to false and using obj exporter caused the program to crash and burn. settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true); @@ -629,7 +613,7 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - IfcGeom::Iterator context_iterator(settings, ifc_file); + IfcGeom::Iterator context_iterator(settings, ifc_file, filter_funcs); if (!context_iterator.initialize()) { /// @todo It would be nice to know and print separate error prints for a case where we found no entities /// and for a case we found no entities that satisfy our filtering criteria. @@ -663,7 +647,6 @@ int main(int argc, char** argv) throw std::runtime_error("needs more work"); - /* if (!quiet) Logger::Status("Computing bounds..."); context_iterator.compute_bounds(); if (!quiet) Logger::Status("Done!"); @@ -672,7 +655,6 @@ int main(int argc, char** argv) offset[0] = -center.X(); offset[1] = -center.Y(); offset[2] = -center.Z(); - */ } else { if (sscanf(offset_str.c_str(), "%lf;%lf;%lf", &offset[0], &offset[1], &offset[2]) != 3) { std::cerr << "[Error] Invalid use of --model-offset\n"; @@ -826,7 +808,6 @@ bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, } -/* bool append_filter(const std::string& type, const std::vector& values, geom_filter& filter) { geom_filter temp; @@ -910,9 +891,6 @@ void parse_filter(geom_filter &filter, const std::vector& values) } else if (type == "arg") { filter.type = geom_filter::ENTITY_ARG; filter.arg = *(values.begin() + 1); - if (std::find(supported_args.begin(), supported_args.end(), filter.arg) == supported_args.end()) { - throw po::validation_error(po::validation_error::invalid_option_value); - } } else { throw po::validation_error(po::validation_error::invalid_option_value); } @@ -958,65 +936,38 @@ void validate(boost::any& v, const std::vector& values, exclusion_t std::vector setup_filters(const std::vector& filters, const std::string& output_extension) { std::vector filter_funcs; - BOOST_FOREACH(const geom_filter& f, filters) { + for(auto& f: filters) { if (f.type == geom_filter::ENTITY_TYPE) { entity_filter.include = f.include; entity_filter.traverse = f.traverse; - try { - entity_filter.populate(f.values); - } catch (const IfcParse::IfcException& e) { - std::cerr << "[Error] " << e.what() << std::endl; - return std::vector(); - } + entity_filter.entity_names = f.values; } else if (f.type == geom_filter::LAYER_NAME) { layer_filter.include = f.include; layer_filter.traverse = f.traverse; layer_filter.populate(f.values); } else if (f.type == geom_filter::ENTITY_ARG) { - if (f.arg == GUID_ARG) { - guid_filter.include = f.include; - guid_filter.traverse = f.traverse; - guid_filter.populate(f.values); - } else if (f.arg == NAME_ARG) { - name_filter.include = f.include; - name_filter.traverse = f.traverse; - name_filter.populate(f.values); - } else if (f.arg == DESC_ARG) { - desc_filter.include = f.include; - desc_filter.traverse = f.traverse; - desc_filter.populate(f.values); - } else if (f.arg == TAG_ARG) { - tag_filter.include = f.include; - tag_filter.traverse = f.traverse; - tag_filter.populate(f.values); - } + attribute_filter.include = f.include; + attribute_filter.traverse = f.traverse; + attribute_filter.attribute_name = f.arg; + attribute_filter.populate(f.values); } } // If no entity names are specified these are the defaults to skip from output - if (entity_filter.values.empty()) { - try { - std::set entities; - entities.insert("IfcSpace"); - if (output_extension == ".svg") { - entity_filter.include = true; - } else { - entities.insert("IfcOpeningElement"); - } - entity_filter.populate(entities); - } catch (const IfcParse::IfcException& e) { - std::cerr << "[Error] " << e.what() << std::endl; - return std::vector(); + if (entity_filter.entity_names.empty()) { + std::set entities; + entities.insert("IfcSpace"); + if (output_extension == ".svg") { + entity_filter.include = true; + } else { + entities.insert("IfcOpeningElement"); } + entity_filter.entity_names = entities; } if (!layer_filter.values.empty()) { filter_funcs.push_back(boost::ref(layer_filter)); } - if (!entity_filter.values.empty()) { filter_funcs.push_back(boost::ref(entity_filter)); } - if (!guid_filter.values.empty()) { filter_funcs.push_back(boost::ref(guid_filter)); } - if (!name_filter.values.empty()) { filter_funcs.push_back(boost::ref(name_filter)); } - if (!desc_filter.values.empty()) { filter_funcs.push_back(boost::ref(desc_filter)); } - if (!tag_filter.values.empty()) { filter_funcs.push_back(boost::ref(tag_filter)); } + if (!entity_filter.entity_names.empty()) { filter_funcs.push_back(boost::ref(entity_filter)); } + if (!attribute_filter.values.empty()) { filter_funcs.push_back(boost::ref(attribute_filter)); } return filter_funcs; } -*/ diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 1dbad17db6..c18478cbc5 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -221,8 +221,6 @@ public: std::pair initializeUnits(IfcSchema::IfcUnitAssignment*); - static IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*); - template IfcGeom::BRepElement* create_brep_for_representation_and_product( const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 70270eba8a..aa113ae5f6 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -1332,7 +1332,7 @@ IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and int parent_id = -1; try { - IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product); + IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product)->as(); if (parent_object) { parent_id = parent_object->data().id(); } @@ -1499,7 +1499,7 @@ IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_processed_represen { int parent_id = -1; try { - IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product); + IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product)->as(); if (parent_object) { parent_id = parent_object->data().id(); } @@ -1541,61 +1541,6 @@ IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_processed_represen ); } -IfcSchema::IfcObjectDefinition* IfcGeom::Kernel::get_decomposing_entity(IfcSchema::IfcProduct* product) { - IfcSchema::IfcObjectDefinition* parent = 0; - - // In case of an opening element, parent to the RelatingBuildingElement - if ( product->declaration().is(IfcSchema::IfcOpeningElement::Class() ) ) { - IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product; - IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements(); - if ( voids->size() ) { - IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin(); - parent = ifc_void->RelatingBuildingElement(); - } - } else if ( product->declaration().is(IfcSchema::IfcElement::Class() ) ) { - IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; - IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids(); - // 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; - IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement(); - if ( product == ifc_objectdef ) continue; - parent = ifc_objectdef; - } - } - // Else simply parent to the containing structure - if (!parent) { - IfcSchema::IfcRelContainedInSpatialStructure::list::ptr parents = element->ContainedInStructure(); - if ( parents->size() ) { - IfcSchema::IfcRelContainedInSpatialStructure* container = *parents->begin(); - parent = container->RelatingStructure(); - } - } - } - // Parent decompositions to the RelatingObject - if (!parent) { - IfcEntityList::ptr parents = product->data().getInverse((&IfcSchema::IfcRelAggregates::Class()), -1); - parents->push(product->data().getInverse((&IfcSchema::IfcRelNests::Class()), -1)); - for ( IfcEntityList::it it = parents->begin(); it != parents->end(); ++ it ) { - IfcSchema::IfcRelDecomposes* decompose = (IfcSchema::IfcRelDecomposes*)*it; - IfcSchema::IfcObjectDefinition* ifc_objectdef; -#ifdef USE_IFC4 - if (decompose->declaration().is(IfcSchema::IfcRelAggregates::Class())) { - ifc_objectdef = ((IfcSchema::IfcRelAggregates*)decompose)->RelatingObject(); - } else { - continue; - } -#else - ifc_objectdef = decompose->RelatingObject(); -#endif - if ( product == ifc_objectdef ) continue; - parent = ifc_objectdef; - } - } - return parent; -} - template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and_product( const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and_product( diff --git a/src/ifcgeom/IfcGeomIteratorImplementation.cpp b/src/ifcgeom/IfcGeomIteratorImplementation.cpp index d556abfa34..d693dbfa68 100644 --- a/src/ifcgeom/IfcGeomIteratorImplementation.cpp +++ b/src/ifcgeom/IfcGeomIteratorImplementation.cpp @@ -14,8 +14,8 @@ namespace IfcGeom { namespace { template struct MAKE_TYPE_NAME(factory_t) { - IfcGeom::IteratorImplementation* operator()(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file) const { - return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)(settings, file); + IfcGeom::IteratorImplementation* operator()(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters) const { + return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)(settings, file, filters); } }; } diff --git a/src/ifcgeom/IfcGeomIteratorImplementation.h b/src/ifcgeom/IfcGeomIteratorImplementation.h index 2da43c237e..9a05d5d5e5 100644 --- a/src/ifcgeom/IfcGeomIteratorImplementation.h +++ b/src/ifcgeom/IfcGeomIteratorImplementation.h @@ -80,8 +80,8 @@ #include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h" #include "../ifcgeom/IfcGeomIteratorSettings.h" #include "../ifcgeom/IfcRepresentationShapeItem.h" -#include "../ifcgeom/IfcGeomFilter.h" +#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h" #include "../ifcgeom_schema_agnostic/IteratorImplementation.h" // The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration @@ -156,15 +156,6 @@ namespace IfcGeom { typedef P Precision; typedef PP PlacementPrecision; - MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, IfcParse::IfcFile* file, std::vector& filters) - : settings(settings) - , ifc_file(file) - , owns_ifc_file(false) - , filters_(filters) - { - _initialize(); - } - bool initialize() { try { initUnits(); @@ -614,7 +605,7 @@ namespace IfcGeom { ifc_product = ifc_entity->as(); parent_id = -1; try { - IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product); + IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product)->as(); if (parent_object) { parent_id = parent_object->data().id(); } @@ -721,31 +712,11 @@ namespace IfcGeom { bool owns_ifc_file; public: - MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, IfcParse::IfcFile* file) + MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters) : settings(settings) , ifc_file(file) , owns_ifc_file(false) - { - _initialize(); - } - MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, const std::string& filename) - : settings(settings) - , ifc_file(new IfcParse::IfcFile(filename)) - , owns_ifc_file(true) - { - _initialize(); - } - MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, void* data, int length) - : settings(settings) - , ifc_file(new IfcParse::IfcFile(data, length)) - , owns_ifc_file(true) - { - _initialize(); - } - MAKE_TYPE_NAME(IteratorImplementation_)(const IteratorSettings& settings, std::istream& filestream, int length) - : settings(settings) - , ifc_file(new IfcParse::IfcFile(filestream, length)) - , owns_ifc_file(true) + , filters_(filters) { _initialize(); } diff --git a/src/ifcgeom/IfcGeomFilter.h b/src/ifcgeom_schema_agnostic/IfcGeomFilter.h similarity index 51% rename from src/ifcgeom/IfcGeomFilter.h rename to src/ifcgeom_schema_agnostic/IfcGeomFilter.h index 0efd7839ae..bc86cc295b 100644 --- a/src/ifcgeom/IfcGeomFilter.h +++ b/src/ifcgeom_schema_agnostic/IfcGeomFilter.h @@ -23,7 +23,8 @@ #ifndef IFCGEOMFILTER_H #define IFCGEOMFILTER_H -#include "IfcGeom.h" +#include "Kernel.h" +#include "../ifcparse/IfcFile.h" #include #include @@ -33,15 +34,13 @@ #include -namespace IfcGeom -{ +namespace IfcGeom { /// The filter function (free or member function) or function object (use boost::ref() to reference to it) /// should return true if the geometry for the product is wanted to be included in the output. /// http://www.boost.org/doc/libs/1_62_0/doc/html/function/tutorial.html - typedef boost::function filter_t; + typedef boost::function filter_t; - struct filter - { + 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). @@ -52,8 +51,7 @@ namespace IfcGeom /// Optional description for the filtering criteria of this filter. std::string description; - bool match(IfcSchema::IfcProduct* prod, const filter_t& pred) const - { + bool match(IfcUtil::IfcBaseEntity* prod, const filter_t& pred) const { bool is_match = pred(prod); if (!is_match && traverse) { is_match = traverse_match(prod, pred); @@ -61,46 +59,38 @@ namespace IfcGeom return is_match == include; } - static bool traverse_match(IfcSchema::IfcProduct* prod, const filter_t& pred) - { - throw std::runtime_error("todo"); - /* - IfcSchema::IfcProduct* parent, *current = prod; - while ((parent = dynamic_cast(IfcGeom::Kernel::get_decomposing_entity(current))) != 0) { + static bool traverse_match(IfcUtil::IfcBaseEntity* prod, const filter_t& pred) { + IfcUtil::IfcBaseEntity* parent, *current = prod; + while ((parent = IfcGeom::Kernel::get_decomposing_entity(current)) != nullptr) { if (pred(parent)) { return true; } current = parent; } - */ return false; } }; - struct wildcard_filter : public filter - { + struct wildcard_filter : public filter { wildcard_filter() : filter(false, false) {} wildcard_filter(bool include, bool traverse, const std::set& patterns) - : filter(include, traverse) - { + : filter(include, traverse) { populate(patterns); } std::set values; - void populate(const std::set& patterns) - { + void populate(const std::set& patterns) { values.clear(); - BOOST_FOREACH(const std::string &pattern, patterns) { + for(auto& pattern: patterns) { values.insert(wildcard_string_to_regex(pattern)); } } bool match(const std::string &str) const { return match_values(values, str); } - static bool match_values(const std::set& values, const std::string &str) - { - BOOST_FOREACH(const boost::regex& r, values) { + static bool match_values(const std::set& values, const std::string &str) { + for(auto& r: values) { if (boost::regex_match(str, r)) { return true; } @@ -108,11 +98,10 @@ namespace IfcGeom return false; } - static boost::regex wildcard_string_to_regex(std::string str) - { + static boost::regex wildcard_string_to_regex(std::string str) { // Escape all non-"*?" regex special chars static const std::string special_chars = "\\^.$|()[]+/"; - BOOST_FOREACH(char c, special_chars) { + for(auto c: special_chars) { std::string char_str(1, c); boost::replace_all(str, char_str, "\\" + char_str); } @@ -124,127 +113,78 @@ namespace IfcGeom }; /// @note supports only string arguments for now - struct string_arg_filter : public wildcard_filter - { - // Using this for now in order to overcome the fact that different classes have the argument at different indices. - typedef std::map arg_map_t; - arg_map_t args; + struct attribute_filter : public wildcard_filter { + std::string attribute_name; - /// @todo Take only attribute name when IfcBaseClass and IfcLateBoundEntity are merged. - string_arg_filter(arg_map_t args) : args(args) { assert_arguments(); } - string_arg_filter(const IfcParse::declaration* type, unsigned short index) { args[type] = index; assert_arguments(); } - string_arg_filter( - const IfcParse::declaration* type1, unsigned short index1, - const IfcParse::declaration* type2, unsigned short index2) - { - args[type1] = index1; - args[type2] = index2; - assert_arguments(); - } + attribute_filter() {} + attribute_filter(const std::string& attribute_name) + : attribute_name(attribute_name) {} - /// @todo this won't be needed when we have the generic argument name access - void assert_arguments() - { - // TODO -#if 0 - for (arg_map_t::const_iterator it = args.begin(); it != args.end(); ++it) { - IfcEntityInstanceData dummy(it->first); - IfcUtil::IfcBaseClass* base = IfcSchema::SchemaEntity(&dummy); - assert(it->second < base->getArgumentCount() && "Argument index out of bounds"); - assert(base->getArgumentType(it->second) == IfcUtil::Argument_STRING && "Argument type not string"); - delete base; + std::string value(IfcUtil::IfcBaseEntity* prod) const { + try { + return (std::string) *prod->get(attribute_name); + } catch (...) { + // Either + // (a) not an attribute name for this entity instance + // (b) not a string attribute + // (c) null for this entity instance + // @todo: validate the filters with a reference to the schema + // probably in IfcGeomIteratorImplementation + return ""; } -#endif } - std::string value(IfcSchema::IfcProduct* prod) const - { - for (arg_map_t::const_iterator it = args.begin(); it != args.end(); ++it) { - if (prod->declaration().is(*it->first) && it->second < prod->data().getArgumentCount() && - prod->data().getArgument(it->second)->type() == IfcUtil::Argument_STRING) { - Argument *arg = prod->data().getArgument(it->second); - if (!arg->isNull()) { - return *arg; - } - } - } - return ""; - } + bool match(IfcUtil::IfcBaseEntity* prod) const { + return wildcard_filter::match(value(prod)); + } - bool match(IfcSchema::IfcProduct* prod) const { return wildcard_filter::match(value(prod)); } - - bool operator()(IfcSchema::IfcProduct* prod) const - { + bool operator()(IfcUtil::IfcBaseEntity* prod) const { // @note bind1st() and mem_fun() deprecated in C++11, use bind() and mem_fn() when migrating to C++11. - return filter::match(prod, std::bind1st(std::mem_fun(&string_arg_filter::match), this)); + return filter::match(prod, std::bind1st(std::mem_fun(&attribute_filter::match), this)); } - void update_description() - { + void update_description() { std::stringstream ss; ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude"); std::vector patterns; - BOOST_FOREACH(const boost::regex& r, values) { + for (auto& r : values) { patterns.push_back("\"" + r.str() + "\""); } - // TODO -#if 0 - for (arg_map_t::const_iterator it = args.begin(); it != args.end(); ++it) { - IfcEntityInstanceData dummy(it->first); - IfcUtil::IfcBaseClass* base = IfcSchema::SchemaEntity(&dummy); - try { - ss << " " << IfcSchema::ToString::Class()(it->first) << "." << base->declaration().as_entity()->all_attributes()[it->second]->name(); - } catch (const std::exception& e) { - Logger::Error(e); - } - delete base; - } -#endif - + ss << " " << attribute_name; ss << " values " << boost::algorithm::join(patterns, " "); + description = ss.str(); } }; - struct layer_filter : public wildcard_filter - { - typedef std::map layer_map_t; + struct layer_filter : public wildcard_filter { + typedef std::map layer_map_t; layer_filter() {} layer_filter(bool include, bool traverse, const std::set& patterns) - : wildcard_filter(include, traverse, patterns) - { - } + : wildcard_filter(include, traverse, patterns) {} - bool match(IfcSchema::IfcProduct* prod) const - { - throw std::runtime_error("todo"); - /* + bool match(IfcUtil::IfcBaseEntity* prod) const { layer_map_t layers = IfcGeom::Kernel::get_layers(prod); return std::find_if(layers.begin(), layers.end(), wildcards_match(values)) != layers.end(); - */ } - bool operator()(IfcSchema::IfcProduct* prod) const - { + bool operator()(IfcUtil::IfcBaseEntity* prod) const { return filter::match(prod, std::bind1st(std::mem_fun(&layer_filter::match), this)); } - struct wildcards_match - { + struct wildcards_match { wildcards_match(const std::set& patterns) : patterns(patterns) {} - bool operator()(const layer_map_t::value_type& layer_map_value) const - { + bool operator()(const layer_map_t::value_type& layer_map_value) const { return wildcard_filter::match_values(patterns, layer_map_value.first); } std::set patterns; }; - void update_description() - { + void update_description() { std::stringstream ss; ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude") << " layers"; std::vector str_values; @@ -256,62 +196,35 @@ namespace IfcGeom } }; - struct entity_filter : public filter - { + struct entity_filter : public filter { + std::set entity_names; + entity_filter() {} - entity_filter(bool include, bool traverse/*, const std::set& types*/) + entity_filter(bool include, bool traverse, const std::set& entity_names) : filter(include, traverse) - { - //populate(types); - } + , entity_names(entity_names) {} - std::set values; - - void populate(const std::set&) - { - // TODO -#if 0 - values.clear(); - BOOST_FOREACH(const std::string& type, types) { - const IfcParse::declaration* ty; - try { - ty = IfcSchema::FromString::Class()(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) - } -#endif - } - - bool match(IfcSchema::IfcProduct* prod) const - { + bool match(IfcUtil::IfcBaseEntity* prod) const { // The set is iterated over to able to filter on subtypes. - BOOST_FOREACH(const IfcParse::declaration* type, values) { - if (prod->declaration().is(*type)) { + for (auto& name : entity_names) { + if (prod->declaration().is(name)) { return true; } } return false; } - bool operator()(IfcSchema::IfcProduct* prod) const - { + bool operator()(IfcUtil::IfcBaseEntity* prod) const { return filter::match(prod, std::bind1st(std::mem_fun(&entity_filter::match), this)); } - void update_description() - { - // TODO -#if 0 + void update_description() { std::stringstream ss; ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude") << " entities"; - BOOST_FOREACH(IfcSchema::Enum::Class() type, values) { - ss << " " << IfcSchema::ToString::Class()(type); + for (auto& name : entity_names) { + ss << " " << name; } description = ss.str(); -#endif } }; } diff --git a/src/ifcgeom_schema_agnostic/IfcGeomIterator.h b/src/ifcgeom_schema_agnostic/IfcGeomIterator.h index 56769d6acd..4658d37780 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomIterator.h +++ b/src/ifcgeom_schema_agnostic/IfcGeomIterator.h @@ -78,6 +78,8 @@ namespace IfcGeom { IfcParse::IfcFile* file_; IfcGeom::IteratorSettings settings_; + std::vector filters_; + IteratorImplementation* implementation_; public: @@ -85,7 +87,15 @@ namespace IfcGeom { : file_(file) , settings_(settings) { - implementation_ = iterator_implementations().construct(file_->schema()->name(), settings, file); + implementation_ = iterator_implementations().construct(file_->schema()->name(), settings, file, filters_); + } + + Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters) + : file_(file) + , settings_(settings) + , filters_(filters) + { + implementation_ = iterator_implementations().construct(file_->schema()->name(), settings, file, filters_); } bool initialize() { @@ -94,6 +104,11 @@ namespace IfcGeom { int progress() const { return implementation_->progress(); } + void compute_bounds() { implementation_->compute_bounds(); } + + const gp_XYZ& bounds_min() const { return implementation_->bounds_min(); } + const gp_XYZ& bounds_max() const { return implementation_->bounds_max(); } + const std::string& unit_name() const { return implementation_->getUnitName(); } double unit_magnitude() const { return implementation_->getUnitMagnitude(); } diff --git a/src/ifcgeom_schema_agnostic/IteratorImplementation.cpp b/src/ifcgeom_schema_agnostic/IteratorImplementation.cpp index daccfb4a44..10608d8cb7 100644 --- a/src/ifcgeom_schema_agnostic/IteratorImplementation.cpp +++ b/src/ifcgeom_schema_agnostic/IteratorImplementation.cpp @@ -31,14 +31,14 @@ void IteratorFactoryImplementation::bind(const std::string& schema_name, } template -IfcGeom::IteratorImplementation* IteratorFactoryImplementation::construct(const std::string& schema_name, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file) { +IfcGeom::IteratorImplementation* IteratorFactoryImplementation::construct(const std::string& schema_name, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters) { const std::string schema_name_lower = boost::to_lower_copy(schema_name); typename std::map::type>::const_iterator it; it = this->find(schema_name_lower); if (it == this->end()) { throw IfcParse::IfcException("No geometry iterator registered for " + schema_name); } - return it->second(settings, file); + return it->second(settings, file, filters); } diff --git a/src/ifcgeom_schema_agnostic/IteratorImplementation.h b/src/ifcgeom_schema_agnostic/IteratorImplementation.h index a6caf78a57..69ddbb618f 100644 --- a/src/ifcgeom_schema_agnostic/IteratorImplementation.h +++ b/src/ifcgeom_schema_agnostic/IteratorImplementation.h @@ -1,9 +1,12 @@ #ifndef ITERATOR_IMPLEMENTATION_H #define ITERATOR_IMPLEMENTATION_H +#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h" #include "../ifcparse/IfcFile.h" #include "../ifcgeom/IfcGeomIteratorSettings.h" +#include + #include #include @@ -20,9 +23,9 @@ namespace IfcGeom { class BRepElement; } -typedef boost::function2*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*> iterator_float_float_fn; -typedef boost::function2*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*> iterator_float_double_fn; -typedef boost::function2*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*> iterator_double_double_fn; +typedef boost::function3*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&> iterator_float_float_fn; +typedef boost::function3*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&> iterator_float_double_fn; +typedef boost::function3*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&> iterator_double_double_fn; template struct get_factory_type {}; @@ -47,7 +50,7 @@ class IteratorFactoryImplementation : public std::map::type fn); - IfcGeom::IteratorImplementation* construct(const std::string& schema_name, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*); + IfcGeom::IteratorImplementation* construct(const std::string& schema_name, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&); }; template @@ -59,6 +62,9 @@ namespace IfcGeom { class IteratorImplementation { public: virtual bool initialize() = 0; + virtual void compute_bounds() = 0; + virtual const gp_XYZ& bounds_min() const = 0; + virtual const gp_XYZ& bounds_max() const = 0; virtual int progress() const = 0; virtual const std::string& getUnitName() const = 0; virtual double getUnitMagnitude() const = 0; diff --git a/src/ifcgeom_schema_agnostic/Kernel.cpp b/src/ifcgeom_schema_agnostic/Kernel.cpp index 8266586b25..d4f154fae9 100644 --- a/src/ifcgeom_schema_agnostic/Kernel.cpp +++ b/src/ifcgeom_schema_agnostic/Kernel.cpp @@ -47,3 +47,119 @@ IfcGeom::Kernel* IfcGeom::impl::KernelFactoryImplementation::construct(const std } return it->second(file); } + +#define CREATE_GET_DECOMPOSING_ENTITY(IfcSchema) \ + \ +IfcSchema::IfcObjectDefinition* get_decomposing_entity_impl(IfcSchema::IfcProduct* product) { \ + IfcSchema::IfcObjectDefinition* parent = 0; \ + \ + /* In case of an opening element, parent to the RelatingBuildingElement */ \ + if (product->declaration().is(IfcSchema::IfcOpeningElement::Class())) { \ + IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product; \ + IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements(); \ + if (voids->size()) { \ + IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin(); \ + parent = ifc_void->RelatingBuildingElement(); \ + } \ + } else if (product->declaration().is(IfcSchema::IfcElement::Class())) { \ + IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; \ + IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids(); \ + /* 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; \ + IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement(); \ + if (product == ifc_objectdef) continue; \ + parent = ifc_objectdef; \ + } \ + } \ + /* Else simply parent to the containing structure */ \ + if (!parent) { \ + IfcSchema::IfcRelContainedInSpatialStructure::list::ptr parents = element->ContainedInStructure(); \ + if (parents->size()) { \ + IfcSchema::IfcRelContainedInSpatialStructure* container = *parents->begin(); \ + parent = container->RelatingStructure(); \ + } \ + } \ + } \ + \ + /* Parent decompositions to the RelatingObject */ \ + if (!parent) { \ + IfcEntityList::ptr parents = product->data().getInverse((&IfcSchema::IfcRelAggregates::Class()), -1); \ + parents->push(product->data().getInverse((&IfcSchema::IfcRelNests::Class()), -1)); \ + for (IfcEntityList::it it = parents->begin(); it != parents->end(); ++it) { \ + IfcSchema::IfcRelDecomposes* decompose = (IfcSchema::IfcRelDecomposes*)*it; \ + IfcUtil::IfcBaseEntity* ifc_objectdef; \ + \ + ifc_objectdef = get_RelatingObject(decompose); \ + \ + if (product == ifc_objectdef) continue; \ + parent = ifc_objectdef->as(); \ + } \ + } \ + return parent; \ +} + +namespace { + IfcUtil::IfcBaseEntity* get_RelatingObject(Ifc4::IfcRelDecomposes* decompose) { + Ifc4::IfcRelAggregates* aggr = decompose->as(); + if (aggr != nullptr) { + return aggr->RelatingObject(); + } + return nullptr; + } + + IfcUtil::IfcBaseEntity* get_RelatingObject(Ifc2x3::IfcRelDecomposes* decompose) { + return decompose->RelatingObject(); + } + + CREATE_GET_DECOMPOSING_ENTITY(Ifc2x3); + CREATE_GET_DECOMPOSING_ENTITY(Ifc4); +} + +IfcUtil::IfcBaseEntity* IfcGeom::Kernel::get_decomposing_entity(IfcUtil::IfcBaseEntity* inst) { + if (inst->as()) { + return get_decomposing_entity_impl(inst->as()); + } else if (inst->as()) { + return get_decomposing_entity_impl(inst->as()); + } else { + throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name()); + } +} + +namespace { + template + static std::map get_layers_impl(typename Schema::IfcProduct* prod) { + std::map layers; + if (prod->hasRepresentation()) { + IfcEntityList::ptr r = IfcParse::traverse(prod->Representation()); + typename Schema::IfcRepresentation::list::ptr representations = r->as(); + for (typename Schema::IfcRepresentation::list::it it = representations->begin(); it != representations->end(); ++it) { + typename Schema::IfcPresentationLayerAssignment::list::ptr a = (*it)->LayerAssignments(); + for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) { + layers[(*jt)->Name()] = *jt; + } + } + + typename Schema::IfcRepresentationItem::list::ptr items = r->as(); + for (typename Schema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) { + typename Schema::IfcPresentationLayerAssignment::list::ptr a = getLayerAssignments(*it)->template as(); + for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) { + layers[(*jt)->Name()] = *jt; + } + } + } + return layers; + } +} + +std::map IfcGeom::Kernel::get_layers(IfcUtil::IfcBaseEntity* inst) { + if (inst->as()) { + return get_layers_impl(inst->as()); + } else if (inst->as()) { + return get_layers_impl(inst->as()); + } else { + throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name()); + } +} + diff --git a/src/ifcgeom_schema_agnostic/Kernel.h b/src/ifcgeom_schema_agnostic/Kernel.h index ae6bc65bf7..a305aa898e 100644 --- a/src/ifcgeom_schema_agnostic/Kernel.h +++ b/src/ifcgeom_schema_agnostic/Kernel.h @@ -95,30 +95,8 @@ namespace IfcGeom { static int count(const TopoDS_Shape&, TopAbs_ShapeEnum); - template - static std::map get_layers(typename Schema::IfcProduct* prod) { - std::map layers; - if (prod->hasRepresentation()) { - IfcEntityList::ptr r = IfcParse::traverse(prod->Representation()); - typename Schema::IfcRepresentation::list::ptr representations = r->as(); - for (typename Schema::IfcRepresentation::list::it it = representations->begin(); it != representations->end(); ++it) { - typename Schema::IfcPresentationLayerAssignment::list::ptr a = (*it)->LayerAssignments(); - for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) { - layers[(*jt)->Name()] = *jt; - } - } - - typename Schema::IfcRepresentationItem::list::ptr items = r->as(); - for (typename Schema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) { - typename Schema::IfcPresentationLayerAssignment::list::ptr a = getLayerAssignments(*it)->template as(); - for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) { - layers[(*jt)->Name()] = *jt; - } - } - } - return layers; - } - + static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*); + static std::map get_layers(IfcUtil::IfcBaseEntity*); }; namespace impl { diff --git a/src/serializers/schema_dependent/XmlSerializer.cpp b/src/serializers/schema_dependent/XmlSerializer.cpp index dc7b8fab30..7b11ca888c 100644 --- a/src/serializers/schema_dependent/XmlSerializer.cpp +++ b/src/serializers/schema_dependent/XmlSerializer.cpp @@ -308,8 +308,8 @@ ptree& descend(IfcSchema::IfcObjectDefinition* product, ptree& tree) { } if (product->declaration().is(IfcSchema::IfcProduct::Class())) { - std::map layers = IfcGeom::Kernel::get_layers(product->as()); - for (std::map::const_iterator it = layers.begin(); it != layers.end(); ++it) { + std::map layers = IfcGeom::Kernel::get_layers(product); + for (std::map::const_iterator it = layers.begin(); it != layers.end(); ++it) { // IfcPresentationLayerAssignments don't have GUIDs (only optional Identifier) so use name as the ID. // Note that the IfcPresentationLayerAssignment passed here doesn't really matter as as_link is true // for the format_entity_instance() call.