mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-20 20:22:09 +00:00
4597929df9
Rename header-scope aliases, enums, and helper types while retaining descriptive names where dropping the suffix would create a collision. Generated with the assistance of an AI coding tool.
1761 lines
53 KiB
C++
1761 lines
53 KiB
C++
#ifndef TAXONOMY_H
|
|
#define TAXONOMY_H
|
|
|
|
#include "../ifcparse/express.h"
|
|
#include "../ifcparse/logger.h"
|
|
|
|
#include "conversion_settings.h"
|
|
|
|
#include <boost/variant.hpp>
|
|
#include <boost/functional/hash.hpp>
|
|
#include <boost/math/constants/constants.hpp>
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
#include <map>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <exception>
|
|
#include <numeric>
|
|
#include <cstdint>
|
|
#include <cmath>
|
|
#include <array>
|
|
#include <limits>
|
|
#include <functional>
|
|
#include <algorithm>
|
|
#include <stdexcept>
|
|
|
|
#ifndef TAXONOMY_USE_UNIQUE_PTR
|
|
#ifndef TAXONOMY_USE_NAKED_PTR
|
|
#define TAXONOMY_USE_SHARED_PTR
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef TAXONOMY_USE_SHARED_PTR
|
|
#include <memory>
|
|
#endif
|
|
|
|
// @todo don't do std::less but use hashing and cache hash values.
|
|
|
|
namespace boost { inline std::size_t hash_value(const boost::blank&) { return 0; } }
|
|
|
|
namespace ifcopenshell {
|
|
|
|
namespace geom {
|
|
|
|
namespace taxonomy {
|
|
|
|
#ifdef TAXONOMY_USE_SHARED_PTR
|
|
template <typename T>
|
|
T clone(T& t) {
|
|
return t;
|
|
}
|
|
template <typename T, typename U>
|
|
std::shared_ptr<T> cast(const std::shared_ptr<U>& u);
|
|
template <typename T, typename U>
|
|
std::shared_ptr<T> dcast(const std::shared_ptr<U>& u);
|
|
#endif
|
|
#ifdef TAXONOMY_USE_UNIQUE_PTR
|
|
// untested currently
|
|
template <typename T>
|
|
T clone(T& t) {
|
|
return t->clone_();
|
|
}
|
|
template <typename T, typename U>
|
|
T* cast(const std::unique_ptr<U>& u);
|
|
template <typename T, typename U>
|
|
T* dcast(const std::unique_ptr<U>& u);
|
|
#endif
|
|
#ifdef TAXONOMY_USE_NAKED_PTR
|
|
// untested currently
|
|
template <typename T>
|
|
T clone(T& t) {
|
|
return t->clone_();
|
|
}
|
|
template <typename T, typename U>
|
|
T* cast(const U*& u);
|
|
template <typename T, typename U>
|
|
T* dcast(const U*& u);
|
|
#endif
|
|
|
|
#ifdef TAXONOMY_USE_SHARED_PTR
|
|
#define DECLARE_PTR(item) \
|
|
typedef std::shared_ptr<item> ptr; \
|
|
typedef std::shared_ptr<const item> const_ptr;
|
|
#endif
|
|
#ifdef TAXONOMY_USE_UNIQUE_PTR
|
|
#define DECLARE_PTR(item) \
|
|
typedef std::uniqe_ptr<item> ptr; \
|
|
typedef std::uniqe_ptr<const item> ptr;
|
|
#endif
|
|
#ifdef TAXONOMY_USE_NAKED_PTR
|
|
#define DECLARE_PTR(item) \
|
|
typedef item* ptr; \
|
|
typedef item const* ptr;
|
|
#endif
|
|
|
|
#if defined(_MSC_VER)
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4275)
|
|
#endif
|
|
|
|
class IFC_GEOM_API topology_error : public std::runtime_error {
|
|
public:
|
|
topology_error() : std::runtime_error("Generic topology error") {}
|
|
topology_error(const char* const s) : std::runtime_error(s) {}
|
|
~topology_error() override;
|
|
};
|
|
|
|
#if defined(_MSC_VER)
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
// 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 kinds_tuple 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
|
|
};
|
|
|
|
IFC_GEOM_API const std::string& kind_to_string(kinds k);
|
|
|
|
struct IFC_GEOM_API item {
|
|
private:
|
|
uint32_t identity_;
|
|
static std::atomic_uint32_t counter_;
|
|
mutable size_t computed_hash_;
|
|
public:
|
|
DECLARE_PTR(item)
|
|
|
|
express::base instance;
|
|
|
|
std::optional<bool> orientation;
|
|
|
|
virtual item* clone_() const = 0;
|
|
virtual kinds kind() const = 0;
|
|
virtual void print(std::ostream&, int indent = 0) const;
|
|
virtual void reverse() { throw taxonomy::topology_error(); }
|
|
virtual size_t calc_hash() const = 0;
|
|
virtual size_t hash() const {
|
|
if (computed_hash_) {
|
|
return computed_hash_;
|
|
}
|
|
computed_hash_ = calc_hash();
|
|
if (computed_hash_ == 0) {
|
|
computed_hash_++;
|
|
}
|
|
return computed_hash_;
|
|
}
|
|
|
|
item(const express::base& instance = express::base()) : identity_(counter_++), computed_hash_(0), instance(instance) {}
|
|
|
|
virtual ~item() {}
|
|
|
|
uint32_t identity() const { return identity_; }
|
|
};
|
|
|
|
namespace {
|
|
|
|
template <typename T>
|
|
const T& eigen_defaults();
|
|
|
|
template <>
|
|
const Eigen::Vector3d& eigen_defaults<Eigen::Vector3d>() {
|
|
static Eigen::Vector3d identity = Eigen::Vector3d::Zero();
|
|
return identity;
|
|
}
|
|
|
|
template <>
|
|
const Eigen::Matrix4d& eigen_defaults<Eigen::Matrix4d>() {
|
|
static Eigen::Matrix4d identity = Eigen::Matrix4d::Identity();
|
|
return identity;
|
|
}
|
|
|
|
}
|
|
|
|
template <typename T>
|
|
struct IFC_GEOM_API eigen_base {
|
|
T* components_;
|
|
|
|
eigen_base() {
|
|
components_ = nullptr;
|
|
}
|
|
|
|
eigen_base(const eigen_base& other) {
|
|
this->components_ = other.components_ ? new T(*other.components_) : nullptr;
|
|
}
|
|
|
|
eigen_base(const T& other) {
|
|
this->components_ = new T(other);
|
|
}
|
|
|
|
eigen_base& operator=(const eigen_base& other) {
|
|
if (this != &other) {
|
|
this->components_ = other.components_ ? new T(*other.components_) : nullptr;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void print_impl(std::ostream& o, const std::string& class_name, int indent = 0) const {
|
|
o << std::string(indent, ' ') << class_name;
|
|
if (this->components_) {
|
|
int n = T::RowsAtCompileTime * T::ColsAtCompileTime;
|
|
for (int i = 0; i < n; ++i) {
|
|
o << " " << (*components_)(i);
|
|
}
|
|
}
|
|
o << std::endl;
|
|
}
|
|
|
|
virtual ~eigen_base() {
|
|
delete this->components_;
|
|
}
|
|
|
|
const T& ccomponents() const {
|
|
if (this->components_) {
|
|
return *this->components_;
|
|
} else {
|
|
return eigen_defaults<T>();
|
|
}
|
|
}
|
|
|
|
T& components() {
|
|
if (!this->components_) {
|
|
this->components_ = new T(eigen_defaults<T>());
|
|
}
|
|
return *this->components_;
|
|
}
|
|
|
|
explicit operator bool() const {
|
|
return components_;
|
|
}
|
|
|
|
uint32_t hash_components() const {
|
|
size_t h = std::hash<size_t>{}(T::RowsAtCompileTime);
|
|
boost::hash_combine(h, std::hash<size_t>{}(T::ColsAtCompileTime));
|
|
if (components_) {
|
|
for (int i = 0; i < components_->size(); ++i) {
|
|
auto elem = *(components_->data() + (size_t)i);
|
|
boost::hash_combine(h, std::hash<typename T::Scalar>()(elem));
|
|
}
|
|
}
|
|
return (uint32_t)h;
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API matrix4 : public item, public eigen_base<Eigen::Matrix4d> {
|
|
private:
|
|
void init(const Eigen::Vector3d& o, const Eigen::Vector3d& z, const Eigen::Vector3d& x) {
|
|
auto Z = z.normalized();
|
|
auto Y = Z.cross(x).normalized();
|
|
auto X = Y.cross(Z);
|
|
components_ = new Eigen::Matrix4d;
|
|
(*components_) <<
|
|
X(0), Y(0), Z(0), o(0),
|
|
X(1), Y(1), Z(1), o(1),
|
|
X(2), Y(2), Z(2), o(2),
|
|
0, 0, 0, 1.;
|
|
if (is_identity()) {
|
|
// @todo detect this earlier to save us the heapalloc.
|
|
delete components_;
|
|
components_ = nullptr;
|
|
tag = IDENTITY;
|
|
}
|
|
}
|
|
public:
|
|
DECLARE_PTR(matrix4)
|
|
|
|
enum tag_type {
|
|
IDENTITY, AFFINE_WO_SCALE, AFFINE_W_UNIFORM_SCALE, AFFINE_W_NONUNIFORM_SCALE, OTHER
|
|
};
|
|
tag_type tag;
|
|
|
|
matrix4() : eigen_base(), tag(IDENTITY) {}
|
|
matrix4(const Eigen::Matrix4d& c) : eigen_base(c), tag(OTHER) {}
|
|
matrix4(const Eigen::Vector3d& o, const Eigen::Vector3d& z, const Eigen::Vector3d& x) : tag(AFFINE_WO_SCALE) {
|
|
init(o, z, x);
|
|
}
|
|
matrix4(const Eigen::Vector3d& o, const Eigen::Vector3d& z) : tag(AFFINE_WO_SCALE) {
|
|
auto x = Eigen::Vector3d(1, 0, 0);
|
|
auto y = z.cross(x);
|
|
if (y.squaredNorm() < 1.e-7) {
|
|
x = Eigen::Vector3d(0, 0, 1);
|
|
}
|
|
init(o, z, x);
|
|
}
|
|
|
|
bool is_identity() const {
|
|
return !components_ || components_->isIdentity();
|
|
}
|
|
|
|
void print(std::ostream& o, int indent = 0) const;
|
|
|
|
virtual matrix4* clone_() const { return new matrix4(*this); }
|
|
virtual kinds kind() const { return MATRIX4; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(MATRIX4), hash_components());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
|
|
void pre_multiply_scale(double s) {
|
|
components().block<3, 4>(0, 0) *= s;
|
|
}
|
|
|
|
void post_multiply_scale(double s) {
|
|
components().block<4, 3>(0, 0) *= s;
|
|
}
|
|
|
|
Eigen::Vector3d translation_part() const { return ccomponents().col(3).head<3>(); }
|
|
};
|
|
|
|
struct IFC_GEOM_API colour : public item, public eigen_base<Eigen::Vector3d> {
|
|
DECLARE_PTR(colour)
|
|
|
|
void print(std::ostream& o, int indent = 0) const;
|
|
|
|
virtual colour* clone_() const { return new colour(*this); }
|
|
virtual kinds kind() const { return COLOUR; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(COLOUR), hash_components());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
|
|
colour() : eigen_base() {}
|
|
colour(double r, double g, double b) { components() << r, g, b; }
|
|
|
|
const double& r() const { return ccomponents()[0]; }
|
|
const double& g() const { return ccomponents()[1]; }
|
|
const double& b() const { return ccomponents()[2]; }
|
|
};
|
|
|
|
struct IFC_GEOM_API style : public item {
|
|
DECLARE_PTR(style)
|
|
|
|
std::string name;
|
|
colour diffuse;
|
|
colour surface;
|
|
colour specular;
|
|
double specularity, transparency;
|
|
bool use_surface_color;
|
|
|
|
void print(std::ostream& o, int indent = 0) const;
|
|
|
|
virtual style* clone_() const { return new style(*this); }
|
|
virtual kinds kind() const { return STYLE; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(STYLE), name, diffuse.hash(), surface.hash(), specular.hash(), specularity, transparency);
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
|
|
// @todo equality implementation based on values?
|
|
bool operator==(const style& other) const { return instance == other.instance; }
|
|
|
|
style() : specularity(std::numeric_limits<double>::quiet_NaN()), transparency(std::numeric_limits<double>::quiet_NaN()), use_surface_color(false) {}
|
|
style(const std::string& name) : name(name), specularity(std::numeric_limits<double>::quiet_NaN()), transparency(std::numeric_limits<double>::quiet_NaN()), use_surface_color(false) {}
|
|
|
|
const colour& get_color() const {
|
|
if (use_surface_color && surface) {
|
|
return surface;
|
|
}
|
|
return diffuse;
|
|
}
|
|
|
|
bool has_specularity() const {
|
|
return !std::isnan(specularity);
|
|
}
|
|
|
|
bool has_transparency() const {
|
|
return !std::isnan(transparency);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API geom_item : public item {
|
|
DECLARE_PTR(geom_item)
|
|
|
|
style::ptr surface_style;
|
|
matrix4::ptr matrix;
|
|
|
|
geom_item(const express::base& instance = express::base()) : item(instance), surface_style(nullptr) {}
|
|
geom_item(const express::base instance, matrix4::ptr m) : item(instance), surface_style(nullptr), matrix(m) {}
|
|
geom_item(matrix4::ptr m) : surface_style(nullptr), matrix(m) {}
|
|
};
|
|
|
|
struct IFC_GEOM_API implicit_item : public geom_item {
|
|
DECLARE_PTR(implicit_item)
|
|
using geom_item::geom_item;
|
|
};
|
|
|
|
struct IFC_GEOM_API function_item : public implicit_item {
|
|
DECLARE_PTR(function_item)
|
|
|
|
function_item(const express::base& instance = express::base()) : 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 IFC_GEOM_API functor_item : public function_item {
|
|
DECLARE_PTR(functor_item)
|
|
|
|
functor_item(double length, std::function<Eigen::Matrix4d(double u)> fn, const express::base& instance = express::base()) : 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 IFC_GEOM_API piecewise_function : public function_item {
|
|
DECLARE_PTR(piecewise_function)
|
|
|
|
using span_list = std::vector<function_item::const_ptr>;
|
|
|
|
piecewise_function(double start, const span_list& s, const express::base& instance = express::base());
|
|
piecewise_function(double start, const std::vector<piecewise_function::ptr>& pwfs, const express::base& instance = express::base());
|
|
piecewise_function(piecewise_function&&) = default;
|
|
piecewise_function(const piecewise_function&) = default;
|
|
virtual ~piecewise_function() = default;
|
|
|
|
const span_list& 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 override;
|
|
double end() const override;
|
|
double length() const override;
|
|
|
|
piecewise_function* clone_() const override { return new piecewise_function(*this); }
|
|
virtual kinds kind() const { return PIECEWISE_FUNCTION; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(PIECEWISE_FUNCTION), 0);
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
|
|
private:
|
|
double start_ = 0.0; // starting value of the pwf
|
|
span_list spans_;
|
|
};
|
|
|
|
struct IFC_GEOM_API gradient_function : public function_item {
|
|
DECLARE_PTR(gradient_function)
|
|
gradient_function(piecewise_function::const_ptr horizontal, piecewise_function::const_ptr vertical, const express::base& instance = express::base());
|
|
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 IFC_GEOM_API cant_function : public function_item {
|
|
DECLARE_PTR(cant_function)
|
|
cant_function(gradient_function::const_ptr gradient, piecewise_function::const_ptr cant, const express::base& instance = express::base());
|
|
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 IFC_GEOM_API offset_function : public function_item {
|
|
DECLARE_PTR(offset_function)
|
|
offset_function(function_item::const_ptr basis, piecewise_function::const_ptr offset, const express::base& instance = express::base());
|
|
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;
|
|
typedef std::shared_ptr<const item> const_ptr;
|
|
template<typename T, typename... Args>
|
|
std::shared_ptr<T> make(Args&&... args) {
|
|
return std::make_shared<T>(std::forward<Args>(args)...);
|
|
}
|
|
#endif
|
|
#ifdef TAXONOMY_USE_UNIQUE_PTR
|
|
typedef std::uniqe_ptr<item> ptr;
|
|
typedef std::uniqe_ptr<const item> ptr;
|
|
template<typename T, typename... Args>
|
|
std::uniqe_ptr<T> make(Args&&... args) {
|
|
return new T(std::forward<Args>(args)...));
|
|
}
|
|
#endif
|
|
#ifdef TAXONOMY_USE_NAKED_PTR
|
|
typedef item* ptr;
|
|
typedef item const* ptr;
|
|
template<typename T, typename... Args>
|
|
T* make(Args&&... args) {
|
|
return new T(std::forward<Args>(args)...));
|
|
}
|
|
#endif
|
|
|
|
IFC_GEOM_API bool less(item::const_ptr, item::const_ptr);
|
|
|
|
struct less_functor {
|
|
bool operator()(item::const_ptr a, item::const_ptr b) const {
|
|
return less(a, b);
|
|
}
|
|
};
|
|
|
|
struct equal_functor {
|
|
bool operator()(taxonomy::item::ptr const& a,
|
|
taxonomy::item::ptr const& b) const
|
|
{
|
|
if (a == b) {
|
|
return true;
|
|
}
|
|
return !less(a, b) && !less(b, a);
|
|
}
|
|
};
|
|
|
|
struct hash_functor {
|
|
size_t operator()(taxonomy::item::ptr const& a) const
|
|
{
|
|
return a->hash();
|
|
}
|
|
};
|
|
|
|
// @todo make 4d for easier multiplication
|
|
template <size_t N>
|
|
struct IFC_GEOM_API cartesian_base : public item, public eigen_base<Eigen::Vector3d> {
|
|
cartesian_base() : eigen_base() {}
|
|
cartesian_base(const Eigen::Vector3d& c) : eigen_base(c) {}
|
|
cartesian_base(double x, double y, double z = 0.) : eigen_base(Eigen::Vector3d(x, y, z)) {}
|
|
};
|
|
|
|
struct IFC_GEOM_API point3 : public cartesian_base<3> {
|
|
DECLARE_PTR(point3)
|
|
|
|
virtual point3* clone_() const { return new point3(*this); }
|
|
virtual kinds kind() const { return POINT3; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(POINT3), hash_components());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
|
|
void print(std::ostream& o, int indent = 0) const;
|
|
|
|
point3() : cartesian_base() {}
|
|
point3(const Eigen::Vector3d& c) : cartesian_base(c) {}
|
|
point3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {}
|
|
};
|
|
|
|
struct IFC_GEOM_API direction3 : public cartesian_base<3> {
|
|
DECLARE_PTR(direction3)
|
|
|
|
virtual direction3* clone_() const { return new direction3(*this); }
|
|
virtual kinds kind() const { return DIRECTION3; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(DIRECTION3), hash_components());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
|
|
void print(std::ostream& o, int indent = 0) const;
|
|
|
|
direction3() : cartesian_base() {}
|
|
direction3(const Eigen::Vector3d& c) : cartesian_base(c) {}
|
|
direction3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {}
|
|
};
|
|
|
|
struct IFC_GEOM_API curve : public geom_item {
|
|
void print_impl(std::ostream& o, const std::string& classname, int indent = 0) const {
|
|
o << std::string(indent, ' ') << classname << std::endl;
|
|
this->matrix->print(o, indent + 4);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API line : public curve {
|
|
DECLARE_PTR(line)
|
|
|
|
virtual line* clone_() const { return new line(*this); }
|
|
virtual kinds kind() const { return LINE; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(LINE), matrix->hash_components());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
|
|
void print(std::ostream& o, int indent = 0) const;
|
|
};
|
|
|
|
struct IFC_GEOM_API circle : public curve {
|
|
DECLARE_PTR(circle)
|
|
|
|
double radius;
|
|
|
|
virtual circle* clone_() const { return new circle(*this); }
|
|
virtual kinds kind() const { return CIRCLE; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(CIRCLE), matrix->hash_components(), radius);
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
|
|
void print(std::ostream& o, int indent = 0) const;
|
|
|
|
static circle::ptr from_3_points(const Eigen::Vector3d& p1, const Eigen::Vector3d& p2, const Eigen::Vector3d& p3) {
|
|
Eigen::Vector3d t = p2 - p1;
|
|
Eigen::Vector3d u = p3 - p1;
|
|
Eigen::Vector3d v = p3 - p2;
|
|
|
|
auto norm = t.cross(u);
|
|
auto mag = norm.dot(norm);
|
|
|
|
auto iwsl2 = 1. / (2. * mag);
|
|
auto tt = t.dot(t);
|
|
auto uu = u.dot(u);
|
|
|
|
auto orig = p1 + (u * tt * u.dot(v) - t * uu * t.dot(v)) * iwsl2;
|
|
|
|
if (!orig.array().isNaN().any()) {
|
|
auto radius = std::sqrt(tt * uu * v.dot(v) * iwsl2 * 0.5f);
|
|
auto ax = norm / std::sqrt(mag);
|
|
|
|
|
|
auto c = make<circle>();
|
|
c->radius = radius;
|
|
c->matrix = taxonomy::make<taxonomy::matrix4>(orig, ax);
|
|
return c;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API ellipse : public curve {
|
|
DECLARE_PTR(ellipse)
|
|
|
|
double radius;
|
|
double radius2;
|
|
|
|
virtual ellipse* clone_() const { return new ellipse(*this); }
|
|
virtual kinds kind() const { return ELLIPSE; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(ELLIPSE), matrix->hash_components(), radius, radius2);
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
|
|
void print(std::ostream& o, int indent = 0) const;
|
|
};
|
|
|
|
struct IFC_GEOM_API bspline_curve : public curve {
|
|
DECLARE_PTR(bspline_curve)
|
|
|
|
virtual bspline_curve* clone_() const { return new bspline_curve(*this); }
|
|
virtual kinds kind() const { return BSPLINE_CURVE; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
size_t h = std::hash<size_t>{}(BSPLINE_CURVE);
|
|
for (auto& x : control_points) {
|
|
boost::hash_combine(h, x->hash());
|
|
}
|
|
for (auto& x : multiplicities) {
|
|
boost::hash_combine(h, std::hash<int>{}(x));
|
|
}
|
|
for (auto& x : knots) {
|
|
boost::hash_combine(h, std::hash<double>{}(x));
|
|
}
|
|
if (weights) {
|
|
for (auto& x : *weights) {
|
|
boost::hash_combine(h, std::hash<double>{}(x));
|
|
}
|
|
}
|
|
boost::hash_combine(h, std::hash<int>{}(degree));
|
|
return h;
|
|
}
|
|
|
|
std::vector<point3::ptr> control_points;
|
|
std::vector<int> multiplicities;
|
|
std::vector<double> knots;
|
|
std::optional<std::vector<double>> weights;
|
|
int degree;
|
|
};
|
|
|
|
struct IFC_GEOM_API offset_curve : public curve {
|
|
DECLARE_PTR(offset_curve)
|
|
|
|
direction3::ptr reference;
|
|
double offset;
|
|
item::ptr basis;
|
|
|
|
virtual offset_curve* clone_() const { return new offset_curve(*this); }
|
|
virtual kinds kind() const { return OFFSET_CURVE; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(OFFSET_CURVE), reference->hash(), offset, basis ? basis->hash() : size_t(0));
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API trimmed_curve : public geom_item {
|
|
DECLARE_PTR(trimmed_curve)
|
|
|
|
// @todo The copy constructor of point3 within the variant fails on the avx instruction
|
|
// on the default gcc in Ubuntu 18.04 and a recent AMD Ryzen. Probably due to allignment.
|
|
std::variant<boost::blank, point3::ptr, double> start, end;
|
|
|
|
// @todo somehow account for the fact that curve in IFC can be trimmed curve, polyline and composite curve as well.
|
|
item::ptr basis;
|
|
|
|
// @todo does this make sense? this is to accommodate for the fact that orientation is defined on both TrimmedCurve as well CompCurveSegment
|
|
std::optional<bool> curve_sense;
|
|
|
|
trimmed_curve() : basis(nullptr) {}
|
|
trimmed_curve(const point3::ptr& a, const point3::ptr& b) : start(a), end(b), basis(nullptr) {}
|
|
|
|
virtual void reverse() {
|
|
// std::swap(start, end);
|
|
orientation = !orientation.value_or(true);
|
|
}
|
|
|
|
void print(std::ostream& o, int indent = 0) const;
|
|
};
|
|
|
|
struct IFC_GEOM_API edge : public trimmed_curve {
|
|
DECLARE_PTR(edge)
|
|
|
|
edge() : trimmed_curve() {}
|
|
edge(const point3::ptr& a, const point3::ptr& b) : trimmed_curve(a, b) {}
|
|
|
|
// @todo how to express similarity between trimmed_curve and edge?
|
|
virtual edge* clone_() const { return new edge(*this); }
|
|
virtual kinds kind() const { return EDGE; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(EDGE), start, end, basis ? basis->hash() : size_t(0), curve_sense ? *curve_sense ? 2 : 1 : 0);
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
template <typename T = item>
|
|
struct IFC_GEOM_API collection_base : public geom_item {
|
|
std::vector<typename T::ptr> children;
|
|
|
|
collection_base() {}
|
|
collection_base(const collection_base& other)
|
|
: geom_item()
|
|
{
|
|
std::transform(other.children.begin(), other.children.end(), std::back_inserter(children), [](typename T::ptr p) { return clone(p); });
|
|
}
|
|
|
|
/*
|
|
template <typename T>
|
|
std::vector<typename T::ptr> children_as() const {
|
|
std::vector<typename T::ptr> ts;
|
|
ts.reserve(children.size());
|
|
std::for_each(children.begin(), children.end(), [&ts](ptr i){
|
|
auto v = dcast<T>(i);
|
|
if (v) {
|
|
ts.push_back(v);
|
|
}
|
|
});
|
|
return ts;
|
|
}
|
|
*/
|
|
|
|
virtual void reverse() {
|
|
// @todo this needs to create copies of the children in case of shared_ptr
|
|
std::reverse(children.begin(), children.end());
|
|
for (auto& child : children) {
|
|
child->reverse();
|
|
}
|
|
}
|
|
|
|
virtual void print_impl(std::ostream&, int) const {
|
|
// empty on purpose
|
|
}
|
|
|
|
void print(std::ostream& o, int indent = 0) const {
|
|
o << std::string(indent, ' ') << kind_to_string(kind()) << std::endl;
|
|
if (matrix && !matrix->is_identity()) {
|
|
matrix->print(o, indent + 4);
|
|
}
|
|
for (auto& c : children) {
|
|
c->print(o, indent + 4);
|
|
}
|
|
print_impl(o, indent + 4);
|
|
}
|
|
|
|
virtual ~collection_base() {
|
|
#ifdef TAXONOMY_USE_NAKED_PTR
|
|
for (auto& c : children) {
|
|
delete c;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
uint32_t hash_elements() const {
|
|
size_t h = 0;
|
|
for (auto& c : children) {
|
|
boost::hash_combine(h, c->hash());
|
|
}
|
|
// @todo should we really use uint32_t instead of size_t for hashes?
|
|
return (uint32_t) h;
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API collection : public collection_base<geom_item> {
|
|
DECLARE_PTR(collection)
|
|
|
|
virtual collection* clone_() const { return new collection(*this); }
|
|
virtual kinds kind() const { return COLLECTION; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(COLLECTION), hash_elements());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
|
|
struct IFC_GEOM_API loop : public collection_base<edge> {
|
|
DECLARE_PTR(loop)
|
|
|
|
std::optional<bool> external, closed;
|
|
std::optional<taxonomy::function_item::ptr> fi;
|
|
std::optional<std::vector<std::string>> tags;
|
|
|
|
bool is_polyhedron() const {
|
|
for (auto& e : children) {
|
|
if (e->basis != nullptr) {
|
|
if (e->basis->kind() != LINE) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void calculate_linear_edge_curves() const {
|
|
for (auto& e : children) {
|
|
if (e->basis == nullptr) {
|
|
if (e->start.index() == 1 && e->end.index() == 1) {
|
|
auto ln = make<taxonomy::line>();
|
|
auto a = std::get<point3::ptr>(e->start)->ccomponents();
|
|
auto b = std::get<point3::ptr>(e->end)->ccomponents();
|
|
ln->matrix = make<matrix4>(a, b - a);
|
|
e->basis = ln;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void remove_linear_edge_curves() const {
|
|
for (auto& e : children) {
|
|
if (e->basis != nullptr && e->basis->kind() == LINE) {
|
|
e->basis = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual loop* clone_() const { return new loop(*this); }
|
|
virtual kinds kind() const { return LOOP; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(LOOP), hash_elements(), external ? *external ? 2 : 1 : 0, closed ? *closed ? 2 : 1 : 0);
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
|
|
// nb only takes into account explicit points
|
|
taxonomy::point3::ptr centroid() const {
|
|
Eigen::Vector3d c(0, 0, 0);
|
|
for (auto& e : children) {
|
|
if (e->start.index() == 1) {
|
|
c += std::get<point3::ptr>(e->start)->ccomponents();
|
|
}
|
|
if (e->end.index() == 1) {
|
|
c += std::get<point3::ptr>(e->end)->ccomponents();
|
|
}
|
|
}
|
|
c /= static_cast<double>(children.size());
|
|
return make<taxonomy::point3>(c);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API face : public collection_base<loop> {
|
|
DECLARE_PTR(face)
|
|
|
|
item::ptr basis;
|
|
|
|
virtual face* clone_() const { return new face(*this); }
|
|
virtual kinds kind() const { return FACE; }
|
|
|
|
virtual void print_impl(std::ostream& o, int indent) const {
|
|
if (basis) {
|
|
o << std::string(indent, ' ') << "basis" << std::endl;
|
|
basis->print(o, indent + 4);
|
|
}
|
|
}
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(FACE), hash_elements(), basis ? basis->hash() : size_t(0));
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API shell : public collection_base<face> {
|
|
DECLARE_PTR(shell)
|
|
|
|
std::optional<bool> closed;
|
|
|
|
virtual void print_impl(std::ostream& o, int indent) const {
|
|
using namespace std::string_literals;
|
|
o << std::string(indent, ' ') << "closed " << (closed ? *closed ? "yes"s : "no"s : "unknown"s) << std::endl;
|
|
}
|
|
|
|
virtual shell* clone_() const { return new shell(*this); }
|
|
virtual kinds kind() const { return SHELL; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(SHELL), hash_elements(), closed ? *closed ? 2 : 1 : 0);
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
|
|
// nb only takes into account explicit points
|
|
taxonomy::point3::ptr centroid() const {
|
|
Eigen::Vector3d c(0, 0, 0);
|
|
for (auto& f : children) {
|
|
for (auto& l : f->children) {
|
|
for (auto& e : l->children) {
|
|
if (e->start.index() == 1) {
|
|
c += std::get<point3::ptr>(e->start)->ccomponents();
|
|
}
|
|
if (e->end.index() == 1) {
|
|
c += std::get<point3::ptr>(e->end)->ccomponents();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
c /= static_cast<double>(children.size());
|
|
return make<taxonomy::point3>(c);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API solid : public collection_base<shell> {
|
|
DECLARE_PTR(solid)
|
|
|
|
virtual solid* clone_() const { return new solid(*this); }
|
|
virtual kinds kind() const { return SOLID; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(SOLID), hash_elements());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API loft : public collection_base<geom_item> {
|
|
DECLARE_PTR(loft)
|
|
|
|
item::ptr axis;
|
|
|
|
virtual loft* clone_() const { return new loft(*this); }
|
|
virtual kinds kind() const { return LOFT; }
|
|
|
|
virtual void print_impl(std::ostream& o, int indent) const {
|
|
o << std::string(indent, ' ') << "axis" << std::endl;
|
|
axis->print(o, indent + 4);
|
|
}
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(LOFT), hash_elements(), axis ? axis->hash() : size_t(0));
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API surface : public geom_item {};
|
|
|
|
struct IFC_GEOM_API plane : public surface {
|
|
DECLARE_PTR(plane)
|
|
|
|
virtual plane* clone_() const { return new plane(*this); }
|
|
virtual kinds kind() const { return PLANE; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(PLANE), matrix->hash_components());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API cylinder : public surface {
|
|
DECLARE_PTR(cylinder)
|
|
|
|
double radius;
|
|
|
|
virtual cylinder* clone_() const { return new cylinder(*this); }
|
|
virtual kinds kind() const { return CYLINDER; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(CYLINDER), matrix->hash_components());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API sphere : public surface {
|
|
DECLARE_PTR(sphere)
|
|
|
|
double radius;
|
|
|
|
virtual sphere* clone_() const { return new sphere(*this); }
|
|
virtual kinds kind() const { return SPHERE; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(SPHERE), matrix->hash_components());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API torus : public surface {
|
|
DECLARE_PTR(torus)
|
|
|
|
double radius1;
|
|
double radius2;
|
|
|
|
virtual torus* clone_() const { return new torus(*this); }
|
|
virtual kinds kind() const { return TORUS; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(TORUS), matrix->hash_components());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API bspline_surface : public surface {
|
|
DECLARE_PTR(bspline_surface)
|
|
|
|
virtual bspline_surface* clone_() const { return new bspline_surface(*this); }
|
|
virtual kinds kind() const { return BSPLINE_SURFACE; }
|
|
|
|
virtual size_t calc_hash() const {
|
|
size_t h = std::hash<size_t>{}(BSPLINE_SURFACE);
|
|
boost::hash_combine(h, std::hash<size_t>{}(control_points.size()));
|
|
for (auto& xs : control_points) {
|
|
for (auto& x : xs) {
|
|
boost::hash_combine(h, x->hash());
|
|
}
|
|
}
|
|
for (auto& xs : multiplicities) {
|
|
for (auto& x : xs) {
|
|
boost::hash_combine(h, std::hash<int>{}(x));
|
|
}
|
|
}
|
|
for (auto& xs : knots) {
|
|
for (auto& x : xs) {
|
|
boost::hash_combine(h, std::hash<double>{}(x));
|
|
}
|
|
}
|
|
if (weights) {
|
|
for (auto& xs : *weights) {
|
|
for (auto& x : xs) {
|
|
boost::hash_combine(h, std::hash<double>{}(x));
|
|
}
|
|
}
|
|
}
|
|
boost::hash_combine(h, std::hash<int>{}(degree[0]));
|
|
boost::hash_combine(h, std::hash<int>{}(degree[1]));
|
|
return h;
|
|
}
|
|
|
|
std::vector<std::vector<point3::ptr>> control_points;
|
|
std::array<std::vector<int>, 2> multiplicities;
|
|
std::array<std::vector<double>, 2> knots;
|
|
std::optional<std::vector<std::vector<double>>> weights;
|
|
std::array<int, 2> degree;
|
|
};
|
|
|
|
struct IFC_GEOM_API sweep : public geom_item {
|
|
DECLARE_PTR(sweep)
|
|
|
|
item::ptr basis;
|
|
|
|
sweep(face::ptr b) : basis(b) {}
|
|
sweep(matrix4::ptr m, item::ptr b) : geom_item(m), basis(b) {}
|
|
};
|
|
|
|
struct IFC_GEOM_API extrusion : public sweep {
|
|
DECLARE_PTR(extrusion)
|
|
|
|
direction3::ptr direction;
|
|
double depth;
|
|
|
|
virtual extrusion* clone_() const { return new extrusion(*this); }
|
|
virtual kinds kind() const { return EXTRUSION; }
|
|
|
|
extrusion(matrix4::ptr m, item::ptr basis, direction3::ptr dir, double d) : sweep(m, basis), direction(dir), depth(d) {}
|
|
|
|
void print(std::ostream& o, int indent = 0) const;
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(EXTRUSION), matrix->hash_components(), basis->calc_hash(), direction->hash_components(), depth);
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API revolve : public sweep {
|
|
DECLARE_PTR(revolve)
|
|
|
|
point3::ptr axis_origin;
|
|
direction3::ptr direction;
|
|
std::optional<double> angle;
|
|
|
|
virtual revolve* clone_() const { return new revolve(*this); }
|
|
virtual kinds kind() const { return REVOLVE; }
|
|
|
|
revolve(matrix4::ptr m, item::ptr basis, point3::ptr pnt, direction3::ptr dir, const std::optional<double>& a) : sweep(m, basis), axis_origin(pnt), direction(dir), angle(a) {}
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(REVOLVE), matrix->hash_components(), basis->calc_hash(), axis_origin->hash_components(), direction->hash_components(), angle ? *angle : 1000.);
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API sweep_along_curve : public sweep {
|
|
DECLARE_PTR(sweep_along_curve)
|
|
|
|
item::ptr surface;
|
|
item::ptr curve;
|
|
direction3::ptr direction = nullptr;
|
|
|
|
virtual sweep_along_curve* clone_() const { return new sweep_along_curve(*this); }
|
|
virtual kinds kind() const { return SWEEP_ALONG_CURVE; }
|
|
|
|
sweep_along_curve(matrix4::ptr m, face::ptr basis, item::ptr surf, item::ptr crv) : sweep(m, basis), surface(surf), curve(crv), direction(nullptr) {}
|
|
|
|
// New constructor for fixed reference swept area solid
|
|
sweep_along_curve(matrix4::ptr m, face::ptr profile, item::ptr directrix, direction3::ptr ref) : sweep(m, profile), surface(nullptr), curve(directrix), direction(ref) { }
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(SWEEP_ALONG_CURVE), matrix->hash_components(), basis->calc_hash(), surface->calc_hash(), curve->calc_hash());
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API node : public item {
|
|
DECLARE_PTR(node)
|
|
|
|
// std::map<std::string, geom_item> representations;
|
|
|
|
virtual node* clone_() const { return new node(*this); }
|
|
virtual kinds kind() const { return NODE; }
|
|
|
|
void print(std::ostream&, int = 0) const {}
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(NODE));
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
struct IFC_GEOM_API boolean_result : public collection_base<geom_item> {
|
|
DECLARE_PTR(boolean_result)
|
|
|
|
enum operation_type {
|
|
UNION, SUBTRACTION, INTERSECTION
|
|
};
|
|
|
|
virtual boolean_result* clone_() const { return new boolean_result(*this); }
|
|
virtual kinds kind() const { return BOOLEAN_RESULT; }
|
|
operation_type operation;
|
|
|
|
static const std::string& operation_str(operation_type op) {
|
|
using namespace std::string_literals;
|
|
static std::string s[] = { "union"s, "subtraction"s, "intersection"s };
|
|
return s[(size_t)op];
|
|
}
|
|
|
|
virtual size_t calc_hash() const {
|
|
auto v = std::make_tuple(static_cast<size_t>(BOOLEAN_RESULT), hash_elements(), static_cast<size_t>(operation));
|
|
return boost::hash<decltype(v)>{}(v);
|
|
}
|
|
};
|
|
|
|
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, function_item, functor_item, piecewise_function, gradient_function, cant_function,offset_function> kinds_tuple;
|
|
typedef std::tuple<line, circle, ellipse, bspline_curve, offset_curve, loop, edge> curves_tuple;
|
|
typedef std::tuple<plane, cylinder, sphere, torus, bspline_surface, extrusion, revolve> surfaces_tuple;
|
|
typedef std::tuple<edge, loop, face, piecewise_function> upgrades_tuple;
|
|
}
|
|
|
|
struct type_by_kind {
|
|
template <std::size_t N>
|
|
using type = typename std::tuple_element<N, impl::kinds_tuple>::type;
|
|
|
|
static const size_t max = std::tuple_size<impl::kinds_tuple>::value;
|
|
};
|
|
|
|
struct curves {
|
|
template <std::size_t N>
|
|
using type = typename std::tuple_element<N, impl::curves_tuple>::type;
|
|
|
|
static const size_t max = std::tuple_size<impl::curves_tuple>::value;
|
|
};
|
|
|
|
struct surfaces {
|
|
template <std::size_t N>
|
|
using type = typename std::tuple_element<N, impl::surfaces_tuple>::type;
|
|
|
|
static const size_t max = std::tuple_size<impl::surfaces_tuple>::value;
|
|
};
|
|
|
|
struct upgrades {
|
|
template <std::size_t N>
|
|
using type = typename std::tuple_element<N, impl::upgrades_tuple>::type;
|
|
|
|
static const size_t max = std::tuple_size<impl::upgrades_tuple>::value;
|
|
};
|
|
|
|
IFC_GEOM_API std::optional<face::ptr> loop_to_face_upgrade_impl(ptr item);
|
|
template <typename T>
|
|
class loop_to_face_upgrade {
|
|
private:
|
|
std::optional<taxonomy::face::ptr> face_;
|
|
public:
|
|
loop_to_face_upgrade(taxonomy::ptr item) {
|
|
if constexpr (std::is_same_v<T, face>) {
|
|
face_ = loop_to_face_upgrade_impl(item);
|
|
}
|
|
}
|
|
|
|
operator bool() const {
|
|
return face_.has_value();
|
|
}
|
|
|
|
operator typename T::ptr() const {
|
|
if constexpr (std::is_same_v<T, face>) {
|
|
if (face_) {
|
|
return *face_;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
IFC_GEOM_API std::optional<edge::ptr> curve_to_edge_upgrade_impl(ptr item);
|
|
template <typename T>
|
|
class curve_to_edge_upgrade {
|
|
private:
|
|
std::optional<taxonomy::edge::ptr> edge_;
|
|
public:
|
|
curve_to_edge_upgrade(taxonomy::ptr item) {
|
|
if constexpr (std::is_same_v<T, edge>) {
|
|
edge_ = taxonomy::curve_to_edge_upgrade_impl(item);
|
|
}
|
|
}
|
|
|
|
operator bool() const {
|
|
return edge_.has_value();
|
|
}
|
|
|
|
operator typename T::ptr() const {
|
|
if constexpr (std::is_same_v<T, edge>) {
|
|
if (edge_) {
|
|
return *edge_;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
IFC_GEOM_API std::optional<loop::ptr> curve_to_loop_upgrade_impl(ptr item);
|
|
template <typename T>
|
|
class curve_to_loop_upgrade {
|
|
private:
|
|
std::optional<taxonomy::loop::ptr> loop_;
|
|
public:
|
|
curve_to_loop_upgrade(taxonomy::ptr item) {
|
|
if constexpr (std::is_same_v<T, loop>) {
|
|
loop_ = curve_to_loop_upgrade_impl(item);
|
|
}
|
|
}
|
|
|
|
operator bool() const {
|
|
return loop_.has_value();
|
|
}
|
|
|
|
operator typename T::ptr() const {
|
|
if constexpr (std::is_same_v<T, loop>) {
|
|
if (loop_) {
|
|
return *loop_;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
IFC_GEOM_API std::optional<loop::ptr> edge_to_loop_upgrade_impl(ptr item);
|
|
template <typename T>
|
|
class edge_to_loop_upgrade {
|
|
private:
|
|
std::optional<taxonomy::loop::ptr> loop_;
|
|
public:
|
|
edge_to_loop_upgrade(taxonomy::ptr item) {
|
|
if constexpr (std::is_same_v<T, loop>) {
|
|
loop_ = edge_to_loop_upgrade_impl(item);
|
|
}
|
|
}
|
|
|
|
operator bool() const {
|
|
return loop_.has_value();
|
|
}
|
|
|
|
operator typename T::ptr() const {
|
|
if constexpr (std::is_same_v<T, loop>) {
|
|
if (loop_) {
|
|
return *loop_;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
IFC_GEOM_API std::optional<face::ptr> curve_to_face_upgrade_impl(ptr item);
|
|
template <typename T>
|
|
class curve_to_face_upgrade {
|
|
private:
|
|
std::optional<taxonomy::face::ptr> face_;
|
|
public:
|
|
curve_to_face_upgrade(taxonomy::ptr item) {
|
|
if constexpr (std::is_same_v<T, edge>) {
|
|
face_ = curve_to_face_upgrade_impl(item);
|
|
}
|
|
}
|
|
|
|
operator bool() const {
|
|
return face_.has_value();
|
|
}
|
|
|
|
operator typename T::ptr() const {
|
|
if constexpr (std::is_same_v<T, face>) {
|
|
if (face_) {
|
|
return *face_;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
IFC_GEOM_API std::optional<function_item::ptr> loop_to_function_item_upgrade_impl(ptr item);
|
|
template <typename T>
|
|
class loop_to_function_item_upgrade {
|
|
private:
|
|
std::optional<taxonomy::function_item::ptr> fi_;
|
|
|
|
public:
|
|
loop_to_function_item_upgrade(taxonomy::ptr item) {
|
|
if constexpr (std::is_same_v<T, function_item>) {
|
|
fi_ = loop_to_function_item_upgrade_impl(item);
|
|
}
|
|
}
|
|
|
|
operator bool() const {
|
|
return fi_.has_value();
|
|
}
|
|
|
|
operator typename T::ptr() const {
|
|
if constexpr (std::is_same_v<T, function_item>) {
|
|
if (fi_) {
|
|
return *fi_;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
#ifdef TAXONOMY_USE_SHARED_PTR
|
|
template <typename T, typename U>
|
|
std::shared_ptr<T> cast(const std::shared_ptr<U>& u) {
|
|
{
|
|
curve_to_edge_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
{
|
|
curve_to_loop_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
{
|
|
curve_to_face_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
{
|
|
edge_to_loop_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
{
|
|
loop_to_face_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
{
|
|
loop_to_function_item_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
if (auto r = std::dynamic_pointer_cast<T>(u)) {
|
|
return r;
|
|
} else {
|
|
throw std::runtime_error("Unexpected topology");
|
|
}
|
|
}
|
|
template <typename T, typename U>
|
|
std::shared_ptr<T> dcast(const std::shared_ptr<U>& u) {
|
|
{
|
|
curve_to_edge_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
{
|
|
curve_to_loop_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
{
|
|
curve_to_face_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
{
|
|
edge_to_loop_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
{
|
|
loop_to_face_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
{
|
|
loop_to_function_item_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
}
|
|
return std::dynamic_pointer_cast<T>(u);
|
|
}
|
|
#endif
|
|
#ifdef TAXONOMY_USE_UNIQUE_PTR
|
|
template <typename T, typename U>
|
|
T* cast(const std::unique_ptr<U>& u) {
|
|
loop_to_face_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
loop_to_piecewise_function_upgrade<T> pwupg(u);
|
|
if (pwupg) {
|
|
return pwupg;
|
|
}
|
|
return static_cast<T*>(&*u);
|
|
}
|
|
template <typename T, typename U>
|
|
T* dcast(const std::unique_ptr<U>& u) {
|
|
loop_to_face_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
loop_to_piecewise_function_upgrade<T> pwupg(u);
|
|
if (pwupg) {
|
|
return pwupg;
|
|
}
|
|
return dynamic_cast<T*>(&*u);
|
|
}
|
|
#endif
|
|
#ifdef TAXONOMY_USE_NAKED_PTR
|
|
template <typename T, typename U>
|
|
T* cast(const U*& u) {
|
|
loop_to_face_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
loop_to_piecewise_function_upgrade<T> pwupg(u);
|
|
if (pwupg) {
|
|
return pwupg;
|
|
}
|
|
return std::static_cast<T*>(u);
|
|
}
|
|
template <typename T, typename U>
|
|
T* dcast(const U*& u) {
|
|
loop_to_face_upgrade<T> upg(u);
|
|
if (upg) {
|
|
return upg;
|
|
}
|
|
loop_to_piecewise_function_upgrade<T> pwupg(u);
|
|
if (pwupg) {
|
|
return pwupg;
|
|
}
|
|
return std::dynamic_cast<T*>(u);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
template <typename U, typename Fn>
|
|
void visit(const typename U::ptr& deep, Fn fn) {
|
|
for (auto& i : deep->children) {
|
|
// @todo Sad... now that we have templated collection members,
|
|
// we can't generally use collection_base anymore as a cast target.
|
|
if (auto s = std::dynamic_pointer_cast<taxonomy::collection>(i)) {
|
|
ifcopenshell::geom::visit<taxonomy::collection>(s, fn);
|
|
} else if (auto s = std::dynamic_pointer_cast<taxonomy::loop>(i)) {
|
|
ifcopenshell::geom::visit<taxonomy::loop>(s, fn);
|
|
} else if (auto s = std::dynamic_pointer_cast<taxonomy::face>(i)) {
|
|
ifcopenshell::geom::visit<taxonomy::face>(s, fn);
|
|
} else if (auto s = std::dynamic_pointer_cast<taxonomy::shell>(i)) {
|
|
ifcopenshell::geom::visit<taxonomy::shell>(s, fn);
|
|
} else if (auto s = std::dynamic_pointer_cast<taxonomy::solid>(i)) {
|
|
ifcopenshell::geom::visit<taxonomy::solid>(s, fn);
|
|
} else if (auto s = std::dynamic_pointer_cast<taxonomy::loft>(i)) {
|
|
ifcopenshell::geom::visit<taxonomy::loft>(s, fn);
|
|
} else if (auto s = std::dynamic_pointer_cast<taxonomy::boolean_result>(i)) {
|
|
ifcopenshell::geom::visit<taxonomy::boolean_result>(s, fn);
|
|
}
|
|
else {
|
|
fn(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T, typename U, typename Fn>
|
|
void visit_2(const typename U::ptr& collection, const Fn& fn) {
|
|
static_assert(std::is_same<T, taxonomy::point3>::value, "@todo Only implemented for point3");
|
|
for (auto& child : collection->children) {
|
|
// @todo Sad... now that we have templated collection members,
|
|
// we can't generally use collection_base anymore as a cast target.
|
|
if (auto col = std::dynamic_pointer_cast<taxonomy::collection>(child)) {
|
|
visit_2<T, taxonomy::collection>(col, fn);
|
|
} else if (auto loop = std::dynamic_pointer_cast<taxonomy::loop>(child)) {
|
|
visit_2<T, taxonomy::loop>(loop, fn);
|
|
} else if (auto face = std::dynamic_pointer_cast<taxonomy::face>(child)) {
|
|
visit_2<T, taxonomy::face>(face, fn);
|
|
} else if (auto shell = std::dynamic_pointer_cast<taxonomy::shell>(child)) {
|
|
visit_2<T, taxonomy::shell>(shell, fn);
|
|
} else if (auto solid = std::dynamic_pointer_cast<taxonomy::solid>(child)) {
|
|
visit_2<T, taxonomy::solid>(solid, fn);
|
|
} else if (auto loft = std::dynamic_pointer_cast<taxonomy::loft>(child)) {
|
|
visit_2<T, taxonomy::loft>(loft, fn);
|
|
} else if (auto bl = std::dynamic_pointer_cast<taxonomy::boolean_result>(child)) {
|
|
visit_2<T, taxonomy::boolean_result>(bl, fn);
|
|
} else if (auto pt = std::dynamic_pointer_cast<taxonomy::point3>(child)) {
|
|
fn(pt);
|
|
} else if (auto ed = std::dynamic_pointer_cast<taxonomy::edge>(child)) {
|
|
// @todo maybe make edge a collection then as well?
|
|
if (ed->start.index() == 1) {
|
|
fn(std::get<taxonomy::point3::ptr>(ed->start));
|
|
}
|
|
if (ed->end.index() == 1) {
|
|
fn(std::get<taxonomy::point3::ptr>(ed->end));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
IFC_GEOM_API taxonomy::collection::ptr flatten(const taxonomy::collection::ptr& deep);
|
|
|
|
template <typename Fn>
|
|
bool apply_predicate_to_collection(const taxonomy::ptr& i, Fn fn) {
|
|
if (i->kind() == taxonomy::COLLECTION) {
|
|
auto c = taxonomy::cast<taxonomy::collection>(i);
|
|
for (auto& child : c->children) {
|
|
if (apply_predicate_to_collection(child, fn)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
else {
|
|
return fn(i);
|
|
}
|
|
}
|
|
|
|
// @nb traverses nested collections
|
|
template <typename Fn>
|
|
taxonomy::collection::ptr filter(const taxonomy::collection::ptr& collection, Fn fn) {
|
|
auto filtered = taxonomy::make<taxonomy::collection>();
|
|
for (auto& child : collection->children) {
|
|
if (apply_predicate_to_collection(child, fn)) {
|
|
filtered->children.push_back(clone(child));
|
|
}
|
|
}
|
|
if (filtered->children.empty()) {
|
|
#ifdef TAXONOMY_USE_NAKED_PTR
|
|
delete filtered;
|
|
#endif
|
|
return nullptr;
|
|
}
|
|
return filtered;
|
|
}
|
|
|
|
// @nb traverses nested collections
|
|
template <typename Fn>
|
|
taxonomy::collection::ptr filter_in_place(taxonomy::collection::ptr collection, Fn fn) {
|
|
auto& c = collection->children;
|
|
auto new_end = std::remove_if(c.begin(), c.end(), [fn](taxonomy::geom_item::ptr i) {
|
|
return !apply_predicate_to_collection(i, fn);
|
|
});
|
|
#ifdef TAXONOMY_USE_NAKED_PTR
|
|
for (auto it = new_end; it != c.end(); ++it) {
|
|
delete *it;
|
|
}
|
|
#endif
|
|
c.erase(new_end, c.end());
|
|
return collection;
|
|
}
|
|
|
|
IFC_GEOM_API taxonomy::solid::ptr create_box(double dx, double dy, double dz);
|
|
IFC_GEOM_API taxonomy::solid::ptr create_box(double x, double y, double z, double dx, double dy, double dz);
|
|
|
|
struct IFC_GEOM_API layerset_information {
|
|
std::vector<double> thicknesses;
|
|
std::vector<ifcopenshell::geom::taxonomy::ptr> layers;
|
|
std::vector<ifcopenshell::geom::taxonomy::style> styles;
|
|
};
|
|
|
|
enum connection_type {
|
|
ATPATH,
|
|
ATSTART,
|
|
ATEND,
|
|
NOTDEFINED
|
|
};
|
|
|
|
typedef std::tuple<connection_type, connection_type, express::base> endpoint_connection;
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|