mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 23:50:59 +00:00
Filtering by entity GUID and layer name w.i.p.
This commit is contained in:
committed by
Thomas Krijnen
parent
f1709dc71a
commit
3abee03b9b
@@ -117,11 +117,10 @@ static std::stringstream log_stream;
|
|||||||
void write_log();
|
void write_log();
|
||||||
|
|
||||||
/// @todo Make this a feature of IfcGeom::Iterator instead.
|
/// @todo Make this a feature of IfcGeom::Iterator instead.
|
||||||
/// Also add GUID filtering.
|
|
||||||
struct geom_filter
|
struct geom_filter
|
||||||
{
|
{
|
||||||
bool include;
|
bool include;
|
||||||
enum filter_type { ENTITIES, NAMES };
|
enum filter_type { ENTITY_TYPE, ENTITY_NAME, ENTITY_GUID, LAYER_NAME };
|
||||||
filter_type type;
|
filter_type type;
|
||||||
std::set<std::string> values;
|
std::set<std::string> values;
|
||||||
};
|
};
|
||||||
@@ -201,7 +200,7 @@ int main(int argc, char** argv)
|
|||||||
"geometrical output. The name patterns are handled case-sensitively. Cannot be placed right before input file argument. "
|
"geometrical output. The name patterns are handled case-sensitively. Cannot be placed right before input file argument. "
|
||||||
"Only single option supported for now.")
|
"Only single option supported for now.")
|
||||||
("exclude", po::value<exclusion_filter>(&exclude_filter)->multitoken(),
|
("exclude", po::value<exclusion_filter>(&exclude_filter)->multitoken(),
|
||||||
"Specifies that the 'entities' or 'names' provided are to be excluded. Defaults to IfcOpeningElement and IfcSpace "
|
"Specifies that the 'entities', 'names', or 'guids' provided are to be excluded. Defaults to IfcOpeningElement and IfcSpace "
|
||||||
"to be excluded. See --include for syntax and more details.")
|
"to be excluded. See --include for syntax and more details.")
|
||||||
("no-normals",
|
("no-normals",
|
||||||
"Disables computation of normals. Saves time and file size and is useful "
|
"Disables computation of normals. Saves time and file size and is useful "
|
||||||
@@ -245,7 +244,7 @@ int main(int argc, char** argv)
|
|||||||
("center-model",
|
("center-model",
|
||||||
"Centers the elements upon serialization by applying the center point of "
|
"Centers the elements upon serialization by applying the center point of "
|
||||||
"all placements as an offset. Applicable for OBJ and DAE output.")
|
"all placements as an offset. Applicable for OBJ and DAE output.")
|
||||||
("model-offset", PO::value<std::string>(&offset_str),
|
("model-offset", po::value<std::string>(&offset_str),
|
||||||
"Applies an arbitrary offset of form 'x;y;z' to all placements. Applicable for OBJ and DAE output.")
|
"Applies an arbitrary offset of form 'x;y;z' to all placements. Applicable for OBJ and DAE output.")
|
||||||
("precision", po::value<short>(&precision)->default_value(SerializerSettings::DEFAULT_PRECISION),
|
("precision", po::value<short>(&precision)->default_value(SerializerSettings::DEFAULT_PRECISION),
|
||||||
"Sets the precision to be used to format floating-point values, 15 by default. "
|
"Sets the precision to be used to format floating-point values, 15 by default. "
|
||||||
@@ -272,13 +271,14 @@ int main(int argc, char** argv)
|
|||||||
std::cerr << "[Error] Invalid usage of '" << e.get_option_name() << "': " << e.what() << "\n\n";
|
std::cerr << "[Error] Invalid usage of '" << e.get_option_name() << "': " << e.what() << "\n\n";
|
||||||
print_usage();
|
print_usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
return EXIT_FAILURE;
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
std::cerr << "[Error] " << e.what() << "\n\n";
|
std::cerr << "[Error] " << e.what() << "\n\n";
|
||||||
print_usage();
|
print_usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
} catch (...) { // other errors such as invalid command line syntax
|
} catch (...) { // other errors such as invalid command line syntax
|
||||||
print_usage();
|
print_usage();
|
||||||
return 1;
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
po::notify(vmap);
|
po::notify(vmap);
|
||||||
|
|
||||||
@@ -295,6 +295,18 @@ int main(int argc, char** argv)
|
|||||||
print_usage();
|
print_usage();
|
||||||
return 1;
|
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 verbose = vmap.count("verbose") != 0;
|
||||||
const bool weld_vertices = vmap.count("weld-vertices") != 0;
|
const bool weld_vertices = vmap.count("weld-vertices") != 0;
|
||||||
const bool use_world_coords = vmap.count("use-world-coords") != 0;
|
const bool use_world_coords = vmap.count("use-world-coords") != 0;
|
||||||
@@ -304,6 +316,10 @@ int main(int argc, char** argv)
|
|||||||
const bool merge_boolean_operands = vmap.count("merge-boolean-operands") != 0;
|
const bool merge_boolean_operands = vmap.count("merge-boolean-operands") != 0;
|
||||||
#endif
|
#endif
|
||||||
const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0;
|
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_plan = vmap.count("plan") != 0;
|
||||||
const bool include_model = vmap.count("model") != 0 || (!include_plan);
|
const bool include_model = vmap.count("model") != 0 || (!include_plan);
|
||||||
const bool enable_layerset_slicing = vmap.count("enable-layerset-slicing") != 0;
|
const bool enable_layerset_slicing = vmap.count("enable-layerset-slicing") != 0;
|
||||||
@@ -484,6 +500,18 @@ int main(int argc, char** argv)
|
|||||||
context_iterator.exclude_entity_names(names);
|
context_iterator.exclude_entity_names(names);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (include_guids) {
|
||||||
|
context_iterator.include_entity_guids(guids);
|
||||||
|
} else {
|
||||||
|
context_iterator.exclude_entity_guids(guids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (include_layers) {
|
||||||
|
context_iterator.include_layer_names(layers);
|
||||||
|
} else {
|
||||||
|
context_iterator.exclude_layer_names(layers);
|
||||||
|
}
|
||||||
|
|
||||||
if (!serializer->ready()) {
|
if (!serializer->ready()) {
|
||||||
write_log();
|
write_log();
|
||||||
return 1;
|
return 1;
|
||||||
@@ -614,9 +642,13 @@ void validate(boost::any& v, const std::vector<std::string>& values, inclusion_f
|
|||||||
}
|
}
|
||||||
std::string type = *values.begin();
|
std::string type = *values.begin();
|
||||||
if (type == "entities") {
|
if (type == "entities") {
|
||||||
filter.type = geom_filter::ENTITIES;
|
filter.type = geom_filter::ENTITY_TYPE;
|
||||||
} else if (type == "names") {
|
} else if (type == "names") {
|
||||||
filter.type = geom_filter::NAMES;
|
filter.type = geom_filter::ENTITY_NAME;
|
||||||
|
} else if (type == "guids") {
|
||||||
|
filter.type = geom_filter::ENTITY_GUID;
|
||||||
|
//} else if (type == "layers") {
|
||||||
|
// filter.type = geom_filter::LAYER_NAME;
|
||||||
} else {
|
} else {
|
||||||
throw po::validation_error(po::validation_error::invalid_option_value);
|
throw po::validation_error(po::validation_error::invalid_option_value);
|
||||||
}
|
}
|
||||||
@@ -634,9 +666,13 @@ void validate(boost::any& v, const std::vector<std::string>& values, exclusion_f
|
|||||||
}
|
}
|
||||||
std::string type = *values.begin();
|
std::string type = *values.begin();
|
||||||
if (type == "entities") {
|
if (type == "entities") {
|
||||||
filter.type = geom_filter::ENTITIES;
|
filter.type = geom_filter::ENTITY_TYPE;
|
||||||
} else if (type == "names") {
|
} else if (type == "names") {
|
||||||
filter.type = geom_filter::NAMES;
|
filter.type = geom_filter::ENTITY_NAME;
|
||||||
|
} else if (type == "guids") {
|
||||||
|
filter.type = geom_filter::ENTITY_GUID;
|
||||||
|
//} else if (type == "layers") {
|
||||||
|
// filter.type = geom_filter::LAYER_NAME;
|
||||||
} else {
|
} else {
|
||||||
throw po::validation_error(po::validation_error::invalid_option_value);
|
throw po::validation_error(po::validation_error::invalid_option_value);
|
||||||
}
|
}
|
||||||
|
|||||||
+130
-58
@@ -135,27 +135,61 @@ namespace IfcGeom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<boost::regex> names_to_include_or_exclude; // regex containing a name or a wildcard expression
|
struct wildcard_filter
|
||||||
std::set<IfcSchema::Type::Enum> entities_to_include_or_exclude;
|
{
|
||||||
bool include_entities_in_processing;
|
bool include;
|
||||||
bool include_names_in_processing_;
|
std::set<boost::regex> values;
|
||||||
|
|
||||||
void populate_set(const std::set<std::string>& include_or_ignore) {
|
void populate(const std::set<std::string>& patterns)
|
||||||
entities_to_include_or_exclude.clear();
|
{
|
||||||
for (std::set<std::string>::const_iterator it = include_or_ignore.begin(); it != include_or_ignore.end(); ++it) {
|
values.clear();
|
||||||
const std::string uppercase_type = boost::to_upper_copy(*it);
|
foreach(const std::string &pattern, patterns) {
|
||||||
IfcSchema::Type::Enum ty;
|
values.insert(wildcard_string_to_regex(pattern));
|
||||||
try {
|
}
|
||||||
ty = IfcSchema::Type::FromString(uppercase_type);
|
}
|
||||||
} catch (const IfcParse::IfcException&) {
|
|
||||||
std::stringstream ss;
|
static boost::regex wildcard_string_to_regex(std::string str)
|
||||||
ss << "'" << *it << "' does not name a valid IFC entity";
|
{
|
||||||
throw IfcParse::IfcException(ss.str());
|
// Escape all non-"*?" regex special chars
|
||||||
}
|
std::string special_chars = "\\^.$|()[]+/";
|
||||||
entities_to_include_or_exclude.insert(ty);
|
foreach(char c, special_chars) {
|
||||||
// TODO: Add child classes so that containment in set can be in O(log n)
|
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
|
||||||
|
{
|
||||||
|
bool include;
|
||||||
|
std::set<IfcSchema::Type::Enum> values;
|
||||||
|
|
||||||
|
void populate(const std::set<std::string>& 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&) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "'" << type << "' does not name a valid IFC entity";
|
||||||
|
throw IfcParse::IfcException(ss.str());
|
||||||
|
}
|
||||||
|
values.insert(ty);
|
||||||
|
// TODO: Add child classes so that containment in set can be in O(log n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
entity_filter entity_filter_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool initialize() {
|
bool initialize() {
|
||||||
@@ -319,47 +353,59 @@ namespace IfcGeom {
|
|||||||
IfcParse::IfcFile* getFile() const { return ifc_file; }
|
IfcParse::IfcFile* getFile() const { return ifc_file; }
|
||||||
|
|
||||||
/// @note Entity names are handled case-insensitively.
|
/// @note Entity names are handled case-insensitively.
|
||||||
void includeEntities(const std::set<std::string>& entities) {
|
void includeEntities(const std::set<std::string>& entities)
|
||||||
populate_set(entities);
|
{
|
||||||
include_entities_in_processing = true;
|
entity_filter_.populate(entities);
|
||||||
}
|
entity_filter_.include = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// @note Entity names are handled case-insensitively.
|
/// @copydoc includeEntities()
|
||||||
void excludeEntities(const std::set<std::string>& entities) {
|
void excludeEntities(const std::set<std::string>& entities)
|
||||||
populate_set(entities);
|
{
|
||||||
include_entities_in_processing = false;
|
entity_filter_.populate(entities);
|
||||||
}
|
entity_filter_.include = false;
|
||||||
|
}
|
||||||
|
|
||||||
/// @note Arbitrary names or wildcard expressions are handled case-sensitively.
|
/// @note Arbitrary names or wildcard expressions are handled case-sensitively.
|
||||||
void include_entity_names(const std::set<std::string>& names)
|
void include_entity_names(const std::set<std::string>& names)
|
||||||
{
|
{
|
||||||
names_to_include_or_exclude.clear();
|
name_filter_.populate(names);
|
||||||
foreach(const std::string &name, names)
|
name_filter_.include = true;
|
||||||
names_to_include_or_exclude.insert(wildcard_string_to_regex(name));
|
}
|
||||||
include_names_in_processing_ = true;
|
|
||||||
|
/// @copydoc include_entity_names()
|
||||||
|
void exclude_entity_names(const std::set<std::string>& names)
|
||||||
|
{
|
||||||
|
name_filter_.populate(names);
|
||||||
|
name_filter_.include = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @note GUIDs (wildcard expressions allowed) are handled case-sensitively.
|
||||||
|
void include_entity_guids(const std::set<std::string>& guids)
|
||||||
|
{
|
||||||
|
guid_filter_.populate(guids);
|
||||||
|
guid_filter_.include = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @copydoc include_entity_guids()
|
||||||
|
void exclude_entity_guids(const std::set<std::string>& guids)
|
||||||
|
{
|
||||||
|
guid_filter_.populate(guids);
|
||||||
|
guid_filter_.include = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @note Arbitrary names or wildcard expressions are handled case-sensitively.
|
/// @note Arbitrary names or wildcard expressions are handled case-sensitively.
|
||||||
void exclude_entity_names(const std::set<std::string>& names)
|
void include_layer_names(const std::set<std::string>& names)
|
||||||
{
|
{
|
||||||
names_to_include_or_exclude.clear();
|
layer_filter_.populate(names);
|
||||||
foreach(const std::string &name, names)
|
layer_filter_.include = true;
|
||||||
names_to_include_or_exclude.insert(wildcard_string_to_regex(name));
|
|
||||||
include_names_in_processing_ = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static boost::regex wildcard_string_to_regex(std::string str)
|
/// @copydoc include_layer_names()
|
||||||
|
void exclude_layer_names(const std::set<std::string>& names)
|
||||||
{
|
{
|
||||||
// Escape all non-"*?" regex special chars
|
layer_filter_.populate(names);
|
||||||
std::string special_chars = "\\^.$|()[]+/";
|
layer_filter_.include = false;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const gp_XYZ& bounds_min() const { return bounds_min_; }
|
const gp_XYZ& bounds_min() const { return bounds_min_; }
|
||||||
@@ -539,15 +585,15 @@ namespace IfcGeom {
|
|||||||
IfcSchema::IfcProduct* prod = *jt;
|
IfcSchema::IfcProduct* prod = *jt;
|
||||||
bool type_found = false;
|
bool type_found = false;
|
||||||
// The set is iterated over to able to filter on subtypes.
|
// The set is iterated over to able to filter on subtypes.
|
||||||
foreach(IfcSchema::Type::Enum type, entities_to_include_or_exclude) {
|
foreach(IfcSchema::Type::Enum type, entity_filter_.values) {
|
||||||
if (prod->is(type)) {
|
if (prod->is(type)) {
|
||||||
type_found = true;
|
type_found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_found != include_entities_in_processing && traverse) {
|
if (type_found != entity_filter_.include && traverse) {
|
||||||
foreach(IfcSchema::Type::Enum type, entities_to_include_or_exclude) {
|
foreach(IfcSchema::Type::Enum type, entity_filter_.values) {
|
||||||
IfcSchema::IfcProduct* parent, * current = prod;
|
IfcSchema::IfcProduct* parent, * current = prod;
|
||||||
while ((parent = static_cast<IfcSchema::IfcProduct*>(kernel.get_decomposing_entity(current))) != 0) {
|
while ((parent = static_cast<IfcSchema::IfcProduct*>(kernel.get_decomposing_entity(current))) != 0) {
|
||||||
if (parent->is(type)) {
|
if (parent->is(type)) {
|
||||||
@@ -563,15 +609,15 @@ namespace IfcGeom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool name_found = false;
|
bool name_found = false;
|
||||||
foreach(const boost::regex& r, names_to_include_or_exclude) {
|
foreach(const boost::regex& r, name_filter_.values) {
|
||||||
if (prod->hasName() && boost::regex_match(prod->Name(), r)) {
|
if (prod->hasName() && boost::regex_match(prod->Name(), r)) {
|
||||||
name_found = true;
|
name_found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name_found != include_names_in_processing_ && traverse) {
|
if (name_found != name_filter_.include && traverse) {
|
||||||
foreach(const boost::regex& r, names_to_include_or_exclude) {
|
foreach(const boost::regex& r, name_filter_.values) {
|
||||||
IfcSchema::IfcProduct* parent, *current = prod;
|
IfcSchema::IfcProduct* parent, *current = prod;
|
||||||
while ((parent = static_cast<IfcSchema::IfcProduct*>(kernel.get_decomposing_entity(current))) != 0) {
|
while ((parent = static_cast<IfcSchema::IfcProduct*>(kernel.get_decomposing_entity(current))) != 0) {
|
||||||
if (parent->hasName() && boost::regex_match(parent->Name(), r)) {
|
if (parent->hasName() && boost::regex_match(parent->Name(), r)) {
|
||||||
@@ -586,7 +632,31 @@ namespace IfcGeom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_found == include_entities_in_processing && name_found == include_names_in_processing_) {
|
bool guid_found = false;
|
||||||
|
foreach(const boost::regex& r, guid_filter_.values) {
|
||||||
|
if (boost::regex_match(prod->GlobalId(), r)) {
|
||||||
|
guid_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guid_found != guid_filter_.include && traverse) {
|
||||||
|
foreach(const boost::regex& r, guid_filter_.values) {
|
||||||
|
IfcSchema::IfcProduct* parent, *current = prod;
|
||||||
|
while ((parent = static_cast<IfcSchema::IfcProduct*>(kernel.get_decomposing_entity(current))) != 0) {
|
||||||
|
if (boost::regex_match(parent->GlobalId(), r)) {
|
||||||
|
guid_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = parent;
|
||||||
|
}
|
||||||
|
if (guid_found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type_found == entity_filter_.include && name_found == name_filter_.include && guid_found == guid_filter_.include) {
|
||||||
ifcproducts->push(prod);
|
ifcproducts->push(prod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -748,8 +818,10 @@ namespace IfcGeom {
|
|||||||
|
|
||||||
// Upon initialisation, the (empty) set of entity names,
|
// Upon initialisation, the (empty) set of entity names,
|
||||||
// should be excluded, or no products would be processed.
|
// should be excluded, or no products would be processed.
|
||||||
include_entities_in_processing = false;
|
entity_filter_.include = false;
|
||||||
include_names_in_processing_ = false;
|
name_filter_.include = false;
|
||||||
|
guid_filter_.include = false;
|
||||||
|
layer_filter_.include = false;
|
||||||
|
|
||||||
unit_name = "METER";
|
unit_name = "METER";
|
||||||
unit_magnitude = 1.f;
|
unit_magnitude = 1.f;
|
||||||
|
|||||||
Reference in New Issue
Block a user