diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 010d713fef..74021b7716 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -1569,7 +1569,133 @@ void SvgSerializer::resetScale() { ymax = -std::numeric_limits::infinity(); } +void SvgSerializer::addTextAnnotations(const drawing_key& k) { + auto& meta = drawing_metadata[k]; + + boost::optional> range; + + if (k.first && section_data_) { + for (auto& sd : *section_data_) { + if (sd.which() == 0) { + const auto& plan = boost::get(sd); + if (k.first == plan.storey) { + range = std::make_pair(plan.elevation, plan.next_elevation); + } + } + } + } + + auto annotations = file->instances_by_type("IfcAnnotation"); + for (auto& ann_ : *annotations) { + auto ann = (IfcUtil::IfcBaseEntity*) ann_; + + auto ot = ann->get("ObjectType"); + auto nm = ann->get("Name"); + auto ds = ann->get("Description"); + auto pl = ann->get("ObjectPlacement"); + + if (!ot->isNull() && !nm->isNull() && !ds->isNull() && !pl->isNull()) { + auto object_type = (std::string) *ot; + auto name = (std::string) *nm; + auto desc = (std::string) *ds; + + if (object_type == "Text") { + IfcGeom::Kernel kernel(file); + gp_Trsf trsf; + if (kernel.convert_placement(*pl, trsf)) { + + auto v = trsf.TranslationPart(); + if (k.first) { + v.ChangeCoord(1) *= -1.; + trsf.SetTranslationPart(v); + } + + if (!range || (v.Z() >= range->first && v.Z() < range->second)) { + + if (meta.pln_3d.Position().Direction().Dot(gp_Dir(trsf.HVectorialPart().Column(3))) > 0.99) { + auto svg_name = nameElement(ann); + path_object* po; + if (k.first) { + po = &start_path(meta.pln_3d, k.first, svg_name); + } else { + po = &start_path(meta.pln_3d, k.second, svg_name); + } + + if (object_type.size()) { + // postfix the object_type for CSS matching + boost::replace_all(svg_name, "class=\"IfcAnnotation\"", "class=\"IfcAnnotation " + object_type + "\""); + } + + boost::optional font_size; + std::vector tokens; + boost::split(tokens, name, boost::is_any_of("_")); + if (tokens.size() == 2) { + try { + font_size = boost::lexical_cast(tokens.back()); + } + catch (...) {} + } + + // @todo column or row? + double z_rotation = gp_Dir(trsf.HVectorialPart().Column(1)).AngleWithRef(gp_Dir(1., 0., 0.), gp_Dir(0., 0., 1.)); + z_rotation *= 180. / M_PI; + + 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 + path.add(" "); + + std::vector labels{ desc }; + + for (auto lit = labels.begin(); lit != labels.end(); ++lit) { + const auto& l = *lit; + double dy = labels.begin() == lit + ? 0.0 // align bottom + : 1.0; // <- dy is relative to the previous text element, so + // always 1 for successive spans. + path.add("(dy)); + path.add("em\">"); + path.add(l); + path.add(""); + } + + path.add(""); + + po->second.push_back(path); + } + } + } + } + } + } +} + void SvgSerializer::finalize() { + for (auto& p : drawing_metadata) { + addTextAnnotations(p.first); + } + for (auto& p : storey_hlr) { draw_hlr(drawing_metadata[{p.first, ""}].pln_3d, { p.first, "" }); } diff --git a/src/serializers/SvgSerializer.h b/src/serializers/SvgSerializer.h index 0772e03bdb..ede299dea3 100644 --- a/src/serializers/SvgSerializer.h +++ b/src/serializers/SvgSerializer.h @@ -220,6 +220,7 @@ public: void setDrawDoorArcs(bool b) { draw_door_arcs_ = b; } void setStoreyHeightLineLength(double d) { storey_height_line_length_ = d; } void setSpaceNameTransform(const std::string& v) { space_name_transform_ = v; } + void addTextAnnotations(const drawing_key& k); std::array, 3> resize(); void resetScale();