Skip to content

Commit 5d4ff0b

Browse files
committed
First push of a more all-round geometrical file conversion utility
1 parent 852cb7d commit 5d4ff0b

20 files changed

Lines changed: 1328 additions & 262 deletions

cmake/CMakeLists.txt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,14 @@ TARGET_LINK_LIBRARIES(IfcGeom IfcParse)
125125

126126
LINK_DIRECTORIES (${LINK_DIRECTORIES} ${IfcOpenShell_BINARY_DIR} ${OCC_LIBRARY_DIR} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64 ${ICU_LIBRARY_DIR} ${Boost_LIBRARY_DIRS})
127127

128-
ADD_EXECUTABLE(IfcObj ../src/ifcobj/IfcObj.cpp)
128+
ADD_EXECUTABLE(IfcConvert
129+
../src/ifcconvert/ColladaSerializer.cpp
130+
../src/ifcconvert/IfcConvert.cpp
131+
../src/ifcconvert/OpenCascadeBasedSerializer.cpp
132+
../src/ifcconvert/WavefrontObjSerializer.cpp
133+
)
129134

130-
TARGET_LINK_LIBRARIES (IfcObj IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet)
135+
TARGET_LINK_LIBRARIES (IfcConvert IfcParse IfcGeom TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES)
131136

