diff --git a/src/ifcgeom/AbstractKernel.cpp b/src/ifcgeom/AbstractKernel.cpp index a82e7c1641..a86a542895 100644 --- a/src/ifcgeom/AbstractKernel.cpp +++ b/src/ifcgeom/AbstractKernel.cpp @@ -3,6 +3,7 @@ #include "../ifcgeom/IfcGeomElement.h" #include "../ifcgeom/ConversionSettings.h" #include "../ifcgeom/abstract_mapping.h" +#include "../ifcgeom/piecewise_function_evaluator.h" #ifdef IFOPSH_WITH_OPENCASCADE #include "../ifcgeom/kernels/opencascade/OpenCascadeKernel.h" @@ -220,7 +221,8 @@ bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonom } bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::piecewise_function::ptr item, IfcGeom::ConversionResults& cs) { - auto expl = item->evaluate(); + piecewise_function_evaluator evaluator(item); + auto expl = evaluator.evaluate(); expl->instance = item->instance; return convert(expl, cs); } diff --git a/src/ifcgeom/mapping/IfcCompositeCurve.cpp b/src/ifcgeom/mapping/IfcCompositeCurve.cpp index b9f2aaaf4d..568b861ad7 100644 --- a/src/ifcgeom/mapping/IfcCompositeCurve.cpp +++ b/src/ifcgeom/mapping/IfcCompositeCurve.cpp @@ -92,7 +92,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) { return loop; } else { - auto pwf = taxonomy::make(0.0,pwfs,&settings_,inst); + auto pwf = taxonomy::make(0.0,pwfs,inst); return pwf; } } diff --git a/src/ifcgeom/mapping/IfcCurveSegment.cpp b/src/ifcgeom/mapping/IfcCurveSegment.cpp index 343cb8300d..e2f38135e3 100644 --- a/src/ifcgeom/mapping/IfcCurveSegment.cpp +++ b/src/ifcgeom/mapping/IfcCurveSegment.cpp @@ -961,7 +961,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCurveSegment* inst) { taxonomy::piecewise_function::spans_t spans; spans.emplace_back(fabs(length), fn); - auto pwf = taxonomy::make(0.0, spans,&settings_,inst); + auto pwf = taxonomy::make(0.0, spans,inst); return pwf; } diff --git a/src/ifcgeom/mapping/IfcFixedReferenceSweptAreaSolid.cpp b/src/ifcgeom/mapping/IfcFixedReferenceSweptAreaSolid.cpp index 7267f61b2a..79632b9f01 100644 --- a/src/ifcgeom/mapping/IfcFixedReferenceSweptAreaSolid.cpp +++ b/src/ifcgeom/mapping/IfcFixedReferenceSweptAreaSolid.cpp @@ -18,6 +18,7 @@ ********************************************************************************/ #include "mapping.h" +#include "../piecewise_function_evaluator.h" #define mapping POSTFIX_SCHEMA(mapping) using namespace ifcopenshell::geometry; @@ -34,6 +35,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcFixedReferenceSweptAreaSolid // @todo currently only the case is handled where directrix returns a piecewise_function if (auto pwf = taxonomy::dcast(dir)) { + piecewise_function_evaluator evaluator(pwf,&settings_); double start = 0; double end = pwf->length(); #ifdef SCHEMA_HAS_IfcDirectrixCurveSweptAreaSolid @@ -53,20 +55,9 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcFixedReferenceSweptAreaSolid } } #endif - auto curve_length = end - start; - auto param_type = settings_.get().get(); - auto param = settings_.get().get(); - size_t num_steps = 0; - if (param_type == ifcopenshell::geometry::settings::PiecewiseStepMethod::MAXSTEPSIZE) { - // parameter is max step size - num_steps = (size_t) std::ceil(curve_length / param); - } else { - // parameter is minimum number of steps - num_steps = (size_t) std::ceil(param); - } - for (size_t i = 0; i <= num_steps; ++i) { - auto distalong = start + curve_length / num_steps * i; - auto m4 = pwf->evaluate(distalong); + auto evaluation_points = evaluator.evaluation_points(); + for (const auto& dist_along : evaluation_points) { + auto m4 = evaluator.evaluate(dist_along); /* std::stringstream ss; diff --git a/src/ifcgeom/mapping/IfcGradientCurve.cpp b/src/ifcgeom/mapping/IfcGradientCurve.cpp index 3c5b95635a..6217b81a0e 100644 --- a/src/ifcgeom/mapping/IfcGradientCurve.cpp +++ b/src/ifcgeom/mapping/IfcGradientCurve.cpp @@ -18,6 +18,7 @@ ********************************************************************************/ #include "mapping.h" +#include "../piecewise_function_evaluator.h" #define mapping POSTFIX_SCHEMA(mapping) using namespace ifcopenshell::geometry; @@ -55,7 +56,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) { double gradient_start = m(0, 3); // start of vertical (row 0, col 3) - "Distance Along" horizontal curve // create the vertical pwf - auto vertical = taxonomy::make(gradient_start, pwfs, &settings_); + auto vertical = taxonomy::make(gradient_start, pwfs); // Determine the valid domain of the PWF... the valid domain is where both // the base curve and gradient curves are defined @@ -69,11 +70,12 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) { } // define the callback function for the gradient curve - auto composition = [horizontal, vertical](double u)->Eigen::Matrix4d { + piecewise_function_evaluator horizontal_evaluator(horizontal, &settings_), vertical_evaluator(vertical, &settings_); + auto composition = [horizontal_evaluator, vertical_evaluator,start=vertical->start()](double u) -> Eigen::Matrix4d { // u is distance from start of gradient curve (vertical) // add vertical->start() to u to get distance from start of horizontal - auto xy = horizontal->evaluate(u + vertical->start()); - auto uz = vertical->evaluate(u); + auto xy = horizontal_evaluator.evaluate(u + start); + auto uz = vertical_evaluator.evaluate(u); uz.col(3)(0) = 0.0; // x is distance along. zero it out so it doesn't add to the x from horizontal uz.col(1).swap(uz.col(2)); // uz is 2D in distance along - y plane, swap y and z so elevations become z @@ -86,7 +88,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) { taxonomy::piecewise_function::spans_t spans; spans.emplace_back(length, composition); - auto pwf = taxonomy::make(start, spans, &settings_, inst); + auto pwf = taxonomy::make(start, spans, inst); return pwf; } diff --git a/src/ifcgeom/mapping/IfcOffsetCurveByDistance.cpp b/src/ifcgeom/mapping/IfcOffsetCurveByDistance.cpp index 7af8b42bd8..1ed4d05e8b 100644 --- a/src/ifcgeom/mapping/IfcOffsetCurveByDistance.cpp +++ b/src/ifcgeom/mapping/IfcOffsetCurveByDistance.cpp @@ -19,6 +19,7 @@ #include "mapping.h" #include "../profile_helper.h" +#include "../piecewise_function_evaluator.h" #define mapping POSTFIX_SCHEMA(mapping) using namespace ifcopenshell::geometry; @@ -144,11 +145,12 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst offset_spans.emplace_back(l, fn); } - auto offsets = taxonomy::make(start,offset_spans,&settings_); + auto offsets = taxonomy::make(start,offset_spans); - auto composition = [pw_curve, offsets](double u) -> Eigen::Matrix4d { - auto p = pw_curve->evaluate(u); - auto offset = offsets->evaluate(u); + piecewise_function_evaluator pw_evaluator(pw_curve, &settings_), offsets_evaluator(offsets, &settings_); + auto composition = [pw_evaluator, offsets_evaluator](double u) -> Eigen::Matrix4d { + auto p = pw_evaluator.evaluate(u); + auto offset = offsets_evaluator.evaluate(u); Eigen::Matrix4d m = p * offset; return m; }; @@ -157,7 +159,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst // this may change depending on decisions in the bSI-IF taxonomy::piecewise_function::spans_t spans; spans.emplace_back(basis_curve_length, composition); - auto pwf = taxonomy::make(start,spans,&settings_,inst); + auto pwf = taxonomy::make(start,spans,inst); return pwf; } diff --git a/src/ifcgeom/mapping/IfcPointByDistanceExpression.cpp b/src/ifcgeom/mapping/IfcPointByDistanceExpression.cpp index 601765e1a3..6097344eb3 100644 --- a/src/ifcgeom/mapping/IfcPointByDistanceExpression.cpp +++ b/src/ifcgeom/mapping/IfcPointByDistanceExpression.cpp @@ -19,6 +19,7 @@ #include "mapping.h" #include "../profile_helper.h" +#include "../piecewise_function_evaluator.h" #define mapping POSTFIX_SCHEMA(mapping) using namespace ifcopenshell::geometry; @@ -31,7 +32,8 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPointByDistanceExpression* i //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); + piecewise_function_evaluator evaluator(pw_curve,&settings_); + auto m = evaluator.evaluate(u); auto o = m.col(3).head<3>(); auto z = m.col(2).head<3>(); diff --git a/src/ifcgeom/mapping/IfcSectionedSolidHorizontal.cpp b/src/ifcgeom/mapping/IfcSectionedSolidHorizontal.cpp index 74e6e4cd89..95b750f82f 100644 --- a/src/ifcgeom/mapping/IfcSectionedSolidHorizontal.cpp +++ b/src/ifcgeom/mapping/IfcSectionedSolidHorizontal.cpp @@ -22,6 +22,7 @@ using namespace ifcopenshell::geometry; #include "../../ifcgeom/profile_helper.h" +#include "../piecewise_function_evaluator.h" #include @@ -114,7 +115,8 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSolidHorizontal* in // @todo currently only the case is handled where directrix returns a piecewise_function // @todo this "if" statement is not really required because the function returns at the start if the Directrix is not a piecewise function if (pwf) { - double start = std::max(0., cross_sections.front().dist_along); + piecewise_function_evaluator evaluator(pwf, &settings_); + double start = std::max(0., cross_sections.front().dist_along); double end = std::min(pwf->length(), cross_sections.back().dist_along); if (end - start < 1.e-9) { @@ -232,7 +234,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSolidHorizontal* in } } - auto m4 = pwf->evaluate(dist_along); + auto m4 = evaluator.evaluate(dist_along); /* { std::wcout << "#" << pwf->instance->data().id() << " " << dist_along << ": " << m4.col(3).row(2).value() << std::endl; }*/ diff --git a/src/ifcgeom/mapping/IfcSegmentedReferenceCurve.cpp b/src/ifcgeom/mapping/IfcSegmentedReferenceCurve.cpp index 2ab56482c1..d1ab88fbe5 100644 --- a/src/ifcgeom/mapping/IfcSegmentedReferenceCurve.cpp +++ b/src/ifcgeom/mapping/IfcSegmentedReferenceCurve.cpp @@ -21,6 +21,8 @@ #define mapping POSTFIX_SCHEMA(mapping) using namespace ifcopenshell::geometry; +#include "../piecewise_function_evaluator.h" + #ifdef SCHEMA_HAS_IfcSegmentedReferenceCurve taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* inst) { @@ -53,7 +55,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins const Eigen::Matrix4d& m = p->ccomponents(); double cant_start = m(0, 3); // start of cant curve - auto cant = taxonomy::make(cant_start,pwfs,&settings_); + auto cant = taxonomy::make(cant_start,pwfs); // Determine the valid domain of the PWF... the valid domain is where // horizontal, gradient and cant curves are defined @@ -68,11 +70,12 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins } // define the callback function for the segmented reference curve - auto composition = [gradient, cant](double u)->Eigen::Matrix4d { + piecewise_function_evaluator gradient_evaluator(gradient, &settings_), cant_evaluator(cant, &settings_); + auto composition = [gradient_evaluator, cant_evaluator, start = cant->start()](double u) -> Eigen::Matrix4d { // u is distance from start of cant curve // add cant->start() to u to get the distance from start of gradient curve - auto g = gradient->evaluate(u+cant->start()); - auto c = cant->evaluate(u); + auto g = gradient_evaluator.evaluate(u + start); + auto c = cant_evaluator.evaluate(u); // Need to multiply g and c so the axis vectors // from cant have the correct rotation applied so @@ -105,7 +108,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins taxonomy::piecewise_function::spans_t spans; spans.emplace_back(length, composition); - auto pwf = taxonomy::make(start, spans, &settings_, inst); + auto pwf = taxonomy::make(start, spans, inst); return pwf; } diff --git a/src/ifcgeom/piecewise_function_evaluator.cpp b/src/ifcgeom/piecewise_function_evaluator.cpp new file mode 100644 index 0000000000..e4a03511ca --- /dev/null +++ b/src/ifcgeom/piecewise_function_evaluator.cpp @@ -0,0 +1,103 @@ +#include "piecewise_function_evaluator.h" +#include "profile_helper.h" + +using namespace ifcopenshell::geometry; + + +piecewise_function_evaluator::piecewise_function_evaluator(taxonomy::piecewise_function::const_ptr pwf, ifcopenshell::geometry::Settings* settings) : pwf_(pwf) { + if (settings) { + settings_ = *settings; + } +} + +std::vector piecewise_function_evaluator::evaluation_points() const { + if (!eval_points_.has_value()) { + double curve_length = pwf_->length(); + + auto param_type = settings_.get().get(); + auto param = settings_.get().get(); + unsigned num_steps = 0; + if (param_type == ifcopenshell::geometry::settings::PiecewiseStepMethod::MAXSTEPSIZE) { + // parameter is max step size + num_steps = (unsigned)std::ceil(curve_length / param); + } else { + // parameter is minimum number of steps + num_steps = (unsigned)std::ceil(param); + } + + eval_points_ = evaluation_points(pwf_->start(), pwf_->start() + curve_length, num_steps); + } + return *eval_points_; +} + +std::vector piecewise_function_evaluator::evaluation_points(double ustart, double uend, unsigned nsteps) const { + double curve_length = pwf_->length(); + ustart = std::max(pwf_->start(), ustart); + uend = std::min(uend, pwf_->start() + curve_length); + + nsteps = std::max(1u, nsteps); // never have fewer than 1 step + + auto resolution = (uend - ustart) / nsteps; + + std::vector u_values; + u_values.reserve(nsteps); + + for (unsigned i = 0; i <= nsteps; ++i) { + auto u = resolution * i + ustart; + u_values.push_back(u); + } + + return u_values; +} + +taxonomy::item::ptr piecewise_function_evaluator::evaluate() const { + return evaluate(evaluation_points()); +} + +taxonomy::item::ptr piecewise_function_evaluator::evaluate(double ustart, double uend, unsigned nsteps) const { + return evaluate(evaluation_points(ustart, uend, nsteps)); +} + +Eigen::Matrix4d piecewise_function_evaluator::evaluate(double u) const { + // assume monotonic evaluation and store last evaluated segment + if (current_span_fn_ == nullptr || (u < current_span_start_ || current_span_end_ < u)) { + // there isn't a current span or u is outside the range of the current span + // get a new "current span" + std::tie(current_span_start_, current_span_end_, current_span_fn_) = get_span(u); + } + + u -= current_span_start_; // make u relative to start of span + return (*current_span_fn_)(u); +} + +taxonomy::item::ptr piecewise_function_evaluator::evaluate(const std::vector& dist) const { + std::vector polygon; + polygon.reserve(dist.size()); + for (auto& u : dist) { + Eigen::Matrix4d m = evaluate(u); + polygon.push_back(taxonomy::make(m(0, 3), m(1, 3), m(2, 3))); + } + + return polygon_from_points(polygon); +} + +std::tuple*> piecewise_function_evaluator::get_span(double u) const { + // force u to be within bounds of the curve + double s = pwf_->start(); + double e = pwf_->end(); + u = std::max(s, u); + u = std::min(u, e); + + double span_start = s; + for (auto& [length, fn] : pwf_->spans()) { + double span_end = span_start + length; + auto tolerance = settings_.get().get(); + if (span_start <= u && u < span_end + tolerance) { + return {span_start, span_end, &fn}; + } + span_start += length; + } + + Logger::Error("piecewise_function_impl::get_span span not found."); + return {0, 0, nullptr}; +} diff --git a/src/ifcgeom/piecewise_function_evaluator.h b/src/ifcgeom/piecewise_function_evaluator.h new file mode 100644 index 0000000000..ca1bddce54 --- /dev/null +++ b/src/ifcgeom/piecewise_function_evaluator.h @@ -0,0 +1,58 @@ +#ifndef ITERATOR_PWF_EVALUATOR_H +#define ITERATOR_PWF_EVALUATOR_H + +#include "../ifcgeom/taxonomy.h" + +#include + +namespace ifcopenshell { namespace geometry { + +/// @brief utility class to evaluate piecewise_function objects +class piecewise_function_evaluator { + public: + piecewise_function_evaluator(taxonomy::piecewise_function::const_ptr pwf, ifcopenshell::geometry::Settings* settings=nullptr); + + /// @brief returns a vector of "distance along" points where the evaluate function computes loop points + std::vector evaluation_points() const; + + /// @brief returns a vector of "distance along" points between ustart and uend + /// @param ustart starting location + /// @param uend ending location + /// @param nsteps number of steps to evaluate + std::vector evaluation_points(double ustart, double uend, unsigned nsteps) const; + + /// @brief evaluates the piecewise function between start and end + /// evaluation point step size is taken from the settings object + taxonomy::item::ptr evaluate() const; + + /// @brief evaluates the piecewise function between ustart and uend + /// if ustart and uend are out of range, the range of values evaluated + /// are constrained to start_ and start_+length_ + /// @param ustart starting location + /// @param uend ending location + /// @param nsteps number of steps to evaluate + /// @return taxonomy::loop::ptr + taxonomy::item::ptr evaluate(double ustart, double uend, unsigned nsteps) const; + + /// @brief evaluates the piecewise function at u + /// @param u u is constrained to be between start_ and start_+length + /// @return 4x4 placement matrix + Eigen::Matrix4d evaluate(double u) const; + + private: + taxonomy::item::ptr evaluate(const std::vector& dist) const; + std::tuple*> get_span(double u) const; + + taxonomy::piecewise_function::const_ptr pwf_; + + ifcopenshell::geometry::Settings settings_; + + mutable double current_span_start_ = 0; + mutable double current_span_end_ = 0; + mutable const std::function* current_span_fn_ = nullptr; + mutable boost::optional> eval_points_; +}; + +}} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/piecewise_function_impl.cpp b/src/ifcgeom/piecewise_function_impl.cpp index ecd2762057..6fa29fb649 100644 --- a/src/ifcgeom/piecewise_function_impl.cpp +++ b/src/ifcgeom/piecewise_function_impl.cpp @@ -7,97 +7,40 @@ namespace geometry { namespace taxonomy { -std::vector ifcopenshell::geometry::taxonomy::piecewise_function_impl::evaluation_points() const { - if (!eval_points_.has_value()) { - double curve_length = length(); +piecewise_function_impl::piecewise_function_impl(double start, const spans_t& s) : start_(start), spans_(s) { +} - auto param_type = settings_ ? settings_->get().get() : ifcopenshell::geometry::settings::PiecewiseStepMethod::MAXSTEPSIZE; - auto param = settings_ ? settings_->get().get() : 0.5; - unsigned num_steps = 0; - if (param_type == ifcopenshell::geometry::settings::PiecewiseStepMethod::MAXSTEPSIZE) { - // parameter is max step size - num_steps = (unsigned)std::ceil(curve_length / param); - } else { - // parameter is minimum number of steps - num_steps = (unsigned)std::ceil(param); - } - - eval_points_ = evaluation_points(start_, start_ + curve_length, num_steps); +piecewise_function_impl::piecewise_function_impl(double start, const std::vector& pwfs) : start_(start) { + for (auto& pwf : pwfs) { + spans_.insert(spans_.end(), pwf->spans().begin(), pwf->spans().end()); } - return *eval_points_; } -std::vector ifcopenshell::geometry::taxonomy::piecewise_function_impl::evaluation_points(double ustart, double uend, unsigned nsteps) const { - double curve_length = length(); - ustart = std::max(start_, ustart); - uend = std::min(uend, start_ + curve_length); +const piecewise_function_impl::spans_t& piecewise_function_impl::spans() const { return spans_; } - nsteps = std::max(1u, nsteps); // never have fewer than 1 step +bool piecewise_function_impl::is_empty() const { return spans_.empty(); } - auto resolution = (uend - ustart) / nsteps; - - std::vector u_values; - u_values.reserve(nsteps); - - for (unsigned i = 0; i <= nsteps; ++i) { - auto u = resolution * i + ustart; - u_values.push_back(u); - } - - return u_values; +double piecewise_function_impl::start() const { + return start_; } -ifcopenshell::geometry::taxonomy::item::ptr ifcopenshell::geometry::taxonomy::piecewise_function_impl::evaluate() const { - return evaluate(evaluation_points()); +double piecewise_function_impl::end() const { + return start_ + length(); } -item::ptr ifcopenshell::geometry::taxonomy::piecewise_function_impl::evaluate(double ustart, double uend, unsigned nsteps) const { - return evaluate(evaluation_points(ustart, uend, nsteps)); +double piecewise_function_impl::length() const { + return std::accumulate(spans_.begin(), spans_.end(), 0.0, [](const auto& v, const auto& s) { return v + s.first; }); + + // this is a secondary option where we only compute length once and cache it. + // mutex is needed to prevent interruption of the accumulation if there is multi-threading + // skipping this detail for now and just adding up the span lengths every time + //if (!length_.has_value()) { + // length_ = std::accumulate(spans_.begin(), spans_.end(), 0.0, [](const auto& v, const auto& s) { return v + s.first; }); + //} + //return *length_; } -item::ptr ifcopenshell::geometry::taxonomy::piecewise_function_impl::evaluate(const std::vector& dist) const { - std::vector polygon; - polygon.reserve(dist.size()); - for (auto& u : dist) { - Eigen::Matrix4d m = evaluate(u); - polygon.push_back(taxonomy::make(m.col(3)(0), m.col(3)(1), m.col(3)(2))); - } - - return polygon_from_points(polygon); -} - -Eigen::Matrix4d ifcopenshell::geometry::taxonomy::piecewise_function_impl::evaluate(double u) const { - // assume monotonic evaluation and store last evaluated segment - if (current_span_fn_ == nullptr || (u < current_span_start_ || current_span_end_ < u)) { - // there isn't a current span or u is outside the range of the current span - // get a new "current span" - std::tie(current_span_start_, current_span_end_, current_span_fn_) = get_span(u); - } - - u -= current_span_start_; // make u relative to start of span - return (*current_span_fn_)(u); -} - -std::tuple*> ifcopenshell::geometry::taxonomy::piecewise_function_impl::get_span(double u) const { - // force u to be within bounds of the curve - double s = start(); - double e = end(); - u = std::max(s, u); - u = std::min(u, e); - - double span_start = s; - for (auto& [length, fn] : spans_) { - double span_end = span_start + length; - auto tolerance = settings_ ? settings_->get().get() : 0.001; - if (span_start <= u && u < span_end + tolerance) { - return {span_start, span_end, &fn}; - } - span_start += length; - } - - Logger::Error("piecewise_function_impl::get_span span not found."); - return {0, 0, nullptr}; -} +piecewise_function_impl* piecewise_function_impl::clone_() const { return new piecewise_function_impl(*this); } } // namespace taxonomy diff --git a/src/ifcgeom/piecewise_function_impl.h b/src/ifcgeom/piecewise_function_impl.h index 0c2f306ac5..daf8636feb 100644 --- a/src/ifcgeom/piecewise_function_impl.h +++ b/src/ifcgeom/piecewise_function_impl.h @@ -12,79 +12,23 @@ namespace taxonomy { struct piecewise_function_impl { using spans_t = std::vector>>; - piecewise_function_impl(double start, const spans_t& s, ifcopenshell::geometry::Settings* settings = nullptr) : start_(start), - settings_(settings), - spans_(s){}; - piecewise_function_impl(double start, const std::vector& pwfs, ifcopenshell::geometry::Settings* settings = nullptr) : start_(start), - settings_(settings) { - for (auto& pwf : pwfs) { - spans_.insert(spans_.end(), pwf->spans().begin(), pwf->spans().end()); - } - }; + piecewise_function_impl(double start, const spans_t& s); + piecewise_function_impl(double start, const std::vector& pwfs); piecewise_function_impl(piecewise_function_impl&&) = default; piecewise_function_impl(const piecewise_function_impl&) = default; - const ifcopenshell::geometry::Settings* settings_ = nullptr; - - const spans_t& spans() const { return spans_; } - - bool is_empty() const { return spans_.empty(); } - - double start() const { - return start_; - } - - double end() const { - return start_ + length(); - } - - double length() const { - if (!length_.has_value()) { - length_ = std::accumulate(spans_.begin(), spans_.end(), 0.0, [](const auto& v, const auto& s) { return v + s.first; }); - } - return *length_; - } - - piecewise_function_impl* clone_() const { return new piecewise_function_impl(*this); } - - /// @brief returns a vector of "distance along" points where the evaluate function computes loop points - std::vector evaluation_points() const; - - /// @brief returns a vector of "distance along" points between ustart and uend - /// @param ustart starting location - /// @param uend ending location - /// @param nsteps number of steps to evaluate - std::vector evaluation_points(double ustart, double uend, unsigned nsteps) const; - - /// @brief evaluates the piecewise function between start and end - /// evaluation point step size is taken from the settings object - item::ptr evaluate() const; - - /// @brief evaluates the piecewise function between ustart and uend - /// if ustart and uend are out of range, the range of values evaluated - /// are constrained to start_ and start_+length_ - /// @param ustart starting location - /// @param uend ending location - /// @param nsteps number of steps to evaluate - /// @return taxonomy::loop::ptr - item::ptr evaluate(double ustart, double uend, unsigned nsteps) const; - - /// @brief evaluates the piecewise function at u - /// @param u u is constrained to be between start_ and start_+length - /// @return 4x4 placement matrix - Eigen::Matrix4d evaluate(double u) const; + const spans_t& spans() const; + bool is_empty() const; + double start() const; + double end() const; + double length() const; + piecewise_function_impl* clone_() const; private: - item::ptr evaluate(const std::vector& dist) const; - std::tuple*> get_span(double u) const; double start_ = 0.0; // starting value of the pwf spans_t spans_; - mutable double current_span_start_ = 0; - mutable double current_span_end_ = 0; - mutable const std::function* current_span_fn_ = nullptr; - mutable boost::optional length_; - mutable boost::optional> eval_points_; + //mutable boost::optional length_; // used for length() method }; } // namespace taxonomy diff --git a/src/ifcgeom/taxonomy.cpp b/src/ifcgeom/taxonomy.cpp index 9b4f5043aa..1dd61d72b0 100644 --- a/src/ifcgeom/taxonomy.cpp +++ b/src/ifcgeom/taxonomy.cpp @@ -464,12 +464,12 @@ ifcopenshell::geometry::taxonomy::solid::ptr ifcopenshell::geometry::create_box( } /////////////////// -piecewise_function::piecewise_function(double start, const spans_t& s, ifcopenshell::geometry::Settings* settings, const IfcUtil::IfcBaseInterface* instance) : implicit_item(instance) { - impl_ = new piecewise_function_impl(start, s, settings); +piecewise_function::piecewise_function(double start, const spans_t& s, const IfcUtil::IfcBaseInterface* instance) : implicit_item(instance) { + impl_ = new piecewise_function_impl(start, s); } -piecewise_function::piecewise_function(double start, const std::vector& pwfs, ifcopenshell::geometry::Settings* settings, const IfcUtil::IfcBaseInterface* instance) : implicit_item(instance) { - impl_ = new piecewise_function_impl(start, pwfs, settings); +piecewise_function::piecewise_function(double start, const std::vector& pwfs, const IfcUtil::IfcBaseInterface* instance) : implicit_item(instance) { + impl_ = new piecewise_function_impl(start, pwfs); }; piecewise_function::piecewise_function(const piecewise_function& other) : implicit_item(other) { @@ -486,11 +486,6 @@ double piecewise_function::start() const { return impl_->start(); } double piecewise_function::end() const { return impl_->end(); } double piecewise_function::length() const { return impl_->length(); } -std::vector piecewise_function::evaluation_points() const { return impl_->evaluation_points(); } -std::vector piecewise_function::evaluation_points(double ustart, double uend, unsigned nsteps) const { return impl_->evaluation_points(ustart, uend, nsteps); } -item::ptr piecewise_function::evaluate() const { return impl_->evaluate(); } -item::ptr piecewise_function::evaluate(double ustart, double uend, unsigned nsteps) const { return impl_->evaluate(ustart, uend, nsteps); } -Eigen::Matrix4d piecewise_function::evaluate(double u) const { return impl_->evaluate(u); } ifcopenshell::geometry::taxonomy::collection::ptr ifcopenshell::geometry::flatten(const taxonomy::collection::ptr& deep) { auto flat = make(); diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 3b77273240..db9c97863e 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -347,8 +347,6 @@ typedef item const* ptr; struct implicit_item : public geom_item { DECLARE_PTR(implicit_item) using geom_item::geom_item; - - virtual item::ptr evaluate() const = 0; }; struct piecewise_function_impl; // forward declaration @@ -357,14 +355,12 @@ typedef item const* ptr; using spans_t = std::vector>>; - piecewise_function(double start, const spans_t& s, ifcopenshell::geometry::Settings* settings = nullptr, const IfcUtil::IfcBaseInterface* instance = nullptr); - piecewise_function(double start, const std::vector& pwfs, ifcopenshell::geometry::Settings* settings = nullptr, const IfcUtil::IfcBaseInterface* instance = nullptr); + piecewise_function(double start, const spans_t& s, const IfcUtil::IfcBaseInterface* instance = nullptr); + piecewise_function(double start, const std::vector& pwfs, const IfcUtil::IfcBaseInterface* instance = nullptr); piecewise_function(piecewise_function&&) = default; piecewise_function(const piecewise_function&); virtual ~piecewise_function(); - const ifcopenshell::geometry::Settings* settings_ = nullptr; - const spans_t& spans() const; bool is_empty() const; double start() const; @@ -379,33 +375,6 @@ typedef item const* ptr; return boost::hash{}(v); } - /// @brief returns a vector of "distance along" points where the evaluate function computes loop points - std::vector evaluation_points() const; - - /// @brief returns a vector of "distance along" points between ustart and uend - /// @param ustart starting location - /// @param uend ending location - /// @param nsteps number of steps to evaluate - std::vector evaluation_points(double ustart, double uend, unsigned nsteps) const; - - /// @brief evaluates the piecewise function between start and end - /// evaluation point step size is taken from the settings object - item::ptr evaluate() const override; - - /// @brief evaluates the piecewise function between ustart and uend - /// if ustart and uend are out of range, the range of values evaluated - /// are constrained to start_ and start_+length_ - /// @param ustart starting location - /// @param uend ending location - /// @param nsteps number of steps to evaluate - /// @return taxonomy::loop::ptr - item::ptr evaluate(double ustart, double uend, unsigned nsteps) const; - - /// @brief evaluates the piecewise function at u - /// @param u u is constrained to be between start_ and start_+length - /// @return 4x4 placement matrix - Eigen::Matrix4d evaluate(double u) const; - private: // note: it would be better if this were a std::unique_ptr, but that requires having the full definition // of piecewise_function_impl in this header file, which defeats the purpose of the PIMPL idiom. diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index 0f26e28db7..2b2178e125 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -246,6 +246,7 @@ namespace { %include "../ifcgeom/Iterator.h" %include "../ifcgeom/GeometrySerializer.h" %include "../ifcgeom/taxonomy.h" +%include "../ifcgeom/piecewise_function_evaluator.h" %include "../serializers/SvgSerializer.h" %include "../serializers/HdfSerializer.h" diff --git a/src/ifcwrap/IfcPython.i b/src/ifcwrap/IfcPython.i index b3b6cc3a85..f70388663d 100644 --- a/src/ifcwrap/IfcPython.i +++ b/src/ifcwrap/IfcPython.i @@ -84,6 +84,7 @@ %{ #include "../ifcgeom/Iterator.h" #include "../ifcgeom/taxonomy.h" + #include "../ifcgeom/piecewise_function_evaluator.h" #ifdef IFOPSH_WITH_OPENCASCADE #include "../ifcgeom/Serialization/Serialization.h" #include "../ifcgeom/kernels/opencascade/IfcGeomTree.h" @@ -159,6 +160,7 @@ %module ifcopenshell_wrapper %{ #include "../ifcgeom/Converter.h" #include "../ifcgeom/taxonomy.h" + #include "../ifcgeom/piecewise_function_evaluator.h" #ifdef IFOPSH_WITH_OPENCASCADE #include "../ifcgeom/Serialization/Serialization.h" #include "../ifcgeom/kernels/opencascade/IfcGeomTree.h"