diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 2191c80e0b..8d0df4356e 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -79,6 +79,7 @@ #include "../ifcparse/IfcGlobalId.h" #include +#include #include "SvgSerializer.h" @@ -422,6 +423,36 @@ namespace { return box_t{ {{x0, y0, z0}}, {{x1, y1, z1}} }; } + + struct string_property { + std::string pset_name, prop_name, value; + }; + + template + void enumerate_string_properties(IfcUtil::IfcBaseEntity* product, It output_it) { + auto rels = product->get_inverse("IsDefinedBy"); + for (auto& rel : *rels) { + if (rel->declaration().is("IfcRelDefinesByProperties")) { + auto pset = (IfcUtil::IfcBaseEntity*) (IfcUtil::IfcBaseClass*) *((IfcUtil::IfcBaseEntity*) rel)->get("RelatingPropertyDefinition"); + std::string pset_name; + if (!pset->get("Name")->isNull()) { + pset_name = *pset->get("Name"); + } + IfcEntityList::ptr props = *pset->get("HasProperties"); + for (auto& prop : *props) { + if (prop->declaration().is("IfcPropertySingleValue")) { + std::string name = *((IfcUtil::IfcBaseEntity*) prop)->get("Name"); + IfcUtil::IfcBaseClass* v = *((IfcUtil::IfcBaseEntity*) prop)->get("NominalValue"); + auto value = v->data().getArgument(0); + if (value->type() == IfcUtil::Argument_STRING) { + std::string v_str = *value; + *output_it++ = string_property{ pset_name, name, v_str }; + } + } + } + } + } + } } void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) { @@ -443,6 +474,9 @@ void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) { // (When determinant < 0, copy is implied and the input is not mutated.) auto compound_unmirrored = make_transform_global.Shape(); + boost::optional scale; + boost::optional> size; + auto e = edge_from_compound(compound_unmirrored); boost::optional pln; if (e) { @@ -457,8 +491,39 @@ void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) { pln = gp_Pln(gp_Ax3(P, N, V)); } } - else if (box_from_compound(compound_local)) { + else if (boost::optional b = box_from_compound(compound_local)) { pln = gp_Pln().Transformed(trsf); + size = std::make_pair( + b->second[0] - b->first[0], + b->second[1] - b->first[1] + ); + } + + std::vector props; + enumerate_string_properties(brep_obj->product(), std::back_inserter(props)); + std::map prop_map; + for (auto& p : props) { + prop_map[p.pset_name + "." + p.prop_name] = p.value; + } + auto pit = prop_map.find("EPset_Drawing.Scale"); + if (pit != prop_map.end()) { + typedef boost::tokenizer> tokenizer; + tokenizer tok{ pit->second }; + auto tokit = tok.begin(); + std::string num, denum; + if (tokit != tok.end()) { + num = *tokit++; + } + tokit++; + if (tokit != tok.end()) { + denum = *tokit++; + } + if (num.size() && denum.size()) { + try { + scale = (float) boost::lexical_cast(num) / boost::lexical_cast(denum); + } + catch (boost::bad_lexical_cast&) {} + } } if (pln) { @@ -477,10 +542,10 @@ void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) { name = boost::lexical_cast(brep_obj->id()); } if (is_section) { - deferred_section_data_->push_back(vertical_section{ *pln , "Section " + name, false }); + deferred_section_data_->push_back(vertical_section{ *pln , "Section " + name, false, scale, size }); } if (is_elevation) { - deferred_section_data_->push_back(vertical_section{ *pln , "Elevation " + name, true }); + deferred_section_data_->push_back(vertical_section{ *pln , "Elevation " + name, true, scale, size }); } } @@ -1233,16 +1298,14 @@ void SvgSerializer::write(const geometry_data& data) { } void SvgSerializer::setBoundingRectangle(double width, double height) { - this->width = width; - this->height = height; - this->rescale = true; + size_ = std::make_pair(width, height); } std::array, 3> SvgSerializer::resize() { // identity matrix; std::array, 3> m = {{ {{1,0,0}},{{0,1,0}},{{0,0,1}} }}; - if (rescale) { + if (size_) { // Scale the resulting image to a bounding rectangle specified by command line arguments const double dx = xmax - xmin; const double dy = ymax - ymin; @@ -1250,19 +1313,19 @@ std::array, 3> SvgSerializer::resize() { double sc, cx, cy; if (scale_) { sc = (*scale_) * 1000; - cx = (xmax + xmin) / 2. * sc - width * center_x_.get_value_or(0.5); - cy = (ymax + ymin) / 2. * sc - height * center_y_.get_value_or(0.5); + cx = (xmax + xmin) / 2. * sc - size_->first * center_x_.get_value_or(0.5); + cy = (ymax + ymin) / 2. * sc - size_->second * center_y_.get_value_or(0.5); } else { if (calculated_scale_) { sc = *calculated_scale_; } else { - if (dx / width > dy / height) { - sc = width / dx; + if (dx / size_->first > dy / size_->second) { + sc = size_->first / dx; } else { - sc = height / dy; + sc = size_->second / dy; } calculated_scale_ = sc; } @@ -1609,11 +1672,11 @@ void SvgSerializer::writeHeader() { if (use_namespace_) { svg_file << " xmlns:ifc=\"http://www.ifcopenshell.org/ns\""; } - if (scale_) { + if (scale_ && size_) { svg_file << - " width=\"" << width << "mm\"" - " height=\"" << height << "mm\"" << - " viewBox=\"0 0 " << width << " " << height << "\""; + " width=\"" << size_->first << "mm\"" + " height=\"" << size_->second << "mm\"" << + " viewBox=\"0 0 " << size_->first << " " << size_->second << "\""; } svg_file << ">\n" diff --git a/src/serializers/SvgSerializer.h b/src/serializers/SvgSerializer.h index 7b19e0434e..2cce214352 100644 --- a/src/serializers/SvgSerializer.h +++ b/src/serializers/SvgSerializer.h @@ -97,6 +97,8 @@ struct vertical_section { gp_Pln plane; std::string name; bool with_projection; + boost::optional scale; + boost::optional> size; }; typedef boost::variant section_data; @@ -130,12 +132,13 @@ public: }; protected: std::ofstream svg_file; - double xmin, ymin, xmax, ymax, width, height; + double xmin, ymin, xmax, ymax; boost::optional> section_data_; boost::optional> deferred_section_data_; - boost::optional scale_, calculated_scale_, center_x_, center_y_; + boost::optional scale_, calculated_scale_, center_x_, center_y_, scale_backup_; + boost::optional> size_, size_backup_; - bool with_section_heights_from_storey_, rescale, print_space_names_, print_space_areas_; + bool with_section_heights_from_storey_, print_space_names_, print_space_areas_; storey_height_display_types storey_height_display_; bool draw_door_arcs_, is_floor_plan_; bool auto_section_, auto_elevation_; @@ -173,7 +176,6 @@ public: , xmax(-std::numeric_limits::infinity()) , ymax(-std::numeric_limits::infinity()) , with_section_heights_from_storey_(false) - , rescale(false) , print_space_names_(false) , print_space_areas_(false) , draw_door_arcs_(false)