diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 9b8efa5b18..0f7f64b8f8 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -355,6 +355,9 @@ int main(int argc, char** argv) { double section_height; std::string svg_scale, svg_center; std::string section_ref, elevation_ref; + // "none", "full" or "left" + std::string storey_height_display; + SvgSerializer::storey_height_display_types svg_storey_height_display = SvgSerializer::SH_NONE; po::options_description serializer_options("Serialization options"); serializer_options.add_options() @@ -381,6 +384,7 @@ int main(int argc, char** argv) { ("auto-elevation", "Creates SVG elevation drawings automatically based on model extents") ("draw-storey-heights", + po::value(&storey_height_display)->default_value("none")->implicit_value("full"), "Draws a horizontal line at the height of building storeys in vertical drawings") ("svg-xmlns", "Stores name and guid in a separate namespace as opposed to data-name, data-guid") @@ -508,6 +512,22 @@ int main(int argc, char** argv) { print_usage(); return EXIT_FAILURE; } + + if (vmap.count("draw-storey-heights")) { + boost::to_lower(storey_height_display); + + if (storey_height_display == "none") { + svg_storey_height_display = SvgSerializer::SH_NONE; + } else if (storey_height_display == "full") { + svg_storey_height_display = SvgSerializer::SH_FULL; + } else if (storey_height_display == "left") { + svg_storey_height_display = SvgSerializer::SH_LEFT; + } else { + cerr_ << "[Error] --draw-storey-heights should be none|full|left" << std::endl; + print_usage(); + return EXIT_FAILURE; + } + } if (vmap.count("log-format") == 1) { boost::to_lower(log_format); @@ -952,7 +972,7 @@ int main(int argc, char** argv) { static_cast(serializer.get())->setPrintSpaceAreas(true); } if (vmap.count("draw-storey-heights") != 0) { - static_cast(serializer.get())->setDrawStoreyHeights(true); + static_cast(serializer.get())->setDrawStoreyHeights(svg_storey_height_display); } if (bounding_width.is_initialized() && bounding_height.is_initialized()) { static_cast(serializer.get())->setBoundingRectangle(bounding_width.get(), bounding_height.get()); diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 0f44dd91a6..ed13923d06 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -1022,7 +1022,12 @@ void SvgSerializer::write(const geometry_data& data) { gp_Pnt prev; for (int i = 1; i <= wires->Length(); ++i) { - const TopoDS_Wire& wire = TopoDS::Wire(wires->Value(i)); + + // @nb not const, because in case of storey annotations we might + // generate a new wire with fixed length + + TopoDS_Wire wire = TopoDS::Wire(wires->Value(i)); + 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 @@ -1040,9 +1045,8 @@ void SvgSerializer::write(const geometry_data& data) { } } - write(*po, wire); - - if (data.product->declaration().is("IfcBuildingStorey") && draw_storey_heights_ && wires->Length() == 1 && IfcGeom::Kernel::count(wire, TopAbs_EDGE) == 1) { + + if (data.product->declaration().is("IfcBuildingStorey") && storey_height_display_ != SH_NONE && wires->Length() == 1 && IfcGeom::Kernel::count(wire, TopAbs_EDGE) == 1) { std::string elev_str; @@ -1077,12 +1081,31 @@ void SvgSerializer::write(const geometry_data& data) { std::swap(p0, p1); } + // @todo these settings are getting out of hand, how can we + // streamline this? + std::string anchor; + gp_Pnt* anchor_pt; + if (storey_height_display_ == SH_FULL) { + anchor = "end"; + anchor_pt = &p1; + } else { + anchor = "start"; + anchor_pt = &p0; + + auto d = (p1.XYZ() - p0.XYZ()); + d.Normalize(); + d *= 3; + gp_Pnt p1x(p0.XYZ() + d); + + wire = BRepBuilderAPI_MakePolygon(p0, p1x).Wire(); + } + // dominant-baseline="central" is not well supported in IE. // so we add a 0.35 offset to the dy of the tspans - path.add(" X())); path.add("\" y=\""); - ycoords.push_back(path.add(p1.Y())); + ycoords.push_back(path.add(anchor_pt->Y())); path.add("\">"); for (auto lit = labels.begin(); lit != labels.end(); ++lit) { const auto& l = *lit; @@ -1091,7 +1114,7 @@ void SvgSerializer::write(const geometry_data& data) { : 1.0; // <- dy is relative to the previous text element, so // always 1 for successive spans. path.add("X())); path.add("\" dy=\""); path.add(boost::lexical_cast(dy)); path.add("em\">"); @@ -1101,6 +1124,8 @@ void SvgSerializer::write(const geometry_data& data) { path.add(""); po->second.push_back(path); } + + write(*po, wire); } } @@ -1497,7 +1522,7 @@ void SvgSerializer::finalize() { draw_hlr(ax, { nullptr, drawing_name }); } - if (draw_storey_heights_ && pln && std::abs(pln->Position().Direction().Z()) < 1.e-5) { + if (storey_height_display_ != SH_NONE && pln && std::abs(pln->Position().Direction().Z()) < 1.e-5) { auto storeys = this->file->instances_by_type("IfcBuildingStorey"); if (storeys) { const double lu = file->getUnit("LENGTHUNIT").second; diff --git a/src/serializers/SvgSerializer.h b/src/serializers/SvgSerializer.h index 6342776296..7b19e0434e 100644 --- a/src/serializers/SvgSerializer.h +++ b/src/serializers/SvgSerializer.h @@ -125,6 +125,9 @@ class SvgSerializer : public GeometrySerializer { public: typedef std::pair > path_object; typedef std::vector< boost::shared_ptr > float_item_list; + enum storey_height_display_types { + SH_NONE, SH_FULL, SH_LEFT + }; protected: std::ofstream svg_file; double xmin, ymin, xmax, ymax, width, height; @@ -133,7 +136,7 @@ protected: boost::optional scale_, calculated_scale_, center_x_, center_y_; bool with_section_heights_from_storey_, rescale, print_space_names_, print_space_areas_; - bool draw_storey_heights_; + storey_height_display_types storey_height_display_; bool draw_door_arcs_, is_floor_plan_; bool auto_section_, auto_elevation_; bool use_namespace_, use_hlr_poly_, always_project_; @@ -208,7 +211,7 @@ public: void setSectionHeightsFromStoreys(double offset=1.); void setPrintSpaceNames(bool b) { print_space_names_ = b; } void setPrintSpaceAreas(bool b) { print_space_areas_ = b; } - void setDrawStoreyHeights(bool b) { draw_storey_heights_ = b; } + void setDrawStoreyHeights(storey_height_display_types sh) { storey_height_display_ = sh; } void setDrawDoorArcs(bool b) { draw_door_arcs_ = b; } std::array, 3> resize();