Updates taxonomy::piecewise_function so it's immutable and implements internal caching. Adds new evaluate2 method that returns loop and vector of distance along for each loop point.

This commit is contained in:
Richard Brice
2024-05-07 10:24:46 -07:00
parent e0a9f44c13
commit a0b4c24224
8 changed files with 134 additions and 98 deletions
+5 -7
View File
@@ -23,7 +23,7 @@ using namespace ifcopenshell::geometry;
taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) {
auto loop = taxonomy::make<taxonomy::loop>();
auto pwf = taxonomy::make<taxonomy::piecewise_function>(&settings_);
std::vector<taxonomy::piecewise_function::ptr> pwfs;
#ifdef SCHEMA_HAS_IfcSegment
// 4x3
@@ -31,8 +31,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) {
#else
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = inst->Segments();
#endif
current_segment_count_ = segments->size();
for (auto& segment : *segments) {
if (segment->as<IfcSchema::IfcCompositeCurveSegment>() && segment->as<IfcSchema::IfcCompositeCurveSegment>()->ParentCurve()->as<IfcSchema::IfcLine>()) {
Logger::Notice("Infinite IfcLine used as ParentCurve of segment, treating as a segment", segment);
@@ -78,8 +77,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) {
}
}
else if (crv && crv->kind() == taxonomy::PIECEWISE_FUNCTION) {
auto seg = taxonomy::cast<taxonomy::piecewise_function>(crv);
pwf->spans.insert(pwf->spans.end(), seg->spans.begin(), seg->spans.end());
pwfs.push_back(taxonomy::cast<taxonomy::piecewise_function>(crv));
} else if (!crv) {
return nullptr;
}
@@ -87,7 +85,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) {
#endif
}
if (pwf->spans.empty()) {
if (pwfs.empty()) {
aggregate_of_instance::ptr profile = inst->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1);
const bool force_close = profile && profile->size() > 0;
loop->closed = force_close;
@@ -95,7 +93,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) {
return loop;
}
else {
pwf->instance = inst;
auto pwf = taxonomy::make<taxonomy::piecewise_function>(pwfs,&settings_,inst);
return pwf;
}
}
+8 -10
View File
@@ -103,7 +103,6 @@ class curve_segment_evaluator {
double length_; // length along the curve, as provided from the IfcCurveSegment
segment_type_t segment_type_;
const IfcSchema::IfcCurve* parent_curve_ = nullptr;
size_t current_segment_count_;
double projected_length_; // for vertical segments, this is the length of curve projected onto the "Distance Along" axis
@@ -111,13 +110,12 @@ class curve_segment_evaluator {
std::optional<Eigen::Matrix4d> parent_curve_placement_; // placement matrix for the parent curve
public:
curve_segment_evaluator(mapping* mapping, const IfcSchema::IfcCurveSegment* inst, double length_unit, segment_type_t segment_type, size_t current_segment_count)
curve_segment_evaluator(mapping* mapping, const IfcSchema::IfcCurveSegment* inst, double length_unit, segment_type_t segment_type)
: mapping_(mapping),
inst_(inst),
length_unit_(length_unit),
segment_type_(segment_type),
parent_curve_(inst->ParentCurve()),
current_segment_count_(current_segment_count) {
parent_curve_(inst->ParentCurve()) {
start_ = translate_if_param_value(inst->ParentCurve(), inst->SegmentStart()) * length_unit;
length_ = translate_if_param_value(inst->ParentCurve(), inst->SegmentLength()) * length_unit;
}
@@ -734,7 +732,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCurveSegment* inst) {
auto segment_type = is_horizontal ? ST_HORIZONTAL : is_vertical ? ST_VERTICAL : ST_CANT;
curve_segment_evaluator cse(this, inst, length_unit_, segment_type, current_segment_count_);
curve_segment_evaluator cse(this, inst, length_unit_, segment_type);
boost::mpl::for_each<curve_seg_types, boost::type<boost::mpl::_>>(std::ref(cse));
const auto& parent_curve_fn = cse.parent_curve_function();
const auto& parent_curve_placement = cse.parent_curve_placement();
@@ -772,11 +770,11 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCurveSegment* inst) {
return curve_segment_placement * rotation * translation * p;
};
// @todo it might be suboptimal that we no longer have the spans now
auto pwf = taxonomy::make<taxonomy::piecewise_function>(&settings_);
auto length = fabs(cse.length());
pwf->spans.push_back({length, fn});
pwf->instance = inst;
auto length = cse.length();
taxonomy::piecewise_function::spans spans;
spans.emplace_back(fabs(length), fn);
auto pwf = taxonomy::make<taxonomy::piecewise_function>(spans,&settings_,inst);
return pwf;
}
+10 -23
View File
@@ -28,18 +28,17 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) {
Logger::Warning("Expected IfcGradientCurve.BaseCurve to be IfcCompositeCurve", inst); // CT 4.1.7.1.1.2
auto horizontal = taxonomy::cast<taxonomy::piecewise_function>(map(inst->BaseCurve()));
auto vertical = taxonomy::make<taxonomy::piecewise_function>(&settings_);
auto segments = inst->Segments();
current_segment_count_ = segments->size();
std::vector<taxonomy::piecewise_function::ptr> pwfs;
for (auto& segment : *segments) {
if (segment->as<IfcSchema::IfcCurveSegment>()) {
// @todo check that we don't get a mixture of implicit and explicit definitions
auto crv = map(segment->as<IfcSchema::IfcCurveSegment>());
if (crv && crv->kind() == taxonomy::PIECEWISE_FUNCTION) {
auto seg = taxonomy::cast<taxonomy::piecewise_function>(crv);
vertical->spans.insert(vertical->spans.end(), seg->spans.begin(), seg->spans.end());
pwfs.push_back(taxonomy::cast<taxonomy::piecewise_function>(crv));
} else {
Logger::Error("Unsupported");
return nullptr;
@@ -49,6 +48,8 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) {
return nullptr;
}
}
auto vertical = taxonomy::make<taxonomy::piecewise_function>(pwfs,&settings_);
auto composition = [horizontal, vertical](double u)->Eigen::Matrix4d {
auto xy = horizontal->evaluate(u);
@@ -63,26 +64,12 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) {
return m;
};
std::array<taxonomy::piecewise_function::ptr, 2> both = { horizontal , vertical };
// @todo: rb - this constrains the range of u to the minimum of horizontal and vertical
// we discussed using the maximum for the range of us and then using std::numeric_limits<double>::NAN
// for values of u that horizontal or vertical cannot be computed.
// Review and decide what to do.
double min_length = std::numeric_limits<double>::infinity();
for (auto i = 0; i < 2; ++i) {
double l = 0;
for (auto& s : both[i]->spans) {
l += s.first;
}
if (l < min_length) {
min_length = l;
}
}
double min_length = std::min(horizontal->length(), vertical->length());
auto pwf = taxonomy::make<taxonomy::piecewise_function>(&settings_);
pwf->spans.emplace_back( min_length, composition );
pwf->instance = inst;
return pwf;
taxonomy::piecewise_function::spans spans;
spans.emplace_back(min_length, composition);
auto pwf = taxonomy::make<taxonomy::piecewise_function>(spans, &settings_, inst);
return pwf;
}
#endif
@@ -42,7 +42,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
auto pw_curve = taxonomy::dcast<taxonomy::piecewise_function>(map(basis_curve));
double basis_curve_length = pw_curve->length();
auto offsets = taxonomy::make<taxonomy::piecewise_function>(&settings_);
taxonomy::piecewise_function::spans offset_spans;
#if defined SCHEMA_HAS_IfcDistanceExpression
double first_distance = first_offset_value->DistanceAlong();
@@ -63,12 +63,12 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
py *= length_unit_;
pz *= length_unit_;
auto fn = [py, pz](double u) -> Eigen::Matrix4d {
auto fn = [py, pz](double /*u*/) -> Eigen::Matrix4d {
Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
m.col(3)(1) = py;
m.col(3)(2) = pz;
return m; };
offsets->spans.push_back({first_distance, fn});
offset_spans.emplace_back(first_distance, fn);
}
auto iter = offset_values->begin();
@@ -112,7 +112,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
m.col(3)(2) = (l == 0.0 ? zp : (zp + (zn - zp) * u / l));
return m;
};
offsets->spans.push_back({l, fn});
offset_spans.emplace_back(l, fn);
}
// at this point, next == end and prev == end-1
@@ -134,15 +134,17 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
py *= length_unit_;
pz *= length_unit_;
double l = basis_curve_length - last_distance;
auto fn = [py, pz](double u) -> Eigen::Matrix4d {
auto fn = [py, pz](double /*u*/) -> Eigen::Matrix4d {
Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
m.col(3)(1) = py;
m.col(3)(2) = pz;
return m; };
offsets->spans.push_back({l, fn});
offset_spans.emplace_back(l, fn);
}
auto offsets = taxonomy::make<taxonomy::piecewise_function>(offset_spans,&settings_);
auto composition = [pw_curve, offsets](double u) -> Eigen::Matrix4d {
auto p = pw_curve->evaluate(u);
auto offset = offsets->evaluate(u);
@@ -152,9 +154,9 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
// 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<taxonomy::piecewise_function>(&settings_);
pwf->spans.emplace_back( basis_curve_length, composition );
pwf->instance = inst;
taxonomy::piecewise_function::spans spans;
spans.emplace_back(basis_curve_length, composition);
auto pwf = taxonomy::make<taxonomy::piecewise_function>(spans,&settings_,inst);
return pwf;
}
@@ -28,18 +28,16 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins
Logger::Warning("Expected IfcSegmentedReferenceCurve.BaseCurve to be IfcGradient", inst); // CT 4.1.7.1.1.3
auto gradient = taxonomy::cast<taxonomy::piecewise_function>(map(inst->BaseCurve()));
auto cant = taxonomy::make<taxonomy::piecewise_function>(&settings_);
auto segments = inst->Segments();
current_segment_count_ = segments->size();
for (auto& segment : *segments) {
std::vector<taxonomy::piecewise_function::ptr> pwfs;
for (auto& segment : *segments) {
if (segment->as<IfcSchema::IfcCurveSegment>()) {
// @todo check that we don't get a mixture of implicit and explicit definitions
auto crv = map(segment->as<IfcSchema::IfcCurveSegment>());
if (crv && crv->kind() == taxonomy::PIECEWISE_FUNCTION) {
auto seg = taxonomy::cast<taxonomy::piecewise_function>(crv);
cant->spans.insert(cant->spans.end(), seg->spans.begin(), seg->spans.end());
pwfs.push_back(taxonomy::cast<taxonomy::piecewise_function>(crv));
} else {
Logger::Error("Unsupported");
return nullptr;
@@ -49,6 +47,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins
return nullptr;
}
}
auto cant = taxonomy::make<taxonomy::piecewise_function>(pwfs,&settings_);
auto composition = [gradient, cant](double u)->Eigen::Matrix4d {
auto g = gradient->evaluate(u);
@@ -63,26 +62,12 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins
return m;
};
std::array<taxonomy::piecewise_function::ptr, 2> both = { gradient , cant };
// @todo: rb - this constrains the range of u to the minimum of gradient and cant
// we discussed using the maximum for the range of us and then using std::numeric_limits<double>::NAN
// for values of u that gradient or cant cannot be computed.
// Review and decide what to do.
double min_length = std::numeric_limits<double>::infinity();
for (auto i = 0; i < 2; ++i) {
double l = 0;
for (auto& s : both[i]->spans) {
l += s.first;
}
if (l < min_length) {
min_length = l;
}
}
double min_length = std::min(gradient->length(), cant->length());
auto pwf = taxonomy::make<taxonomy::piecewise_function>(&settings_);
pwf->spans.emplace_back( min_length, composition );
pwf->instance = inst;
return pwf;
taxonomy::piecewise_function::spans spans;
spans.emplace_back(min_length, composition);
auto pwf = taxonomy::make<taxonomy::piecewise_function>(spans, &settings_, inst);
return pwf;
}
#endif
-1
View File
@@ -22,7 +22,6 @@ namespace geometry {
IfcParse::IfcFile* file_;
double length_unit_, angle_unit_;
std::string length_unit_name_;
size_t current_segment_count_;
std::map<uint32_t, ifcopenshell::geometry::taxonomy::ptr> cache_;