--section-height-from-storeys

This commit is contained in:
Thomas Krijnen
2020-07-11 13:39:09 +02:00
parent 803cc66abb
commit 1e916896ab
3 changed files with 246 additions and 200 deletions
+24 -13
View File
@@ -325,6 +325,7 @@ int main(int argc, char** argv) {
#endif #endif
short precision; short precision;
double section_height; double section_height;
po::options_description serializer_options("Serialization options"); po::options_description serializer_options("Serialization options");
serializer_options.add_options() serializer_options.add_options()
#ifdef HAVE_ICU #ifdef HAVE_ICU
@@ -337,6 +338,7 @@ int main(int argc, char** argv) {
"output will be scaled. Only used when converting to SVG.") "output will be scaled. Only used when converting to SVG.")
("section-height", po::value<double>(&section_height), ("section-height", po::value<double>(&section_height),
"Specifies the cut section height for SVG 2D geometry.") "Specifies the cut section height for SVG 2D geometry.")
("section-height-from-storeys", "Derives section height from storey elevation. Use --section-height to override default offset of 1")
("use-element-names", ("use-element-names",
"Use entity names instead of unique IDs for naming elements upon serialization. " "Use entity names instead of unique IDs for naming elements upon serialization. "
"Applicable for OBJ, DAE, and SVG output.") "Applicable for OBJ, DAE, and SVG output.")
@@ -695,19 +697,6 @@ int main(int argc, char** argv) {
} else if (output_extension == SVG) { } else if (output_extension == SVG) {
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
serializer = boost::make_shared<SvgSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings); serializer = boost::make_shared<SvgSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
if (vmap.count("section-height") != 0) {
Logger::Notice("Overriding section height");
static_cast<SvgSerializer*>(serializer.get())->setSectionHeight(section_height);
}
if (vmap.count("print-space-names") != 0) {
static_cast<SvgSerializer*>(serializer.get())->setPrintSpaceNames(true);
}
if (vmap.count("print-space-areas") != 0) {
static_cast<SvgSerializer*>(serializer.get())->setPrintSpaceAreas(true);
}
if (bounding_width.is_initialized() && bounding_height.is_initialized()) {
static_cast<SvgSerializer*>(serializer.get())->setBoundingRectangle(bounding_width.get(), bounding_height.get());
}
} else { } else {
cerr_ << "[Error] Unknown output filename extension '" << output_extension << "'\n"; cerr_ << "[Error] Unknown output filename extension '" << output_extension << "'\n";
write_log(!quiet); write_log(!quiet);
@@ -825,6 +814,28 @@ int main(int argc, char** argv) {
serializer->setFile(context_iterator.file()); serializer->setFile(context_iterator.file());
if (output_extension == SVG) {
if (vmap.count("section-height-from-storeys") != 0) {
if (vmap.count("section-height")) {
static_cast<SvgSerializer*>(serializer.get())->setSectionHeightsFromStoreys(section_height);
} else {
static_cast<SvgSerializer*>(serializer.get())->setSectionHeightsFromStoreys();
}
} else if (vmap.count("section-height") != 0) {
Logger::Notice("Overriding section height");
static_cast<SvgSerializer*>(serializer.get())->setSectionHeight(section_height);
}
if (vmap.count("print-space-names") != 0) {
static_cast<SvgSerializer*>(serializer.get())->setPrintSpaceNames(true);
}
if (vmap.count("print-space-areas") != 0) {
static_cast<SvgSerializer*>(serializer.get())->setPrintSpaceAreas(true);
}
if (bounding_width.is_initialized() && bounding_height.is_initialized()) {
static_cast<SvgSerializer*>(serializer.get())->setBoundingRectangle(bounding_width.get(), bounding_height.get());
}
}
if (convert_back_units) { if (convert_back_units) {
serializer->setUnitNameAndMagnitude(context_iterator.unit_name(), static_cast<float>(context_iterator.unit_magnitude())); serializer->setUnitNameAndMagnitude(context_iterator.unit_name(), static_cast<float>(context_iterator.unit_magnitude()));
} else { } else {
+64 -30
View File
@@ -290,32 +290,40 @@ SvgSerializer::path_object& SvgSerializer::start_path(IfcUtil::IfcBaseEntity* st
return p; return p;
} }
#include <Bnd_Box.hxx>
#include <BRepBndLib.hxx>
void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o) void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
{ {
IfcUtil::IfcBaseEntity* storey = storey_; std::vector<std::pair<double, IfcUtil::IfcBaseEntity*>> section_heights_storage;
boost::optional<double> storey_elevation = boost::none; const std::vector<std::pair<double, IfcUtil::IfcBaseEntity*>>* section_heights_used = &section_heights_storage;
if (section_heights) {
section_heights_used = section_heights.get_ptr();
} else {
for (const auto& p : o->parents()) { for (const auto& p : o->parents()) {
if (p->type() == "IfcBuildingStorey") { if (p->type() == "IfcBuildingStorey") {
try { try {
const IfcGeom::ElementSettings& settings = o->geometry().settings(); const IfcGeom::ElementSettings& settings = o->geometry().settings();
double e = *p->product()->get("Elevation"); double e = *p->product()->get("Elevation");
storey_elevation = e * settings.unit_magnitude(); double storey_elevation = e * settings.unit_magnitude();
section_heights_storage.push_back({ storey_elevation + 1. , p->product() });
} catch (...) { } catch (...) {
continue; continue;
} }
storey = p->product();
break; break;
} }
} }
// With a global section height, building storeys are not a requirement. if (section_heights_storage.empty()) {
if (!storey && !section_height) {
Logger::Warning("No global section height and unable to determine building storey for:", o->product()); Logger::Warning("No global section height and unable to determine building storey for:", o->product());
return; return;
} }
}
path_object& p = start_path(storey, nameElement(o)); for (auto& pair : *section_heights_used) {
auto cut_z = pair.first;
auto storey = pair.second;
// SVG has a coordinate system with the origin in the *upper*-left corner // SVG has a coordinate system with the origin in the *upper*-left corner
// therefore we mirror the shape along the XZ-plane. // therefore we mirror the shape along the XZ-plane.
@@ -331,52 +339,50 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
TopoDS_Face largest_closed_wire_face; TopoDS_Face largest_closed_wire_face;
double largest_closed_wire_area = 0.; double largest_closed_wire_area = 0.;
path_object* po;
// Iterate over components of compound to have better chance of matching section edges to closed wires // Iterate over components of compound to have better chance of matching section edges to closed wires
for (; it.More(); it.Next()) { for (; it.More(); it.Next()) {
const TopoDS_Shape& subshape = it.Value(); const TopoDS_Shape& subshape = it.Value();
const double inf = std::numeric_limits<double>::infinity(); Bnd_Box bb;
double zmin = inf; BRepBndLib::Add(it.Value(), bb);
double zmax = -inf;
{TopExp_Explorer exp(subshape, TopAbs_VERTEX);
for (; exp.More(); exp.Next()) {
const TopoDS_Vertex& vertex = TopoDS::Vertex(exp.Current());
gp_Pnt pnt = BRep_Tool::Pnt(vertex);
if (pnt.Z() < zmin) { zmin = pnt.Z(); }
if (pnt.Z() > zmax) { zmax = pnt.Z(); }
}}
// Empty geometry, no vertices encountered // Empty geometry
if (zmin == inf) continue; if (bb.IsVoid()) {
continue;
}
double x1, y1, zmin, x2, y2, zmax;
bb.Get(x1, y1, zmin, x2, y2, zmax);
// Determine slicing plane z coordinate, priority: // Determine slicing plane z coordinate, priority:
// 1) explicitly set global section height // 1) explicitly set global section height
// 2) containing building storey elevation + 1m // 2) containing building storey elevation + 1m
// 3) zmin (from geometry bounding box) + 1m // 3) zmin (from geometry bounding box) + 1m
double cut_z;
if (section_height) { if (std::isnan(cut_z)) {
cut_z = section_height.get();
} else if (storey_elevation && !(zmin > *storey_elevation || zmax < *storey_elevation)) {
cut_z = storey_elevation.get() + 1.;
} else {
cut_z = zmin + 1.; cut_z = zmin + 1.;
} }
// No intersection with bounding box, fail early // No intersection with bounding box, fail early
if (zmin > cut_z || zmax < cut_z) continue; if (zmin > cut_z || zmax < cut_z) continue;
po = &start_path(storey, nameElement(o));
// Create a horizontal cross section 1 meter above the bottom point of the shape // Create a horizontal cross section 1 meter above the bottom point of the shape
const gp_Pln pln(gp_Pnt(0, 0, cut_z), gp::DZ()); const gp_Pln pln(gp_Pnt(0, 0, cut_z), gp::DZ());
TopoDS_Shape result = BRepAlgoAPI_Section(subshape, pln); TopoDS_Shape result = BRepAlgoAPI_Section(subshape, pln);
Handle(TopTools_HSequenceOfShape) edges = new TopTools_HSequenceOfShape(); Handle(TopTools_HSequenceOfShape) edges = new TopTools_HSequenceOfShape();
Handle(TopTools_HSequenceOfShape) wires = new TopTools_HSequenceOfShape(); Handle(TopTools_HSequenceOfShape) wires = new TopTools_HSequenceOfShape();
{TopExp_Explorer exp(result, TopAbs_EDGE); {
TopExp_Explorer exp(result, TopAbs_EDGE);
for (; exp.More(); exp.Next()) { for (; exp.More(); exp.Next()) {
edges->Append(exp.Current()); edges->Append(exp.Current());
}} }
}
ShapeAnalysis_FreeBounds::ConnectEdgesToWires(edges, 1e-5, false, wires); ShapeAnalysis_FreeBounds::ConnectEdgesToWires(edges, 1e-5, false, wires);
gp_Pnt prev; gp_Pnt prev;
@@ -400,7 +406,7 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
} }
} }
write(p, wire); write(*po, wire);
} }
} }
@@ -470,7 +476,6 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
labels.push_back(ss.str() + "m&#178;"); labels.push_back(ss.str() + "m&#178;");
} }
path_object& po = p;
util::string_buffer path; util::string_buffer path;
// dominant-baseline="central" is not well supported in IE. // dominant-baseline="central" is not well supported in IE.
// so we add a 0.35 offset to the dy of the tspans // so we add a 0.35 offset to the dy of the tspans
@@ -494,7 +499,8 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
path.add("</tspan>"); path.add("</tspan>");
} }
path.add("</text>"); path.add("</text>");
po.second.push_back(path); po->second.push_back(path);
}
} }
} }
} }
@@ -635,3 +641,31 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) {
Logger::Warning("No building storeys encountered, output might be invalid or missing"); Logger::Warning("No building storeys encountered, output might be invalid or missing");
} }
} }
void SvgSerializer::setSectionHeight(double h, IfcUtil::IfcBaseEntity* storey) {
section_heights.emplace();
section_heights->push_back({ h, storey });
}
void SvgSerializer::setSectionHeightsFromStoreys(double offset) {
section_heights.emplace();
auto storeys = file->instances_by_type("IfcBuildingStorey");
const double lu = file->getUnit("LENGTHUNIT").second;
if (storeys && storeys->size() > 0) {
for (auto& s : *storeys) {
auto attr_value = ((IfcUtil::IfcBaseEntity*)s)->get("Elevation");
if (!attr_value->isNull()) {
double elev;
try {
elev = *attr_value;
} catch (std::exception& e) {
Logger::Error(e);
continue;
}
section_heights->push_back({ elev * lu + offset , (IfcUtil::IfcBaseEntity*)s });
}
}
} else {
section_heights->push_back({ std::numeric_limits<double>::quiet_NaN(), nullptr });
}
}
+3 -2
View File
@@ -64,7 +64,7 @@ public:
protected: protected:
std::ofstream svg_file; std::ofstream svg_file;
double xmin, ymin, xmax, ymax, width, height; double xmin, ymin, xmax, ymax, width, height;
boost::optional<double> section_height; boost::optional<std::vector<std::pair<double, IfcUtil::IfcBaseEntity*>>> section_heights;
bool rescale, print_space_names_, print_space_areas_; bool rescale, print_space_names_, print_space_areas_;
std::multimap<IfcUtil::IfcBaseEntity*, path_object, storey_sorter> paths; std::multimap<IfcUtil::IfcBaseEntity*, path_object, storey_sorter> paths;
std::vector< boost::shared_ptr<util::string_buffer::float_item> > xcoords; std::vector< boost::shared_ptr<util::string_buffer::float_item> > xcoords;
@@ -99,7 +99,8 @@ public:
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
void setFile(IfcParse::IfcFile* f); void setFile(IfcParse::IfcFile* f);
void setBoundingRectangle(double width, double height); void setBoundingRectangle(double width, double height);
void setSectionHeight(double h, IfcUtil::IfcBaseEntity* storey = 0) { section_height = h; storey_ = storey; } void setSectionHeight(double h, IfcUtil::IfcBaseEntity* storey = 0);
void setSectionHeightsFromStoreys(double offset=1.);
void setPrintSpaceNames(bool b) { print_space_names_ = b; } void setPrintSpaceNames(bool b) { print_space_names_ = b; }
void setPrintSpaceAreas(bool b) { print_space_areas_ = b; } void setPrintSpaceAreas(bool b) { print_space_areas_ = b; }
std::string nameElement(const IfcGeom::Element<real_t>* elem); std::string nameElement(const IfcGeom::Element<real_t>* elem);