Option to validate created geometries based on explicit quantities

This commit is contained in:
Thomas Krijnen
2018-12-12 12:33:09 +01:00
parent b88c5ee930
commit 72c96905b9
8 changed files with 128 additions and 26 deletions
+34 -21
View File
@@ -379,6 +379,7 @@ int main(int argc, char** argv)
const bool site_local_placement = vmap.count("site-local-placement") != 0;
const bool building_local_placement = vmap.count("building-local-placement") != 0;
const bool generate_uvs = vmap.count("generate-uvs") != 0;
const bool validate = vmap.count("validate") != 0;
if (!quiet || vmap.count("version")) {
print_version();
@@ -571,7 +572,7 @@ int main(int argc, char** argv)
settings.set(IfcGeom::IteratorSettings::SEARCH_FLOOR, use_element_hierarchy);
settings.set(IfcGeom::IteratorSettings::SITE_LOCAL_PLACEMENT, site_local_placement);
settings.set(IfcGeom::IteratorSettings::BUILDING_LOCAL_PLACEMENT, building_local_placement);
settings.set(IfcGeom::IteratorSettings::VALIDATE_QUANTITIES, validate);
settings.set(SerializerSettings::USE_ELEMENT_NAMES, use_element_names);
settings.set(SerializerSettings::USE_ELEMENT_GUIDS, use_element_guids);
@@ -785,6 +786,11 @@ int main(int argc, char** argv)
output_temp_filename + "' for the conversion result.");
}
if (validate && Logger::MaxSeverity() >= Logger::LOG_ERROR) {
Logger::Error("Errors encountered during proccessing.");
successful = false;
}
write_log(!quiet);
time(&end);
@@ -1151,10 +1157,17 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
IfcEntityList::ptr objects;
boost::shared_ptr<IfcGeom::Representation::BRep> previous_geometry_pointer;
do {
IfcGeom::BRepElement<double>* geom_object = context_iterator.get_native();
for (;; ++num_created) {
bool has_more = true;
if (num_created) {
has_more = context_iterator.next();
}
IfcGeom::BRepElement<double>* geom_object = nullptr;
if (has_more) {
geom_object = context_iterator.get_native();
}
if (geom_object->geometry_pointer() == previous_geometry_pointer) {
if (geom_object && geom_object->geometry_pointer() == previous_geometry_pointer) {
objects->push(geom_object->product());
} else {
if (quantity) {
@@ -1164,6 +1177,10 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
latebound_access::set(rel, "RelatingPropertyDefinition", quantity);
}
if (!geom_object) {
break;
}
IfcEntityList::ptr quantities(new IfcEntityList);
double a, b, c;
@@ -1188,27 +1205,23 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
quantities->push(quantity_area);
}
for (auto& part : geom_object->geometry()) {
auto quantity_complex = latebound_access::create(f, "IfcPhysicalComplexQuantity");
latebound_access::set(quantity_complex, "Name", std::string("Shape validation properties"));
latebound_access::set(quantity_complex, "Discrimination", '#' + boost::lexical_cast<std::string>(part.ItemId()));
auto quantity_complex = latebound_access::create(f, "IfcPhysicalComplexQuantity");
latebound_access::set(quantity_complex, "Name", std::string("Shape Validation Properties"));
quantities->push(quantity_complex);
IfcEntityList::ptr quantities_2(new IfcEntityList);
int nv = IfcGeom::Kernel::count(part.Shape(), TopAbs_VERTEX, true);
int ne = IfcGeom::Kernel::count(part.Shape(), TopAbs_EDGE, true);
int nf = IfcGeom::Kernel::count(part.Shape(), TopAbs_FACE, true);
IfcEntityList::ptr quantities_2(new IfcEntityList);
const int euler = nv - ne + nf;
const int genus = (2 - euler) / 2;
for (auto& part : geom_object->geometry()) {
auto quantity_count = latebound_access::create(f, "IfcQuantityCount");
latebound_access::set(quantity_count, "Name", std::string("Surface Genus"));
latebound_access::set(quantity_count, "Description", '#' + boost::lexical_cast<std::string>(part.ItemId()));
latebound_access::set(quantity_count, "CountValue", IfcGeom::Kernel::surface_genus(part.Shape()));
auto quantity_area = latebound_access::create(f, "IfcQuantityCount");
latebound_access::set(quantity_area, "Name", std::string("Surface genus"));
latebound_access::set(quantity_area, "CountValue", genus);
latebound_access::set(quantity_complex, "HasQuantities", quantities_2);
quantities_2->push(quantity_count);
}
latebound_access::set(quantity_complex, "HasQuantities", quantities_2);
if (quantities->size()) {
quantity = latebound_access::create(f, "IfcElementQuantity");
latebound_access::set(quantity, "OwnerHistory", ownerhist);
@@ -1238,7 +1251,7 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std
old_progress = progress;
}
}
} while (++num_created, context_iterator.next());
}
if (!no_progress && quiet) {
for (; old_progress < 100; ++old_progress) {
+69 -3
View File
@@ -1591,17 +1591,83 @@ IfcGeom::BRepElement<P, PP>* IfcGeom::Kernel::create_brep_for_representation_and
context_string = representation->ContextOfItems()->ContextType();
}
return new BRepElement<P, PP>(
auto elem = new BRepElement<P, PP>(
product->data().id(),
parent_id,
name,
name,
product_type,
guid,
context_string,
trsf,
boost::shared_ptr<IfcGeom::Representation::BRep>(shape),
product
product
);
if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) {
auto rels = product->IsDefinedBy();
for (auto& rel : *rels) {
if (rel->as<IfcSchema::IfcRelDefinesByProperties>()) {
auto pdef = rel->as<IfcSchema::IfcRelDefinesByProperties>()->RelatingPropertyDefinition();
if (pdef->as<IfcSchema::IfcElementQuantity>()) {
if (pdef->as<IfcSchema::IfcElementQuantity>()->OwnerHistory()->OwningApplication()->ApplicationDeveloper()->Name() == "IfcOpenShell") {
auto qs = pdef->as<IfcSchema::IfcElementQuantity>()->Quantities();
for (auto& q : *qs) {
if (q->as<IfcSchema::IfcQuantityArea>() && q->Name() == "Total Surface Area") {
double a_calc;
double a_file = q->as<IfcSchema::IfcQuantityArea>()->AreaValue();
if (elem->geometry().calculate_surface_area(a_calc)) {
double diff = std::abs(a_calc - a_file);
if (diff / std::sqrt(a_file) > getValue(GV_PRECISION)) {
Logger::Error("Validation of surface area failed for:", product);
} else {
Logger::Notice("Validation of surface area succeeded for:", product);
}
} else {
Logger::Error("Validation of surface area failed for:", product);
}
} else if (q->as<IfcSchema::IfcQuantityVolume>() && q->Name() == "Volume") {
double v_calc;
double v_file = q->as<IfcSchema::IfcQuantityVolume>()->VolumeValue();
if (elem->geometry().calculate_volume(v_calc)) {
double diff = std::abs(v_calc - v_file);
if (diff / std::sqrt(v_file) > getValue(GV_PRECISION)) {
Logger::Error("Validation of volume failed for:", product);
} else {
Logger::Notice("Validation of volume succeeded for:", product);
}
} else {
Logger::Error("Validation of volume failed for:", product);
}
} else if (q->as<IfcSchema::IfcPhysicalComplexQuantity>() && q->Name() == "Shape Validation Properties") {
auto qs2 = q->as<IfcSchema::IfcPhysicalComplexQuantity>()->HasQuantities();
bool all_succeeded = qs2->size() > 0;
for (auto& q2 : *qs2) {
if (q2->as<IfcSchema::IfcQuantityCount>() && q2->Name() == "Surface Genus" && q2->hasDescription()) {
int item_id = boost::lexical_cast<int>(q2->Description().substr(1));
int genus = q2->as<IfcSchema::IfcQuantityCount>()->CountValue();
for (auto& part : elem->geometry()) {
if (part.ItemId() == item_id) {
if (surface_genus(part.Shape()) != genus) {
all_succeeded = false;
}
}
}
}
}
if (!all_succeeded) {
Logger::Error("Validation of surface genus failed for:", product);
} else {
Logger::Notice("Validation of surface genus succeeded for:", product);
}
}
}
}
}
}
}
}
return elem;
}
IfcSchema::IfcRepresentation* IfcGeom::Kernel::representation_mapped_to(const IfcSchema::IfcRepresentation* representation) {
+3 -1
View File
@@ -84,8 +84,10 @@ namespace IfcGeom
SITE_LOCAL_PLACEMENT = 1 << 15,
///
BUILDING_LOCAL_PLACEMENT = 1 << 16,
///
VALIDATE_QUANTITIES = 1 << 17,
/// Number of different setting flags.
NUM_SETTINGS = 16
NUM_SETTINGS = 17
};
/// Used to store logical OR combination of setting flags.
typedef unsigned SettingField;
+1 -1
View File
@@ -725,7 +725,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresen
} else {
TopoDS_Shape s;
if (convert_shape(representation_item,s)) {
shapes.push_back(IfcRepresentationShapeItem(l->data().id(), s, get_style(representation_item)));
shapes.push_back(IfcRepresentationShapeItem(representation_item->data().id(), s, get_style(representation_item)));
part_succes |= true;
}
}
+12
View File
@@ -31,6 +31,18 @@ int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool uniqu
}
}
int IfcGeom::Kernel::surface_genus(const TopoDS_Shape& s) {
int nv = count(s, TopAbs_VERTEX, true);
int ne = count(s, TopAbs_EDGE, true);
int nf = count(s, TopAbs_FACE, true);
const int euler = nv - ne + nf;
const int genus = (2 - euler) / 2;
return genus;
}
IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementations() {
static KernelFactoryImplementation impl;
return impl;
+1
View File
@@ -84,6 +84,7 @@ namespace IfcGeom {
}
static int count(const TopoDS_Shape&, TopAbs_ShapeEnum, bool unique=false);
static int surface_genus(const TopoDS_Shape&);
static bool is_manifold(const TopoDS_Shape& a);
static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*);
+6
View File
@@ -76,6 +76,9 @@ void Logger::SetOutput(std::ostream* l1, std::ostream* l2) {
}
void Logger::Message(Logger::Severity type, const std::string& message, const IfcUtil::IfcBaseClass* instance) {
if (type > max_severity) {
max_severity = type;
}
if (log2 && type >= verbosity) {
if (format == FMT_PLAIN) {
plain_text_message(*log2, current_product, type, message, instance);
@@ -110,6 +113,8 @@ std::string Logger::GetLog() {
void Logger::Verbosity(Logger::Severity v) { verbosity = v; }
Logger::Severity Logger::Verbosity() { return verbosity; }
Logger::Severity Logger::MaxSeverity() { return max_severity; }
void Logger::OutputFormat(Format f) { format = f; }
Logger::Format Logger::OutputFormat() { return format; }
@@ -117,5 +122,6 @@ std::ostream* Logger::log1 = 0;
std::ostream* Logger::log2 = 0;
std::stringstream Logger::log_stream;
Logger::Severity Logger::verbosity = Logger::LOG_NOTICE;
Logger::Severity Logger::max_severity = Logger::LOG_NOTICE;
Logger::Format Logger::format = Logger::FMT_PLAIN;
boost::optional<IfcUtil::IfcBaseClass*> Logger::current_product;
+2
View File
@@ -44,6 +44,7 @@ private:
static Severity verbosity;
static Format format;
static boost::optional<IfcUtil::IfcBaseClass*> current_product;
static Severity max_severity;
public:
static void SetProduct(boost::optional<IfcUtil::IfcBaseClass*> product) {
@@ -56,6 +57,7 @@ public:
/// Determines the types of log messages to get logged
static void Verbosity(Severity v);
static Severity Verbosity();
static Severity MaxSeverity();
/// Determines output format: plain text or sequence of JSON objects
static void OutputFormat(Format f);