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
+5 -1
View File
@@ -24,7 +24,7 @@ project (IfcOpenShell)
OPTION(UNICODE_SUPPORT "Build IfcOpenShell with Unicode support (requires ICU)." ON) OPTION(UNICODE_SUPPORT "Build IfcOpenShell with Unicode support (requires ICU)." ON)
OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON) OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF) OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
#TODO OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." OFF) OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." ON)
OPTION(USE_IFC4 "Use IFC 4 instead of IFC 2x3 (full rebuild recommended when switching this)" OFF) OPTION(USE_IFC4 "Use IFC 4 instead of IFC 2x3 (full rebuild recommended when switching this)" OFF)
OPTION(BUILD_IFCPYTHON "Build IfcPython." ON) OPTION(BUILD_IFCPYTHON "Build IfcPython." ON)
OPTION(BUILD_EXAMPLES "Build example applications." ON) OPTION(BUILD_EXAMPLES "Build example applications." ON)
@@ -397,6 +397,10 @@ if(NOT WIN32)
LINK_DIRECTORIES(${LINK_DIRECTORIES} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64) LINK_DIRECTORIES(${LINK_DIRECTORIES} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
endif() endif()
# IfcConvert
if (IFCCONVERT_DOUBLE_PRECISION)
add_definitions(-DIFCCONVERT_DOUBLE_PRECISION)
endif()
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp) file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h) file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES}) set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
+99 -45
View File
@@ -21,48 +21,63 @@
#include "ColladaSerializer.h" #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 <boost/lexical_cast.hpp>
#include <string> #include <string>
#include <cmath>
std::string collada_id(const std::string& s) { static void collada_id(std::string &s)
std::string id; {
id.reserve(s.size()); IfcUtil::sanitate_material_name(s);
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) { IfcUtil::escape_xml(s);
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;
} }
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); COLLADASW::FloatSource source(mSW);
source.setId(mesh_id + suffix); source.setId(mesh_id + suffix);
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX); source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
source.setAccessorStride((unsigned long)strlen(coords)); const size_t num_elems = strlen(coords);
source.setAccessorCount((unsigned long)floats.size() / 3); source.setAccessorStride(static_cast<unsigned long>(num_elems));
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) { 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.getParameterNameList().push_back(std::string(1, coords[i]));
} }
source.prepareToAppendValues(); 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.appendValues(*it);
} }
source.finish(); 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); openMesh(mesh_id);
// The normals vector can be empty for example when the WELD_VERTICES setting is used. // 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. // IfcOpenShell does not provide them with multiple face normals collapsed into a single vertex.
const bool has_normals = !normals.empty(); const bool has_normals = !normals.empty();
const bool has_uvs = !uvs.empty();
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions); addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions);
if (has_normals) { if (has_normals) {
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, 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); COLLADASW::VerticesElement vertices(mSW);
@@ -82,20 +97,28 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
current_material_id = *(material_it++); 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())) { if ((previous_material_id != current_material_id && num_triangles > 0) || (it == faces.end())) {
COLLADASW::Triangles triangles(mSW); COLLADASW::Triangles triangles(mSW);
triangles.setMaterial(materials[previous_material_id].name()); std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
triangles.setCount(num_triangles); ? 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; 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) { 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(); triangles.prepareToAppendValues();
for (std::vector<int>::const_iterator jt = index_range_start; jt != it; ++jt) { for (std::vector<int>::const_iterator jt = index_range_start; jt != it; ++jt) {
const int idx = *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); triangles.appendValues(idx, idx);
} else { } else {
triangles.appendValues(idx); 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) { for (linelist_t::const_iterator it = linelist.begin(); it != linelist.end(); ++it) {
COLLADASW::Lines lines(mSW); 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()); lines.setCount((unsigned long)it->second.size());
int offset = 0; 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.prepareToAppendValues();
lines.appendValues(it->second); lines.appendValues(it->second);
lines.finish(); lines.finish();
@@ -151,7 +177,10 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
closeLibrary(); 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) { if (!scene_opened) {
openVisualScene(scene_id); openVisualScene(scene_id);
scene_opened = true; 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. // 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. // Note that this placement is absolute, ie it is multiplied with all parent placements.
double matrix_array[4][4] = { double matrix_array[4][4] = {
{matrix[0], matrix[3], matrix[6], matrix[ 9]}, { (double)matrix[0], (double)matrix[3], (double)matrix[6], (double)matrix[ 9] },
{matrix[1], matrix[4], matrix[7], matrix[10]}, { (double)matrix[1], (double)matrix[4], (double)matrix[7], (double)matrix[10] },
{matrix[2], matrix[5], matrix[8], matrix[11]}, { (double)matrix[2], (double)matrix[5], (double)matrix[8], (double)matrix[11] },
{ 0, 0, 0, 1} { 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.start();
node.addMatrix(matrix_array); node.addMatrix(matrix_array);
COLLADASW::InstanceGeometry instanceGeometry(mSW); COLLADASW::InstanceGeometry instanceGeometry(mSW);
instanceGeometry.setUrl ("#" + geom_name); instanceGeometry.setUrl ("#" + geom_name);
for (std::vector<std::string>::const_iterator it = material_ids.begin(); it != material_ids.end(); ++it) { foreach(std::string material_name, material_ids) {
COLLADASW::InstanceMaterial material (*it, "#" + *it); /// @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.getBindMaterial().getInstanceMaterialList().push_back(material);
} }
instanceGeometry.add(); instanceGeometry.add();
@@ -193,8 +228,12 @@ void ColladaSerializer::ColladaExporter::ColladaScene::write() {
} }
} }
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material) { void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material)
openEffect(collada_id(material.name()) + "-fx"); {
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); COLLADASW::EffectProfile effect(mSW);
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT); effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
if (material.hasDiffuse()) { if (material.hasDiffuse()) {
@@ -237,10 +276,14 @@ bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeo
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() { void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
effects.close(); effects.close();
for (std::vector<IfcGeom::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) { foreach(const IfcGeom::Material& material, materials) {
const std::string& material_name = collada_id((*it).name()); 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); openMaterial(material_name);
addInstanceEffect("#" + material_name + "-fx"); addInstanceEffect("#" + material_name_unescaped + "-fx");
closeMaterial(); closeMaterial();
} }
closeLibrary(); closeLibrary();
@@ -256,16 +299,28 @@ void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_n
asset.add(); 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; std::vector<std::string> material_references;
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) { foreach(const IfcGeom::Material& material, mesh.materials()) {
const IfcGeom::Material& material = *it;
if (!materials.contains(material)) { if (!materials.contains(material)) {
materials.add(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() { void ColladaSerializer::ColladaExporter::endDocument() {
@@ -278,7 +333,7 @@ void ColladaSerializer::ColladaExporter::endDocument() {
continue; continue;
} }
geometries_written.insert(it->representation_id); 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(); geometries.close();
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) { for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
@@ -297,9 +352,8 @@ void ColladaSerializer::writeHeader() {
exporter.startDocument(unit_name, unit_magnitude); exporter.startDocument(unit_name, unit_magnitude);
} }
void ColladaSerializer::write(const IfcGeom::TriangulationElement<double>* o) { void ColladaSerializer::write(const IfcGeom::TriangulationElement<real_t>* o) {
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry(); exporter.write(o);
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::finalize() { void ColladaSerializer::finalize() {
+53 -36
View File
@@ -27,17 +27,10 @@
#pragma warning(disable : 4201 4512) #pragma warning(disable : 4201 4512)
#endif #endif
#include <COLLADASWStreamWriter.h> #include <COLLADASWStreamWriter.h>
#include <COLLADASWPrimitves.h>
#include <COLLADASWLibraryGeometries.h> #include <COLLADASWLibraryGeometries.h>
#include <COLLADASWSource.h>
#include <COLLADASWScene.h>
#include <COLLADASWNode.h>
#include <COLLADASWInstanceGeometry.h>
#include <COLLADASWLibraryVisualScenes.h> #include <COLLADASWLibraryVisualScenes.h>
#include <COLLADASWLibraryEffects.h> #include <COLLADASWLibraryEffects.h>
#include <COLLADASWLibraryMaterials.h> #include <COLLADASWLibraryMaterials.h>
#include <COLLADASWBaseInputElement.h>
#include <COLLADASWAsset.h>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
#endif #endif
@@ -58,12 +51,19 @@ private:
ColladaGeometries(const ColladaGeometries&); //N/A ColladaGeometries(const ColladaGeometries&); //N/A
ColladaGeometries& operator =(const ColladaGeometries&); //N/A ColladaGeometries& operator =(const ColladaGeometries&); //N/A
public: public:
explicit ColladaGeometries(COLLADASW::StreamWriter& stream) explicit ColladaGeometries(COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer)
: COLLADASW::LibraryGeometries(&stream) : 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 addFloatSource(const std::string& mesh_id, const std::string& suffix,
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); 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(); void close();
ColladaSerializer *serializer;
}; };
class ColladaScene : public COLLADASW::LibraryVisualScenes class ColladaScene : public COLLADASW::LibraryVisualScenes
{ {
@@ -74,13 +74,16 @@ private:
const std::string scene_id; const std::string scene_id;
bool scene_opened; bool scene_opened;
public: public:
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream) ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer)
: COLLADASW::LibraryVisualScenes(&stream) : COLLADASW::LibraryVisualScenes(&stream)
, scene_id(scene_id) , 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(); void write();
ColladaSerializer *serializer;
}; };
class ColladaMaterials : public COLLADASW::LibraryMaterials class ColladaMaterials : public COLLADASW::LibraryMaterials
{ {
@@ -97,32 +100,37 @@ private:
{} {}
void write(const IfcGeom::Material& material); void write(const IfcGeom::Material& material);
void close(); void close();
ColladaSerializer *serializer;
}; };
std::vector<IfcGeom::Material> materials; std::vector<IfcGeom::Material> materials;
ColladaEffects effects;
public: public:
explicit ColladaMaterials(COLLADASW::StreamWriter& stream) explicit ColladaMaterials(COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer)
: COLLADASW::LibraryMaterials(&stream) : COLLADASW::LibraryMaterials(&stream)
, effects(stream) , effects(stream)
, serializer(_serializer)
{} {}
void add(const IfcGeom::Material& material); void add(const IfcGeom::Material& material);
bool contains(const IfcGeom::Material& material); bool contains(const IfcGeom::Material& material);
void write(); void write();
ColladaSerializer *serializer;
ColladaEffects effects;
}; };
class DeferredObject { class DeferredObject {
public: public:
std::string unique_id, representation_id, type; std::string unique_id, representation_id, type;
std::vector<double> matrix; std::vector<real_t> matrix;
std::vector<double> vertices; std::vector<real_t> vertices;
std::vector<double> normals; std::vector<real_t> normals;
std::vector<int> faces; std::vector<int> faces;
std::vector<int> edges; std::vector<int> edges;
std::vector<int> material_ids; std::vector<int> material_ids;
std::vector<IfcGeom::Material> materials; std::vector<IfcGeom::Material> materials;
std::vector<std::string> material_references; 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, std::vector<real_t> uvs;
const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, DeferredObject(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector<real_t>& matrix,
const std::vector<IfcGeom::Material>& materials, const std::vector<std::string>& material_references) 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) : unique_id(unique_id)
, representation_id(representation_id) , representation_id(representation_id)
, type(type) , type(type)
@@ -134,39 +142,48 @@ private:
, material_ids(material_ids) , material_ids(material_ids)
, materials(materials) , materials(materials)
, material_references(material_references) , material_references(material_references)
, uvs(uvs)
{} {}
}; };
COLLADABU::NativeString filename; COLLADABU::NativeString filename;
COLLADASW::StreamWriter stream; COLLADASW::StreamWriter stream;
ColladaGeometries geometries;
ColladaScene scene; ColladaScene scene;
ColladaMaterials materials;
public: public:
ColladaExporter(const std::string& scene_name, const std::string& fn) ColladaExporter(const std::string& scene_name, const std::string& fn, ColladaSerializer *_serializer)
: filename(fn.c_str()) : filename(fn)
, stream(filename) , stream(filename, sizeof(real_t) == sizeof(double)) // utilise Collada stream's double precision feature
, geometries(stream) , geometries(stream, _serializer)
, scene(scene_name, stream) , scene(scene_name, stream, _serializer)
, materials(stream) , materials(stream, _serializer)
{} , serializer(_serializer)
{
}
ColladaMaterials materials;
ColladaSerializer *serializer;
ColladaGeometries geometries;
std::vector<DeferredObject> deferreds; std::vector<DeferredObject> deferreds;
virtual ~ColladaExporter() {} virtual ~ColladaExporter() {}
void startDocument(const std::string& unit_name, float unit_magnitude); 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(); void endDocument();
}; };
ColladaExporter exporter; ColladaExporter exporter;
std::string unit_name; std::string unit_name;
float unit_magnitude; float unit_magnitude;
public: public:
ColladaSerializer(const std::string& dae_filename) ColladaSerializer(const std::string& dae_filename, const IfcGeom::IteratorSettings &settings)
: GeometrySerializer() : GeometrySerializer(settings)
, exporter("IfcOpenShell", dae_filename) , exporter("IfcOpenShell", dae_filename, this)
{} {
exporter.serializer = this;
exporter.materials.serializer = this;
exporter.materials.effects.serializer = this;
exporter.geometries.serializer = this;
}
bool ready(); bool ready();
void writeHeader(); void writeHeader();
void write(const IfcGeom::TriangulationElement<double>* o); void write(const IfcGeom::TriangulationElement<real_t>* o);
void write(const IfcGeom::BRepElement<double>* /*o*/) {} void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
void finalize(); void finalize();
bool isTesselated() const { return true; } bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& name, float magnitude) { void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
+15 -2
View File
@@ -20,17 +20,30 @@
#ifndef GEOMETRYSERIALIZER_H #ifndef GEOMETRYSERIALIZER_H
#define GEOMETRYSERIALIZER_H #define GEOMETRYSERIALIZER_H
#ifdef IFCCONVERT_DOUBLE_PRECISION
typedef double real_t;
#else
typedef float real_t;
#endif
#include "../ifcconvert/Serializer.h" #include "../ifcconvert/Serializer.h"
#include "../ifcgeom/IfcGeomIterator.h" #include "../ifcgeom/IfcGeomIterator.h"
class GeometrySerializer : public Serializer { class GeometrySerializer : public Serializer {
public: public:
GeometrySerializer(const IfcGeom::IteratorSettings &settings) : settings_(settings) {}
virtual ~GeometrySerializer() {} virtual ~GeometrySerializer() {}
virtual bool isTesselated() const = 0; virtual bool isTesselated() const = 0;
virtual void write(const IfcGeom::TriangulationElement<double>* o) = 0; virtual void write(const IfcGeom::TriangulationElement<real_t>* o) = 0;
virtual void write(const IfcGeom::BRepElement<double>* o) = 0; virtual void write(const IfcGeom::BRepElement<real_t>* o) = 0;
virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 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
+237 -105
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/ColladaSerializer.h"
#include "../ifcconvert/IgesSerializer.h" #include "../ifcconvert/IgesSerializer.h"
#include "../ifcconvert/StepSerializer.h" #include "../ifcconvert/StepSerializer.h"
@@ -43,35 +33,58 @@
#include "../ifcconvert/XmlSerializer.h" #include "../ifcconvert/XmlSerializer.h"
#include "../ifcconvert/SvgSerializer.h" #include "../ifcconvert/SvgSerializer.h"
#include "../ifcgeom/IfcGeomIterator.h"
#include <IGESControl_Controller.hxx> #include <IGESControl_Controller.hxx>
#include <Standard_Version.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 #if USE_VLD
#include <vld.h> #include <vld.h>
#endif #endif
static std::string DEFAULT_EXTENSION = "obj"; const std::string DEFAULT_EXTENSION = "obj";
const std::string TEMP_FILE_EXTENSION = ".tmp";
void printVersion() { void print_version()
std::cerr << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << std::endl; {
/// @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) { void print_usage(bool suggest_help = true)
printVersion(); {
std::cerr << "Usage: IfcConvert [options] <input.ifc> [<output>]" << std::endl std::cerr << "Usage: IfcConvert [options] <input.ifc> [<output>]" << "\n"
<< std::endl << "\n"
<< "Converts the geometry in an IFC file into one of the following formats:" << std::endl << "Converts the geometry in an IFC file into one of the following formats:" << "\n"
<< " .obj WaveFront OBJ (a .mtl file is also created)" << std::endl; << " .obj WaveFront OBJ (a .mtl file is also created)" << "\n"
#ifdef WITH_OPENCOLLADA #ifdef WITH_OPENCOLLADA
std::cerr << " .dae Collada Digital Asset Exchange" << std::endl; << " .dae Collada Digital Assets Exchange" << "\n"
#endif #endif
std::cerr << " .stp STEP Standard for the Exchange of Product Data" << std::endl << " .stp STEP Standard for the Exchange of Product Data" << "\n"
<< " .igs IGES Initial Graphics Exchange Specification" << std::endl << " .igs IGES Initial Graphics Exchange Specification" << "\n"
<< " .xml XML Property definitions and decomposition tree" << std::endl << " .xml XML Property definitions and decomposition tree" << "\n"
<< " .svg SVG Scalable Vector Graphics (2d floor plan)" << std::endl << " .svg SVG Scalable Vector Graphics (2D floor plan)" << "\n"
<< std::endl << "\n"
<< "Command line options" << std::endl << generic_options << std::endl << "If no output filename given, <input>." + DEFAULT_EXTENSION + " will be used as the output file.\n";
<< "Advanced options" << std::endl << geom_options << std::endl; 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) { 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; static std::stringstream log_stream;
void write_log(); void write_log();
int main(int argc, char** argv) { 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() generic_options.add_options()
("help", "display usage information") ("help,h", "display usage information")
("version", "display version 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; boost::program_options::options_description fileio_options;
fileio_options.add_options() fileio_options.add_options()
("input-file", boost::program_options::value<std::string>(), "input IFC file") ("input-file", boost::program_options::value<std::string>(), "input IFC file")
("output-file", boost::program_options::value<std::string>(), "output geometry file"); ("output-file", boost::program_options::value<std::string>(), "output geometry file");
std::string bounds; std::vector<std::string> entity_vector, names;
std::vector<std::string> entity_vector; double deflection_tolerance;
boost::program_options::options_description geom_options; boost::program_options::options_description geom_options("Geometry options");
geom_options.add_options() geom_options.add_options()
("plan", ("plan",
"Specifies whether to include curves in the output result. Typically " "Specifies whether to include curves in the output result. Typically "
@@ -142,20 +172,51 @@ int main(int argc, char** argv) {
("disable-opening-subtractions", ("disable-opening-subtractions",
"Specifies whether to disable the boolean subtraction of " "Specifies whether to disable the boolean subtraction of "
"IfcOpeningElement Representations from their RelatingElements.") "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", ("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", ("exclude",
"Specifies that the entities listed after --entities are to be excluded") "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(), ("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 " "A list of entities that should be included in or excluded from the "
"geometrical output, depending on whether --ignore or --include is " "geometrical output, depending on whether --exclude or --include is specified. "
"specified. Defaults to IfcOpeningElement and IfcSpace to be excluded."); "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; 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; boost::program_options::positional_options_description positional_options;
positional_options.add("input-file", 1); positional_options.add("input-file", 1);
@@ -167,21 +228,30 @@ int main(int argc, char** argv) {
options(cmdline_options).positional(positional_options).run(), vmap); options(cmdline_options).positional(positional_options).run(), vmap);
} catch (const boost::program_options::unknown_option& e) { } catch (const boost::program_options::unknown_option& e) {
std::cerr << "[Error] Unknown option '" << e.get_option_name() << "'" << std::endl << std::endl; 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 (...) {
// Catch other errors such as invalid command line syntax // Catch other errors such as invalid command line syntax
print_usage();
return 1;
} }
boost::program_options::notify(vmap); boost::program_options::notify(vmap);
if (vmap.count("version")) { print_version();
printVersion();
return 0; if (vmap.count("version")) {
} else if (vmap.count("help") || !vmap.count("input-file")) { return 0;
printUsage(generic_options, geom_options); } else if (vmap.count("help")) {
return vmap.count("help") ? 0 : 1; 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")) { } else if (vmap.count("include") && vmap.count("exclude")) {
std::cerr << "[Error] --include and --ignore can not be specified together" << std::endl; std::cerr << "[Error] --include and --exclude can not be specified together" << std::endl;
printUsage(generic_options, geom_options); print_options(geom_options);
return 1; return 1;
} }
@@ -197,6 +267,13 @@ int main(int argc, char** argv) {
bool include_entities = vmap.count("include") != 0; bool include_entities = vmap.count("include") != 0;
const bool include_plan = vmap.count("plan") != 0; const bool include_plan = vmap.count("plan") != 0;
const bool include_model = vmap.count("model") != 0 || (!include_plan); 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; boost::optional<int> bounding_width, bounding_height;
if (vmap.count("bounds") == 1) { if (vmap.count("bounds") == 1) {
int w, h; int w, h;
@@ -205,19 +282,20 @@ int main(int argc, char** argv) {
bounding_height = h; bounding_height = h;
} else { } else {
std::cerr << "[Error] Invalid use of --bounds" << std::endl; std::cerr << "[Error] Invalid use of --bounds" << std::endl;
printUsage(generic_options, geom_options); print_options(serializer_options);
return 1; return 1;
} }
} }
// Gets the set ifc types to be ignored from the command line. // Gets the set ifc types to be ignored from the command line.
std::set<std::string> entities; std::set<std::string> entities(entity_vector.begin(), entity_vector.end());
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));
}
const std::string input_filename = vmap["input-file"].as<std::string>(); 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 // If no output filename is specified a Wavefront OBJ file will be output
// to maintain backwards compatibility with the obsolete IfcObj executable. // to maintain backwards compatibility with the obsolete IfcObj executable.
const std::string output_filename = vmap.count("output-file") == 1 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); : change_extension(input_filename, DEFAULT_EXTENSION);
if (output_filename.size() < 5) { 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; 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); std::string output_extension = output_filename.substr(output_filename.size()-4);
boost::to_lower(output_extension); boost::to_lower(output_extension);
// If no entities are specified these are the defaults to skip from output // If no entity or names filters are specified these are the defaults to skip from output
if (entity_vector.empty()) { if (entities.empty() && names.empty()) {
entities.insert("IfcSpace");
if (output_extension == ".svg") { if (output_extension == ".svg") {
entities.insert("ifcspace");
include_entities = true; include_entities = true;
} else { } else {
entities.insert("ifcopeningelement"); entities.insert("IfcOpeningElement");
entities.insert("ifcspace");
} }
} }
@@ -249,13 +338,14 @@ int main(int argc, char** argv) {
if (output_extension == ".xml") { if (output_extension == ".xml") {
int exit_code = 1; int exit_code = 1;
try { try {
XmlSerializer s(output_filename); XmlSerializer s(output_temp_filename);
IfcParse::IfcFile f; IfcParse::IfcFile f;
if (!f.Init(input_filename)) { 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 { } else {
s.setFile(&f); s.setFile(&f);
s.finalize(); s.finalize();
rename_file(output_temp_filename, output_filename);
exit_code = 0; exit_code = 0;
} }
} catch (...) {} } catch (...) {}
@@ -264,7 +354,7 @@ int main(int argc, char** argv) {
} }
IfcGeom::IteratorSettings settings; 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::APPLY_DEFAULT_MATERIALS, true);
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords); settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords);
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, weld_vertices); 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::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions);
settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan); settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan);
settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model); 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; GeometrySerializer* serializer;
if (output_extension == ".obj") { 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) { if (!use_world_coords) {
Logger::Message(Logger::LOG_NOTICE, "Using world coords when writing WaveFront OBJ files"); Logger::Message(Logger::LOG_NOTICE, "Using world coords when writing WaveFront OBJ files");
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true); 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 #ifdef WITH_OPENCOLLADA
} else if (output_extension == ".dae") { } else if (output_extension == ".dae") {
serializer = new ColladaSerializer(output_filename); serializer = new ColladaSerializer(output_temp_filename, settings);
#endif #endif
} else if (output_extension == ".stp") { } else if (output_extension == ".stp") {
serializer = new StepSerializer(output_filename); serializer = new StepSerializer(output_temp_filename, settings);
} else if (output_extension == ".igs") { } else if (output_extension == ".igs") {
// Not sure why this is needed, but it is. IGESControl_Controller::Init(); // work around Open Cascade bug
// See: http://tracker.dev.opencascade.org/view.php?id=23679 serializer = new IgesSerializer(output_temp_filename, settings);
IGESControl_Controller::Init();
serializer = new IgesSerializer(output_filename);
} else if (output_extension == ".svg") { } else if (output_extension == ".svg") {
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
serializer = new SvgSerializer(output_filename); serializer = new SvgSerializer(output_temp_filename, settings);
if (bounding_width && bounding_height) { if (bounding_width && bounding_height) {
((SvgSerializer*) serializer)->setBoundingRectangle( static_cast<SvgSerializer*>(serializer)->setBoundingRectangle(*bounding_width, *bounding_height);
static_cast<double>(*bounding_width),
static_cast<double>(*bounding_height)
);
} }
} else { } else {
Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension"); Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension '" + output_extension + "'");
write_log(); write_log();
printUsage(generic_options, geom_options); print_usage();
return 1; return 1;
} }
if (!serializer->isTesselated()) { const bool is_tesselated = serializer->isTesselated(); // isTesselated() doesn't change at run-time
if (!is_tesselated) {
if (weld_vertices) { 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 { try {
if (include_entities) { if (include_entities) {
context_iterator.includeEntities(entities); context_iterator.includeEntities(entities);
context_iterator.include_entity_names(names);
} else { } else {
context_iterator.excludeEntities(entities); context_iterator.excludeEntities(entities);
context_iterator.exclude_entity_names(names);
} }
} catch (const IfcParse::IfcException& e) { } catch (const IfcParse::IfcException& e) {
std::cout << "[Error] " << e.what() << std::endl; std::cout << "[Error] " << e.what() << std::endl;
@@ -333,7 +437,7 @@ int main(int argc, char** argv) {
} }
if (!serializer->ready()) { 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(); write_log();
return 1; return 1;
} }
@@ -342,26 +446,25 @@ int main(int argc, char** argv) {
time(&start); time(&start);
if (!context_iterator.initialize()) { 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(); write_log();
return 1; return 1;
} }
serializer->setFile(context_iterator.getFile()); serializer->setFile(context_iterator.getFile());
if (convert_back_units) { 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 { } else {
serializer->setUnitNameAndMagnitude("METER", 1.0f); serializer->setUnitNameAndMagnitude("METER", 1.0f);
} }
serializer->writeHeader(); serializer->writeHeader();
std::set<std::string> materials;
int old_progress = -1; int old_progress = -1;
Logger::Status("Creating geometry..."); Logger::Status("Creating geometry...");
std::vector<IfcGeom::Element<real_t>* > geometries;
// The functions IfcGeom::Iterator::get() and IfcGeom::Iterator::next() // The functions IfcGeom::Iterator::get() and IfcGeom::Iterator::next()
// wrap an iterator of all geometrical products in the Ifc file. // wrap an iterator of all geometrical products in the Ifc file.
// IfcGeom::Iterator::get() returns an IfcGeom::TriangulationElement or // 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 // true return value guarantees that a successfully processed product is
// available. // available.
do { do {
const IfcGeom::Element<double>* geom_object = context_iterator.get(); 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());
if (serializer->isTesselated()) { Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(geometries.size()) +
serializer->write(static_cast<const IfcGeom::TriangulationElement<double>*>(geom_object)); " objects) ");
} else {
serializer->write(static_cast<const IfcGeom::BRepElement<double>*>(geom_object));
}
const int progress = context_iterator.progress() / 2; if (center_model) {
if (old_progress!= progress) Logger::ProgressBar(progress); double* offset = serializer->settings().offset;
old_progress = progress; 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, ...);
}
} while (context_iterator.next()); 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(); serializer->finalize();
Logger::Status("\rDone serializing geometry ");
delete serializer; 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(); write_log();
time(&end); time(&end);
int dif = (int) difftime (end,start); int seconds = (int)difftime(end, start);
printf ("\nConversion took %d seconds\n", dif ); 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; return 0;
} }
@@ -404,7 +537,6 @@ int main(int argc, char** argv) {
void write_log() { void write_log() {
std::string log = log_stream.str(); std::string log = log_stream.str();
if (!log.empty()) { if (!log.empty()) {
std::cerr << std::endl << "Log:" << std::endl; std::cerr << "\n" << "Log:\n" << log << std::endl;
std::cerr << log << std::endl;
} }
} }
+6 -6
View File
@@ -20,20 +20,20 @@
#ifndef IGESSERIALIZER_H #ifndef IGESSERIALIZER_H
#define IGESSERIALIZER_H #define IGESSERIALIZER_H
#include "OpenCascadeBasedSerializer.h"
#include <IGESControl_Writer.hxx> #include <IGESControl_Writer.hxx>
#include <Interface_Static.hxx> #include <Interface_Static.hxx>
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
class IgesSerializer : public OpenCascadeBasedSerializer class IgesSerializer : public OpenCascadeBasedSerializer
{ {
private: private:
IGESControl_Writer writer; IGESControl_Writer writer;
public: public:
explicit IgesSerializer(const std::string& out_filename) /// @note IGESControl_Controller::Init() must be called prior to instantiating IgesSerializer.
: OpenCascadeBasedSerializer(out_filename) /// 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() {} virtual ~IgesSerializer() {}
void writeShape(const TopoDS_Shape& shape) { void writeShape(const TopoDS_Shape& shape) {
@@ -36,14 +36,14 @@ bool OpenCascadeBasedSerializer::ready() {
return succeeded; 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) { for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
gp_GTrsf gtrsf = it->Placement(); gp_GTrsf gtrsf = it->Placement();
const gp_Trsf& o_trsf = o->transformation().data(); const gp_Trsf& o_trsf = o->transformation().data();
gtrsf.PreMultiply(o_trsf); gtrsf.PreMultiply(o_trsf);
if (o->geometry().settings().convert_back_units()) { if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) {
gp_Trsf scale; gp_Trsf scale;
scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude()); scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude());
gtrsf.PreMultiply(scale); gtrsf.PreMultiply(scale);
+4 -4
View File
@@ -31,16 +31,16 @@ protected:
const std::string out_filename; const std::string out_filename;
const char* getSymbolForUnitMagnitude(float mag); const char* getSymbolForUnitMagnitude(float mag);
public: public:
explicit OpenCascadeBasedSerializer(const std::string& out_filename) explicit OpenCascadeBasedSerializer(const std::string& out_filename, const IfcGeom::IteratorSettings &settings)
: GeometrySerializer() : GeometrySerializer(settings)
, out_filename(out_filename) , out_filename(out_filename)
{} {}
virtual ~OpenCascadeBasedSerializer() {} virtual ~OpenCascadeBasedSerializer() {}
void writeHeader() {} void writeHeader() {}
bool ready(); bool ready();
virtual void writeShape(const TopoDS_Shape& shape) = 0; virtual void writeShape(const TopoDS_Shape& shape) = 0;
void write(const IfcGeom::TriangulationElement<double>* /*o*/) {} void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
void write(const IfcGeom::BRepElement<double>* o); void write(const IfcGeom::BRepElement<real_t>* o);
bool isTesselated() const { return false; } bool isTesselated() const { return false; }
void setFile(IfcParse::IfcFile*) {} void setFile(IfcParse::IfcFile*) {}
}; };
+2 -2
View File
@@ -32,8 +32,8 @@ class StepSerializer : public OpenCascadeBasedSerializer
private: private:
STEPControl_Writer writer; STEPControl_Writer writer;
public: public:
explicit StepSerializer(const std::string& out_filename) explicit StepSerializer(const std::string& out_filename, const IfcGeom::IteratorSettings &settings)
: OpenCascadeBasedSerializer(out_filename) : OpenCascadeBasedSerializer(out_filename, settings)
{} {}
virtual ~StepSerializer() {} virtual ~StepSerializer() {}
void writeShape(const TopoDS_Shape& shape) { void writeShape(const TopoDS_Shape& shape) {
+8 -3
View File
@@ -168,7 +168,8 @@ SvgSerializer::path_object& SvgSerializer::start_path(IfcSchema::IfcBuildingStor
return p; return p;
} }
void SvgSerializer::write(const IfcGeom::BRepElement<double>* o) { void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
{
IfcSchema::IfcBuildingStorey* storey = 0; IfcSchema::IfcBuildingStorey* storey = 0;
IfcSchema::IfcObjectDefinition* obdef = static_cast<IfcSchema::IfcObjectDefinition*>(file->entityById(o->id())); 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"; 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; std::ostringstream oss;
const std::string type = "product"; 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(); return oss.str();
} }
+23 -26
View File
@@ -22,15 +22,13 @@
#ifndef SVGSERIALIZER_H #ifndef SVGSERIALIZER_H
#define SVGSERIALIZER_H #define SVGSERIALIZER_H
#include "../ifcconvert/GeometrySerializer.h"
#include "../ifcconvert/util.h"
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <limits> #include <limits>
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcconvert/GeometrySerializer.h"
#include "../ifcconvert/util.h"
class SvgSerializer : public GeometrySerializer { class SvgSerializer : public GeometrySerializer {
public: public:
typedef std::pair<std::string, std::vector<util::string_buffer> > path_object; 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; std::vector< boost::shared_ptr<util::string_buffer::float_item> > radii;
IfcParse::IfcFile* file; IfcParse::IfcFile* file;
public: public:
explicit SvgSerializer(const std::string& out_filename) SvgSerializer(const std::string& out_filename, const IfcGeom::IteratorSettings &settings)
: GeometrySerializer() : GeometrySerializer(settings)
, svg_file(out_filename.c_str()) , svg_file(out_filename.c_str())
, xmin(+std::numeric_limits<double>::infinity()) , xmin(+std::numeric_limits<double>::infinity())
, xmax(-std::numeric_limits<double>::infinity()) , xmax(-std::numeric_limits<double>::infinity())
@@ -55,25 +53,24 @@ public:
, rescale(false) , rescale(false)
, file(0) , file(0)
{} {}
virtual void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); } 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); } 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); } 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; } 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() {} void writeHeader();
virtual void writeHeader(); bool ready();
virtual bool ready(); void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
virtual void write(const IfcGeom::TriangulationElement<double>* /*o*/) {} void write(const IfcGeom::BRepElement<real_t>* o);
virtual void write(const IfcGeom::BRepElement<double>* o); void write(path_object& p, const TopoDS_Wire& wire);
virtual void write(path_object& p, const TopoDS_Wire& wire); path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id);
virtual path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id); bool isTesselated() const { return false; }
virtual bool isTesselated() const { return false; } void finalize();
virtual void finalize(); void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
virtual void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} void setFile(IfcParse::IfcFile* f) { file = f; }
virtual void setFile(IfcParse::IfcFile* f) { file = f; } void setBoundingRectangle(double width, double height);
virtual void setBoundingRectangle(double width, double height); void setSectionHeight(double h) { section_height = h; }
virtual void setSectionHeight(double h) { section_height = h; } std::string nameElement(const IfcGeom::Element<real_t>* elem);
virtual std::string nameElement(const IfcGeom::Element<double>* elem); std::string nameElement(const IfcSchema::IfcProduct* elem);
virtual std::string nameElement(const IfcSchema::IfcProduct* elem);
}; };
#endif #endif
+41 -21
View File
@@ -17,12 +17,13 @@
* * * *
********************************************************************************/ ********************************************************************************/
#include <limits>
#include <iomanip> #include "WavefrontObjSerializer.h"
#include "../ifcgeom/IfcGeomRenderStyles.h" #include "../ifcgeom/IfcGeomRenderStyles.h"
#include "WavefrontObjSerializer.h" #include <boost/lexical_cast.hpp>
#include <iomanip>
bool WaveFrontOBJSerializer::ready() { bool WaveFrontOBJSerializer::ready() {
return obj_stream.is_open() && mtl_stream.is_open(); return obj_stream.is_open() && mtl_stream.is_open();
@@ -44,8 +45,12 @@ void WaveFrontOBJSerializer::writeHeader() {
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) { void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style)
mtl_stream << "newmtl " << style.name() << "\n"; {
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()) { if (style.hasDiffuse()) {
const double* diffuse = style.diffuse(); const double* diffuse = style.diffuse();
mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n"; 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 << "s 1" << "\n";
obj_stream << std::setprecision(std::numeric_limits<double>::digits10); const IfcGeom::Representation::Triangulation<real_t>& mesh = o->geometry();
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
const int vcount = (int)mesh.verts().size() / 3; const int vcount = (int)mesh.verts().size() / 3;
for ( std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) { for ( std::vector<real_t>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
const double x = *(it++); const real_t x = *(it++) + (real_t)settings().offset[0];
const double y = *(it++); const real_t y = *(it++) + (real_t)settings().offset[1];
const double z = *(it++); const real_t z = *(it++) + (real_t)settings().offset[2];
obj_stream << "v " << x << " " << y << " " << z << "\n"; obj_stream << "v " << x << " " << y << " " << z << "\n";
} }
for ( std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) { for ( std::vector<real_t>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
const double x = *(it++); const real_t x = *(it++);
const double y = *(it++); const real_t y = *(it++);
const double z = *(it++); const real_t z = *(it++);
obj_stream << "vn " << x << " " << y << " " << z << "\n"; 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; int previous_material_id = -2;
std::vector<int>::const_iterator material_it = mesh.material_ids().begin(); 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(); ) { for ( std::vector<int>::const_iterator it = mesh.faces().begin(); it != mesh.faces().end(); ) {
const int material_id = *(material_it++); const int material_id = *(material_it++);
if (material_id != previous_material_id) { if (material_id != previous_material_id) {
const IfcGeom::Material& material = mesh.materials()[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"; obj_stream << "usemtl " << material_name << "\n";
if (materials.find(material_name) == materials.end()) { if (materials.find(material_name) == materials.end()) {
writeMaterial(material); writeMaterial(material);
@@ -110,7 +126,9 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>*
const int v1 = *(it++)+vcount_total; const int v1 = *(it++)+vcount_total;
const int v2 = *(it++)+vcount_total; const int v2 = *(it++)+vcount_total;
const int v3 = *(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) { if (material_id != previous_material_id) {
const IfcGeom::Material& material = mesh.materials()[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"; obj_stream << "usemtl " << material_name << "\n";
if (materials.find(material_name) == materials.end()) { if (materials.find(material_name) == materials.end()) {
writeMaterial(material); writeMaterial(material);
+5 -4
View File
@@ -26,6 +26,7 @@
#include "../ifcconvert/GeometrySerializer.h" #include "../ifcconvert/GeometrySerializer.h"
// http://people.sc.fsu.edu/~jburkardt/txt/obj_format.txt
class WaveFrontOBJSerializer : public GeometrySerializer { class WaveFrontOBJSerializer : public GeometrySerializer {
private: private:
const std::string mtl_filename; const std::string mtl_filename;
@@ -34,8 +35,8 @@ private:
unsigned int vcount_total; unsigned int vcount_total;
std::set<std::string> materials; std::set<std::string> materials;
public: public:
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename) WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename, const IfcGeom::IteratorSettings &settings)
: GeometrySerializer() : GeometrySerializer(settings)
, obj_stream(obj_filename.c_str()) , obj_stream(obj_filename.c_str())
, mtl_filename(mtl_filename) , mtl_filename(mtl_filename)
, mtl_stream(mtl_filename.c_str()) , mtl_stream(mtl_filename.c_str())
@@ -45,8 +46,8 @@ public:
bool ready(); bool ready();
void writeHeader(); void writeHeader();
void writeMaterial(const IfcGeom::Material& style); void writeMaterial(const IfcGeom::Material& style);
void write(const IfcGeom::TriangulationElement<double>* o); void write(const IfcGeom::TriangulationElement<real_t>* o);
void write(const IfcGeom::BRepElement<double>* /*o*/) {} void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
void finalize() {} void finalize() {}
bool isTesselated() const { return true; } bool isTesselated() const { return true; }
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
+14 -5
View File
@@ -21,7 +21,6 @@
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp> #include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/version.hpp> #include <boost/version.hpp>
#include "XmlSerializer.h" #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 #ifdef USE_IFC2x3
IfcObjectDefinition::list::ptr structures = get_related IfcObjectDefinition::list::ptr structures = get_related
<IfcProduct, IfcRelDecomposes, IfcObjectDefinition> <IfcProduct, IfcRelDecomposes, IfcObjectDefinition>
@@ -246,16 +255,16 @@ void XmlSerializer::finalize() {
ptree root, header, decomposition, properties; ptree root, header, decomposition, properties;
// Write the SPF header as XML nodes. // 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)); 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)); 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)); 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.add_child("file_schema.schema_identifiers", ptree(s));
} }
header.put("file_description.implementation_level", file->header().file_description().implementation_level()); header.put("file_description.implementation_level", file->header().file_description().implementation_level());
+1 -1
View File
@@ -44,7 +44,7 @@ namespace IfcGeom {
for(int i = 1; i < 5; ++i) { for(int i = 1; i < 5; ++i) {
for (int j = 1; j < 4; ++j) { for (int j = 1; j < 4; ++j) {
const double trsf_value = trsf.Value(j,i); const double trsf_value = trsf.Value(j,i);
const double matrix_value = i == 4 && settings.convert_back_units() const double matrix_value = i == 4 && settings.get(IteratorSettings::CONVERT_BACK_UNITS)
? trsf_value / settings.unit_magnitude() ? trsf_value / settings.unit_magnitude()
: trsf_value; : trsf_value;
_data.push_back(static_cast<P>(matrix_value)); _data.push_back(static_cast<P>(matrix_value));
+4 -4
View File
@@ -1116,11 +1116,11 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_pro
const std::string product_type = IfcSchema::Type::ToString(product->type()); const std::string product_type = IfcSchema::Type::ToString(product->type());
ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type); ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type);
if ( !settings.disable_opening_subtractions() && openings && openings->size() ) { if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) {
IfcGeom::IfcRepresentationShapeItems opened_shapes; IfcGeom::IfcRepresentationShapeItems opened_shapes;
try { try {
#if OCC_VERSION_HEX < 0x60900 #if OCC_VERSION_HEX < 0x60900
const bool faster_booleans = settings.faster_booleans(); const bool faster_booleans = settings.get(IteratorSettings::FASTER_BOOLEANS);
#else #else
const bool faster_booleans = true; const bool faster_booleans = true;
#endif #endif
@@ -1136,14 +1136,14 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_pro
} catch(...) { } catch(...) {
Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",product->entity); Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",product->entity);
} }
if ( settings.use_world_coords() ) { if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) { for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
it->prepend(trsf); it->prepend(trsf);
} }
trsf = gp_Trsf(); trsf = gp_Trsf();
} }
shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), opened_shapes); shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), opened_shapes);
} else if ( settings.use_world_coords() ) { } else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++ it ) { for ( IfcGeom::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
it->prepend(trsf); it->prepend(trsf);
} }
+86 -32
View File
@@ -86,6 +86,9 @@ namespace IfcGeom {
template <typename P> template <typename P>
class Iterator { class Iterator {
private: private:
Iterator(const Iterator&); // N/I
Iterator& operator=(const Iterator&); // N/I
Kernel kernel; Kernel kernel;
IteratorSettings settings; IteratorSettings settings;
@@ -110,6 +113,8 @@ namespace IfcGeom {
std::string unit_name; std::string unit_name;
// double? // double?
P unit_magnitude; P unit_magnitude;
gp_XYZ bounds_min_;
gp_XYZ bounds_max_;
void initUnits() { void initUnits() {
IfcSchema::IfcProject::list::ptr projects = ifc_file->entitiesByType<IfcSchema::IfcProject>(); IfcSchema::IfcProject::list::ptr projects = ifc_file->entitiesByType<IfcSchema::IfcProject>();
@@ -121,6 +126,7 @@ namespace IfcGeom {
} }
} }
std::set<boost::regex> names_to_include_or_exclude; // regex containing a name or a wildcard expression
std::set<IfcSchema::Type::Enum> entities_to_include_or_exclude; std::set<IfcSchema::Type::Enum> entities_to_include_or_exclude;
bool include_entities_in_processing; bool include_entities_in_processing;
@@ -148,7 +154,7 @@ namespace IfcGeom {
} catch (...) {} } catch (...) {}
std::set<std::string> context_types; std::set<std::string> context_types;
if (!settings.exclude_solids_and_surfaces()) { if (!settings.get(IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) {
// Really this should only be 'Model', as per // Really this should only be 'Model', as per
// the standard 'Design' is deprecated. So, // the standard 'Design' is deprecated. So,
// just for backwards compatibility: // just for backwards compatibility:
@@ -157,7 +163,7 @@ namespace IfcGeom {
// DDS likes to output 'model view' // DDS likes to output 'model view'
context_types.insert("model view"); context_types.insert("model view");
} }
if (settings.include_curves()) { if (settings.get(IteratorSettings::INCLUDE_CURVES)) {
context_types.insert("plan"); context_types.insert("plan");
} }
@@ -247,39 +253,74 @@ namespace IfcGeom {
done = 0; done = 0;
total = representations->size(); total = representations->size();
for (int i = 1; i < 4; ++i) {
bounds_min_.SetCoord(i, std::numeric_limits<double>::infinity());
bounds_max_.SetCoord(i, -std::numeric_limits<double>::infinity());
}
IfcSchema::IfcProduct::list::ptr products = ifc_file->entitiesByType<IfcSchema::IfcProduct>();
for (IfcSchema::IfcProduct::list::it iter = products->begin(); iter != products->end(); ++iter) {
IfcSchema::IfcProduct* product = *iter;
if (product->hasObjectPlacement()) {
gp_Trsf trsf; // Use a fresh trsf every time in order to prevent the result to be concatenated
if (kernel.convert(product->ObjectPlacement(), trsf)) {
const gp_XYZ& pos = trsf.TranslationPart();
bounds_min_.SetX(std::min(bounds_min_.X(), pos.X()));
bounds_min_.SetY(std::min(bounds_min_.Y(), pos.Y()));
bounds_min_.SetZ(std::min(bounds_min_.Z(), pos.Z()));
bounds_max_.SetX(std::max(bounds_max_.X(), pos.X()));
bounds_max_.SetY(std::max(bounds_max_.Y(), pos.Y()));
bounds_max_.SetZ(std::max(bounds_max_.Z(), pos.Z()));
}
}
}
return true; return true;
} }
int progress() { int progress() const { return 100 * done / total; }
return 100 * done / total;
}
const std::string& getUnitName() { const std::string& getUnitName() const { return unit_name; }
return unit_name;
}
const P getUnitMagnitude() { P getUnitMagnitude() const { return unit_magnitude; }
return unit_magnitude;
}
const std::string getLog() { std::string getLog() const { return Logger::GetLog(); }
return Logger::GetLog();
}
IfcParse::IfcFile* getFile() { IfcParse::IfcFile* getFile() const { return ifc_file; }
return ifc_file;
}
/// @note Entity names are handled case-insensitively.
void includeEntities(const std::set<std::string>& entities) { void includeEntities(const std::set<std::string>& entities) {
populate_set(entities); populate_set(entities);
include_entities_in_processing = true; include_entities_in_processing = true;
} }
/// @note Entity names are handled case-insensitively.
void excludeEntities(const std::set<std::string>& entities) { void excludeEntities(const std::set<std::string>& entities) {
populate_set(entities); populate_set(entities);
include_entities_in_processing = false; include_entities_in_processing = false;
} }
/// @note Arbitrary names or wildcard expressions are handled case-sensitively.
void include_entity_names(const std::vector<std::string>& names)
{
names_to_include_or_exclude.clear();
foreach(const std::string &name, names)
names_to_include_or_exclude.insert(IfcUtil::wildcard_string_to_regex(name));
include_entities_in_processing = true;
}
/// @note Arbitrary names or wildcard expressions are handled case-sensitively.
void exclude_entity_names(const std::vector<std::string>& names)
{
names_to_include_or_exclude.clear();
foreach(const std::string &name, names)
names_to_include_or_exclude.insert(IfcUtil::wildcard_string_to_regex(name));
include_entities_in_processing = false;
}
const gp_XYZ& bounds_min() const { return bounds_min_; }
const gp_XYZ& bounds_max() const { return bounds_max_; }
private: private:
// Move to the next IfcRepresentation // Move to the next IfcRepresentation
void _nextShape() { void _nextShape() {
@@ -340,7 +381,7 @@ namespace IfcGeom {
} }
} }
const bool process_maps_for_current_representation = (!has_openings || settings.disable_opening_subtractions()); const bool process_maps_for_current_representation = (!has_openings || settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS));
bool representation_processed_as_mapped_item = false; bool representation_processed_as_mapped_item = false;
IfcSchema::IfcRepresentation* representation_mapped_to = 0; IfcSchema::IfcRepresentation* representation_mapped_to = 0;
@@ -365,7 +406,7 @@ namespace IfcGeom {
IfcSchema::IfcProduct::list::ptr products_of_prodrep = (*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>(); IfcSchema::IfcProduct::list::ptr products_of_prodrep = (*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>();
products->push(products_of_prodrep); products->push(products_of_prodrep);
for (IfcSchema::IfcProduct::list::it jt = products_of_prodrep->begin(); jt != products_of_prodrep->end(); ++jt) { for (IfcSchema::IfcProduct::list::it jt = products_of_prodrep->begin(); jt != products_of_prodrep->end(); ++jt) {
if (kernel.find_openings(*jt)->size() > 0 && !settings.disable_opening_subtractions()) { if (kernel.find_openings(*jt)->size() > 0 && !settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) {
all_product_without_openings = false; all_product_without_openings = false;
break; break;
} }
@@ -418,7 +459,7 @@ namespace IfcGeom {
for (IfcSchema::IfcProductRepresentation::list::it kt = prodreps->begin(); kt != prodreps->end(); ++kt) { for (IfcSchema::IfcProductRepresentation::list::it kt = prodreps->begin(); kt != prodreps->end(); ++kt) {
IfcSchema::IfcProduct::list::ptr prods = (*kt)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>(); IfcSchema::IfcProduct::list::ptr prods = (*kt)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>();
for (IfcSchema::IfcProduct::list::it lt = prods->begin(); lt != prods->end(); ++lt) { for (IfcSchema::IfcProduct::list::it lt = prods->begin(); lt != prods->end(); ++lt) {
if (kernel.find_openings(*lt)->size() == 0 || settings.disable_opening_subtractions()) { if (kernel.find_openings(*lt)->size() == 0 || settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) {
if (!unfiltered_products->contains(*lt)) { if (!unfiltered_products->contains(*lt)) {
unfiltered_products->push(*lt); unfiltered_products->push(*lt);
} }
@@ -440,6 +481,14 @@ namespace IfcGeom {
break; break;
} }
} }
foreach(const boost::regex& r, names_to_include_or_exclude) {
if (boost::regex_match((*jt)->Name(), r)) {
found = true;
break;
}
}
if (found == include_entities_in_processing) { if (found == include_entities_in_processing) {
ifcproducts->push(*jt); ifcproducts->push(*jt);
} }
@@ -494,13 +543,17 @@ namespace IfcGeom {
return create(); return create();
} }
Element<P>* get() { /// Gets or takes the representation of the current geometrical entity.
// TODO: Test settings and throw /// @param take_ownership Pass in 'true' as if wishing to maintain the element lifetime yourself.
if (current_triangulation) return current_triangulation; Element<P>* get(bool take_ownership = false)
else if (current_serialization) return current_serialization; {
else if (current_shape_model) return current_shape_model; // TODO: Test settings and throw
else return 0; Element<P>* ret = 0;
} if (current_triangulation) { ret = current_triangulation; if (take_ownership) current_triangulation = 0; }
else if (current_serialization) { ret = current_serialization; if (take_ownership) current_serialization = 0; }
else if (current_shape_model) { ret = current_shape_model; if (take_ownership) current_shape_model = 0; }
return ret;
}
const Element<P>* getObject(int id) { const Element<P>* getObject(int id) {
@@ -549,15 +602,15 @@ namespace IfcGeom {
} catch (...) {} } catch (...) {}
if (next_shape_model) { if (next_shape_model) {
if (settings.use_brep_data()) { if (settings.get(IteratorSettings::USE_BREP_DATA)) {
try { try {
next_serialization = new SerializedElement<P>(*next_shape_model); next_serialization = new SerializedElement<P>(*next_shape_model);
} catch (...) { } catch (...) {
success = false; success = false;
} }
} else if (!settings.disable_triangulation()) { } else if (!settings.get(IteratorSettings::DISABLE_TRIANGULATION)) {
try { try {
if (ifcproduct_iterator == ifcproducts->begin() || settings.use_world_coords()) { if (ifcproduct_iterator == ifcproducts->begin() || settings.get(IteratorSettings::USE_WORLD_COORDS)) {
next_triangulation = new TriangulationElement<P>(*next_shape_model); next_triangulation = new TriangulationElement<P>(*next_shape_model);
} else { } else {
next_triangulation = new TriangulationElement<P>(*next_shape_model, current_triangulation->geometry_pointer()); next_triangulation = new TriangulationElement<P>(*next_shape_model, current_triangulation->geometry_pointer());
@@ -591,8 +644,9 @@ namespace IfcGeom {
unit_name = "METER"; unit_name = "METER";
unit_magnitude = 1.f; unit_magnitude = 1.f;
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1); kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.get(IteratorSettings::SEW_SHELLS) ? 1000 : -1);
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.include_curves() ? (settings.exclude_solids_and_surfaces() ? -1. : 0.) : +1.)); kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES)
? (settings.get(IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.));
} }
bool owns_ifc_file; bool owns_ifc_file;
+127 -142
View File
@@ -20,160 +20,145 @@
#ifndef IFCGEOMITERATORSETTINGS_H #ifndef IFCGEOMITERATORSETTINGS_H
#define IFCGEOMITERATORSETTINGS_H #define IFCGEOMITERATORSETTINGS_H
#include <string>
#include "../ifcparse/IfcException.h" #include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcUtil.h"
namespace IfcGeom { namespace IfcGeom
{
class IteratorSettings
{
public:
/// Enumeration of setting identifiers. These settings define the
/// behaviour of various aspects of IfcOpenShell.
enum Setting
{
/// Specifies whether vertices are welded, meaning that the coordinates
/// vector will only contain unique xyz-triplets. This results in a
/// manifold mesh which is useful for modelling applications, but might
/// result in unwanted shading artifacts in rendering applications.
WELD_VERTICES = 1,
/// Specifies whether to apply the local placements of building elements
/// directly to the coordinates of the representation mesh rather than
/// to represent the local placement in the 4x3 matrix, which will in that
/// case be the identity matrix.
USE_WORLD_COORDS = 1 << 1,
/// Internally IfcOpenShell measures everything in meters. This settings
/// specifies whether to convert IfcGeomObjects back to the units in which
/// the geometry in the IFC file is specified.
CONVERT_BACK_UNITS = 1 << 2,
/// Specifies whether to use the Open Cascade BREP format for representation
/// items rather than to create triangle meshes. This is useful is IfcOpenShell
/// is used as a library in an application that is also built on Open Cascade.
USE_BREP_DATA = 1 << 3,
/// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
/// TopoDS_Shells or whether to keep them as a loose collection of faces.
SEW_SHELLS = 1 << 4,
/// Specifies whether to compose IfcOpeningElements into a single compound
/// in order to speed up the processing of opening subtractions.
FASTER_BOOLEANS = 1 << 5,
/// Disables the subtraction of IfcOpeningElement representations from
/// the related building element representations.
DISABLE_OPENING_SUBTRACTIONS = 1 << 6,
/// Disables the triangulation of the topological representations. Useful if
/// the client application understands Open Cascade's native format.
DISABLE_TRIANGULATION = 1 << 7,
/// Applies default materials to entity instances without a surface style.
APPLY_DEFAULT_MATERIALS = 1 << 8,
/// Specifies whether to include subtypes of IfcCurve.
INCLUDE_CURVES = 1 << 9,
/// Specifies whether to exclude subtypes of IfcSolidModel and IfcSurface.
EXCLUDE_SOLIDS_AND_SURFACES = 1 << 10,
/// 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.
NO_NORMALS = 1 << 11,
/// Use entity names instead of unique IDs for naming elements.
/// Applicable for OBJ, DAE, and SVG output.
USE_ELEMENT_NAMES = 1 << 12,
/// Use entity GUIDs instead of unique IDs for naming elements.
/// Applicable for OBJ, DAE, and SVG output.
USE_ELEMENT_GUIDS = 1 << 13,
/// Use material names instead of unique IDs for naming materials.
/// Applicable for OBJ and DAE output.
USE_MATERIAL_NAMES = 1 << 14,
/// Centers the models upon serialization by the applying the center point of
/// the scene bounds as an offset. Applicable only for DAE output currently.
CENTER_MODEL = 1 << 15,
/// Generates UVs by using simple box projection. Requires normals.
/// Applicable only for DAE output currently.
GENERATE_UVS = 1 << 16,
/// Number of different setting flags.
NUM_SETTINGS = 16
};
/// Used to store logical OR combination of setting flags.
typedef unsigned SettingField;
class IteratorSettings { IteratorSettings()
public: : settings_(WELD_VERTICES) // OR options that default to true here
// Enumeration of setting identifiers. These settings define the , deflection_tolerance_(1.e-3)
// behaviour of various aspects of IfcOpenShell. {
memset(offset, 0, sizeof(offset));
}
// Specifies whether vertices are welded, meaning that the coordinates /// Optional offset that is applied to serialized objects, (0,0,0) by default.
// vector will only contain unique xyz-triplets. This results in a double offset[3];
// manifold mesh which is useful for modelling applications, but might
// result in unwanted shading artifacts in rendering applications.
static const int WELD_VERTICES = 1;
// Specifies whether to apply the local placements of building elements
// directly to the coordinates of the representation mesh rather than
// to represent the local placement in the 4x3 matrix, which will in that
// case be the identity matrix.
static const int USE_WORLD_COORDS = 2;
// Internally IfcOpenShell measures everything in meters. This settings
// specifies whether to convert IfcGeomObjects back to the units in which
// the geometry in the IFC file is specified.
static const int CONVERT_BACK_UNITS = 3;
// Specifies whether to use the Open Cascade BREP format for representation
// items rather than to create triangle meshes. This is useful is IfcOpenShell
// is used as a library in an application that is also built on Open Cascade.
static const int USE_BREP_DATA = 4;
// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
// TopoDS_Shells or whether to keep them as a loose collection of faces.
static const int SEW_SHELLS = 5;
// Specifies whether to compose IfcOpeningElements into a single compound
// in order to speed up the processing of opening subtractions.
static const int FASTER_BOOLEANS = 6;
// Disables the subtraction of IfcOpeningElement representations from
// the related building element representations.
static const int DISABLE_OPENING_SUBTRACTIONS = 8;
// Disables the triangulation of the topological representations. Useful if
// the client application understands Open Cascade's native format.
static const int DISABLE_TRIANGULATION = 9;
// Applies default materials to entity instances without a surface style.
static const int APPLY_DEFAULT_MATERIALS = 10;
// Specifies whether to include subtypes of IfcCurve.
static const int INCLUDE_CURVES = 11;
// Specifies whether to exclude subtypes of IfcSolidModel and IfcSurface.
static const int EXCLUDE_SOLIDS_AND_SURFACES = 12;
// End of settings enumeration. /// Note that this is independent of the IFC length unit, one millimeter by default.
double deflection_tolerance() const { return deflection_tolerance_; }
private: void set_deflection_tolerance(double value)
bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials, _include_curves, _exclude_solids_and_surfaces; {
double _deflection_tolerance; /// @todo Using deflection tolerance of 1e-6 or smaller hangs the conversion, research more in-depth.
public: /// This bug can be reproduced e.g. with the Duplex model that can be found from http://www.nibs.org/?page=bsa_commonbimfiles#project1
IteratorSettings() deflection_tolerance_ = value;
: _weld_vertices(true) if (deflection_tolerance_ <= 1e-6) {
, _use_world_coords(false) Logger::Message(Logger::LOG_WARNING, "Deflection tolerance cannot be set to <= 1e-6; using the default value 1e-3");
, _convert_back_units(false) deflection_tolerance_ = 1e-3;
, _use_brep_data(false) }
, _sew_shells(false) }
, _faster_booleans(false)
, _disable_opening_subtractions(false)
, _disable_triangulation(false)
, _apply_default_materials(false)
, _include_curves(false)
, _exclude_solids_and_surfaces(false)
// TODO: Make deflection tolerance into a command line argument
// For now, stick to one millimeter. Note that this is independent of the IFC length unit.
, _deflection_tolerance(1.e-3)
{}
const bool& weld_vertices() const { return _weld_vertices; } /// Get boolean value for a single settings or for a combination of settings.
bool& weld_vertices() { return _weld_vertices; } bool get(SettingField setting) const
const bool& use_world_coords() const { return _use_world_coords; } {
bool& use_world_coords() { return _use_world_coords; } /// @todo If unknown setting value/combination: throw IfcParse::IfcException("Invalid IteratorSetting")?
const bool& convert_back_units() const { return _convert_back_units; } return (settings_ & setting) != 0;
bool& convert_back_units() { return _convert_back_units; } }
const bool& use_brep_data() const { return _use_brep_data; }
bool& use_brep_data() { return _use_brep_data; }
const bool& sew_shells() const { return _sew_shells; }
bool& sew_shells() { return _sew_shells; }
const bool& faster_booleans() const { return _faster_booleans; }
bool& faster_booleans() { return _faster_booleans; }
const bool& disable_opening_subtractions() const { return _disable_opening_subtractions; }
bool& disable_opening_subtractions() { return _disable_opening_subtractions; }
const bool& disable_triangulation() const { return _disable_triangulation; }
bool& disable_triangulation() { return _disable_triangulation; }
const bool& apply_default_materials() const { return _apply_default_materials; }
bool& apply_default_materials() { return _apply_default_materials; }
const bool& include_curves() const { return _include_curves; }
bool& include_curves() { return _include_curves; }
const bool& exclude_solids_and_surfaces() const { return _exclude_solids_and_surfaces; }
bool& exclude_solids_and_surfaces() { return _exclude_solids_and_surfaces; }
const double& deflection_tolerance() const { return _deflection_tolerance; } /// Set boolean value for a single settings or for a combination of settings.
double& deflection_tolerance() { return _deflection_tolerance; } void set(SettingField setting, bool value)
{
/// @todo If unknown setting value/combination: throw IfcParse::IfcException("Invalid IteratorSetting")?
if (value) {
settings_ |= setting;
} else {
settings_ &= ~setting;
}
}
void set(int setting, bool value) { protected:
switch (setting) { SettingField settings_;
case USE_WORLD_COORDS: double deflection_tolerance_;
_use_world_coords = value; };
break;
case WELD_VERTICES:
_weld_vertices = value;
break;
case CONVERT_BACK_UNITS:
_convert_back_units = value;
break;
case USE_BREP_DATA:
_use_brep_data = value;
break;
case FASTER_BOOLEANS:
_faster_booleans = value;
break;
case SEW_SHELLS:
_sew_shells = value;
break;
case DISABLE_OPENING_SUBTRACTIONS:
_disable_opening_subtractions = value;
break;
case DISABLE_TRIANGULATION:
_disable_triangulation = value;
break;
case APPLY_DEFAULT_MATERIALS:
_apply_default_materials = value;
break;
case INCLUDE_CURVES:
_include_curves = value;
break;
case EXCLUDE_SOLIDS_AND_SURFACES:
_exclude_solids_and_surfaces = value;
break;
default: throw IfcParse::IfcException("Invalid IteratorSetting");
}
}
};
class ElementSettings : public IteratorSettings { class ElementSettings : public IteratorSettings
private: {
double _unit_magnitude; public:
std::string _element_type; ElementSettings(const IteratorSettings& settings,
public: double unit_magnitude,
ElementSettings(const IteratorSettings& settings, const std::string& element_type)
double unit_magnitude, : IteratorSettings(settings)
const std::string& element_type) , unit_magnitude_(unit_magnitude)
: IteratorSettings(settings) , element_type_(element_type)
, _unit_magnitude(unit_magnitude) {
, _element_type(element_type) }
{}
const double& unit_magnitude() const { return _unit_magnitude; } double unit_magnitude() const { return unit_magnitude_; }
const std::string& element_type() const { return _element_type; } const std::string& element_type() const { return element_type_; }
};
private:
double unit_magnitude_;
std::string element_type_;
};
} }
#endif #endif
+2 -1
View File
@@ -30,5 +30,6 @@ const double* IfcGeom::Material::diffuse() const { if (hasDiffuse()) return &((*
const double* IfcGeom::Material::specular() const { if (hasSpecular()) return &((*style->Specular()).R()); else return black; } const double* IfcGeom::Material::specular() const { if (hasSpecular()) return &((*style->Specular()).R()); else return black; }
double IfcGeom::Material::transparency() const { if (hasTransparency()) return *style->Transparency(); else return 0; } double IfcGeom::Material::transparency() const { if (hasTransparency()) return *style->Transparency(); else return 0; }
double IfcGeom::Material::specularity() const { if (hasSpecularity()) return *style->Specularity(); else return 0; } double IfcGeom::Material::specularity() const { if (hasSpecularity()) return *style->Specularity(); else return 0; }
const std::string IfcGeom::Material::name() const { return style->Name(); } const std::string &IfcGeom::Material::name() const { return style->Name(); }
const std::string &IfcGeom::Material::original_name() const { return style->original_name(); }
bool IfcGeom::Material::operator==(const IfcGeom::Material& other) const { return style == other.style; } bool IfcGeom::Material::operator==(const IfcGeom::Material& other) const { return style == other.style; }
+2 -1
View File
@@ -41,7 +41,8 @@ namespace IfcGeom {
const double* specular() const; const double* specular() const;
double transparency() const; double transparency() const;
double specularity() const; double specularity() const;
const std::string name() const; const std::string &name() const;
const std::string &original_name() const;
bool operator==(const Material& other) const; bool operator==(const Material& other) const;
}; };
+9 -5
View File
@@ -45,21 +45,21 @@ namespace IfcGeom {
}; };
private: private:
std::string name; std::string name;
std::string original_name_;
boost::optional<int> id; boost::optional<int> id;
boost::optional<ColorComponent> diffuse, specular; boost::optional<ColorComponent> diffuse, specular;
boost::optional<double> transparency; boost::optional<double> transparency;
boost::optional<double> specularity; boost::optional<double> specularity;
public: public:
SurfaceStyle() { SurfaceStyle() : name("surface-style") {}
this->name = "surface-style";
}
SurfaceStyle(int id) : id(id) { SurfaceStyle(int id) : id(id) {
std::stringstream sstr; std::stringstream sstr;
sstr << "surface-style-" << id; sstr << "surface-style-" << id;
this->name = sstr.str(); this->name = sstr.str();
} }
SurfaceStyle(const std::string& name) : name(name) {} SurfaceStyle(const std::string& name) : name(name), original_name_(name) {}
SurfaceStyle(int id, const std::string& name) : id(id) { SurfaceStyle(int id, const std::string& name) : id(id), original_name_(name)
{
std::stringstream sstr; std::stringstream sstr;
std::string sanitized = name; std::string sanitized = name;
std::transform(sanitized.begin(), sanitized.end(), sanitized.begin(), ::tolower); std::transform(sanitized.begin(), sanitized.end(), sanitized.begin(), ::tolower);
@@ -76,8 +76,12 @@ namespace IfcGeom {
return name == other.name; return name == other.name;
} }
/// ID name, e.g. "surface-style-66675-metal---aluminium"
const std::string& Name() const { return name; } const std::string& Name() const { return name; }
/// Original name, if available, e.g. "Metal - Aluminium"
const std::string& original_name() const { return original_name_; }
const boost::optional<ColorComponent>& Diffuse() const { return diffuse; } const boost::optional<ColorComponent>& Diffuse() const { return diffuse; }
const boost::optional<ColorComponent>& Specular() const { return specular; } const boost::optional<ColorComponent>& Specular() const { return specular; }
const boost::optional<double>& Transparency() const { return transparency; } const boost::optional<double>& Transparency() const { return transparency; }
+1 -1
View File
@@ -38,7 +38,7 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) { for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
const TopoDS_Shape& s = it->Shape(); const TopoDS_Shape& s = it->Shape();
gp_GTrsf trsf = it->Placement(); gp_GTrsf trsf = it->Placement();
if (settings().convert_back_units()) { if (settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
gp_Trsf scale; gp_Trsf scale;
scale.SetScaleFactor(1.0 / settings().unit_magnitude()); scale.SetScaleFactor(1.0 / settings().unit_magnitude());
trsf.PreMultiply(scale); trsf.PreMultiply(scale);
+47 -7
View File
@@ -103,6 +103,7 @@ namespace IfcGeom {
std::vector<int> _faces; std::vector<int> _faces;
std::vector<int> _edges; std::vector<int> _edges;
std::vector<P> _normals; std::vector<P> _normals;
std::vector<P> uvs_;
std::vector<int> _material_ids; std::vector<int> _material_ids;
std::vector<Material> _materials; std::vector<Material> _materials;
VertexKeyMap welds; VertexKeyMap welds;
@@ -113,8 +114,10 @@ namespace IfcGeom {
const std::vector<int>& faces() const { return _faces; } const std::vector<int>& faces() const { return _faces; }
const std::vector<int>& edges() const { return _edges; } const std::vector<int>& edges() const { return _edges; }
const std::vector<P>& normals() const { return _normals; } const std::vector<P>& normals() const { return _normals; }
const std::vector<P>& uvs() const { return uvs_; }
const std::vector<int>& material_ids() const { return _material_ids; } const std::vector<int>& material_ids() const { return _material_ids; }
const std::vector<Material>& materials() const { return _materials; } const std::vector<Material>& materials() const { return _materials; }
Triangulation(const BRep& shape_model) Triangulation(const BRep& shape_model)
: Representation(shape_model.settings()) : Representation(shape_model.settings())
, _id(shape_model.getId()) , _id(shape_model.getId())
@@ -133,7 +136,7 @@ namespace IfcGeom {
} }
} }
if (settings().apply_default_materials() && surface_style_id == -1) { if (settings().get(IteratorSettings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) {
Material material(IfcGeom::get_default_style(settings().element_type())); Material material(IfcGeom::get_default_style(settings().element_type()));
std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material); std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
if (mit == _materials.end()) { if (mit == _materials.end()) {
@@ -182,8 +185,9 @@ namespace IfcGeom {
BRepGProp_Face prop(face); BRepGProp_Face prop(face);
std::map<int,int> dict; std::map<int,int> dict;
// Vertex normals are only calculated if vertices are not welded // Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
const bool calculate_normals = !settings().weld_vertices(); const bool calculate_normals = !settings().get(IteratorSettings::WELD_VERTICES) &&
!settings().get(IteratorSettings::NO_NORMALS);
for( int i = 1; i <= nodes.Length(); ++ i ) { for( int i = 1; i <= nodes.Length(); ++ i ) {
coords.push_back(nodes(i).Transformed(loc).XYZ()); coords.push_back(nodes(i).Transformed(loc).XYZ());
@@ -246,6 +250,10 @@ namespace IfcGeom {
} }
} }
if (!_normals.empty() && settings().get(IfcGeom::IteratorSettings::GENERATE_UVS)) {
uvs_ = box_project_uvs(_verts, _normals);
}
if (num_faces == 0) { if (num_faces == 0) {
// Edges are only emitted if there are no faces. A mixed representation of faces // Edges are only emitted if there are no faces. A mixed representation of faces
// and loose edges is discouraged by the standard. An alternative would be to use // and loose edges is discouraged by the standard. An alternative would be to use
@@ -277,14 +285,46 @@ namespace IfcGeom {
} }
} }
virtual ~Triangulation() {} virtual ~Triangulation() {}
/// Generates UVs for a single mesh using box projection.
/// @todo Very simple impl. Assumes that input vertices and normals match 1:1.
static std::vector<P> box_project_uvs(const std::vector<P> &vertices, const std::vector<P> &normals)
{
std::vector<P> uvs;
uvs.resize(vertices.size() / 3 * 2);
for (size_t uv_idx = 0, v_idx = 0;
uv_idx < uvs.size() && v_idx < vertices.size() && v_idx < normals.size();
uv_idx += 2, v_idx += 3) {
P n_x = normals[v_idx], n_y = normals[v_idx + 1], n_z = normals[v_idx + 2];
P v_x = vertices[v_idx], v_y = vertices[v_idx + 1], v_z = vertices[v_idx + 2];
if (std::abs(n_x) > std::abs(n_y) && std::abs(n_x) > std::abs(n_z)) {
uvs[uv_idx] = v_z;
uvs[uv_idx + 1] = v_y;
}
if (std::abs(n_y) > std::abs(n_x) && std::abs(n_y) > std::abs(n_z)) {
uvs[uv_idx] = v_x;
uvs[uv_idx + 1] = v_z;
}
if (std::abs(n_z) > std::abs(n_x) && std::abs(n_z) > std::abs(n_y)) {
uvs[uv_idx] = v_x;
uvs[uv_idx + 1] = v_y;
}
}
return uvs;
}
private: private:
// Welds vertices that belong to different faces // Welds vertices that belong to different faces
int addVertex(int material_index, const gp_XYZ& p) { int addVertex(int material_index, const gp_XYZ& p) {
const P X = static_cast<P>(settings().convert_back_units() ? (p.X() / settings().unit_magnitude()) : p.X()); const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS);
const P Y = static_cast<P>(settings().convert_back_units() ? (p.Y() / settings().unit_magnitude()) : p.Y()); const P X = static_cast<P>(convert ? (p.X() / settings().unit_magnitude()) : p.X());
const P Z = static_cast<P>(settings().convert_back_units() ? (p.Z() / settings().unit_magnitude()) : p.Z()); const P Y = static_cast<P>(convert ? (p.Y() / settings().unit_magnitude()) : p.Y());
const P Z = static_cast<P>(convert ? (p.Z() / settings().unit_magnitude()) : p.Z());
int i = (int) _verts.size() / 3; int i = (int) _verts.size() / 3;
if (settings().weld_vertices()) { if (settings().get(IteratorSettings::WELD_VERTICES)) {
const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z))); const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z)));
typename VertexKeyMap::const_iterator it = welds.find(key); typename VertexKeyMap::const_iterator it = welds.find(key);
if ( it != welds.end() ) return it->second; if ( it != welds.end() ) return it->second;
+4 -4
View File
@@ -318,10 +318,10 @@ int main () {
memcpy(data, m.string().c_str(), len); memcpy(data, m.string().c_str(), len);
IfcGeom::IteratorSettings settings; IfcGeom::IteratorSettings settings;
settings.use_world_coords() = false; settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
settings.weld_vertices() = false; settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false);
settings.convert_back_units() = true; settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true);
settings.include_curves() = true; settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, true);
iterator = new IfcGeom::Iterator<float>(settings, data, (int)len); iterator = new IfcGeom::Iterator<float>(settings, data, (int)len);
has_more = iterator->initialize(); has_more = iterator->initialize();
+3 -3
View File
@@ -214,9 +214,9 @@ static Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL /*suppressPrompts*/) { int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL /*suppressPrompts*/) {
IfcGeom::IteratorSettings settings; IfcGeom::IteratorSettings settings;
settings.use_world_coords() = false; settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
settings.weld_vertices() = true; settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, true);
settings.sew_shells() = true; settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
#ifdef _UNICODE #ifdef _UNICODE
int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0); int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0);
+13 -4
View File
@@ -69,7 +69,10 @@ void init_locale() {
// //
// Opens the file, gets the filesize and reads a chunk in memory // Opens the file, gets the filesize and reads a chunk in memory
// //
IfcSpfStream::IfcSpfStream(const std::string& fn) { IfcSpfStream::IfcSpfStream(const std::string& fn)
: stream(0)
, buffer(0)
{
eof = false; eof = false;
#ifdef _MSC_VER #ifdef _MSC_VER
int fn_buffer_size = MultiByteToWideChar(CP_UTF8, 0, fn.c_str(), -1, 0, 0); int fn_buffer_size = MultiByteToWideChar(CP_UTF8, 0, fn.c_str(), -1, 0, 0);
@@ -86,7 +89,7 @@ IfcSpfStream::IfcSpfStream(const std::string& fn) {
} }
valid = true; valid = true;
fseek(stream, 0, SEEK_END); fseek(stream, 0, SEEK_END);
size = (unsigned int) ftell(stream);; size = (unsigned int) ftell(stream);
rewind(stream); rewind(stream);
#ifdef BUF_SIZE #ifdef BUF_SIZE
offset = 0; offset = 0;
@@ -100,7 +103,10 @@ IfcSpfStream::IfcSpfStream(const std::string& fn) {
ReadBuffer(false); ReadBuffer(false);
} }
IfcSpfStream::IfcSpfStream(std::istream& f, int l) { IfcSpfStream::IfcSpfStream(std::istream& f, int l)
: stream(0)
, buffer(0)
{
eof = false; eof = false;
size = l; size = l;
#ifdef BUF_SIZE #ifdef BUF_SIZE
@@ -114,7 +120,10 @@ IfcSpfStream::IfcSpfStream(std::istream& f, int l) {
len = l; len = l;
} }
IfcSpfStream::IfcSpfStream(void* data, int l) { IfcSpfStream::IfcSpfStream(void* data, int l)
: stream(0)
, buffer(0)
{
eof = false; eof = false;
size = l; size = l;
#ifdef BUF_SIZE #ifdef BUF_SIZE
+44 -3
View File
@@ -17,12 +17,14 @@
* * * *
********************************************************************************/ ********************************************************************************/
#include "IfcUtil.h"
#include "../ifcparse/IfcException.h"
#include <boost/algorithm/string/replace.hpp>
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include "../ifcparse/IfcException.h"
#include "IfcUtil.h"
void IfcEntityList::push(IfcUtil::IfcBaseClass* l) { void IfcEntityList::push(IfcUtil::IfcBaseClass* l) {
if (l) { if (l) {
@@ -144,3 +146,42 @@ bool IfcUtil::valid_binary_string(const std::string& s) {
} }
return true; return true;
} }
boost::regex IfcUtil::wildcard_string_to_regex(std::string str)
{
// Escape all non-"*?" regex special chars
std::string special_chars = "\\^.$|()[]+/";
foreach(char c, special_chars) {
std::string char_str(1, c);
boost::replace_all(str, char_str, "\\"+ char_str);
}
// Convert "*?" to their regex equivalents
boost::replace_all(str, "?", ".");
boost::replace_all(str, "*", ".*");
return boost::regex(str);
}
void IfcUtil::sanitate_material_name(std::string &str)
{
// Spaces in material names have been observed to cause problems with obj and dae importers.
// Handle other potential problematic characters here too if observing problems.
boost::replace_all(str, " ", "_");
}
void IfcUtil::escape_xml(std::string &str)
{
boost::replace_all(str, "\"", "&quot;");
boost::replace_all(str, "'", "&apos;");
boost::replace_all(str, "<", "&lt;");
boost::replace_all(str, ">", "&gt;");
boost::replace_all(str, "&", "&amp;");
}
void IfcUtil::unescape_xml(std::string &str)
{
boost::replace_all(str, "&quot;", "\"");
boost::replace_all(str, "&apos;", "'");
boost::replace_all(str, "&lt;", "<");
boost::replace_all(str, "&gt;", ">");
boost::replace_all(str, "&amp;", "&");
}
+15 -3
View File
@@ -26,15 +26,20 @@
#include <sstream> #include <sstream>
#include <algorithm> #include <algorithm>
#include <boost/shared_ptr.hpp>
#include <boost/dynamic_bitset.hpp>
#ifdef USE_IFC4 #ifdef USE_IFC4
#include "../ifcparse/Ifc4enum.h" #include "../ifcparse/Ifc4enum.h"
#else #else
#include "../ifcparse/Ifc2x3enum.h" #include "../ifcparse/Ifc2x3enum.h"
#endif #endif
#include <boost/shared_ptr.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/regex.hpp>
#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH
#define rforeach BOOST_REVERSE_FOREACH
class Argument; class Argument;
class IfcEntityList; class IfcEntityList;
class IfcEntityListList; class IfcEntityListList;
@@ -110,6 +115,13 @@ namespace IfcUtil {
}; };
bool valid_binary_string(const std::string& s); bool valid_binary_string(const std::string& s);
boost::regex wildcard_string_to_regex(std::string str);
/// Replaces spaces and potentially other problem causing characters with underscores.
void sanitate_material_name(std::string &str);
void escape_xml(std::string &str);
void unescape_xml(std::string &str);
} }
template <class T> template <class T>
+10 -10
View File
@@ -244,8 +244,8 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
IfcSchema::IfcProject* project = *projects->begin(); IfcSchema::IfcProject* project = *projects->begin();
IfcGeom::Kernel kernel; IfcGeom::Kernel kernel;
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.sew_shells() ? 1000 : -1); kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.get(IfcGeom::IteratorSettings::SEW_SHELLS) ? 1000 : -1);
kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.include_curves() ? (settings.exclude_solids_and_surfaces() ? -1. : 0.) : +1.)); kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IfcGeom::IteratorSettings::INCLUDE_CURVES) ? (settings.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.));
std::pair<std::string, double> length_unit = kernel.initializeUnits(project->UnitsInContext()); std::pair<std::string, double> length_unit = kernel.initializeUnits(project->UnitsInContext());
if (instance->is(IfcSchema::Type::IfcProduct)) { if (instance->is(IfcSchema::Type::IfcProduct)) {
@@ -269,13 +269,13 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
// First, try to find a representation based on the settings // First, try to find a representation based on the settings
for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) { for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) {
IfcSchema::IfcRepresentation* rep = *it; IfcSchema::IfcRepresentation* rep = *it;
if (!settings.exclude_solids_and_surfaces()) { if (!settings.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) {
if (rep->RepresentationIdentifier() == "Body") { if (rep->RepresentationIdentifier() == "Body") {
ifc_representation = rep; ifc_representation = rep;
break; break;
} }
} }
if (settings.include_curves()) { if (settings.get(IfcGeom::IteratorSettings::INCLUDE_CURVES)) {
if (rep->RepresentationIdentifier() == "Plan" || rep->RepresentationIdentifier() == "Axis") { if (rep->RepresentationIdentifier() == "Plan" || rep->RepresentationIdentifier() == "Axis") {
ifc_representation = rep; ifc_representation = rep;
break; break;
@@ -293,12 +293,12 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
// TODO: Remove redundancy with IfcGeomIterator.h // TODO: Remove redundancy with IfcGeomIterator.h
if (context->hasContextType()) { if (context->hasContextType()) {
std::set<std::string> context_types; std::set<std::string> context_types;
if (!settings.exclude_solids_and_surfaces()) { if (!settings.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) {
context_types.insert("model"); context_types.insert("model");
context_types.insert("design"); context_types.insert("design");
context_types.insert("model view"); context_types.insert("model view");
} }
if (settings.include_curves()) { if (settings.get(IfcGeom::IteratorSettings::INCLUDE_CURVES)) {
context_types.insert("plan"); context_types.insert("plan");
} }
@@ -347,11 +347,11 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
if (!brep) { if (!brep) {
throw IfcParse::IfcException("Failed to process shape"); throw IfcParse::IfcException("Failed to process shape");
} }
if (settings.use_brep_data()) { if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) {
IfcGeom::SerializedElement<double>* serialization = new IfcGeom::SerializedElement<double>(*brep); IfcGeom::SerializedElement<double>* serialization = new IfcGeom::SerializedElement<double>(*brep);
delete brep; delete brep;
return serialization; return serialization;
} else if (!settings.disable_triangulation()) { } else if (!settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) {
IfcGeom::TriangulationElement<double>* triangulation = new IfcGeom::TriangulationElement<double>(*brep); IfcGeom::TriangulationElement<double>* triangulation = new IfcGeom::TriangulationElement<double>(*brep);
delete brep; delete brep;
return triangulation; return triangulation;
@@ -366,9 +366,9 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
IfcGeom::ElementSettings element_settings(settings, kernel.getValue(IfcGeom::Kernel::GV_LENGTH_UNIT), IfcSchema::Type::ToString(instance->type())); IfcGeom::ElementSettings element_settings(settings, kernel.getValue(IfcGeom::Kernel::GV_LENGTH_UNIT), IfcSchema::Type::ToString(instance->type()));
IfcGeom::Representation::BRep brep(element_settings, instance->entity->id(), shapes); IfcGeom::Representation::BRep brep(element_settings, instance->entity->id(), shapes);
try { try {
if (settings.use_brep_data()) { if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) {
return new IfcGeom::Representation::Serialization(brep); return new IfcGeom::Representation::Serialization(brep);
} else if (!settings.disable_triangulation()) { } else if (!settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) {
return new IfcGeom::Representation::Triangulation<double>(brep); return new IfcGeom::Representation::Triangulation<double>(brep);
} }
} catch (...) { } catch (...) {
File diff suppressed because it is too large Load Diff