Refactors alignment geometry

This commit is contained in:
Richard Brice
2025-01-02 11:10:56 -08:00
committed by GitHub
parent bb9be861c8
commit 26ba761c68
23 changed files with 948 additions and 555 deletions
+39 -3
View File
@@ -3,7 +3,7 @@
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/ConversionSettings.h"
#include "../ifcgeom/abstract_mapping.h"
#include "../ifcgeom/piecewise_function_evaluator.h"
#include "../ifcgeom/function_item_evaluator.h"
#ifdef IFOPSH_WITH_OPENCASCADE
#include "../ifcgeom/kernels/opencascade/OpenCascadeKernel.h"
@@ -71,6 +71,7 @@ bool is_valid_for_kernel(const ifcopenshell::geometry::kernels::AbstractKernel*
return dynamic_cast<ifcopenshell::geometry::CgalShape*>(shp.Shape().get()) != nullptr;
}
#endif
return false;
}
class HybridKernel : public ifcopenshell::geometry::kernels::AbstractKernel {
@@ -237,9 +238,44 @@ bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonom
return r.size() > s;
}
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::piecewise_function::ptr item, IfcGeom::ConversionResults& cs) {
piecewise_function_evaluator evaluator(item);
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::function_item::ptr item, IfcGeom::ConversionResults& cs) {
function_item_evaluator evaluator(settings(),item);
auto expl = evaluator.evaluate();
expl->instance = item->instance;
return convert(expl, cs);
}
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::functor_item::ptr item, IfcGeom::ConversionResults& cs) {
function_item_evaluator evaluator(settings(), item);
auto expl = evaluator.evaluate();
expl->instance = item->instance;
return convert(expl, cs);
}
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::piecewise_function::ptr item, IfcGeom::ConversionResults& cs) {
function_item_evaluator evaluator(settings(), item);
auto expl = evaluator.evaluate();
expl->instance = item->instance;
return convert(expl, cs);
}
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::gradient_function::ptr item, IfcGeom::ConversionResults& cs) {
function_item_evaluator evaluator(settings(), item);
auto expl = evaluator.evaluate();
expl->instance = item->instance;
return convert(expl, cs);
}
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::cant_function::ptr item, IfcGeom::ConversionResults& cs) {
function_item_evaluator evaluator(settings(), item);
auto expl = evaluator.evaluate();
expl->instance = item->instance;
return convert(expl, cs);
}
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::offset_function::ptr item, IfcGeom::ConversionResults& cs) {
function_item_evaluator evaluator(settings(), item);
auto expl = evaluator.evaluate();
expl->instance = item->instance;
return convert(expl, cs);
}
+6 -1
View File
@@ -76,7 +76,12 @@ namespace ifcopenshell {
virtual bool convert_impl(const taxonomy::sweep_along_curve::ptr, IfcGeom::ConversionResults&) { throw not_implemented_error(); }
virtual bool convert_impl(const taxonomy::loft::ptr, IfcGeom::ConversionResults&) { throw not_implemented_error(); }
virtual bool convert_impl(const taxonomy::collection::ptr, IfcGeom::ConversionResults&);
virtual bool convert_impl(const taxonomy::piecewise_function::ptr item, IfcGeom::ConversionResults& cs);
virtual bool convert_impl(const taxonomy::function_item::ptr item, IfcGeom::ConversionResults& cs);
virtual bool convert_impl(const taxonomy::functor_item::ptr item, IfcGeom::ConversionResults& cs);
virtual bool convert_impl(const taxonomy::piecewise_function::ptr item, IfcGeom::ConversionResults& cs);
virtual bool convert_impl(const taxonomy::gradient_function::ptr item, IfcGeom::ConversionResults& cs);
virtual bool convert_impl(const taxonomy::cant_function::ptr item, IfcGeom::ConversionResults& cs);
virtual bool convert_impl(const taxonomy::offset_function::ptr item, IfcGeom::ConversionResults& cs);
/*
virtual void set_offset(const std::array<double, 3> &p_offset);
+1 -1
View File
@@ -49,7 +49,7 @@ std::istream& ifcopenshell::geometry::settings::operator>>(std::istream& in, Ite
return in;
}
std::istream& ifcopenshell::geometry::settings::operator>>(std::istream& in, PiecewiseStepMethod& ioo) {
std::istream& ifcopenshell::geometry::settings::operator>>(std::istream& in, FunctionStepMethod& ioo) {
std::string token;
in >> token;
boost::to_upper(token);
+12 -12
View File
@@ -365,22 +365,22 @@ namespace ifcopenshell {
static constexpr bool defaultvalue = false;
};
enum PiecewiseStepMethod {
enum FunctionStepMethod {
MAXSTEPSIZE,
MINSTEPS };
std::istream& operator>>(std::istream& in, PiecewiseStepMethod& ioo);
std::istream& operator>>(std::istream& in, FunctionStepMethod& ioo);
struct PiecewiseStepType : public SettingBase<PiecewiseStepType, PiecewiseStepMethod> {
static constexpr const char* const name = "piecewise-step-type";
static constexpr const char* const description = "Indicates the method used for defining step size when evaluating piecewise curves. Provides interpretation of piecewise-step-param";
static constexpr PiecewiseStepMethod defaultvalue = MAXSTEPSIZE;
struct FunctionStepType : public SettingBase<FunctionStepType, FunctionStepMethod> {
static constexpr const char* const name = "function-step-type";
static constexpr const char* const description = "Indicates the method used for defining step size when evaluating function-based curves. Provides interpretation of function-step-param";
static constexpr FunctionStepMethod defaultvalue = MAXSTEPSIZE;
};
struct PiecewiseStepParam : public SettingBase<PiecewiseStepParam, double> {
static constexpr const char* const name = "piecewise-step-param";
static constexpr const char* const description = "Indicates the parameter value for defining step size when evaluating piecewise curves.";
static constexpr double defaultvalue = 0.5; // ceiling of this value is used when PiecewiseStepMethod is MinSteps
struct FunctionStepParam : public SettingBase<FunctionStepParam, double> {
static constexpr const char* const name = "function-step-param";
static constexpr const char* const description = "Indicates the parameter value for defining step size when evaluating function-based curves.";
static constexpr double defaultvalue = 0.5; // ceiling of this value is used when FunctionStepMethod is MinSteps
};
struct ModelOffset : public SettingBase<ModelOffset, std::vector<double>> {
@@ -413,7 +413,7 @@ namespace ifcopenshell {
template <typename settings_t>
class IFC_GEOM_API SettingsContainer {
public:
typedef boost::variant<bool, int, double, std::string, std::set<int>, std::set<std::string>, std::vector<double>, IteratorOutputOptions, PiecewiseStepMethod, OutputDimensionalityTypes, TriangulationMethod> value_variant_t;
typedef boost::variant<bool, int, double, std::string, std::set<int>, std::set<std::string>, std::vector<double>, IteratorOutputOptions, FunctionStepMethod, OutputDimensionalityTypes, TriangulationMethod> value_variant_t;
private:
settings_t settings;
@@ -500,7 +500,7 @@ namespace ifcopenshell {
};
class IFC_GEOM_API Settings : public SettingsContainer<
std::tuple<MesherLinearDeflection, MesherAngularDeflection, ReorientShells, LengthUnit, PlaneUnit, Precision, OutputDimensionality, LayersetFirst, DisableBooleanResult, NoWireIntersectionCheck, NoWireIntersectionTolerance, PrecisionFactor, DebugBooleanOperations, BooleanAttempt2d, SurfaceColour, WeldVertices, UseWorldCoords, UnifyShapes, UseMaterialNames, ConvertBackUnits, ContextIds, ContextTypes, ContextIdentifiers, IteratorOutput, DisableOpeningSubtractions, ApplyDefaultMaterials, DontEmitNormals, GenerateUvs, ApplyLayerSets, UseElementHierarchy, ValidateQuantities, EdgeArrows, BuildingLocalPlacement, SiteLocalPlacement, ForceSpaceTransparency, CircleSegments, KeepBoundingBoxes, PiecewiseStepType, PiecewiseStepParam, NoParallelMapping, ModelOffset, ModelRotation, TriangulationType>
std::tuple<MesherLinearDeflection, MesherAngularDeflection, ReorientShells, LengthUnit, PlaneUnit, Precision, OutputDimensionality, LayersetFirst, DisableBooleanResult, NoWireIntersectionCheck, NoWireIntersectionTolerance, PrecisionFactor, DebugBooleanOperations, BooleanAttempt2d, SurfaceColour, WeldVertices, UseWorldCoords, UnifyShapes, UseMaterialNames, ConvertBackUnits, ContextIds, ContextTypes, ContextIdentifiers, IteratorOutput, DisableOpeningSubtractions, ApplyDefaultMaterials, DontEmitNormals, GenerateUvs, ApplyLayerSets, UseElementHierarchy, ValidateQuantities, EdgeArrows, BuildingLocalPlacement, SiteLocalPlacement, ForceSpaceTransparency, CircleSegments, KeepBoundingBoxes, FunctionStepType, FunctionStepParam, NoParallelMapping, ModelOffset, ModelRotation, TriangulationType>
>
{};
}
+270
View File
@@ -0,0 +1,270 @@
#include "function_item_evaluator.h"
#include "profile_helper.h"
using namespace ifcopenshell::geometry;
struct functor_fn_evaluator : public fn_evaluator {
functor_fn_evaluator(taxonomy::functor_item::const_ptr fn, const ifcopenshell::geometry::Settings& settings) : fn_evaluator(settings),
fn_(fn) {
}
fn_evaluator* clone() const override { return new functor_fn_evaluator(*this); }
double start() const override { return fn_->start(); }
double end() const override { return fn_->end(); }
Eigen::Matrix4d evaluate(double u) const override {
return (*fn_)(u);
}
taxonomy::functor_item::const_ptr fn_;
};
struct piecewise_fn_evaluator : public fn_evaluator {
piecewise_fn_evaluator(taxonomy::piecewise_function::const_ptr fn, const ifcopenshell::geometry::Settings& settings) : fn_evaluator(settings),
fn_(fn) {
}
fn_evaluator* clone() const override { return new piecewise_fn_evaluator(*this); }
double start() const override { return fn_->start(); }
double end() const override { return fn_->end(); }
Eigen::Matrix4d evaluate(double u) const override {
// 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
function_item_evaluator evaluator(settings_, current_span_fn_);
return evaluator.evaluate(u);
}
std::tuple<double, double, taxonomy::function_item::const_ptr> get_span(double u) const {
// force u to be within bounds of the curve
double s = fn_->start();
double e = fn_->end();
u = std::max(s, u);
u = std::min(u, e);
double span_start = s;
for (auto& fn : fn_->spans()) {
double span_end = span_start + fn->length();
auto tolerance = settings_.get<ifcopenshell::geometry::settings::Precision>().get();
if (span_start <= u && u < span_end + tolerance) {
return {span_start, span_end, fn};
}
span_start += fn->length();
}
Logger::Error("piecewise span not found.");
return {0, 0, nullptr};
}
taxonomy::piecewise_function::const_ptr fn_;
mutable double current_span_start_ = 0;
mutable double current_span_end_ = 0;
mutable taxonomy::function_item::const_ptr current_span_fn_ = nullptr;
};
struct gradient_fn_evaluator : public fn_evaluator {
gradient_fn_evaluator(taxonomy::gradient_function::const_ptr fn, const ifcopenshell::geometry::Settings& settings) :
fn_evaluator(settings),
fn_(fn),
horizontal_evaluator_(settings, fn->get_horizontal()),
vertical_evaluator_(settings, fn->get_vertical())
{
start_ = fn_->get_vertical()->start();
}
fn_evaluator* clone() const override { return new gradient_fn_evaluator(*this); }
double start() const override { return fn_->start(); }
double end() const override { return fn_->end(); }
Eigen::Matrix4d evaluate(double u) const override {
// u is distance from start of vertical.
// add vertical->start() to u to get distance from start of horizontal
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
uz.row(1).swap(uz.row(2));
Eigen::Matrix4d m;
m = xy * uz; // combine horizontal and vertical
return m;
}
function_item_evaluator horizontal_evaluator_, vertical_evaluator_;
double start_; // start of vertical
taxonomy::gradient_function::const_ptr fn_;
};
struct cant_fn_evaluator : public fn_evaluator {
cant_fn_evaluator(taxonomy::cant_function::const_ptr fn, const ifcopenshell::geometry::Settings& settings) : fn_evaluator(settings),
fn_(fn),
gradient_evaluator_(settings, fn->get_gradient()),
cant_evaluator_(settings, fn->get_cant()) {
start_ = fn_->get_cant()->start();
}
fn_evaluator* clone() const override { return new cant_fn_evaluator(*this); }
double start() const override { return fn_->start(); }
double end() const override { return fn_->end(); }
Eigen::Matrix4d evaluate(double u) const override {
// 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_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
// they are relative to the gradient curve coordinate system
//
// However, the coordinate points don't need to have the rotations
// of g applied. Save off the x,y,z and cant values
auto x = g(0, 3);
auto y = g(1, 3);
auto z = g(2, 3);
auto s = c(1, 3); // superelevation
// change column 3 to (0,0,0,1)
Eigen::Vector4d p(0, 0, 0, 1);
g.col(3) = p;
c.col(3) = p;
// multiply g and c to get the axes in the correct orientation
Eigen::Matrix4d m = g * c;
// reinstate the values for x and y.
// z is the gradient curve z value plus the superelevation
// that comes from the cant.
m(0, 3) = x;
m(1, 3) = y;
m(2, 3) = z + s;
return m;
}
function_item_evaluator gradient_evaluator_, cant_evaluator_;
double start_; // start of cant
taxonomy::cant_function::const_ptr fn_;
};
struct offset_fn_evaluator : public fn_evaluator {
offset_fn_evaluator(taxonomy::offset_function::const_ptr fn, const ifcopenshell::geometry::Settings& settings) : fn_evaluator(settings),
fn_(fn),
basis_evaluator_(settings, fn->get_basis()),
offset_evaluator_(settings, fn->get_offset()) {
}
fn_evaluator* clone() const override { return new offset_fn_evaluator(*this); }
double start() const override { return fn_->start(); }
double end() const override { return fn_->end(); }
Eigen::Matrix4d evaluate(double u) const override {
auto p = basis_evaluator_.evaluate(u);
auto offset = offset_evaluator_.evaluate(u);
Eigen::Matrix4d m = p * offset;
return m;
}
function_item_evaluator basis_evaluator_, offset_evaluator_;
taxonomy::offset_function::const_ptr fn_;
};
function_item_evaluator::function_item_evaluator(const ifcopenshell::geometry::Settings& settings,taxonomy::function_item::const_ptr fn) {
auto kind = fn->kind();
if (kind == taxonomy::FUNCTOR_ITEM) {
fn_evaluator_ = new functor_fn_evaluator(std::dynamic_pointer_cast<const taxonomy::functor_item>(fn),settings);
} else if (kind == taxonomy::PIECEWISE_FUNCTION) {
fn_evaluator_ = new piecewise_fn_evaluator(std::dynamic_pointer_cast<const taxonomy::piecewise_function>(fn), settings);
} else if (kind == taxonomy::GRADIENT_FUNCTION) {
fn_evaluator_ = new gradient_fn_evaluator(std::dynamic_pointer_cast<const taxonomy::gradient_function>(fn), settings);
} else if (kind == taxonomy::CANT_FUNCTION) {
fn_evaluator_ = new cant_fn_evaluator(std::dynamic_pointer_cast<const taxonomy::cant_function>(fn), settings);
} else if (kind == taxonomy::OFFSET_FUNCTION) {
fn_evaluator_ = new offset_fn_evaluator(std::dynamic_pointer_cast<const taxonomy::offset_function>(fn), settings);
} else {
Logger::Error("Unexpected function type");
}
}
function_item_evaluator::function_item_evaluator(const function_item_evaluator& other) {
fn_evaluator_ = other.fn_evaluator_->clone();
eval_points_ = other.eval_points_;
}
function_item_evaluator::~function_item_evaluator() {
delete fn_evaluator_;
}
std::vector<double> function_item_evaluator::evaluation_points() const {
if (!eval_points_.has_value()) {
double curve_length = fn_evaluator_->length();
auto param_type = fn_evaluator_->settings_.get<ifcopenshell::geometry::settings::FunctionStepType>().get();
auto param = fn_evaluator_->settings_.get<ifcopenshell::geometry::settings::FunctionStepParam>().get();
unsigned num_steps = 0;
if (param_type == ifcopenshell::geometry::settings::FunctionStepMethod::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(fn_evaluator_->start(), fn_evaluator_->end(), num_steps);
}
return *eval_points_;
}
std::vector<double> function_item_evaluator::evaluation_points(double ustart, double uend, unsigned nsteps) const {
double curve_length = fn_evaluator_->length();
ustart = std::max(fn_evaluator_->start(), ustart);
uend = std::min(uend, fn_evaluator_->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;
}
taxonomy::item::ptr function_item_evaluator::evaluate() const {
return evaluate(evaluation_points());
}
taxonomy::item::ptr function_item_evaluator::evaluate(double ustart, double uend, unsigned nsteps) const {
return evaluate(evaluation_points(ustart, uend, nsteps));
}
taxonomy::item::ptr function_item_evaluator::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(0, 3), m(1, 3), m(2, 3)));
}
return polygon_from_points(polygon);
}
Eigen::Matrix4d function_item_evaluator::evaluate(double u) const {
return fn_evaluator_->evaluate(u);
}
@@ -7,10 +7,29 @@
namespace ifcopenshell { namespace geometry {
/// @brief utility class to evaluate piecewise_function objects
class piecewise_function_evaluator {
/// @brief Abstract class for evaluating a function_item. This class is specialized for each of the function_item types.
struct fn_evaluator {
fn_evaluator(const ifcopenshell::geometry::Settings& settings) : settings_(settings) {
}
fn_evaluator(const fn_evaluator& other) = default;
virtual ~fn_evaluator() = default;
virtual fn_evaluator* clone() const = 0;
virtual Eigen::Matrix4d evaluate(double u) const = 0;
virtual double start() const = 0;
virtual double end() const = 0;
double length() const { return end() - start(); }
ifcopenshell::geometry::Settings settings_;
};
/// @brief utility class to evaluate function_item objects.
class function_item_evaluator {
public:
piecewise_function_evaluator(taxonomy::piecewise_function::const_ptr pwf, const ifcopenshell::geometry::Settings* settings=nullptr);
function_item_evaluator(const ifcopenshell::geometry::Settings& settings, taxonomy::function_item::const_ptr fn);
function_item_evaluator(const function_item_evaluator& other);
~function_item_evaluator();
/// @brief returns a vector of "distance along" points where the evaluate function computes loop points
std::vector<double> evaluation_points() const;
@@ -21,11 +40,11 @@ class piecewise_function_evaluator {
/// @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
/// @brief evaluates the 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
/// @brief evaluates the 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
@@ -34,23 +53,16 @@ class piecewise_function_evaluator {
/// @return taxonomy::loop::ptr
taxonomy::item::ptr evaluate(double ustart, double uend, unsigned nsteps) const;
/// @brief evaluates the piecewise function at u
/// @brief evaluates the 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<double>& dist) const;
std::tuple<double, double, const std::function<Eigen::Matrix4d(double u)>*> get_span(double u) const;
fn_evaluator* fn_evaluator_ = nullptr;
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<Eigen::Matrix4d(double u)>* current_span_fn_ = nullptr;
mutable boost::optional<std::vector<double>> eval_points_;
mutable boost::optional<std::vector<double>> eval_points_; // cache evaluation points
};
}}
+11 -11
View File
@@ -1,6 +1,6 @@
#include "profile_helper.h"
#include "infra_sweep_helper.h"
#include "piecewise_function_evaluator.h"
#include "function_item_evaluator.h"
#include <boost/range/combine.hpp>
@@ -14,7 +14,7 @@ namespace {
}
}
taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_, const IfcUtil::IfcBaseClass* inst, const taxonomy::piecewise_function::ptr& pwf, std::vector<cross_section>& cross_sections)
taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_, const IfcUtil::IfcBaseClass* inst, const taxonomy::function_item::ptr& fn, std::vector<cross_section>& cross_sections)
{
std::sort(cross_sections.begin(), cross_sections.end());
@@ -22,23 +22,23 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
// @todo intialize as default
loft->axis = nullptr;
// @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) {
piecewise_function_evaluator evaluator(pwf, &settings_);
// @todo currently only the case is handled where directrix returns a function_item
// @todo this "if" statement is not really required because the function returns at the start if the Directrix is not a function_item function
if (fn) {
function_item_evaluator evaluator(settings_,fn);
double start = std::max(0., cross_sections.front().dist_along);
double end = std::min(pwf->length(), cross_sections.back().dist_along);
double end = std::min(fn->length(), cross_sections.back().dist_along);
if (end - start < 1.e-9) {
Logger::Warning("Empty sweep domain with start at " + std::to_string(cross_sections.front().dist_along) + " end at " + std::to_string(cross_sections.back().dist_along) + " and curve domain length " + std::to_string(pwf->length()), inst);
Logger::Warning("Empty sweep domain with start at " + std::to_string(cross_sections.front().dist_along) + " end at " + std::to_string(cross_sections.back().dist_along) + " and curve domain length " + std::to_string(fn->length()), inst);
return nullptr;
}
auto curve_length = end - start;
auto param_type = settings_.get<ifcopenshell::geometry::settings::PiecewiseStepType>().get();
auto param = settings_.get<ifcopenshell::geometry::settings::PiecewiseStepParam>().get();
auto param_type = settings_.get<ifcopenshell::geometry::settings::FunctionStepType>().get();
auto param = settings_.get<ifcopenshell::geometry::settings::FunctionStepParam>().get();
size_t num_steps = 0;
if (param_type == ifcopenshell::geometry::settings::PiecewiseStepMethod::MAXSTEPSIZE) {
if (param_type == ifcopenshell::geometry::settings::FunctionStepMethod::MAXSTEPSIZE) {
// parameter is max step size
num_steps = (size_t)std::ceil(curve_length / param);
} else {
+1 -1
View File
@@ -18,7 +18,7 @@ namespace ifcopenshell {
}
};
taxonomy::loft::ptr make_loft(const Settings& settings_, const IfcUtil::IfcBaseClass* inst, const taxonomy::piecewise_function::ptr& directrix, std::vector<cross_section>& cross_sections);
taxonomy::loft::ptr make_loft(const Settings& settings_, const IfcUtil::IfcBaseClass* inst, const taxonomy::function_item::ptr& directrix, std::vector<cross_section>& cross_sections);
}
}
+8 -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>();
std::vector<taxonomy::piecewise_function::ptr> pwfs;
taxonomy::piecewise_function::spans_t spans;
#ifdef SCHEMA_HAS_IfcSegment
// 4x3
@@ -74,17 +74,18 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) {
for (auto& s : taxonomy::cast<taxonomy::loop>(crv)->children) {
loop->children.push_back(s);
}
}
else if (crv && crv->kind() == taxonomy::PIECEWISE_FUNCTION) {
pwfs.push_back(taxonomy::cast<taxonomy::piecewise_function>(crv));
} else if (!crv) {
} else if (auto fi = taxonomy::dcast<taxonomy::function_item>(crv); crv && fi /*crv->kind() == taxonomy::FUNCTION_ITEM*/) {
// crv->kind() is polymorphic and the kind of the actual function_item is returned. PWF can have spans of any FUNCTION_ITEM
// for this reason, a dynamic cast is used and if crv is a function_item it is added to the span
spans.push_back(fi);
} else if (!crv) {
return nullptr;
}
}
#endif
}
if (pwfs.empty()) {
if (spans.empty()) {
aggregate_of_instance::ptr profile = inst->file_->getInverse(inst->id(), &IfcSchema::IfcProfileDef::Class(), -1);
const bool force_close = profile && profile->size() > 0;
loop->closed = force_close;
@@ -92,7 +93,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) {
return loop;
}
else {
auto pwf = taxonomy::make<taxonomy::piecewise_function>(0.0,pwfs,inst);
auto pwf = taxonomy::make<taxonomy::piecewise_function>(0.0,spans,inst);
return pwf;
}
}
+210 -155
View File
@@ -96,6 +96,87 @@ typedef boost::mpl::vector<
#endif
> curve_seg_types;
struct parent_curve_function {
parent_curve_function() = default;
parent_curve_function(const parent_curve_function&) = default;
parent_curve_function(std::function<Eigen::Matrix4d(double)> fn) : fn_(fn) {
}
parent_curve_function& operator=(std::function<Eigen::Matrix4d(double)> fn) {
fn_ = fn;
return *this;
}
virtual Eigen::Matrix4d operator()(double u) const { return fn_(u); }
private:
std::function<Eigen::Matrix4d(double)> fn_;
};
struct polynomial_parent_curve : public parent_curve_function {
using parent_curve_function::parent_curve_function;
};
struct line_parent_curve : public parent_curve_function {
using parent_curve_function::parent_curve_function;
};
struct circle_parent_curve : public parent_curve_function {
using parent_curve_function::parent_curve_function;
};
struct spiral_parent_curve : public parent_curve_function {
using parent_curve_function::parent_curve_function;
};
// this is the piecewise curve segment function for horizontal and vertical
struct curve_segment_function {
curve_segment_function(const Eigen::Matrix4d& curve_segment_placement, const Eigen::Matrix4d& remove_parent_curve_rotation, const Eigen::Matrix4d& remove_parent_curve_translation, std::shared_ptr<parent_curve_function> parent_curve_fn) :
curve_segment_placement_(curve_segment_placement),
remove_parent_curve_rotation_(remove_parent_curve_rotation),
remove_parent_curve_translation_(remove_parent_curve_translation),
parent_curve_fn_(parent_curve_fn) {
}
Eigen::Matrix4d operator()(double u) const {
Eigen::Matrix4d parent_curve_point = (*parent_curve_fn_)(u);
Eigen::Matrix4d curve_segment_point = curve_segment_placement_ * remove_parent_curve_rotation_ * remove_parent_curve_translation_ * parent_curve_point;
return curve_segment_point;
}
private:
Eigen::Matrix4d curve_segment_placement_;
Eigen::Matrix4d remove_parent_curve_rotation_;
Eigen::Matrix4d remove_parent_curve_translation_;
std::shared_ptr<parent_curve_function> parent_curve_fn_;
};
// this is the piecewise curve segment function for cant
struct cant_curve_segment_function {
cant_curve_segment_function(const Eigen::Matrix4d& curve_segment_placement, const Eigen::Matrix4d& parent_curve_start_point, std::shared_ptr<parent_curve_function> parent_curve_fn) :
curve_segment_placement_(curve_segment_placement),
parent_curve_start_point_(parent_curve_start_point),
parent_curve_fn_(parent_curve_fn) {
}
Eigen::Matrix4d operator()(double u) const {
// The parent curve function returns the cant rotation and superelevation for the parent curve.
// Subtract the parent_curve_start_point to get the incremental cant rotation and superelevation
// Add the incremental cant rotation and superelevation to curve_segment_placement to get the curve_segment_point
Eigen::Matrix4d parent_curve_point = (*parent_curve_fn_)(u);
Eigen::Matrix4d cant_increment = parent_curve_point - parent_curve_start_point_;
Eigen::Matrix4d curve_segment_point = curve_segment_placement_ + cant_increment;
return curve_segment_point;
}
private:
Eigen::Matrix4d curve_segment_placement_;
Eigen::Matrix4d parent_curve_start_point_;
std::shared_ptr<parent_curve_function> parent_curve_fn_;
};
// evaluates a IfcCurveSegment to set up the placement and parent curve function
class curve_segment_evaluator {
private:
mapping* mapping_ = nullptr;
@@ -108,24 +189,71 @@ class curve_segment_evaluator {
double projected_length_; // for vertical segments, this is the length of curve projected onto the "Distance Along" axis
std::optional<std::function<Eigen::Matrix4d(double)>> parent_curve_fn_; // function for the parent curve. Function takes distances along, u, and returns the 4x4 position matrix
std::optional<Eigen::Matrix4d> parent_curve_start_point_; // placement matrix for the parent curve
std::shared_ptr<parent_curve_function> parent_curve_fn_; // function for the parent curve. Function takes distances along, u, and returns the 4x4 position matrix
std::optional<Eigen::Matrix4d> parent_curve_start_point_; // placement matrix for the parent curve
std::optional<Eigen::Matrix4d> placement_; // placement of this segment
std::optional<Eigen::Matrix4d> curve_segment_placement_; // placement of this segment
std::optional<Eigen::Matrix4d> next_segment_placement_; // placement of the next segment
public:
curve_segment_evaluator(mapping* mapping, const IfcSchema::IfcCurveSegment* inst, const IfcSchema::IfcCurveSegment* next_inst, double length_unit, segment_type_t segment_type)
curve_segment_evaluator(mapping* mapping, const IfcSchema::IfcCurveSegment* inst, double length_unit)
: mapping_(mapping),
inst_(inst),
length_unit_(length_unit),
segment_type_(segment_type),
parent_curve_(inst->ParentCurve()) {
auto composite_curves = inst->UsingCurves();
// Find the next segment after inst
const IfcSchema::IfcCurveSegment* next_inst = nullptr;
if (composite_curves) {
if (composite_curves->size() == 1) {
auto segments = (*composite_curves->begin())->as<IfcSchema::IfcCompositeCurve>()->Segments();
bool emit_next = false;
for (auto& s : *segments) {
if (emit_next) {
next_inst = s->as<IfcSchema::IfcCurveSegment>();
break;
}
if (s == inst) {
emit_next = true;
}
}
} else {
Logger::Warning("IfcCurveSegment belongs to multiple IfcCompositeCurve instances. Cannot determine the next segment.");
}
}
bool is_horizontal = false;
bool is_vertical = false;
bool is_cant = false;
if (composite_curves) {
for (auto& cc : *composite_curves) {
if (cc->as<IfcSchema::IfcSegmentedReferenceCurve>()) {
is_cant = true;
} else if (cc->as<IfcSchema::IfcGradientCurve>()) {
is_vertical = true;
} else {
is_horizontal = true;
}
}
}
if ((is_horizontal + is_vertical + is_cant) != 1) {
// We have to choose the correct functor based on usage. We can't
// support multiple, because we don't know the caller at this point.
Logger::Error(std::runtime_error("multiple uses of IfcSegmentCurve not supported"), inst_);
}
segment_type_ = is_horizontal ? ST_HORIZONTAL : is_vertical ? ST_VERTICAL : ST_CANT;
start_ = translate_if_param_value(inst->ParentCurve(), inst->SegmentStart()) * length_unit;
length_ = translate_if_param_value(inst->ParentCurve(), inst->SegmentLength()) * length_unit;
if (inst) {
placement_ = taxonomy::cast<taxonomy::matrix4>(mapping_->map(inst->Placement()))->ccomponents();
curve_segment_placement_ = taxonomy::cast<taxonomy::matrix4>(mapping_->map(inst->Placement()))->ccomponents();
}
if (next_inst) {
@@ -133,7 +261,6 @@ class curve_segment_evaluator {
} else {
// there is not a next segment, however IfcGradientCurve and IfcSegmentReferenceCurve have an
// optional EndPoint which services the same purpose as the zero-length last segment.
auto composite_curves = inst->UsingCurves();
IfcSchema::IfcPlacement* end_point = nullptr;
if (composite_curves->size() == 1) {
auto& cc = *(composite_curves)->begin();
@@ -165,16 +292,47 @@ class curve_segment_evaluator {
return (segment_type_ == ST_HORIZONTAL || segment_type_ == ST_CANT) ? length_ : projected_length_;
}
const std::optional<std::function<Eigen::Matrix4d(double)>>& parent_curve_function() const {
return parent_curve_fn_;
}
taxonomy::ptr get_segment_curve_function() {
if (!parent_curve_fn_ || !parent_curve_start_point_) {
Logger::Error(std::runtime_error(inst_->ParentCurve()->declaration().name() + " not implemented"), inst_);
}
const std::optional<Eigen::Matrix4d>& parent_curve_start_point() const {
return parent_curve_start_point_;
}
auto length = fabs(this->length());
const std::optional<Eigen::Matrix4d>& segment_placement() const {
return placement_;
if (segment_type_ == ST_CANT) {
auto fn = cant_curve_segment_function(*curve_segment_placement_, *parent_curve_start_point_, parent_curve_fn_);
return taxonomy::make<taxonomy::functor_item>(length, fn);
} else {
// The parent curve function returns the 4x4 matrix for the parent curve.
// Subtract the parent curve start point (remove the translation and rotation)
// to get the incremental translation and rotation. Apply the incremental
// translation and rotation to the curve_segment_placement to get the curve_segment_point
// Do a negative translation of the parent curve point relative to the start of the parent curve.
// This moves parent_curve_fn(u=0.0) to coordinate (0,0).
// This is done so the curve_segment_placement is applied relative to (0,0)
Eigen::Matrix4d remove_parent_curve_translation = Eigen::Matrix4d::Identity();
remove_parent_curve_translation.col(3) = -1.0 * (*parent_curve_start_point_).col(3);
remove_parent_curve_translation(3, 3) = 1.0;
// Do a rotation so that the tangent of the parent curve is in the direction (1,0)
// Example: if the parent curve IfcLine is at a 30 degree clockwise angle, this does
// a 30 degree counter-clockwise rotation
// Clockwise rotation matrix = [cos(angle) -sin(angle)]
// [sin(angle) cos(angle)]
//
// Counter-clockwise rotation = [ cos(angle) sin(angle)]
// [-sin(angle) cos(angle)]
//
// That's just a sign flip in positions (0,1) and (1,0)
Eigen::Matrix4d remove_parent_curve_rotation = (*parent_curve_start_point_);
remove_parent_curve_rotation(0, 1) *= -1.0;
remove_parent_curve_rotation(1, 0) *= -1.0;
remove_parent_curve_rotation.col(3) = Eigen::Vector4d(0, 0, 0, 1); // remove the parent curve placement point
auto fn = curve_segment_function(*curve_segment_placement_, remove_parent_curve_rotation, remove_parent_curve_translation, parent_curve_fn_);
return taxonomy::make<taxonomy::functor_item>(length, fn);
}
}
void set_spiral_function(double s, std::function<double(double)> fnX, std::function<double(double)> fnY) {
@@ -224,7 +382,7 @@ class curve_segment_evaluator {
};
}
parent_curve_fn_ = [start=start_, s, convert_u, fnX, fnY](double u) {
parent_curve_fn_ = std::make_shared<spiral_parent_curve>([start=start_, s, convert_u, fnX, fnY](double u) {
u = convert_u(u+start);
// integration limits, integrate from a to b
@@ -241,20 +399,20 @@ class curve_segment_evaluator {
m.col(1) = Eigen::Vector4d(-dy, dx, 0, 0);
m.col(3) = Eigen::Vector4d(x, y, 0, 1);
return m;
};
});
} else if (segment_type_ == ST_CANT) {
Logger::Error(std::runtime_error("Unexpected segment type encountered - cant is handled in set_cant_spiral_function - should never get here"));
parent_curve_fn_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
parent_curve_fn_ = std::make_shared<parent_curve_function>([](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
} else {
Logger::Error(std::runtime_error("Unexpected segment type encountered"));
parent_curve_fn_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
parent_curve_fn_ = std::make_shared<parent_curve_function>([](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
}
}
// defines the parent_curve_fn_ functor for cant segments.
void set_cant_spiral_function(std::function<double(double)> Superelevation, std::function<double(double)> SuperelevationSlope, std::function<double(double)> Cant) {
auto dy = (*placement_)(1, 2); // placement dy
auto dz = (*placement_)(2, 2); // placement dz
auto dy = (*curve_segment_placement_)(1, 2); // placement dy
auto dz = (*curve_segment_placement_)(2, 2); // placement dz
auto start_angle = atan2(dz, dy);
dy = (next_segment_placement_.has_value() ? (*next_segment_placement_)(1, 2) : 0.0);
@@ -266,7 +424,7 @@ class curve_segment_evaluator {
auto end_cant = Cant(/* start_ + */ length_);
auto delta_cant = end_cant - start_cant;
parent_curve_fn_ = [start_angle,delta_angle,start_cant,delta_cant,Superelevation, SuperelevationSlope, Cant](double u) -> Eigen::Matrix4d {
parent_curve_fn_ = std::make_shared<spiral_parent_curve>([start_angle,delta_angle,start_cant,delta_cant,Superelevation, SuperelevationSlope, Cant](double u) -> Eigen::Matrix4d {
// departure of the curve segment from the base curve (superelevation)
auto super_elevation = Superelevation(u);
auto slope = SuperelevationSlope(u);
@@ -292,7 +450,7 @@ class curve_segment_evaluator {
m.col(2) = axis;
m.col(3) = Eigen::Vector4d(u, super_elevation, 0.0, 1.0);
return m;
};
});
parent_curve_start_point_ = (*parent_curve_fn_)(0.0);
}
@@ -304,8 +462,8 @@ class curve_segment_evaluator {
boost::optional<std::function<double(double)>> superelevation_fn;
boost::optional<std::function<double(double)>> superelevation_slope_fn;
if (placement_.has_value() && next_segment_placement_.has_value()) {
double y1 = (*placement_)(1, 3);
if (curve_segment_placement_.has_value() && next_segment_placement_.has_value()) {
double y1 = (*curve_segment_placement_)(1, 3);
double y2 = (*next_segment_placement_)(1, 3);
// if y2-y1 = 0, the super elevation is constant
@@ -390,10 +548,10 @@ class curve_segment_evaluator {
set_cant_spiral_function(*super, *slope, cant);
} else if (segment_type_ == ST_VERTICAL) {
Logger::Error(std::runtime_error("IfcCosineSpiral cannot be used for vertical alignment"));
parent_curve_fn_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
parent_curve_fn_ = std::make_shared<parent_curve_function>([](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
} else {
Logger::Error(std::runtime_error("Unexpected segment type encountered"));
parent_curve_fn_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
parent_curve_fn_ = std::make_shared<parent_curve_function>([](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
}
}
#endif
@@ -447,10 +605,10 @@ class curve_segment_evaluator {
set_cant_spiral_function(*super, *slope, cant);
} else if (segment_type_ == ST_VERTICAL) {
Logger::Error(std::runtime_error("IfcSineSpiral cannot be used for vertical alignment"));
parent_curve_fn_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
parent_curve_fn_ = std::make_shared<parent_curve_function>([](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
} else {
Logger::Error(std::runtime_error("Unexpected segment type encountered"));
parent_curve_fn_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
parent_curve_fn_ = std::make_shared<parent_curve_function>([](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
}
}
#endif
@@ -623,7 +781,7 @@ class curve_segment_evaluator {
};
}
parent_curve_fn_ = [segment_type = segment_type_, R, pcCenterX, pcCenterY, start_angle, sign_l, convert_u](double u) {
parent_curve_fn_ = std::make_shared<circle_parent_curve>([segment_type = segment_type_, R, pcCenterX, pcCenterY, start_angle, sign_l, convert_u](double u) {
u = convert_u(u);
// u is measured along the circle
@@ -645,7 +803,7 @@ class curve_segment_evaluator {
m.col(1) = Eigen::Vector4d(-pcDy, pcDx, 0, 0);
m.col(3) = Eigen::Vector4d(pcX, pcY, 0.0, 1.0);
return m;
};
});
if (segment_type_ == ST_HORIZONTAL) {
parent_curve_start_point_ = (*parent_curve_fn_)(start_);
@@ -675,10 +833,10 @@ class curve_segment_evaluator {
} else if (segment_type_ == ST_CANT) {
Logger::Warning(std::runtime_error("Use of IfcCircle for cant is not supported"));
parent_curve_fn_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
parent_curve_fn_ = std::make_shared<parent_curve_function>([](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
} else {
Logger::Error(std::runtime_error("Unexpected segment type encountered"));
parent_curve_fn_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
parent_curve_fn_ = std::make_shared<parent_curve_function>([](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
}
}
@@ -706,12 +864,12 @@ class curve_segment_evaluator {
auto pcDx = dr[0];
auto pcDy = dr[1];
if (segment_type_ == ST_VERTICAL && placement_) {
if (segment_type_ == ST_VERTICAL && curve_segment_placement_) {
// the general algorithm for mapping parent curve onto curve segment doesn't
// exactly work for IfcLine. This is easily overcome by using the curve segment
// placement for the IfcLine direction
pcDx = (*placement_)(0, 0);
pcDy = (*placement_)(1, 0);
pcDx = (*curve_segment_placement_)(0, 0);
pcDy = (*curve_segment_placement_)(1, 0);
}
if (segment_type_ == ST_HORIZONTAL || segment_type_ == ST_VERTICAL || segment_type_ == ST_CANT) {
@@ -723,7 +881,7 @@ class curve_segment_evaluator {
convert_u = [pcDx](double u) { return u/pcDx; };
}
parent_curve_fn_ = [pcX, pcY, pcDx, pcDy, convert_u](double u) {
parent_curve_fn_ = std::make_shared<line_parent_curve>([pcX, pcY, pcDx, pcDy, convert_u](double u) {
u = convert_u(u);
auto x = pcX + pcDx * u;
@@ -734,13 +892,13 @@ class curve_segment_evaluator {
m.col(1) = Eigen::Vector4d(-pcDy, pcDx, 0, 0);
m.col(3) = Eigen::Vector4d(x, y, 0.0, 1.0);
return m;
};
});
parent_curve_start_point_ = (*parent_curve_fn_)(start_);
} else {
Logger::Warning(std::runtime_error("Unexpected segment type encountered"));
parent_curve_fn_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
}
parent_curve_fn_ = std::make_shared<parent_curve_function>([](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
}
}
void operator()(const IfcSchema::IfcPolynomialCurve* pc) {
@@ -755,7 +913,7 @@ class curve_segment_evaluator {
if (segment_type_ == ST_HORIZONTAL || segment_type_ == ST_VERTICAL) {
projected_length_ = length_;
// There is one significant difference between IfcPolynomalCurve used for horizontal and vertical alignments.
// There is one significant difference between IfcPolynomialCurve used for horizontal and vertical alignments.
// For horizontal alignment, u is the distance along the curve. For vertical alignment, u is the horizontal distance.
// From 4.2.2.2.8 the polynomial curve equation is in the form of y = Ax^3 for horizontal parabolic transition segments.
// To evaluate the horizontal function, the value of x that corresponds to the distance along the curve u is needed.
@@ -775,7 +933,11 @@ class curve_segment_evaluator {
for (; iter != end; iter++) {
auto exp = std::distance(begin, iter);
auto coeff = (*iter);
value += (double)exp * coeff * pow(lu, lu_exp--) * pow(x, exp - 1);
double a = (double)exp * coeff * pow(lu, lu_exp--);
double b = x ? pow(x, exp - 1) : 0; // when x and exp are zero? 0^-1 is infinite and the result is undefined
double v = a * b;
//double v = (double)exp * coeff * pow(lu, lu_exp--) * pow(x, exp - 1);
value += v;
}
return value;
};
@@ -815,7 +977,7 @@ class curve_segment_evaluator {
}
// This functor evaluates the polynomial at a distance u along the curve
parent_curve_fn_ = [start = start_, lu = length_unit_, coeffX, coeffY, convert_u](double u) -> Eigen::Matrix4d {
parent_curve_fn_ = std::make_shared<polynomial_parent_curve>([start = start_, lu = length_unit_, coeffX, coeffY, convert_u](double u)->Eigen::Matrix4d {
auto x = convert_u(u + start); // find x for u
// evaluate the polynomial at x
std::array<const std::vector<double>*, 2> coefficients{&coeffX, &coeffY};
@@ -851,131 +1013,24 @@ class curve_segment_evaluator {
m.col(1) = Eigen::Vector4d(-Dy, Dx, 0, 0);
m.col(3) = Eigen::Vector4d(X, Y, 0.0, 1.0);
return m;
};
});
parent_curve_start_point_ = (*parent_curve_fn_)(0.0); // start is added to u in parent_curve_fn_, so use 0.0 here
} else if (segment_type_ == ST_CANT) {
Logger::Warning(std::runtime_error("Use of IfcPolynomialCurve for cant is not supported"));
parent_curve_fn_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
parent_curve_fn_ = std::make_shared<parent_curve_function>([](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
} else {
Logger::Error(std::runtime_error("Unexpected segment type encountered"));
parent_curve_fn_ = [](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); };
parent_curve_fn_ = std::make_shared<parent_curve_function>([](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
}
}
};
} // namespace
taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCurveSegment* inst) {
auto composite_curves = inst->UsingCurves();
// Find the next segment after inst
const IfcSchema::IfcCurveSegment* next_inst = nullptr;
if (composite_curves) {
if (composite_curves->size() == 1) {
auto segments = (*composite_curves->begin())->as<IfcSchema::IfcCompositeCurve>()->Segments();
bool emit_next = false;
for (auto& s : *segments) {
if (emit_next) {
next_inst = s->as<IfcSchema::IfcCurveSegment>();
break;
}
if (s == inst) {
emit_next = true;
}
}
} else {
Logger::Warning("IfcCurveSegment belongs to multiple IfcCompositeCurve instances. Cannot determine the next segment.");
}
}
bool is_horizontal = false;
bool is_vertical = false;
bool is_cant = false;
if (composite_curves) {
for (auto& cc : *composite_curves) {
if (cc->as<IfcSchema::IfcSegmentedReferenceCurve>()) {
is_cant = true;
} else if (cc->as<IfcSchema::IfcGradientCurve>()) {
is_vertical = true;
} else {
is_horizontal = true;
}
}
}
if ((is_horizontal + is_vertical + is_cant) != 1) {
// We have to choose the correct functor based on usage. We can't
// support multiple, because we don't know the caller at this point.
return nullptr;
}
auto segment_type = is_horizontal ? ST_HORIZONTAL : is_vertical ? ST_VERTICAL : ST_CANT;
curve_segment_evaluator cse(this, inst, next_inst, length_unit_, segment_type);
curve_segment_evaluator cse(this, inst, length_unit_);
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_start_point = cse.parent_curve_start_point();
if (!parent_curve_fn || !parent_curve_start_point) {
Logger::Error(std::runtime_error(inst->ParentCurve()->declaration().name() + " not implemented"), inst);
}
const auto& curve_segment_placement = cse.segment_placement();
std::function<Eigen::Matrix4d(double u)> fn;
if (segment_type == ST_CANT)
{
fn = [curve_segment_placement, parent_curve_start_point, parent_curve_fn](double u) -> Eigen::Matrix4d {
// The parent curve function returns the cant rotation and superelevation for the parent curve.
// Subtract the parent_curve_start_point to get the incremental cant rotation and superelevation
// Add the incremental cant rotation and superelevation to curve_segment_placement to get the curve_segment_point
Eigen::Matrix4d parent_curve_point = (*parent_curve_fn)(u);
Eigen::Matrix4d cant_increment = parent_curve_point - (*parent_curve_start_point);
Eigen::Matrix4d curve_segment_point = (*curve_segment_placement) + cant_increment;
return curve_segment_point;
};
} else {
// The parent curve function returns the 4x4 matrix for the parent curve.
// Subtract the parent curve start point (remove the translation and rotation)
// to get the incremental translation and rotation. Apply the incremental
// translation and rotation to the curve_segment_placement to get the curve_segment_point
// Do a negative translation of the parent curve point relative to the start of the parent curve.
// This moves parent_curve_fn(u=0.0) to coordinate (0,0).
// This is done so the curve_segment_placement is applied relative to (0,0)
Eigen::Matrix4d remove_parent_curve_translation = Eigen::Matrix4d::Identity();
remove_parent_curve_translation.col(3) = -1.0 * (*parent_curve_start_point).col(3);
remove_parent_curve_translation(3, 3) = 1.0;
// Do a rotation so that the tangent of the parent curve is in the direction (1,0)
// Example: if the parent curve IfcLine is at a 30 degree clockwise angle, this does
// a 30 degree counter-clockwise rotation
// Clockwise rotation matrix = [cos(angle) -sin(angle)]
// [sin(angle) cos(angle)]
//
// Counter-clockwise rotation = [ cos(angle) sin(angle)]
// [-sin(angle) cos(angle)]
//
// That's just a sign flip in positions (0,1) and (1,0)
Eigen::Matrix4d remove_parent_curve_rotation = *parent_curve_start_point;
remove_parent_curve_rotation(0, 1) *= -1.0;
remove_parent_curve_rotation(1, 0) *= -1.0;
remove_parent_curve_rotation.col(3) = Eigen::Vector4d(0, 0, 0, 1); // remove the parent curve placement point
fn = [curve_segment_placement, remove_parent_curve_rotation, remove_parent_curve_translation, parent_curve_fn](double u) -> Eigen::Matrix4d {
Eigen::Matrix4d parent_curve_point = (*parent_curve_fn)(u);
Eigen::Matrix4d curve_segment_point = (*curve_segment_placement) * remove_parent_curve_rotation * remove_parent_curve_translation * parent_curve_point;
return curve_segment_point;
};
}
auto length = cse.length();
taxonomy::piecewise_function::spans_t spans;
spans.emplace_back(fabs(length), fn);
auto pwf = taxonomy::make<taxonomy::piecewise_function>(0.0, spans,inst);
return pwf;
return cse.get_segment_curve_function();
}
#endif
@@ -18,7 +18,7 @@
********************************************************************************/
#include "mapping.h"
#include "../piecewise_function_evaluator.h"
#include "../function_item_evaluator.h"
#define mapping POSTFIX_SCHEMA(mapping)
using namespace ifcopenshell::geometry;
@@ -34,10 +34,10 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcFixedReferenceSweptAreaSolid
loft->axis = nullptr;
// @todo currently only the case is handled where directrix returns a piecewise_function
if (auto pwf = taxonomy::dcast<taxonomy::piecewise_function>(dir)) {
piecewise_function_evaluator evaluator(pwf,&settings_);
if (auto fn = taxonomy::dcast<taxonomy::function_item>(dir)) {
function_item_evaluator evaluator(settings_,fn);
double start = 0;
double end = pwf->length();
double end = fn->length();
#ifdef SCHEMA_HAS_IfcDirectrixCurveSweptAreaSolid
// IfcDirectrixCurveSweptAreaSolid introduced in 4.3 changed attribute type
// from optional IfcParamValue to optional IfcCurveMeasureSelect.
+16 -33
View File
@@ -18,7 +18,7 @@
********************************************************************************/
#include "mapping.h"
#include "../piecewise_function_evaluator.h"
#include "../function_item_evaluator.h"
#define mapping POSTFIX_SCHEMA(mapping)
using namespace ifcopenshell::geometry;
@@ -30,15 +30,17 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) {
auto segments = inst->Segments();
std::vector<taxonomy::piecewise_function::ptr> pwfs;
taxonomy::piecewise_function::spans_t spans;
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) {
pwfs.push_back(taxonomy::cast<taxonomy::piecewise_function>(crv));
} else {
if (auto fi = taxonomy::dcast<taxonomy::function_item>(crv); crv && fi /*crv->kind() == taxonomy::FUNCTION_ITEM*/) {
// crv->kind() is polymorphic and the kind of the actual function_item is returned. PWF can have spans of any FUNCTION_ITEM
// for this reason, a dynamic cast is used and if crv is a function_item it is added to the span
spans.push_back(fi);
} else {
Logger::Error("Unsupported");
return nullptr;
}
@@ -56,40 +58,21 @@ 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<taxonomy::piecewise_function>(gradient_start, pwfs);
auto vertical = taxonomy::make<taxonomy::piecewise_function>(gradient_start, spans);
// Determine the valid domain of the PWF... the valid domain is where both
// the base curve and gradient curves are defined
// create the horizontal pwf
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)) {
// create the composite gradient curve function
auto gradient_function = taxonomy::make<taxonomy::gradient_function>(horizontal, vertical, inst);
// check to see if there is valid overlap of the horizontal and vertical domains
if (!(0 < gradient_function->length())) {
Logger::Error("IfcGradientCurve does not have a common domain with BaseCurve");
gradient_function = nullptr; // not valid
}
// define the callback function for the gradient curve
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_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
uz.row(1).swap(uz.row(2));
Eigen::Matrix4d m;
m = xy * uz; // combine horizontal and vertical
return m;
};
taxonomy::piecewise_function::spans_t spans;
spans.emplace_back(length, composition);
auto pwf = taxonomy::make<taxonomy::piecewise_function>(start, spans, inst);
return pwf;
return gradient_function;
}
#endif
@@ -19,7 +19,7 @@
#include "mapping.h"
#include "../profile_helper.h"
#include "../piecewise_function_evaluator.h"
#include "../function_item_evaluator.h"
#define mapping POSTFIX_SCHEMA(mapping)
using namespace ifcopenshell::geometry;
@@ -39,10 +39,10 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
auto first_offset_value = *(offset_values->begin());
auto basis_curve = inst->BasisCurve();
auto pw_curve = taxonomy::dcast<taxonomy::piecewise_function>(map(basis_curve));
auto curve = taxonomy::dcast<taxonomy::piecewise_function>(map(basis_curve));
double start = pw_curve->start();
double basis_curve_length = pw_curve->length();
double start = curve->start();
double basis_curve_length = curve->length();
taxonomy::piecewise_function::spans_t offset_spans;
@@ -70,7 +70,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
m.col(3)(1) = py;
m.col(3)(2) = pz;
return m; };
offset_spans.emplace_back(first_distance, fn);
offset_spans.emplace_back(taxonomy::make<taxonomy::functor_item>(first_distance, fn));
}
auto iter = offset_values->begin();
@@ -114,7 +114,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;
};
offset_spans.emplace_back(l, fn);
offset_spans.emplace_back(taxonomy::make<taxonomy::functor_item>(l, fn));
}
// at this point, next == end and prev == end-1
@@ -142,25 +142,13 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
m.col(3)(2) = pz;
return m; };
offset_spans.emplace_back(l, fn);
offset_spans.emplace_back(taxonomy::make<taxonomy::functor_item>(l, fn));
}
auto offsets = taxonomy::make<taxonomy::piecewise_function>(start,offset_spans);
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;
};
// 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_t spans;
spans.emplace_back(basis_curve_length, composition);
auto pwf = taxonomy::make<taxonomy::piecewise_function>(start,spans,inst);
return pwf;
auto fn = taxonomy::make<taxonomy::offset_function>(curve, offsets);
return fn;
}
#endif
@@ -19,7 +19,7 @@
#include "mapping.h"
#include "../profile_helper.h"
#include "../piecewise_function_evaluator.h"
#include "../function_item_evaluator.h"
#define mapping POSTFIX_SCHEMA(mapping)
using namespace ifcopenshell::geometry;
@@ -28,11 +28,15 @@ using namespace ifcopenshell::geometry;
taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPointByDistanceExpression* inst) {
auto u = (*inst->DistanceAlong()->as<IfcSchema::IfcLengthMeasure>()) * length_unit_;
//auto basis_curve = inst->BasisCurve();
//auto item = map(basis_curve);
//auto pw_curve = ifcopenshell::geometry::piecewise_from_item(item);
auto pw_curve = taxonomy::dcast<taxonomy::piecewise_function>(map(inst->BasisCurve()));
piecewise_function_evaluator evaluator(pw_curve,&settings_);
auto basis_curve = map(inst->BasisCurve());
taxonomy::function_item::ptr curve = taxonomy::dcast<taxonomy::function_item>(basis_curve);
if (!curve) {
// if the basis curve is not a function_item, the cast it to piecewise_function. the casting operator
// calls loop_to_piecewise_function_upgrade and will convert loops to a piecewise function
curve = taxonomy::dcast<taxonomy::piecewise_function>(basis_curve);
}
function_item_evaluator evaluator(settings_,curve);
auto m = evaluator.evaluate(u);
auto o = m.col(3).head<3>();
@@ -21,7 +21,7 @@
#define mapping POSTFIX_SCHEMA(mapping)
using namespace ifcopenshell::geometry;
#include "../piecewise_function_evaluator.h"
#include "../function_item_evaluator.h"
#ifdef SCHEMA_HAS_IfcSegmentedReferenceCurve
@@ -31,14 +31,16 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins
auto segments = inst->Segments();
std::vector<taxonomy::piecewise_function::ptr> pwfs;
taxonomy::piecewise_function::spans_t spans;
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) {
pwfs.push_back(taxonomy::cast<taxonomy::piecewise_function>(crv));
} else {
if (auto fi = taxonomy::dcast<taxonomy::function_item>(crv); crv && fi /*crv->kind() == taxonomy::FUNCTION_ITEM*/) {
// crv->kind() is polymorphic and the kind of the actual function_item is returned. PWF can have spans of any FUNCTION_ITEM
// for this reason, a dynamic cast is used and if crv is a function_item it is added to the span
spans.push_back(fi);
} else {
Logger::Error("Unsupported");
return nullptr;
}
@@ -55,61 +57,15 @@ 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<taxonomy::piecewise_function>(cant_start,pwfs);
auto cant = taxonomy::make<taxonomy::piecewise_function>(cant_start,spans);
auto gradient = taxonomy::cast<taxonomy::gradient_function>(map(inst->BaseCurve()));
// 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
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_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
// they are relative to the gradient curve coordinate system
//
// However, the coordinate points don't need to have the rotations
// of g applied. Save off the x,y,z and cant values
auto x = g(0, 3);
auto y = g(1, 3);
auto z = g(2, 3);
auto s = c(1, 3); // superelevation
// change column 3 to (0,0,0,1)
Eigen::Vector4d p(0, 0, 0, 1);
g.col(3) = p;
c.col(3) = p;
// multiply g and c to get the axes in the correct orientation
Eigen::Matrix4d m = g * c;
// reinstate the values for x and y.
// z is the gradient curve z value plus the superelevation
// that comes from the cant.
m(0, 3) = x;
m(1, 3) = y;
m(2, 3) = z + s;
return m;
};
taxonomy::piecewise_function::spans_t spans;
spans.emplace_back(length, composition);
auto pwf = taxonomy::make<taxonomy::piecewise_function>(start, spans, inst);
return pwf;
auto cant_function = taxonomy::make<taxonomy::cant_function>(gradient, cant, inst);
if (!(0 < cant_function->length())) {
Logger::Error("IfcSegmentedReferenceCurve does not have a common domain with BaseCurve");
cant_function = nullptr;
}
return cant_function;
}
#endif
@@ -1,103 +0,0 @@
#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, const ifcopenshell::geometry::Settings* settings) : pwf_(pwf) {
if (settings) {
settings_ = *settings;
}
}
std::vector<double> piecewise_function_evaluator::evaluation_points() const {
if (!eval_points_.has_value()) {
double curve_length = pwf_->length();
auto param_type = settings_.get<ifcopenshell::geometry::settings::PiecewiseStepType>().get();
auto param = settings_.get<ifcopenshell::geometry::settings::PiecewiseStepParam>().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<double> 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<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;
}
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<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(0, 3), m(1, 3), m(2, 3)));
}
return polygon_from_points(polygon);
}
std::tuple<double, double, const std::function<Eigen::Matrix4d(double u)>*> 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<ifcopenshell::geometry::settings::Precision>().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};
}
-49
View File
@@ -1,49 +0,0 @@
#include "piecewise_function_impl.h"
#include "profile_helper.h"
namespace ifcopenshell {
namespace geometry {
namespace taxonomy {
piecewise_function_impl::piecewise_function_impl(double start, const spans_t& s) : start_(start), spans_(s) {
}
piecewise_function_impl::piecewise_function_impl(double start, const std::vector<piecewise_function::ptr>& pwfs) : start_(start) {
for (auto& pwf : pwfs) {
spans_.insert(spans_.end(), pwf->spans().begin(), pwf->spans().end());
}
}
const piecewise_function_impl::spans_t& piecewise_function_impl::spans() const { return spans_; }
bool piecewise_function_impl::is_empty() const { return spans_.empty(); }
double piecewise_function_impl::start() const {
return start_;
}
double piecewise_function_impl::end() const {
return start_ + length();
}
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_;
}
piecewise_function_impl* piecewise_function_impl::clone_() const { return new piecewise_function_impl(*this); }
} // namespace taxonomy
} // namespace geometry
} // namespace ifcopenshell
-37
View File
@@ -1,37 +0,0 @@
#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);
piecewise_function_impl(double start, const std::vector<piecewise_function::ptr>& pwfs);
piecewise_function_impl(piecewise_function_impl&&) = default;
piecewise_function_impl(const piecewise_function_impl&) = default;
const spans_t& spans() const;
bool is_empty() const;
double start() const;
double end() const;
double length() const;
piecewise_function_impl* clone_() const;
private:
double start_ = 0.0; // starting value of the pwf
spans_t spans_;
//mutable boost::optional<double> length_; // used for length() method
};
} // namespace taxonomy
} // namespace geometry
} // namespace ifcopenshell
#endif PIECEWISE_FUNCTION_IMPL
+100 -17
View File
@@ -1,7 +1,7 @@
#include "../ifcparse/IfcLogger.h"
#include "taxonomy.h"
#include "profile_helper.h"
#include "piecewise_function_impl.h"
#include "function_item_evaluator.h"
using namespace ifcopenshell::geometry::taxonomy;
@@ -163,10 +163,30 @@ namespace {
throw std::runtime_error("not implemented");
}
bool compare(const function_item&, const function_item&) {
throw std::runtime_error("not implemented");
}
bool compare(const functor_item&, const functor_item&) {
throw std::runtime_error("not implemented");
}
bool compare(const piecewise_function&, const piecewise_function&) {
throw std::runtime_error("not implemented");
}
bool compare(const gradient_function&, const gradient_function&) {
throw std::runtime_error("not implemented");
}
bool compare(const cant_function&, const cant_function&) {
throw std::runtime_error("not implemented");
}
bool compare(const offset_function&, const offset_function&) {
throw std::runtime_error("not implemented");
}
bool compare(const style& a, const style& b) {
const int order[5] = {
less_to_order(a.name, b.name),
@@ -464,27 +484,58 @@ ifcopenshell::geometry::taxonomy::solid::ptr ifcopenshell::geometry::create_box(
}
///////////////////
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 spans_t& s, const IfcUtil::IfcBaseInterface* instance) : function_item(instance), start_(start), spans_(s) {
}
piecewise_function::piecewise_function(double start, const std::vector<piecewise_function::ptr>& pwfs, const IfcUtil::IfcBaseInterface* instance) : implicit_item(instance) {
impl_ = new piecewise_function_impl(start, pwfs);
piecewise_function::piecewise_function(double start, const std::vector<piecewise_function::ptr>& pwfs, const IfcUtil::IfcBaseInterface* instance) : function_item(instance), start_(start) {
for (auto& pwf : pwfs) {
spans_.insert(spans_.end(), pwf->spans().begin(), pwf->spans().end());
}
};
piecewise_function::piecewise_function(const piecewise_function& other) : implicit_item(other) {
impl_ = other.impl_->clone_();
const piecewise_function::spans_t& piecewise_function::spans() const { return spans_; }
bool piecewise_function::is_empty() const { return spans_.empty(); }
double piecewise_function::start() const { return start_; }
double piecewise_function::end() const { return start_ + length(); }
double piecewise_function::length() const {
return std::accumulate(spans_.begin(), spans_.end(), 0.0, [](const auto& v, const auto& s) { return v + s->length(); });
// 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->length(); });
//}
//return *length_;
}
piecewise_function::~piecewise_function() {
delete impl_;
}
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(); }
gradient_function::gradient_function(piecewise_function::const_ptr horizontal, piecewise_function::const_ptr vertical, const IfcUtil::IfcBaseInterface* instance) :
function_item(instance), horizontal_(horizontal), vertical_(vertical) {
}
double gradient_function::start() const { return std::max(horizontal_->start(), vertical_->start()); }
double gradient_function::end() const { return std::min(horizontal_->end(), vertical_->end()); }
piecewise_function::const_ptr gradient_function::get_horizontal() const { return horizontal_; }
piecewise_function::const_ptr gradient_function::get_vertical() const { return vertical_; }
cant_function::cant_function(gradient_function::const_ptr gradient, piecewise_function::const_ptr cant, const IfcUtil::IfcBaseInterface* instance) :
function_item(instance), gradient_(gradient), cant_(cant) {
}
double cant_function::start() const { return std::max(gradient_->start(), cant_->start()); }
double cant_function::end() const { return std::min(gradient_->end(), cant_->end()); }
gradient_function::const_ptr cant_function::get_gradient() const { return gradient_; }
piecewise_function::const_ptr cant_function::get_cant() const { return cant_; }
offset_function::offset_function(function_item::const_ptr basis, piecewise_function::const_ptr offset, const IfcUtil::IfcBaseInterface* instance) : function_item(instance),
basis_(basis),
offset_(offset) {
}
double offset_function::start() const { return basis_->start(); }
double offset_function::end() const { return basis_->end(); }
function_item::const_ptr offset_function::get_basis() const { return basis_; }
piecewise_function::const_ptr offset_function::get_offset() const { return offset_; }
ifcopenshell::geometry::taxonomy::collection::ptr ifcopenshell::geometry::flatten(const taxonomy::collection::ptr& deep) {
@@ -499,7 +550,39 @@ const std::string& ifcopenshell::geometry::taxonomy::kind_to_string(kinds k) {
using namespace std::string_literals;
static std::string values[] = {
"matrix4"s, "point3"s, "direction3"s, "line"s, "circle"s, "ellipse"s, "bspline_curve"s, "offset_curve"s, "plane"s, "cylinder"s, "sphere"s, "torus"s, "bspline_surface"s, "edge"s, "loop"s, "face"s, "shell"s, "solid"s, "loft"s, "extrusion"s, "revolve"s, "sweep_along_curve"s, "node"s, "collection"s, "boolean_result"s, "piecewise_function"s, "colour"s, "style"s,
"matrix4"s,
"point3"s,
"direction3"s,
"line"s,
"circle"s,
"ellipse"s,
"bspline_curve"s,
"offset_curve"s,
"plane"s,
"cylinder"s,
"sphere"s,
"torus"s,
"bspline_surface"s,
"edge"s,
"loop"s,
"face"s,
"shell"s,
"solid"s,
"loft"s,
"extrusion"s,
"revolve"s,
"sweep_along_curve"s,
"node"s,
"collection"s,
"boolean_result"s,
"function_item"s,
"functor_item"s,
"piecewise_function"s,
"gradient_function"s,
"cant_function"s,
"offset_function"s,
"colour"s,
"style"s,
};
return values[k];
@@ -743,7 +826,7 @@ boost::optional<piecewise_function::ptr> ifcopenshell::geometry::taxonomy::loop_
axis = refDirection.cross(Y).normalized();
return make<matrix4>(o, axis, refDirection)->components();
};
spans.emplace_back(l, fn);
spans.emplace_back(taxonomy::make<taxonomy::functor_item>(l, fn));
}
pwf_ = make<piecewise_function>(0.0,spans);
loop_->pwf = pwf_;
+185 -16
View File
@@ -93,7 +93,50 @@ typedef item const* ptr;
topology_error(const char* const s) : std::runtime_error(s) {}
};
enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE_CURVE, OFFSET_CURVE, PLANE, CYLINDER, SPHERE, TORUS, BSPLINE_SURFACE, EDGE, LOOP, FACE, SHELL, SOLID, LOFT, EXTRUSION, REVOLVE, SWEEP_ALONG_CURVE, NODE, COLLECTION, BOOLEAN_RESULT, PIECEWISE_FUNCTION, COLOUR, STYLE };
// Implementer note: If you add a new item type, be sure to do the following
// 1) Add a new kind to this list
// 2) Update the values array used by kind_to_string()
// 3) Update the KindsTuple with the class name of the new item
// 4) Add compare function (see compare functions in taxonomy.cpp starting around line 9)
// 4) Update Python bindings
// a) update list of assign_repr in IfcGeomWrapper.i
// b) update inheritance list in IfcGeomWrapper.i (around line 120 in the file)
// c) update item_to_pyobject function definition in type_conversion.i
enum kinds {
MATRIX4,
POINT3,
DIRECTION3,
LINE,
CIRCLE,
ELLIPSE,
BSPLINE_CURVE,
OFFSET_CURVE,
PLANE,
CYLINDER,
SPHERE,
TORUS,
BSPLINE_SURFACE,
EDGE,
LOOP,
FACE,
SHELL,
SOLID,
LOFT,
EXTRUSION,
REVOLVE,
SWEEP_ALONG_CURVE,
NODE,
COLLECTION,
BOOLEAN_RESULT,
FUNCTION_ITEM,
FUNCTOR_ITEM,
PIECEWISE_FUNCTION,
GRADIENT_FUNCTION,
CANT_FUNCTION,
OFFSET_FUNCTION,
COLOUR,
STYLE
};
const std::string& kind_to_string(kinds k);
@@ -358,25 +401,73 @@ typedef item const* ptr;
using geom_item::geom_item;
};
struct piecewise_function_impl; // forward declaration
struct piecewise_function : public implicit_item {
struct function_item : public implicit_item {
DECLARE_PTR(function_item)
function_item(const IfcUtil::IfcBaseInterface* instance = nullptr) : implicit_item(instance) {}
function_item(function_item&&) = default;
function_item(const function_item&) = default;
virtual ~function_item() = default;
virtual double start() const = 0;
virtual double end() const = 0;
virtual double length() const {
return end() - start();
}
virtual kinds kind() const { return FUNCTION_ITEM; }
virtual size_t calc_hash() const {
auto v = std::make_tuple(static_cast<size_t>(FUNCTION_ITEM), 0);
return boost::hash<decltype(v)>{}(v);
};
};
struct functor_item : public function_item {
DECLARE_PTR(functor_item)
functor_item(double length, std::function<Eigen::Matrix4d(double u)> fn, const IfcUtil::IfcBaseInterface* instance = nullptr) : function_item(instance),
length_(length), fn_(fn) {}
functor_item(functor_item&&) = default;
functor_item(const functor_item&) = default;
virtual ~functor_item() = default;
double start() const override { return 0.0; }
double end() const override { return length_; }
Eigen::Matrix4d operator()(double u) const { return fn_(u); }
functor_item* clone_() const override { return new functor_item(*this); }
virtual kinds kind() const { return FUNCTOR_ITEM; }
virtual size_t calc_hash() const {
auto v = std::make_tuple(static_cast<size_t>(FUNCTOR_ITEM), 0);
return boost::hash<decltype(v)>{}(v);
}
private:
double length_;
std::function<Eigen::Matrix4d(double u)> fn_;
};
struct piecewise_function : public function_item {
DECLARE_PTR(piecewise_function)
using spans_t = std::vector<std::pair<double, std::function<Eigen::Matrix4d(double u)>>>;
using spans_t = std::vector<function_item::const_ptr>;
piecewise_function(double start, const spans_t& s, const IfcUtil::IfcBaseInterface* instance = nullptr);
piecewise_function(double start, const std::vector<piecewise_function::ptr>& pwfs, const IfcUtil::IfcBaseInterface* instance = nullptr);
piecewise_function(piecewise_function&&) = default;
piecewise_function(const piecewise_function&);
virtual ~piecewise_function();
piecewise_function(const piecewise_function&) = default;
virtual ~piecewise_function() = default;
const spans_t& spans() const;
size_t span_count() const {return spans_.size();}
function_item::const_ptr span_fn(size_t i) { return spans_[i]; }
bool is_empty() const;
double start() const;
double end() const;
double length() const;
double start() const override;
double end() const override;
double length() const override;
virtual piecewise_function* clone_() const { return new piecewise_function(*this); }
piecewise_function* clone_() const override { return new piecewise_function(*this); }
virtual kinds kind() const { return PIECEWISE_FUNCTION; }
virtual size_t calc_hash() const {
@@ -385,11 +476,89 @@ typedef item const* ptr;
}
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.
// if this is a std::unique_ptr, then the _ifcopenshell_wrapper library doesn't compile
piecewise_function_impl* impl_ = nullptr;
};
double start_ = 0.0; // starting value of the pwf
spans_t spans_;
};
struct gradient_function : public function_item {
DECLARE_PTR(gradient_function)
gradient_function(piecewise_function::const_ptr horizontal, piecewise_function::const_ptr vertical, const IfcUtil::IfcBaseInterface* instance = nullptr);
gradient_function(gradient_function&&) = default;
gradient_function(const gradient_function&) = default;
virtual ~gradient_function() = default;
virtual double start() const override;
virtual double end() const override;
piecewise_function::const_ptr get_horizontal() const;
piecewise_function::const_ptr get_vertical() const;
gradient_function* clone_() const override { return new gradient_function(*this); }
virtual kinds kind() const { return GRADIENT_FUNCTION; }
virtual size_t calc_hash() const {
auto v = std::make_tuple(static_cast<size_t>(GRADIENT_FUNCTION), 0);
return boost::hash<decltype(v)>{}(v);
}
private:
piecewise_function::const_ptr horizontal_, vertical_;
};
struct cant_function : public function_item {
DECLARE_PTR(cant_function)
cant_function(gradient_function::const_ptr gradient, piecewise_function::const_ptr cant, const IfcUtil::IfcBaseInterface* instance = nullptr);
cant_function(cant_function&&) = default;
cant_function(const cant_function&) = default;
virtual ~cant_function() = default;
virtual double start() const override;
virtual double end() const override;
gradient_function::const_ptr get_gradient() const;
piecewise_function::const_ptr get_cant() const;
cant_function* clone_() const override { return new cant_function(*this); }
virtual kinds kind() const { return CANT_FUNCTION; }
virtual size_t calc_hash() const {
auto v = std::make_tuple(static_cast<size_t>(CANT_FUNCTION), 0);
return boost::hash<decltype(v)>{}(v);
}
private:
gradient_function::const_ptr gradient_;
piecewise_function::const_ptr cant_;
};
struct offset_function : public function_item {
DECLARE_PTR(offset_function)
offset_function(function_item::const_ptr basis, piecewise_function::const_ptr offset, const IfcUtil::IfcBaseInterface* instance = nullptr);
offset_function(offset_function&&) = default;
offset_function(const offset_function&) = default;
virtual ~offset_function() = default;
virtual double start() const override;
virtual double end() const override;
function_item::const_ptr get_basis() const;
piecewise_function::const_ptr get_offset() const;
offset_function* clone_() const override { return new offset_function(*this); }
virtual kinds kind() const { return OFFSET_FUNCTION; }
virtual size_t calc_hash() const {
auto v = std::make_tuple(static_cast<size_t>(OFFSET_FUNCTION), 0);
return boost::hash<decltype(v)>{}(v);
}
private:
function_item::const_ptr basis_;
piecewise_function::const_ptr offset_;
};
#ifdef TAXONOMY_USE_SHARED_PTR
typedef std::shared_ptr<item> ptr;
@@ -1041,7 +1210,7 @@ typedef item const* ptr;
};
namespace impl {
typedef std::tuple<matrix4, point3, direction3, line, circle, ellipse, bspline_curve, offset_curve, plane, cylinder, sphere, torus, bspline_surface, edge, loop, face, shell, solid, loft, extrusion, revolve, sweep_along_curve, node, collection, boolean_result, piecewise_function> KindsTuple;
typedef std::tuple<matrix4, point3, direction3, line, circle, ellipse, bspline_curve, offset_curve, plane, cylinder, sphere, torus, bspline_surface, edge, loop, face, shell, solid, loft, extrusion, revolve, sweep_along_curve, node, collection, boolean_result, function_item, functor_item, piecewise_function, gradient_function, cant_function,offset_function> KindsTuple;
typedef std::tuple<line, circle, ellipse, bspline_curve, offset_curve, loop, edge> CurvesTuple;
typedef std::tuple<plane, cylinder, sphere, torus, bspline_surface, extrusion, revolve> SurfacesTuple;
typedef std::tuple<edge, loop, face, piecewise_function> UpgradesTuple;
+17 -2
View File
@@ -135,7 +135,12 @@ std::pair<char const*, size_t> vector_to_buffer(const T& t) {
if (!$1) $1 = try_upcast<matrix4>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__matrix4_t);
if (!$1) $1 = try_upcast<node>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__node_t);
if (!$1) $1 = try_upcast<offset_curve>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__offset_curve_t);
if (!$1) $1 = try_upcast<function_item>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__function_item_t);
if (!$1) $1 = try_upcast<functor_item>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__functor_item_t);
if (!$1) $1 = try_upcast<piecewise_function>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__piecewise_function_t);
if (!$1) $1 = try_upcast<gradient_function>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__gradient_function_t);
if (!$1) $1 = try_upcast<cant_function>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__cant_function_t);
if (!$1) $1 = try_upcast<offset_function>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__offset_function_t);
if (!$1) $1 = try_upcast<plane>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__plane_t);
if (!$1) $1 = try_upcast<point3>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__point3_t);
if (!$1) $1 = try_upcast<revolve>($input, SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__revolve_t);
@@ -199,7 +204,12 @@ namespace {
%shared_ptr(ifcopenshell::geometry::taxonomy::boolean_result);
%shared_ptr(ifcopenshell::geometry::taxonomy::item);
%shared_ptr(ifcopenshell::geometry::taxonomy::implicit_item);
%shared_ptr(ifcopenshell::geometry::taxonomy::function_item);
%shared_ptr(ifcopenshell::geometry::taxonomy::functor_item);
%shared_ptr(ifcopenshell::geometry::taxonomy::piecewise_function);
%shared_ptr(ifcopenshell::geometry::taxonomy::gradient_function);
%shared_ptr(ifcopenshell::geometry::taxonomy::cant_function);
%shared_ptr(ifcopenshell::geometry::taxonomy::offset_function);
%shared_ptr(ifcopenshell::geometry::taxonomy::less_functor);
%shared_ptr(ifcopenshell::geometry::taxonomy::eigen_base);
%shared_ptr(ifcopenshell::geometry::taxonomy::matrix4);
@@ -246,7 +256,7 @@ namespace {
%include "../ifcgeom/Iterator.h"
%include "../ifcgeom/GeometrySerializer.h"
%include "../ifcgeom/taxonomy.h"
%include "../ifcgeom/piecewise_function_evaluator.h"
%include "../ifcgeom/function_item_evaluator.h"
%include "../serializers/SvgSerializer.h"
%include "../serializers/HdfSerializer.h"
@@ -358,7 +368,7 @@ assign_matrix_access(revolve);
void set_(const std::string& name, ifcopenshell::geometry::settings::IteratorOutputOptions val) {
return $self->set(name, val);
}
void set_(const std::string& name, ifcopenshell::geometry::settings::PiecewiseStepMethod val) {
void set_(const std::string& name, ifcopenshell::geometry::settings::FunctionStepMethod val) {
return $self->set(name, val);
}
void set_(const std::string& name, ifcopenshell::geometry::settings::OutputDimensionalityTypes val) {
@@ -1291,7 +1301,12 @@ assign_repr(ifcopenshell::geometry::taxonomy::loop)
assign_repr(ifcopenshell::geometry::taxonomy::matrix4)
assign_repr(ifcopenshell::geometry::taxonomy::node)
assign_repr(ifcopenshell::geometry::taxonomy::offset_curve)
assign_repr(ifcopenshell::geometry::taxonomy::function_item)
assign_repr(ifcopenshell::geometry::taxonomy::functor_item)
assign_repr(ifcopenshell::geometry::taxonomy::piecewise_function)
assign_repr(ifcopenshell::geometry::taxonomy::gradient_function)
assign_repr(ifcopenshell::geometry::taxonomy::cant_function)
assign_repr(ifcopenshell::geometry::taxonomy::offset_function)
assign_repr(ifcopenshell::geometry::taxonomy::plane)
assign_repr(ifcopenshell::geometry::taxonomy::point3)
assign_repr(ifcopenshell::geometry::taxonomy::revolve)
+2 -2
View File
@@ -171,7 +171,7 @@
%{
#include "../ifcgeom/Iterator.h"
#include "../ifcgeom/taxonomy.h"
#include "../ifcgeom/piecewise_function_evaluator.h"
#include "../ifcgeom/function_item_evaluator.h"
#ifdef IFOPSH_WITH_OPENCASCADE
#include "../ifcgeom/Serialization/Serialization.h"
#include "../ifcgeom/kernels/opencascade/IfcGeomTree.h"
@@ -265,7 +265,7 @@ constexpr bool is_std_vector_vector_v = is_std_vector_vector<T>::value;
%module ifcopenshell_wrapper %{
#include "../ifcgeom/Converter.h"
#include "../ifcgeom/taxonomy.h"
#include "../ifcgeom/piecewise_function_evaluator.h"
#include "../ifcgeom/function_item_evaluator.h"
#ifdef IFOPSH_WITH_OPENCASCADE
#include "../ifcgeom/Serialization/Serialization.h"
#include "../ifcgeom/kernels/opencascade/IfcGeomTree.h"
+5
View File
@@ -261,7 +261,12 @@ PyObject* item_to_pyobject(const ifcopenshell::geometry::taxonomy::item::ptr& i)
else if (kind == MATRIX4) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<matrix4>(std::static_pointer_cast<matrix4>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__matrix4_t, 0 | SWIG_POINTER_OWN); }
else if (kind == NODE) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<node>(std::static_pointer_cast<node>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__node_t, 0 | SWIG_POINTER_OWN); }
else if (kind == OFFSET_CURVE) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<offset_curve>(std::static_pointer_cast<offset_curve>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__offset_curve_t, 0 | SWIG_POINTER_OWN); }
else if (kind == FUNCTION_ITEM) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<function_item>(std::static_pointer_cast<function_item>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__function_item_t, 0 | SWIG_POINTER_OWN); }
else if (kind == FUNCTOR_ITEM) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<functor_item>(std::static_pointer_cast<functor_item>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__functor_item_t, 0 | SWIG_POINTER_OWN); }
else if (kind == PIECEWISE_FUNCTION) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<piecewise_function>(std::static_pointer_cast<piecewise_function>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__piecewise_function_t, 0 | SWIG_POINTER_OWN); }
else if (kind == GRADIENT_FUNCTION) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<gradient_function>(std::static_pointer_cast<gradient_function>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__gradient_function_t, 0 | SWIG_POINTER_OWN); }
else if (kind == CANT_FUNCTION) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<cant_function>(std::static_pointer_cast<cant_function>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__cant_function_t, 0 | SWIG_POINTER_OWN); }
else if (kind == OFFSET_FUNCTION) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<offset_function>(std::static_pointer_cast<offset_function>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__offset_function_t, 0 | SWIG_POINTER_OWN); }
else if (kind == PLANE) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<plane>(std::static_pointer_cast<plane>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__plane_t, 0 | SWIG_POINTER_OWN); }
else if (kind == POINT3) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<point3>(std::static_pointer_cast<point3>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__point3_t, 0 | SWIG_POINTER_OWN); }
else if (kind == REVOLVE) { return SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<revolve>(std::static_pointer_cast<revolve>(i))), SWIGTYPE_p_std__shared_ptrT_ifcopenshell__geometry__taxonomy__revolve_t, 0 | SWIG_POINTER_OWN); }