From a447dc6208bde783b8bd6f148e37aae189dcf1e2 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 16 Sep 2019 19:30:11 +0200 Subject: [PATCH] Work towards trimmed curves --- .../kernels/opencascade/IfcGeomShapes.cpp | 19 ++- src/ifcgeom/schema/mapping.cpp | 125 ++++++++++++++++++ src/ifcgeom/schema/mapping.i | 6 +- src/ifcgeom/taxonomy.h | 11 +- 4 files changed, 145 insertions(+), 16 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 93cc497246..fb7f92803a 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -533,8 +533,14 @@ namespace { template T convert_xyz(const U& u) { - const double* vs = u.components.data(); - return T(vs[0], vs[1], vs[2]); + const auto& vs = u.components; + return T(vs(0), vs(1), vs(2)); + } + + // @todo eliminate + template + T convert_xyz2(const U& vs) { + return T(vs(0), vs(1), vs(2)); } struct curve_creation_visitor { @@ -547,15 +553,18 @@ namespace { } result_type operator()(const taxonomy::line& l) { - return result = Handle(Geom_Curve)(new Geom_Line(convert_xyz(l.origin), convert_xyz(l.direction))); + const auto& m = l.matrix.components; + return result = Handle(Geom_Curve)(new Geom_Line(convert_xyz2(m.row(3)), convert_xyz2(m.row(0)))); } result_type operator()(const taxonomy::circle& c) { - return result = Handle(Geom_Curve)(new Geom_Circle(gp_Ax2(convert_xyz(c.origin), convert_xyz(c.z), convert_xyz(c.x)), c.radius)); + const auto& m = c.matrix.components; + return result = Handle(Geom_Curve)(new Geom_Circle(gp_Ax2(convert_xyz2(m.row(3)), convert_xyz2(m.row(2)), convert_xyz2(m.row(0))), c.radius)); } 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)); + const auto& m = e.matrix.components; + return result = Handle(Geom_Curve)(new Geom_Ellipse(gp_Ax2(convert_xyz2(m.row(3)), convert_xyz2(m.row(2)), convert_xyz2(m.row(0))), e.radius, e.radius2)); } result_type operator()(const taxonomy::loop& l) { diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 9b4ce1ccef..c87e29d015 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1190,3 +1190,128 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcMappedItem* inst) { return shapes; } + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) { + auto loop = new taxonomy::loop; + auto segments = inst->Segments(); + for (auto& segment : *segments) { + auto crv = map(segment->ParentCurve()); + if (crv) { + ((taxonomy::geom_item*)crv)->orientation = segment->SameSense(); + loop->children.push_back(crv); + } + } + IfcEntityList::ptr profile = inst->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1); + const bool force_close = profile && profile->size() > 0; + loop->closed = force_close; + return loop; +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) { + IfcSchema::IfcCurve* basis_curve = inst->BasisCurve(); + bool isConic = basis_curve->declaration().is(IfcSchema::IfcConic::Class()); + double parameterFactor = isConic ? angle_unit_ : length_unit_; + + auto tc = new taxonomy::edge; + tc->basis = map(inst->BasisCurve()); + + bool trim_cartesian = inst->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER; + IfcEntityList::ptr trims1 = inst->Trim1(); + IfcEntityList::ptr trims2 = inst->Trim2(); + + unsigned sense_agreement = inst->SenseAgreement() ? 0 : 1; + double flts[2]; + taxonomy::point3 pnts[2]; + bool has_flts[2] = { false,false }; + bool has_pnts[2] = { false,false }; + + tc->orientation = sense_agreement != 0; + + for (IfcEntityList::it it = trims1->begin(); it != trims1->end(); it++) { + IfcUtil::IfcBaseClass* i = *it; + if (i->declaration().is(IfcSchema::IfcCartesianPoint::Class())) { + pnts[sense_agreement] = as(map(i)); + has_pnts[sense_agreement] = true; + } else if (i->declaration().is(IfcSchema::IfcParameterValue::Class())) { + const double value = *((IfcSchema::IfcParameterValue*)i); + flts[sense_agreement] = value * parameterFactor; + has_flts[sense_agreement] = true; + } + } + + for (IfcEntityList::it it = trims2->begin(); it != trims2->end(); it++) { + IfcUtil::IfcBaseClass* i = *it; + if (i->declaration().is(IfcSchema::IfcCartesianPoint::Class())) { + pnts[1 - sense_agreement] = as(map(i)); + has_pnts[1 - sense_agreement] = true; + } else if (i->declaration().is(IfcSchema::IfcParameterValue::Class())) { + const double value = *((IfcSchema::IfcParameterValue*)i); + flts[1 - sense_agreement] = value * parameterFactor; + has_flts[1 - sense_agreement] = true; + } + } + + // @todo + const double precision_ = 1.e-5; + const double M_PI = 3.141592653; + + trim_cartesian &= has_pnts[0] && has_pnts[1]; + if (trim_cartesian) { + if ((pnts[0].components - pnts[1].components).norm() < (2 * precision_)) { + Logger::Message(Logger::LOG_WARNING, "Skipping segment with length below tolerance level:", inst); + return false; + } + } else if (has_flts[0] && has_flts[1]) { + // The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine + // is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because + // the vector is normalised when passed to Geom_Line constructor the magnitude + // needs to be factored in with the IfcParameterValue here. + if (basis_curve->declaration().is(IfcSchema::IfcLine::Class())) { + IfcSchema::IfcLine* line = static_cast(basis_curve); + const double magnitude = line->Dir()->Magnitude(); + flts[0] *= magnitude; flts[1] *= magnitude; + } + if (basis_curve->declaration().is(IfcSchema::IfcEllipse::Class())) { + IfcSchema::IfcEllipse* ellipse = static_cast(basis_curve); + double x = ellipse->SemiAxis1() * length_unit_; + double y = ellipse->SemiAxis2() * length_unit_; + const bool rotated = y > x; + if (rotated) { + flts[0] -= M_PI / 2.; + flts[1] -= M_PI / 2.; + } + } + } + + /* + // @todo + if (isConic) { + // Tiny circle segnments can cause issues later on, for example + // when the comp curve is used as the sweeping directrix. + double a, b; + Handle(Geom_Curve) crv = BRep_Tool::Curve(e, a, b); + double radius = -1.; + if (crv->DynamicType() == STANDARD_TYPE(Geom_Circle)) { + radius = Handle(Geom_Circle)::DownCast(crv)->Radius(); + } else if (crv->DynamicType() == STANDARD_TYPE(Geom_Ellipse)) { + // The formula above is for circles, but probably good enough + radius = Handle(Geom_Ellipse)::DownCast(crv)->MajorRadius(); + } + if (radius > 0. && deflection_for_approximating_circle(radius, b - a) < getValue(GV_PRECISION)) { + TopoDS_Vertex v0, v1; + TopExp::Vertices(e, v0, v1); + e = TopoDS::Edge(BRepBuilderAPI_MakeEdge(v0, v1).Edge().Oriented(e.Orientation())); + Logger::Warning("Subsituted edge with linear approximation", l); + } + } + */ + + return tc; +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcCircle* inst) { + auto c = new taxonomy::circle; + c->matrix = as(map(inst->Position())); + c->radius = inst->Radius(); + return c; +} diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index d023250b61..5cb68bd7fb 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -102,14 +102,14 @@ BIND(IfcFace); // BIND(IfcEdgeLoop); BIND(IfcPolyline); BIND(IfcPolyLoop); -// BIND(IfcCompositeCurve); -// BIND(IfcTrimmedCurve); +BIND(IfcCompositeCurve); +BIND(IfcTrimmedCurve); // BIND(IfcArbitraryOpenProfileDef); #ifdef SCHEMA_HAS_IfcIndexedPolyCurve // BIND(IfcIndexedPolyCurve) #endif -// BIND(IfcCircle); +BIND(IfcCircle); // BIND(IfcEllipse); // BIND(IfcLine); #ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index d9f57828e4..d7b9187c3e 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -97,6 +97,7 @@ struct style : public item { struct geom_item : public item { style surface_style; matrix4 matrix; + boost::optional orientation; geom_item(const IfcUtil::IfcBaseClass* instance = nullptr) : item(instance) {} geom_item(const IfcUtil::IfcBaseClass* instance, matrix4 m) : item(instance), matrix(m) {} @@ -128,17 +129,11 @@ struct direction3 : public cartesian_base<3> { struct curve : public geom_item {}; struct line : public curve { - point3 origin; - direction3 direction; - virtual item* clone() const { return new line(*this); } virtual kinds kind() const { return LINE; } }; struct circle : public curve { - point3 origin; - direction3 x; - direction3 z; double radius; virtual item* clone() const { return new circle(*this); } @@ -160,7 +155,7 @@ struct bspline_curve : public curve { struct trimmed_curve : public curve { boost::variant start, end; // @todo somehow account for the fact that curve in IFC can be trimmed curve, polyline and composite curve as well. - curve* basis; + item* basis; bool orientation; trimmed_curve() : basis(nullptr), orientation(true) {} @@ -216,7 +211,7 @@ struct face : public collection { }; struct loop : public collection { - boost::optional external; + boost::optional external, closed; virtual item* clone() const { return new loop(*this); } virtual kinds kind() const { return LOOP; }