diff --git a/src/ifcgeom/mapping/IfcCompositeCurve.cpp b/src/ifcgeom/mapping/IfcCompositeCurve.cpp index db61d37b86..7ed02dfabb 100644 --- a/src/ifcgeom/mapping/IfcCompositeCurve.cpp +++ b/src/ifcgeom/mapping/IfcCompositeCurve.cpp @@ -31,49 +31,47 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) { IfcSchema::IfcCompositeCurveSegment::list::ptr segments = inst->Segments(); #endif - for (auto& segment_ : *segments) { - if (!(segment_)->declaration().is(IfcSchema::IfcCompositeCurveSegment::Class())) { - Logger::Error("Not implemented", segment_); - return nullptr; - } - - auto segment = (IfcSchema::IfcCompositeCurveSegment*) segment_; - - IfcSchema::IfcCurve* curve = segment->ParentCurve(); - - if (curve->as()) { + for (auto& segment : *segments) { + if (segment->as() && segment->as()->ParentCurve()->as()) { Logger::Notice("Infinite IfcLine used as ParentCurve of segment, treating as a segment", segment); double u0 = 0.0; - double u1 = curve->as()->Dir()->Magnitude() * length_unit_; + double u1 = segment->as()->ParentCurve()->as()->Dir()->Magnitude() * length_unit_; if (u1 < conv_settings_.getValue(ConversionSettings::GV_PRECISION)) { Logger::Warning("Segment length below tolerance", segment); } auto e = taxonomy::make(); - e->basis = map(curve); + e->basis = map(segment->as()->ParentCurve()); e->start = u0; e->end = u1; - e->orientation_2.reset(segment->SameSense()); + e->orientation_2.reset(segment->as()->SameSense()); loop->children.push_back(e); - } else { - auto crv = map(segment->ParentCurve()); + } else if (segment->as()) { + auto crv = map(segment->as()->ParentCurve()); if (crv) { if (crv->kind() == taxonomy::EDGE) { auto ecrv = taxonomy::cast(crv); - ecrv->orientation_2.reset(segment->SameSense()); + ecrv->orientation_2.reset(segment->as()->SameSense()); loop->children.push_back(ecrv); } else if (crv->kind() == taxonomy::LOOP) { - if (!segment->SameSense()) { + if (!segment->as()->SameSense()) { crv->reverse(); } for (auto& s : taxonomy::cast(crv)->children) { loop->children.push_back(s); } - // @todo delete crv without children } } } +#ifdef SCHEMA_HAS_IfcCurveSegment + else if (segment->as()) { + auto crv = map(segment->as()->ParentCurve()); + for (auto& s : taxonomy::cast(crv)->children) { + loop->children.push_back(s); + } + } +#endif } aggregate_of_instance::ptr profile = inst->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1); diff --git a/src/ifcgeom/mapping/IfcCurveSegment.cpp b/src/ifcgeom/mapping/IfcCurveSegment.cpp new file mode 100644 index 0000000000..65ec09bb67 --- /dev/null +++ b/src/ifcgeom/mapping/IfcCurveSegment.cpp @@ -0,0 +1,135 @@ +/******************************************************************************** + * * + * This file is part of IfcOpenShell. * + * * + * IfcOpenShell is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as published by * + * the Free Software Foundation, either version 3.0 of the License, or * + * (at your option) any later version. * + * * + * IfcOpenShell is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * Lesser GNU General Public License for more details. * + * * + * You should have received a copy of the Lesser GNU General Public License * + * along with this program. If not, see . * + * * + ********************************************************************************/ + +#include "mapping.h" +#define mapping POSTFIX_SCHEMA(mapping) +using namespace ifcopenshell::geometry; + +#ifdef SCHEMA_HAS_IfcCurveSegment + +#include "../profile_helper.h" + +#include +#include + +typedef boost::mpl::vector< + IfcSchema::IfcLine +#ifdef SCHEMA_HAS_IfcClothoid + , IfcSchema::IfcClothoid +#endif +> curve_seg_types; + +class curve_segment_evaluator { +private: + double length_unit_; + double start_; + double length_; + IfcSchema::IfcCurve* curve_; + + std::optional> eval_; + +public: + // First constructor, takes parameters from IfcCurveSegment + curve_segment_evaluator(double length_unit, IfcSchema::IfcCurve* curve, IfcSchema::IfcCurveMeasureSelect* st, IfcSchema::IfcCurveMeasureSelect* le) + : length_unit_(length_unit) + , curve_(curve) + { + // @todo in IFC4X3_ADD2 this needs to be length measure + + if (!st->as() || !le->as()) { + // @nb Parameter values are forbidden in the specification until parametrization is provided for all spirals + throw std::runtime_error("Unsupported curve measure type"); + } + + start_ = *st->as() * length_unit; + length_ = *le->as() * length_unit; + } + +#ifdef SCHEMA_HAS_IfcClothoid + // Then initialize Function(double) -> Vector3, by means of IfcCurve subtypes + void operator()(boost::type) { + if (!curve_->as()) { + return; + } + + // @todo verify + auto L = start_ + length_; + auto A = curve_->as()->ClothoidConstant(); + auto R = A * A / L; + auto RL = R * L; + + eval_ = [RL](double u) { + auto xterm_1 = u; + auto xterm_2 = std::pow(u, 5) / (40 * std::pow(RL, 2)); + auto xterm_3 = std::pow(u, 9) / (3456 * std::pow(RL, 4)); + auto xterm_4 = std::pow(u, 13) / (599040 * std::pow(RL, 6)); + auto x = xterm_1 - xterm_2 + xterm_3 - xterm_4; + + auto yterm_1 = std::pow(u, 3) / (6 * RL); + auto yterm_2 = std::pow(u, 7) / (336 * std::pow(RL, 3)); + auto yterm_3 = std::pow(u, 11) / (42240 * std::pow(RL, 5)); + auto yterm_4 = std::pow(u, 15) / (9676800 * std::pow(RL, 7)); + auto y = yterm_1 - yterm_2 + yterm_3 - yterm_4; + + return Eigen::Vector3d(x, y, 0.); + }; + } +#endif + + // Another IfcCurve subtype + void operator()(boost::type) { + if (!curve_->as()) { + return; + } + throw std::runtime_error("not implemented"); + } + + // Then, with function populated based on IfcCurve subtype, we can evaluate to points + Eigen::Vector3d operator()(double u) { + if (eval_) { + return (*eval_)((u + start_) * length_unit_); + } else { + throw std::runtime_error(curve_->declaration().name() + " not implemented"); + } + } + + double length() const { + return length_; + } +}; + +taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCurveSegment* inst) { + // @todo fixed number of segments or fixed interval? + // @todo placement + + static int NUM_SEGMENTS = 64; + curve_segment_evaluator cse(length_unit_, inst->ParentCurve(), inst->SegmentStart(), inst->SegmentLength()); + boost::mpl::for_each>(cse); + + std::vector polygon; + + for (int i = 0; i <= NUM_SEGMENTS; ++i) { + auto p = cse(cse.length() * i / NUM_SEGMENTS); + polygon.push_back(taxonomy::make(p(0), p(1), p(2))); + } + + return polygon_from_points(polygon); +} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/mapping/mapping.i b/src/ifcgeom/mapping/mapping.i index b2efc31a56..435366a0c0 100644 --- a/src/ifcgeom/mapping/mapping.i +++ b/src/ifcgeom/mapping/mapping.i @@ -147,3 +147,7 @@ BIND(IfcVector); // BIND(IfcColourRgb); BIND(IfcMaterial); // -> style BIND(IfcStyledItem); // -> style + +#ifdef SCHEMA_HAS_IfcCurveSegment +BIND(IfcCurveSegment); +#endif \ No newline at end of file