diff --git a/src/ifcgeom/mapping/IfcOffsetCurveByDistance.cpp b/src/ifcgeom/mapping/IfcOffsetCurveByDistance.cpp index 390db1ee71..6bba88b482 100644 --- a/src/ifcgeom/mapping/IfcOffsetCurveByDistance.cpp +++ b/src/ifcgeom/mapping/IfcOffsetCurveByDistance.cpp @@ -12,12 +12,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * Lesser GNU General Public License for more details. * * * - * You should have received a copz of the Lesser GNU General Public License * + * You should have received a copy of the Lesser GNU General Public License * * along with this program. If not, see . * * * ********************************************************************************/ #include "mapping.h" +#include "../profile_helper.h" #define mapping POSTFIX_SCHEMA(mapping) using namespace ifcopenshell::geometry; @@ -34,17 +35,12 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst Logger::Error("IfcOffsetCurveByDistances must have at least one offset value"); } - auto basis_curve = inst->BasisCurve(); - auto first_offset_value = *(offset_values->begin()); - // todo@ rb - basis_curve might not be piecewise - other valid types are IfcOffsetCurveByDistances, IfcPolyline and IfcIndexedPolyCurve - // Is there a more generic type that can be evaluated at "u"? - auto basis = taxonomy::cast(map(basis_curve)); - double basis_curve_length = 0; - for (auto& s : basis->spans) { - basis_curve_length += s.first; - } + auto basis_curve = inst->BasisCurve(); + //auto pw_curve = ifcopenshell::geometry::piecewise_from_item(map(basis_curve)); + auto pw_curve = taxonomy::dcast(map(basis_curve)); + double basis_curve_length = pw_curve->length(); auto offsets = taxonomy::make(&settings_); @@ -95,7 +91,10 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst #endif if ((dp < 0.0 || basis_curve_length < dp) or - (dn < 0.0 || basis_curve_length < dn)) + (dn < 0.0 || basis_curve_length < dn) + or + (dn < dp) + ) { Logger::Warning("IfcOffsetCurveByDistance offset value is out of bounds."); continue; @@ -144,14 +143,14 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst offsets->spans.push_back({l, fn}); } - auto composition = [basis, offsets](double u)->Eigen::Matrix4d { - auto p = basis->evaluate(u); + auto composition = [pw_curve, offsets](double u) -> Eigen::Matrix4d { + auto p = pw_curve->evaluate(u); auto offset = offsets->evaluate(u); Eigen::Matrix4d m = p * offset; return m; }; - // current implementation assumes that offsets is equal to the full length of basis curve + // current implementation assumes that composition is equal to the full length of basis curve // this may change depending on decisions in the bSI-IF auto pwf = taxonomy::make(&settings_); pwf->spans.emplace_back( basis_curve_length, composition ); diff --git a/src/ifcgeom/mapping/IfcPointByDistanceExpression.cpp b/src/ifcgeom/mapping/IfcPointByDistanceExpression.cpp index 95a5778a93..51417d924c 100644 --- a/src/ifcgeom/mapping/IfcPointByDistanceExpression.cpp +++ b/src/ifcgeom/mapping/IfcPointByDistanceExpression.cpp @@ -18,6 +18,8 @@ ********************************************************************************/ #include "mapping.h" +#include "../profile_helper.h" + #define mapping POSTFIX_SCHEMA(mapping) using namespace ifcopenshell::geometry; @@ -25,9 +27,11 @@ using namespace ifcopenshell::geometry; taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPointByDistanceExpression* inst) { auto u = (*inst->DistanceAlong()->as()) * length_unit_; - // @todo: rb - is it safe to assume the basis curve is a piecewise_function? - auto curve = ifcopenshell::geometry::taxonomy::cast(map(inst->BasisCurve())); - auto m = curve->evaluate(u); + //auto basis_curve = inst->BasisCurve(); + //auto item = map(basis_curve); + //auto pw_curve = ifcopenshell::geometry::piecewise_from_item(item); + auto pw_curve = taxonomy::dcast(map(inst->BasisCurve())); + auto m = pw_curve->evaluate(u); auto o = m.col(3).head<3>(); auto z = m.col(2).head<3>(); diff --git a/src/ifcgeom/taxonomy.cpp b/src/ifcgeom/taxonomy.cpp index 9419db78ee..bafd9d73e9 100644 --- a/src/ifcgeom/taxonomy.cpp +++ b/src/ifcgeom/taxonomy.cpp @@ -455,9 +455,7 @@ ifcopenshell::geometry::taxonomy::solid::ptr ifcopenshell::geometry::create_box( ifcopenshell::geometry::taxonomy::item::ptr ifcopenshell::geometry::taxonomy::piecewise_function::evaluate() const { // @todo configure resolution - double length = 0.0; - for (auto& s : spans) - length += s.first; + double curve_length = length(); std::vector polygon; @@ -466,12 +464,12 @@ ifcopenshell::geometry::taxonomy::item::ptr ifcopenshell::geometry::taxonomy::pi int num_steps = 0; if (param_type == ifcopenshell::geometry::settings::PiecewiseStepMethod::MAXSTEPSIZE) { // parameter is max step size - num_steps = (int)std::ceil(length / param); + num_steps = (int)std::ceil(curve_length / param); } else { // parameter is minimum number of steps num_steps = (int)std::ceil(param); } - auto resolution = length / num_steps; + auto resolution = curve_length / num_steps; for (int i = 0; i <= num_steps; ++i) { auto u = resolution * i; diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 569d877314..c15c413493 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -2,6 +2,7 @@ #define TAXONOMY_H #include "../ifcparse/IfcBaseClass.h" +#include "../ifcparse/IfcLogger.h" #include "ConversionSettings.h" @@ -14,6 +15,7 @@ #include #include #include +#include #ifndef TAXONOMY_USE_UNIQUE_PTR #ifndef TAXONOMY_USE_NAKED_PTR @@ -147,6 +149,10 @@ typedef item const* ptr; // length of span, function to evaluate span std::vector>> spans; + double length() const { + return std::accumulate(spans.begin(), spans.end(), 0.0, [](const auto& v,const auto& s) { return v + s.first; }); + } + void print(std::ostream& o, int = 0) const { o << "piecewise_function" << std::endl; } @@ -1096,6 +1102,65 @@ typedef item const* ptr; } }; + // Hacks around not wanting to use if constexpr + template + class loop_to_piecewise_function_upgrade { + public: + loop_to_piecewise_function_upgrade(taxonomy::ptr) {} + + operator bool() const { + return false; + } + + operator taxonomy::piecewise_function::ptr() const { + throw taxonomy::topology_error(); + } + + operator typename T::ptr() const { + throw taxonomy::topology_error(); + } + }; + + template <> + class loop_to_piecewise_function_upgrade { + private: + boost::optional pwf_; + + public: + loop_to_piecewise_function_upgrade(taxonomy::ptr item) { + auto loop = taxonomy::dcast(item); + if (loop) { + pwf_ = taxonomy::make(); + for (auto& edge : loop->children) { + // the edge could be an arc or trimmed circle in the case of IfcIndexPolyCurve - support for this isn't implemented yet + if (edge->basis) { + Logger::Message(Logger::Severity::LOG_NOTICE, "Shape of basis curve ignored - edge is treated as a straight line edge"); + } + + const auto& s = boost::get(edge->start)->ccomponents(); + const auto& e = boost::get(edge->end)->ccomponents(); + Eigen::Vector3d v = e - s; + auto l = v.norm(); // the norm of a vector is a measure of its length + v.normalize(); // normalize the vector so that it is a unit direction vector + std::function fn = [s, v](double u) { + Eigen::Vector3d o(s + u * v), axis(0, 0, 1), refDirection(v); + auto Y = axis.cross(refDirection).normalized(); + axis = refDirection.cross(Y).normalized(); + return taxonomy::make(o, axis, refDirection)->components(); + }; + (*pwf_)->spans.emplace_back(l, fn); + } + } + } + + operator bool() const { + return pwf_.is_initialized(); + } + + operator taxonomy::piecewise_function::ptr() const { + return *pwf_; + } + }; #ifdef TAXONOMY_USE_SHARED_PTR template @@ -1104,6 +1169,10 @@ typedef item const* ptr; if (upg) { return upg; } + loop_to_piecewise_function_upgrade pwupg(u); + if (pwupg) { + return pwupg; + } return std::static_pointer_cast(u); } template @@ -1112,7 +1181,11 @@ typedef item const* ptr; if (upg) { return upg; } - return std::dynamic_pointer_cast(u); + loop_to_piecewise_function_upgrade pwupg(u); + if (pwupg) { + return pwupg; + } + return std::dynamic_pointer_cast(u); } #endif #ifdef TAXONOMY_USE_UNIQUE_PTR @@ -1122,7 +1195,11 @@ typedef item const* ptr; if (upg) { return upg; } - return static_cast(&*u); + loop_to_piecewise_function_upgrade pwupg(u); + if (pwupg) { + return pwupg; + } + return static_cast(&*u); } template T* dcast(const std::unique_ptr& u) { @@ -1130,7 +1207,11 @@ typedef item const* ptr; if (upg) { return upg; } - return dynamic_cast(&*u); + loop_to_piecewise_function_upgrade pwupg(u); + if (pwupg) { + return pwupg; + } + return dynamic_cast(&*u); } #endif #ifdef TAXONOMY_USE_NAKED_PTR @@ -1140,7 +1221,11 @@ typedef item const* ptr; if (upg) { return upg; } - return std::static_cast(u); + loop_to_piecewise_function_upgrade pwupg(u); + if (pwupg) { + return pwupg; + } + return std::static_cast(u); } template T* dcast(const U*& u) { @@ -1148,7 +1233,11 @@ typedef item const* ptr; if (upg) { return upg; } - return std::dynamic_cast(u); + loop_to_piecewise_function_upgrade pwupg(u); + if (pwupg) { + return pwupg; + } + return std::dynamic_cast(u); } #endif