132137
# Build python wrapper using separate CMakeLists.txt
133138
ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap)
@@ -171,5 +176,5 @@ SET(include_files_parse
171176
)
172177
INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom)
173178
INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse)
174-
INSTALL(TARGETS IfcObj DESTINATION bin)
179+
INSTALL(TARGETS IfcConvert DESTINATION bin)
175180
INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib)
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/********************************************************************************
2+
* *
3+
* This file is part of IfcOpenShell. *
4+
* *
5+
* IfcOpenShell is free software: you can redistribute it and/or modify *
6+
* it under the terms of the Lesser GNU General Public License as published by *
7+
* the Free Software Foundation, either version 3.0 of the License, or *
8+
* (at your option) any later version. *
9+
* *
10+
* IfcOpenShell is distributed in the hope that it will be useful, *
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13+
* Lesser GNU General Public License for more details. *
14+
* *
15+
* You should have received a copy of the Lesser GNU General Public License *
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
17+
* *
18+
********************************************************************************/
19+
20+
#include "ColladaSerializer.h"
21+
22+
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<float>& floats, const char* coords /* = "XYZ" */) {
23+
COLLADASW::FloatSource source(mSW);
24+
source.setId(mesh_id + suffix);
25+
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
26+
source.setAccessorStride(strlen(coords));
27+
source.setAccessorCount(floats.size() / 3);
28+
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
29+
source.getParameterNameList().push_back(std::string(1, coords[i]));
30+
}
31+
source.prepareToAppendValues();
32+
for (std::vector<float>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
33+
source.appendValues(*it);
34+
}
35+
source.finish();
36+
}
37+
38+
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::vector<float>& positions, const std::vector<float>& normals, const std::vector<int>& indices) {
39+
openMesh(mesh_id);
40+
41+
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions);
42+
if (!normals.empty()) {
43+
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
44+
// IfcOpenShell does not provide them with multiple face normals collapsed into a single vertex.
45+
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals);
46+
}
47+
48+
COLLADASW::VerticesElement vertices(mSW);
49+
vertices.setId(mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX );
50+
vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX));
51+
vertices.add();
52+
53+
COLLADASW::Triangles triangles(mSW);
54+
triangles.setCount(indices.size() / 3);
55+
int offset = 0;
56+
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++ ) );
57+
if (!normals.empty()) {
58+
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++ ) );
59+
}
60+
triangles.prepareToAppendValues();
61+
for (auto it = indices.begin(); it != indices.end(); ++it) {
62+
const auto& idx = *it;
63+
if (!normals.empty()) {
64+
triangles.appendValues(idx, idx);
65+
} else {
66+
triangles.appendValues(idx);
67+
}
68+
}
69+
triangles.finish();
70+
71+
closeMesh();
72+
closeGeometry();
73+
}
74+
75+
void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
76+
closeLibrary();
77+
}
78+
79+
void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_id, const std::string& material_id, const std::vector<float>& matrix) {
80+
if (!scene_opened) {
81+
openVisualScene(scene_id);
82+
scene_opened = true;
83+
}
84+
85+
COLLADASW::Node node(mSW);
86+
node.setNodeId(node_id);
87+
node.setNodeName(node_name);
88+
node.setType(COLLADASW::Node::DEFAULT);
89+
90+
// The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement.
91+
// Note that this placement is absolute, ie it is multiplied with all parent placements.
92+
double matrix_array[4][4] = {
93+
{matrix[0], matrix[3], matrix[6], matrix[ 9]},
94+
{matrix[1], matrix[4], matrix[7], matrix[10]},
95+
{matrix[2], matrix[5], matrix[8], matrix[11]},
96+
{ 0, 0, 0, 1}
97+
};
98+
99+
node.start();
100+
node.addMatrix(matrix_array);
101+
102+
COLLADASW::InstanceGeometry instanceGeometry(mSW);
103+
instanceGeometry.setUrl ("#" + geom_id);
104+
COLLADASW::InstanceMaterial material ("ColorMaterial", "#" + material_id);
105+
instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material);
106+
instanceGeometry.add();
107+
node.end();
108+
}
109+
110+
void ColladaSerializer::ColladaExporter::ColladaScene::write() {
111+
if (scene_opened) {
112+
closeVisualScene();
113+
closeLibrary();
114+
115+
COLLADASW::Scene scene (mSW, COLLADASW::URI ("#" + scene_id));
116+
scene.add();
117+
}
118+
}
119+
120+
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const SurfaceStyle& style) {
121+
openEffect(style.Name() + "-fx");
122+
COLLADASW::EffectProfile effect(mSW);
123+
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
124+
effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(style.Diffuse().R(),style.Diffuse().G(),style.Diffuse().B())));
125+
addEffectProfile(effect);
126+
}
127+
128+
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() {
129+
closeLibrary();
130+
}
131+
132+
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const SurfaceStyle& style) {
133+
if (!contains(style.Name())) {
134+
effects.write(style);
135+
surface_styles.push_back(style);
136+
}
137+
}
138+
139+
bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const std::string& name) {
140+
for (auto it = surface_styles.begin(); it != surface_styles.end(); ++it) {
141+
if (it->Name() == name) return true;
142+
}
143+
return false;
144+
}
145+
146+
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
147+
effects.close();
148+
for (auto it = surface_styles.begin(); it != surface_styles.end(); ++it) {
149+
const std::string& material_name = it->Name();
150+
openMaterial(material_name);
151+
addInstanceEffect("#" + material_name + "-fx");
152+
closeLibrary();
153+
}
154+
}
155+
156+
void ColladaSerializer::ColladaExporter::startDocument() {
157+
stream.startDocument();
158+
159+
COLLADASW::Asset asset(&stream);
160+
asset.getContributor().mAuthoringTool = std::string("IfcOpenShell ") + IFCOPENSHELL_VERSION;
161+
// TODO: Get the appropriate unit from the IFC file.
162+
asset.setUnit("meter", 1.0);
163+
asset.setUpAxisType(COLLADASW::Asset::Z_UP);
164+
asset.add();
165+
}
166+
167+
void ColladaSerializer::ColladaExporter::writeTesselated(const std::string& type, int obj_id, const std::vector<float>& matrix, const std::vector<float>& vertices, const std::vector<float>& normals, const std::vector<int>& indices) {
168+
if (!materials.contains(type)) materials.add(GetDefaultMaterial(type));
169+
deferreds.push_back(DeferedObject(type, obj_id, matrix, vertices, normals, indices));
170+
}
171+
172+
void ColladaSerializer::ColladaExporter::endDocument() {
173+
// In fact due the XML based nature of Collada and its dependency on library nodes,
174+
// only at this point all objects are written to the stream.
175+
materials.write();
176+
for (auto it = deferreds.begin(); it != deferreds.end(); ++it) {
177+
std::stringstream ss; ss << "object" << it->obj_id;
178+
const std::string object_id = ss.str();
179+
geometries.write(object_id, it->vertices, it->normals, it->indices);
180+
}
181+
geometries.close();
182+
for (auto it = deferreds.begin(); it != deferreds.end(); ++it) {
183+
std::stringstream ss; ss << "object" << it->obj_id;
184+
const std::string object_id = ss.str();
185+
scene.add(object_id, object_id, object_id, it->type, it->matrix);
186+
}
187+
scene.write();
188+
stream.endDocument();
189+
}
190+
191+
bool ColladaSerializer::ready() {
192+
return true;
193+
}
194+
195+
void ColladaSerializer::writeHeader() {
196+
exporter.startDocument();
197+
}
198+
199+
void ColladaSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {
200+
exporter.writeTesselated(o->type, o->id, o->matrix, o->mesh->verts, o->mesh->normals, o->mesh->faces);
201+
}
202+
203+
void ColladaSerializer::finalize() {
204+
exporter.endDocument();
205+
}
206+

