2015-07-26 14:26:13 +00:00
|
|
|
/********************************************************************************
|
|
|
|
|
* *
|
|
|
|
|
* Copyright 2015 IfcOpenShell and ROOT B.V. *
|
|
|
|
|
* *
|
|
|
|
|
* This file is part of IfcOpenShell. *
|
|
|
|
|
* *
|
|
|
|
|
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
|
|
|
|
* it under the terms of the Lesser GNU General Public License as published by *
|
|
|
|
|
* the Free Software Foundation, either version 3.0 of the License, or *
|
|
|
|
|
* (at your option) any later version. *
|
|
|
|
|
* *
|
|
|
|
|
* IfcOpenShell is distributed in the hope that it will be useful, *
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
|
* Lesser GNU General Public License for more details. *
|
|
|
|
|
* *
|
|
|
|
|
* You should have received a copy of the Lesser GNU General Public License *
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
|
|
|
|
* *
|
|
|
|
|
********************************************************************************/
|
|
|
|
|
|
|
|
|
|
#ifndef SVGSERIALIZER_H
|
|
|
|
|
#define SVGSERIALIZER_H
|
|
|
|
|
|
2018-03-16 13:49:11 +01:00
|
|
|
#include "../serializers/GeometrySerializer.h"
|
|
|
|
|
#include "../serializers/util.h"
|
2016-03-10 17:00:06 +02:00
|
|
|
|
2019-02-08 15:18:55 +01:00
|
|
|
#include "../ifcparse/utils.h"
|
|
|
|
|
|
2020-09-20 15:08:52 +02:00
|
|
|
#include <HLRBRep_Algo.hxx>
|
|
|
|
|
#include <HLRBRep_HLRToShape.hxx>
|
2021-01-02 12:34:10 +01:00
|
|
|
#include <HLRBRep_PolyAlgo.hxx>
|
|
|
|
|
#include <HLRAlgo_Projector.hxx>
|
2020-09-22 14:10:38 +02:00
|
|
|
#include <gp_Pln.hxx>
|
2021-03-05 21:50:32 +01:00
|
|
|
#include <Bnd_Box.hxx>
|
2020-09-20 15:08:52 +02:00
|
|
|
|
2015-07-26 14:26:13 +00:00
|
|
|
#include <sstream>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <limits>
|
|
|
|
|
|
2020-09-20 15:08:52 +02:00
|
|
|
typedef std::pair<IfcUtil::IfcBaseEntity*, std::string> drawing_key;
|
|
|
|
|
|
2020-05-10 11:48:39 +02:00
|
|
|
struct storey_sorter {
|
2020-09-20 15:08:52 +02:00
|
|
|
bool operator()(const drawing_key& ad, const drawing_key& bd) const {
|
|
|
|
|
if (ad.first == nullptr && bd.first != nullptr) {
|
2020-09-20 15:43:57 +02:00
|
|
|
return false;
|
2020-09-20 15:08:52 +02:00
|
|
|
} else if (bd.first == nullptr && ad.first != nullptr) {
|
|
|
|
|
return true;
|
|
|
|
|
} else if (ad.first == nullptr && bd.first == nullptr) {
|
|
|
|
|
return std::less<std::string>()(ad.second, bd.second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto a = ad.first;
|
|
|
|
|
auto b = bd.first;
|
|
|
|
|
|
2020-05-10 11:48:39 +02:00
|
|
|
const bool a_is_storey = a->declaration().is("IfcBuildingStorey");
|
|
|
|
|
const bool b_is_storey = b->declaration().is("IfcBuildingStorey");
|
|
|
|
|
if (a_is_storey && b_is_storey) {
|
|
|
|
|
boost::optional<double> a_elev, b_elev;
|
|
|
|
|
try {
|
|
|
|
|
a_elev = static_cast<double>(*a->get("Elevation"));
|
|
|
|
|
b_elev = static_cast<double>(*b->get("Elevation"));
|
|
|
|
|
} catch (...) {};
|
|
|
|
|
if (a_elev && b_elev) {
|
2020-07-23 11:27:38 +02:00
|
|
|
if (std::equal_to<double>()(*a_elev, *b_elev)) {
|
|
|
|
|
return std::less<unsigned int>()(a->data().id(), b->data().id());
|
|
|
|
|
} else {
|
|
|
|
|
return std::less<double>()(*a_elev, *b_elev);
|
|
|
|
|
}
|
2020-05-10 11:48:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boost::optional<std::string> a_name, b_name;
|
|
|
|
|
try {
|
|
|
|
|
a_name = static_cast<std::string>(*a->get("Name"));
|
|
|
|
|
b_name = static_cast<std::string>(*b->get("Name"));
|
|
|
|
|
} catch (...) {};
|
|
|
|
|
if (a_name && b_name) {
|
2020-07-23 11:27:38 +02:00
|
|
|
if (std::equal_to<std::string>()(*a_name, *b_name)) {
|
|
|
|
|
return std::less<unsigned int>()(a->data().id(), b->data().id());
|
|
|
|
|
} else {
|
|
|
|
|
return std::less<std::string>()(*a_name, *b_name);
|
|
|
|
|
}
|
2020-05-10 11:48:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return std::less<IfcUtil::IfcBaseEntity*>()(a, b);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2020-09-20 15:08:52 +02:00
|
|
|
struct horizontal_plan {
|
|
|
|
|
IfcUtil::IfcBaseEntity* storey;
|
|
|
|
|
double elevation, offset, next_elevation;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct horizontal_plan_at_element {};
|
|
|
|
|
|
|
|
|
|
struct vertical_section {
|
|
|
|
|
gp_Pln plane;
|
|
|
|
|
std::string name;
|
|
|
|
|
bool with_projection;
|
2021-03-28 12:48:20 +02:00
|
|
|
boost::optional<double> scale;
|
|
|
|
|
boost::optional<std::pair<double, double>> size;
|
2020-09-20 15:08:52 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef boost::variant<horizontal_plan, horizontal_plan_at_element, vertical_section> section_data;
|
|
|
|
|
|
|
|
|
|
struct geometry_data {
|
|
|
|
|
TopoDS_Shape compound_local;
|
2021-03-28 16:55:52 +02:00
|
|
|
std::vector<boost::optional<std::vector<double>>> dash_arrays;
|
2020-09-20 15:08:52 +02:00
|
|
|
gp_Trsf trsf;
|
|
|
|
|
IfcUtil::IfcBaseEntity* product;
|
|
|
|
|
IfcUtil::IfcBaseEntity* storey;
|
|
|
|
|
double storey_elevation;
|
|
|
|
|
std::string ifc_name, svg_name;
|
|
|
|
|
};
|
|
|
|
|
|
2020-12-31 11:31:05 +01:00
|
|
|
struct drawing_meta {
|
|
|
|
|
gp_Pln pln_3d;
|
|
|
|
|
std::array<std::array<double, 3>, 3> matrix_3;
|
|
|
|
|
};
|
|
|
|
|
|
2021-01-27 22:34:19 +01:00
|
|
|
typedef boost::variant<
|
|
|
|
|
boost::blank,
|
|
|
|
|
Handle(HLRBRep_Algo),
|
|
|
|
|
Handle(HLRBRep_PolyAlgo)
|
|
|
|
|
> hlr_t;
|
|
|
|
|
|
2015-07-26 14:26:13 +00:00
|
|
|
class SvgSerializer : public GeometrySerializer {
|
|
|
|
|
public:
|
|
|
|
|
typedef std::pair<std::string, std::vector<util::string_buffer> > path_object;
|
2020-09-20 15:08:52 +02:00
|
|
|
typedef std::vector< boost::shared_ptr<util::string_buffer::float_item> > float_item_list;
|
2021-03-09 16:11:42 +01:00
|
|
|
enum storey_height_display_types {
|
|
|
|
|
SH_NONE, SH_FULL, SH_LEFT
|
|
|
|
|
};
|
2015-07-26 14:26:13 +00:00
|
|
|
protected:
|
|
|
|
|
std::ofstream svg_file;
|
2021-03-28 12:48:20 +02:00
|
|
|
double xmin, ymin, xmax, ymax;
|
2020-09-20 15:08:52 +02:00
|
|
|
boost::optional<std::vector<section_data>> section_data_;
|
|
|
|
|
boost::optional<std::vector<section_data>> deferred_section_data_;
|
2021-03-28 12:48:20 +02:00
|
|
|
boost::optional<double> scale_, calculated_scale_, center_x_, center_y_, scale_backup_;
|
2021-03-28 21:38:29 +02:00
|
|
|
boost::optional<double> storey_height_line_length_;
|
2021-03-28 12:48:20 +02:00
|
|
|
boost::optional<std::pair<double, double>> size_, size_backup_;
|
2020-09-20 15:37:47 +02:00
|
|
|
|
2021-03-28 12:48:20 +02:00
|
|
|
bool with_section_heights_from_storey_, print_space_names_, print_space_areas_;
|
2021-03-09 16:11:42 +01:00
|
|
|
storey_height_display_types storey_height_display_;
|
2020-12-30 14:25:08 +01:00
|
|
|
bool draw_door_arcs_, is_floor_plan_;
|
|
|
|
|
bool auto_section_, auto_elevation_;
|
2021-01-27 22:34:19 +01:00
|
|
|
bool use_namespace_, use_hlr_poly_, always_project_;
|
2020-09-20 15:37:47 +02:00
|
|
|
|
2020-11-03 15:54:48 +01:00
|
|
|
IfcParse::IfcFile* file;
|
|
|
|
|
IfcUtil::IfcBaseEntity* storey_;
|
2020-09-20 15:08:52 +02:00
|
|
|
std::multimap<drawing_key, path_object, storey_sorter> paths;
|
2020-12-31 11:31:05 +01:00
|
|
|
std::map<drawing_key, drawing_meta> drawing_metadata;
|
2021-01-27 22:34:19 +01:00
|
|
|
std::map<IfcUtil::IfcBaseEntity*, hlr_t> storey_hlr;
|
2020-09-20 15:08:52 +02:00
|
|
|
|
|
|
|
|
float_item_list xcoords, ycoords, radii;
|
|
|
|
|
size_t xcoords_begin, ycoords_begin, radii_begin;
|
|
|
|
|
|
|
|
|
|
boost::optional<std::string> section_ref_, elevation_ref_;
|
2020-11-03 15:54:48 +01:00
|
|
|
|
2020-09-20 15:08:52 +02:00
|
|
|
std::list<geometry_data> element_buffer_;
|
|
|
|
|
|
2021-01-27 22:34:19 +01:00
|
|
|
hlr_t hlr;
|
2020-12-30 14:44:43 +01:00
|
|
|
|
|
|
|
|
std::string namespace_prefix_;
|
2021-01-27 22:34:19 +01:00
|
|
|
|
2021-03-05 21:50:32 +01:00
|
|
|
// Used for drawing the storey elevation heights
|
|
|
|
|
// @todo maybe better to rely on a screen-space bounding box
|
|
|
|
|
Bnd_Box bnd_;
|
|
|
|
|
|
2021-01-27 22:34:19 +01:00
|
|
|
void draw_hlr(const gp_Pln& pln, const drawing_key& drawing_name);
|
|
|
|
|
|
2015-07-26 14:26:13 +00:00
|
|
|
public:
|
2017-01-11 12:00:51 +02:00
|
|
|
SvgSerializer(const std::string& out_filename, const SerializerSettings& settings)
|
2016-03-10 11:35:32 +02:00
|
|
|
: GeometrySerializer(settings)
|
2019-02-08 15:18:55 +01:00
|
|
|
, svg_file(IfcUtil::path::from_utf8(out_filename).c_str())
|
2015-07-26 14:26:13 +00:00
|
|
|
, xmin(+std::numeric_limits<double>::infinity())
|
|
|
|
|
, ymin(+std::numeric_limits<double>::infinity())
|
2016-05-15 15:47:21 +02:00
|
|
|
, xmax(-std::numeric_limits<double>::infinity())
|
2015-07-26 14:26:13 +00:00
|
|
|
, ymax(-std::numeric_limits<double>::infinity())
|
2020-07-23 11:27:38 +02:00
|
|
|
, with_section_heights_from_storey_(false)
|
2020-08-25 15:01:07 +02:00
|
|
|
, print_space_names_(false)
|
|
|
|
|
, print_space_areas_(false)
|
|
|
|
|
, draw_door_arcs_(false)
|
2020-09-20 15:37:47 +02:00
|
|
|
, is_floor_plan_(true)
|
2020-12-30 14:25:08 +01:00
|
|
|
, auto_section_(false)
|
|
|
|
|
, auto_elevation_(false)
|
2020-12-30 14:44:43 +01:00
|
|
|
, use_namespace_(false)
|
2021-01-02 12:34:10 +01:00
|
|
|
, use_hlr_poly_(false)
|
2021-01-27 22:34:19 +01:00
|
|
|
, always_project_(false)
|
2015-07-26 14:26:13 +00:00
|
|
|
, file(0)
|
2017-12-11 11:19:15 +01:00
|
|
|
, storey_(0)
|
2020-09-20 15:08:52 +02:00
|
|
|
, xcoords_begin(0)
|
|
|
|
|
, ycoords_begin(0)
|
|
|
|
|
, radii_begin(0)
|
2020-12-30 14:44:43 +01:00
|
|
|
, namespace_prefix_("data-")
|
2015-07-26 14:26:13 +00:00
|
|
|
{}
|
2016-03-10 17:00:06 +02:00
|
|
|
void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
|
|
|
|
|
void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
|
|
|
|
|
void addSizeComponent(const boost::shared_ptr<util::string_buffer::float_item>& 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();
|
|
|
|
|
bool ready();
|
|
|
|
|
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
|
|
|
|
|
void write(const IfcGeom::BRepElement<real_t>* o);
|
2021-03-28 16:55:52 +02:00
|
|
|
void write(path_object& p, const TopoDS_Wire& wire, boost::optional<std::vector<double>> dash_array=boost::none);
|
2020-09-20 15:08:52 +02:00
|
|
|
void write(const geometry_data& data);
|
2020-12-31 11:31:05 +01:00
|
|
|
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);
|
2020-09-20 15:08:52 +02:00
|
|
|
bool isTesselated() const { return false; }
|
2016-03-10 17:00:06 +02:00
|
|
|
void finalize();
|
|
|
|
|
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
2017-10-23 14:17:54 +02:00
|
|
|
void setFile(IfcParse::IfcFile* f);
|
2016-03-10 17:00:06 +02:00
|
|
|
void setBoundingRectangle(double width, double height);
|
2020-07-11 13:39:09 +02:00
|
|
|
void setSectionHeight(double h, IfcUtil::IfcBaseEntity* storey = 0);
|
|
|
|
|
void setSectionHeightsFromStoreys(double offset=1.);
|
2020-04-01 12:19:56 +02:00
|
|
|
void setPrintSpaceNames(bool b) { print_space_names_ = b; }
|
2020-05-10 11:10:30 +02:00
|
|
|
void setPrintSpaceAreas(bool b) { print_space_areas_ = b; }
|
2021-03-09 16:11:42 +01:00
|
|
|
void setDrawStoreyHeights(storey_height_display_types sh) { storey_height_display_ = sh; }
|
2020-07-11 23:26:21 +02:00
|
|
|
void setDrawDoorArcs(bool b) { draw_door_arcs_ = b; }
|
2021-03-28 21:38:29 +02:00
|
|
|
void setStoreyHeightLineLength(double d) { storey_height_line_length_ = d; }
|
2020-12-30 14:25:08 +01:00
|
|
|
|
2020-12-31 11:31:05 +01:00
|
|
|
std::array<std::array<double, 3>, 3> resize();
|
2020-12-30 14:25:08 +01:00
|
|
|
void resetScale();
|
|
|
|
|
|
2020-09-20 15:08:52 +02:00
|
|
|
void setSectionRef(const boost::optional<std::string>& s) {
|
|
|
|
|
section_ref_ = s;
|
|
|
|
|
}
|
|
|
|
|
void setElevationRef(const boost::optional<std::string>& s) {
|
|
|
|
|
elevation_ref_ = s;
|
|
|
|
|
}
|
2020-12-30 14:25:08 +01:00
|
|
|
|
|
|
|
|
void setAutoSection(bool b) {
|
|
|
|
|
auto_section_ = b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setAutoElevation(bool b) {
|
|
|
|
|
auto_elevation_ = b;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-30 14:44:43 +01:00
|
|
|
void setUseNamespace(bool b) {
|
|
|
|
|
use_namespace_ = b;
|
|
|
|
|
namespace_prefix_ = use_namespace_ ? "ifc:" : "data-";
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-02 12:34:10 +01:00
|
|
|
void setUseHlrPoly(bool b) {
|
|
|
|
|
use_hlr_poly_ = b;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-27 22:34:19 +01:00
|
|
|
void setAlwaysProject(bool b) {
|
|
|
|
|
always_project_ = b;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-25 15:01:07 +02:00
|
|
|
void setScale(double s) { scale_ = s; }
|
2020-09-27 14:29:27 +02:00
|
|
|
void setDrawingCenter(double x, double y) {
|
|
|
|
|
center_x_ = x; center_y_ = y;
|
|
|
|
|
}
|
2020-07-23 11:27:38 +02:00
|
|
|
std::string nameElement(const IfcUtil::IfcBaseEntity* storey, const IfcGeom::Element<real_t>* elem);
|
|
|
|
|
std::string nameElement(const IfcUtil::IfcBaseEntity* elem);
|
|
|
|
|
std::string idElement(const IfcUtil::IfcBaseEntity* elem);
|
|
|
|
|
std::string object_id(const IfcUtil::IfcBaseEntity* storey, const IfcGeom::Element<real_t>* o) {
|
2020-09-20 15:08:52 +02:00
|
|
|
if (storey) {
|
|
|
|
|
return idElement(storey) + "-" + GeometrySerializer::object_id(o);
|
|
|
|
|
} else {
|
|
|
|
|
return GeometrySerializer::object_id(o);
|
|
|
|
|
}
|
2020-07-23 11:27:38 +02:00
|
|
|
}
|
2020-12-31 11:31:05 +01:00
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
std::string writeMetadata(const drawing_meta& m);
|
2015-07-26 14:26:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|