mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-28 19:27:10 +00:00
Ignore entity types earlier in IfcConvert so that representations are not processed in vain
This commit is contained in:
@@ -84,35 +84,48 @@ int main(int argc, char** argv) {
|
|||||||
("input-file", boost::program_options::value<std::string>(), "input IFC file")
|
("input-file", boost::program_options::value<std::string>(), "input IFC file")
|
||||||
("output-file", boost::program_options::value<std::string>(), "output geometry file");
|
("output-file", boost::program_options::value<std::string>(), "output geometry file");
|
||||||
|
|
||||||
std::vector<std::string> ignore_types_vector;
|
std::vector<std::string> entity_vector;
|
||||||
boost::program_options::options_description geom_options;
|
boost::program_options::options_description geom_options;
|
||||||
geom_options.add_options()
|
geom_options.add_options()
|
||||||
("weld-vertices", "Specifies whether vertices are welded, meaning that the coordinates "
|
("weld-vertices",
|
||||||
"vector will only contain unique xyz-triplets. This results in a "
|
"Specifies whether vertices are welded, meaning that the coordinates "
|
||||||
"manifold mesh which is useful for modelling applications, but might "
|
"vector will only contain unique xyz-triplets. This results in a "
|
||||||
"result in unwanted shading artifacts in rendering applications.")
|
"manifold mesh which is useful for modelling applications, but might "
|
||||||
("use-world-coords", "Specifies whether to apply the local placements of building elements "
|
"result in unwanted shading artefacts in rendering applications.")
|
||||||
"directly to the coordinates of the representation mesh rather than "
|
("use-world-coords",
|
||||||
"to represent the local placement in the 4x3 matrix, which will in that "
|
"Specifies whether to apply the local placements of building elements "
|
||||||
"case be the identity matrix.")
|
"directly to the coordinates of the representation mesh rather than "
|
||||||
("convert-back-units", "Specifies whether to convert back geometrical output back to the "
|
"to represent the local placement in the 4x3 matrix, which will in that "
|
||||||
"unit of measure in which it is defined in the IFC file. Default is "
|
"case be the identity matrix.")
|
||||||
"to use meters.")
|
("convert-back-units",
|
||||||
("sew-shells", "Specifies whether to sew the faces of IfcConnectedFaceSets together. This is a "
|
"Specifies whether to convert back geometrical output back to the "
|
||||||
"potentially time consuming operation, but guarantees a consistent orientation "
|
"unit of measure in which it is defined in the IFC file. Default is "
|
||||||
"of surface normals, even if the faces are not properly oriented in the IFC file.")
|
"to use meters.")
|
||||||
("merge-boolean-operands", "Specifies whether to merge all IfcOpeningElement operands into a single "
|
("sew-shells",
|
||||||
"operand before applying the subtraction operation. This may "
|
"Specifies whether to sew the faces of IfcConnectedFaceSets together. "
|
||||||
"introduce a performance improvement at the risk of failing, in "
|
"This is a potentially time consuming operation, but guarantees a "
|
||||||
"which case the subtraction is applied one-by-one.")
|
"consistent orientation of surface normals, even if the faces are not "
|
||||||
("force-ccw-face-orientation", "Recompute topological face normals using Newell's Method to "
|
"properly oriented in the IFC file.")
|
||||||
"guarantee that face vertices are defined in a Counter Clock "
|
("merge-boolean-operands",
|
||||||
"Wise order, even if the faces are not part of a closed shell.")
|
"Specifies whether to merge all IfcOpeningElement operands into a single "
|
||||||
("disable-opening-subtractions", "Specifies whether to disable the boolean subtraction of "
|
"operand before applying the subtraction operation. This may "
|
||||||
"IfcOpeningElement Representations from their RelatingElements.")
|
"introduce a performance improvement at the risk of failing, in "
|
||||||
("ignore-types", boost::program_options::value< std::vector<std::string> >(&ignore_types_vector)->multitoken(),
|
"which case the subtraction is applied one-by-one.")
|
||||||
"A list of IFC datatype keywords that should not be included in the geometrical output. "
|
("force-ccw-face-orientation",
|
||||||
"Defaults to IfcOpeningElement and IfcSpace");
|
"Recompute topological face normals using Newell's Method to "
|
||||||
|
"guarantee that face vertices are defined in a Counter Clock "
|
||||||
|
"Wise order, even if the faces are not part of a closed shell.")
|
||||||
|
("disable-opening-subtractions",
|
||||||
|
"Specifies whether to disable the boolean subtraction of "
|
||||||
|
"IfcOpeningElement Representations from their RelatingElements.")
|
||||||
|
("include",
|
||||||
|
"Specifies that the entities listed after --entities are to be included")
|
||||||
|
("exclude",
|
||||||
|
"Specifies that the entities listed after --entities are to be excluded")
|
||||||
|
("entities", boost::program_options::value< std::vector<std::string> >(&entity_vector)->multitoken(),
|
||||||
|
"A list of entities that should be included in or excluded from the "
|
||||||
|
"geometrical output, depending on whether --ignore or --include is "
|
||||||
|
"specified. Defaults to IfcOpeningElement and IfcSpace to be excluded.");
|
||||||
|
|
||||||
boost::program_options::options_description cmdline_options;
|
boost::program_options::options_description cmdline_options;
|
||||||
cmdline_options.add(generic_options).add(fileio_options).add(geom_options);
|
cmdline_options.add(generic_options).add(fileio_options).add(geom_options);
|
||||||
@@ -139,6 +152,10 @@ int main(int argc, char** argv) {
|
|||||||
} else if (vmap.count("help") || !vmap.count("input-file")) {
|
} else if (vmap.count("help") || !vmap.count("input-file")) {
|
||||||
printUsage(generic_options, geom_options);
|
printUsage(generic_options, geom_options);
|
||||||
return vmap.count("help") ? 0 : 1;
|
return vmap.count("help") ? 0 : 1;
|
||||||
|
} else if (vmap.count("include") && vmap.count("exclude")) {
|
||||||
|
std::cerr << "[Error] --include and --ignore can not be specified together" << std::endl;
|
||||||
|
printUsage(generic_options, geom_options);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool verbose = vmap.count("verbose") != 0;
|
const bool verbose = vmap.count("verbose") != 0;
|
||||||
@@ -149,20 +166,22 @@ 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;
|
||||||
const bool force_ccw_face_orientation = vmap.count("force-ccw-face-orientation") != 0;
|
const bool force_ccw_face_orientation = vmap.count("force-ccw-face-orientation") != 0;
|
||||||
const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0;
|
const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0;
|
||||||
|
const bool include_entities = vmap.count("include") != 0;
|
||||||
|
|
||||||
// Gets the set ifc types to be ignored from the command line.
|
// Gets the set ifc types to be ignored from the command line.
|
||||||
std::set<std::string> ignore_types;
|
std::set<std::string> entities;
|
||||||
for (std::vector<std::string>::const_iterator it = ignore_types_vector.begin(); it != ignore_types_vector.end(); ++it) {
|
for (std::vector<std::string>::const_iterator it = entity_vector.begin(); it != entity_vector.end(); ++it) {
|
||||||
std::string lowercase_type = *it;
|
std::string lowercase_type = *it;
|
||||||
for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) {
|
for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) {
|
||||||
*c = tolower(*c);
|
*c = tolower(*c);
|
||||||
}
|
}
|
||||||
ignore_types.insert(lowercase_type);
|
entities.insert(lowercase_type);
|
||||||
}
|
}
|
||||||
// If none are specified these are the defaults to skip from output
|
|
||||||
if (ignore_types_vector.empty()) {
|
// If no entities are specified these are the defaults to skip from output
|
||||||
ignore_types.insert("ifcopeningelement");
|
if (entity_vector.empty()) {
|
||||||
ignore_types.insert("ifcspace");
|
entities.insert("ifcopeningelement");
|
||||||
|
entities.insert("ifcspace");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string input_filename = vmap["input-file"].as<std::string>();
|
const std::string input_filename = vmap["input-file"].as<std::string>();
|
||||||
@@ -224,6 +243,17 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
IfcGeom::Iterator<double> context_iterator(settings, input_filename);
|
IfcGeom::Iterator<double> context_iterator(settings, input_filename);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (include_entities) {
|
||||||
|
context_iterator.includeEntities(entities);
|
||||||
|
} else {
|
||||||
|
context_iterator.excludeEntities(entities);
|
||||||
|
}
|
||||||
|
} catch (const IfcParse::IfcException& e) {
|
||||||
|
std::cout << "[Error] " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!serializer->ready()) {
|
if (!serializer->ready()) {
|
||||||
Logger::Message(Logger::LOG_ERROR, "Unable to open output file for writing");
|
Logger::Message(Logger::LOG_ERROR, "Unable to open output file for writing");
|
||||||
write_log();
|
write_log();
|
||||||
@@ -231,7 +261,6 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!serializer->isTesselated()) {
|
if (!serializer->isTesselated()) {
|
||||||
|
|
||||||
if (weld_vertices) {
|
if (weld_vertices) {
|
||||||
Logger::Message(Logger::LOG_NOTICE, "Weld vertices setting ignored when writing STEP or IGES files");
|
Logger::Message(Logger::LOG_NOTICE, "Weld vertices setting ignored when writing STEP or IGES files");
|
||||||
}
|
}
|
||||||
@@ -239,7 +268,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
time_t start,end;
|
time_t start,end;
|
||||||
time(&start);
|
time(&start);
|
||||||
// Parse the file supplied in argv[1]. Returns true on succes.
|
|
||||||
if (!context_iterator.findContext()) {
|
if (!context_iterator.findContext()) {
|
||||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found");
|
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found");
|
||||||
write_log();
|
write_log();
|
||||||
@@ -264,13 +293,7 @@ int main(int argc, char** argv) {
|
|||||||
// IfcGeomObjects::Next() is used to poll whether more geometrical entities are available
|
// IfcGeomObjects::Next() is used to poll whether more geometrical entities are available
|
||||||
do {
|
do {
|
||||||
const IfcGeom::Element<double>* geom_object = context_iterator.get();
|
const IfcGeom::Element<double>* geom_object = context_iterator.get();
|
||||||
|
|
||||||
std::string lowercase_type = geom_object->type();
|
|
||||||
for (std::string::iterator c = lowercase_type.begin(); c != lowercase_type.end(); ++c) {
|
|
||||||
*c = tolower(*c);
|
|
||||||
}
|
|
||||||
if (ignore_types.find(lowercase_type) != ignore_types.end()) continue;
|
|
||||||
|
|
||||||
if (serializer->isTesselated()) {
|
if (serializer->isTesselated()) {
|
||||||
serializer->write(static_cast<const IfcGeom::TriangulationElement<double>*>(geom_object));
|
serializer->write(static_cast<const IfcGeom::TriangulationElement<double>*>(geom_object));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ namespace IfcGeom {
|
|||||||
SerializedElement<P>* current_serialization;
|
SerializedElement<P>* current_serialization;
|
||||||
|
|
||||||
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
|
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
|
||||||
IfcSchema::IfcProduct::list::ptr entities;
|
IfcSchema::IfcProduct::list::ptr ifcproducts;
|
||||||
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
|
IfcSchema::IfcProduct::list::it ifcproduct_iterator;
|
||||||
|
|
||||||
int done;
|
int done;
|
||||||
@@ -119,6 +119,29 @@ namespace IfcGeom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::set<IfcSchema::Type::Enum> entities_to_include_or_exclude;
|
||||||
|
bool include_entities_in_processing;
|
||||||
|
|
||||||
|
void populate_set(const std::set<std::string>& include_or_ignore) {
|
||||||
|
entities_to_include_or_exclude.clear();
|
||||||
|
for (std::set<std::string>::const_iterator it = include_or_ignore.begin(); it != include_or_ignore.end(); ++it) {
|
||||||
|
std::string uppercase_type = *it;
|
||||||
|
for (std::string::iterator c = uppercase_type.begin(); c != uppercase_type.end(); ++c) {
|
||||||
|
*c = toupper(*c);
|
||||||
|
}
|
||||||
|
IfcSchema::Type::Enum ty;
|
||||||
|
try {
|
||||||
|
ty = IfcSchema::Type::FromString(uppercase_type);
|
||||||
|
} catch (const IfcParse::IfcException&) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "'" << *it << "' does not name a valid IFC entity";
|
||||||
|
throw IfcParse::IfcException(ss.str());
|
||||||
|
}
|
||||||
|
entities_to_include_or_exclude.insert(ty);
|
||||||
|
// TODO: Add child classes so that containment in set can be in O(log n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool findContext() {
|
bool findContext() {
|
||||||
try {
|
try {
|
||||||
@@ -202,7 +225,7 @@ namespace IfcGeom {
|
|||||||
if (representations->size() == 0) return false;
|
if (representations->size() == 0) return false;
|
||||||
|
|
||||||
representation_iterator = representations->begin();
|
representation_iterator = representations->begin();
|
||||||
entities.reset();
|
ifcproducts.reset();
|
||||||
|
|
||||||
if (!create()) {
|
if (!create()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -234,10 +257,20 @@ namespace IfcGeom {
|
|||||||
return ifc_file;
|
return ifc_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void includeEntities(const std::set<std::string>& entities) {
|
||||||
|
populate_set(entities);
|
||||||
|
include_entities_in_processing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void excludeEntities(const std::set<std::string>& entities) {
|
||||||
|
populate_set(entities);
|
||||||
|
include_entities_in_processing = false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Move to the next IfcRepresentation
|
// Move to the next IfcRepresentation
|
||||||
void _nextShape() {
|
void _nextShape() {
|
||||||
entities.reset();
|
ifcproducts.reset();
|
||||||
++ representation_iterator;
|
++ representation_iterator;
|
||||||
++ done;
|
++ done;
|
||||||
}
|
}
|
||||||
@@ -254,14 +287,16 @@ namespace IfcGeom {
|
|||||||
representation = *representation_iterator;
|
representation = *representation_iterator;
|
||||||
|
|
||||||
// Has the list of IfcProducts for this representation been initialized?
|
// Has the list of IfcProducts for this representation been initialized?
|
||||||
if ( ! entities ) {
|
if (!ifcproducts) {
|
||||||
|
|
||||||
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
|
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
|
||||||
entities = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
|
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
|
||||||
|
IfcSchema::IfcProduct::list::ptr unfiltered_products(new IfcSchema::IfcProduct::list);
|
||||||
|
|
||||||
for ( IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
|
for ( IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it ) {
|
||||||
if ( (*it)->is(IfcSchema::Type::IfcProductDefinitionShape) ) {
|
if ( (*it)->is(IfcSchema::Type::IfcProductDefinitionShape) ) {
|
||||||
IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it;
|
IfcSchema::IfcProductDefinitionShape* pds = (IfcSchema::IfcProductDefinitionShape*)*it;
|
||||||
entities->push(pds->ShapeOfProduct());
|
unfiltered_products->push(pds->ShapeOfProduct());
|
||||||
} else {
|
} else {
|
||||||
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
|
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
|
||||||
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
|
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
|
||||||
@@ -269,21 +304,34 @@ namespace IfcGeom {
|
|||||||
|
|
||||||
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
|
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
|
||||||
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
|
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
|
||||||
IfcEntityList::ptr products = (*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1);
|
unfiltered_products->push((*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>());
|
||||||
for ( IfcEntityList::it it = products->begin(); it != products->end(); ++ it ) {
|
}
|
||||||
entities->push((IfcSchema::IfcProduct*)*it);
|
|
||||||
|
// Filter the products based on the set of entities being included or excluded for
|
||||||
|
// processing. The set is iterated over te able to filter on subtypes.
|
||||||
|
for ( IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it ) {
|
||||||
|
bool found = false;
|
||||||
|
for (std::set<IfcSchema::Type::Enum>::const_iterator jt = entities_to_include_or_exclude.begin(); jt != entities_to_include_or_exclude.end(); ++jt) {
|
||||||
|
if ((*it)->is(*jt)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found == include_entities_in_processing) {
|
||||||
|
ifcproducts->push(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// Does this representation have any IfcProducts?
|
// Does this representation have any IfcProducts?
|
||||||
if ( ! entities->size() ) {
|
if (!ifcproducts->size()) {
|
||||||
_nextShape();
|
_nextShape();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ifcproduct_iterator = entities->begin();
|
ifcproduct_iterator = ifcproducts->begin();
|
||||||
}
|
}
|
||||||
// Have we reached the end of our list of IfcProducts?
|
// Have we reached the end of our list of IfcProducts?
|
||||||
if ( ifcproduct_iterator == entities->end() ) {
|
if ( ifcproduct_iterator == ifcproducts->end() ) {
|
||||||
_nextShape();
|
_nextShape();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -314,7 +362,7 @@ namespace IfcGeom {
|
|||||||
|
|
||||||
// Increment the iterator over the list of products using the current
|
// Increment the iterator over the list of products using the current
|
||||||
// shape representation
|
// shape representation
|
||||||
if (entities) {
|
if (ifcproducts) {
|
||||||
++ifcproduct_iterator;
|
++ifcproduct_iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user