From cd132473f561be1d52f122d1268db2f76fac6814 Mon Sep 17 00:00:00 2001 From: Stinkfist0 Date: Wed, 1 Mar 2017 23:51:57 +0200 Subject: [PATCH] IfcConvert: instead of global --traverse option provide --include+ and --exclude+ options that control traversal on per filter basis. --- src/ifcconvert/IfcConvert.cpp | 195 +++++++++++++++++----------------- 1 file changed, 97 insertions(+), 98 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index ac55009ea5..5aff473aad 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -128,18 +128,23 @@ IfcGeom::string_arg_filter tag_filter(IfcSchema::Type::IfcProxy, 8, IfcSchema::T struct geom_filter { - geom_filter() : type(UNUSED) {} + geom_filter(bool include, bool traverse) : type(UNUSED), include(include), traverse(traverse) {} + geom_filter() : type(UNUSED), include(false), traverse(false) {} enum filter_type { UNUSED, ENTITY_TYPE, LAYER_NAME, ENTITY_ARG }; filter_type type; + bool include; + bool traverse; std::string arg; 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 {}; -struct exclusion_filter : public geom_filter {}; +struct inclusion_filter : public geom_filter { inclusion_filter() : geom_filter(true, false) {} }; +struct inclusion_traverse_filter : public geom_filter { inclusion_traverse_filter() : geom_filter(true, true) {} }; +struct exclusion_filter : public geom_filter { exclusion_filter() : geom_filter(false, false) {} }; +struct exclusion_traverse_filter : public geom_filter { exclusion_traverse_filter() : geom_filter(false, true) {} }; -std::vector setup_filters(const geom_filter&, const geom_filter&, const std::string&, bool); +std::vector setup_filters(const std::vector&, const std::string&); int main(int argc, char** argv) { @@ -157,7 +162,9 @@ 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; po::options_description geom_options("Geometry options"); geom_options.add_options() @@ -215,9 +222,16 @@ int main(int argc, char** argv) "The values for 'layers' and 'arg' are handled case-sensitively (wildcards supported)." "--include and --exclude cannot be placed right before input file argument and " "only single of each argument supported for now. See also --exclude and --traverse.") + ("include+", po::value(&include_traverse_filter)->multitoken(), + "Same as --include but applies filtering also to the decomposition and/or containment (IsDecomposedBy, " + "HasOpenings, FillsVoid, ContainedInStructure) of the filtered entity, e.g. --include+=names \"Level 1\" " + "includes entity with name \"Level 1\" and all of its children. See --include for more information. ") ("exclude", po::value(&exclude_filter)->multitoken(), "Specifies that the entities that match a specific filtering criteria are to be excluded in the geometrical output." "See --include for syntax and more details. The default value is '--exclude=entities IfcOpeningElement IfcSpace'.") + ("exclude+", po::value(&exclude_traverse_filter)->multitoken(), + "Same as --exclude but applies filtering also to the decomposition and/or containment " + "of the filtered entity. See --include+ 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 " @@ -226,11 +240,7 @@ int main(int argc, char** argv) "Sets the deflection tolerance of the mesher, 1e-3 by default if not specified.") ("generate-uvs", "Generates UVs (texture coordinates) by using simple box projection. Requires normals. " - "Not guaranteed to work properly if used with --weld-vertices.") - ("traverse", - "Applies all --include or --exclude filters also to the decomposition and/or containment (IsDecomposedBy, " - "HasOpenings, FillsVoid, ContainedInStructure) of the filtered entity, e.g. --include=names \"Level 1\" " - "--traverse includes entity with name \"Level 1\" and all of its children."); + "Not guaranteed to work properly if used with --weld-vertices."); std::string bounds, offset_str; #ifdef HAVE_ICU @@ -329,8 +339,6 @@ 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 if (!unicode_mode.empty()) { @@ -394,8 +402,15 @@ int main(int argc, char** argv) Logger::SetOutput(&std::cout, &log_stream); Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR); - std::vector used_filters = setup_filters(include_filter, exclude_filter, output_extension, traverse); - if (used_filters.empty()) { + /// @todo Clean up this filter code further. + std::vector used_filters; + if (include_filter.type != geom_filter::UNUSED) { used_filters.push_back(include_filter); } + if (include_traverse_filter.type != geom_filter::UNUSED) { used_filters.push_back(include_traverse_filter); } + if (exclude_filter.type != geom_filter::UNUSED) { used_filters.push_back(exclude_filter); } + if (exclude_traverse_filter.type != geom_filter::UNUSED) { used_filters.push_back(exclude_traverse_filter); } + + std::vector filter_funcs = setup_filters(used_filters, output_extension); + if (filter_funcs.empty()) { std::cerr << "[Error] Failed to set up geometry filters\n"; return EXIT_FAILURE; } @@ -504,7 +519,7 @@ int main(int argc, char** argv) time_t start,end; time(&start); - IfcGeom::Iterator context_iterator(settings, input_filename, used_filters); + IfcGeom::Iterator context_iterator(settings, input_filename, filter_funcs); if (!context_iterator.initialize()) { /// @todo It would be nice to know and print separate error prints for a case where we failed to parse /// the file and for a case where we found no entities that satisfy our filtering criteria. @@ -646,6 +661,14 @@ void validate(boost::any& v, const std::vector& values, inclusion_f v = filter; } +void validate(boost::any& v, const std::vector& values, inclusion_traverse_filter*, int) +{ + po::validators::check_first_occurrence(v); + inclusion_traverse_filter filter; + parse_filter(filter, values); + v = filter; +} + void validate(boost::any& v, const std::vector& values, exclusion_filter*, int) { po::validators::check_first_occurrence(v); @@ -654,26 +677,58 @@ void validate(boost::any& v, const std::vector& values, exclusion_f v = filter; } -/// @todo Clean up this filter initialization code further. -/// @return The used filters, if none an error occurred. -std::vector setup_filters( - const geom_filter& include_filter, - const geom_filter& exclude_filter, - const std::string& output_extension, - bool traverse) +void validate(boost::any& v, const std::vector& values, exclusion_traverse_filter*, int) { - std::vector filters; - 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); + po::validators::check_first_occurrence(v); + exclusion_traverse_filter filter; + parse_filter(filter, values); + v = filter; +} + + +/// @todo Clean up this filter initialization code further. +/// @return References to the used filter functors, if none an error occurred. +std::vector setup_filters(const std::vector& filters, const std::string& output_extension) +{ + std::vector filter_funcs; + foreach(const geom_filter& 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(); + } + } 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); + } } - // If no entity names are specified these are the defaults to skip from output - if (entity_filter.values.empty()) { + } + + // 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") { @@ -682,74 +737,18 @@ std::vector setup_filters( entities.insert("IfcOpeningElement"); } entity_filter.populate(entities); + } catch (const IfcParse::IfcException& e) { + std::cerr << "[Error] " << e.what() << std::endl; + return std::vector(); } - } catch (const IfcParse::IfcException& e) { - std::cerr << "[Error] " << e.what() << std::endl; - return filters; - } - if (!entity_filter.values.empty()) { - filters.push_back(boost::ref(entity_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 (!layer_filter.values.empty()) { - filters.push_back(boost::ref(layer_filter)); - } + 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)); } - guid_filter.traverse = traverse; - if (include_filter.arg == GUID_ARG) { - guid_filter.include = true; - guid_filter.populate(include_filter.values); - } else if (exclude_filter.arg == GUID_ARG) { - guid_filter.include = false; - guid_filter.populate(exclude_filter.values); - } - if (!guid_filter.values.empty()) { - filters.push_back(boost::ref(guid_filter)); - } - - name_filter.traverse = traverse; - if (include_filter.arg == NAME_ARG) { - name_filter.include = true; - name_filter.populate(include_filter.values); - } else if (exclude_filter.arg == NAME_ARG) { - name_filter.include = false; - name_filter.populate(exclude_filter.values); - } - if (!name_filter.values.empty()) { - filters.push_back(boost::ref(name_filter)); - } - - desc_filter.traverse = traverse; - if (include_filter.arg == DESC_ARG) { - desc_filter.include = true; - desc_filter.populate(include_filter.values); - } else if (exclude_filter.arg == DESC_ARG) { - desc_filter.include = false; - desc_filter.populate(exclude_filter.values); - } - if (!desc_filter.values.empty()) { - filters.push_back(boost::ref(desc_filter)); - } - - tag_filter.traverse = traverse; - if (include_filter.arg == TAG_ARG) { - tag_filter.include = true; - tag_filter.populate(include_filter.values); - } else if (exclude_filter.arg == TAG_ARG) { - tag_filter.include = false; - tag_filter.populate(exclude_filter.values); - } - if (!tag_filter.values.empty()) { - filters.push_back(boost::ref(tag_filter)); - } - - return filters; + return filter_funcs; }