From bb6312e174787b4d42cf2e92865cf5529395797b Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 18 Apr 2021 15:03:28 +0200 Subject: [PATCH] #1153 --svg-without-storeys and correct positioning and scale based on annotation block --- src/ifcconvert/IfcConvert.cpp | 2 ++ src/serializers/SvgSerializer.cpp | 46 ++++++++++++++++++++++++++++--- src/serializers/SvgSerializer.h | 11 ++++++-- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 8ac40cff6f..536881401b 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -396,6 +396,7 @@ int main(int argc, char** argv) { "Approximate every curve as polygonal in SVG output") ("svg-project", "Always enable hidden line rendering instead of only on elevations") + ("svg-without-storeys", "Don't emit drawings for building storeys") ("door-arcs", "Draw door openings arcs for IfcDoor elements") ("section-height", po::value(§ion_height), "Specifies the cut section height for SVG 2D geometry.") @@ -1012,6 +1013,7 @@ int main(int argc, char** argv) { static_cast(serializer.get())->setUseHlrPoly(vmap.count("svg-poly") > 0); static_cast(serializer.get())->setPolygonal(vmap.count("svg-write-poly") > 0); static_cast(serializer.get())->setAlwaysProject(vmap.count("svg-project") > 0); + static_cast(serializer.get())->setWithoutStoreys(vmap.count("svg-without-storeys") > 0); if (relative_center_x && relative_center_y) { static_cast(serializer.get())->setDrawingCenter(*relative_center_x, *relative_center_y); } diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index b24af6b7a5..9662544c8a 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -603,14 +603,37 @@ void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) { } } + if (!emit_building_storeys_ && scale && size) { + scale_ = scale; + size_ = std::make_pair( + // The header writes values in mm + size->first * 1000 * *scale_, + size->second * 1000 * *scale_ + ); + } + if (pln) { // Move pln to have projection of origin at plane center. // This is necessary to have Poly and BRep HLR at the same position // (Poly) is wrong otherwise. Extrema_ExtPElS ext; ext.Perform(gp::Origin(), *pln, 1.e-5); + auto P0 = pln->Location(); pln->SetLocation(ext.Point(1).Value()); + if (!emit_building_storeys_ && scale && size) { + auto P1 = pln->Location(); + gp_Vec v(P1.XYZ() - P0.XYZ()); + gp_Trsf pi; + pi.SetTransformation(pln->Position()); + pi.Invert(); + v.Transform(pi); + offset_2d_ = std::make_pair( + (-size->first / 2. - v.X()) * 1000 * *scale_, + (-size->second / 2. + v.Y()) * 1000 * *scale_ + ); + } + if (!deferred_section_data_) { deferred_section_data_.emplace(); } @@ -639,7 +662,9 @@ void SvgSerializer::write(const IfcGeom::BRepElement* brep_obj) { element_buffer_.push_back(data); } - write(data); + if (emit_building_storeys_) { + write(data); + } } namespace { @@ -1408,16 +1433,22 @@ std::array, 3> SvgSerializer::resize() { if (size_) { // Scale the resulting image to a bounding rectangle specified by command line arguments + // or specified by IfcAnnotation[ObjectType=DRAWING] const double dx = xmax - xmin; const double dy = ymax - ymin; double sc, cx, cy; - if (scale_) { + if (offset_2d_ && scale_) { + // offset_2d is the offset in plane u,v coordinates as we want to keep the + // plane coordinates used for HLR close to the model origin. + sc = (*scale_) * 1000; + cx = offset_2d_->first; + cy = offset_2d_->second; + } else if (scale_) { sc = (*scale_) * 1000; 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 { + } else { if (calculated_scale_) { sc = *calculated_scale_; } @@ -1708,6 +1739,8 @@ void SvgSerializer::addTextAnnotations(const drawing_key& k) { } void SvgSerializer::finalize() { + doWriteHeader(); + for (auto& p : drawing_metadata) { addTextAnnotations(p.first); } @@ -1900,6 +1933,11 @@ void SvgSerializer::finalize() { } void SvgSerializer::writeHeader() { + // This doesn't do anything anymore because there is now the option that an + // IfcAnnotation[ObjectType=DRAWING] defines the SVG viewBox and dimensions +} + +void SvgSerializer::doWriteHeader() { svg_file << "> section_data_; boost::optional> deferred_section_data_; - boost::optional scale_, calculated_scale_, center_x_, center_y_, scale_backup_; + boost::optional scale_, calculated_scale_, center_x_, center_y_; boost::optional storey_height_line_length_; - boost::optional> size_, size_backup_; + boost::optional> size_, offset_2d_; boost::optional space_name_transform_; bool with_section_heights_from_storey_, print_space_names_, print_space_areas_; @@ -146,6 +146,7 @@ protected: bool draw_door_arcs_, is_floor_plan_; bool auto_section_, auto_elevation_; bool use_namespace_, use_hlr_poly_, always_project_, polygonal_; + bool emit_building_storeys_; IfcParse::IfcFile* file; IfcUtil::IfcBaseEntity* storey_; @@ -189,6 +190,7 @@ public: , use_hlr_poly_(false) , always_project_(false) , polygonal_(false) + , emit_building_storeys_(true) , file(0) , storey_(0) , xcoords_begin(0) @@ -201,6 +203,7 @@ public: void addSizeComponent(const boost::shared_ptr& fi) { radii.push_back(fi); } void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; } void writeHeader(); + void doWriteHeader(); bool ready(); void write(const IfcGeom::TriangulationElement* /*o*/) {} void write(const IfcGeom::BRepElement* o); @@ -258,6 +261,10 @@ public: always_project_ = b; } + void setWithoutStoreys(bool b) { + emit_building_storeys_ = !b; + } + void setScale(double s) { scale_ = s; } void setDrawingCenter(double x, double y) { center_x_ = x; center_y_ = y;