Skip to content

Commit d879bf9

Browse files
committed
Reintroduce --model-offset/-rotation MODEL_OFFSET/_ROTATION setting #5231
1 parent 81399ff commit d879bf9

9 files changed

Lines changed: 87 additions & 206 deletions

File tree

src/ifcconvert/IfcConvert.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,10 +297,6 @@ int main(int argc, char** argv) {
297297
"Can take several minutes on large models.")
298298
("center-model-geometry",
299299
"Centers the elements by applying the center point of all mesh vertices as an offset.")
300-
("model-offset", po::value<std::string>(&offset_str),
301-
"Applies an arbitrary offset of form 'x;y;z' to all placements.")
302-
("model-rotation", po::value<std::string>(&rotation_str),
303-
"Applies an arbitrary quaternion rotation of form 'x;y;z;w' to all placements.")
304300
("include", po::value<inclusion_filter>(&include_filter)->multitoken(),
305301
"Specifies that the instances that match a specific filtering criteria are to be included in the geometrical output:\n"
306302
"1) 'entities': the following list of types should be included. SVG output defaults "

src/ifcgeom/ConversionSettings.cpp

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,34 @@
11
#include "ConversionSettings.h"
22

3-
/*
4-
void ifcopenshell::geometry::ConversionSettings::setValue(GeomValue var, double value) {
5-
values_[var] = value;
6-
}
7-
8-
double ifcopenshell::geometry::ConversionSettings::getValue(GeomValue var) const {
9-
return values_[var];
10-
}
11-
*/
12-
133
template <typename T>
14-
void istream_helper(std::istream& in, std::set<T>& ints) {
4+
void istream_helper(std::istream& in, T& vs) {
155
std::string tokens;
166
in >> tokens;
177
std::vector<std::string> strs;
188
boost::split(strs, tokens, boost::is_any_of(","));
199
for (auto& s : strs) {
20-
if constexpr (std::is_same_v<T, std::string>) {
21-
ints.insert(s);
22-
} else {
23-
ints.insert(boost::lexical_cast<T>(s));
10+
if constexpr (std::is_same_v<std::decay_t<T>, std::set<std::string>>) {
11+
vs.insert(s);
12+
} else if constexpr (std::is_same_v<std::decay_t<T>, std::set<int>>) {
13+
vs.insert(boost::lexical_cast<typename T::value_type>(s));
14+
} else if constexpr (std::is_same_v<std::decay_t<T>, std::vector<double>>) {
15+
vs.push_back(boost::lexical_cast<typename T::value_type>(s));
2416
}
2517
}
2618
}
2719

2820
std::istream& std::operator>>(istream& in, set<int>& ints) {
29-
istream_helper<int>(in, ints);
21+
istream_helper<std::set<int>>(in, ints);
3022
return in;
3123
}
3224

3325
std::istream& std::operator>>(istream& in, set<string>& strs) {
34-
istream_helper<std::string>(in, strs);
26+
istream_helper<std::set<std::string>>(in, strs);
27+
return in;
28+
}
29+
30+
std::istream& std::operator>>(istream& in, vector<double>& ds) {
31+
istream_helper<std::vector<double>>(in, ds);
3532
return in;
3633
}
3734

src/ifcgeom/ConversionSettings.h

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace po = boost::program_options;
2424
namespace std {
2525
istream& operator>>(istream& in, set<int>& ints);
2626
istream& operator>>(istream& in, set<string>& ints);
27+
istream& operator>>(istream& in, vector<double>& vs);
2728
}
2829
#endif
2930

@@ -43,7 +44,10 @@ namespace ifcopenshell {
4344
struct SettingBase {
4445
typedef T base_type;
4546

46-
boost::optional<T> value;
47+
// boost program options does not seem to handle optional<vector> types, so in case
48+
// of vector settings we need to strip away the optional and detect argument presence
49+
// with !vector::empty()
50+
std::conditional_t<std::is_same_v<T, std::vector<double>>, T, boost::optional<T>> value;
4751

4852
SettingBase() {}
4953

@@ -59,24 +63,34 @@ namespace ifcopenshell {
5963
// @todo bool_switch doesn't work with optional unfortunately...
6064
value.emplace();
6165
desc.add_options()(Derived::name, apply_default(po::bool_switch(&*value)), Derived::description);
66+
} else if constexpr (std::is_same_v<T, std::vector<double>>) {
67+
desc.add_options()(Derived::name, apply_default(po::value(&value)->multitoken()), Derived::description);
6268
} else {
6369
desc.add_options()(Derived::name, apply_default(po::value(&value)), Derived::description);
6470
}
6571
}
6672

6773
T get() const {
68-
if (value) {
69-
return value.get();
70-
}
71-
if constexpr (HasDefault<Derived>()) {
72-
return Derived::defaultvalue;
74+
if constexpr (std::is_same_v<T, std::vector<double>>) {
75+
return value;
76+
} else {
77+
if (value) {
78+
return value.get();
79+
}
80+
if constexpr (HasDefault<Derived>()) {
81+
return Derived::defaultvalue;
82+
}
83+
throw std::runtime_error("Setting not set");
7384
}
74-
throw std::runtime_error("Setting not set");
7585
}
7686

7787
bool has() const {
78-
// @todo this is not reliable, better use vmap[...].defaulted()
79-
return !!value;
88+
if constexpr (std::is_same_v<T, std::vector<double>>) {
89+
return !value.empty();
90+
} else {
91+
// @todo this is not reliable, better use vmap[...].defaulted()
92+
return !!value;
93+
}
8094
}
8195
};
8296

@@ -354,12 +368,22 @@ namespace ifcopenshell {
354368
static constexpr const char* const description = "Indicates the parameter value for defining step size when evaluating piecewise curves.";
355369
static constexpr double defaultvalue = 0.5; // ceiling of this value is used when PiecewiseStepMethod is MinSteps
356370
};
371+
372+
struct ModelOffset : public SettingBase<ModelOffset, std::vector<double>> {
373+
static constexpr const char* const name = "model-offset";
374+
static constexpr const char* const description = "Applies an arbitrary offset of form 'x,y,z' to all placements.";
375+
};
376+
377+
struct ModelRotation : public SettingBase<ModelRotation, std::vector<double>> {
378+
static constexpr const char* const name = "model-rotation";
379+
static constexpr const char* const description = "Applies an arbitrary quaternion rotation of form 'x,y,z,w' to all placements.";
380+
};
357381
}
358382

359383
template <typename settings_t>
360384
class IFC_GEOM_API SettingsContainer {
361385
public:
362-
typedef boost::variant<bool, int, double, std::string, std::set<int>, std::set<std::string>, IteratorOutputOptions, PiecewiseStepMethod, OutputDimensionalityTypes> value_variant_t;
386+
typedef boost::variant<bool, int, double, std::string, std::set<int>, std::set<std::string>, std::vector<double>, IteratorOutputOptions, PiecewiseStepMethod, OutputDimensionalityTypes> value_variant_t;
363387
private:
364388
settings_t settings;
365389

@@ -446,7 +470,7 @@ namespace ifcopenshell {
446470
};
447471

448472
class IFC_GEOM_API Settings : public SettingsContainer<
449-
std::tuple<MesherLinearDeflection, MesherAngularDeflection, ReorientShells, LengthUnit, PlaneUnit, Precision, OutputDimensionality, LayersetFirst, DisableBooleanResult, NoWireIntersectionCheck, NoWireIntersectionTolerance, PrecisionFactor, DebugBooleanOperations, BooleanAttempt2d, WeldVertices, UseWorldCoords, UseMaterialNames, ConvertBackUnits, ContextIds, ContextTypes, ContextIdentifiers, IteratorOutput, DisableOpeningSubtractions, ApplyDefaultMaterials, DontEmitNormals, GenerateUvs, ApplyLayerSets, UseElementHierarchy, ValidateQuantities, EdgeArrows, BuildingLocalPlacement, SiteLocalPlacement, ForceSpaceTransparency, CircleSegments, KeepBoundingBoxes, PiecewiseStepType, PiecewiseStepParam, NoParallelMapping>
473+
std::tuple<MesherLinearDeflection, MesherAngularDeflection, ReorientShells, LengthUnit, PlaneUnit, Precision, OutputDimensionality, LayersetFirst, DisableBooleanResult, NoWireIntersectionCheck, NoWireIntersectionTolerance, PrecisionFactor, DebugBooleanOperations, BooleanAttempt2d, WeldVertices, UseWorldCoords, UseMaterialNames, ConvertBackUnits, ContextIds, ContextTypes, ContextIdentifiers, IteratorOutput, DisableOpeningSubtractions, ApplyDefaultMaterials, DontEmitNormals, GenerateUvs, ApplyLayerSets, UseElementHierarchy, ValidateQuantities, EdgeArrows, BuildingLocalPlacement, SiteLocalPlacement, ForceSpaceTransparency, CircleSegments, KeepBoundingBoxes, PiecewiseStepType, PiecewiseStepParam, NoParallelMapping, ModelOffset, ModelRotation>
450474
>
451475
{};
452476
}

src/ifcgeom/mapping.cpp

Lines changed: 0 additions & 169 deletions
This file was deleted.

src/ifcgeom/mapping/IfcObjectPlacement.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,21 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcObjectPlacement* inst) {
6565
}
6666
}
6767

68-
taxonomy::ptr result;
68+
taxonomy::matrix4::ptr result;
6969
if (!parent_placement_ignored && relative_to) {
7070
result = taxonomy::make<taxonomy::matrix4>(
71+
// @nb this is a bit silly, in 0.7 we didn't have a recursive function
72+
// but a while loop to apply the hierarchical placements, so after the
73+
// loop we could apply the global offset. Since we have a recursive
74+
// function now we need to undo the global offset when recursing.
75+
offset_and_rotation_.inverse() *
7176
taxonomy::cast<taxonomy::matrix4>(map(relative_to))->ccomponents() *
7277
taxonomy::cast<taxonomy::matrix4>(map(transform))->ccomponents()
7378
);
7479
} else {
7580
// The parent placement of the current is a placement for a type that is
7681
// being ignored (Site or Building) or it is the host element of an opening.
77-
result = map(transform);
82+
result = taxonomy::cast<taxonomy::matrix4>(map(transform));
7883
}
7984

8085
if (fallback) {
@@ -84,10 +89,9 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcObjectPlacement* inst) {
8489
}
8590
}
8691

