From e3041219b5b6104b3d4950d9c23ac0d4288da382 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 15 Sep 2019 15:59:05 +0200 Subject: [PATCH] Further work on profiles --- .../kernels/opencascade/IfcGeomShapes.cpp | 45 ++++-- src/ifcgeom/schema/bind_convert_impl.i | 2 +- src/ifcgeom/schema/mapping.cpp | 147 +++++++++++++++++- src/ifcgeom/schema/mapping.i | 6 +- src/ifcgeom/taxonomy.h | 3 +- 5 files changed, 180 insertions(+), 23 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index c59b3056d4..6eaa97b427 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -505,7 +505,7 @@ namespace { /* A compile-time for loop over the curve kinds */ template struct dispatch_curve_creation { - static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T visitor) { + static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T& visitor) { // @todo it should be possible to eliminate this dynamic_cast when there is a static equivalent to kind() const ifcopenshell::geometry::taxonomy::curves::type* v = dynamic_cast*>(item); if (v) { @@ -519,7 +519,7 @@ namespace { template struct dispatch_curve_creation { - static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T visitor) { + static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T& visitor) { Logger::Error("No conversion for " + std::to_string(item->kind())); return false; } @@ -532,6 +532,7 @@ namespace { } struct curve_creation_visitor { + OpenCascadeKernel* kernel; typedef boost::variant result_type; result_type result; @@ -550,10 +551,32 @@ namespace { result_type operator()(const taxonomy::ellipse& e) { return result = Handle(Geom_Curve)(new Geom_Ellipse(gp_Ax2(convert_xyz(e.origin), convert_xyz(e.z), convert_xyz(e.x)), e.radius, e.radius2)); } + + result_type operator()(const taxonomy::loop& l) { + TopoDS_Wire wire; + kernel->convert(&l, wire); + return result = wire; + } + + result_type operator()(const taxonomy::edge& e) { + if (e.basis == nullptr) { + // @todo we should probably construct edges based on correct oriented TopoDS_Vertex instead. + auto p1 = convert_xyz(boost::get(e.start)); + auto p2 = convert_xyz(boost::get(e.end)); + TopoDS_Edge e = BRepBuilderAPI_MakeEdge(p1, p2).Edge(); + BRep_Builder B; + TopoDS_Wire W; + B.MakeWire(W); + B.Add(W, e); + return result = W; + } else { + throw std::runtime_error("not implemented"); + } + } }; - curve_creation_visitor::result_type convert_curve(const taxonomy::item* curve) { - curve_creation_visitor v; + curve_creation_visitor::result_type convert_curve(OpenCascadeKernel* kernel, const taxonomy::item* curve) { + curve_creation_visitor v{ kernel }; if (dispatch_curve_creation::dispatch(curve, v)) { return v.result; } else { @@ -771,7 +794,7 @@ bool OpenCascadeKernel::convert(const taxonomy::loop* loop, TopoDS_Wire& wire) { TopTools_ListOfShape converted_segments; for (auto& segment : segments) { - TopoDS_Wire segment_wire = boost::get(convert_curve(segment)); + auto segment_wire = boost::get(convert_curve(this, segment)); if (!segment->orientation) { segment_wire.Reverse(); @@ -837,11 +860,13 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell: bool OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf) { // @todo check - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++j) { - trsf.SetValue(i + 1, j + 1, matrix->components(i, j)); - } - } + gp_Trsf t; + t.SetValues( + matrix->components(0, 0), matrix->components(1, 0), matrix->components(2, 0), matrix->components(3, 0), + matrix->components(0, 1), matrix->components(1, 1), matrix->components(2, 1), matrix->components(3, 1), + matrix->components(0, 2), matrix->components(1, 2), matrix->components(2, 2), matrix->components(3, 2) + ); + trsf = t; return true; } diff --git a/src/ifcgeom/schema/bind_convert_impl.i b/src/ifcgeom/schema/bind_convert_impl.i index 298c809e0e..32ebf485b6 100644 --- a/src/ifcgeom/schema/bind_convert_impl.i +++ b/src/ifcgeom/schema/bind_convert_impl.i @@ -9,7 +9,7 @@ if (item != nullptr) { \ item->instance = l; \ try { \ - if (l->as()) { \ + if (l->as() && !l->as()) { \ auto style = find_style(l->as()); \ if (style) { \ ((taxonomy::geom_item*)item)->surface_style = as(map(style)); \ diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 2ce140442f..33919e8b90 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -106,7 +106,7 @@ namespace { as(taxonomy::item* item) : item_(item) {} operator T() const { if (!item_) { - throw taxonomy::topology_error(); + throw taxonomy::topology_error("item was nullptr"); } T* t = dynamic_cast(item_); if (t) { @@ -118,7 +118,7 @@ namespace { return upgrade; } } - throw taxonomy::topology_error(); + throw taxonomy::topology_error("item does not match type"); } } ~as() { @@ -145,12 +145,11 @@ namespace { }; taxonomy::item* mapping::map_impl(const IfcSchema::IfcExtrudedAreaSolid* inst) { - // @todo length unit return new taxonomy::extrusion( as(map(inst->Position())), as(map(inst->SweptArea())), as(map(inst->ExtrudedDirection())), - inst->Depth() + inst->Depth() * length_unit_ ); } @@ -265,12 +264,12 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement3D* inst) { } if (hasAxis) { - taxonomy::point3 v = as(map(inst->Axis())); + taxonomy::direction3 v = as(map(inst->Axis())); axis = v.components; } if (hasRef) { - taxonomy::point3 v = as(map(inst->RefDirection())); + taxonomy::direction3 v = as(map(inst->RefDirection())); refDirection = v.components; } else { if (acos(axis.dot(X)) > 1.e-5) { @@ -285,6 +284,20 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement3D* inst) { return new taxonomy::matrix4(o, axis, refDirection); } +taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement2D* inst) { + Eigen::Vector3d P, axis(0, 0, 1), V(1, 0, 0); + { + taxonomy::point3 v = as(map(inst->Location())); + P = v.components; + } + const bool hasRef = inst->hasRefDirection(); + if (hasRef) { + taxonomy::direction3 v = as(map(inst->RefDirection())); + V = v.components; + } + return new taxonomy::matrix4(P, axis, V); +} + taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* inst) { // @todo return new taxonomy::matrix4(); @@ -756,8 +769,8 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcMaterial* material) { for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) { styles->push((**it).Items()->as()); } - for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) { - return map(*it); + if (styles->size() == 1) { + return map(*styles->begin()); } } @@ -829,6 +842,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcStyledItem* inst) { taxonomy::item* mapping::map(const IfcBaseClass* l) { + // std::wcout << l->data().toString().c_str() << std::endl; #include "bind_convert_impl.i" Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l); return nullptr; @@ -983,3 +997,120 @@ void mapping::initialize_units_() { Logger::Warning("No plane angle unit encountered"); } } + +namespace { + struct profile_point { + std::array xy; + boost::optional radius; + }; + + struct profile_point_with_neighbours { + std::array xy; + boost::optional radius; + profile_point* previous, *next; + }; + taxonomy::loop* profile_helper(mapping* self, const IfcSchema::IfcParameterizedProfileDef* inst, const std::vector& points) { + + /* TopoDS_Vertex* vertices = new TopoDS_Vertex[numVerts]; + + for (int i = 0; i < numVerts; i++) { + gp_XY xy(verts[2 * i], verts[2 * i + 1]); + trsf.Transforms(xy); + vertices[i] = BRepBuilderAPI_MakeVertex(gp_Pnt(xy.X(), xy.Y(), 0.0f)); + } + + BRepBuilderAPI_MakeWire w; + for (int i = 0; i < numVerts; i++) + w.Add(BRepBuilderAPI_MakeEdge(vertices[i], vertices[(i + 1) % numVerts])); + + TopoDS_Face face; + convert_wire_to_face(w.Wire(), face); + + if (numFillets && *std::max_element(filletRadii, filletRadii + numFillets) > ALMOST_ZERO) { + BRepFilletAPI_MakeFillet2d fillet(face); + for (int i = 0; i < numFillets; i++) { + const double radius = filletRadii[i]; + if (radius <= ALMOST_ZERO) continue; + fillet.AddFillet(vertices[filletIndices[i]], radius); + } + fillet.Build(); + if (fillet.IsDone()) { + face = TopoDS::Face(fillet.Shape()); + } else { + Logger::Error("Failed to process profile fillets"); + } + } + */ + + Eigen::Matrix4d m4; + + bool has_position = true; +#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL + has_position = inst->hasPosition(); +#endif + if (has_position) { + taxonomy::matrix4 m = as(self->map(inst->Position())); + m4 = m.components; + } + + // @todo precision + if (m4.isIdentity()) { + has_position = false; + } + + std::vector ps; + ps.reserve(points.size()); + std::transform(points.begin(), points.end(), std::back_inserter(ps), [&has_position, &m4](const profile_point& p) { + if (has_position) { + Eigen::Vector4d v(p.xy[0], p.xy[1], 0., 1.); + v = m4 * v; + return taxonomy::point3(v(0), v(1), 0.); + } else { + return taxonomy::point3(p.xy[0], p.xy[1], 0.); + } + }); + + auto loop = new taxonomy::loop(); + auto previous = ps.back(); + for (auto& p : ps) { + auto e = new taxonomy::edge; + e->start = previous; + e->end = p; + previous = p; + loop->children.push_back(e); + } + + return loop; + } +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcRectangleProfileDef* inst) { + const double x = inst->XDim() / 2.0f * length_unit_; + const double y = inst->YDim() / 2.0f * length_unit_; + + // @todo + const double precision_ = 1.e-5; + + if (x < precision_ || y < precision_) { + Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); + return nullptr; + } + + return profile_helper(this, inst, { + {{-x, -y}}, + {{+x, -y}}, + {{+x, +y}}, + {{-x, +y}}, + }); +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcArbitraryClosedProfileDef* l) { + auto loop = map(l->OuterCurve()); + if (loop) { + auto face = new taxonomy::face; + face->children = { loop }; + return face; + } else { + return nullptr; + } +} \ No newline at end of file diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index bc94010fd7..d588e3360a 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -73,10 +73,10 @@ BIND(IfcConnectedFaceSet); // BIND(IfcSweptDiskSolid); // BIND(IfcArbitraryProfileDefWithVoids); -// BIND(IfcArbitraryClosedProfileDef); +BIND(IfcArbitraryClosedProfileDef); // BIND(IfcRoundedRectangleProfileDef); // BIND(IfcRectangleHollowProfileDef); -// BIND(IfcRectangleProfileDef); +BIND(IfcRectangleProfileDef); // BIND(IfcTrapeziumProfileDef) // BIND(IfcCShapeProfileDef); // IfcAsymmetricIShapeProfileDef included @@ -119,7 +119,7 @@ BIND(IfcPolyLoop); BIND(IfcCartesianPoint); BIND(IfcDirection); -// BIND(IfcAxis2Placement2D); +BIND(IfcAxis2Placement2D); BIND(IfcAxis2Placement3D); // BIND(IfcAxis1Placement); BIND(IfcCartesianTransformationOperator2DnonUniform); diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 35a79e176c..d9f57828e4 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -22,6 +22,7 @@ namespace taxonomy { class topology_error : public std::runtime_error { public: topology_error() : std::runtime_error("Generic topology error") {} + topology_error(const char* const s) : std::runtime_error(s) {} }; enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE_CURVE, EDGE, LOOP, FACE, SHELL, EXTRUSION, NODE, COLLECTION, COLOUR, STYLE }; @@ -248,7 +249,7 @@ struct node : public geom_item { namespace impl { typedef std::tuple KindsTuple; - typedef std::tuple CurvesTuple; + typedef std::tuple CurvesTuple; } struct type_by_kind {