diff --git a/src/ifcgeom/mapping/IfcLinearPlacement.cpp b/src/ifcgeom/mapping/IfcLinearPlacement.cpp
deleted file mode 100644
index 6e205bc3d3..0000000000
--- a/src/ifcgeom/mapping/IfcLinearPlacement.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/********************************************************************************
- * *
- * This file is part of IfcOpenShell. *
- * *
- * IfcOpenShell is free software: you can redistribute it and/or modify *
- * it under the terms of the Lesser GNU General Public License as published by *
- * the Free Software Foundation, either version 3.0 of the License, or *
- * (at your option) any later version. *
- * *
- * IfcOpenShell is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * Lesser GNU General Public License for more details. *
- * *
- * You should have received a copy of the Lesser GNU General Public License *
- * along with this program. If not, see . *
- * *
- ********************************************************************************/
-
-#include "mapping.h"
-#define mapping POSTFIX_SCHEMA(mapping)
-using namespace ifcopenshell::geometry;
-
-#if defined SCHEMA_HAS_IfcLinearPlacement
-
-taxonomy::ptr mapping::map_impl(const IfcSchema::IfcLinearPlacement* inst) {
-
- // IfcLinearPlacement was added in IFC 4.1 but it had an Orientation attribute of type IfcOrientationExpression, which when combined with other
- // attributes was similar to IfcAxis2PlacementLinear. IFC 4.1 and IFC 4.2 have been withdrawn so I'm not going to try to implement linear placement for them.
- // For this reason the preprocessor skips this code if SCHEMA_HAS_IfcAxis2PlacementLinear is not defined
-#if defined SCHEMA_HAS_IfcAxis2PlacementLinear
- // the following is taken from IfcLocalPlacement and tweaked a little
- // assumes that PlacementRelTo is relative to another IfcLinearPlacement
- IfcSchema::IfcLinearPlacement* current = (IfcSchema::IfcLinearPlacement*)inst;
- auto m4 = taxonomy::make();
-
-
- for (;;) {
- IfcSchema::IfcAxis2PlacementLinear* relplacement = current->RelativePlacement();
- m4->components() = taxonomy::cast(map(relplacement))->ccomponents() * m4->ccomponents();
-
- if (current->PlacementRelTo()) {
- IfcSchema::IfcObjectPlacement* parent = current->PlacementRelTo();
-
- bool parent_placement_ignored = false;
- if (placement_rel_to_type_ || placement_rel_to_instance_) {
- IfcSchema::IfcProduct::list::ptr parent_places = parent->PlacesObject();
- for (auto iter = parent_places->begin(); iter != parent_places->end(); ++iter) {
- if ((placement_rel_to_type_ && (*iter)->declaration().is(*placement_rel_to_type_)) ||
- (placement_rel_to_instance_ && (*iter)->as() == placement_rel_to_instance_)) {
- parent_placement_ignored = true;
- }
- }
- }
-
- if (parent_placement_ignored) {
- // The parent placement of the current is a placement for a type that is
- // being ignored (Site or Building) or it is the host element of an opening.
- break;
- } else if (parent->declaration().is(IfcSchema::IfcLinearPlacement::Class())) {
- // Keep processing parent placements
- current = current->PlacementRelTo()->as();
- } else {
- // This is the root placement (typically Site).
- break;
- }
- } else {
- break;
- }
- }
-
- // The IFC specification does not provided a description of the optional
- // CartesianPosition attribute. It is assumed to be a pre-computed IfcAxis2Placement3D
- // to be used by software that don't support IfcLinearPlacement. Check that the
- // provided cartesian position is the same as the one determined by linear placement
- if (inst->CartesianPosition()) {
- auto m_fallback = taxonomy::cast(map(inst->CartesianPosition()));
- if (m4 != m_fallback) {
- Logger::Warning("IfcLinearPlacement.CartesianPosition is different than the computed placement", inst);
- }
- }
-
- // @todo: rb - not sure what this means... it came from IfcLocalPlacement
- // m4->components() = offset_and_rotation_ * m4->components();
-
- return m4;
-
-#else
- // The IFC specification does not provided a description of the optional
- // CartesianPosition attribute. It is assumed to be a pre-computed IfcAxis2Placement3D
- // to be used by software that don't support IfcLinearPlacement. In this case,
- // we will simply use the intended CartesianPosition provided by the IFC model
- if (inst->CartesianPosition()) {
- return map(inst->CartesianPosition());
- } else {
- Logger::Error("Unsupported");
- }
-#endif // SCHEMA_HAS_IfcAxis2PlacementLinear
-}
-
-#endif
diff --git a/src/ifcgeom/mapping/IfcLocalPlacement.cpp b/src/ifcgeom/mapping/IfcLocalPlacement.cpp
deleted file mode 100644
index ac275c8201..0000000000
--- a/src/ifcgeom/mapping/IfcLocalPlacement.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/********************************************************************************
- * *
- * This file is part of IfcOpenShell. *
- * *
- * IfcOpenShell is free software: you can redistribute it and/or modify *
- * it under the terms of the Lesser GNU General Public License as published by *
- * the Free Software Foundation, either version 3.0 of the License, or *
- * (at your option) any later version. *
- * *
- * IfcOpenShell is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * Lesser GNU General Public License for more details. *
- * *
- * You should have received a copy of the Lesser GNU General Public License *
- * along with this program. If not, see . *
- * *
- ********************************************************************************/
-
-#include "mapping.h"
-#define mapping POSTFIX_SCHEMA(mapping)
-using namespace ifcopenshell::geometry;
-
-taxonomy::ptr mapping::map_impl(const IfcSchema::IfcLocalPlacement* inst) {
- IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)inst;
- auto m4 = taxonomy::make();
- for (;;) {
- IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
- // @todo this type check is wrong and unnecessary?
- if (relplacement->as()) {
- // @todo check
- m4->components() = taxonomy::cast(map(relplacement))->ccomponents() * m4->ccomponents();
- }
- if (current->PlacementRelTo()) {
- IfcSchema::IfcObjectPlacement* parent = current->PlacementRelTo();
-
- bool parent_placement_ignored = false;
- if (placement_rel_to_type_ || placement_rel_to_instance_) {
- IfcSchema::IfcProduct::list::ptr parent_places = parent->PlacesObject();
- for (auto iter = parent_places->begin(); iter != parent_places->end(); ++iter) {
- if ((placement_rel_to_type_ && (*iter)->declaration().is(*placement_rel_to_type_)) ||
- (placement_rel_to_instance_ && (*iter)->as() == placement_rel_to_instance_)) {
- parent_placement_ignored = true;
- }
- }
- }
-
- if (parent_placement_ignored) {
- // The parent placement of the current is a placement for a type that is
- // being ignored (Site or Building) or it is the host element of an opening.
- break;
- } else if (parent->declaration().is(IfcSchema::IfcLocalPlacement::Class())) {
- // Keep processing parent placements
- current = current->PlacementRelTo()->as();
- } else {
- // This is the root placement (typically Site).
- break;
- }
- } else {
- break;
- }
- }
-
- // @todo
- // m4->components() = offset_and_rotation_ * m4->components();
-
- return m4;
-}
diff --git a/src/ifcgeom/mapping/IfcObjectPlacement.cpp b/src/ifcgeom/mapping/IfcObjectPlacement.cpp
new file mode 100644
index 0000000000..34ef7bee61
--- /dev/null
+++ b/src/ifcgeom/mapping/IfcObjectPlacement.cpp
@@ -0,0 +1,73 @@
+/********************************************************************************
+ * *
+ * This file is part of IfcOpenShell. *
+ * *
+ * IfcOpenShell is free software: you can redistribute it and/or modify *
+ * it under the terms of the Lesser GNU General Public License as published by *
+ * the Free Software Foundation, either version 3.0 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * IfcOpenShell is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * Lesser GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the Lesser GNU General Public License *
+ * along with this program. If not, see . *
+ * *
+ ********************************************************************************/
+
+#include "mapping.h"
+#define mapping POSTFIX_SCHEMA(mapping)
+using namespace ifcopenshell::geometry;
+
+taxonomy::ptr mapping::map_impl(const IfcSchema::IfcObjectPlacement* inst) {
+ const IfcSchema::IfcObjectPlacement* relative_to = nullptr;
+ const IfcUtil::IfcBaseInterface* transform;
+
+#ifdef SCHEMA_HAS_IfcLinearPlacement
+ if (inst->as()) {
+ transform = inst->as()->RelativePlacement();
+ }
+#endif
+ if (inst->as()) {
+ transform = inst->as()->RelativePlacement();
+ }
+ if (inst->as()) {
+ // @todo a bit harder to map without kernel
+ return nullptr;
+ }
+
+#ifdef SCHEMA_IfcObjectPlacement_HAS_PlacementRelTo
+ relative_to = inst->PlacementRelTo();
+#else
+ if (inst->as()) {
+ relative_to = inst->as()->PlacementRelTo();
+ }
+#endif
+
+ bool parent_placement_ignored = false;
+ if (relative_to && (placement_rel_to_type_ || placement_rel_to_instance_)) {
+ IfcSchema::IfcProduct::list::ptr parent_places = relative_to->PlacesObject();
+ for (auto iter = parent_places->begin(); iter != parent_places->end(); ++iter) {
+ if ((placement_rel_to_type_ && (*iter)->declaration().is(*placement_rel_to_type_)) ||
+ (placement_rel_to_instance_ && (*iter)->as() == placement_rel_to_instance_)) {
+ parent_placement_ignored = true;
+ }
+ }
+ }
+
+ if (!parent_placement_ignored && relative_to) {
+ // The parent placement of the current is a placement for a type that is
+ // being ignored (Site or Building) or it is the host element of an opening.
+ return taxonomy::make(
+ taxonomy::cast(map(relative_to))->ccomponents() *
+ taxonomy::cast(map(transform))->ccomponents()
+ );
+ } else {
+ return map(transform);
+ }
+
+ // @todo
+ // m4->components() = offset_and_rotation_ * m4->components();
+}
diff --git a/src/ifcgeom/mapping/mapping.i b/src/ifcgeom/mapping/mapping.i
index 7f1d425350..ffb5f6ec6a 100644
--- a/src/ifcgeom/mapping/mapping.i
+++ b/src/ifcgeom/mapping/mapping.i
@@ -149,11 +149,7 @@ BIND(IfcAxis1Placement);
BIND(IfcCartesianTransformationOperator2D);
// IfcCartesianTransformationOperator3DnonUniform included
BIND(IfcCartesianTransformationOperator3D);
-// BIND(IfcObjectPlacement);
-BIND(IfcLocalPlacement); // -> matrix4
-#if defined SCHEMA_HAS_IfcLinearPlacement
-BIND(IfcLinearPlacement); // -> matrix4
-#endif
+BIND(IfcObjectPlacement); // -> matrix4
BIND(IfcVector);
// BIND(IfcColourRgb);