87-
return result;
92+
result->components() = offset_and_rotation_ * result->ccomponents();
8893

89-
// @todo
90-
// m4->components() = offset_and_rotation_ * m4->components();
94+
return result;
9195
}
9296

9397
/*

src/ifcgeom/mapping/mapping.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,28 @@ void mapping::initialize_units_() {
807807
if (settings_.get<settings::SiteLocalPlacement>().get()) {
808808
placement_rel_to_type_ = file_->schema()->declaration_by_name("IfcSite");
809809
}
810+
811+
// Translation is applied first, then rotation.
812+
if (settings_.get<ModelOffset>().has()) {
813+
auto vs = settings_.get<ModelOffset>().get();
814+
if (vs.size() == 3) {
815+
offset_and_rotation_ *= Eigen::Affine3d(Eigen::Translation3d(vs[0], vs[1], vs[2])).matrix();
816+
} else {
817+
Logger::Error("Expected 3 values for model-offset setting");
818+
}
819+
}
820+
821+
if (settings_.get<ModelRotation>().has()) {
822+
auto vs = settings_.get<ModelRotation>().get();
823+
if (vs.size() == 4) {
824+
auto m3 = Eigen::Quaterniond(vs[0], vs[1], vs[2], vs[3]).matrix();
825+
Eigen::Matrix4d m4 = Eigen::Matrix4d::Identity();
826+
m4 << m3;
827+
offset_and_rotation_ *= m4;
828+
} else {
829+
Logger::Error("Expected 4 values for model-rotation setting");
830+
}
831+
}
810832
}
811833

812834
void mapping::initialize_settings() {

0 commit comments

Comments
 (0)