src/ifcconvert/ColladaSerializer.h

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/********************************************************************************
2+
* *
3+
* This file is part of IfcOpenShell. *
4+
* *
5+
* IfcOpenShell is free software: you can redistribute it and/or modify *
6+
* it under the terms of the Lesser GNU General Public License as published by *
7+
* the Free Software Foundation, either version 3.0 of the License, or *
8+
* (at your option) any later version. *
9+
* *
10+
* IfcOpenShell is distributed in the hope that it will be useful, *
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13+
* Lesser GNU General Public License for more details. *
14+
* *
15+
* You should have received a copy of the Lesser GNU General Public License *
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
17+
* *
18+
********************************************************************************/
19+
20+
#ifndef COLLADASERIALIZER_H
21+
#define COLLADASERIALIZER_H
22+
23+
#include <COLLADASWStreamWriter.h>
24+
#include <COLLADASWPrimitves.h>
25+
#include <COLLADASWLibraryGeometries.h>
26+
#include <COLLADASWSource.h>
27+
#include <COLLADASWScene.h>
28+
#include <COLLADASWNode.h>
29+
#include <COLLADASWInstanceGeometry.h>
30+
#include <COLLADASWLibraryVisualScenes.h>
31+
#include <COLLADASWLibraryEffects.h>
32+
#include <COLLADASWLibraryMaterials.h>
33+
#include <COLLADASWBaseInputElement.h>
34+
#include <COLLADASWAsset.h>
35+
36+
#include "../ifcgeom/IfcGeomObjects.h"
37+
38+
#include "../ifcconvert/GeometrySerializer.h"
39+
#include "../ifcconvert/SurfaceStyle.h"
40+
41+
class ColladaSerializer : public GeometrySerializer
42+
{
43+
private:
44+
class ColladaExporter
45+
{
46+
private:
47+
class ColladaGeometries : public COLLADASW::LibraryGeometries
48+
{
49+
public:
50+
explicit ColladaGeometries(COLLADASW::StreamWriter& stream)
51+
: COLLADASW::LibraryGeometries(&stream)
52+
{}
53+
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<float>& floats, const char* coords = "XYZ");
54+
void write(const std::string mesh_id, const std::vector<float>& positions, const std::vector<float>& normals, const std::vector<int>& indices);
55+
void close();
56+
};
57+
class ColladaScene : public COLLADASW::LibraryVisualScenes
58+
{
59+
private:
60+
const std::string scene_id;
61+
bool scene_opened;
62+
public:
63+
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream)
64+
: COLLADASW::LibraryVisualScenes(&stream)
65+
, scene_id(scene_id)
66+
, scene_opened(false)
67+
{}
68+
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_id, const std::string& material_id, const std::vector<float>& matrix);
69+
void write();
70+
};
71+
class ColladaMaterials : public COLLADASW::LibraryMaterials
72+
{
73+
private:
74+
class ColladaEffects : public COLLADASW::LibraryEffects
75+
{
76+
public:
77+
explicit ColladaEffects(COLLADASW::StreamWriter& stream)
78+
: COLLADASW::LibraryEffects(&stream)
79+
{}
80+
void write(const SurfaceStyle& style);
81+
void close();
82+
};
83+
std::vector<SurfaceStyle> surface_styles;
84+
ColladaEffects effects;
85+
public:
86+
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
87+
: COLLADASW::LibraryMaterials(&stream)
88+
, effects(stream)
89+
{}
90+
void add(const SurfaceStyle& style);
91+
bool contains(const std::string& name);
92+
void write();
93+
};
94+
class DeferedObject {
95+
public:
96+
const std::string type;
97+
int obj_id;
98+
const std::vector<float> matrix;
99+
const std::vector<float> vertices;
100+
const std::vector<float> normals;
101+
const std::vector<int> indices;
102+
DeferedObject(const std::string& type, int obj_id, const std::vector<float>& matrix, const std::vector<float>& vertices,
103+
const std::vector<float>& normals, const std::vector<int>& indices)
104+
: type(type)
105+
, obj_id(obj_id)
106+
, matrix(matrix)
107+
, vertices(vertices)
108+
, normals(normals)
109+
, indices(indices)
110+
{}
111+
};
112+
COLLADABU::NativeString filename;
113+
COLLADASW::StreamWriter stream;
114+
ColladaGeometries geometries;
115+
ColladaScene scene;
116+
ColladaMaterials materials;
117+
public:
118+
ColladaExporter(const std::string& scene_name, const std::string& fn)
119+
: filename(fn.c_str())
120+
, stream(filename)
121+
, geometries(stream)
122+
, scene(scene_name, stream)
123+
, materials(stream)
124+
{}
125+
std::vector<DeferedObject> deferreds;
126+
virtual ~ColladaExporter() {}
127+
void startDocument();
128+
void writeTesselated(const std::string& type, int obj_id, const std::vector<float>& matrix, const std::vector<float>& vertices, const std::vector<float>& normals, const std::vector<int>& indices);
129+
void endDocument();
130+
};
131+
ColladaExporter exporter;
132+
public:
133+
ColladaSerializer(const std::string& dae_filename)
134+
: GeometrySerializer()
135+
, exporter("IfcOpenShell", dae_filename)
136+
{}
137+
bool ready();
138+
void writeHeader();
139+
void writeTesselated(const IfcGeomObjects::IfcGeomObject* o);
140+
void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {}
141+
void finalize();
142+
bool isTesselated() const { return true; }
143+
};
144+
145+
#endif

0 commit comments

Comments
 (0)