From 0adcb9ae20d7a8399a1fe55421775641ca54f315 Mon Sep 17 00:00:00 2001 From: Stinkfist0 Date: Fri, 19 May 2017 18:10:20 +0300 Subject: [PATCH] IfcConvert --filter-file: Specifies a filter file that describes the used filtering criteria. --- src/ifcconvert/IfcConvert.cpp | 95 ++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 05bb2602b5..fe86ce54b3 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -144,6 +144,8 @@ struct inclusion_traverse_filter : public geom_filter { inclusion_traverse_filte 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) {} }; +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&); int main(int argc, char** argv) @@ -165,6 +167,7 @@ int main(int argc, char** argv) 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() @@ -240,7 +243,12 @@ 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."); + "Not guaranteed to work properly if used with --weld-vertices.") + ("filter-file", po::value(&filter_filename), + "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."); std::string bounds, offset_str; #ifdef HAVE_ICU @@ -411,6 +419,9 @@ int main(int argc, char** argv) Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR); IfcParse::IfcFile ifc_file; + /// @todo Do not read/initialize the file just yet. We got many potential error and + /// exit points below and reading/initializing at this point can stall up to tens of + /// seconds if the file is very large. if (!ifc_file.Init(input_filename)) { Logger::Error("Unable to parse input file '" + input_filename + "'"); return EXIT_FAILURE; @@ -431,6 +442,16 @@ 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) { + Logger::Notice(boost::lexical_cast(num_filters) + " filters read from '" + filter_filename + "'."); + } else { + std::cerr << "[Error] No filters read from '" + filter_filename + "'.\n"; + return EXIT_FAILURE; + } + } + /// @todo Clean up this filter code further. std::vector used_filters; if (include_filter.type != geom_filter::UNUSED) { used_filters.push_back(include_filter); } @@ -655,6 +676,76 @@ void write_log() { } } +bool append_filter(const std::string& type, const std::vector& values, geom_filter& filter) +{ + geom_filter temp; + parse_filter(temp, values); + // Merge values only if type and arg match. + if ((filter.type != geom_filter::UNUSED && filter.type != temp.type) || (!filter.arg.empty() && filter.arg != temp.arg)) { + std::cerr << "[Error] Multiple '" << type << "' filters specified with different criteria\n"; + return false; + } + filter.type = temp.type; + filter.values.insert(temp.values.begin(), temp.values.end()); + filter.arg = temp.arg; + return true; +} + +size_t read_filters_from_file( + const std::string& filename, + inclusion_filter& include_filter, + inclusion_traverse_filter& include_traverse_filter, + exclusion_filter& exclude_filter, + exclusion_traverse_filter& exclude_traverse_filter) +{ + std::ifstream filter_file(filename.c_str()); + if (!filter_file.is_open()) { + std::cerr << "[Error] Unable to open filter file '" + filename + "'\n"; + return 0; + } + + size_t line_number = 1, num_filters = 0; + for (std::string line; std::getline(filter_file, line); ++line_number) { + boost::trim(line); + if (line.empty()) { + continue; + } + + std::vector values; + boost::split(values, line, boost::is_any_of("\t "), boost::token_compress_on); + if (values.empty()) { + continue; + } + + std::string type = values.front(); + values.erase(values.begin()); + // Support both "--include=arg GlobalId 1VQ5n5$RrEbPk8le4ZCI81" and "include arg GlobalId 1VQ5n5$RrEbPk8le4ZCI81" + // and tolerate extraneous whitespace. + boost::trim_left_if(type, boost::is_any_of("-")); + size_t equal_pos = type.find('='); + if (equal_pos != std::string::npos) { + std::string value = type.substr(equal_pos + 1); + type = type.substr(0, equal_pos); + values.insert(values.begin(), value); + } + + try { + if (type == "include") { if (append_filter("include", values, include_filter)) { ++num_filters; } } + else if (type == "include+") { if (append_filter("include+", values, include_traverse_filter)) { ++num_filters; } } + else if (type == "exclude") { if (append_filter("exclude", values, exclude_filter)) { ++num_filters; } } + else if (type == "exclude+") { if (append_filter("exclude+", values, exclude_traverse_filter)) { ++num_filters; } } + else { + std::cerr << "[Error] Invalid filtering type at line " + boost::lexical_cast(line_number) + "\n"; + return 0; + } + } catch(...) { + std::cerr << "[Error] Unable to parse filter at line " + boost::lexical_cast(line_number) + ".\n"; + return 0; + } + } + return num_filters; +} + void parse_filter(geom_filter &filter, const std::vector& values) { if (values.size() == 0) { @@ -679,7 +770,7 @@ void parse_filter(geom_filter &filter, const std::vector& values) void validate(boost::any& v, const std::vector& values, inclusion_filter*, int) { - /// @todo For now only single --include or --exclude supported. Support having multiple. + /// @todo For now only single --include, --include+, --exclude, or --exclude+ supported. Support having multiple. po::validators::check_first_occurrence(v); inclusion_filter filter; parse_filter(filter, values);