.. _program_listing_file_src_ifcgeom_schema_agnostic_IfcGeomFilter.h: Program Listing for File IfcGeomFilter.h ======================================== |exhale_lsh| :ref:`Return to documentation for file ` (``src/ifcgeom_schema_agnostic/IfcGeomFilter.h``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /******************************************************************************** * * * 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 . * * * ********************************************************************************/ #ifndef IFCGEOMFILTER_H #define IFCGEOMFILTER_H #include "Kernel.h" #include "../ifcparse/IfcFile.h" #include #include #include #include #include #include namespace IfcGeom { typedef boost::function filter_t; struct filter { filter() : include(false), traverse(false), traverse_openings(false) {} filter(bool incl, bool trav, bool trav_openings = false) : include(incl), traverse(trav), traverse_openings(trav_openings) {} bool include; bool traverse; bool traverse_openings; std::string description; 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); } return is_match == include; } bool traverse_match(IfcUtil::IfcBaseEntity* prod, const filter_t& pred) const { IfcUtil::IfcBaseEntity* parent, *current = prod; while ((parent = IfcGeom::Kernel::get_decomposing_entity(current, traverse_openings)) != nullptr) { if (pred(parent)) { return true; } current = parent; } return false; } }; 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(); 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) { for(auto& 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 static const std::string special_chars = "\\^.$|()[]+/"; for(auto 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); } }; struct attribute_filter : public wildcard_filter { std::string attribute_name; attribute_filter() {} attribute_filter(const std::string& attribute_name) : attribute_name(attribute_name) {} 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 ""; } } bool match(IfcUtil::IfcBaseEntity* prod) const { return wildcard_filter::match(value(prod)); } bool operator()(IfcUtil::IfcBaseEntity* prod) const { return filter::match(prod, std::bind(&attribute_filter::match, this, std::placeholders::_1)); } void update_description() { std::stringstream ss; ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude"); std::vector patterns; for (auto& r : values) { patterns.push_back("\"" + r.str() + "\""); } ss << " " << attribute_name; ss << " values " << boost::algorithm::join(patterns, " "); description = ss.str(); } }; 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) {} 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()(IfcUtil::IfcBaseEntity* prod) const { return filter::match(prod, std::bind(&layer_filter::match, this, std::placeholders::_1)); } struct wildcards_match { wildcards_match(const std::set& patterns) : patterns(patterns) {} 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() { std::stringstream ss; ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude") << " layers"; std::vector str_values; BOOST_FOREACH(const boost::regex& r, values) { str_values.push_back(" \"" + r.str() + "\""); } ss << boost::algorithm::join(str_values, " "); description = ss.str(); } }; struct entity_filter : public filter { std::set entity_names; entity_filter() {} entity_filter(bool include, bool traverse, const std::set& entity_names) : filter(include, traverse) , entity_names(entity_names) {} bool match(IfcUtil::IfcBaseEntity* prod) const { // The set is iterated over to able to filter on subtypes. for (auto& name : entity_names) { if (prod->declaration().is(name)) { return true; } } return false; } bool operator()(IfcUtil::IfcBaseEntity* prod) const { return filter::match(prod, std::bind(&entity_filter::match, this, std::placeholders::_1)); } void update_description() { std::stringstream ss; ss << (traverse ? "traverse " : "") << (include ? "include" : "exclude") << " entities"; for (auto& name : entity_names) { ss << " " << name; } description = ss.str(); } }; } #endif