mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 06:39:13 +00:00
settings: DeferProcessingFirstElement, MaxOffset, MaxOffsetDeviation, ApplyOffset; taxonomy: centroid funcs; iterator get_tasks + items() funcs; geom.map_shape()
This commit is contained in:
@@ -441,6 +441,27 @@ namespace ifcopenshell {
|
|||||||
static constexpr const char* const description = "Experimental as not all topology hash functions fully implemented";
|
static constexpr const char* const description = "Experimental as not all topology hash functions fully implemented";
|
||||||
static constexpr bool defaultvalue = false;
|
static constexpr bool defaultvalue = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DeferProcessingFirstElement : public SettingBase<DeferProcessingFirstElement, bool, true> {
|
||||||
|
static constexpr const char* const name = "defer-processing-first-element";
|
||||||
|
static constexpr const char* const description = "Don't process first element in Iterator::initialize call()";
|
||||||
|
static constexpr bool defaultvalue = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MaxOffset : public SettingBase<MaxOffset, double> {
|
||||||
|
static constexpr const char* const name = "max-offset";
|
||||||
|
static constexpr const char* const description = "Maximum translation offset to be observed after which median offset in model gets removed and logged. Requires --no-parallel-mapping.";
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MaxOffsetDeviation : public SettingBase<MaxOffsetDeviation, double> {
|
||||||
|
static constexpr const char* const name = "max-offset-deviation";
|
||||||
|
static constexpr const char* const description = "To retain field of view, completely remove elements outside of the median offset. Requires --no-parallel-mapping.";
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ApplyOffset : public SettingBase<ApplyOffset, std::vector<double>> {
|
||||||
|
static constexpr const char* const name = "apply-offset";
|
||||||
|
static constexpr const char* const description = "Slight variation of --model-offset where large offsets are applied by negating existing large offsets to retain maximum precision. Requires --no-parallel-mapping.";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
@@ -616,7 +637,7 @@ namespace ifcopenshell {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class IFC_GEOM_API Settings : public SettingsContainer<
|
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, ComputeCurvature, FunctionStepType, FunctionStepParam, NoParallelMapping, PermissiveShapeReuse, ModelOffset, ModelRotation, TriangulationType, CgalEmitOriginalEdges, OcctNoCleanTriangulation, CacheShapes>
|
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, ComputeCurvature, FunctionStepType, FunctionStepParam, NoParallelMapping, PermissiveShapeReuse, ModelOffset, ModelRotation, TriangulationType, CgalEmitOriginalEdges, OcctNoCleanTriangulation, CacheShapes, DeferProcessingFirstElement, MaxOffset, MaxOffsetDeviation, ApplyOffset>
|
||||||
>
|
>
|
||||||
{};
|
{};
|
||||||
}
|
}
|
||||||
|
|||||||
+184
-2
@@ -53,7 +53,7 @@ bool IfcGeom::Iterator::initialize() {
|
|||||||
if (settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get() && settings_.get<ifcopenshell::geometry::settings::PermissiveShapeReuse>().get()) {
|
if (settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get() && settings_.get<ifcopenshell::geometry::settings::PermissiveShapeReuse>().get()) {
|
||||||
std::unordered_map<
|
std::unordered_map<
|
||||||
ifcopenshell::geometry::taxonomy::item::ptr,
|
ifcopenshell::geometry::taxonomy::item::ptr,
|
||||||
std::vector<std::pair<const IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::taxonomy::matrix4::ptr>>> folded;
|
std::vector<std::pair<IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::taxonomy::matrix4::ptr>>> folded;
|
||||||
|
|
||||||
for (auto& r : tasks_) {
|
for (auto& r : tasks_) {
|
||||||
auto i = r.item;
|
auto i = r.item;
|
||||||
@@ -94,6 +94,10 @@ bool IfcGeom::Iterator::initialize() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get()) {
|
||||||
|
remove_offset_();
|
||||||
|
}
|
||||||
|
|
||||||
size_t num_products = 0;
|
size_t num_products = 0;
|
||||||
for (auto& r : tasks_) {
|
for (auto& r : tasks_) {
|
||||||
num_products += !settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get() ? r.products_2->size() : r.products.size();
|
num_products += !settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get() ? r.products_2->size() : r.products.size();
|
||||||
@@ -136,7 +140,7 @@ bool IfcGeom::Iterator::initialize() {
|
|||||||
if (tasks_.size() == 0) {
|
if (tasks_.size() == 0) {
|
||||||
Logger::Warning("No representations encountered, aborting");
|
Logger::Warning("No representations encountered, aborting");
|
||||||
initialization_outcome_.reset(false);
|
initialization_outcome_.reset(false);
|
||||||
} else {
|
} else if (!settings_.get<ifcopenshell::geometry::settings::DeferProcessingFirstElement>().get()) {
|
||||||
|
|
||||||
task_iterator_ = tasks_.begin();
|
task_iterator_ = tasks_.begin();
|
||||||
|
|
||||||
@@ -153,6 +157,8 @@ bool IfcGeom::Iterator::initialize() {
|
|||||||
} else {
|
} else {
|
||||||
initialization_outcome_ = create();
|
initialization_outcome_ = create();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
initialization_outcome_.reset(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *initialization_outcome_;
|
return *initialization_outcome_;
|
||||||
@@ -505,6 +511,10 @@ IfcGeom::Element* IfcGeom::Iterator::get()
|
|||||||
throw std::runtime_error("Iterator not initialized");
|
throw std::runtime_error("Iterator not initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settings_.get<ifcopenshell::geometry::settings::DeferProcessingFirstElement>().get() && !task_result_ptr_initialized) {
|
||||||
|
throw std::runtime_error("No elements processed");
|
||||||
|
}
|
||||||
|
|
||||||
auto ret = *task_result_iterator_;
|
auto ret = *task_result_iterator_;
|
||||||
|
|
||||||
// If we want to organize the element considering their hierarchy
|
// If we want to organize the element considering their hierarchy
|
||||||
@@ -625,6 +635,178 @@ const IfcUtil::IfcBaseClass* IfcGeom::Iterator::create() {
|
|||||||
return product;
|
return product;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ifcopenshell::geometry::taxonomy::direction3::ptr IfcGeom::Iterator::remove_offset_() {
|
||||||
|
|
||||||
|
using namespace ifcopenshell::geometry::taxonomy;
|
||||||
|
using namespace ifcopenshell::geometry::settings;
|
||||||
|
|
||||||
|
if (!settings_.get<MaxOffset>().has()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!settings_.get<NoParallelMapping>().get()) {
|
||||||
|
throw std::runtime_error("remove_offset() can only be called with defer-processing-first-element and no-parallel-mapping settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto collect_offset = [&](const item::ptr& itm, const std::vector<std::pair<IfcUtil::IfcBaseEntity*, matrix4::ptr>>& pr) -> std::pair<double, Eigen::Vector3d> {
|
||||||
|
std::function<std::pair<double, Eigen::Vector3d>(const item::ptr&, Eigen::Matrix4d)> traverse;
|
||||||
|
traverse = [&](const item::ptr& node, Eigen::Matrix4d m4) -> std::pair<double, Eigen::Vector3d> {
|
||||||
|
if (auto shl = std::dynamic_pointer_cast<shell>(node)) {
|
||||||
|
auto p = shl->centroid();
|
||||||
|
Eigen::Vector4d v;
|
||||||
|
v << p->components()(0), p->components()(1), p->components()(2), 1.0;
|
||||||
|
Eigen::Vector3d translation_part = (m4 * v).head<3>();
|
||||||
|
double translation_amnt = translation_part.norm();
|
||||||
|
if (translation_amnt > settings_.get<MaxOffset>().get()) {
|
||||||
|
return { translation_amnt, translation_part };
|
||||||
|
} else {
|
||||||
|
return { 0.0, Eigen::Vector3d::Zero() };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (auto gi = std::dynamic_pointer_cast<geom_item>(node)) {
|
||||||
|
if (gi->matrix) {
|
||||||
|
m4 = m4 * gi->matrix->ccomponents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Eigen::Vector3d translation_part = m4.block<3, 1>(0, 3);
|
||||||
|
double translation_amnt = translation_part.norm();
|
||||||
|
if (translation_amnt > settings_.get<MaxOffset>().get()) {
|
||||||
|
return { translation_amnt, translation_part };
|
||||||
|
} else if (auto col = std::dynamic_pointer_cast<collection>(node)) {
|
||||||
|
std::vector<std::pair<double, Eigen::Vector3d>> child_transforms;
|
||||||
|
for (const auto& child : col->children) {
|
||||||
|
child_transforms.push_back(traverse(child, m4));
|
||||||
|
}
|
||||||
|
if (!child_transforms.empty()) {
|
||||||
|
return *std::max_element(child_transforms.begin(), child_transforms.end(),
|
||||||
|
[](const auto& a, const auto& b) { return a.first < b.first; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { 0.0, Eigen::Vector3d::Zero() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Eigen::Matrix4d m4 = Eigen::Matrix4d::Identity();
|
||||||
|
if (pr.size() == 1 && pr[0].second) {
|
||||||
|
m4 = pr[0].second->ccomponents();
|
||||||
|
}
|
||||||
|
return traverse(itm, m4);
|
||||||
|
};
|
||||||
|
|
||||||
|
Eigen::Vector3d vec;
|
||||||
|
|
||||||
|
if (settings_.get<ApplyOffset>().has()) {
|
||||||
|
auto vs = settings_.get<ApplyOffset>().get();
|
||||||
|
if (vs.size() != 3) {
|
||||||
|
throw std::runtime_error("ApplyOffset setting must be a vector of size 3");
|
||||||
|
}
|
||||||
|
vec = Eigen::Vector3d(vs[0], vs[1], vs[2]);
|
||||||
|
} else {
|
||||||
|
// Collect all norms and vectors
|
||||||
|
std::vector<double> norms;
|
||||||
|
std::vector<Eigen::Vector3d> vectors;
|
||||||
|
for (const auto& task : tasks_) {
|
||||||
|
auto result = collect_offset(task.item, task.products);
|
||||||
|
norms.push_back(result.first);
|
||||||
|
vectors.push_back(result.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the median norm index
|
||||||
|
std::vector<double> sorted_norms = norms;
|
||||||
|
std::nth_element(sorted_norms.begin(), sorted_norms.begin() + sorted_norms.size() / 2, sorted_norms.end());
|
||||||
|
double median = sorted_norms[sorted_norms.size() / 2];
|
||||||
|
auto median_it = std::find(norms.begin(), norms.end(), median);
|
||||||
|
size_t median_index = std::distance(norms.begin(), median_it);
|
||||||
|
|
||||||
|
if (median_index >= vectors.size()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec = -vectors[median_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
Eigen::Matrix4d translation_matrix = Eigen::Matrix4d::Identity();
|
||||||
|
translation_matrix.block<3, 1>(0, 3) = vec;
|
||||||
|
|
||||||
|
auto remove_offset = [&](const item::ptr& itm, const std::vector<std::pair<IfcUtil::IfcBaseEntity*, matrix4::ptr>>& pr) -> bool {
|
||||||
|
std::function<bool(const item::ptr&, Eigen::Matrix4d)> traverse;
|
||||||
|
traverse = [&](const item::ptr& node, Eigen::Matrix4d m4) -> bool {
|
||||||
|
if (auto shl = std::dynamic_pointer_cast<shell>(node)) {
|
||||||
|
auto p = shl->centroid();
|
||||||
|
Eigen::Vector4d v;
|
||||||
|
v << p->components()(0), p->components()(1), p->components()(2), 1.0;
|
||||||
|
Eigen::Vector3d translation_part = (m4 * v).head<3>();
|
||||||
|
double translation_amnt = translation_part.norm();
|
||||||
|
if (translation_amnt > settings_.get<MaxOffset>().get()) {
|
||||||
|
shl->matrix = make<matrix4>(translation_matrix);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
auto m4b = m4;
|
||||||
|
if (auto gi = std::dynamic_pointer_cast<geom_item>(node)) {
|
||||||
|
if (gi->matrix) {
|
||||||
|
m4b = m4 * gi->matrix->ccomponents();
|
||||||
|
}
|
||||||
|
Eigen::Vector3d translation_part = m4b.block<3, 1>(0, 3);
|
||||||
|
double translation_amnt = translation_part.norm();
|
||||||
|
if (translation_amnt > settings_.get<MaxOffset>().get()) {
|
||||||
|
auto inverted_rot_scale3 = m4.block<3, 3>(0, 0).inverse();
|
||||||
|
Eigen::Matrix4d inverted_rot_scale = Eigen::Matrix4d::Identity();
|
||||||
|
inverted_rot_scale.block<3, 3>(0, 0) = inverted_rot_scale3;
|
||||||
|
if (!gi->matrix) {
|
||||||
|
gi->matrix = make<matrix4>();
|
||||||
|
}
|
||||||
|
gi->matrix->components() = (inverted_rot_scale * translation_matrix) * gi->matrix->ccomponents();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool b = true;
|
||||||
|
if (auto col = std::dynamic_pointer_cast<collection>(node)) {
|
||||||
|
for (const auto& child : col->children) {
|
||||||
|
if (!traverse(child, m4b)) {
|
||||||
|
b = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Eigen::Matrix4d m4 = Eigen::Matrix4d::Identity();
|
||||||
|
if (pr.size() == 1 && pr[0].second) {
|
||||||
|
m4 = pr[0].second->ccomponents();
|
||||||
|
}
|
||||||
|
return traverse(itm, m4);
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t num_offset_applied = 0;
|
||||||
|
for (auto& task : tasks_) {
|
||||||
|
bool all_applied = true;
|
||||||
|
for (auto& p : task.products) {
|
||||||
|
auto bb = p.second->components().block<3, 1>(0, 3);
|
||||||
|
double translation_amnt = bb.norm();
|
||||||
|
if (translation_amnt > settings_.get<MaxOffset>().get()) {
|
||||||
|
// block has an underlying mutable ref to the matrix
|
||||||
|
bb -= vec;
|
||||||
|
} else {
|
||||||
|
all_applied = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (all_applied) {
|
||||||
|
num_offset_applied += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (remove_offset(task.item, task.products)) {
|
||||||
|
num_offset_applied += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::Notice("Removed large offsets within " + std::to_string(num_offset_applied) + " products");
|
||||||
|
Logger::Notice("Offset applied (" + std::to_string(vec(0)) + "," + std::to_string(vec(1)) + "," + std::to_string(vec(2)) + ")");
|
||||||
|
|
||||||
|
return make<direction3>(vec);
|
||||||
|
}
|
||||||
|
|
||||||
IfcGeom::Iterator::~Iterator() {
|
IfcGeom::Iterator::~Iterator() {
|
||||||
if (num_threads_ != 1) {
|
if (num_threads_ != 1) {
|
||||||
terminating_ = true;
|
terminating_ = true;
|
||||||
|
|||||||
+27
-2
@@ -91,7 +91,7 @@ namespace IfcGeom {
|
|||||||
|
|
||||||
// For NoParallelMapping==true
|
// For NoParallelMapping==true
|
||||||
ifcopenshell::geometry::taxonomy::ptr item;
|
ifcopenshell::geometry::taxonomy::ptr item;
|
||||||
std::vector<std::pair<const IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::taxonomy::matrix4::ptr>> products;
|
std::vector<std::pair<IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::taxonomy::matrix4::ptr>> products;
|
||||||
|
|
||||||
// For NoParallelMapping==false
|
// For NoParallelMapping==false
|
||||||
IfcUtil::IfcBaseEntity* representation;
|
IfcUtil::IfcBaseEntity* representation;
|
||||||
@@ -209,7 +209,7 @@ namespace IfcGeom {
|
|||||||
|
|
||||||
void log_timepoints() const;
|
void log_timepoints() const;
|
||||||
|
|
||||||
/// @todo public/private sections all over the place: move all public to the beginning of the class
|
ifcopenshell::geometry::taxonomy::direction3::ptr remove_offset_();
|
||||||
public:
|
public:
|
||||||
Iterator(const std::string& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads)
|
Iterator(const std::string& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads)
|
||||||
: settings_(settings)
|
: settings_(settings)
|
||||||
@@ -262,6 +262,31 @@ namespace IfcGeom {
|
|||||||
|
|
||||||
void set_cache(GeometrySerializer* cache) { cache_ = cache; }
|
void set_cache(GeometrySerializer* cache) { cache_ = cache; }
|
||||||
|
|
||||||
|
std::vector<ifcopenshell::geometry::taxonomy::item::ptr> get_task_items() const {
|
||||||
|
std::vector<ifcopenshell::geometry::taxonomy::item::ptr> items;
|
||||||
|
items.reserve(tasks_.size());
|
||||||
|
for (const auto& task : tasks_) {
|
||||||
|
items.push_back(task.item);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
aggregate_of_aggregate_of_instance::ptr get_task_products() const {
|
||||||
|
aggregate_of_aggregate_of_instance::ptr products = aggregate_of_aggregate_of_instance::ptr(new aggregate_of_aggregate_of_instance);
|
||||||
|
for (const auto& task : tasks_) {
|
||||||
|
if (task.products_2) {
|
||||||
|
products->push(task.products_2);
|
||||||
|
} else {
|
||||||
|
for (auto& product : task.products) {
|
||||||
|
aggregate_of_instance::ptr p(new aggregate_of_instance);
|
||||||
|
p->push(product.first);
|
||||||
|
products->push(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return products;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& unit_name() const { return converter_->mapping()->get_length_unit_name(); }
|
const std::string& unit_name() const { return converter_->mapping()->get_length_unit_name(); }
|
||||||
double unit_magnitude() const { return converter_->mapping()->get_length_unit(); }
|
double unit_magnitude() const { return converter_->mapping()->get_length_unit(); }
|
||||||
// Check if error occurred during iterator initialization or iteration over elements.
|
// Check if error occurred during iterator initialization or iteration over elements.
|
||||||
|
|||||||
@@ -952,6 +952,21 @@ typedef item const* ptr;
|
|||||||
auto v = std::make_tuple(static_cast<size_t>(LOOP), hash_elements(), external ? *external ? 2 : 1 : 0, closed ? *closed ? 2 : 1 : 0);
|
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);
|
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.which() == 1) {
|
||||||
|
c += boost::get<point3::ptr>(e->start)->ccomponents();
|
||||||
|
}
|
||||||
|
if (e->end.which() == 1) {
|
||||||
|
c += boost::get<point3::ptr>(e->end)->ccomponents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c /= static_cast<double>(children.size());
|
||||||
|
return make<taxonomy::point3>(c);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct face : public collection_base<loop> {
|
struct face : public collection_base<loop> {
|
||||||
@@ -992,6 +1007,25 @@ typedef item const* ptr;
|
|||||||
auto v = std::make_tuple(static_cast<size_t>(SHELL), hash_elements(), closed ? *closed ? 2 : 1 : 0);
|
auto v = std::make_tuple(static_cast<size_t>(SHELL), hash_elements(), closed ? *closed ? 2 : 1 : 0);
|
||||||
return boost::hash<decltype(v)>{}(v);
|
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.which() == 1) {
|
||||||
|
c += boost::get<point3::ptr>(e->start)->ccomponents();
|
||||||
|
}
|
||||||
|
if (e->end.which() == 1) {
|
||||||
|
c += boost::get<point3::ptr>(e->end)->ccomponents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c /= static_cast<double>(children.size());
|
||||||
|
return make<taxonomy::point3>(c);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct solid : public collection_base<shell> {
|
struct solid : public collection_base<shell> {
|
||||||
|
|||||||
@@ -299,8 +299,11 @@ class iterator(ifcopenshell_wrapper.Iterator):
|
|||||||
):
|
):
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
if isinstance(file_or_filename, file):
|
if isinstance(file_or_filename, file):
|
||||||
|
self.file = file
|
||||||
file_or_filename = file_or_filename.wrapped_data
|
file_or_filename = file_or_filename.wrapped_data
|
||||||
else:
|
else:
|
||||||
|
# @todo?
|
||||||
|
self.file = None
|
||||||
# Makes sure people are able to use python's platform agnostic paths
|
# Makes sure people are able to use python's platform agnostic paths
|
||||||
file_or_filename = os.path.abspath(file_or_filename)
|
file_or_filename = os.path.abspath(file_or_filename)
|
||||||
|
|
||||||
@@ -346,6 +349,9 @@ class iterator(ifcopenshell_wrapper.Iterator):
|
|||||||
if not self.next():
|
if not self.next():
|
||||||
break
|
break
|
||||||
|
|
||||||
|
def get_task_products(self):
|
||||||
|
return entity_instance.wrap_value(ifcopenshell_wrapper.Iterator.get_task_products(self), self.file)
|
||||||
|
|
||||||
|
|
||||||
ClashType = Literal["protrusion", "pierce", "collision", "clearance"]
|
ClashType = Literal["protrusion", "pierce", "collision", "clearance"]
|
||||||
CLASH_TYPE_ITEMS = ("protrusion", "pierce", "collision", "clearance")
|
CLASH_TYPE_ITEMS = ("protrusion", "pierce", "collision", "clearance")
|
||||||
@@ -453,9 +459,7 @@ def create_shape(
|
|||||||
geometry_library: GEOMETRY_LIBRARY = "opencascade",
|
geometry_library: GEOMETRY_LIBRARY = "opencascade",
|
||||||
) -> Union[ShapeType, ShapeElementType, ifcopenshell_wrapper.Transformation, utils.shape_tuple, TopoDS.TopoDS_Shape]:
|
) -> Union[ShapeType, ShapeElementType, ifcopenshell_wrapper.Transformation, utils.shape_tuple, TopoDS.TopoDS_Shape]:
|
||||||
"""
|
"""
|
||||||
Return a geometric representation from STEP-based IFCREPRESENTATIONSHAPE
|
Returns a geometric interpretation of the IFC entity instance
|
||||||
or
|
|
||||||
Return an OpenCASCADE BRep if 'use-python-opencascade' is True
|
|
||||||
|
|
||||||
Note that in Python, you must store a reference to the element returned by this function to prevent garbage
|
Note that in Python, you must store a reference to the element returned by this function to prevent garbage
|
||||||
collection when you access its children. See #1124.
|
collection when you access its children. See #1124.
|
||||||
@@ -504,6 +508,20 @@ def create_shape(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def map_shape(settings: settings, inst: entity_instance) -> ifcopenshell_wrapper.item:
|
||||||
|
"""
|
||||||
|
Returns an interpretation of the geometry encoded as per IfcOpenShell's taxonomy layer.
|
||||||
|
In many cases this is somewhat equivalent to the raw IFC data (but schema-agnostic in C++), but
|
||||||
|
in other cases such as IfcParameterizedProfileDef the returned item is the equivalent
|
||||||
|
of an explicit composite curve.
|
||||||
|
|
||||||
|
>>> point = ifc_file.by_type('IfcCartesianPoint')[0]
|
||||||
|
>>> ifcopenshell.geom.map_shape(ifcopenshell.geom.settings(), point).components
|
||||||
|
(0.0, 0.0, 0.0)
|
||||||
|
"""
|
||||||
|
return ifcopenshell_wrapper.map_shape(settings, inst.wrapped_data)
|
||||||
|
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def consume_iterator(it: iterator, with_progress: Literal[False] = False) -> Generator[IteratorOutput, None, None]: ...
|
def consume_iterator(it: iterator, with_progress: Literal[False] = False) -> Generator[IteratorOutput, None, None]: ...
|
||||||
@overload
|
@overload
|
||||||
|
|||||||
@@ -6,6 +6,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%typemap(out) aggregate_of_aggregate_of_instance::ptr {
|
||||||
|
const unsigned size = $1 ? $1->size() : 0;
|
||||||
|
$result = PyTuple_New(size);
|
||||||
|
for (unsigned i = 0; i < size; ++i) {
|
||||||
|
const auto& r_i = *(result->begin() + i);
|
||||||
|
PyTuple_SetItem($result, i, pythonize_vector(r_i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
%typemap(out) IfcUtil::ArgumentType {
|
%typemap(out) IfcUtil::ArgumentType {
|
||||||
$result = SWIG_Python_str_FromChar(IfcUtil::ArgumentTypeToString($1));
|
$result = SWIG_Python_str_FromChar(IfcUtil::ArgumentTypeToString($1));
|
||||||
}
|
}
|
||||||
@@ -122,6 +132,14 @@ CREATE_VECTOR_TYPEMAP_OUT(IfcGeom::ConversionResultShape *)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
%typemap(out) std::vector<item_name::ptr> {
|
||||||
|
const auto& v = (std::vector<item_name::ptr>) $1;
|
||||||
|
$result = PyTuple_New(v.size());
|
||||||
|
for (int i = 0; i < v.size(); ++i) {
|
||||||
|
PyTuple_SetItem($result, i, item_to_pyobject(v[i]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
%typemap(out) const item_name::ptr& {
|
%typemap(out) const item_name::ptr& {
|
||||||
$result = item_to_pyobject(*$1);
|
$result = item_to_pyobject(*$1);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user