From 7d16b725a33d2ffd938a7c2772d930d9ef44ec17 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 13 Mar 2017 19:08:50 -0600 Subject: [PATCH] IfcTrimmedCurve. Needs projection to closest point in curve? --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 158 ++++++++++++++++++ 2 files changed, 159 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 21dbc8cbb6..80a6cae20a 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -72,6 +72,7 @@ WIRE(IfcOrientedEdge); WIRE(IfcPolyLoop); WIRE(IfcPolyline); WIRE(IfcCompositeCurve); +WIRE(IfcTrimmedCurve); CURVE(IfcCircle); CURVE(IfcEllipse); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index 72ac78fa2d..c6832de476 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -175,3 +175,161 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCompositeCurve* l, cgal_wi wire = w; return true; } + +// TODO: Project points to closest point in curve? +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire_t& wire) { + IfcSchema::IfcCurve* basis_curve = l->BasisCurve(); + bool isConic = basis_curve->is(IfcSchema::Type::IfcConic); + double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT); + cgal_curve_t curve; + if ( !convert_curve(basis_curve,curve) ) return false; + bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN; + IfcEntityList::ptr trims1 = l->Trim1(); + IfcEntityList::ptr trims2 = l->Trim2(); + unsigned sense_agreement = l->SenseAgreement() ? 0 : 1; + double flts[2]; + cgal_point_t pnts[2]; + bool has_flts[2] = {false,false}; + bool has_pnts[2] = {false,false}; + cgal_wire_t w; + for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) { + IfcUtil::IfcBaseClass* i = *it; + if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] ); + has_pnts[sense_agreement] = true; + } else if ( i->is(IfcSchema::Type::IfcParameterValue) ) { + 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->is(IfcSchema::Type::IfcCartesianPoint) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] ); + has_pnts[1-sense_agreement] = true; + } else if ( i->is(IfcSchema::Type::IfcParameterValue) ) { + const double value = *((IfcSchema::IfcParameterValue*)i); + flts[1-sense_agreement] = value * parameterFactor; + has_flts[1-sense_agreement] = true; + } + } + trim_cartesian &= has_pnts[0] && has_pnts[1]; + bool trim_cartesian_failed = !trim_cartesian; + if ( trim_cartesian ) { + if ( CGAL::squared_distance(pnts[0], pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE) ) { + Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity); + return false; + } + if (l->SenseAgreement()) { + bool found = false; + int loops_to_go = 2; + std::vector::const_iterator point = curve.begin(); + do { + if (!found) { + if (CGAL::squared_distance(*point, pnts[0]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + found = true; + w.push_back(*point); + } + } else { + w.push_back(*point); + if (CGAL::squared_distance(*point, pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + break; + } + } ++point; + if (point == curve.end()) { + point = curve.begin(); + --loops_to_go; + } + } while (point != curve.begin() && loops_to_go > 0); + } else { + bool found = false; + int loops_to_go = 2; + std::vector::const_reverse_iterator point = curve.rbegin(); + do { + if (!found) { + if (CGAL::squared_distance(*point, pnts[0]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + found = true; + w.push_back(*point); + } + } else { + w.push_back(*point); + if (CGAL::squared_distance(*point, pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + break; + } + } ++point; + if (point == curve.rend() && loops_to_go > 0) point = curve.rbegin(); + } while (point != curve.rbegin()); + } + } + if ( (!trim_cartesian || trim_cartesian_failed) && (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->is(IfcSchema::Type::IfcLine) ) { + IfcSchema::IfcLine* line = static_cast(basis_curve); + const double magnitude = line->Dir()->Magnitude(); + flts[0] *= magnitude; flts[1] *= magnitude; + } + if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) { + IfcSchema::IfcEllipse* ellipse = static_cast(basis_curve); + double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT); + double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT); + const bool rotated = y > x; + if (rotated) { + flts[0] -= M_PI / 2.; + flts[1] -= M_PI / 2.; + } + } + if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) { + for (auto &point: curve) w.push_back(point); + } else { + if (l->SenseAgreement()) { + bool found = false; + int loops_to_go = 2; + std::vector::const_iterator point = curve.begin(); + do { + if (!found) { + if (CGAL::squared_distance(*point, pnts[0]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + found = true; + w.push_back(*point); + } + } else { + w.push_back(*point); + if (CGAL::squared_distance(*point, pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + break; + } + } ++point; + if (point == curve.end()) { + point = curve.begin(); + --loops_to_go; + } + } while (point != curve.begin() && loops_to_go > 0); + } else { + bool found = false; + int loops_to_go = 2; + std::vector::const_reverse_iterator point = curve.rbegin(); + do { + if (!found) { + if (CGAL::squared_distance(*point, pnts[0]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + found = true; + w.push_back(*point); + } + } else { + w.push_back(*point); + if (CGAL::squared_distance(*point, pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + break; + } + } ++point; + if (point == curve.rend() && loops_to_go > 0) point = curve.rbegin(); + } while (point != curve.rbegin()); + } + } + } else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) { + w.push_back(pnts[0]); + w.push_back(pnts[1]); + } + wire = w; + return true; +}