From 1ee488b1480eea41548b423f550c2d295c5fa1d7 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 28 Mar 2021 16:55:52 +0200 Subject: [PATCH] Quick solution for inline dasharray --- src/serializers/SvgSerializer.cpp | 89 ++++++++++++++++++++++++++++--- src/serializers/SvgSerializer.h | 3 +- 2 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index a865f5464c..1ff4529977 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -89,7 +89,7 @@ bool SvgSerializer::ready() { return true; } -void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire) { +void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire, boost::optional> dash_array) { /* ShapeFix_Wire fix; Handle(ShapeExtend_WireData) data = new ShapeExtend_WireData; for (TopExp_Explorer edges(result, TopAbs_EDGE); edges.More(); edges.Next()) { @@ -302,7 +302,22 @@ void SvgSerializer::write(path_object& p, const TopoDS_Wire& wire) { first = false; } - path.add("\"/>\n"); + path.add("\""); + + if (dash_array) { + path.add(" stroke-dasharray=\""); + bool first = true; + for (auto& d : *dash_array) { + if (!first) { + path.add(" "); + } + first = false; + radii.push_back(path.add(d)); + } + path.add("\""); + } + + path.add("/>\n"); p.second.push_back(path); } @@ -455,6 +470,38 @@ namespace { } } +namespace { + boost::optional get_curve_style_name(IfcUtil::IfcBaseEntity* item) { + auto refs = item->get_inverse("StyledByItem"); + for (auto& ref : *refs) { + if (ref->declaration().is("IfcStyledItem")) { + IfcEntityList::ptr styles = *((IfcUtil::IfcBaseEntity*)ref)->get("Styles"); + for (auto& s_ : *styles) { + auto s = (IfcUtil::IfcBaseEntity*) s_; + std::vector pss; + if (s->declaration().is("IfcPresentationStyleAssignment")) { + IfcEntityList::ptr pstyles = *s->get("Styles"); + for (auto& ssss : *pstyles) { + pss.push_back((IfcUtil::IfcBaseEntity*) ssss); + } + } else { + pss.push_back(s); + } + for (auto& ps : pss) { + if (ps->declaration().is("IfcCurveStyle")) { + auto arg = ps->get("Name"); + if (!arg->isNull()) { + return (std::string) *arg; + } + } + } + } + } + } + return boost::none; + } +} + void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) { boost::optional object_type; @@ -462,7 +509,36 @@ void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) { object_type = static_cast(*brep_obj->product()->get("ObjectType")); } + std::vector>> dash_arrays; + TopoDS_Shape compound_local = brep_obj->geometry().as_compound(); + for (auto& x : brep_obj->geometry()) { + dash_arrays.emplace_back(); + + auto item = (IfcUtil::IfcBaseEntity*) this->file->instance_by_id(x.ItemId()); + auto curve_style_name = get_curve_style_name(item); + + if (curve_style_name && + (boost::starts_with(*curve_style_name, "LINE_") || + boost::starts_with(*curve_style_name, "DASH_"))) + { + std::vector tokens; + boost::split(tokens, *curve_style_name, boost::is_any_of("_")); + if (tokens.size() > 1) { + dash_arrays.back().emplace(); + for (auto& tok : tokens) { + double d; + try { + d = boost::lexical_cast(tok); + } catch (boost::bad_lexical_cast&) { + continue; + } + dash_arrays.back()->push_back(d / 1000.); + } + } + } + } + const gp_Trsf& trsf = brep_obj->transformation().data(); const bool is_section = (section_ref_ && object_type && *section_ref_ == *object_type); @@ -556,7 +632,7 @@ void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) { IfcUtil::IfcBaseEntity* storey = p ? p->first : nullptr; double elev = p ? p->second : std::numeric_limits::quiet_NaN(); // @todo is it correct to call nameElement() here with a single storey (what if this element spans multiple?) - geometry_data data{ compound_local, trsf, brep_obj->product(), storey, elev, brep_obj->name(), nameElement(storey, brep_obj) }; + geometry_data data{ compound_local, dash_arrays, trsf, brep_obj->product(), storey, elev, brep_obj->name(), nameElement(storey, brep_obj) }; if (auto_section_ || auto_elevation_ || section_ref_ || elevation_ref_) { element_buffer_.push_back(data); @@ -884,13 +960,14 @@ void SvgSerializer::write(const geometry_data& data) { } TopoDS_Iterator it(compound_to_use); + auto dash_it = data.dash_arrays.begin(); TopoDS_Face largest_closed_wire_face; double largest_closed_wire_area = 0.; path_object* po = nullptr; // 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(), ++dash_it) { const TopoDS_Shape& subshape = it.Value(); @@ -1030,7 +1107,7 @@ void SvgSerializer::write(const geometry_data& data) { TopExp_Explorer exp(subshape, TopAbs_WIRE, TopAbs_FACE); for (; exp.More(); exp.Next()) { const auto& W = TopoDS::Wire(exp.Current()); - write(*po, W); + write(*po, W, *dash_it); } } @@ -1616,7 +1693,7 @@ void SvgSerializer::finalize() { name = (std::string) *a2; } write(geometry_data{ - C,trsf,storey,storey,elev,name,nameElement(storey) + C,{boost::none},trsf,storey,storey,elev,name,nameElement(storey) }); } } diff --git a/src/serializers/SvgSerializer.h b/src/serializers/SvgSerializer.h index 2cce214352..762d7ff8f8 100644 --- a/src/serializers/SvgSerializer.h +++ b/src/serializers/SvgSerializer.h @@ -105,6 +105,7 @@ typedef boost::variant>> dash_arrays; gp_Trsf trsf; IfcUtil::IfcBaseEntity* product; IfcUtil::IfcBaseEntity* storey; @@ -200,7 +201,7 @@ public: bool ready(); void write(const IfcGeom::TriangulationElement* /*o*/) {} void write(const IfcGeom::BRepElement* o); - void write(path_object& p, const TopoDS_Wire& wire); + void write(path_object& p, const TopoDS_Wire& wire, boost::optional> dash_array=boost::none); void write(const geometry_data& data); 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);