Skip to content

Commit 0edfb0e

Browse files
committed
Settings rework for plan/model/context and interfacing with python
1 parent b62b328 commit 0edfb0e

File tree

8 files changed

+164
-44
lines changed

8 files changed

+164
-44
lines changed

src/ifcconvert/IfcConvert.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,10 @@ int main(int argc, char** argv) {
329329
("exterior-only",
330330
po::value<std::string>(&exterior_only_algo)->default_value("none")->implicit_value("minkowski-triangles"),
331331
"Export only the exterior shell of the building found by geometric analysis. convex-decomposition, minkowski-triangles or halfspace-snapping")
332+
("plan", "Specifies whether to include curves in the output result. Typically "
333+
"these are representations of type Plan or Axis. Excluded by default.")
334+
("model", "Specifies whether to include surfaces and solids in the output result. "
335+
"Typically these are representations of type Body or Facetation. ")
332336
;
333337

334338
geometry_settings.define_options(geom_options);
@@ -975,6 +979,16 @@ int main(int argc, char** argv) {
975979
Logger::Notice(msg.str());
976980
}
977981
*/
982+
983+
// backwards compatibility
984+
if (vmap.count("plan") && vmap.count("model")) {
985+
geometry_settings.get<ifcopenshell::geometry::settings::OutputDimensionality>().value = ifcopenshell::geometry::settings::CURVES_SURFACES_AND_SOLIDS;
986+
} else if (vmap.count("model")) {
987+
geometry_settings.get<ifcopenshell::geometry::settings::OutputDimensionality>().value = ifcopenshell::geometry::settings::SURFACES_AND_SOLIDS;
988+
} else if (vmap.count("plan")) {
989+
geometry_settings.get<ifcopenshell::geometry::settings::OutputDimensionality>().value = ifcopenshell::geometry::settings::CURVES;
990+
}
991+
978992
std::unique_ptr<IfcGeom::Iterator> context_iterator;
979993
if (!elems_from_adaptor) {
980994
context_iterator.reset(new IfcGeom::Iterator(geometry_kernel, geometry_settings, ifc_file, filter_funcs, num_threads));

src/ifcconvert/cityjson

src/ifcgeom/ConversionSettings.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,28 @@ double ifcopenshell::geometry::ConversionSettings::getValue(GeomValue var) const
1010
}
1111
*/
1212

13-
std::istream& std::operator>>(istream& in, set<int>& ints) {
14-
string tokens;
13+
template <typename T>
14+
void istream_helper(std::istream& in, std::set<T>& ints) {
15+
std::string tokens;
1516
in >> tokens;
16-
vector<string> strs;
17+
std::vector<std::string> strs;
1718
boost::split(strs, tokens, boost::is_any_of(","));
1819
for (auto& s : strs) {
19-
ints.insert(boost::lexical_cast<int>(s));
20+
if constexpr (std::is_same_v<T, std::string>) {
21+
ints.insert(s);
22+
} else {
23+
ints.insert(boost::lexical_cast<T>(s));
24+
}
2025
}
26+
}
27+
28+
std::istream& std::operator>>(istream& in, set<int>& ints) {
29+
istream_helper<int>(in, ints);
30+
return in;
31+
}
32+
33+
std::istream& std::operator>>(istream& in, set<string>& strs) {
34+
istream_helper<std::string>(in, strs);
2135
return in;
2236
}
2337

@@ -51,3 +65,19 @@ std::istream& ifcopenshell::geometry::settings::operator>>(std::istream& in, Pie
5165
}
5266
return in;
5367
}
68+
69+
std::istream& ifcopenshell::geometry::settings::operator>>(std::istream& in, OutputDimensionalityTypes& v) {
70+
std::string token;
71+
in >> token;
72+
boost::to_upper(token);
73+
if (token == "CURVES") {
74+
v = CURVES;
75+
} else if (token == "SURFACES_AND_SOLIDS") {
76+
v = SURFACES_AND_SOLIDS;
77+
} else if (token == "CURVES_SURFACES_AND_SOLIDS") {
78+
v = CURVES_SURFACES_AND_SOLIDS;
79+
} else {
80+
in.setstate(std::ios_base::failbit);
81+
}
82+
return in;
83+
}

src/ifcgeom/ConversionSettings.h

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace po = boost::program_options;
2323

2424
namespace std {
2525
istream& operator>>(istream& in, set<int>& ints);
26+
istream& operator>>(istream& in, set<string>& ints);
2627
}
2728
#endif
2829

@@ -120,21 +121,6 @@ namespace ifcopenshell {
120121
static constexpr double defaultvalue = 0.00001;
121122
};
122123

123-
struct IncludeCurves : public SettingBase<IncludeCurves, bool> {
124-
static constexpr const char* const name = "plan";
125-
static constexpr const char* const description = "Specifies whether to include curves in the output result. Typically "
126-
"these are representations of type Plan or Axis. Excluded by default.";
127-
static constexpr bool defaultvalue = false;
128-
};
129-
130-
struct IncludeSurfaces : public SettingBase<IncludeSurfaces, bool> {
131-
static constexpr const char* const name = "model";
132-
static constexpr const char* const description = "Specifies whether to include surfaces and solids in the output result. "
133-
"Typically these are representations of type Body or Facetation. "
134-
"Included by default.";
135-
static constexpr bool defaultvalue = true;
136-
};
137-
138124
struct LayersetFirst : public SettingBase<LayersetFirst, bool> {
139125
static constexpr const char* const name = "layerset-first";
140126
static constexpr const char* const description = "Assigns the first layer material of the layerset "
@@ -214,6 +200,30 @@ namespace ifcopenshell {
214200
static constexpr const char* const description = "";
215201
};
216202

203+
struct ContextTypes : public SettingBase<ContextIds, std::set<std::string>> {
204+
static constexpr const char* const name = "context-types";
205+
static constexpr const char* const description = "";
206+
};
207+
208+
struct ContextIdentifiers : public SettingBase<ContextIds, std::set<std::string>> {
209+
static constexpr const char* const name = "context-identifiers";
210+
static constexpr const char* const description = "";
211+
};
212+
213+
enum OutputDimensionalityTypes {
214+
CURVES,
215+
SURFACES_AND_SOLIDS,
216+
CURVES_SURFACES_AND_SOLIDS
217+
};
218+
219+
std::istream& operator>>(std::istream& in, OutputDimensionalityTypes& ioo);
220+
221+
struct OutputDimensionality : public SettingBase<OutputDimensionality, OutputDimensionalityTypes> {
222+
static constexpr const char* const name = "dimensionality";
223+
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.";
224+
static constexpr OutputDimensionalityTypes defaultvalue = CURVES_SURFACES_AND_SOLIDS;
225+
};
226+
217227
enum IteratorOutputOptions {
218228
TRIANGULATED,
219229
NATIVE,
@@ -336,7 +346,7 @@ namespace ifcopenshell {
336346
template <typename settings_t>
337347
class IFC_GEOM_API SettingsContainer {
338348
public:
339-
typedef boost::variant<bool, int, double, std::string, std::set<int>, IteratorOutputOptions, PiecewiseStepMethod> value_variant_t;
349+
typedef boost::variant<bool, int, double, std::string, std::set<int>, std::set<std::string>, IteratorOutputOptions, PiecewiseStepMethod, OutputDimensionalityTypes> value_variant_t;
340350
private:
341351
settings_t settings;
342352

@@ -416,7 +426,7 @@ namespace ifcopenshell {
416426
};
417427

418428
class IFC_GEOM_API Settings : public SettingsContainer<
419-
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>
429+
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>
420430
>
421431
{};
422432
}

src/ifcgeom/kernels/opencascade/IfcGeomTree.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ namespace IfcGeom {
8080

8181
struct clash {
8282
int clash_type; // 0 = protrusion, 1 = pierce, 2 = collision, 3 = clearance
83-
IfcUtil::IfcBaseClass* a;
84-
IfcUtil::IfcBaseClass* b;
83+
const IfcUtil::IfcBaseClass* a;
84+
const IfcUtil::IfcBaseClass* b;
8585
double distance;
8686
std::array<double, 3> p1;
8787
std::array<double, 3> p2;

src/ifcwrap/IfcGeomWrapper.i

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,13 @@ std::pair<char const*, size_t> vector_to_buffer(const T& t) {
114114
}
115115
void set_(const std::string& name, ifcopenshell::geometry::settings::IteratorOutputOptions val) {
116116
return $self->set(name, val);
117-
}
117+
}
118+
void set_(const std::string& name, ifcopenshell::geometry::settings::PiecewiseStepMethod val) {
119+
return $self->set(name, val);
120+
}
121+
void set_(const std::string& name, ifcopenshell::geometry::settings::OutputDimensionalityTypes val) {
122+
return $self->set(name, val);
123+
}
118124
void set_(const std::string& name, double val) {
119125
return $self->set(name, val);
120126
}
@@ -124,6 +130,9 @@ std::pair<char const*, size_t> vector_to_buffer(const T& t) {
124130
void set_(const std::string& name, const std::set<int>& val) {
125131
return $self->set(name, val);
126132
}
133+
void set_(const std::string& name, const std::set<std::string>& val) {
134+
return $self->set(name, val);
135+
}
127136
ifcopenshell::geometry::Settings::value_variant_t get_(const std::string& name) {
128137
return $self->get(name);
129138
}
@@ -244,8 +253,8 @@ std::pair<char const*, size_t> vector_to_buffer(const T& t) {
244253
}
245254

246255
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 {
247-
std::vector<IfcUtil::IfcBaseEntity*> set_a_entities;
248-
std::vector<IfcUtil::IfcBaseEntity*> set_b_entities;
256+
std::vector<const IfcUtil::IfcBaseEntity*> set_a_entities;
257+
std::vector<const IfcUtil::IfcBaseEntity*> set_b_entities;
249258
for (auto* e : set_a) {
250259
if (!e->declaration().is("IfcProduct")) {
251260
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) {
262271
}
263272

264273
std::vector<clash> clash_collision_many(const std::vector<IfcUtil::IfcBaseClass*>& set_a, const std::vector<IfcUtil::IfcBaseClass*>& set_b, bool allow_touching) const {
265-
std::vector<IfcUtil::IfcBaseEntity*> set_a_entities;
266-
std::vector<IfcUtil::IfcBaseEntity*> set_b_entities;
274+
std::vector<const IfcUtil::IfcBaseEntity*> set_a_entities;
275+
std::vector<const IfcUtil::IfcBaseEntity*> set_b_entities;
267276
for (auto* e : set_a) {
268277
if (!e->declaration().is("IfcProduct")) {
269278
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) {
280289
}
281290

282291
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 {
283-
std::vector<IfcUtil::IfcBaseEntity*> set_a_entities;
284-
std::vector<IfcUtil::IfcBaseEntity*> set_b_entities;
292+
std::vector<const IfcUtil::IfcBaseEntity*> set_a_entities;
293+
std::vector<const IfcUtil::IfcBaseEntity*> set_b_entities;
285294
for (auto* e : set_a) {
286295
if (!e->declaration().is("IfcProduct")) {
287296
throw IfcParse::IfcException("All instances should be of type IfcProduct");
@@ -597,13 +606,12 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
597606
if (!rep->RepresentationIdentifier()) {
598607
continue;
599608
}
600-
if (settings.get<ifcopenshell::geometry::settings::IncludeSurfaces>().get()) {
601-
if (*rep->RepresentationIdentifier() == "Body") {
609+
if (settings.get<ifcopenshell::geometry::settings::OutputDimensionality>().get() != ifcopenshell::geometry::settings::CURVES) {
610+
if (*rep->RepresentationIdentifier() == "Body" || *rep->RepresentationIdentifier() == "Facetation") {
602611
ifc_representation = rep;
603612
break;
604613
}
605-
}
606-
if (settings.get<ifcopenshell::geometry::settings::IncludeCurves>().get()) {
614+
} else {
607615
if (*rep->RepresentationIdentifier() == "Plan" || *rep->RepresentationIdentifier() == "Axis") {
608616
ifc_representation = rep;
609617
break;
@@ -621,13 +629,12 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
621629
// TODO: Remove redundancy with IfcGeomIterator.h
622630
if (context->ContextType()) {
623631
std::set<std::string> context_types;
624-
if (settings.get<ifcopenshell::geometry::settings::IncludeSurfaces>().get()) {
632+
if (settings.get<ifcopenshell::geometry::settings::OutputDimensionality>().get() != ifcopenshell::geometry::settings::CURVES) {
625633
context_types.insert("model");
626634
context_types.insert("design");
627635
context_types.insert("model view");
628636
context_types.insert("detail view");
629-
}
630-
if (settings.get<ifcopenshell::geometry::settings::IncludeCurves>().get()) {
637+
} else {
631638
context_types.insert("plan");
632639
}
633640

src/ifcwrap/utils/type_conversion.i

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,40 @@
8585
return static_cast<IfcUtil::IfcBaseClass*>(SWIG_IsOK(res) ? arg : 0);
8686
}
8787

88-
template <typename T>
89-
std::vector<T> python_sequence_as_vector(PyObject* aggregate) {
90-
std::vector<T> result_vector;
91-
result_vector.reserve(PySequence_Size(aggregate));
88+
template<typename T>
89+
void add_to_container(std::vector<T>& container, const T& element) {
90+
container.push_back(element);
91+
}
92+
93+
template<typename T>
94+
void add_to_container(std::set<T>& container, const T& element) {
95+
container.insert(element);
96+
}
97+
98+
template <typename T, template<typename> typename U>
99+
U<T> python_sequence_as_cpp_container(PyObject* aggregate) {
100+
U<T> result_vector;
101+
if constexpr (std::is_same_v<U<T>, std::vector<T>>) {
102+
result_vector.reserve(PySequence_Size(aggregate));
103+
}
92104
for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) {
93105
PyObject* element = PySequence_GetItem(aggregate, i);
94106
T t = cast_pyobject<T>(element);
95-
result_vector.push_back(t);
107+
add_to_container(result_vector, t);
96108
}
97109
return result_vector;
98110
}
99111

112+
template <typename T>
113+
std::vector<T> python_sequence_as_vector(PyObject* aggregate) {
114+
return python_sequence_as_cpp_container<T, std::vector>(aggregate);
115+
}
116+
117+
template <typename T>
118+
std::set<T> python_sequence_as_set(PyObject* aggregate) {
119+
return python_sequence_as_cpp_container<T, std::set>(aggregate);
120+
}
121+
100122
template <typename T>
101123
std::vector< std::vector<T> > python_sequence_as_vector_of_vector(PyObject* aggregate) {
102124
std::vector< std::vector<T> > result_vector;
@@ -196,7 +218,10 @@
196218
if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::set<int>>) {
197219
std::vector<int> vs(t.begin(), t.end());
198220
return pythonize_vector(vs);
199-
} else {
221+
} else if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::set<std::string>>) {
222+
std::vector<std::string> vs(t.begin(), t.end());
223+
return pythonize_vector(vs);
224+
} else {
200225
return pythonize(t);
201226
}
202227
}

src/ifcwrap/utils/typemaps_in.i

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,3 +372,37 @@ CREATE_OPTIONAL_TYPEMAP_IN(std::string, string, str)
372372
%typemap(freearg) const std::vector<IfcGeom::OpaqueCoordinate<4>>& {
373373
delete $1;
374374
}
375+
376+
377+
378+
%define CREATE_SET_TYPEMAP_IN(template_type)
379+
380+
%typemap(in) std::set<template_type> {
381+
if (!check_aggregate_of_type($input, get_python_type<template_type>())) {
382+
SWIG_exception(SWIG_TypeError, "Invalid");
383+
}
384+
$1 = python_sequence_as_set<template_type>($input);
385+
}
386+
%typemap(typecheck,precedence=SWIG_TYPECHECK_INTEGER) std::set<template_type> {
387+
$1 = check_aggregate_of_type($input, get_python_type<template_type>()) ? 1 : 0;
388+
}
389+
390+
%typemap(typecheck,precedence=SWIG_TYPECHECK_INTEGER) const std::set<template_type>& {
391+
$1 = check_aggregate_of_type($input, get_python_type<template_type>()) ? 1 : 0;
392+
}
393+
%typemap(arginit) const std::set<template_type>& {
394+
$1 = new std::set<template_type>();
395+
}
396+
%typemap(in) const std::set<template_type>& {
397+
if (!check_aggregate_of_type($input, get_python_type<template_type>())) {
398+
SWIG_exception(SWIG_TypeError, "Invalid");
399+
}
400+
*$1 = python_sequence_as_set<template_type>($input);
401+
}
402+
%typemap(freearg) const std::set<template_type>& {
403+
delete $1;
404+
}
405+
%enddef
406+
407+
CREATE_SET_TYPEMAP_IN(int)
408+
CREATE_SET_TYPEMAP_IN(std::string)

0 commit comments

Comments
 (0)