Settings rework for plan/model/context and interfacing with python

This commit is contained in:
Thomas Krijnen
2024-04-18 21:04:02 +02:00
parent b62b328f1d
commit 0edfb0e791
8 changed files with 164 additions and 44 deletions
+14
View File
@@ -329,6 +329,10 @@ int main(int argc, char** argv) {
("exterior-only", ("exterior-only",
po::value<std::string>(&exterior_only_algo)->default_value("none")->implicit_value("minkowski-triangles"), po::value<std::string>(&exterior_only_algo)->default_value("none")->implicit_value("minkowski-triangles"),
"Export only the exterior shell of the building found by geometric analysis. convex-decomposition, minkowski-triangles or halfspace-snapping") "Export only the exterior shell of the building found by geometric analysis. convex-decomposition, minkowski-triangles or halfspace-snapping")
("plan", "Specifies whether to include curves in the output result. Typically "
"these are representations of type Plan or Axis. Excluded by default.")
("model", "Specifies whether to include surfaces and solids in the output result. "
"Typically these are representations of type Body or Facetation. ")
; ;
geometry_settings.define_options(geom_options); geometry_settings.define_options(geom_options);
@@ -975,6 +979,16 @@ int main(int argc, char** argv) {
Logger::Notice(msg.str()); Logger::Notice(msg.str());
} }
*/ */
// backwards compatibility
if (vmap.count("plan") && vmap.count("model")) {
geometry_settings.get<ifcopenshell::geometry::settings::OutputDimensionality>().value = ifcopenshell::geometry::settings::CURVES_SURFACES_AND_SOLIDS;
} else if (vmap.count("model")) {
geometry_settings.get<ifcopenshell::geometry::settings::OutputDimensionality>().value = ifcopenshell::geometry::settings::SURFACES_AND_SOLIDS;
} else if (vmap.count("plan")) {
geometry_settings.get<ifcopenshell::geometry::settings::OutputDimensionality>().value = ifcopenshell::geometry::settings::CURVES;
}
std::unique_ptr<IfcGeom::Iterator> context_iterator; std::unique_ptr<IfcGeom::Iterator> context_iterator;
if (!elems_from_adaptor) { if (!elems_from_adaptor) {
context_iterator.reset(new IfcGeom::Iterator(geometry_kernel, geometry_settings, ifc_file, filter_funcs, num_threads)); context_iterator.reset(new IfcGeom::Iterator(geometry_kernel, geometry_settings, ifc_file, filter_funcs, num_threads));
+34 -4
View File
@@ -10,14 +10,28 @@ double ifcopenshell::geometry::ConversionSettings::getValue(GeomValue var) const
} }
*/ */
std::istream& std::operator>>(istream& in, set<int>& ints) { template <typename T>
string tokens; void istream_helper(std::istream& in, std::set<T>& ints) {
std::string tokens;
in >> tokens; in >> tokens;
vector<string> strs; std::vector<std::string> strs;
boost::split(strs, tokens, boost::is_any_of(",")); boost::split(strs, tokens, boost::is_any_of(","));
for (auto& s : strs) { for (auto& s : strs) {
ints.insert(boost::lexical_cast<int>(s)); if constexpr (std::is_same_v<T, std::string>) {
ints.insert(s);
} else {
ints.insert(boost::lexical_cast<T>(s));
}
} }
}
std::istream& std::operator>>(istream& in, set<int>& ints) {
istream_helper<int>(in, ints);
return in;
}
std::istream& std::operator>>(istream& in, set<string>& strs) {
istream_helper<std::string>(in, strs);
return in; return in;
} }
@@ -51,3 +65,19 @@ std::istream& ifcopenshell::geometry::settings::operator>>(std::istream& in, Pie
} }
return in; return in;
} }
std::istream& ifcopenshell::geometry::settings::operator>>(std::istream& in, OutputDimensionalityTypes& v) {
std::string token;
in >> token;
boost::to_upper(token);
if (token == "CURVES") {
v = CURVES;
} else if (token == "SURFACES_AND_SOLIDS") {
v = SURFACES_AND_SOLIDS;
} else if (token == "CURVES_SURFACES_AND_SOLIDS") {
v = CURVES_SURFACES_AND_SOLIDS;
} else {
in.setstate(std::ios_base::failbit);
}
return in;
}
+27 -17
View File
@@ -23,6 +23,7 @@ namespace po = boost::program_options;
namespace std { namespace std {
istream& operator>>(istream& in, set<int>& ints); istream& operator>>(istream& in, set<int>& ints);
istream& operator>>(istream& in, set<string>& ints);
} }
#endif #endif
@@ -120,21 +121,6 @@ namespace ifcopenshell {
static constexpr double defaultvalue = 0.00001; static constexpr double defaultvalue = 0.00001;
}; };
struct IncludeCurves : public SettingBase<IncludeCurves, bool> {
static constexpr const char* const name = "plan";
static constexpr const char* const description = "Specifies whether to include curves in the output result. Typically "
"these are representations of type Plan or Axis. Excluded by default.";
static constexpr bool defaultvalue = false;
};
struct IncludeSurfaces : public SettingBase<IncludeSurfaces, bool> {
static constexpr const char* const name = "model";
static constexpr const char* const description = "Specifies whether to include surfaces and solids in the output result. "
"Typically these are representations of type Body or Facetation. "
"Included by default.";
static constexpr bool defaultvalue = true;
};
struct LayersetFirst : public SettingBase<LayersetFirst, bool> { struct LayersetFirst : public SettingBase<LayersetFirst, bool> {
static constexpr const char* const name = "layerset-first"; static constexpr const char* const name = "layerset-first";
static constexpr const char* const description = "Assigns the first layer material of the layerset " static constexpr const char* const description = "Assigns the first layer material of the layerset "
@@ -214,6 +200,30 @@ namespace ifcopenshell {
static constexpr const char* const description = ""; static constexpr const char* const description = "";
}; };
struct ContextTypes : public SettingBase<ContextIds, std::set<std::string>> {
static constexpr const char* const name = "context-types";
static constexpr const char* const description = "";
};
struct ContextIdentifiers : public SettingBase<ContextIds, std::set<std::string>> {
static constexpr const char* const name = "context-identifiers";
static constexpr const char* const description = "";
};
enum OutputDimensionalityTypes {
CURVES,
SURFACES_AND_SOLIDS,
CURVES_SURFACES_AND_SOLIDS
};
std::istream& operator>>(std::istream& in, OutputDimensionalityTypes& ioo);
struct OutputDimensionality : public SettingBase<OutputDimensionality, OutputDimensionalityTypes> {
static constexpr const char* const name = "dimensionality";
static constexpr const char* const description = "Specifies whether to include curves and/or surfaces and solids in the output result. Defaults to only surfaces and solids.";
static constexpr OutputDimensionalityTypes defaultvalue = CURVES_SURFACES_AND_SOLIDS;
};
enum IteratorOutputOptions { enum IteratorOutputOptions {
TRIANGULATED, TRIANGULATED,
NATIVE, NATIVE,
@@ -336,7 +346,7 @@ namespace ifcopenshell {
template <typename settings_t> template <typename settings_t>
class IFC_GEOM_API SettingsContainer { class IFC_GEOM_API SettingsContainer {
public: public:
typedef boost::variant<bool, int, double, std::string, std::set<int>, IteratorOutputOptions, PiecewiseStepMethod> value_variant_t; typedef boost::variant<bool, int, double, std::string, std::set<int>, std::set<std::string>, IteratorOutputOptions, PiecewiseStepMethod, OutputDimensionalityTypes> value_variant_t;
private: private:
settings_t settings; settings_t settings;
@@ -416,7 +426,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, IncludeCurves, IncludeSurfaces, LayersetFirst, DisableBooleanResult, NoWireIntersectionCheck, NoWireIntersectionTolerance, PrecisionFactor, DebugBooleanOperations, BooleanAttempt2d, WeldVertices, UseWorldCoords, ConvertBackUnits, ContextIds, IteratorOutput, DisableOpeningSubtractions, ApplyDefaultMaterials, DontEmitNormals, GenerateUvs, ApplyLayerSets, UseElementHierarchy, ValidateQuantities, EdgeArrows, BuildingLocalPlacement, SiteLocalPlacement, ForceSpaceTransparency, CircleSegments, KeepBoundingBoxes, PiecewiseStepType, PiecewiseStepParam> std::tuple<MesherLinearDeflection, MesherAngularDeflection, ReorientShells, LengthUnit, PlaneUnit, Precision, OutputDimensionality, LayersetFirst, DisableBooleanResult, NoWireIntersectionCheck, NoWireIntersectionTolerance, PrecisionFactor, DebugBooleanOperations, BooleanAttempt2d, WeldVertices, UseWorldCoords, ConvertBackUnits, ContextIds, ContextTypes, ContextIdentifiers, IteratorOutput, DisableOpeningSubtractions, ApplyDefaultMaterials, DontEmitNormals, GenerateUvs, ApplyLayerSets, UseElementHierarchy, ValidateQuantities, EdgeArrows, BuildingLocalPlacement, SiteLocalPlacement, ForceSpaceTransparency, CircleSegments, KeepBoundingBoxes, PiecewiseStepType, PiecewiseStepParam>
> >
{}; {};
} }
@@ -80,8 +80,8 @@ namespace IfcGeom {
struct clash { struct clash {
int clash_type; // 0 = protrusion, 1 = pierce, 2 = collision, 3 = clearance int clash_type; // 0 = protrusion, 1 = pierce, 2 = collision, 3 = clearance
IfcUtil::IfcBaseClass* a; const IfcUtil::IfcBaseClass* a;
IfcUtil::IfcBaseClass* b; const IfcUtil::IfcBaseClass* b;
double distance; double distance;
std::array<double, 3> p1; std::array<double, 3> p1;
std::array<double, 3> p2; std::array<double, 3> p2;
+21 -14
View File
@@ -114,7 +114,13 @@ std::pair<char const*, size_t> vector_to_buffer(const T& t) {
} }
void set_(const std::string& name, ifcopenshell::geometry::settings::IteratorOutputOptions val) { void set_(const std::string& name, ifcopenshell::geometry::settings::IteratorOutputOptions val) {
return $self->set(name, val); return $self->set(name, val);
} }
void set_(const std::string& name, ifcopenshell::geometry::settings::PiecewiseStepMethod val) {
return $self->set(name, val);
}
void set_(const std::string& name, ifcopenshell::geometry::settings::OutputDimensionalityTypes val) {
return $self->set(name, val);
}
void set_(const std::string& name, double val) { void set_(const std::string& name, double val) {
return $self->set(name, val); return $self->set(name, val);
} }
@@ -124,6 +130,9 @@ std::pair<char const*, size_t> vector_to_buffer(const T& t) {
void set_(const std::string& name, const std::set<int>& val) { void set_(const std::string& name, const std::set<int>& val) {
return $self->set(name, val); return $self->set(name, val);
} }
void set_(const std::string& name, const std::set<std::string>& val) {
return $self->set(name, val);
}
ifcopenshell::geometry::Settings::value_variant_t get_(const std::string& name) { ifcopenshell::geometry::Settings::value_variant_t get_(const std::string& name) {
return $self->get(name); return $self->get(name);
} }
@@ -244,8 +253,8 @@ std::pair<char const*, size_t> vector_to_buffer(const T& t) {
} }
std::vector<clash> clash_intersection_many(const std::vector<IfcUtil::IfcBaseClass*>& set_a, const std::vector<IfcUtil::IfcBaseClass*>& set_b, double tolerance, bool check_all) const { std::vector<clash> clash_intersection_many(const std::vector<IfcUtil::IfcBaseClass*>& set_a, const std::vector<IfcUtil::IfcBaseClass*>& set_b, double tolerance, bool check_all) const {
std::vector<IfcUtil::IfcBaseEntity*> set_a_entities; std::vector<const IfcUtil::IfcBaseEntity*> set_a_entities;
std::vector<IfcUtil::IfcBaseEntity*> set_b_entities; std::vector<const IfcUtil::IfcBaseEntity*> set_b_entities;
for (auto* e : set_a) { for (auto* e : set_a) {
if (!e->declaration().is("IfcProduct")) { if (!e->declaration().is("IfcProduct")) {
throw IfcParse::IfcException("All instances should be of type IfcProduct"); throw IfcParse::IfcException("All instances should be of type IfcProduct");
@@ -262,8 +271,8 @@ std::pair<char const*, size_t> vector_to_buffer(const T& t) {
} }
std::vector<clash> clash_collision_many(const std::vector<IfcUtil::IfcBaseClass*>& set_a, const std::vector<IfcUtil::IfcBaseClass*>& set_b, bool allow_touching) const { std::vector<clash> clash_collision_many(const std::vector<IfcUtil::IfcBaseClass*>& set_a, const std::vector<IfcUtil::IfcBaseClass*>& set_b, bool allow_touching) const {
std::vector<IfcUtil::IfcBaseEntity*> set_a_entities; std::vector<const IfcUtil::IfcBaseEntity*> set_a_entities;
std::vector<IfcUtil::IfcBaseEntity*> set_b_entities; std::vector<const IfcUtil::IfcBaseEntity*> set_b_entities;
for (auto* e : set_a) { for (auto* e : set_a) {
if (!e->declaration().is("IfcProduct")) { if (!e->declaration().is("IfcProduct")) {
throw IfcParse::IfcException("All instances should be of type IfcProduct"); throw IfcParse::IfcException("All instances should be of type IfcProduct");
@@ -280,8 +289,8 @@ std::pair<char const*, size_t> vector_to_buffer(const T& t) {
} }
std::vector<clash> clash_clearance_many(const std::vector<IfcUtil::IfcBaseClass*>& set_a, const std::vector<IfcUtil::IfcBaseClass*>& set_b, double clearance, bool check_all) const { std::vector<clash> clash_clearance_many(const std::vector<IfcUtil::IfcBaseClass*>& set_a, const std::vector<IfcUtil::IfcBaseClass*>& set_b, double clearance, bool check_all) const {
std::vector<IfcUtil::IfcBaseEntity*> set_a_entities; std::vector<const IfcUtil::IfcBaseEntity*> set_a_entities;
std::vector<IfcUtil::IfcBaseEntity*> set_b_entities; std::vector<const IfcUtil::IfcBaseEntity*> set_b_entities;
for (auto* e : set_a) { for (auto* e : set_a) {
if (!e->declaration().is("IfcProduct")) { if (!e->declaration().is("IfcProduct")) {
throw IfcParse::IfcException("All instances should be of type IfcProduct"); throw IfcParse::IfcException("All instances should be of type IfcProduct");
@@ -597,13 +606,12 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
if (!rep->RepresentationIdentifier()) { if (!rep->RepresentationIdentifier()) {
continue; continue;
} }
if (settings.get<ifcopenshell::geometry::settings::IncludeSurfaces>().get()) { if (settings.get<ifcopenshell::geometry::settings::OutputDimensionality>().get() != ifcopenshell::geometry::settings::CURVES) {
if (*rep->RepresentationIdentifier() == "Body") { if (*rep->RepresentationIdentifier() == "Body" || *rep->RepresentationIdentifier() == "Facetation") {
ifc_representation = rep; ifc_representation = rep;
break; break;
} }
} } else {
if (settings.get<ifcopenshell::geometry::settings::IncludeCurves>().get()) {
if (*rep->RepresentationIdentifier() == "Plan" || *rep->RepresentationIdentifier() == "Axis") { if (*rep->RepresentationIdentifier() == "Plan" || *rep->RepresentationIdentifier() == "Axis") {
ifc_representation = rep; ifc_representation = rep;
break; break;
@@ -621,13 +629,12 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
// TODO: Remove redundancy with IfcGeomIterator.h // TODO: Remove redundancy with IfcGeomIterator.h
if (context->ContextType()) { if (context->ContextType()) {
std::set<std::string> context_types; std::set<std::string> context_types;
if (settings.get<ifcopenshell::geometry::settings::IncludeSurfaces>().get()) { if (settings.get<ifcopenshell::geometry::settings::OutputDimensionality>().get() != ifcopenshell::geometry::settings::CURVES) {
context_types.insert("model"); context_types.insert("model");
context_types.insert("design"); context_types.insert("design");
context_types.insert("model view"); context_types.insert("model view");
context_types.insert("detail view"); context_types.insert("detail view");
} } else {
if (settings.get<ifcopenshell::geometry::settings::IncludeCurves>().get()) {
context_types.insert("plan"); context_types.insert("plan");
} }
+31 -6
View File
@@ -85,18 +85,40 @@
return static_cast<IfcUtil::IfcBaseClass*>(SWIG_IsOK(res) ? arg : 0); return static_cast<IfcUtil::IfcBaseClass*>(SWIG_IsOK(res) ? arg : 0);
} }
template <typename T> template<typename T>
std::vector<T> python_sequence_as_vector(PyObject* aggregate) { void add_to_container(std::vector<T>& container, const T& element) {
std::vector<T> result_vector; container.push_back(element);
result_vector.reserve(PySequence_Size(aggregate)); }
template<typename T>
void add_to_container(std::set<T>& container, const T& element) {
container.insert(element);
}
template <typename T, template<typename> typename U>
U<T> python_sequence_as_cpp_container(PyObject* aggregate) {
U<T> result_vector;
if constexpr (std::is_same_v<U<T>, std::vector<T>>) {
result_vector.reserve(PySequence_Size(aggregate));
}
for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) { for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) {
PyObject* element = PySequence_GetItem(aggregate, i); PyObject* element = PySequence_GetItem(aggregate, i);
T t = cast_pyobject<T>(element); T t = cast_pyobject<T>(element);
result_vector.push_back(t); add_to_container(result_vector, t);
} }
return result_vector; return result_vector;
} }
template <typename T>
std::vector<T> python_sequence_as_vector(PyObject* aggregate) {
return python_sequence_as_cpp_container<T, std::vector>(aggregate);
}
template <typename T>
std::set<T> python_sequence_as_set(PyObject* aggregate) {
return python_sequence_as_cpp_container<T, std::set>(aggregate);
}
template <typename T> template <typename T>
std::vector< std::vector<T> > python_sequence_as_vector_of_vector(PyObject* aggregate) { std::vector< std::vector<T> > python_sequence_as_vector_of_vector(PyObject* aggregate) {
std::vector< std::vector<T> > result_vector; std::vector< std::vector<T> > result_vector;
@@ -196,7 +218,10 @@
if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::set<int>>) { if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::set<int>>) {
std::vector<int> vs(t.begin(), t.end()); std::vector<int> vs(t.begin(), t.end());
return pythonize_vector(vs); return pythonize_vector(vs);
} else { } else if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::set<std::string>>) {
std::vector<std::string> vs(t.begin(), t.end());
return pythonize_vector(vs);
} else {
return pythonize(t); return pythonize(t);
} }
} }
+34
View File
@@ -372,3 +372,37 @@ CREATE_OPTIONAL_TYPEMAP_IN(std::string, string, str)
%typemap(freearg) const std::vector<IfcGeom::OpaqueCoordinate<4>>& { %typemap(freearg) const std::vector<IfcGeom::OpaqueCoordinate<4>>& {
delete $1; delete $1;
} }
%define CREATE_SET_TYPEMAP_IN(template_type)
%typemap(in) std::set<template_type> {
if (!check_aggregate_of_type($input, get_python_type<template_type>())) {
SWIG_exception(SWIG_TypeError, "Invalid");
}
$1 = python_sequence_as_set<template_type>($input);
}
%typemap(typecheck,precedence=SWIG_TYPECHECK_INTEGER) std::set<template_type> {
$1 = check_aggregate_of_type($input, get_python_type<template_type>()) ? 1 : 0;
}
%typemap(typecheck,precedence=SWIG_TYPECHECK_INTEGER) const std::set<template_type>& {
$1 = check_aggregate_of_type($input, get_python_type<template_type>()) ? 1 : 0;
}
%typemap(arginit) const std::set<template_type>& {
$1 = new std::set<template_type>();
}
%typemap(in) const std::set<template_type>& {
if (!check_aggregate_of_type($input, get_python_type<template_type>())) {
SWIG_exception(SWIG_TypeError, "Invalid");
}
*$1 = python_sequence_as_set<template_type>($input);
}
%typemap(freearg) const std::set<template_type>& {
delete $1;
}
%enddef
CREATE_SET_TYPEMAP_IN(int)
CREATE_SET_TYPEMAP_IN(std::string)