diff --git a/src/ifcgeom/mapping/IfcOpenCrossProfileDef.cpp b/src/ifcgeom/mapping/IfcOpenCrossProfileDef.cpp
new file mode 100644
index 0000000000..d3083a23e7
--- /dev/null
+++ b/src/ifcgeom/mapping/IfcOpenCrossProfileDef.cpp
@@ -0,0 +1,94 @@
+/********************************************************************************
+ * *
+ * 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;
+
+#include "../../ifcgeom/profile_helper.h"
+#include "../../ifcgeom/infra_sweep_helper.h"
+
+#include
+const double PI = boost::math::constants::pi();
+
+#ifdef SCHEMA_HAS_IfcOpenCrossProfileDef
+
+
+taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOpenCrossProfileDef* inst) {
+ if (inst->ProfileType() != IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE) {
+ Logger::Warning("Expected IfcOpenCrossProfileDef.ProfileType to be CURVE", inst);
+ return nullptr;
+ }
+
+ std::vector points;
+ taxonomy::point3::ptr start;
+ if (inst->OffsetPoint()) {
+ start = taxonomy::cast(map(inst->OffsetPoint()));
+ } else {
+ start = taxonomy::make(0., 0., 0.);
+ }
+ points.push_back(start);
+
+ boost::optional> tags = inst->Tags();
+ boost::optional tag = boost::none;
+ if (tags.has_value() && !tags.get().empty()) {
+ tag = tags.get()[0];
+ }
+ start->tag = tag;
+
+ auto widths = inst->Widths();
+ auto angles = inst->Slopes(); // these are actually angles, but the attribute is called Slopes
+
+ if (widths.size() != angles.size()) {
+ Logger::Warning("Expected Widths and Slopes to be equal length, but got " + std::to_string(widths.size()) + " and " + std::to_string(angles.size()) + " respectively", inst);
+ return nullptr;
+ }
+
+ auto horizontal_widths = inst->HorizontalWidths();
+
+ double x = start->ccomponents().x();
+ double y = start->ccomponents().y();
+ double z = start->ccomponents().z();
+ for (size_t i = 0; i < widths.size(); ++i) {
+ double w = widths[i] * length_unit_;
+ double a = PI - angles[i] * angle_unit_;
+ double dx = (horizontal_widths ? w : w * std::cos(a));
+ double dy = (horizontal_widths ? w * std::tan(a) : w * std::sin(a));
+ double dz = 0.;
+ x -= dx; // subtract because X is positive to the left
+ y += dy;
+ z += dz;
+
+ if (tags.has_value() && !tags.get().empty()) {
+ tag = tags.get()[i+1];
+ }
+
+ points.push_back(taxonomy::make(x, y, z, tag));
+ }
+
+ auto mapped = polygon_from_points(points);
+ if (mapped->kind() == taxonomy::LOOP) {
+ auto r = taxonomy::loop::ptr((taxonomy::loop*)mapped->clone_());
+ r->closed = false;
+ return r;
+ }
+ return mapped;
+}
+
+#endif
diff --git a/src/ifcgeom/mapping/mapping.i b/src/ifcgeom/mapping/mapping.i
index adc2e3c10b..c67d0f7f4a 100644
--- a/src/ifcgeom/mapping/mapping.i
+++ b/src/ifcgeom/mapping/mapping.i
@@ -135,6 +135,9 @@ BIND(IfcFixedReferenceSweptAreaSolid)
#ifdef SCHEMA_HAS_IfcSectionedSolidHorizontal
BIND(IfcSectionedSolidHorizontal)
#endif
+#ifdef SCHEMA_HAS_IfcOpenCrossProfileDef
+BIND(IfcOpenCrossProfileDef)
+#endif
#ifdef SCHEMA_HAS_IfcSectionedSurface
BIND(IfcSectionedSurface)
#endif
diff --git a/src/serializers/WavefrontObjSerializer.cpp b/src/serializers/WavefrontObjSerializer.cpp
index 300fceeb88..f29612a65e 100644
--- a/src/serializers/WavefrontObjSerializer.cpp
+++ b/src/serializers/WavefrontObjSerializer.cpp
@@ -93,7 +93,9 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* o)
const IfcGeom::Representation::Triangulation& mesh = o->geometry();
- const int vcount = (int)mesh.verts().size() / 3;
+ size_t vcount = mesh.verts().size() / 3;
+ size_t ncount = mesh.normals().size() / 3;
+
for (auto it = mesh.verts().begin(); it != mesh.verts().end();) {
const double x = *(it++);
const double y = *(it++);
@@ -139,22 +141,25 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* o)
previous_material_id = material_id;
}
- const int v1 = *(it++)+vcount_total;
- const int v2 = *(it++)+vcount_total;
- const int v3 = *(it++)+vcount_total;
+ const int v1 = *(it++) + vcount_total;
+ const int v2 = *(it++) + vcount_total;
+ const int v3 = *(it++) + vcount_total;
- if (has_normals && has_uvs) {
- obj_stream.stream << "f " << v1 << "/" << v1 << "/" << v1 << " "
- << v2 << "/" << v2 << "/" << v2 << " "
- << v3 << "/" << v3 << "/" << v3 << "\n";
+ const int n1 = v1 - vcount_total + ncount_total;
+ const int n2 = v2 - vcount_total + ncount_total;
+ const int n3 = v3 - vcount_total + ncount_total;
+
+ if (has_normals && has_uvs) {
+ obj_stream.stream << "f " << v1 << "/" << n1 << "/" << n1 << " "
+ << v2 << "/" << n2 << "/" << n2 << " "
+ << v3 << "/" << n3 << "/" << n3 << "\n";
} else if (has_normals) {
- obj_stream.stream << "f " << v1 << "//" << v1 << " "
- << v2 << "//" << v2 << " "
- << v3 << "//" << v3 << "\n";
+ obj_stream.stream << "f " << v1 << "//" << n1 << " "
+ << v2 << "//" << n2 << " "
+ << v3 << "//" << n3 << "\n";
} else {
obj_stream.stream << "f " << v1 << " " << v2 << " " << v3 << "\n";
}
-
}
std::set faces_set (mesh.faces().begin(), mesh.faces().end());
@@ -189,4 +194,5 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* o)
}
vcount_total += vcount;
+ ncount_total += ncount;
}
diff --git a/src/serializers/WavefrontObjSerializer.h b/src/serializers/WavefrontObjSerializer.h
index 4085dfa376..d3ea41f69e 100644
--- a/src/serializers/WavefrontObjSerializer.h
+++ b/src/serializers/WavefrontObjSerializer.h
@@ -32,7 +32,7 @@ class SERIALIZERS_API WaveFrontOBJSerializer : public WriteOnlyGeometrySerialize
private:
stream_or_filename obj_stream;
stream_or_filename mtl_stream;
- unsigned int vcount_total;
+ size_t vcount_total, ncount_total;
std::set materials;
public:
WaveFrontOBJSerializer(const stream_or_filename& obj_filename, const stream_or_filename& mtl_filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings);