mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 14:31:39 +00:00
IfcConvert: instead of global --traverse option provide --include+ and --exclude+ options that control traversal on per filter basis.
This commit is contained in:
committed by
Thomas Krijnen
parent
06c1ea9d2c
commit
cd132473f5
@@ -128,18 +128,23 @@ IfcGeom::string_arg_filter tag_filter(IfcSchema::Type::IfcProxy, 8, IfcSchema::T
|
|||||||
|
|
||||||
struct geom_filter
|
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 };
|
enum filter_type { UNUSED, ENTITY_TYPE, LAYER_NAME, ENTITY_ARG };
|
||||||
filter_type type;
|
filter_type type;
|
||||||
|
bool include;
|
||||||
|
bool traverse;
|
||||||
std::string arg;
|
std::string arg;
|
||||||
std::set<std::string> values;
|
std::set<std::string> values;
|
||||||
};
|
};
|
||||||
// Specialized classes for knowing which type of filter we are validating within validate().
|
// 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.
|
// Could not figure out easily how else to know it if using single type for both.
|
||||||
struct inclusion_filter : public geom_filter {};
|
struct inclusion_filter : public geom_filter { inclusion_filter() : geom_filter(true, false) {} };
|
||||||
struct exclusion_filter : public geom_filter {};
|
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<IfcGeom::filter_t> setup_filters(const geom_filter&, const geom_filter&, const std::string&, bool);
|
std::vector<IfcGeom::filter_t> setup_filters(const std::vector<geom_filter>&, const std::string&);
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
@@ -157,7 +162,9 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
double deflection_tolerance;
|
double deflection_tolerance;
|
||||||
inclusion_filter include_filter;
|
inclusion_filter include_filter;
|
||||||
|
inclusion_traverse_filter include_traverse_filter;
|
||||||
exclusion_filter exclude_filter;
|
exclusion_filter exclude_filter;
|
||||||
|
exclusion_traverse_filter exclude_traverse_filter;
|
||||||
|
|
||||||
po::options_description geom_options("Geometry options");
|
po::options_description geom_options("Geometry options");
|
||||||
geom_options.add_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)."
|
"The values for 'layers' and 'arg' are handled case-sensitively (wildcards supported)."
|
||||||
"--include and --exclude cannot be placed right before input file argument and "
|
"--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.")
|
"only single of each argument supported for now. See also --exclude and --traverse.")
|
||||||
|
("include+", po::value<inclusion_traverse_filter>(&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<exclusion_filter>(&exclude_filter)->multitoken(),
|
("exclude", po::value<exclusion_filter>(&exclude_filter)->multitoken(),
|
||||||
"Specifies that the entities that match a specific filtering criteria are to be excluded in the geometrical output."
|
"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'.")
|
"See --include for syntax and more details. The default value is '--exclude=entities IfcOpeningElement IfcSpace'.")
|
||||||
|
("exclude+", po::value<exclusion_traverse_filter>(&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",
|
("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 "
|
||||||
"in instances where you're going to recompute normals for the exported "
|
"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.")
|
"Sets the deflection tolerance of the mesher, 1e-3 by default if not specified.")
|
||||||
("generate-uvs",
|
("generate-uvs",
|
||||||
"Generates UVs (texture coordinates) by using simple box projection. Requires normals. "
|
"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.");
|
||||||
("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.");
|
|
||||||
|
|
||||||
std::string bounds, offset_str;
|
std::string bounds, offset_str;
|
||||||
#ifdef HAVE_ICU
|
#ifdef HAVE_ICU
|
||||||
@@ -329,8 +339,6 @@ int main(int argc, char** argv)
|
|||||||
const bool center_model = vmap.count("center-model") != 0 ;
|
const bool center_model = vmap.count("center-model") != 0 ;
|
||||||
const bool model_offset = vmap.count("model-offset") != 0 ;
|
const bool model_offset = vmap.count("model-offset") != 0 ;
|
||||||
const bool generate_uvs = vmap.count("generate-uvs") != 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
|
#ifdef HAVE_ICU
|
||||||
if (!unicode_mode.empty()) {
|
if (!unicode_mode.empty()) {
|
||||||
@@ -394,8 +402,15 @@ int main(int argc, char** argv)
|
|||||||
Logger::SetOutput(&std::cout, &log_stream);
|
Logger::SetOutput(&std::cout, &log_stream);
|
||||||
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
|
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
|
||||||
|
|
||||||
std::vector<IfcGeom::filter_t> used_filters = setup_filters(include_filter, exclude_filter, output_extension, traverse);
|
/// @todo Clean up this filter code further.
|
||||||
if (used_filters.empty()) {
|
std::vector<geom_filter> 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<IfcGeom::filter_t> filter_funcs = setup_filters(used_filters, output_extension);
|
||||||
|
if (filter_funcs.empty()) {
|
||||||
std::cerr << "[Error] Failed to set up geometry filters\n";
|
std::cerr << "[Error] Failed to set up geometry filters\n";
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -504,7 +519,7 @@ int main(int argc, char** argv)
|
|||||||
time_t start,end;
|
time_t start,end;
|
||||||
time(&start);
|
time(&start);
|
||||||
|
|
||||||
IfcGeom::Iterator<real_t> context_iterator(settings, input_filename, used_filters);
|
IfcGeom::Iterator<real_t> context_iterator(settings, input_filename, filter_funcs);
|
||||||
if (!context_iterator.initialize()) {
|
if (!context_iterator.initialize()) {
|
||||||
/// @todo It would be nice to know and print separate error prints for a case where we failed to parse
|
/// @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.
|
/// 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<std::string>& values, inclusion_f
|
|||||||
v = filter;
|
v = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void validate(boost::any& v, const std::vector<std::string>& 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<std::string>& values, exclusion_filter*, int)
|
void validate(boost::any& v, const std::vector<std::string>& values, exclusion_filter*, int)
|
||||||
{
|
{
|
||||||
po::validators::check_first_occurrence(v);
|
po::validators::check_first_occurrence(v);
|
||||||
@@ -654,26 +677,58 @@ void validate(boost::any& v, const std::vector<std::string>& values, exclusion_f
|
|||||||
v = filter;
|
v = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @todo Clean up this filter initialization code further.
|
void validate(boost::any& v, const std::vector<std::string>& values, exclusion_traverse_filter*, int)
|
||||||
/// @return The used filters, if none an error occurred.
|
|
||||||
std::vector<IfcGeom::filter_t> setup_filters(
|
|
||||||
const geom_filter& include_filter,
|
|
||||||
const geom_filter& exclude_filter,
|
|
||||||
const std::string& output_extension,
|
|
||||||
bool traverse)
|
|
||||||
{
|
{
|
||||||
std::vector<IfcGeom::filter_t> filters;
|
po::validators::check_first_occurrence(v);
|
||||||
entity_filter.traverse = traverse;
|
exclusion_traverse_filter filter;
|
||||||
try {
|
parse_filter(filter, values);
|
||||||
if (include_filter.type == geom_filter::ENTITY_TYPE) {
|
v = filter;
|
||||||
entity_filter.include = true;
|
}
|
||||||
entity_filter.populate(include_filter.values);
|
|
||||||
} else if (exclude_filter.type == geom_filter::ENTITY_TYPE) {
|
|
||||||
entity_filter.include = false;
|
/// @todo Clean up this filter initialization code further.
|
||||||
entity_filter.populate(exclude_filter.values);
|
/// @return References to the used filter functors, if none an error occurred.
|
||||||
|
std::vector<IfcGeom::filter_t> setup_filters(const std::vector<geom_filter>& filters, const std::string& output_extension)
|
||||||
|
{
|
||||||
|
std::vector<IfcGeom::filter_t> 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<IfcGeom::filter_t>();
|
||||||
|
}
|
||||||
|
} 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<std::string> entities;
|
std::set<std::string> entities;
|
||||||
entities.insert("IfcSpace");
|
entities.insert("IfcSpace");
|
||||||
if (output_extension == ".svg") {
|
if (output_extension == ".svg") {
|
||||||
@@ -682,74 +737,18 @@ std::vector<IfcGeom::filter_t> setup_filters(
|
|||||||
entities.insert("IfcOpeningElement");
|
entities.insert("IfcOpeningElement");
|
||||||
}
|
}
|
||||||
entity_filter.populate(entities);
|
entity_filter.populate(entities);
|
||||||
|
} catch (const IfcParse::IfcException& e) {
|
||||||
|
std::cerr << "[Error] " << e.what() << std::endl;
|
||||||
|
return std::vector<IfcGeom::filter_t>();
|
||||||
}
|
}
|
||||||
} 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 (!layer_filter.values.empty()) { filter_funcs.push_back(boost::ref(layer_filter)); }
|
||||||
if (include_filter.type == geom_filter::LAYER_NAME) {
|
if (!entity_filter.values.empty()) { filter_funcs.push_back(boost::ref(entity_filter)); }
|
||||||
layer_filter.include = true;
|
if (!guid_filter.values.empty()) { filter_funcs.push_back(boost::ref(guid_filter)); }
|
||||||
layer_filter.populate(include_filter.values);
|
if (!name_filter.values.empty()) { filter_funcs.push_back(boost::ref(name_filter)); }
|
||||||
} else if (exclude_filter.type == geom_filter::LAYER_NAME) {
|
if (!desc_filter.values.empty()) { filter_funcs.push_back(boost::ref(desc_filter)); }
|
||||||
layer_filter.include = false;
|
if (!tag_filter.values.empty()) { filter_funcs.push_back(boost::ref(tag_filter)); }
|
||||||
layer_filter.populate(exclude_filter.values);
|
|
||||||
}
|
|
||||||
if (!layer_filter.values.empty()) {
|
|
||||||
filters.push_back(boost::ref(layer_filter));
|
|
||||||
}
|
|
||||||
|
|
||||||
guid_filter.traverse = traverse;
|
return filter_funcs;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user