Proceed with merge

This commit is contained in:
Thomas Krijnen
2023-03-21 20:15:01 +01:00
parent cfb0eda067
commit c78b2893de
194 changed files with 105325 additions and 7785 deletions
+57 -111
View File
@@ -17,76 +17,39 @@
* *
********************************************************************************/
#include <cmath>
#include <gp_Pnt.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Wire.hxx>
#include <TopExp.hxx>
#include <BRep_Tool.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <BRepAdaptor_CompCurve.hxx>
#include <Standard_Version.hxx>
#include "mapping.h"
#define mapping POSTFIX_SCHEMA(mapping)
using namespace ifcopenshell::geometry;
#if OCC_VERSION_HEX < 0x70600
#include <BRepAdaptor_HCompCurve.hxx>
#endif
#include <boost/math/constants/constants.hpp>
#include <Approx_Curve3d.hxx>
#include "../ifcgeom/IfcGeom.h"
taxonomy::item* mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) {
static const double pi = boost::math::constants::pi<double>();
#include "../ifcgeom_schema_agnostic/wire_builder.h"
#define _USE_MATH_DEFINES
#define Kernel MAKE_TYPE_NAME(Kernel)
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
IfcSchema::IfcCurve* basis_curve = inst->BasisCurve();
bool isConic = basis_curve->declaration().is(IfcSchema::IfcConic::Class());
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
double parameterFactor = isConic ? angle_unit_ : length_unit_;
Handle(Geom_Curve) curve;
if (shape_type(basis_curve) == ST_CURVE) {
if (!convert_curve(basis_curve, curve)) return false;
} else if (shape_type(basis_curve) == ST_WIRE) {
Logger::Warning("Approximating BasisCurve due to possible discontinuities", l);
TopoDS_Wire w;
if (!convert_wire(basis_curve, w)) return false;
#if OCC_VERSION_HEX < 0x70600
BRepAdaptor_CompCurve cc(w, true);
Handle(Adaptor3d_HCurve) hcc = Handle(Adaptor3d_HCurve)(new BRepAdaptor_HCompCurve(cc));
#else
auto hcc = new BRepAdaptor_CompCurve(w, true);
#endif
// @todo, arbitrary numbers here, note they cannot be too high as contiguous memory is allocated based on them.
Approx_Curve3d approx(hcc, getValue(GV_PRECISION), GeomAbs_C0, 10, 10);
curve = approx.Curve();
} else {
Logger::Error("Unknown BasisCurve", l);
return false;
}
auto tc = new taxonomy::edge;
tc->basis = map(inst->BasisCurve());
bool trim_cartesian = l->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER;
aggregate_of_instance::ptr trims1 = l->Trim1();
aggregate_of_instance::ptr trims2 = l->Trim2();
bool trim_cartesian = inst->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER;
aggregate_of_instance::ptr trims1 = inst->Trim1();
aggregate_of_instance::ptr trims2 = inst->Trim2();
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
// reversed orientation handling happens in geometry kernel
unsigned sense_agreement = 0;
double flts[2];
gp_Pnt pnts[2];
taxonomy::point3 pnts[2];
bool has_flts[2] = {false,false};
bool has_pnts[2] = {false,false};
TopoDS_Edge e;
tc->orientation = inst->SenseAgreement();
for ( aggregate_of_instance::it it = trims1->begin(); it != trims1->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->declaration().is(IfcSchema::IfcCartesianPoint::Class()) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
pnts[sense_agreement] = as<taxonomy::point3>(map(i));
has_pnts[sense_agreement] = true;
} else if ( i->declaration().is(IfcSchema::IfcParameterValue::Class()) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
@@ -98,7 +61,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
for ( aggregate_of_instance::it it = trims2->begin(); it != trims2->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
if ( i->declaration().is(IfcSchema::IfcCartesianPoint::Class()) ) {
IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
pnts[1 - sense_agreement] = as<taxonomy::point3>(map(i));
has_pnts[1-sense_agreement] = true;
} else if ( i->declaration().is(IfcSchema::IfcParameterValue::Class()) ) {
const double value = *((IfcSchema::IfcParameterValue*)i);
@@ -107,66 +70,46 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
}
}
const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION);
trim_cartesian &= has_pnts[0] && has_pnts[1];
bool trim_cartesian_failed = !trim_cartesian;
if ( trim_cartesian ) {
if ( pnts[0].Distance(pnts[1]) < 2 * getValue(GV_PRECISION) ) {
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l);
return false;
if (trim_cartesian) {
if ((pnts[0].ccomponents() - pnts[1].ccomponents()).norm() < (2 * tol)) {
Logger::Message(Logger::LOG_WARNING, "Skipping segment with length below tolerance level:", inst);
return nullptr;
}
ShapeFix_ShapeTolerance FTol;
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
FTol.SetTolerance(v1, getValue(GV_PRECISION), TopAbs_VERTEX);
FTol.SetTolerance(v2, getValue(GV_PRECISION), TopAbs_VERTEX);
BRepBuilderAPI_MakeEdge me (curve,v1,v2);
if (!me.IsDone()) {
BRepBuilderAPI_EdgeError err = me.Error();
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l);
trim_cartesian_failed = true;
}
} else {
e = me.Edge();
// BRepBuilderAPI_MakeEdge swaps v1 and v2 if the parameter value of v2 is
// smaller than that of v1. In that case the edge has to be reversed so that
// the vertex order is consistent with Trim1 and Trim2. Otherwise the
// IfcOpenShell wire builder will create intermediate edges automatically.
// The alternative would be to reverse the underlying curve instead.
if (!TopExp::FirstVertex(e, true).IsSame(v1)) {
e.Reverse();
}
}
}
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
tc->start = pnts[0];
tc->end = pnts[1];
} 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()) ) {
if (basis_curve->declaration().is(IfcSchema::IfcLine::Class())) {
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
const double magnitude = line->Dir()->Magnitude();
flts[0] *= magnitude; flts[1] *= magnitude;
}
if ( basis_curve->declaration().is(IfcSchema::IfcEllipse::Class()) ) {
if (basis_curve->declaration().is(IfcSchema::IfcEllipse::Class())) {
IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT);
double x = ellipse->SemiAxis1() * length_unit_;
double y = ellipse->SemiAxis2() * length_unit_;
const bool rotated = y > x;
// @todo do we apply this rotation here or in the kernel.
if (rotated) {
flts[0] -= M_PI / 2.;
flts[1] -= M_PI / 2.;
flts[0] -= pi / 2.;
flts[1] -= pi / 2.;
}
}
double radius = 1.0;
if (curve->DynamicType() == STANDARD_TYPE(Geom_Circle)) {
auto circle_curve = Handle_Geom_Circle::DownCast(curve);
radius = circle_curve->Radius();
} else if (curve->DynamicType() == STANDARD_TYPE(Geom_Ellipse)) {
auto circle_curve = Handle_Geom_Ellipse::DownCast(curve);
radius = (circle_curve->MajorRadius() + circle_curve->MinorRadius()) / 2.;
if (tc->basis->kind() == taxonomy::CIRCLE) {
auto typed_curve = (taxonomy::circle*) tc->basis;
radius = typed_curve->radius;
} else if (tc->basis->kind() == taxonomy::ELLIPSE) {
auto typed_curve = (taxonomy::ellipse*) tc->basis;
radius = (typed_curve->radius + typed_curve->radius2) / 2.;
}
// Fix from @sanderboer to compare using model tolerance, see #744
@@ -176,7 +119,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
// or trimmed segment would be whether there are other curve segments or this
// is the only one.
boost::optional<size_t> num_segments;
auto segment = l->data().getInverse(&IfcSchema::IfcCompositeCurveSegment::Class(), -1);
auto segment = inst->data().getInverse(&IfcSchema::IfcCompositeCurveSegment::Class(), -1);
if (segment->size() == 1) {
auto comp = (*segment->begin())->data().getInverse(&IfcSchema::IfcCompositeCurve::Class(), -1);
if (comp->size() == 1) {
@@ -185,15 +128,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
}
// @todo is 100. not too much? Check with the original issue.
const double precision_markup = getValue(IfcGeom::Kernel::GV_PRECISION_FACTOR) == 1. ? 1. : 100.;
const double precision_markup = conv_settings_.getValue(ConversionSettings::GV_PRECISION_FACTOR) == 1. ? 1. : 100.;
if (isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.), 0., precision_markup * getValue(GV_PRECISION) / (2 * M_PI * radius))) {
e = BRepBuilderAPI_MakeEdge(curve).Edge();
} else {
BRepBuilderAPI_MakeEdge me (curve,flts[0],flts[1]);
e = me.Edge();
if (isConic && std::fabs(fmod(flts[1] - flts[0], pi * 2.)) < precision_markup * tol / (2 * pi * radius)) {
flts[0] = 0.;
flts[1] = 2 * pi;
}
tc->start = flts[0];
tc->end = flts[1];
/*
// @todo
if (num_segments && *num_segments > 1) {
TopoDS_Vertex v0, v1;
TopExp::Vertices(e, v0, v1);
@@ -202,14 +148,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
return false;
}
}
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
e = BRepBuilderAPI_MakeEdge(pnts[0], pnts[1]).Edge();
*/
}
if (e.IsNull()) {
return false;
}
return tc;
/*
// @todo
if (isConic) {
// Tiny circle segnments can cause issues later on, for example
@@ -249,4 +194,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
} else {
return false;
}
*/
}