mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 10:06:47 +00:00
--door-arcs option in SVG serializer
This commit is contained in:
@@ -336,6 +336,7 @@ int main(int argc, char** argv) {
|
||||
("bounds", po::value<std::string>(&bounds),
|
||||
"Specifies the bounding rectangle, for example 512x512, to which the "
|
||||
"output will be scaled. Only used when converting to SVG.")
|
||||
("door-arcs", "Draw door openings arcs for IfcDoor elements")
|
||||
("section-height", po::value<double>(§ion_height),
|
||||
"Specifies the cut section height for SVG 2D geometry.")
|
||||
("section-height-from-storeys", "Derives section height from storey elevation. Use --section-height to override default offset of 1")
|
||||
@@ -645,7 +646,7 @@ int main(int argc, char** argv) {
|
||||
SerializerSettings settings;
|
||||
/// @todo Make APPLY_DEFAULT_MATERIALS configurable? Quickly tested setting this to false and using obj exporter caused the program to crash and burn.
|
||||
settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords || output_extension == SVG || output_extension == OBJ);
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords || output_extension == OBJ);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, weld_vertices);
|
||||
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, orient_shells);
|
||||
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, convert_back_units);
|
||||
@@ -834,6 +835,9 @@ int main(int argc, char** argv) {
|
||||
if (bounding_width.is_initialized() && bounding_height.is_initialized()) {
|
||||
static_cast<SvgSerializer*>(serializer.get())->setBoundingRectangle(bounding_width.get(), bounding_height.get());
|
||||
}
|
||||
if (vmap.count("door-arcs")) {
|
||||
static_cast<SvgSerializer*>(serializer.get())->setDrawDoorArcs(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (convert_back_units) {
|
||||
|
||||
@@ -59,6 +59,11 @@
|
||||
#include <BRepGProp.hxx>
|
||||
#include <BRepTopAdaptor_FClass2d.hxx>
|
||||
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
|
||||
#include "../ifcparse/IfcGlobalId.h"
|
||||
|
||||
#include "SvgSerializer.h"
|
||||
@@ -290,9 +295,6 @@ SvgSerializer::path_object& SvgSerializer::start_path(IfcUtil::IfcBaseEntity* st
|
||||
return p;
|
||||
}
|
||||
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
|
||||
void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
|
||||
{
|
||||
std::vector<std::pair<double, IfcUtil::IfcBaseEntity*>> section_heights_storage;
|
||||
@@ -321,25 +323,119 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
|
||||
}
|
||||
}
|
||||
|
||||
TopoDS_Shape compound_local = o->geometry().as_compound();
|
||||
const gp_Trsf& trsf = o->transformation().data();
|
||||
BRepBuilderAPI_Transform make_transform_global(compound_local, trsf, true);
|
||||
make_transform_global.Build();
|
||||
// (When determinant < 0, copy is implied and the input is not mutated.)
|
||||
auto compound = make_transform_global.Shape();
|
||||
|
||||
// SVG has a coordinate system with the origin in the *upper*-left corner
|
||||
// therefore we mirror the shape along the XZ-plane.
|
||||
gp_Trsf trsf_mirror;
|
||||
trsf_mirror.SetMirror(gp_Ax2(gp::Origin(), gp::DY()));
|
||||
BRepBuilderAPI_Transform make_transform_mirror(compound, trsf_mirror, true);
|
||||
make_transform_mirror.Build();
|
||||
// (When determinant < 0, copy is implied and the input is not mutated.)
|
||||
compound = make_transform_mirror.Shape();
|
||||
|
||||
TopoDS_Wire annotation;
|
||||
|
||||
if (draw_door_arcs_ && o->product()->declaration().is("IfcDoor")) {
|
||||
|
||||
boost::optional<std::string> operation_type;
|
||||
|
||||
try {
|
||||
IfcEntityList::ptr rels;
|
||||
if (o->product()->declaration().schema()->name() == "IFC2X3") {
|
||||
rels = o->product()->get_inverse("IsDefinedBy");
|
||||
} else {
|
||||
// Damn you, IFC
|
||||
rels = o->product()->get_inverse("IsTypedBy");
|
||||
}
|
||||
for (auto& rel : *rels) {
|
||||
if (rel->declaration().name() == "IfcRelDefinesByType") {
|
||||
IfcUtil::IfcBaseClass* ty = *((IfcUtil::IfcBaseEntity*)rel)->get("RelatingType");
|
||||
const std::string& ty_entity_name = ty->declaration().name();
|
||||
// Damn you, IFC
|
||||
if (ty_entity_name == "IfcDoorStyle" || ty_entity_name == "IfcDoorType") {
|
||||
operation_type = *((IfcUtil::IfcBaseEntity*)ty)->get("OperationType");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
if (operation_type && (*operation_type == "SINGLE_SWING_LEFT") || (*operation_type == "SINGLE_SWING_RIGHT")) {
|
||||
const bool is_left = *operation_type == "SINGLE_SWING_LEFT";
|
||||
|
||||
Bnd_Box bb;
|
||||
BRepBndLib::Add(compound_local, bb);
|
||||
|
||||
if (bb.IsVoid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
double x1, y1, z1, x2, y2, z2;
|
||||
bb.Get(x1, y1, z1, x2, y2, z2);
|
||||
double width = x2 - x1;
|
||||
double y12 = (y1 + y2) / 2.;
|
||||
|
||||
gp_Pnt center(is_left ? x1 : x2, y12, 0);
|
||||
gp_Pnt p1(is_left ? x2 : x1, y12, 0);
|
||||
gp_Pnt p2(is_left ? x1 : x2, y12 + width, 0);
|
||||
|
||||
if (!is_left) {
|
||||
// circles are counter clockwise, so for swing right
|
||||
// we need to reverse the points in order to get the
|
||||
// shorter part of the circle arc.
|
||||
std::swap(p1, p2);
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeEdge me(gp_Circ(gp_Ax2(center, gp::DZ()), width), p1, p2);
|
||||
if (me.IsDone()) {
|
||||
BRep_Builder B;
|
||||
B.MakeWire(annotation);
|
||||
auto edge = me.Edge();
|
||||
|
||||
make_transform_global.Perform(edge, true);
|
||||
auto edge_global = make_transform_global.Shape();
|
||||
make_transform_mirror.Perform(edge_global, true);
|
||||
auto edge_global_mirrored = make_transform_mirror.Shape();
|
||||
|
||||
center.Transform(trsf);
|
||||
p1.Transform(trsf);
|
||||
p2.Transform(trsf);
|
||||
center.Transform(trsf_mirror);
|
||||
p1.Transform(trsf_mirror);
|
||||
p2.Transform(trsf_mirror);
|
||||
|
||||
if (!is_left) {
|
||||
// For the purpose of the SVG serializer we do not a topologically
|
||||
// connected wire. So adding disconnected edges is fine.
|
||||
|
||||
B.Add(annotation, BRepBuilderAPI_MakeEdge(center, p1).Edge());
|
||||
}
|
||||
|
||||
B.Add(annotation, edge_global_mirrored);
|
||||
|
||||
if (is_left) {
|
||||
B.Add(annotation, BRepBuilderAPI_MakeEdge(p2, center).Edge());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& pair : *section_heights_used) {
|
||||
auto cut_z = pair.first;
|
||||
auto storey = pair.second;
|
||||
|
||||
// SVG has a coordinate system with the origin in the *upper*-left corner
|
||||
// therefore we mirror the shape along the XZ-plane.
|
||||
TopoDS_Shape compound = o->geometry().as_compound();
|
||||
gp_Trsf trsf;
|
||||
trsf.SetMirror(gp_Ax2(gp::Origin(), gp::DY()));
|
||||
BRepBuilderAPI_Transform make_transform(compound, trsf);
|
||||
make_transform.Build();
|
||||
// When determinant < 0, copy is implied and the input is not mutated.
|
||||
compound = make_transform.Shape();
|
||||
|
||||
TopoDS_Iterator it(compound);
|
||||
|
||||
TopoDS_Face largest_closed_wire_face;
|
||||
double largest_closed_wire_area = 0.;
|
||||
path_object* po;
|
||||
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()) {
|
||||
@@ -502,6 +598,10 @@ void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
|
||||
po->second.push_back(path);
|
||||
}
|
||||
}
|
||||
|
||||
if (po && !annotation.IsNull()) {
|
||||
write(*po, annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ protected:
|
||||
std::ofstream svg_file;
|
||||
double xmin, ymin, xmax, ymax, width, height;
|
||||
boost::optional<std::vector<std::pair<double, IfcUtil::IfcBaseEntity*>>> section_heights;
|
||||
bool rescale, print_space_names_, print_space_areas_;
|
||||
bool rescale, print_space_names_, print_space_areas_, draw_door_arcs_;
|
||||
std::multimap<IfcUtil::IfcBaseEntity*, path_object, storey_sorter> paths;
|
||||
std::vector< boost::shared_ptr<util::string_buffer::float_item> > xcoords;
|
||||
std::vector< boost::shared_ptr<util::string_buffer::float_item> > ycoords;
|
||||
@@ -103,6 +103,7 @@ public:
|
||||
void setSectionHeightsFromStoreys(double offset=1.);
|
||||
void setPrintSpaceNames(bool b) { print_space_names_ = b; }
|
||||
void setPrintSpaceAreas(bool b) { print_space_areas_ = b; }
|
||||
void setDrawDoorArcs(bool b) { draw_door_arcs_ = b; }
|
||||
std::string nameElement(const IfcGeom::Element<real_t>* elem);
|
||||
std::string nameElement(const IfcUtil::IfcBaseEntity* elem);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user