From c3d4ce8f51e10fd71f2bc3b91560d6752535d4db Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 31 Dec 2020 11:31:05 +0100 Subject: [PATCH] Store drawing location in SVG --- src/serializers/SvgSerializer.cpp | 97 +++++++++++++++++++++++-------- src/serializers/SvgSerializer.h | 15 ++++- 2 files changed, 85 insertions(+), 27 deletions(-) diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 1d2381436d..998d68c577 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -292,16 +293,18 @@ void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire) { p.second.push_back(path); } -SvgSerializer::path_object& SvgSerializer::start_path(IfcUtil::IfcBaseEntity* storey, const std::string& id) { +SvgSerializer::path_object& SvgSerializer::start_path(const gp_Pln& pln, IfcUtil::IfcBaseEntity* storey, const std::string& id) { auto key = std::make_pair(std::make_pair(storey, ""), path_object()); SvgSerializer::path_object& p = paths.insert(key)->second; + drawing_metadata[key.first].pln_3d = pln; p.first = id; return p; } -SvgSerializer::path_object& SvgSerializer::start_path(const std::string& drawing_name, const std::string& id) { +SvgSerializer::path_object& SvgSerializer::start_path(const gp_Pln& pln, 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; + drawing_metadata[key.first].pln_3d = pln; p.first = id; return p; } @@ -633,6 +636,15 @@ void SvgSerializer::write(const geometry_data& data) { cut_z = zmin + 1.; } + gp_Pln pln; + if (variant.which() < 2) { + pln = gp_Pln(gp_Pnt(0, 0, cut_z), gp::DZ()); + } + else { + const auto& section = boost::get(variant); + pln = section.plane; + } + gp_Vec bbmin(x1, y1, zmin); gp_Vec bbmax(x2, y2, zmax); auto bbdif = bbmax - bbmin; @@ -641,9 +653,9 @@ void SvgSerializer::write(const geometry_data& data) { if (data.product->declaration().is("IfcAnnotation") && (proj.Magnitude() > 1.e-5) && zmin >= range.first && zmin <= range.second) { if (po == nullptr) { if (storey) { - po = &start_path(storey, data.svg_name); + po = &start_path(pln, storey, data.svg_name); } else { - po = &start_path(drawing_name, data.svg_name); + po = &start_path(pln, drawing_name, data.svg_name); } } @@ -717,20 +729,12 @@ void SvgSerializer::write(const geometry_data& data) { if (po == nullptr) { if (storey) { - po = &start_path(storey, data.svg_name); + po = &start_path(pln, storey, data.svg_name); } else { - po = &start_path(drawing_name, data.svg_name); + po = &start_path(pln, drawing_name, data.svg_name); } } - // Create a horizontal cross section 1 meter above the bottom point of the shape - gp_Pln pln; - if (variant.which() < 2) { - pln = gp_Pln(gp_Pnt(0, 0, cut_z), gp::DZ()); - } else { - const auto& section = boost::get(variant); - pln = section.plane; - } TopoDS_Shape result = BRepAlgoAPI_Section(subshape, pln); if (variant.which() == 2) { @@ -889,7 +893,10 @@ void SvgSerializer::setBoundingRectangle(double width, double height) { this->rescale = true; } -void SvgSerializer::resize() { +std::array, 3> SvgSerializer::resize() { + // identity matrix; + std::array, 3> m = {{ {{1,0,0}},{{0,1,0}},{{0,0,1}} }}; + if (rescale) { // Scale the resulting image to a bounding rectangle specified by command line arguments const double dx = xmax - xmin; @@ -918,6 +925,8 @@ void SvgSerializer::resize() { cy = ymin * sc; } + m = {{ {{sc,0,-cx}},{{0,sc,-cy}},{{0,0,1}} }}; + float_item_list::const_iterator it; for (it = xcoords.begin() + xcoords_begin; it != xcoords.end(); ++it, ++xcoords_begin) { double& v = (*it)->value(); @@ -931,6 +940,8 @@ void SvgSerializer::resize() { (*it)->value() *= sc; } } + + return m; } void SvgSerializer::resetScale() { @@ -944,7 +955,12 @@ void SvgSerializer::resetScale() { } void SvgSerializer::finalize() { - resize(); + auto m = resize(); + + // Update the paper space scale matrices + for (auto& p : paths) { + drawing_metadata[p.first].matrix_3 = m; + } if (!deferred_section_data_.is_initialized() && (auto_section_ || auto_elevation_)) { deferred_section_data_.emplace(); @@ -987,21 +1003,20 @@ void SvgSerializer::finalize() { { gp_Pln pln(gp_Ax3( gp_Pnt((xmin + xmax) / 2., -(ymax + 1.e-1), 0.), - gp_Dir(0, -1, 0), + gp_Dir(0, 1, 0), gp_Dir(1, 0, 0))); deferred_section_data_->push_back(vertical_section{ pln , "Elevation North", true }); } { gp_Pln pln(gp_Ax3( gp_Pnt(xmin - 1.e-1, (ymin + ymax) / -2., 0.), - gp_Dir(-1, 0, 0), - gp_Dir(0, -1, 0))); + gp_Dir(1, 0, 0), + gp_Dir(0, 1, 0))); deferred_section_data_->push_back(vertical_section{ pln , "Elevation West", true }); } } resetScale(); - if (deferred_section_data_ && deferred_section_data_->size() && element_buffer_.size()) { @@ -1059,7 +1074,7 @@ void SvgSerializer::finalize() { exp.Init(hlr_compound, TopAbs_EDGE); BRep_Builder B; - auto& po = start_path(drawing_name, "class=\"projection\""); + auto& po = start_path(section.plane, drawing_name, "class=\"projection\""); for (; exp.More(); exp.Next()) { TopoDS_Wire w; B.MakeWire(w); @@ -1070,7 +1085,11 @@ void SvgSerializer::finalize() { } } - resize(); + auto m3 = resize(); + + auto k = std::make_pair(nullptr, drawing_name); + drawing_metadata[k].matrix_3 = m3; + resetScale(); if (use_hlr) { @@ -1089,11 +1108,11 @@ void SvgSerializer::finalize() { } std::ostringstream oss; if (it->first.first) { - svg_file << " first.first) << ">\n"; + svg_file << " first.first) << " " << writeMetadata(drawing_metadata[it->first]) << ">\n"; } else { auto n = it->first.second; IfcUtil::escape_xml(n); - svg_file << " \n"; + svg_file << " first]) << ">\n"; } } svg_file << " second.first << ">\n"; @@ -1285,3 +1304,33 @@ void SvgSerializer::setSectionHeightsFromStoreys(double offset) { section_data_->push_back(horizontal_plan_at_element{}); } } + +namespace { + std::string array_to_string(double v) { + return std::to_string(v); + } + + template + std::string array_to_string(const T& v) { + return "[" + std::accumulate( + ++v.begin(), v.end(), + array_to_string(v.front()), + [](const std::string& accum, auto const & item) { + return accum + "," + array_to_string(item); + }) + "]"; + } +} + +std::string SvgSerializer::writeMetadata(const drawing_meta& m) { + gp_Trsf trsf; + trsf.SetTransformation(m.pln_3d.Position(), gp::XOY()); + auto m43 = IfcGeom::Matrix(IfcGeom::ElementSettings(IfcGeom::IteratorSettings(), 1., ""), trsf).data(); + std::array, 4> m4 = {{ + {{ (double)m43[0], (double)m43[3], (double)m43[6], (double)m43[9] }}, + {{ (double)m43[1], (double)m43[4], (double)m43[7], (double)m43[10] }}, + {{ (double)m43[2], (double)m43[5], (double)m43[8], (double)m43[11] }}, + {{ 0, 0, 0, 1 }} + }}; + return namespace_prefix_ + "plane=\""+ array_to_string(m4) +"\" " + + namespace_prefix_ + "matrix3=\"" + array_to_string(m.matrix_3) + "\""; +} \ No newline at end of file diff --git a/src/serializers/SvgSerializer.h b/src/serializers/SvgSerializer.h index f483a69a47..73555e125d 100644 --- a/src/serializers/SvgSerializer.h +++ b/src/serializers/SvgSerializer.h @@ -107,6 +107,11 @@ struct geometry_data { std::string ifc_name, svg_name; }; +struct drawing_meta { + gp_Pln pln_3d; + std::array, 3> matrix_3; +}; + class SvgSerializer : public GeometrySerializer { public: typedef std::pair > path_object; @@ -126,6 +131,7 @@ protected: IfcParse::IfcFile* file; IfcUtil::IfcBaseEntity* storey_; std::multimap paths; + std::map drawing_metadata; float_item_list xcoords, ycoords, radii; size_t xcoords_begin, ycoords_begin, radii_begin; @@ -171,8 +177,8 @@ public: void write(const IfcGeom::BRepElement* 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); - path_object& start_path(const std::string& drawing_name, const std::string& id); + path_object& start_path(const gp_Pln& p, IfcUtil::IfcBaseEntity* storey, const std::string& id); + path_object& start_path(const gp_Pln& p, const std::string& drawing_name, const std::string& id); bool isTesselated() const { return false; } void finalize(); void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} @@ -184,7 +190,7 @@ public: void setPrintSpaceAreas(bool b) { print_space_areas_ = b; } void setDrawDoorArcs(bool b) { draw_door_arcs_ = b; } - void resize(); + std::array, 3> resize(); void resetScale(); void setSectionRef(const boost::optional& s) { @@ -221,6 +227,9 @@ public: return GeometrySerializer::object_id(o); } } + +protected: + std::string writeMetadata(const drawing_meta& m); }; #endif