Merge branch 'master' into performance_improvements

# Conflicts:
#	src/ifcconvert/ColladaSerializer.cpp
#	src/ifcconvert/ColladaSerializer.h
#	src/ifcgeom/IfcGeomIterator.h
#	src/ifcgeom/IfcGeomRenderStyles.h
This commit is contained in:
Thomas Krijnen
2016-03-22 16:15:28 +01:00
30 changed files with 1998 additions and 516 deletions
+105 -51
View File
@@ -21,48 +21,63 @@
#include "ColladaSerializer.h"
#include <COLLADASWPrimitves.h>
#include <COLLADASWSource.h>
#include <COLLADASWScene.h>
#include <COLLADASWNode.h>
#include <COLLADASWInstanceGeometry.h>
#include <COLLADASWBaseInputElement.h>
#include <COLLADASWAsset.h>
#include <boost/lexical_cast.hpp>
#include <string>
#include <cmath>
std::string collada_id(const std::string& s) {
std::string id;
id.reserve(s.size());
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
const std::string::value_type c = *it;
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || ( c == '-')) {
id.push_back(c);
}
}
return id;
static void collada_id(std::string &s)
{
IfcUtil::sanitate_material_name(s);
IfcUtil::escape_xml(s);
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords /* = "XYZ" */) {
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id,
const std::string& suffix, const std::vector<real_t>& floats, const char* coords /* = "XYZ" */)
{
COLLADASW::FloatSource source(mSW);
source.setId(mesh_id + suffix);
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
source.setAccessorStride((unsigned long)strlen(coords));
source.setAccessorCount((unsigned long)floats.size() / 3);
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
const size_t num_elems = strlen(coords);
source.setAccessorStride(static_cast<unsigned long>(num_elems));
source.setAccessorCount(static_cast<unsigned long>(floats.size() / num_elems));
for (size_t i = 0; i < num_elems; ++i) {
source.getParameterNameList().push_back(std::string(1, coords[i]));
}
source.prepareToAppendValues();
for (std::vector<double>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
for (std::vector<real_t>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
source.appendValues(*it);
}
source.finish();
}
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(
const std::string &mesh_id, const std::string& default_material_name, const std::vector<real_t>& positions,
const std::vector<real_t>& normals, const std::vector<int>& faces, const std::vector<int>& edges,
const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials,
const std::vector<real_t>& uvs)
{
openMesh(mesh_id);
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
// IfcOpenShell does not provide them with multiple face normals collapsed into a single vertex.
const bool has_normals = !normals.empty();
const bool has_uvs = !uvs.empty();
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions);
if (has_normals) {
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals);
if (has_uvs) {
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::TEXCOORDS_SOURCE_ID_SUFFIX, uvs, "UV");
}
}
COLLADASW::VerticesElement vertices(mSW);
@@ -82,20 +97,28 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
current_material_id = *(material_it++);
}
const unsigned long num_triangles = (unsigned long)std::distance(index_range_start, it) / 3;
const size_t num_triangles = std::distance(index_range_start, it) / 3;
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == faces.end())) {
COLLADASW::Triangles triangles(mSW);
triangles.setMaterial(materials[previous_material_id].name());
triangles.setCount(num_triangles);
std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
? materials[previous_material_id].original_name() : materials[previous_material_id].name());
collada_id(material_name);
triangles.setMaterial(material_name);
triangles.setCount((unsigned long)num_triangles);
int offset = 0;
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++ ) );
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++));
if (has_normals) {
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++ ) );
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++));
}
if (has_uvs) {
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::TEXCOORD,"#" + mesh_id + COLLADASW::LibraryGeometries::TEXCOORDS_SOURCE_ID_SUFFIX, offset++));
}
triangles.prepareToAppendValues();
for (std::vector<int>::const_iterator jt = index_range_start; jt != it; ++jt) {
const int idx = *jt;
if (has_normals) {
if (has_normals && has_uvs) {
triangles.appendValues(idx, idx, idx);
} else if(has_normals) {
triangles.appendValues(idx, idx);
} else {
triangles.appendValues(idx);
@@ -134,10 +157,13 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
for (linelist_t::const_iterator it = linelist.begin(); it != linelist.end(); ++it) {
COLLADASW::Lines lines(mSW);
lines.setMaterial(materials[it->first].name());
std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
? materials[it->first].original_name() : materials[it->first].name());
collada_id(material_name);
lines.setMaterial(material_name);
lines.setCount((unsigned long)it->second.size());
int offset = 0;
lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++));
lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset));
lines.prepareToAppendValues();
lines.appendValues(it->second);
lines.finish();
@@ -150,8 +176,11 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
closeLibrary();
}
void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix) {
void ColladaSerializer::ColladaExporter::ColladaScene::add(
const std::string& node_id, const std::string& node_name, const std::string& geom_name,
const std::vector<std::string>& material_ids, const std::vector<real_t>& matrix)
{
if (!scene_opened) {
openVisualScene(scene_id);
scene_opened = true;
@@ -165,18 +194,24 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& no
// The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement.
// Note that this placement is absolute, ie it is multiplied with all parent placements.
double matrix_array[4][4] = {
{matrix[0], matrix[3], matrix[6], matrix[ 9]},
{matrix[1], matrix[4], matrix[7], matrix[10]},
{matrix[2], matrix[5], matrix[8], matrix[11]},
{ 0, 0, 0, 1}
{ (double)matrix[0], (double)matrix[3], (double)matrix[6], (double)matrix[ 9] },
{ (double)matrix[1], (double)matrix[4], (double)matrix[7], (double)matrix[10] },
{ (double)matrix[2], (double)matrix[5], (double)matrix[8], (double)matrix[11] },
{ 0, 0, 0, 1 }
};
matrix_array[0][3] += serializer->settings().offset[0];
matrix_array[1][3] += serializer->settings().offset[1];
matrix_array[2][3] += serializer->settings().offset[2];
node.start();
node.addMatrix(matrix_array);
COLLADASW::InstanceGeometry instanceGeometry(mSW);
instanceGeometry.setUrl ("#" + geom_name);
for (std::vector<std::string>::const_iterator it = material_ids.begin(); it != material_ids.end(); ++it) {
COLLADASW::InstanceMaterial material (*it, "#" + *it);
foreach(std::string material_name, material_ids) {
/// @todo This is done 6 times in this file, try to perform this once and be done with the material naming for the export.
collada_id(material_name);
COLLADASW::InstanceMaterial material (material_name, "#" + material_name);
instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material);
}
instanceGeometry.add();
@@ -192,9 +227,13 @@ void ColladaSerializer::ColladaExporter::ColladaScene::write() {
scene.add();
}
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material) {
openEffect(collada_id(material.name()) + "-fx");
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material)
{
std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
? material.original_name() : material.name());
collada_id(material_name);
openEffect(material_name + "-fx");
COLLADASW::EffectProfile effect(mSW);
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
if (material.hasDiffuse()) {
@@ -223,7 +262,7 @@ void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() {
closeLibrary();
}
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) {
if (!contains(material)) {
effects.write(material);
@@ -237,15 +276,19 @@ bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeo
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
effects.close();
for (std::vector<IfcGeom::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
const std::string& material_name = collada_id((*it).name());
foreach(const IfcGeom::Material& material, materials) {
std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
? material.original_name() : material.name());
std::string material_name_unescaped = material_name; // workaround double-escaping that would occur in addInstanceEffect()
IfcUtil::sanitate_material_name(material_name_unescaped);
collada_id(material_name);
openMaterial(material_name);
addInstanceEffect("#" + material_name + "-fx");
addInstanceEffect("#" + material_name_unescaped + "-fx");
closeMaterial();
}
closeLibrary();
}
void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_name, float unit_magnitude) {
stream.startDocument();
@@ -256,16 +299,28 @@ void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_n
asset.add();
}
void ColladaSerializer::ColladaExporter::write(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
void ColladaSerializer::ColladaExporter::write(const IfcGeom::TriangulationElement<real_t>* o)
{
const IfcGeom::Representation::Triangulation<real_t>& mesh = o->geometry();
const std::string name = serializer->settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_GUIDS) ?
o->guid() : (serializer->settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_NAMES) ? o->name() : o->unique_id());
const std::string representation_id = "representation-" + boost::lexical_cast<std::string>(o->geometry().id());
std::vector<std::string> material_references;
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
const IfcGeom::Material& material = *it;
foreach(const IfcGeom::Material& material, mesh.materials()) {
if (!materials.contains(material)) {
materials.add(material);
}
material_references.push_back(collada_id(material.name()));
std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
? material.original_name() : material.name());
collada_id(material_name);
material_references.push_back(material_name);
}
deferreds.push_back(DeferredObject(unique_id, representation_id, type, matrix, vertices, normals, faces, edges, material_ids, _materials, material_references));
deferreds.push_back(
DeferredObject(name, representation_id, o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(),
mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials(), material_references, mesh.uvs())
);
}
void ColladaSerializer::ColladaExporter::endDocument() {
@@ -278,7 +333,7 @@ void ColladaSerializer::ColladaExporter::endDocument() {
continue;
}
geometries_written.insert(it->representation_id);
geometries.write(it->representation_id, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials);
geometries.write(it->representation_id, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials, it->uvs);
}
geometries.close();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
@@ -288,7 +343,7 @@ void ColladaSerializer::ColladaExporter::endDocument() {
scene.write();
stream.endDocument();
}
bool ColladaSerializer::ready() {
return true;
}
@@ -297,9 +352,8 @@ void ColladaSerializer::writeHeader() {
exporter.startDocument(unit_name, unit_magnitude);
}
void ColladaSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
exporter.write(o->unique_id(), "representation-" + boost::lexical_cast<std::string>(o->geometry().id()), o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials());
void ColladaSerializer::write(const IfcGeom::TriangulationElement<real_t>* o) {
exporter.write(o);
}
void ColladaSerializer::finalize() {
+54 -37
View File
@@ -27,17 +27,10 @@
#pragma warning(disable : 4201 4512)
#endif
#include <COLLADASWStreamWriter.h>
#include <COLLADASWPrimitves.h>
#include <COLLADASWLibraryGeometries.h>
#include <COLLADASWSource.h>
#include <COLLADASWScene.h>
#include <COLLADASWNode.h>
#include <COLLADASWInstanceGeometry.h>
#include <COLLADASWLibraryVisualScenes.h>
#include <COLLADASWLibraryEffects.h>
#include <COLLADASWLibraryMaterials.h>
#include <COLLADASWBaseInputElement.h>
#include <COLLADASWAsset.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
@@ -58,12 +51,19 @@ private:
ColladaGeometries(const ColladaGeometries&); //N/A
ColladaGeometries& operator =(const ColladaGeometries&); //N/A
public:
explicit ColladaGeometries(COLLADASW::StreamWriter& stream)
explicit ColladaGeometries(COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer)
: COLLADASW::LibraryGeometries(&stream)
, serializer(_serializer)
{}
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords = "XYZ");
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials);
void addFloatSource(const std::string& mesh_id, const std::string& suffix,
const std::vector<real_t>& floats, const char* coords = "XYZ");
void write(const std::string &mesh_id, const std::string& default_material_name,
const std::vector<real_t>& positions, const std::vector<real_t>& normals,
const std::vector<int>& faces, const std::vector<int>& edges,
const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials,
const std::vector<real_t>& uvs);
void close();
ColladaSerializer *serializer;
};
class ColladaScene : public COLLADASW::LibraryVisualScenes
{
@@ -74,13 +74,16 @@ private:
const std::string scene_id;
bool scene_opened;
public:
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream)
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer)
: COLLADASW::LibraryVisualScenes(&stream)
, scene_id(scene_id)
, scene_opened(false)
, scene_opened(false)
, serializer(_serializer)
{}
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix);
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name,
const std::vector<std::string>& material_ids, const std::vector<real_t>& matrix);
void write();
ColladaSerializer *serializer;
};
class ColladaMaterials : public COLLADASW::LibraryMaterials
{
@@ -97,32 +100,37 @@ private:
{}
void write(const IfcGeom::Material& material);
void close();
ColladaSerializer *serializer;
};
std::vector<IfcGeom::Material> materials;
ColladaEffects effects;
public:
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
explicit ColladaMaterials(COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer)
: COLLADASW::LibraryMaterials(&stream)
, effects(stream)
, serializer(_serializer)
{}
void add(const IfcGeom::Material& material);
bool contains(const IfcGeom::Material& material);
void write();
ColladaSerializer *serializer;
ColladaEffects effects;
};
class DeferredObject {
public:
std::string unique_id, representation_id, type;
std::vector<double> matrix;
std::vector<double> vertices;
std::vector<double> normals;
std::vector<real_t> matrix;
std::vector<real_t> vertices;
std::vector<real_t> normals;
std::vector<int> faces;
std::vector<int> edges;
std::vector<int> material_ids;
std::vector<IfcGeom::Material> materials;
std::vector<std::string> material_references;
DeferredObject(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices,
const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids,
const std::vector<IfcGeom::Material>& materials, const std::vector<std::string>& material_references)
std::vector<real_t> uvs;
DeferredObject(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector<real_t>& matrix,
const std::vector<real_t>& vertices, const std::vector<real_t>& normals, const std::vector<int>& faces,
const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials,
const std::vector<std::string>& material_references, const std::vector<real_t>& uvs)
: unique_id(unique_id)
, representation_id(representation_id)
, type(type)
@@ -134,39 +142,48 @@ private:
, material_ids(material_ids)
, materials(materials)
, material_references(material_references)
, uvs(uvs)
{}
};
COLLADABU::NativeString filename;
COLLADASW::StreamWriter stream;
ColladaGeometries geometries;
ColladaScene scene;
ColladaMaterials materials;
public:
ColladaExporter(const std::string& scene_name, const std::string& fn)
: filename(fn.c_str())
, stream(filename)
, geometries(stream)
, scene(scene_name, stream)
, materials(stream)
{}
ColladaExporter(const std::string& scene_name, const std::string& fn, ColladaSerializer *_serializer)
: filename(fn)
, stream(filename, sizeof(real_t) == sizeof(double)) // utilise Collada stream's double precision feature
, geometries(stream, _serializer)
, scene(scene_name, stream, _serializer)
, materials(stream, _serializer)
, serializer(_serializer)
{
}
ColladaMaterials materials;
ColladaSerializer *serializer;
ColladaGeometries geometries;
std::vector<DeferredObject> deferreds;
virtual ~ColladaExporter() {}
void startDocument(const std::string& unit_name, float unit_magnitude);
void write(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
void write(const IfcGeom::TriangulationElement<real_t>* o);
void endDocument();
};
ColladaExporter exporter;
std::string unit_name;
float unit_magnitude;
public:
ColladaSerializer(const std::string& dae_filename)
: GeometrySerializer()
, exporter("IfcOpenShell", dae_filename)
{}
ColladaSerializer(const std::string& dae_filename, const IfcGeom::IteratorSettings &settings)
: GeometrySerializer(settings)
, exporter("IfcOpenShell", dae_filename, this)
{
exporter.serializer = this;
exporter.materials.serializer = this;
exporter.materials.effects.serializer = this;
exporter.geometries.serializer = this;
}
bool ready();
void writeHeader();
void write(const IfcGeom::TriangulationElement<double>* o);
void write(const IfcGeom::BRepElement<double>* /*o*/) {}
void write(const IfcGeom::TriangulationElement<real_t>* o);
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
void finalize();
bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
+16 -3
View File
@@ -20,17 +20,30 @@
#ifndef GEOMETRYSERIALIZER_H
#define GEOMETRYSERIALIZER_H
#ifdef IFCCONVERT_DOUBLE_PRECISION
typedef double real_t;
#else
typedef float real_t;
#endif
#include "../ifcconvert/Serializer.h"
#include "../ifcgeom/IfcGeomIterator.h"
class GeometrySerializer : public Serializer {
public:
GeometrySerializer(const IfcGeom::IteratorSettings &settings) : settings_(settings) {}
virtual ~GeometrySerializer() {}
virtual bool isTesselated() const = 0;
virtual void write(const IfcGeom::TriangulationElement<double>* o) = 0;
virtual void write(const IfcGeom::BRepElement<double>* o) = 0;
virtual void write(const IfcGeom::TriangulationElement<real_t>* o) = 0;
virtual void write(const IfcGeom::BRepElement<real_t>* o) = 0;
virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0;
const IfcGeom::IteratorSettings& settings() const { return settings_; }
IfcGeom::IteratorSettings& settings() { return settings_; }
protected:
IfcGeom::IteratorSettings settings_;
};
#endif
#endif
+245 -113
View File
@@ -26,16 +26,6 @@
* *
********************************************************************************/
#include <fstream>
#include <sstream>
#include <set>
#include <time.h>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/ColladaSerializer.h"
#include "../ifcconvert/IgesSerializer.h"
#include "../ifcconvert/StepSerializer.h"
@@ -43,35 +33,58 @@
#include "../ifcconvert/XmlSerializer.h"
#include "../ifcconvert/SvgSerializer.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include <IGESControl_Controller.hxx>
#include <Standard_Version.hxx>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/optional/optional_io.hpp>
#include <fstream>
#include <sstream>
#include <set>
#include <time.h>
#if USE_VLD
#include <vld.h>
#endif
static std::string DEFAULT_EXTENSION = "obj";
const std::string DEFAULT_EXTENSION = "obj";
const std::string TEMP_FILE_EXTENSION = ".tmp";
void printVersion() {
std::cerr << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << std::endl;
void print_version()
{
/// @todo Why cerr used for info prints? Change to cout.
std::cerr << "IfcOpenShell " << IfcSchema::Identifier << " IfcConvert " << IFCOPENSHELL_VERSION << std::endl;
}
void printUsage(const boost::program_options::options_description& generic_options, const boost::program_options::options_description& geom_options) {
printVersion();
std::cerr << "Usage: IfcConvert [options] <input.ifc> [<output>]" << std::endl
<< std::endl
<< "Converts the geometry in an IFC file into one of the following formats:" << std::endl
<< " .obj WaveFront OBJ (a .mtl file is also created)" << std::endl;
#ifdef WITH_OPENCOLLADA
std::cerr << " .dae Collada Digital Asset Exchange" << std::endl;
void print_usage(bool suggest_help = true)
{
std::cerr << "Usage: IfcConvert [options] <input.ifc> [<output>]" << "\n"
<< "\n"
<< "Converts the geometry in an IFC file into one of the following formats:" << "\n"
<< " .obj WaveFront OBJ (a .mtl file is also created)" << "\n"
#ifdef WITH_OPENCOLLADA
<< " .dae Collada Digital Assets Exchange" << "\n"
#endif
std::cerr << " .stp STEP Standard for the Exchange of Product Data" << std::endl
<< " .igs IGES Initial Graphics Exchange Specification" << std::endl
<< " .xml XML Property definitions and decomposition tree" << std::endl
<< " .svg SVG Scalable Vector Graphics (2d floor plan)" << std::endl
<< std::endl
<< "Command line options" << std::endl << generic_options << std::endl
<< "Advanced options" << std::endl << geom_options << std::endl;
<< " .stp STEP Standard for the Exchange of Product Data" << "\n"
<< " .igs IGES Initial Graphics Exchange Specification" << "\n"
<< " .xml XML Property definitions and decomposition tree" << "\n"
<< " .svg SVG Scalable Vector Graphics (2D floor plan)" << "\n"
<< "\n"
<< "If no output filename given, <input>." + DEFAULT_EXTENSION + " will be used as the output file.\n";
if (suggest_help) {
std::cerr << "\nRun 'IfcConvert --help' for more information.";
}
std::cerr << std::endl;
}
void print_options(const boost::program_options::options_description& options)
{
std::cerr << "\n" << options;
std::cerr << std::endl;
}
std::string change_extension(const std::string& fn, const std::string& ext) {
@@ -83,24 +96,41 @@ std::string change_extension(const std::string& fn, const std::string& ext) {
}
}
bool file_exists(const std::string& filename)
{
/// @todo Windows Unicode support
std::ifstream file(filename.c_str());
return file.good();
}
bool rename_file(const std::string& old_filename, const std::string& new_filename)
{
// Whether or not rename() replaces an existing file is implementation-specific,
// so remove() possible existing file always.
/// @todo Windows Unicode support
std::remove(new_filename.c_str());
return std::rename(old_filename.c_str(), new_filename.c_str()) == 0;
}
static std::stringstream log_stream;
void write_log();
int main(int argc, char** argv) {
boost::program_options::options_description generic_options;
boost::program_options::options_description generic_options("Command line options");
generic_options.add_options()
("help", "display usage information")
("help,h", "display usage information")
("version", "display version information")
("verbose,v", "more verbose output");
("verbose,v", "more verbose output")
("yes,y", "answer 'yes' automatically to possible confirmation queries (e.g overwriting an existing output file)");
boost::program_options::options_description fileio_options;
fileio_options.add_options()
("input-file", boost::program_options::value<std::string>(), "input IFC file")
("output-file", boost::program_options::value<std::string>(), "output geometry file");
std::string bounds;
std::vector<std::string> entity_vector;
boost::program_options::options_description geom_options;
std::vector<std::string> entity_vector, names;
double deflection_tolerance;
boost::program_options::options_description geom_options("Geometry options");
geom_options.add_options()
("plan",
"Specifies whether to include curves in the output result. Typically "
@@ -142,20 +172,51 @@ int main(int argc, char** argv) {
("disable-opening-subtractions",
"Specifies whether to disable the boolean subtraction of "
"IfcOpeningElement Representations from their RelatingElements.")
("bounds", boost::program_options::value<std::string>(&bounds),
"Specifies the bounding rectangle, for example 512x512, to which the "
"output will be scaled. Only used when converting to SVG.")
("include",
"Specifies that the entities listed after --entities are to be included")
"Specifies that the entities listed after --entities or --names are to be included")
("exclude",
"Specifies that the entities listed after --entities are to be excluded")
("entities", boost::program_options::value< std::vector<std::string> >(&entity_vector)->multitoken(),
"Specifies that the entities listed after --entities or --names are to be excluded")
("entities", boost::program_options::value< std::vector<std::string> >(&entity_vector)->multitoken(),
"A list of entities that should be included in or excluded from the "
"geometrical output, depending on whether --ignore or --include is "
"specified. Defaults to IfcOpeningElement and IfcSpace to be excluded.");
"geometrical output, depending on whether --exclude or --include is specified. "
"Defaults to IfcOpeningElement and IfcSpace to be excluded. SVG output defaults "
"to IfcSpace to be included."
"The names are handled case-insensitively. Cannot be placed right before input file argument.")
("names", boost::program_options::value< std::vector<std::string> >(&names)->multitoken(),
"A list of names or wildcard patterns that should be included in or excluded from the "
"geometrical output, depending on whether --exclude or --include is specified. "
"The names are handled case-sensitively. Cannot be placed right before input file argument.")
("no-normals",
"Disables computation of normals. Saves time and file size and is useful "
"in instances where you're going to recompute normals for the exported "
"model in other modelling application in any case.")
("deflection-tolerance", boost::program_options::value<double>(&deflection_tolerance),
"Sets the deflection tolerance of the mesher, 1e-3 by default if not specified.")
("generate-uvs",
"Generates UVs (texture coordinates) by using simple box projection. Requires normals. "
"Not guaranteed to work properly if used with --weld-vertices.");
std::string bounds;
boost::program_options::options_description serializer_options("Serialization options");
serializer_options.add_options()
("bounds", boost::program_options::value<std::string>(&bounds),
"Specifies the bounding rectangle, for example 512x512, to which the "
"output will be scaled. Only used when converting to SVG.")
("use-element-names",
"Use entity names instead of unique IDs for naming elements upon serialization. "
"Applicable for OBJ, DAE, and SVG output.")
("use-element-guids",
"Use entity GUIDs instead of unique IDs for naming elements upon serialization. "
"Applicable for OBJ, DAE, and SVG output.")
("use-material-names",
"Use material names instead of unique IDs for naming materials upon serialization. "
"Applicable for OBJ and DAE output.")
("center-model",
"Centers the elements upon serialization by applying the center point of "
"all placements as an offset. Applicable for OBJ and DAE output.");
boost::program_options::options_description cmdline_options;
cmdline_options.add(generic_options).add(fileio_options).add(geom_options);
cmdline_options.add(generic_options).add(fileio_options).add(geom_options).add(serializer_options);
boost::program_options::positional_options_description positional_options;
positional_options.add("input-file", 1);
@@ -167,21 +228,30 @@ int main(int argc, char** argv) {
options(cmdline_options).positional(positional_options).run(), vmap);
} catch (const boost::program_options::unknown_option& e) {
std::cerr << "[Error] Unknown option '" << e.get_option_name() << "'" << std::endl << std::endl;
// Usage information will be emitted below
print_usage();
return 1;
} catch (...) {
// Catch other errors such as invalid command line syntax
print_usage();
return 1;
}
boost::program_options::notify(vmap);
if (vmap.count("version")) {
printVersion();
return 0;
} else if (vmap.count("help") || !vmap.count("input-file")) {
printUsage(generic_options, geom_options);
return vmap.count("help") ? 0 : 1;
print_version();
if (vmap.count("version")) {
return 0;
} else if (vmap.count("help")) {
print_usage(false);
print_options(generic_options.add(geom_options).add(serializer_options));
return 0;
} else if (!vmap.count("input-file")) {
std::cerr << "[Error] Input file not specified" << std::endl;
print_usage();
return 1;
} else if (vmap.count("include") && vmap.count("exclude")) {
std::cerr << "[Error] --include and --ignore can not be specified together" << std::endl;
printUsage(generic_options, geom_options);
std::cerr << "[Error] --include and --exclude can not be specified together" << std::endl;
print_options(geom_options);
return 1;
}
@@ -197,6 +267,13 @@ int main(int argc, char** argv) {
bool include_entities = vmap.count("include") != 0;
const bool include_plan = vmap.count("plan") != 0;
const bool include_model = vmap.count("model") != 0 || (!include_plan);
const bool use_element_names = vmap.count("use-element-names") != 0;
const bool use_element_guids = vmap.count("use-element-guids") != 0 ;
const bool use_material_names = vmap.count("use-material-names") != 0;
const bool no_normals = vmap.count("no-normals") != 0 ;
bool center_model = vmap.count("center-model") != 0 ;
const bool generate_uvs = vmap.count("generate-uvs") != 0 ;
const bool deflection_tolerance_specified = vmap.count("deflection-tolerance") != 0 ;
boost::optional<int> bounding_width, bounding_height;
if (vmap.count("bounds") == 1) {
int w, h;
@@ -205,19 +282,20 @@ int main(int argc, char** argv) {
bounding_height = h;
} else {
std::cerr << "[Error] Invalid use of --bounds" << std::endl;
printUsage(generic_options, geom_options);
print_options(serializer_options);
return 1;
}
}
// Gets the set ifc types to be ignored from the command line.
std::set<std::string> entities;
for (std::vector<std::string>::const_iterator it = entity_vector.begin(); it != entity_vector.end(); ++it) {
const std::string& mixed_case_type = *it;
entities.insert(boost::to_lower_copy(mixed_case_type));
}
std::set<std::string> entities(entity_vector.begin(), entity_vector.end());
const std::string input_filename = vmap["input-file"].as<std::string>();
if (!file_exists(input_filename)) {
std::cerr << "[Error] Input file '" << input_filename << "' does not exist" << std::endl;
return 1;
}
// If no output filename is specified a Wavefront OBJ file will be output
// to maintain backwards compatibility with the obsolete IfcObj executable.
const std::string output_filename = vmap.count("output-file") == 1
@@ -225,21 +303,32 @@ int main(int argc, char** argv) {
: change_extension(input_filename, DEFAULT_EXTENSION);
if (output_filename.size() < 5) {
printUsage(generic_options, geom_options);
std::cerr << "[Error] Invalid or unsupported output file '" << output_filename << "' given" << std::endl;
print_usage();
return 1;
}
if (file_exists(output_filename) && !vmap.count("yes")) {
std::string answer;
std::cout << "A file '" << output_filename << "' already exists. Overwrite the existing file?" << std::endl;
std::cin >> answer;
if (!boost::iequals(answer, "yes") && !boost::iequals(answer, "y")) {
return 0;
}
}
std::string output_temp_filename = output_filename + TEMP_FILE_EXTENSION;
std::string output_extension = output_filename.substr(output_filename.size()-4);
boost::to_lower(output_extension);
// If no entities are specified these are the defaults to skip from output
if (entity_vector.empty()) {
// If no entity or names filters are specified these are the defaults to skip from output
if (entities.empty() && names.empty()) {
entities.insert("IfcSpace");
if (output_extension == ".svg") {
entities.insert("ifcspace");
include_entities = true;
} else {
entities.insert("ifcopeningelement");
entities.insert("ifcspace");
entities.insert("IfcOpeningElement");
}
}
@@ -249,13 +338,14 @@ int main(int argc, char** argv) {
if (output_extension == ".xml") {
int exit_code = 1;
try {
XmlSerializer s(output_filename);
XmlSerializer s(output_temp_filename);
IfcParse::IfcFile f;
if (!f.Init(input_filename)) {
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
Logger::Message(Logger::LOG_ERROR, "Unable to parse input file '" + input_filename + "'");
} else {
s.setFile(&f);
s.finalize();
rename_file(output_temp_filename, output_filename);
exit_code = 0;
}
} catch (...) {}
@@ -264,7 +354,7 @@ int main(int argc, char** argv) {
}
IfcGeom::IteratorSettings settings;
/// @todo Make APPLY_DEFAULT_MATERIALS configurable? Quickly tested setting this to false and using obj exporter caused the program to crash and burn.
settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true);
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords);
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, weld_vertices);
@@ -276,56 +366,70 @@ int main(int argc, char** argv) {
settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions);
settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan);
settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model);
settings.set(IfcGeom::IteratorSettings::USE_ELEMENT_NAMES, use_element_names);
settings.set(IfcGeom::IteratorSettings::USE_ELEMENT_GUIDS, use_element_guids);
settings.set(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES, use_material_names);
settings.set(IfcGeom::IteratorSettings::NO_NORMALS, no_normals);
settings.set(IfcGeom::IteratorSettings::CENTER_MODEL, center_model);
settings.set(IfcGeom::IteratorSettings::GENERATE_UVS, generate_uvs);
if (deflection_tolerance_specified) {
settings.set_deflection_tolerance(deflection_tolerance);
}
GeometrySerializer* serializer;
if (output_extension == ".obj") {
const std::string mtl_filename = output_filename.substr(0,output_filename.size()-3) + "mtl";
const std::string mtl_temp_filename = change_extension(output_filename, "mtl") + TEMP_FILE_EXTENSION;
if (!use_world_coords) {
Logger::Message(Logger::LOG_NOTICE, "Using world coords when writing WaveFront OBJ files");
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
}
serializer = new WaveFrontOBJSerializer(output_filename, mtl_filename);
serializer = new WaveFrontOBJSerializer(output_temp_filename, mtl_temp_filename, settings);
#ifdef WITH_OPENCOLLADA
} else if (output_extension == ".dae") {
serializer = new ColladaSerializer(output_filename);
serializer = new ColladaSerializer(output_temp_filename, settings);
#endif
} else if (output_extension == ".stp") {
serializer = new StepSerializer(output_filename);
serializer = new StepSerializer(output_temp_filename, settings);
} else if (output_extension == ".igs") {
// Not sure why this is needed, but it is.
// See: http://tracker.dev.opencascade.org/view.php?id=23679
IGESControl_Controller::Init();
serializer = new IgesSerializer(output_filename);
IGESControl_Controller::Init(); // work around Open Cascade bug
serializer = new IgesSerializer(output_temp_filename, settings);
} else if (output_extension == ".svg") {
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
serializer = new SvgSerializer(output_filename);
serializer = new SvgSerializer(output_temp_filename, settings);
if (bounding_width && bounding_height) {
((SvgSerializer*) serializer)->setBoundingRectangle(
static_cast<double>(*bounding_width),
static_cast<double>(*bounding_height)
);
static_cast<SvgSerializer*>(serializer)->setBoundingRectangle(*bounding_width, *bounding_height);
}
} else {
Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension");
Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension '" + output_extension + "'");
write_log();
printUsage(generic_options, geom_options);
print_usage();
return 1;
}
if (!serializer->isTesselated()) {
const bool is_tesselated = serializer->isTesselated(); // isTesselated() doesn't change at run-time
if (!is_tesselated) {
if (weld_vertices) {
Logger::Message(Logger::LOG_NOTICE, "Weld vertices setting ignored when writing STEP or IGES files");
Logger::Message(Logger::LOG_NOTICE, "Weld vertices setting ignored when writing non-tesselated output");
}
settings.disable_triangulation() = true;
if (generate_uvs) {
Logger::Message(Logger::LOG_NOTICE, "Generate UVs setting ignored when writing non-tesselated output");
}
if (center_model) {
Logger::Message(Logger::LOG_NOTICE, "Center model setting ignored when writing non-tesselated output");
}
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
}
IfcGeom::Iterator<double> context_iterator(settings, input_filename);
IfcGeom::Iterator<real_t> context_iterator(settings, input_filename);
try {
if (include_entities) {
context_iterator.includeEntities(entities);
context_iterator.include_entity_names(names);
} else {
context_iterator.excludeEntities(entities);
context_iterator.exclude_entity_names(names);
}
} catch (const IfcParse::IfcException& e) {
std::cout << "[Error] " << e.what() << std::endl;
@@ -333,7 +437,7 @@ int main(int argc, char** argv) {
}
if (!serializer->ready()) {
Logger::Message(Logger::LOG_ERROR, "Unable to open output file for writing");
Logger::Message(Logger::LOG_ERROR, "Unable to open output '" + output_filename + "' file for writing");
write_log();
return 1;
}
@@ -342,26 +446,25 @@ int main(int argc, char** argv) {
time(&start);
if (!context_iterator.initialize()) {
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found");
Logger::Message(Logger::LOG_ERROR, "Unable to parse input file '" + input_filename + "' or no geometrical entities found");
write_log();
return 1;
}
serializer->setFile(context_iterator.getFile());
serializer->setFile(context_iterator.getFile());
if (convert_back_units) {
serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<const float>(context_iterator.getUnitMagnitude()));
serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<float>(context_iterator.getUnitMagnitude()));
} else {
serializer->setUnitNameAndMagnitude("METER", 1.0f);
}
serializer->writeHeader();
std::set<std::string> materials;
int old_progress = -1;
Logger::Status("Creating geometry...");
std::vector<IfcGeom::Element<real_t>* > geometries;
// The functions IfcGeom::Iterator::get() and IfcGeom::Iterator::next()
// wrap an iterator of all geometrical products in the Ifc file.
// IfcGeom::Iterator::get() returns an IfcGeom::TriangulationElement or
@@ -373,30 +476,60 @@ int main(int argc, char** argv) {
// true return value guarantees that a successfully processed product is
// available.
do {
const IfcGeom::Element<double>* geom_object = context_iterator.get();
if (serializer->isTesselated()) {
serializer->write(static_cast<const IfcGeom::TriangulationElement<double>*>(geom_object));
} else {
serializer->write(static_cast<const IfcGeom::BRepElement<double>*>(geom_object));
}
const int progress = context_iterator.progress() / 2;
if (old_progress!= progress) Logger::ProgressBar(progress);
old_progress = progress;
} while (context_iterator.next());
IfcGeom::Element<real_t> *geom_object = context_iterator.get(true); // true == take ownership, we will clean up ourselves
geometries.push_back(geom_object);
const int progress = context_iterator.progress() / 2;
if (old_progress != progress) Logger::ProgressBar(progress);
old_progress = progress;
} while (context_iterator.next());
Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(geometries.size()) +
" objects) ");
if (center_model) {
double* offset = serializer->settings().offset;
gp_XYZ center = (context_iterator.bounds_min() + context_iterator.bounds_max()) * 0.5;
offset[0] = -center.X();
offset[1] = -center.Y();
offset[2] = -center.Z();
//printf("Bounds min. (%g, %g, %g)\n", context_iterator.bounds_min().X(), context_iterator.bounds_min().Y(), context_iterator.bounds_min().Z());
//printf("Bounds max. (%g, %g, %g)\n", context_iterator.bounds_min().X(), context_iterator.bounds_min().X(), context_iterator.bounds_min().Z());
printf("Using model offset (%g, %g, %g)\n", offset[0], offset[1], offset[2]); //TODO Logger::Message(Logger::LOG_NOTICE, ...);
}
Logger::Status("Serializing geometry...");
foreach(const IfcGeom::Element<real_t>* geom, geometries) {
if (is_tesselated) {
serializer->write(static_cast<const IfcGeom::TriangulationElement<real_t>*>(geom));
} else {
serializer->write(static_cast<const IfcGeom::BRepElement<real_t>*>(geom));
}
delete geom;
}
serializer->finalize();
Logger::Status("\rDone serializing geometry ");
delete serializer;
Logger::Status("\rDone creating geometry ");
rename_file(output_temp_filename, output_filename);
if (output_extension == ".obj") {
std::string mtl_filename = change_extension(output_filename, "mtl");
std::string mtl_tmp_filename = mtl_filename + TEMP_FILE_EXTENSION;
rename_file(mtl_tmp_filename, mtl_filename);
}
write_log();
time(&end);
int dif = (int) difftime (end,start);
printf ("\nConversion took %d seconds\n", dif );
int seconds = (int)difftime(end, start);
if (seconds < 60)
printf("\nConversion took %d seconds\n", seconds); // TODO Logger::Message(Logger::LOG_NOTICE, ...);
else
printf("\nConversion took %d minute(s) %d seconds\n", seconds/60, seconds%60); // TODO Logger::Message(Logger::LOG_NOTICE, ...);
return 0;
}
@@ -404,7 +537,6 @@ int main(int argc, char** argv) {
void write_log() {
std::string log = log_stream.str();
if (!log.empty()) {
std::cerr << std::endl << "Log:" << std::endl;
std::cerr << log << std::endl;
std::cerr << "\n" << "Log:\n" << log << std::endl;
}
}
}
+8 -8
View File
@@ -20,20 +20,20 @@
#ifndef IGESSERIALIZER_H
#define IGESSERIALIZER_H
#include "OpenCascadeBasedSerializer.h"
#include <IGESControl_Writer.hxx>
#include <Interface_Static.hxx>
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
class IgesSerializer : public OpenCascadeBasedSerializer
{
private:
IGESControl_Writer writer;
IGESControl_Writer writer;
public:
explicit IgesSerializer(const std::string& out_filename)
: OpenCascadeBasedSerializer(out_filename)
/// @note IGESControl_Controller::Init() must be called prior to instantiating IgesSerializer.
/// See http://tracker.dev.opencascade.org/view.php?id=23679 for more information.
IgesSerializer(const std::string& out_filename, const IfcGeom::IteratorSettings &settings)
: OpenCascadeBasedSerializer(out_filename, settings)
{}
virtual ~IgesSerializer() {}
void writeShape(const TopoDS_Shape& shape) {
@@ -51,4 +51,4 @@ public:
}
};
#endif
#endif
@@ -36,14 +36,14 @@ bool OpenCascadeBasedSerializer::ready() {
return succeeded;
}
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<double>* o) {
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<real_t>* o) {
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
gp_GTrsf gtrsf = it->Placement();
const gp_Trsf& o_trsf = o->transformation().data();
gtrsf.PreMultiply(o_trsf);
if (o->geometry().settings().convert_back_units()) {
if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude());
gtrsf.PreMultiply(scale);
+5 -5
View File
@@ -31,18 +31,18 @@ protected:
const std::string out_filename;
const char* getSymbolForUnitMagnitude(float mag);
public:
explicit OpenCascadeBasedSerializer(const std::string& out_filename)
: GeometrySerializer()
explicit OpenCascadeBasedSerializer(const std::string& out_filename, const IfcGeom::IteratorSettings &settings)
: GeometrySerializer(settings)
, out_filename(out_filename)
{}
virtual ~OpenCascadeBasedSerializer() {}
void writeHeader() {}
bool ready();
virtual void writeShape(const TopoDS_Shape& shape) = 0;
void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
void write(const IfcGeom::BRepElement<double>* o);
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
void write(const IfcGeom::BRepElement<real_t>* o);
bool isTesselated() const { return false; }
void setFile(IfcParse::IfcFile*) {}
};
#endif
#endif
+2 -2
View File
@@ -32,8 +32,8 @@ class StepSerializer : public OpenCascadeBasedSerializer
private:
STEPControl_Writer writer;
public:
explicit StepSerializer(const std::string& out_filename)
: OpenCascadeBasedSerializer(out_filename)
explicit StepSerializer(const std::string& out_filename, const IfcGeom::IteratorSettings &settings)
: OpenCascadeBasedSerializer(out_filename, settings)
{}
virtual ~StepSerializer() {}
void writeShape(const TopoDS_Shape& shape) {
+9 -4
View File
@@ -168,7 +168,8 @@ SvgSerializer::path_object& SvgSerializer::start_path(IfcSchema::IfcBuildingStor
return p;
}
void SvgSerializer::write(const IfcGeom::BRepElement<double>* o) {
void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
{
IfcSchema::IfcBuildingStorey* storey = 0;
IfcSchema::IfcObjectDefinition* obdef = static_cast<IfcSchema::IfcObjectDefinition*>(file->entityById(o->id()));
@@ -340,10 +341,14 @@ void SvgSerializer::writeHeader() {
svg_file << "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
}
std::string SvgSerializer::nameElement(const IfcGeom::Element<double>* elem) {
std::string SvgSerializer::nameElement(const IfcGeom::Element<real_t>* elem)
{
std::ostringstream oss;
const std::string type = "product";
oss << "id=\"" << type << "-" << elem->unique_id() << "\"";
const std::string name = (settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_GUIDS)
? elem->guid() : (settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_NAMES)
? elem->name() : elem->unique_id()));
oss << "id=\"" << type << "-" << name<< "\"";
return oss.str();
}
@@ -352,4 +357,4 @@ std::string SvgSerializer::nameElement(const IfcSchema::IfcProduct* elem) {
const std::string type = elem->is(IfcSchema::Type::IfcBuildingStorey) ? "storey" : "product";
oss << "id=\"product-" << IfcParse::IfcGlobalId(elem->GlobalId()).formatted() << "\"";
return oss.str();
}
}
+23 -26
View File
@@ -22,15 +22,13 @@
#ifndef SVGSERIALIZER_H
#define SVGSERIALIZER_H
#include "../ifcconvert/GeometrySerializer.h"
#include "../ifcconvert/util.h"
#include <sstream>
#include <string>
#include <limits>
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/GeometrySerializer.h"
#include "../ifcconvert/util.h"
class SvgSerializer : public GeometrySerializer {
public:
typedef std::pair<std::string, std::vector<util::string_buffer> > path_object;
@@ -45,8 +43,8 @@ protected:
std::vector< boost::shared_ptr<util::string_buffer::float_item> > radii;
IfcParse::IfcFile* file;
public:
explicit SvgSerializer(const std::string& out_filename)
: GeometrySerializer()
SvgSerializer(const std::string& out_filename, const IfcGeom::IteratorSettings &settings)
: GeometrySerializer(settings)
, svg_file(out_filename.c_str())
, xmin(+std::numeric_limits<double>::infinity())
, xmax(-std::numeric_limits<double>::infinity())
@@ -55,25 +53,24 @@ public:
, rescale(false)
, file(0)
{}
virtual void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
virtual void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
virtual void addSizeComponent(const boost::shared_ptr<util::string_buffer::float_item>& fi) { radii.push_back(fi); }
virtual void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; }
virtual ~SvgSerializer() {}
virtual void writeHeader();
virtual bool ready();
virtual void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
virtual void write(const IfcGeom::BRepElement<double>* o);
virtual void write(path_object& p, const TopoDS_Wire& wire);
virtual path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id);
virtual bool isTesselated() const { return false; }
virtual void finalize();
virtual void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
virtual void setFile(IfcParse::IfcFile* f) { file = f; }
virtual void setBoundingRectangle(double width, double height);
virtual void setSectionHeight(double h) { section_height = h; }
virtual std::string nameElement(const IfcGeom::Element<double>* elem);
virtual std::string nameElement(const IfcSchema::IfcProduct* elem);
void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
void addSizeComponent(const boost::shared_ptr<util::string_buffer::float_item>& fi) { radii.push_back(fi); }
void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; }
void writeHeader();
bool ready();
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
void write(const IfcGeom::BRepElement<real_t>* o);
void write(path_object& p, const TopoDS_Wire& wire);
path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id);
bool isTesselated() const { return false; }
void finalize();
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
void setFile(IfcParse::IfcFile* f) { file = f; }
void setBoundingRectangle(double width, double height);
void setSectionHeight(double h) { section_height = h; }
std::string nameElement(const IfcGeom::Element<real_t>* elem);
std::string nameElement(const IfcSchema::IfcProduct* elem);
};
#endif
+42 -22
View File
@@ -17,12 +17,13 @@
* *
********************************************************************************/
#include <limits>
#include <iomanip>
#include "WavefrontObjSerializer.h"
#include "../ifcgeom/IfcGeomRenderStyles.h"
#include "WavefrontObjSerializer.h"
#include <boost/lexical_cast.hpp>
#include <iomanip>
bool WaveFrontOBJSerializer::ready() {
return obj_stream.is_open() && mtl_stream.is_open();
@@ -41,11 +42,15 @@ void WaveFrontOBJSerializer::writeHeader() {
mtl_basename = mtl_basename.substr(slash+1);
}
obj_stream << "mtllib " << mtl_basename << "\n";
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
}
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
mtl_stream << "newmtl " << style.name() << "\n";
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style)
{
std::string material_name = (settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
? style.original_name() : style.name());
IfcUtil::sanitate_material_name(material_name);
mtl_stream << "newmtl " << material_name << "\n";
if (style.hasDiffuse()) {
const double* diffuse = style.diffuse();
mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n";
@@ -66,39 +71,50 @@ void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
}
}
}
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
obj_stream << "g " << o->unique_id() << "\n";
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<real_t>* o)
{
const std::string name = (settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_GUIDS)
? o->guid() : (settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_NAMES)
? o->name() : o->unique_id()));
obj_stream << "g " << name << "\n";
obj_stream << "s 1" << "\n";
obj_stream << std::setprecision(std::numeric_limits<double>::digits10);
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
const IfcGeom::Representation::Triangulation<real_t>& mesh = o->geometry();
const int vcount = (int)mesh.verts().size() / 3;
for ( std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
const double x = *(it++);
const double y = *(it++);
const double z = *(it++);
for ( std::vector<real_t>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
const real_t x = *(it++) + (real_t)settings().offset[0];
const real_t y = *(it++) + (real_t)settings().offset[1];
const real_t z = *(it++) + (real_t)settings().offset[2];
obj_stream << "v " << x << " " << y << " " << z << "\n";
}
for ( std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
const double x = *(it++);
const double y = *(it++);
const double z = *(it++);
for ( std::vector<real_t>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
const real_t x = *(it++);
const real_t y = *(it++);
const real_t z = *(it++);
obj_stream << "vn " << x << " " << y << " " << z << "\n";
}
for (std::vector<real_t>::const_iterator it = mesh.uvs().begin(); it != mesh.uvs().end();) {
const real_t u = *it++;
const real_t v = *it++;
obj_stream << "vt " << u << " " << v << "\n";
}
int previous_material_id = -2;
std::vector<int>::const_iterator material_it = mesh.material_ids().begin();
const bool has_uvs = !mesh.uvs().empty();
for ( std::vector<int>::const_iterator it = mesh.faces().begin(); it != mesh.faces().end(); ) {
const int material_id = *(material_it++);
if (material_id != previous_material_id) {
const IfcGeom::Material& material = mesh.materials()[material_id];
const std::string material_name = material.name();
std::string material_name = (settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
? material.original_name() : material.name());
IfcUtil::sanitate_material_name(material_name);
obj_stream << "usemtl " << material_name << "\n";
if (materials.find(material_name) == materials.end()) {
writeMaterial(material);
@@ -110,7 +126,9 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>*
const int v1 = *(it++)+vcount_total;
const int v2 = *(it++)+vcount_total;
const int v3 = *(it++)+vcount_total;
obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << "\n";
obj_stream << "f " << v1 << "/" << (has_uvs ? boost::lexical_cast<std::string>(v1) : "") << "/" << v1 << " "
<< v2 << "/" << (has_uvs ? boost::lexical_cast<std::string>(v2) : "") << "/" << v2 << " "
<< v3 << "/" << (has_uvs ? boost::lexical_cast<std::string>(v3) : "") << "/" << v3 << "\n";
}
@@ -129,7 +147,9 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>*
if (material_id != previous_material_id) {
const IfcGeom::Material& material = mesh.materials()[material_id];
const std::string material_name = material.name();
std::string material_name = (settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
? material.original_name() : material.name());
IfcUtil::sanitate_material_name(material_name);
obj_stream << "usemtl " << material_name << "\n";
if (materials.find(material_name) == materials.end()) {
writeMaterial(material);
+6 -5
View File
@@ -26,6 +26,7 @@
#include "../ifcconvert/GeometrySerializer.h"
// http://people.sc.fsu.edu/~jburkardt/txt/obj_format.txt
class WaveFrontOBJSerializer : public GeometrySerializer {
private:
const std::string mtl_filename;
@@ -34,8 +35,8 @@ private:
unsigned int vcount_total;
std::set<std::string> materials;
public:
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename)
: GeometrySerializer()
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename, const IfcGeom::IteratorSettings &settings)
: GeometrySerializer(settings)
, obj_stream(obj_filename.c_str())
, mtl_filename(mtl_filename)
, mtl_stream(mtl_filename.c_str())
@@ -45,12 +46,12 @@ public:
bool ready();
void writeHeader();
void writeMaterial(const IfcGeom::Material& style);
void write(const IfcGeom::TriangulationElement<double>* o);
void write(const IfcGeom::BRepElement<double>* /*o*/) {}
void write(const IfcGeom::TriangulationElement<real_t>* o);
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
void finalize() {}
bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
void setFile(IfcParse::IfcFile*) {}
};
#endif
#endif
+15 -6
View File
@@ -21,7 +21,6 @@
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/version.hpp>
#include "XmlSerializer.h"
@@ -164,6 +163,16 @@ void descend(IfcProduct* product, ptree& tree) {
}
}
if (product->is(Type::IfcElement)) {
IfcElement* element = static_cast<IfcElement*>(product);
IfcOpeningElement::list::ptr openings = get_related<IfcElement, IfcRelVoidsElement, IfcOpeningElement>(
element, &IfcElement::HasOpenings, &IfcRelVoidsElement::RelatedOpeningElement);
for (IfcOpeningElement::list::it it = openings->begin(); it != openings->end(); ++it) {
descend(*it, child);
}
}
#ifdef USE_IFC2x3
IfcObjectDefinition::list::ptr structures = get_related
<IfcProduct, IfcRelDecomposes, IfcObjectDefinition>
@@ -246,16 +255,16 @@ void XmlSerializer::finalize() {
ptree root, header, decomposition, properties;
// Write the SPF header as XML nodes.
BOOST_FOREACH(const std::string& s, file->header().file_description().description()) {
foreach(const std::string& s, file->header().file_description().description()) {
header.add_child("file_description.description", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().author()) {
foreach(const std::string& s, file->header().file_name().author()) {
header.add_child("file_name.author", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_name().organization()) {
foreach(const std::string& s, file->header().file_name().organization()) {
header.add_child("file_name.organization", ptree(s));
}
BOOST_FOREACH(const std::string& s, file->header().file_schema().schema_identifiers()) {
foreach(const std::string& s, file->header().file_schema().schema_identifiers()) {
header.add_child("file_schema.schema_identifiers", ptree(s));
}
header.put("file_description.implementation_level", file->header().file_description().implementation_level());
@@ -288,4 +297,4 @@ void XmlSerializer::finalize() {
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
#endif
boost::property_tree::write_xml(xml_filename, root, std::locale(), settings);
}
}