mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-31 00:46:36 +00:00
Merge branch 'v0.8.0' into tfk-unify-variant-storage
This commit is contained in:
@@ -391,6 +391,31 @@ bool IfcGeom::OpenCascadeKernel::convert_openings(const IfcUtil::IfcBaseEntity*
|
||||
return true;
|
||||
}
|
||||
|
||||
#include <BRepPrimAPI_MakeRevol.hxx>
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert_impl(const taxonomy::revolve::ptr r, IfcGeom::ConversionResults& results) {
|
||||
|
||||
|
||||
gp_Ax1 ax(
|
||||
convert_xyz<gp_Pnt>(*r->axis_origin),
|
||||
convert_xyz<gp_Dir>(*r->direction));
|
||||
|
||||
TopoDS_Shape face;
|
||||
if (!convert(taxonomy::cast<taxonomy::face>(r->basis), face)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TopoDS_Shape shape = BRepPrimAPI_MakeRevol(face, ax);
|
||||
|
||||
results.emplace_back(ConversionResult(
|
||||
r->instance->data().id(),
|
||||
r->matrix,
|
||||
new OpenCascadeShape(shape),
|
||||
r->surface_style
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
// IfcSchema::IfcRelVoidsElement::list::ptr IfcGeom::Kernel::find_openings(IfcSchema::IfcProduct* product) {
|
||||
// std::vector<IfcSchema::IfcRelVoidsElement*> rs;
|
||||
//
|
||||
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
{}
|
||||
|
||||
bool convert(const ifcopenshell::geometry::taxonomy::extrusion::ptr, TopoDS_Shape&);
|
||||
bool convert(const ifcopenshell::geometry::taxonomy::face::ptr, TopoDS_Shape&);
|
||||
bool convert(const ifcopenshell::geometry::taxonomy::face::ptr, TopoDS_Shape&, bool reversed_surface = false);
|
||||
bool convert(const ifcopenshell::geometry::taxonomy::loop::ptr, TopoDS_Wire&);
|
||||
bool convert(const ifcopenshell::geometry::taxonomy::matrix4::ptr, gp_GTrsf&);
|
||||
bool convert(const ifcopenshell::geometry::taxonomy::shell::ptr, TopoDS_Shape&);
|
||||
@@ -143,6 +143,7 @@ public:
|
||||
virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::solid::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::shell::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::extrusion::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::revolve::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::boolean_result::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::loft::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::sweep_along_curve::ptr, IfcGeom::ConversionResults&);
|
||||
|
||||
@@ -229,7 +229,7 @@ Handle(Geom_Surface) OpenCascadeKernel::convert_surface(const taxonomy::ptr surf
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& result) {
|
||||
bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& result, bool reversed_surface) {
|
||||
#ifdef IFOPSH_DEBUG
|
||||
std::ostringstream oss;
|
||||
face->print(oss);
|
||||
@@ -382,7 +382,11 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
}
|
||||
}
|
||||
} else if (!fd.all_outer()) {
|
||||
BRepBuilderAPI_MakeFace mf(fd.surface(), fd.outer_wire());
|
||||
auto surf = fd.surface();
|
||||
if (reversed_surface) {
|
||||
surf = surf->UReversed();
|
||||
}
|
||||
BRepBuilderAPI_MakeFace mf(surf, fd.outer_wire());
|
||||
|
||||
if (mf.IsDone()) {
|
||||
// Is this necessary
|
||||
@@ -434,10 +438,20 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
for (; jt.More(); jt.Next()) {
|
||||
Message_ListIteratorOfListOfMsg kt(jt.Value());
|
||||
for (; kt.More(); kt.Next()) {
|
||||
char* c = new char[kt.Value().Value().LengthOfCString() + 1];
|
||||
kt.Value().Value().ToUTF8CString(c);
|
||||
Logger::Notice(c, face->instance);
|
||||
char* c = new char[kt.Value().Original().LengthOfCString() + 1];
|
||||
kt.Value().Original().ToUTF8CString(c);
|
||||
std::string message = c;
|
||||
delete[] c;
|
||||
#if OCC_VERSION_MAJOR==7 && OCC_VERSION_MINOR == 7
|
||||
if (!reversed_surface && !fd.surface().IsNull() && fd.surface()->IsUPeriodic() && message == "Unknown message invoked with the keyword FixAdvFace.FixOrientation.MSG0") {
|
||||
Logger::Notice("Detected reversed wire, reattempting with reversed basis surface");
|
||||
TopoDS_Face reversed_result;
|
||||
convert(face, reversed_result, true);
|
||||
result = reversed_result;
|
||||
return true;
|
||||
} else
|
||||
#endif
|
||||
Logger::Warning(message, face->instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) {
|
||||
return loop;
|
||||
}
|
||||
else {
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(pwfs,&settings_,inst);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(0.0,pwfs,&settings_,inst);
|
||||
return pwf;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -888,9 +888,9 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCurveSegment* inst) {
|
||||
|
||||
auto length = cse.length();
|
||||
|
||||
taxonomy::piecewise_function::spans spans;
|
||||
taxonomy::piecewise_function::spans_t spans;
|
||||
spans.emplace_back(fabs(length), fn);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(spans,&settings_,inst);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(0.0, spans,&settings_,inst);
|
||||
return pwf;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,11 +27,9 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) {
|
||||
if (!inst->BaseCurve()->as<IfcSchema::IfcCompositeCurve>())
|
||||
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 segments = inst->Segments();
|
||||
|
||||
std::vector<taxonomy::piecewise_function::ptr> pwfs;
|
||||
std::vector<taxonomy::piecewise_function::ptr> pwfs;
|
||||
|
||||
for (auto& segment : *segments) {
|
||||
if (segment->as<IfcSchema::IfcCurveSegment>()) {
|
||||
@@ -48,11 +46,33 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
auto vertical = taxonomy::make<taxonomy::piecewise_function>(pwfs,&settings_);
|
||||
|
||||
// Get starting position of gradient curve, which is relative to the base curve
|
||||
// The gradient curve can start before or after the start of the base curve
|
||||
auto first_segment = *(segments->begin());
|
||||
auto p = taxonomy::cast<taxonomy::matrix4>(map(first_segment->as<IfcSchema::IfcCurveSegment>()->Placement()));
|
||||
const Eigen::Matrix4d& m = p->ccomponents();
|
||||
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<taxonomy::piecewise_function>(gradient_start, pwfs, &settings_);
|
||||
|
||||
// Determine the valid domain of the PWF... the valid domain is where both
|
||||
// the base curve and gradient curves are defined
|
||||
auto horizontal = taxonomy::cast<taxonomy::piecewise_function>(map(inst->BaseCurve()));
|
||||
double start = std::max(horizontal->start(),vertical->start());
|
||||
double end = std::min(horizontal->end(), vertical->end());
|
||||
double length = end - start;
|
||||
|
||||
if (!(0 < length)) {
|
||||
Logger::Error("IfcGradientCurve does not have a common domain with BaseCurve");
|
||||
}
|
||||
|
||||
// define the callback function for the gradient curve
|
||||
auto composition = [horizontal, vertical](double u)->Eigen::Matrix4d {
|
||||
auto xy = horizontal->evaluate(u);
|
||||
// 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);
|
||||
|
||||
uz.col(3)(0) = 0.0; // x is distance along. zero it out so it doesn't add to the x from horizontal
|
||||
@@ -64,11 +84,9 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) {
|
||||
return m;
|
||||
};
|
||||
|
||||
double min_length = std::min(horizontal->length(), vertical->length());
|
||||
|
||||
taxonomy::piecewise_function::spans spans;
|
||||
spans.emplace_back(min_length, composition);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(spans, &settings_, inst);
|
||||
taxonomy::piecewise_function::spans_t spans;
|
||||
spans.emplace_back(length, composition);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(start, spans, &settings_, inst);
|
||||
return pwf;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,11 +38,12 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
|
||||
auto first_offset_value = *(offset_values->begin());
|
||||
|
||||
auto basis_curve = inst->BasisCurve();
|
||||
//auto pw_curve = ifcopenshell::geometry::piecewise_from_item(map(basis_curve));
|
||||
auto pw_curve = taxonomy::dcast<taxonomy::piecewise_function>(map(basis_curve));
|
||||
|
||||
double start = pw_curve->start();
|
||||
double basis_curve_length = pw_curve->length();
|
||||
|
||||
taxonomy::piecewise_function::spans offset_spans;
|
||||
taxonomy::piecewise_function::spans_t offset_spans;
|
||||
|
||||
#if defined SCHEMA_HAS_IfcDistanceExpression
|
||||
double first_distance = first_offset_value->DistanceAlong();
|
||||
@@ -143,7 +144,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
|
||||
offset_spans.emplace_back(l, fn);
|
||||
}
|
||||
|
||||
auto offsets = taxonomy::make<taxonomy::piecewise_function>(offset_spans,&settings_);
|
||||
auto offsets = taxonomy::make<taxonomy::piecewise_function>(start,offset_spans,&settings_);
|
||||
|
||||
auto composition = [pw_curve, offsets](double u) -> Eigen::Matrix4d {
|
||||
auto p = pw_curve->evaluate(u);
|
||||
@@ -154,9 +155,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
|
||||
taxonomy::piecewise_function::spans spans;
|
||||
taxonomy::piecewise_function::spans_t spans;
|
||||
spans.emplace_back(basis_curve_length, composition);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(spans,&settings_,inst);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(start,spans,&settings_,inst);
|
||||
return pwf;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,6 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins
|
||||
if (!inst->BaseCurve()->as<IfcSchema::IfcGradientCurve>())
|
||||
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 segments = inst->Segments();
|
||||
|
||||
std::vector<taxonomy::piecewise_function::ptr> pwfs;
|
||||
@@ -46,11 +44,34 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins
|
||||
Logger::Error("Unsupported");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
auto cant = taxonomy::make<taxonomy::piecewise_function>(pwfs,&settings_);
|
||||
}
|
||||
|
||||
// Get starting position of cant curve, relative to the gradient curve.
|
||||
// The cant curve can start before or after the start of the gradient curve
|
||||
auto first_segment = *(segments->begin());
|
||||
auto p = taxonomy::cast<taxonomy::matrix4>(map(first_segment->as<IfcSchema::IfcCurveSegment>()->Placement()));
|
||||
const Eigen::Matrix4d& m = p->ccomponents();
|
||||
double cant_start = m(0, 3); // start of cant curve
|
||||
|
||||
auto cant = taxonomy::make<taxonomy::piecewise_function>(cant_start,pwfs,&settings_);
|
||||
|
||||
// Determine the valid domain of the PWF... the valid domain is where
|
||||
// horizontal, gradient and cant curves are defined
|
||||
auto gradient = taxonomy::cast<taxonomy::piecewise_function>(map(inst->BaseCurve()));
|
||||
auto horizontal = taxonomy::cast<taxonomy::piecewise_function>(map(inst->BaseCurve()->as<IfcSchema::IfcGradientCurve>()->BaseCurve()));
|
||||
double start = std::max(std::max(cant->start(), gradient->start()), horizontal->start());
|
||||
double end = std::min(std::min(cant->end(), gradient->end()), horizontal->end());
|
||||
double length = end - start;
|
||||
|
||||
if (!(0 < length)) {
|
||||
Logger::Error("IfcSegmentedReferenceCurve does not have a common domain with BaseCurve");
|
||||
}
|
||||
|
||||
// define the callback function for the segmented reference curve
|
||||
auto composition = [gradient, cant](double u)->Eigen::Matrix4d {
|
||||
auto g = gradient->evaluate(u);
|
||||
// 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);
|
||||
|
||||
c.col(3)(0) = 0.0; // x is distance along. zero it out so it doesn't add to the x from gradient curve
|
||||
@@ -62,11 +83,9 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins
|
||||
return m;
|
||||
};
|
||||
|
||||
double min_length = std::min(gradient->length(), cant->length());
|
||||
|
||||
taxonomy::piecewise_function::spans spans;
|
||||
spans.emplace_back(min_length, composition);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(spans, &settings_, inst);
|
||||
taxonomy::piecewise_function::spans_t spans;
|
||||
spans.emplace_back(length, composition);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(start, spans, &settings_, inst);
|
||||
return pwf;
|
||||
}
|
||||
|
||||
|
||||
@@ -299,14 +299,45 @@ const IfcUtil::IfcBaseEntity* mapping::get_single_material_association(const Ifc
|
||||
single_material = associated_material->as<IfcSchema::IfcMaterial>();
|
||||
// NB: Single-layer layersets are also considered, regardless of --enable-layerset-slicing, this
|
||||
// in accordance with other viewers.
|
||||
if (!single_material && associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()) {
|
||||
IfcSchema::IfcMaterialLayerSet* layerset = associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()->ForLayerSet();
|
||||
if (settings_.get<settings::LayersetFirst>().value ? layerset->MaterialLayers()->size() >= 1 : layerset->MaterialLayers()->size() == 1) {
|
||||
IfcSchema::IfcMaterialLayer* layer = (*layerset->MaterialLayers()->begin());
|
||||
if (layer->Material()) {
|
||||
single_material = layer->Material();
|
||||
if (!single_material) {
|
||||
if (associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>() || associated_material->as<IfcSchema::IfcMaterialLayerSet>()) {
|
||||
IfcSchema::IfcMaterialLayerSet* layerset;
|
||||
if (auto *m = associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()) {
|
||||
if (m->get("ForLayerSet")->isNull()) {
|
||||
Logger::Warning("Missing ForLayerSet for:", m);
|
||||
return nullptr;
|
||||
}
|
||||
layerset = m->ForLayerSet();
|
||||
} else {
|
||||
layerset = associated_material->as<IfcSchema::IfcMaterialLayerSet>();
|
||||
}
|
||||
if (settings_.get<settings::LayersetFirst>().value ? layerset->MaterialLayers()->size() >= 1 : layerset->MaterialLayers()->size() == 1) {
|
||||
IfcSchema::IfcMaterialLayer* layer = (*layerset->MaterialLayers()->begin());
|
||||
if (auto *m_ = layer->Material()) {
|
||||
single_material = m_;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef SCHEMA_HAS_IfcMaterialProfileSet
|
||||
if (associated_material->as<IfcSchema::IfcMaterialProfileSetUsage>() || associated_material->as<IfcSchema::IfcMaterialProfileSet>()) {
|
||||
IfcSchema::IfcMaterialProfileSet* profileset;
|
||||
if (auto* m = associated_material->as<IfcSchema::IfcMaterialProfileSetUsage>()) {
|
||||
if (m->get("ForProfileSet")->isNull()) {
|
||||
Logger::Warning("Missing ForProfileSet for:", m);
|
||||
return nullptr;
|
||||
}
|
||||
profileset = m->ForProfileSet();
|
||||
} else {
|
||||
profileset = associated_material->as<IfcSchema::IfcMaterialProfileSet>();
|
||||
}
|
||||
if (settings_.get<settings::LayersetFirst>().value ? profileset->MaterialProfiles()->size() >= 1 : profileset->MaterialProfiles()->size() == 1) {
|
||||
IfcSchema::IfcMaterialProfile* profile = (*profileset->MaterialProfiles()->begin());
|
||||
if (auto *m_ = profile->Material()) {
|
||||
single_material = m_;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -581,6 +612,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcStyledItem* inst) {
|
||||
taxonomy::ptr mapping::map(const IfcBaseInterface* inst) {
|
||||
auto iden = inst->as<IfcUtil::IfcBaseClass>()->identity();
|
||||
if (use_caching_) {
|
||||
std::lock_guard<std::mutex> guard(cache_guard_);
|
||||
auto it = cache_.find(iden);
|
||||
if (it != cache_.end()) {
|
||||
return it->second;
|
||||
@@ -598,7 +630,8 @@ taxonomy::ptr mapping::map(const IfcBaseInterface* inst) {
|
||||
|
||||
if (item) {
|
||||
if (use_caching_) {
|
||||
cache_.insert({ iden, item });
|
||||
std::lock_guard<std::mutex> guard(cache_guard_);
|
||||
cache_.insert({iden, item});
|
||||
}
|
||||
} else if (!matched) {
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", inst);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
#include "../../ifcparse/IfcLogger.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
@@ -24,6 +26,7 @@ namespace geometry {
|
||||
std::string length_unit_name_;
|
||||
|
||||
std::map<uint32_t, ifcopenshell::geometry::taxonomy::ptr> cache_;
|
||||
std::mutex cache_guard_; // provides mutually exclusive access to cache_
|
||||
|
||||
const IfcParse::declaration* placement_rel_to_type_;
|
||||
const IfcUtil::IfcBaseEntity* placement_rel_to_instance_;
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "piecewise_function_impl.h"
|
||||
#include "profile_helper.h"
|
||||
|
||||
namespace ifcopenshell {
|
||||
|
||||
namespace geometry {
|
||||
|
||||
namespace taxonomy {
|
||||
|
||||
std::vector<double> ifcopenshell::geometry::taxonomy::piecewise_function_impl::evaluation_points() const {
|
||||
if (!eval_points_.has_value()) {
|
||||
double curve_length = length();
|
||||
|
||||
auto param_type = settings_ ? settings_->get<ifcopenshell::geometry::settings::PiecewiseStepType>().get() : ifcopenshell::geometry::settings::PiecewiseStepMethod::MAXSTEPSIZE;
|
||||
auto param = settings_ ? settings_->get<ifcopenshell::geometry::settings::PiecewiseStepParam>().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);
|
||||
}
|
||||
return *eval_points_;
|
||||
}
|
||||
|
||||
std::vector<double> 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);
|
||||
|
||||
nsteps = std::max(1u, nsteps); // never have fewer than 1 step
|
||||
|
||||
auto resolution = (uend - ustart) / nsteps;
|
||||
|
||||
std::vector<double> 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;
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::taxonomy::item::ptr ifcopenshell::geometry::taxonomy::piecewise_function_impl::evaluate() const {
|
||||
return evaluate(evaluation_points());
|
||||
}
|
||||
|
||||
item::ptr ifcopenshell::geometry::taxonomy::piecewise_function_impl::evaluate(double ustart, double uend, unsigned nsteps) const {
|
||||
return evaluate(evaluation_points(ustart, uend, nsteps));
|
||||
}
|
||||
|
||||
item::ptr ifcopenshell::geometry::taxonomy::piecewise_function_impl::evaluate(const std::vector<double>& dist) const {
|
||||
std::vector<taxonomy::point3::ptr> polygon;
|
||||
polygon.reserve(dist.size());
|
||||
for (auto& u : dist) {
|
||||
Eigen::Matrix4d m = evaluate(u);
|
||||
polygon.push_back(taxonomy::make<taxonomy::point3>(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<double, double, const std::function<Eigen::Matrix4d(double u)>*> 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<ifcopenshell::geometry::settings::Precision>().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};
|
||||
}
|
||||
|
||||
} // namespace taxonomy
|
||||
|
||||
} // namespace geometry
|
||||
|
||||
} // namespace ifcopenshell
|
||||
@@ -0,0 +1,93 @@
|
||||
#ifndef PIECEWISE_FUNCTION_IMPL
|
||||
#define PIECEWISE_FUNCTION_IMPL
|
||||
|
||||
#include "taxonomy.h"
|
||||
|
||||
namespace ifcopenshell {
|
||||
|
||||
namespace geometry {
|
||||
|
||||
namespace taxonomy {
|
||||
|
||||
struct piecewise_function_impl {
|
||||
using spans_t = std::vector<std::pair<double, std::function<Eigen::Matrix4d(double u)>>>;
|
||||
|
||||
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<piecewise_function::ptr>& 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(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<double> 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<double> 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;
|
||||
|
||||
private:
|
||||
item::ptr evaluate(const std::vector<double>& dist) const;
|
||||
std::tuple<double, double, const std::function<Eigen::Matrix4d(double u)>*> 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<Eigen::Matrix4d(double u)>* current_span_fn_ = nullptr;
|
||||
mutable boost::optional<double> length_;
|
||||
mutable boost::optional<std::vector<double>> eval_points_;
|
||||
};
|
||||
|
||||
} // namespace taxonomy
|
||||
} // namespace geometry
|
||||
} // namespace ifcopenshell
|
||||
#endif PIECEWISE_FUNCTION_IMPL
|
||||
+21
-74
@@ -1,6 +1,7 @@
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
#include "taxonomy.h"
|
||||
#include "profile_helper.h"
|
||||
#include "piecewise_function_impl.h"
|
||||
|
||||
using namespace ifcopenshell::geometry::taxonomy;
|
||||
|
||||
@@ -462,88 +463,34 @@ ifcopenshell::geometry::taxonomy::solid::ptr ifcopenshell::geometry::create_box(
|
||||
return solid;
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::taxonomy::item::ptr ifcopenshell::geometry::taxonomy::piecewise_function::evaluate() const {
|
||||
return evaluate2().first;
|
||||
///////////////////
|
||||
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);
|
||||
}
|
||||
|
||||
std::pair<item::ptr, std::vector<double>> ifcopenshell::geometry::taxonomy::piecewise_function::evaluate2() const {
|
||||
double curve_length = length();
|
||||
piecewise_function::piecewise_function(double start, const std::vector<piecewise_function::ptr>& pwfs, ifcopenshell::geometry::Settings* settings, const IfcUtil::IfcBaseInterface* instance) : implicit_item(instance) {
|
||||
impl_ = new piecewise_function_impl(start, pwfs, settings);
|
||||
};
|
||||
|
||||
std::vector<taxonomy::point3::ptr> polygon;
|
||||
|
||||
auto param_type = settings_ ? settings_->get<ifcopenshell::geometry::settings::PiecewiseStepType>().get() : ifcopenshell::geometry::settings::PiecewiseStepMethod::MAXSTEPSIZE;
|
||||
auto param = settings_ ? settings_->get<ifcopenshell::geometry::settings::PiecewiseStepParam>().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);
|
||||
}
|
||||
|
||||
num_steps = std::max(1u, num_steps); // never have fewer than 1 step
|
||||
|
||||
return evaluate2(0.0, curve_length, num_steps);
|
||||
piecewise_function::piecewise_function(const piecewise_function& other) : implicit_item(other) {
|
||||
impl_ = other.impl_->clone_();
|
||||
}
|
||||
|
||||
item::ptr ifcopenshell::geometry::taxonomy::piecewise_function::evaluate(double ustart, double uend,unsigned nsteps) const {
|
||||
return evaluate2(ustart, uend, nsteps).first;
|
||||
piecewise_function::~piecewise_function() {
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
std::pair<item::ptr, std::vector<double>> ifcopenshell::geometry::taxonomy::piecewise_function::evaluate2(double ustart, double uend, unsigned nsteps) const {
|
||||
double curve_length = length();
|
||||
ustart = std::max(0.0, ustart);
|
||||
uend = std::min(uend, curve_length);
|
||||
const piecewise_function::spans_t& piecewise_function::spans() const { return impl_->spans(); }
|
||||
bool piecewise_function::is_empty() const { return impl_->is_empty(); }
|
||||
double piecewise_function::start() const { return impl_->start(); }
|
||||
double piecewise_function::end() const { return impl_->end(); }
|
||||
double piecewise_function::length() const { return impl_->length(); }
|
||||
|
||||
auto resolution = (uend - ustart) / nsteps;
|
||||
|
||||
std::vector<taxonomy::point3::ptr> polygon;
|
||||
std::vector<double> u_values;
|
||||
polygon.reserve(nsteps);
|
||||
u_values.reserve(nsteps);
|
||||
|
||||
for (unsigned i = 0; i <= nsteps; ++i) {
|
||||
auto u = resolution * i + ustart;
|
||||
u_values.push_back(u);
|
||||
Eigen::Matrix4d m = evaluate(u);
|
||||
polygon.push_back(taxonomy::make<taxonomy::point3>(m.col(3)(0), m.col(3)(1), m.col(3)(2)));
|
||||
}
|
||||
|
||||
return {polygon_from_points(polygon), u_values};
|
||||
}
|
||||
|
||||
Eigen::Matrix4d ifcopenshell::geometry::taxonomy::piecewise_function::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<double, double, const std::function<Eigen::Matrix4d(double u)>*> ifcopenshell::geometry::taxonomy::piecewise_function::get_span(double u) const {
|
||||
// force u to be within bounds of the curve
|
||||
double curve_length = length();
|
||||
u = std::max(0.0, u);
|
||||
u = std::min(u, curve_length);
|
||||
|
||||
double start = 0;
|
||||
for (auto& [length, fn] : spans_) {
|
||||
auto tolerance = settings_ ? settings_->get<ifcopenshell::geometry::settings::Precision>().get() : 0.001;
|
||||
if (u < length + tolerance) {
|
||||
return {start, start+length, &fn} ;
|
||||
}
|
||||
start += length;
|
||||
u -= length;
|
||||
}
|
||||
|
||||
Logger::Error("taxonomy::piecewise_function::get_span span not found.");
|
||||
return {0, 0, nullptr};
|
||||
}
|
||||
std::vector<double> piecewise_function::evaluation_points() const { return impl_->evaluation_points(); }
|
||||
std::vector<double> 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<taxonomy::collection>();
|
||||
|
||||
+36
-41
@@ -351,71 +351,66 @@ typedef item const* ptr;
|
||||
virtual item::ptr evaluate() const = 0;
|
||||
};
|
||||
|
||||
struct piecewise_function_impl; // forward declaration
|
||||
struct piecewise_function : public implicit_item {
|
||||
DECLARE_PTR(piecewise_function)
|
||||
|
||||
using spans = std::vector<std::pair<double, std::function<Eigen::Matrix4d(double u)>>>;
|
||||
using spans_t = std::vector<std::pair<double, std::function<Eigen::Matrix4d(double u)>>>;
|
||||
|
||||
piecewise_function(const spans& s, ifcopenshell::geometry::Settings* settings = nullptr, const IfcUtil::IfcBaseInterface* instance = nullptr) :
|
||||
implicit_item(instance), settings_(settings), spans_(s){};
|
||||
piecewise_function(const std::vector<piecewise_function::ptr>& pwfs, ifcopenshell::geometry::Settings* settings = nullptr, const IfcUtil::IfcBaseInterface* instance = nullptr) :
|
||||
implicit_item(instance), settings_(settings)
|
||||
{
|
||||
for (auto& pwf : pwfs) {
|
||||
spans_.insert(spans_.end(), pwf->spans_.begin(), pwf->spans_.end());
|
||||
}
|
||||
};
|
||||
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<piecewise_function::ptr>& pwfs, ifcopenshell::geometry::Settings* settings = nullptr, const IfcUtil::IfcBaseInterface* instance = nullptr);
|
||||
piecewise_function(piecewise_function&&) = default;
|
||||
piecewise_function(const piecewise_function&) = default;
|
||||
piecewise_function(const piecewise_function&);
|
||||
virtual ~piecewise_function();
|
||||
|
||||
const ifcopenshell::geometry::Settings* settings_ = nullptr;
|
||||
|
||||
bool is_empty() const { return spans_.empty(); }
|
||||
|
||||
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_;
|
||||
}
|
||||
const spans_t& spans() const;
|
||||
bool is_empty() const;
|
||||
double start() const;
|
||||
double end() const;
|
||||
double length() const;
|
||||
|
||||
virtual piecewise_function* clone_() const { return new piecewise_function(*this); }
|
||||
virtual kinds kind() const { return PIECEWISE_FUNCTION; }
|
||||
|
||||
virtual size_t calc_hash() const {
|
||||
virtual size_t calc_hash() const {
|
||||
auto v = std::make_tuple(static_cast<size_t>(PIECEWISE_FUNCTION), 0);
|
||||
return boost::hash<decltype(v)>{}(v);
|
||||
}
|
||||
|
||||
item::ptr evaluate() const override;
|
||||
std::pair<item::ptr,std::vector<double>> evaluate2() const;
|
||||
/// @brief returns a vector of "distance along" points where the evaluate function computes loop points
|
||||
std::vector<double> 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<double> 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
|
||||
/// @param ustart starting location - taken as 0.0 if before start
|
||||
/// @param uend ending location - taken as length if beyond end
|
||||
/// 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 between ustart and uend
|
||||
/// @param ustart starting location - taken as 0.0 if before start
|
||||
/// @param uend ending location - taken as length if beyond end
|
||||
/// @param nsteps number of steps to evaluate
|
||||
/// @return taxonomy::loop::ptr and vector of u values
|
||||
std::pair<item::ptr, std::vector<double>> evaluate2(double ustart, double uend, unsigned nsteps) const;
|
||||
|
||||
/// @brief evaluates the piecewise function at u
|
||||
/// @param u u is constrained to be between 0 and length
|
||||
/// @param u u is constrained to be between start_ and start_+length
|
||||
/// @return 4x4 placement matrix
|
||||
Eigen::Matrix4d evaluate(double u) const;
|
||||
|
||||
private:
|
||||
std::tuple<double, double, const std::function<Eigen::Matrix4d(double u)>*> get_span(double u) const;
|
||||
spans spans_;
|
||||
mutable double current_span_start_ = 0;
|
||||
mutable double current_span_end_ = 0;
|
||||
mutable const std::function<Eigen::Matrix4d(double u)>* current_span_fn_ = nullptr;
|
||||
mutable boost::optional<double> length_;
|
||||
// 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.
|
||||
// if this is a std::unique_ptr, then the _ifcopenshell_wrapper library doesn't compile
|
||||
piecewise_function_impl* impl_ = nullptr;
|
||||
};
|
||||
|
||||
#ifdef TAXONOMY_USE_SHARED_PTR
|
||||
@@ -1313,14 +1308,14 @@ typedef item const* ptr;
|
||||
boost::optional<taxonomy::piecewise_function::ptr> pwf_;
|
||||
|
||||
public:
|
||||
loop_to_piecewise_function_upgrade(taxonomy::ptr item) {
|
||||
loop_to_piecewise_function_upgrade(taxonomy::ptr item) {
|
||||
if constexpr (std::is_same_v<T, piecewise_function>) {
|
||||
auto loop = taxonomy::dcast<taxonomy::loop>(item);
|
||||
if (loop) {
|
||||
if (loop->pwf.is_initialized()) {
|
||||
pwf_ = loop->pwf;
|
||||
} else {
|
||||
taxonomy::piecewise_function::spans spans;
|
||||
taxonomy::piecewise_function::spans_t spans;
|
||||
spans.reserve(loop->children.size());
|
||||
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
|
||||
@@ -1341,7 +1336,7 @@ typedef item const* ptr;
|
||||
};
|
||||
spans.emplace_back(l, fn);
|
||||
}
|
||||
pwf_ = taxonomy::make<taxonomy::piecewise_function>(spans);
|
||||
pwf_ = taxonomy::make<taxonomy::piecewise_function>(0.0,spans);
|
||||
loop->pwf = pwf_;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user