support for section and elevation references as annotation lines

This commit is contained in:
Thomas Krijnen
2020-09-20 15:08:52 +02:00
parent 0fba3bde2d
commit 3e9210d29f
4 changed files with 374 additions and 93 deletions
+11
View File
@@ -343,6 +343,7 @@ int main(int argc, char** argv) {
short precision;
double section_height;
std::string svg_scale;
std::string section_ref, elevation_ref;
po::options_description serializer_options("Serialization options");
serializer_options.add_options()
@@ -357,6 +358,10 @@ int main(int argc, char** argv) {
("scale", po::value<std::string>(&svg_scale),
"Interprets SVG bounds in mm, centers layout and draw elements to scale. "
"Only used when converting to SVG. Example 1:100.")
("section-ref", po::value<std::string>(&section_ref),
"Element at which vertical cross sections should be created")
("elevation-ref", po::value<std::string>(&elevation_ref),
"Element at which vertical elevations should be created")
("door-arcs", "Draw door openings arcs for IfcDoor elements")
("section-height", po::value<double>(&section_height),
"Specifies the cut section height for SVG 2D geometry.")
@@ -908,6 +913,12 @@ int main(int argc, char** argv) {
return EXIT_FAILURE;
}
}
if (vmap.count("section-ref")) {
static_cast<SvgSerializer*>(serializer.get())->setSectionRef(section_ref);
}
if (vmap.count("elevation-ref")) {
static_cast<SvgSerializer*>(serializer.get())->setElevationRef(elevation_ref);
}
}
if (convert_back_units) {
+286 -82
View File
@@ -291,68 +291,154 @@ void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire) {
}
SvgSerializer::path_object& SvgSerializer::start_path(IfcUtil::IfcBaseEntity* storey, const std::string& id) {
SvgSerializer::path_object& p = paths.insert(std::make_pair(storey, path_object()))->second;
auto key = std::make_pair(std::make_pair(storey, ""), path_object());
SvgSerializer::path_object& p = paths.insert(key)->second;
p.first = id;
return p;
}
void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
{
std::vector<std::pair<std::pair<double, double>, IfcUtil::IfcBaseEntity*>> section_heights_storage;
const std::vector<std::pair<std::pair<double, double>, IfcUtil::IfcBaseEntity*>>* section_heights_used = &section_heights_storage;
SvgSerializer::path_object& SvgSerializer::start_path(const std::string& drawing_name, const std::string& id) {
auto key = std::make_pair(std::make_pair(nullptr, drawing_name), path_object());
SvgSerializer::path_object& p = paths.insert(key)->second;
p.first = id;
return p;
}
if (section_heights) {
section_heights_used = section_heights.get_ptr();
} else {
namespace {
boost::optional<std::pair<IfcUtil::IfcBaseEntity*, double>> storey_elevation_from_element(const IfcGeom::BRepElement<real_t>* o) {
for (const auto& p : o->parents()) {
if (p->type() == "IfcBuildingStorey") {
try {
const IfcGeom::ElementSettings& settings = o->geometry().settings();
double e = *p->product()->get("Elevation");
double storey_elevation = e * settings.unit_magnitude();
section_heights_storage.push_back({ {storey_elevation, +1.} , p->product() });
return std::make_pair(p->product(), storey_elevation);
} catch (...) {
continue;
}
break;
}
}
return boost::none;
}
if (section_heights_storage.empty()) {
Logger::Warning("No global section height and unable to determine building storey for:", o->product());
boost::optional<TopoDS_Edge> edge_from_compound(TopoDS_Shape& compound) {
TopoDS_Iterator it(compound);
if (it.More()) {
TopoDS_Shape wire = it.Value();
it.Next();
if (!it.More() && wire.ShapeType() == TopAbs_WIRE) {
TopoDS_Iterator jt(wire);
if (jt.More()) {
TopoDS_Shape edge = jt.Value();
jt.Next();
if (!jt.More() && edge.ShapeType() == TopAbs_EDGE) {
return TopoDS::Edge(edge);
}
}
}
}
return boost::none;
}
}
void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* brep_obj) {
boost::optional<std::string> object_type;
if (!brep_obj->product()->get("ObjectType")->isNull()) {
object_type = static_cast<std::string>(*brep_obj->product()->get("ObjectType"));
}
TopoDS_Shape compound_local = brep_obj->geometry().as_compound();
const gp_Trsf& trsf = brep_obj->transformation().data();
const bool is_section = (section_ref_ && object_type && *section_ref_ == *object_type);
const bool is_elevation = (elevation_ref_ && object_type && *elevation_ref_ == *object_type);
if (is_section || is_elevation) {
auto e = edge_from_compound(compound_local);
if (e) {
TopoDS_Edge global_edge = TopoDS::Edge(e->Moved(trsf));
double u0, u1;
auto crv = BRep_Tool::Curve(global_edge, u0, u1);
if (crv->DynamicType() == STANDARD_TYPE(Geom_Line)) {
gp_Pnt P;
gp_Vec V;
crv->D1((u0 + u1) / 2., P, V);
auto N = gp::DZ().Crossed(V);
gp_Pln pln(gp_Ax3(P, N, V));
if (!deferred_section_data_) {
deferred_section_data_.emplace();
}
std::string name = brep_obj->name();
if (name.empty()) {
name = boost::lexical_cast<std::string>(brep_obj->id());
}
if (is_section) {
deferred_section_data_->push_back(vertical_section{ pln , "Section " + name, false });
}
if (is_elevation) {
deferred_section_data_->push_back(vertical_section{ pln , "Elevation " + name, true });
}
}
}
return;
}
auto p = storey_elevation_from_element(brep_obj);
IfcUtil::IfcBaseEntity* storey = p ? p->first : nullptr;
double elev = p ? p->second : std::numeric_limits<double>::quiet_NaN();
geometry_data data{ compound_local, trsf, brep_obj->product(), storey, elev, brep_obj->name(), nameElement(storey, brep_obj) };
if (buffer_elements_) {
element_buffer_.push_back(data);
}
write(data);
}
void SvgSerializer::write(const geometry_data& data) {
std::vector<section_data> section_heights_storage;
const std::vector<section_data>* section_heights_used = &section_heights_storage;
if (section_data_) {
section_heights_used = section_data_.get_ptr();
} else {
if (data.storey) {
section_heights_storage.push_back(horizontal_plan{ data.storey, data.storey_elevation, +1. });
} else {
Logger::Warning("No global section height and unable to determine building storey for:", data.product);
return;
}
}
TopoDS_Shape compound_local = o->geometry().as_compound();
const gp_Trsf& trsf = o->transformation().data();
BRepBuilderAPI_Transform make_transform_global(compound_local, trsf, true);
BRepBuilderAPI_Transform make_transform_global(data.compound_local, data.trsf, true);
make_transform_global.Build();
// (When determinant < 0, copy is implied and the input is not mutated.)
auto compound = make_transform_global.Shape();
auto compound_unmirrored = make_transform_global.Shape();
// SVG has a coordinate system with the origin in the *upper*-left corner
// therefore we mirror the shape along the XZ-plane.
gp_Trsf trsf_mirror;
trsf_mirror.SetMirror(gp_Ax2(gp::Origin(), gp::DY()));
BRepBuilderAPI_Transform make_transform_mirror(compound, trsf_mirror, true);
BRepBuilderAPI_Transform make_transform_mirror(compound_unmirrored, trsf_mirror, true);
make_transform_mirror.Build();
// (When determinant < 0, copy is implied and the input is not mutated.)
compound = make_transform_mirror.Shape();
auto compound = make_transform_mirror.Shape();
TopoDS_Wire annotation;
if (draw_door_arcs_ && o->product()->declaration().is("IfcDoor")) {
if (draw_door_arcs_ && data.product->declaration().is("IfcDoor")) {
boost::optional<std::string> operation_type;
try {
IfcEntityList::ptr rels;
if (o->product()->declaration().schema()->name() == "IFC2X3") {
rels = o->product()->get_inverse("IsDefinedBy");
if (data.product->declaration().schema()->name() == "IFC2X3") {
rels = data.product->get_inverse("IsDefinedBy");
} else {
// Damn you, IFC
rels = o->product()->get_inverse("IsTypedBy");
rels = data.product->get_inverse("IsTypedBy");
}
for (auto& rel : *rels) {
if (rel->declaration().name() == "IfcRelDefinesByType") {
@@ -372,7 +458,7 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
const bool is_left = *operation_type == "SINGLE_SWING_LEFT";
Bnd_Box bb;
BRepBndLib::Add(compound_local, bb);
BRepBndLib::Add(data.compound_local, bb);
if (bb.IsVoid()) {
return;
@@ -405,9 +491,9 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
make_transform_mirror.Perform(edge_global, true);
auto edge_global_mirrored = make_transform_mirror.Shape();
center.Transform(trsf);
p1.Transform(trsf);
p2.Transform(trsf);
center.Transform(data.trsf);
p1.Transform(data.trsf);
p2.Transform(data.trsf);
center.Transform(trsf_mirror);
p1.Transform(trsf_mirror);
p2.Transform(trsf_mirror);
@@ -431,20 +517,44 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
bool emitted = false;
for (auto sit = section_heights_used->begin(); sit != section_heights_used->end(); ++sit) {
const auto& pair = *sit;
const auto& variant = *sit;
// Elev + offset
auto cut_z = pair.first.first + pair.first.second;
double cut_z = std::numeric_limits<double>::infinity();
// Elev .. Elev(next)
std::pair<double, double> range{ pair.first.first, std::numeric_limits<double>::infinity() };
if (sit == section_heights_used->begin()) {
range.first = -range.second;
std::pair<double, double> range;
gp_Vec projection_direction;
IfcUtil::IfcBaseEntity* storey = nullptr;
std::string drawing_name;
bool use_hlr = false;
// @todo use visitor
// horizontal_plan, horizontal_plan_at_element, vertical_section
if (variant.which() == 0) {
const auto& plan = boost::get<horizontal_plan>(variant);
storey = plan.storey;
cut_z = plan.elevation + plan.offset;
range = { plan.elevation, plan.next_elevation };
if (sit == section_heights_used->begin()) {
range.first = -std::numeric_limits<double>::infinity();
}
projection_direction = gp::DZ();
} else if (variant.which() == 1) {
projection_direction = gp::DZ();
} else if (variant.which() == 2) {
const auto& section = boost::get<vertical_section>(variant);
projection_direction = section.plane.Axis().Direction();
drawing_name = section.name;
use_hlr = section.with_projection;
}
if (use_hlr && hlr) {
hlr->Add(compound_unmirrored);
}
if (sit + 1 != section_heights_used->end()) {
range.second = (sit + 1)->first.first;
}
auto storey = pair.second;
TopoDS_Iterator it(compound);
@@ -456,7 +566,7 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
for (; it.More(); it.Next()) {
const TopoDS_Shape& subshape = it.Value();
Bnd_Box bb;
try {
BRepBndLib::Add(it.Value(), bb);
@@ -469,19 +579,28 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
double x1, y1, zmin, x2, y2, zmax;
bb.Get(x1, y1, zmin, x2, y2, zmax);
// Determine slicing plane z coordinate, priority:
// 1) explicitly set global section height
// 2) containing building storey elevation + 1m
// 3) zmin (from geometry bounding box) + 1m
if (std::isnan(cut_z)) {
if (variant.which() == 1) {
cut_z = zmin + 1.;
}
if (o->type() == "IfcAnnotation" && ((zmax - zmin) < 1.e-5) && zmin >= range.first && zmin <= range.second) {
gp_Vec bbmin(x1, y1, zmin);
gp_Vec bbmax(x2, y2, zmax);
auto bbdif = bbmax - bbmin;
auto proj = projection_direction ^ bbdif ^ projection_direction;
if (data.product->declaration().is("IfcAnnotation") && (proj.Magnitude() > 1.e-5) && zmin >= range.first && zmin <= range.second) {
if (po == nullptr) {
po = &start_path(storey, nameElement(storey, o));
if (storey) {
po = &start_path(storey, data.svg_name);
} else {
po = &start_path(drawing_name, data.svg_name);
}
}
TopExp_Explorer exp(subshape, TopAbs_EDGE, TopAbs_FACE);
@@ -499,6 +618,9 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
B.Add(W, e);
write(*po, W);
util::string_buffer path;
// dominant-baseline="central" is not well supported in IE.
// so we add a 0.35 offset to the dy of the tspans
@@ -543,18 +665,32 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
}
// No intersection with bounding box, fail early
if (zmin > cut_z || zmax < cut_z) continue;
if (variant.which() < 2) {
if (zmin > cut_z || zmax < cut_z) continue;
}
emitted = true;
if (po == nullptr) {
po = &start_path(storey, nameElement(storey, o));
po = &start_path(storey, data.svg_name);
}
// 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());
gp_Pln pln;
if (variant.which() < 2) {
pln = gp_Pln(gp_Pnt(0, 0, cut_z), gp::DZ());
} else {
const auto& section = boost::get<vertical_section>(variant);
pln = section.plane;
}
TopoDS_Shape result = BRepAlgoAPI_Section(subshape, pln);
if (variant.which() == 2) {
gp_Trsf trsf;
trsf.SetTransformation(gp::XOY(), pln.Position());
result.Move(trsf);
}
Handle(TopTools_HSequenceOfShape) edges = new TopTools_HSequenceOfShape();
Handle(TopTools_HSequenceOfShape) wires = new TopTools_HSequenceOfShape();
{
@@ -569,7 +705,7 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
for (int i = 1; i <= wires->Length(); ++i) {
const TopoDS_Wire& wire = TopoDS::Wire(wires->Value(i));
if (wire.Closed() && (print_space_names_ || print_space_areas_) && o->type() == "IfcSpace") {
if (wire.Closed() && (print_space_names_ || print_space_areas_) && data.product->declaration().is("IfcSpace")) {
// we explicitly specify the surface here, to later on
// simplify the projection from {x,y,z} to {u, v} because
// we know we can simply discard z.
@@ -636,10 +772,10 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
if (center_point) {
std::vector<std::string> labels;
if (print_space_names_) {
labels.push_back(o->name());
labels.push_back(data.ifc_name);
}
if (print_space_names_ && o->type() == "IfcSpace") {
auto attr = o->product()->get("LongName");
if (print_space_names_ && data.product->declaration().is("IfcSpace")) {
auto attr = data.product->get("LongName");
if (!attr->isNull()) {
std::string long_name = *attr;
if (!long_name.empty()) {
@@ -689,7 +825,7 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
}
if (!emitted) {
Logger::Warning("Element not written to SVG due to section heights", o->product());
Logger::Warning("Element not written to SVG due to section heights", data.product);
}
}
@@ -699,8 +835,7 @@ void SvgSerializer::setBoundingRectangle(double width, double height) {
this->rescale = true;
}
void SvgSerializer::finalize() {
void SvgSerializer::resize() {
if (rescale) {
// Scale the resulting image to a bounding rectangle specified by command line arguments
const double dx = xmax - xmin;
@@ -712,40 +847,107 @@ void SvgSerializer::finalize() {
cx = (xmax + xmin) / 2. * sc - width / 2.;
cy = (ymax + ymin) / 2. * sc - height / 2.;
} else {
if (dx / width > dy / height) {
sc = width / dx;
if (calculated_scale_) {
sc = *calculated_scale_;
} else {
sc = height / dy;
if (dx / width > dy / height) {
sc = width / dx;
} else {
sc = height / dy;
}
calculated_scale_ = sc;
}
cx = xmin * sc;
cy = ymin * sc;
}
{std::vector< boost::shared_ptr<util::string_buffer::float_item> >::const_iterator it;
for (it = xcoords.begin(); it != xcoords.end(); ++it) {
float_item_list::const_iterator it;
for (it = xcoords.begin() + xcoords_begin; it != xcoords.end(); ++it, ++xcoords_begin) {
double& v = (*it)->value();
v = v * sc - cx;
}
for (it = ycoords.begin(); it != ycoords.end(); ++it) {
for (it = ycoords.begin() + ycoords_begin; it != ycoords.end(); ++it, ++ycoords_begin) {
double& v = (*it)->value();
v = v * sc - cy;
}
for (it = radii.begin(); it != radii.end(); ++it) {
for (it = radii.begin() + radii_begin; it != radii.end(); ++it, ++radii_begin) {
(*it)->value() *= sc;
}}
}
}
std::multimap<IfcUtil::IfcBaseEntity*, path_object>::const_iterator it;
// reset the bounding box, as a subsequent drawing (elevation, section) will be centered, but use the same scale.
xmin = +std::numeric_limits<double>::infinity();
ymin = +std::numeric_limits<double>::infinity();
xmax = -std::numeric_limits<double>::infinity();
ymax = -std::numeric_limits<double>::infinity();
}
IfcUtil::IfcBaseEntity* previous = 0;
bool first = true;
void SvgSerializer::finalize() {
resize();
if (deferred_section_data_ && deferred_section_data_->size() && element_buffer_.size()) {
for (auto& sd : *deferred_section_data_) {
bool use_hlr = false;
std::string drawing_name;
if (sd.which() == 2) {
const auto& section = boost::get<vertical_section>(sd);
use_hlr = section.with_projection;
drawing_name = section.name;
}
if (use_hlr) {
hlr = new HLRBRep_Algo;
}
*section_data_ = { sd };
for (auto& e : element_buffer_) {
write(e);
}
if (use_hlr) {
const auto& section = boost::get<vertical_section>(sd);
gp_Ax2 transform = section.plane.Position().Ax2();
HLRAlgo_Projector projector(transform);
hlr->Projector(projector);
hlr->Update();
hlr->Hide();
HLRBRep_HLRToShape hlr_shapes(hlr);
auto compound = hlr_shapes.VCompound();
TopExp_Explorer exp(compound, TopAbs_EDGE);
BRep_Builder B;
auto& po = start_path(drawing_name, "class=\"projection\"");
for (; exp.More(); exp.Next()) {
TopoDS_Wire w;
B.MakeWire(w);
B.Add(w, exp.Current());
write(po, w);
}
}
resize();
if (use_hlr) {
hlr.Nullify();
}
}
}
std::multimap<drawing_key, path_object, storey_sorter>::const_iterator it;
boost::optional<drawing_key> previous;
for (it = paths.begin(); it != paths.end(); ++it) {
if (it->first != previous || first) {
if (!first) {
if (!previous || it->first != *previous) {
if (previous) {
svg_file << " </g>\n";
}
std::ostringstream oss;
svg_file << " <g " << nameElement(it->first) << ">\n";
if (it->first.first) {
svg_file << " <g " << nameElement(it->first.first) << ">\n";
} else {
svg_file << " <g id=\"" << it->first.second << "\" class=\"section\">\n";
}
}
svg_file << " <g " << it->second.first << ">\n";
std::vector<util::string_buffer>::const_iterator jt;
@@ -754,10 +956,9 @@ void SvgSerializer::finalize() {
}
svg_file << " </g>\n";
previous = it->first;
first = false;
}
if (!first) {
if (previous) {
svg_file << " </g>\n";
}
svg_file << "</svg>" << std::endl;
@@ -803,11 +1004,11 @@ void SvgSerializer::writeHeader() {
namespace {
std::string nameElement_(const std::vector<std::pair<std::string, std::string> >& attrs) {
std::ostringstream oss;
for (auto& a : attrs) {
// @todo while we're at it might as well implement escaping
oss << a.first << "=\"" << a.second << "\" ";
}
return oss.str();
for (auto& a : attrs) {
// @todo while we're at it might as well implement escaping
oss << a.first << "=\"" << a.second << "\" ";
}
return oss.str();
}
}
@@ -817,7 +1018,7 @@ std::string SvgSerializer::nameElement(const IfcUtil::IfcBaseEntity* storey, con
{"class", elem->type()},
{"data-name", elem->name()},
{"data-guid", elem->guid()}
});
});
}
std::string SvgSerializer::idElement(const IfcUtil::IfcBaseEntity* elem) {
@@ -843,11 +1044,11 @@ std::string SvgSerializer::nameElement(const IfcUtil::IfcBaseEntity* elem) {
}
return nameElement_({
{"id", idElement(elem)},
{"class", entity},
{"id", idElement(elem)},
{"class", entity},
{"data-name", ifc_name},
{"data-guid", *elem->get("GlobalId")}
});
});
}
void SvgSerializer::setFile(IfcParse::IfcFile* f) {
@@ -855,9 +1056,9 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) {
auto storeys = f->instances_by_type("IfcBuildingStorey");
if (!storeys || storeys->size() == 0) {
IfcGeom::Kernel kernel(f);
std::vector<const IfcParse::declaration*> to_derive_from;
to_derive_from.push_back(f->schema()->declaration_by_name("IfcBuilding"));
to_derive_from.push_back(f->schema()->declaration_by_name("IfcSite"));
@@ -883,13 +1084,13 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) {
}
void SvgSerializer::setSectionHeight(double h, IfcUtil::IfcBaseEntity* storey) {
section_heights.emplace();
section_heights->push_back({ {h, 0.}, storey });
section_data_.emplace();
section_data_->push_back(horizontal_plan{ storey, h, 0., std::numeric_limits<double>::infinity() });
}
void SvgSerializer::setSectionHeightsFromStoreys(double offset) {
with_section_heights_from_storey_ = true;
section_heights.emplace();
section_data_.emplace();
auto storeys = file->instances_by_type("IfcBuildingStorey");
const double lu = file->getUnit("LENGTHUNIT").second;
if (storeys && storeys->size() > 0) {
@@ -903,10 +1104,13 @@ void SvgSerializer::setSectionHeightsFromStoreys(double offset) {
Logger::Error(e);
continue;
}
section_heights->push_back({ {elev * lu, offset} , (IfcUtil::IfcBaseEntity*)s });
if (!section_data_->empty()) {
boost::get<horizontal_plan>(section_data_->back()).next_elevation = elev * lu;
}
section_data_->push_back(horizontal_plan{ (IfcUtil::IfcBaseEntity*)s, elev * lu, offset, std::numeric_limits<double>::infinity() });
}
}
} else {
section_heights->push_back({ {std::numeric_limits<double>::quiet_NaN(), 0.}, nullptr });
section_data_->push_back(horizontal_plan_at_element{});
}
}
+76 -10
View File
@@ -27,12 +27,28 @@
#include "../ifcparse/utils.h"
#include <HLRBRep_Algo.hxx>
#include <HLRBRep_HLRToShape.hxx>
#include <sstream>
#include <string>
#include <limits>
typedef std::pair<IfcUtil::IfcBaseEntity*, std::string> drawing_key;
struct storey_sorter {
bool operator()(IfcUtil::IfcBaseEntity* a, IfcUtil::IfcBaseEntity* b) const {
bool operator()(const drawing_key& ad, const drawing_key& bd) const {
if (ad.first == nullptr && bd.first != nullptr) {
return true;
} else if (bd.first == nullptr && ad.first != nullptr) {
return true;
} else if (ad.first == nullptr && bd.first == nullptr) {
return std::less<std::string>()(ad.second, bd.second);
}
auto a = ad.first;
auto b = bd.first;
const bool a_is_storey = a->declaration().is("IfcBuildingStorey");
const bool b_is_storey = b->declaration().is("IfcBuildingStorey");
if (a_is_storey && b_is_storey) {
@@ -66,21 +82,52 @@ struct storey_sorter {
}
};
struct horizontal_plan {
IfcUtil::IfcBaseEntity* storey;
double elevation, offset, next_elevation;
};
struct horizontal_plan_at_element {};
struct vertical_section {
gp_Pln plane;
std::string name;
bool with_projection;
};
typedef boost::variant<horizontal_plan, horizontal_plan_at_element, vertical_section> section_data;
struct geometry_data {
TopoDS_Shape compound_local;
gp_Trsf trsf;
IfcUtil::IfcBaseEntity* product;
IfcUtil::IfcBaseEntity* storey;
double storey_elevation;
std::string ifc_name, svg_name;
};
class SvgSerializer : public GeometrySerializer {
public:
typedef std::pair<std::string, std::vector<util::string_buffer> > path_object;
typedef std::vector< boost::shared_ptr<util::string_buffer::float_item> > float_item_list;
protected:
std::ofstream svg_file;
double xmin, ymin, xmax, ymax, width, height;
boost::optional<std::vector<std::pair<std::pair<double, double>, IfcUtil::IfcBaseEntity*>>> section_heights;
boost::optional<double> scale_;
bool rescale, print_space_names_, print_space_areas_, draw_door_arcs_, with_section_heights_from_storey_;
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> > ycoords;
std::vector< boost::shared_ptr<util::string_buffer::float_item> > radii;
boost::optional<std::vector<section_data>> section_data_;
boost::optional<std::vector<section_data>> deferred_section_data_;
boost::optional<double> scale_, calculated_scale_;
bool rescale, print_space_names_, print_space_areas_, draw_door_arcs_, with_section_heights_from_storey_, buffer_elements_;
std::multimap<drawing_key, path_object, storey_sorter> paths;
float_item_list xcoords, ycoords, radii;
size_t xcoords_begin, ycoords_begin, radii_begin;
boost::optional<std::string> section_ref_, elevation_ref_;
IfcParse::IfcFile* file;
IfcUtil::IfcBaseEntity* storey_;
std::list<geometry_data> element_buffer_;
Handle(HLRBRep_Algo) hlr;
public:
SvgSerializer(const std::string& out_filename, const SerializerSettings& settings)
: GeometrySerializer(settings)
@@ -94,8 +141,12 @@ public:
, print_space_names_(false)
, print_space_areas_(false)
, draw_door_arcs_(false)
, buffer_elements_(false)
, file(0)
, storey_(0)
, xcoords_begin(0)
, ycoords_begin(0)
, radii_begin(0)
{}
void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
@@ -106,8 +157,10 @@ public:
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
void write(const IfcGeom::BRepElement<real_t>* o);
void write(path_object& p, const TopoDS_Wire& wire);
void write(const geometry_data& data);
path_object& start_path(IfcUtil::IfcBaseEntity* storey, const std::string& id);
bool isTesselated() const { return false; }
path_object& start_path(const std::string& drawing_name, const std::string& id);
bool isTesselated() const { return false; }
void finalize();
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
void setFile(IfcParse::IfcFile* f);
@@ -117,12 +170,25 @@ public:
void setPrintSpaceNames(bool b) { print_space_names_ = b; }
void setPrintSpaceAreas(bool b) { print_space_areas_ = b; }
void setDrawDoorArcs(bool b) { draw_door_arcs_ = b; }
void resize();
void setSectionRef(const boost::optional<std::string>& s) {
section_ref_ = s;
buffer_elements_ = true;
}
void setElevationRef(const boost::optional<std::string>& s) {
elevation_ref_ = s;
buffer_elements_ = true;
}
void setScale(double s) { scale_ = s; }
std::string nameElement(const IfcUtil::IfcBaseEntity* storey, const IfcGeom::Element<real_t>* elem);
std::string nameElement(const IfcUtil::IfcBaseEntity* elem);
std::string idElement(const IfcUtil::IfcBaseEntity* elem);
std::string object_id(const IfcUtil::IfcBaseEntity* storey, const IfcGeom::Element<real_t>* o) {
return idElement(storey) + "-" + GeometrySerializer::object_id(o);
if (storey) {
return idElement(storey) + "-" + GeometrySerializer::object_id(o);
} else {
return GeometrySerializer::object_id(o);
}
}
};