mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
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:
@@ -24,7 +24,7 @@ project (IfcOpenShell)
|
||||
OPTION(UNICODE_SUPPORT "Build IfcOpenShell with Unicode support (requires ICU)." 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)
|
||||
#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(BUILD_IFCPYTHON "Build IfcPython." 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)
|
||||
endif()
|
||||
|
||||
# IfcConvert
|
||||
if (IFCCONVERT_DOUBLE_PRECISION)
|
||||
add_definitions(-DIFCCONVERT_DOUBLE_PRECISION)
|
||||
endif()
|
||||
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
|
||||
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
|
||||
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
|
||||
|
||||
@@ -21,48 +21,63 @@
|
||||
|
||||
#include "ColladaSerializer.h"
|
||||
|
||||
#include <COLLADASWPrimitves.h>
|
||||
#include <COLLADASWSource.h>
|
||||
#include <COLLADASWScene.h>
|
||||
#include <COLLADASWNode.h>
|
||||
#include <COLLADASWInstanceGeometry.h>
|
||||
#include <COLLADASWBaseInputElement.h>
|
||||
#include <COLLADASWAsset.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
|
||||
std::string collada_id(const std::string& s) {
|
||||
std::string id;
|
||||
id.reserve(s.size());
|
||||
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
|
||||
const std::string::value_type c = *it;
|
||||
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || ( c == '-')) {
|
||||
id.push_back(c);
|
||||
}
|
||||
}
|
||||
return id;
|
||||
static void collada_id(std::string &s)
|
||||
{
|
||||
IfcUtil::sanitate_material_name(s);
|
||||
IfcUtil::escape_xml(s);
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords /* = "XYZ" */) {
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id,
|
||||
const std::string& suffix, const std::vector<real_t>& floats, const char* coords /* = "XYZ" */)
|
||||
{
|
||||
COLLADASW::FloatSource source(mSW);
|
||||
source.setId(mesh_id + suffix);
|
||||
source.setArrayId(mesh_id + suffix + COLLADASW::LibraryGeometries::ARRAY_ID_SUFFIX);
|
||||
source.setAccessorStride((unsigned long)strlen(coords));
|
||||
source.setAccessorCount((unsigned long)floats.size() / 3);
|
||||
for (unsigned int i = 0; i < source.getAccessorStride(); ++i) {
|
||||
const size_t num_elems = strlen(coords);
|
||||
source.setAccessorStride(static_cast<unsigned long>(num_elems));
|
||||
source.setAccessorCount(static_cast<unsigned long>(floats.size() / num_elems));
|
||||
for (size_t i = 0; i < num_elems; ++i) {
|
||||
source.getParameterNameList().push_back(std::string(1, coords[i]));
|
||||
}
|
||||
source.prepareToAppendValues();
|
||||
for (std::vector<double>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
|
||||
for (std::vector<real_t>::const_iterator it = floats.begin(); it != floats.end(); ++it) {
|
||||
source.appendValues(*it);
|
||||
}
|
||||
source.finish();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials) {
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::write(
|
||||
const std::string &mesh_id, const std::string& default_material_name, const std::vector<real_t>& positions,
|
||||
const std::vector<real_t>& normals, const std::vector<int>& faces, const std::vector<int>& edges,
|
||||
const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials,
|
||||
const std::vector<real_t>& uvs)
|
||||
{
|
||||
openMesh(mesh_id);
|
||||
|
||||
// The normals vector can be empty for example when the WELD_VERTICES setting is used.
|
||||
// IfcOpenShell does not provide them with multiple face normals collapsed into a single vertex.
|
||||
const bool has_normals = !normals.empty();
|
||||
const bool has_uvs = !uvs.empty();
|
||||
|
||||
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions);
|
||||
if (has_normals) {
|
||||
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals);
|
||||
if (has_uvs) {
|
||||
addFloatSource(mesh_id, COLLADASW::LibraryGeometries::TEXCOORDS_SOURCE_ID_SUFFIX, uvs, "UV");
|
||||
}
|
||||
}
|
||||
|
||||
COLLADASW::VerticesElement vertices(mSW);
|
||||
@@ -82,20 +97,28 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
|
||||
current_material_id = *(material_it++);
|
||||
}
|
||||
|
||||
const unsigned long num_triangles = (unsigned long)std::distance(index_range_start, it) / 3;
|
||||
const size_t num_triangles = std::distance(index_range_start, it) / 3;
|
||||
if ((previous_material_id != current_material_id && num_triangles > 0) || (it == faces.end())) {
|
||||
COLLADASW::Triangles triangles(mSW);
|
||||
triangles.setMaterial(materials[previous_material_id].name());
|
||||
triangles.setCount(num_triangles);
|
||||
std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
|
||||
? materials[previous_material_id].original_name() : materials[previous_material_id].name());
|
||||
collada_id(material_name);
|
||||
triangles.setMaterial(material_name);
|
||||
triangles.setCount((unsigned long)num_triangles);
|
||||
int offset = 0;
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++ ) );
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++));
|
||||
if (has_normals) {
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++ ) );
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++));
|
||||
}
|
||||
if (has_uvs) {
|
||||
triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::TEXCOORD,"#" + mesh_id + COLLADASW::LibraryGeometries::TEXCOORDS_SOURCE_ID_SUFFIX, offset++));
|
||||
}
|
||||
triangles.prepareToAppendValues();
|
||||
for (std::vector<int>::const_iterator jt = index_range_start; jt != it; ++jt) {
|
||||
const int idx = *jt;
|
||||
if (has_normals) {
|
||||
if (has_normals && has_uvs) {
|
||||
triangles.appendValues(idx, idx, idx);
|
||||
} else if(has_normals) {
|
||||
triangles.appendValues(idx, idx);
|
||||
} else {
|
||||
triangles.appendValues(idx);
|
||||
@@ -134,10 +157,13 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
|
||||
|
||||
for (linelist_t::const_iterator it = linelist.begin(); it != linelist.end(); ++it) {
|
||||
COLLADASW::Lines lines(mSW);
|
||||
lines.setMaterial(materials[it->first].name());
|
||||
std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
|
||||
? materials[it->first].original_name() : materials[it->first].name());
|
||||
collada_id(material_name);
|
||||
lines.setMaterial(material_name);
|
||||
lines.setCount((unsigned long)it->second.size());
|
||||
int offset = 0;
|
||||
lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++));
|
||||
lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset));
|
||||
lines.prepareToAppendValues();
|
||||
lines.appendValues(it->second);
|
||||
lines.finish();
|
||||
@@ -150,8 +176,11 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str
|
||||
void ColladaSerializer::ColladaExporter::ColladaGeometries::close() {
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix) {
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaScene::add(
|
||||
const std::string& node_id, const std::string& node_name, const std::string& geom_name,
|
||||
const std::vector<std::string>& material_ids, const std::vector<real_t>& matrix)
|
||||
{
|
||||
if (!scene_opened) {
|
||||
openVisualScene(scene_id);
|
||||
scene_opened = true;
|
||||
@@ -165,18 +194,24 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& no
|
||||
// The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement.
|
||||
// Note that this placement is absolute, ie it is multiplied with all parent placements.
|
||||
double matrix_array[4][4] = {
|
||||
{matrix[0], matrix[3], matrix[6], matrix[ 9]},
|
||||
{matrix[1], matrix[4], matrix[7], matrix[10]},
|
||||
{matrix[2], matrix[5], matrix[8], matrix[11]},
|
||||
{ 0, 0, 0, 1}
|
||||
{ (double)matrix[0], (double)matrix[3], (double)matrix[6], (double)matrix[ 9] },
|
||||
{ (double)matrix[1], (double)matrix[4], (double)matrix[7], (double)matrix[10] },
|
||||
{ (double)matrix[2], (double)matrix[5], (double)matrix[8], (double)matrix[11] },
|
||||
{ 0, 0, 0, 1 }
|
||||
};
|
||||
|
||||
matrix_array[0][3] += serializer->settings().offset[0];
|
||||
matrix_array[1][3] += serializer->settings().offset[1];
|
||||
matrix_array[2][3] += serializer->settings().offset[2];
|
||||
|
||||
node.start();
|
||||
node.addMatrix(matrix_array);
|
||||
COLLADASW::InstanceGeometry instanceGeometry(mSW);
|
||||
instanceGeometry.setUrl ("#" + geom_name);
|
||||
for (std::vector<std::string>::const_iterator it = material_ids.begin(); it != material_ids.end(); ++it) {
|
||||
COLLADASW::InstanceMaterial material (*it, "#" + *it);
|
||||
foreach(std::string material_name, material_ids) {
|
||||
/// @todo This is done 6 times in this file, try to perform this once and be done with the material naming for the export.
|
||||
collada_id(material_name);
|
||||
COLLADASW::InstanceMaterial material (material_name, "#" + material_name);
|
||||
instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material);
|
||||
}
|
||||
instanceGeometry.add();
|
||||
@@ -192,9 +227,13 @@ void ColladaSerializer::ColladaExporter::ColladaScene::write() {
|
||||
scene.add();
|
||||
}
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material) {
|
||||
openEffect(collada_id(material.name()) + "-fx");
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material)
|
||||
{
|
||||
std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
|
||||
? material.original_name() : material.name());
|
||||
collada_id(material_name);
|
||||
openEffect(material_name + "-fx");
|
||||
COLLADASW::EffectProfile effect(mSW);
|
||||
effect.setShaderType(COLLADASW::EffectProfile::LAMBERT);
|
||||
if (material.hasDiffuse()) {
|
||||
@@ -223,7 +262,7 @@ void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() {
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) {
|
||||
if (!contains(material)) {
|
||||
effects.write(material);
|
||||
@@ -237,15 +276,19 @@ bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeo
|
||||
|
||||
void ColladaSerializer::ColladaExporter::ColladaMaterials::write() {
|
||||
effects.close();
|
||||
for (std::vector<IfcGeom::Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
|
||||
const std::string& material_name = collada_id((*it).name());
|
||||
foreach(const IfcGeom::Material& material, materials) {
|
||||
std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
|
||||
? material.original_name() : material.name());
|
||||
std::string material_name_unescaped = material_name; // workaround double-escaping that would occur in addInstanceEffect()
|
||||
IfcUtil::sanitate_material_name(material_name_unescaped);
|
||||
collada_id(material_name);
|
||||
openMaterial(material_name);
|
||||
addInstanceEffect("#" + material_name + "-fx");
|
||||
addInstanceEffect("#" + material_name_unescaped + "-fx");
|
||||
closeMaterial();
|
||||
}
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
|
||||
void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_name, float unit_magnitude) {
|
||||
stream.startDocument();
|
||||
|
||||
@@ -256,16 +299,28 @@ void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_n
|
||||
asset.add();
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::write(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& _materials) {
|
||||
void ColladaSerializer::ColladaExporter::write(const IfcGeom::TriangulationElement<real_t>* o)
|
||||
{
|
||||
const IfcGeom::Representation::Triangulation<real_t>& mesh = o->geometry();
|
||||
const std::string name = serializer->settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_GUIDS) ?
|
||||
o->guid() : (serializer->settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_NAMES) ? o->name() : o->unique_id());
|
||||
const std::string representation_id = "representation-" + boost::lexical_cast<std::string>(o->geometry().id());
|
||||
|
||||
std::vector<std::string> material_references;
|
||||
for (std::vector<IfcGeom::Material>::const_iterator it = _materials.begin(); it != _materials.end(); ++it) {
|
||||
const IfcGeom::Material& material = *it;
|
||||
foreach(const IfcGeom::Material& material, mesh.materials()) {
|
||||
if (!materials.contains(material)) {
|
||||
materials.add(material);
|
||||
}
|
||||
material_references.push_back(collada_id(material.name()));
|
||||
std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
|
||||
? material.original_name() : material.name());
|
||||
collada_id(material_name);
|
||||
material_references.push_back(material_name);
|
||||
}
|
||||
deferreds.push_back(DeferredObject(unique_id, representation_id, type, matrix, vertices, normals, faces, edges, material_ids, _materials, material_references));
|
||||
|
||||
deferreds.push_back(
|
||||
DeferredObject(name, representation_id, o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(),
|
||||
mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials(), material_references, mesh.uvs())
|
||||
);
|
||||
}
|
||||
|
||||
void ColladaSerializer::ColladaExporter::endDocument() {
|
||||
@@ -278,7 +333,7 @@ void ColladaSerializer::ColladaExporter::endDocument() {
|
||||
continue;
|
||||
}
|
||||
geometries_written.insert(it->representation_id);
|
||||
geometries.write(it->representation_id, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials);
|
||||
geometries.write(it->representation_id, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials, it->uvs);
|
||||
}
|
||||
geometries.close();
|
||||
for (std::vector<DeferredObject>::const_iterator it = deferreds.begin(); it != deferreds.end(); ++it) {
|
||||
@@ -288,7 +343,7 @@ void ColladaSerializer::ColladaExporter::endDocument() {
|
||||
scene.write();
|
||||
stream.endDocument();
|
||||
}
|
||||
|
||||
|
||||
bool ColladaSerializer::ready() {
|
||||
return true;
|
||||
}
|
||||
@@ -297,9 +352,8 @@ void ColladaSerializer::writeHeader() {
|
||||
exporter.startDocument(unit_name, unit_magnitude);
|
||||
}
|
||||
|
||||
void ColladaSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
|
||||
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
|
||||
exporter.write(o->unique_id(), "representation-" + boost::lexical_cast<std::string>(o->geometry().id()), o->type(), o->transformation().matrix().data(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials());
|
||||
void ColladaSerializer::write(const IfcGeom::TriangulationElement<real_t>* o) {
|
||||
exporter.write(o);
|
||||
}
|
||||
|
||||
void ColladaSerializer::finalize() {
|
||||
|
||||
@@ -27,17 +27,10 @@
|
||||
#pragma warning(disable : 4201 4512)
|
||||
#endif
|
||||
#include <COLLADASWStreamWriter.h>
|
||||
#include <COLLADASWPrimitves.h>
|
||||
#include <COLLADASWLibraryGeometries.h>
|
||||
#include <COLLADASWSource.h>
|
||||
#include <COLLADASWScene.h>
|
||||
#include <COLLADASWNode.h>
|
||||
#include <COLLADASWInstanceGeometry.h>
|
||||
#include <COLLADASWLibraryVisualScenes.h>
|
||||
#include <COLLADASWLibraryEffects.h>
|
||||
#include <COLLADASWLibraryMaterials.h>
|
||||
#include <COLLADASWBaseInputElement.h>
|
||||
#include <COLLADASWAsset.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
@@ -58,12 +51,19 @@ private:
|
||||
ColladaGeometries(const ColladaGeometries&); //N/A
|
||||
ColladaGeometries& operator =(const ColladaGeometries&); //N/A
|
||||
public:
|
||||
explicit ColladaGeometries(COLLADASW::StreamWriter& stream)
|
||||
explicit ColladaGeometries(COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer)
|
||||
: COLLADASW::LibraryGeometries(&stream)
|
||||
, serializer(_serializer)
|
||||
{}
|
||||
void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector<double>& floats, const char* coords = "XYZ");
|
||||
void write(const std::string mesh_id, const std::string& default_material_name, const std::vector<double>& positions, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials);
|
||||
void addFloatSource(const std::string& mesh_id, const std::string& suffix,
|
||||
const std::vector<real_t>& floats, const char* coords = "XYZ");
|
||||
void write(const std::string &mesh_id, const std::string& default_material_name,
|
||||
const std::vector<real_t>& positions, const std::vector<real_t>& normals,
|
||||
const std::vector<int>& faces, const std::vector<int>& edges,
|
||||
const std::vector<int> material_ids, const std::vector<IfcGeom::Material>& materials,
|
||||
const std::vector<real_t>& uvs);
|
||||
void close();
|
||||
ColladaSerializer *serializer;
|
||||
};
|
||||
class ColladaScene : public COLLADASW::LibraryVisualScenes
|
||||
{
|
||||
@@ -74,13 +74,16 @@ private:
|
||||
const std::string scene_id;
|
||||
bool scene_opened;
|
||||
public:
|
||||
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream)
|
||||
ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer)
|
||||
: COLLADASW::LibraryVisualScenes(&stream)
|
||||
, scene_id(scene_id)
|
||||
, scene_opened(false)
|
||||
, scene_opened(false)
|
||||
, serializer(_serializer)
|
||||
{}
|
||||
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector<std::string>& material_ids, const std::vector<double>& matrix);
|
||||
void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name,
|
||||
const std::vector<std::string>& material_ids, const std::vector<real_t>& matrix);
|
||||
void write();
|
||||
ColladaSerializer *serializer;
|
||||
};
|
||||
class ColladaMaterials : public COLLADASW::LibraryMaterials
|
||||
{
|
||||
@@ -97,32 +100,37 @@ private:
|
||||
{}
|
||||
void write(const IfcGeom::Material& material);
|
||||
void close();
|
||||
ColladaSerializer *serializer;
|
||||
};
|
||||
std::vector<IfcGeom::Material> materials;
|
||||
ColladaEffects effects;
|
||||
public:
|
||||
explicit ColladaMaterials(COLLADASW::StreamWriter& stream)
|
||||
explicit ColladaMaterials(COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer)
|
||||
: COLLADASW::LibraryMaterials(&stream)
|
||||
, effects(stream)
|
||||
, serializer(_serializer)
|
||||
{}
|
||||
void add(const IfcGeom::Material& material);
|
||||
bool contains(const IfcGeom::Material& material);
|
||||
void write();
|
||||
ColladaSerializer *serializer;
|
||||
ColladaEffects effects;
|
||||
};
|
||||
class DeferredObject {
|
||||
public:
|
||||
std::string unique_id, representation_id, type;
|
||||
std::vector<double> matrix;
|
||||
std::vector<double> vertices;
|
||||
std::vector<double> normals;
|
||||
std::vector<real_t> matrix;
|
||||
std::vector<real_t> vertices;
|
||||
std::vector<real_t> normals;
|
||||
std::vector<int> faces;
|
||||
std::vector<int> edges;
|
||||
std::vector<int> material_ids;
|
||||
std::vector<IfcGeom::Material> materials;
|
||||
std::vector<std::string> material_references;
|
||||
DeferredObject(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices,
|
||||
const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids,
|
||||
const std::vector<IfcGeom::Material>& materials, const std::vector<std::string>& material_references)
|
||||
std::vector<real_t> uvs;
|
||||
DeferredObject(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector<real_t>& matrix,
|
||||
const std::vector<real_t>& vertices, const std::vector<real_t>& normals, const std::vector<int>& faces,
|
||||
const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials,
|
||||
const std::vector<std::string>& material_references, const std::vector<real_t>& uvs)
|
||||
: unique_id(unique_id)
|
||||
, representation_id(representation_id)
|
||||
, type(type)
|
||||
@@ -134,39 +142,48 @@ private:
|
||||
, material_ids(material_ids)
|
||||
, materials(materials)
|
||||
, material_references(material_references)
|
||||
, uvs(uvs)
|
||||
{}
|
||||
};
|
||||
COLLADABU::NativeString filename;
|
||||
COLLADASW::StreamWriter stream;
|
||||
ColladaGeometries geometries;
|
||||
ColladaScene scene;
|
||||
ColladaMaterials materials;
|
||||
public:
|
||||
ColladaExporter(const std::string& scene_name, const std::string& fn)
|
||||
: filename(fn.c_str())
|
||||
, stream(filename)
|
||||
, geometries(stream)
|
||||
, scene(scene_name, stream)
|
||||
, materials(stream)
|
||||
{}
|
||||
ColladaExporter(const std::string& scene_name, const std::string& fn, ColladaSerializer *_serializer)
|
||||
: filename(fn)
|
||||
, stream(filename, sizeof(real_t) == sizeof(double)) // utilise Collada stream's double precision feature
|
||||
, geometries(stream, _serializer)
|
||||
, scene(scene_name, stream, _serializer)
|
||||
, materials(stream, _serializer)
|
||||
, serializer(_serializer)
|
||||
{
|
||||
}
|
||||
ColladaMaterials materials;
|
||||
ColladaSerializer *serializer;
|
||||
ColladaGeometries geometries;
|
||||
std::vector<DeferredObject> deferreds;
|
||||
virtual ~ColladaExporter() {}
|
||||
void startDocument(const std::string& unit_name, float unit_magnitude);
|
||||
void write(const std::string& unique_id, const std::string& representation_id, const std::string& type, const std::vector<double>& matrix, const std::vector<double>& vertices, const std::vector<double>& normals, const std::vector<int>& faces, const std::vector<int>& edges, const std::vector<int>& material_ids, const std::vector<IfcGeom::Material>& materials);
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* o);
|
||||
void endDocument();
|
||||
};
|
||||
ColladaExporter exporter;
|
||||
std::string unit_name;
|
||||
float unit_magnitude;
|
||||
public:
|
||||
ColladaSerializer(const std::string& dae_filename)
|
||||
: GeometrySerializer()
|
||||
, exporter("IfcOpenShell", dae_filename)
|
||||
{}
|
||||
ColladaSerializer(const std::string& dae_filename, const IfcGeom::IteratorSettings &settings)
|
||||
: GeometrySerializer(settings)
|
||||
, exporter("IfcOpenShell", dae_filename, this)
|
||||
{
|
||||
exporter.serializer = this;
|
||||
exporter.materials.serializer = this;
|
||||
exporter.materials.effects.serializer = this;
|
||||
exporter.geometries.serializer = this;
|
||||
}
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
void write(const IfcGeom::TriangulationElement<double>* o);
|
||||
void write(const IfcGeom::BRepElement<double>* /*o*/) {}
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* o);
|
||||
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
|
||||
void finalize();
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& name, float magnitude) {
|
||||
|
||||
@@ -20,17 +20,30 @@
|
||||
#ifndef GEOMETRYSERIALIZER_H
|
||||
#define GEOMETRYSERIALIZER_H
|
||||
|
||||
#ifdef IFCCONVERT_DOUBLE_PRECISION
|
||||
typedef double real_t;
|
||||
#else
|
||||
typedef float real_t;
|
||||
#endif
|
||||
|
||||
#include "../ifcconvert/Serializer.h"
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
class GeometrySerializer : public Serializer {
|
||||
public:
|
||||
GeometrySerializer(const IfcGeom::IteratorSettings &settings) : settings_(settings) {}
|
||||
virtual ~GeometrySerializer() {}
|
||||
|
||||
virtual bool isTesselated() const = 0;
|
||||
virtual void write(const IfcGeom::TriangulationElement<double>* o) = 0;
|
||||
virtual void write(const IfcGeom::BRepElement<double>* o) = 0;
|
||||
virtual void write(const IfcGeom::TriangulationElement<real_t>* o) = 0;
|
||||
virtual void write(const IfcGeom::BRepElement<real_t>* o) = 0;
|
||||
virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0;
|
||||
|
||||
const IfcGeom::IteratorSettings& settings() const { return settings_; }
|
||||
IfcGeom::IteratorSettings& settings() { return settings_; }
|
||||
|
||||
protected:
|
||||
IfcGeom::IteratorSettings settings_;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+245
-113
@@ -26,16 +26,6 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <time.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/ColladaSerializer.h"
|
||||
#include "../ifcconvert/IgesSerializer.h"
|
||||
#include "../ifcconvert/StepSerializer.h"
|
||||
@@ -43,35 +33,58 @@
|
||||
#include "../ifcconvert/XmlSerializer.h"
|
||||
#include "../ifcconvert/SvgSerializer.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include <IGESControl_Controller.hxx>
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/optional/optional_io.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <time.h>
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
static std::string DEFAULT_EXTENSION = "obj";
|
||||
const std::string DEFAULT_EXTENSION = "obj";
|
||||
const std::string TEMP_FILE_EXTENSION = ".tmp";
|
||||
|
||||
void printVersion() {
|
||||
std::cerr << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << std::endl;
|
||||
void print_version()
|
||||
{
|
||||
/// @todo Why cerr used for info prints? Change to cout.
|
||||
std::cerr << "IfcOpenShell " << IfcSchema::Identifier << " IfcConvert " << IFCOPENSHELL_VERSION << std::endl;
|
||||
}
|
||||
|
||||
void printUsage(const boost::program_options::options_description& generic_options, const boost::program_options::options_description& geom_options) {
|
||||
printVersion();
|
||||
std::cerr << "Usage: IfcConvert [options] <input.ifc> [<output>]" << std::endl
|
||||
<< std::endl
|
||||
<< "Converts the geometry in an IFC file into one of the following formats:" << std::endl
|
||||
<< " .obj WaveFront OBJ (a .mtl file is also created)" << std::endl;
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
std::cerr << " .dae Collada Digital Asset Exchange" << std::endl;
|
||||
void print_usage(bool suggest_help = true)
|
||||
{
|
||||
std::cerr << "Usage: IfcConvert [options] <input.ifc> [<output>]" << "\n"
|
||||
<< "\n"
|
||||
<< "Converts the geometry in an IFC file into one of the following formats:" << "\n"
|
||||
<< " .obj WaveFront OBJ (a .mtl file is also created)" << "\n"
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
<< " .dae Collada Digital Assets Exchange" << "\n"
|
||||
#endif
|
||||
std::cerr << " .stp STEP Standard for the Exchange of Product Data" << std::endl
|
||||
<< " .igs IGES Initial Graphics Exchange Specification" << std::endl
|
||||
<< " .xml XML Property definitions and decomposition tree" << std::endl
|
||||
<< " .svg SVG Scalable Vector Graphics (2d floor plan)" << std::endl
|
||||
<< std::endl
|
||||
<< "Command line options" << std::endl << generic_options << std::endl
|
||||
<< "Advanced options" << std::endl << geom_options << std::endl;
|
||||
<< " .stp STEP Standard for the Exchange of Product Data" << "\n"
|
||||
<< " .igs IGES Initial Graphics Exchange Specification" << "\n"
|
||||
<< " .xml XML Property definitions and decomposition tree" << "\n"
|
||||
<< " .svg SVG Scalable Vector Graphics (2D floor plan)" << "\n"
|
||||
<< "\n"
|
||||
<< "If no output filename given, <input>." + DEFAULT_EXTENSION + " will be used as the output file.\n";
|
||||
if (suggest_help) {
|
||||
std::cerr << "\nRun 'IfcConvert --help' for more information.";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
void print_options(const boost::program_options::options_description& options)
|
||||
{
|
||||
std::cerr << "\n" << options;
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
std::string change_extension(const std::string& fn, const std::string& ext) {
|
||||
@@ -83,24 +96,41 @@ std::string change_extension(const std::string& fn, const std::string& ext) {
|
||||
}
|
||||
}
|
||||
|
||||
bool file_exists(const std::string& filename)
|
||||
{
|
||||
/// @todo Windows Unicode support
|
||||
std::ifstream file(filename.c_str());
|
||||
return file.good();
|
||||
}
|
||||
|
||||
bool rename_file(const std::string& old_filename, const std::string& new_filename)
|
||||
{
|
||||
// Whether or not rename() replaces an existing file is implementation-specific,
|
||||
// so remove() possible existing file always.
|
||||
/// @todo Windows Unicode support
|
||||
std::remove(new_filename.c_str());
|
||||
return std::rename(old_filename.c_str(), new_filename.c_str()) == 0;
|
||||
}
|
||||
|
||||
static std::stringstream log_stream;
|
||||
void write_log();
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
boost::program_options::options_description generic_options;
|
||||
boost::program_options::options_description generic_options("Command line options");
|
||||
generic_options.add_options()
|
||||
("help", "display usage information")
|
||||
("help,h", "display usage information")
|
||||
("version", "display version information")
|
||||
("verbose,v", "more verbose output");
|
||||
("verbose,v", "more verbose output")
|
||||
("yes,y", "answer 'yes' automatically to possible confirmation queries (e.g overwriting an existing output file)");
|
||||
|
||||
boost::program_options::options_description fileio_options;
|
||||
fileio_options.add_options()
|
||||
("input-file", boost::program_options::value<std::string>(), "input IFC file")
|
||||
("output-file", boost::program_options::value<std::string>(), "output geometry file");
|
||||
|
||||
std::string bounds;
|
||||
std::vector<std::string> entity_vector;
|
||||
boost::program_options::options_description geom_options;
|
||||
std::vector<std::string> entity_vector, names;
|
||||
double deflection_tolerance;
|
||||
boost::program_options::options_description geom_options("Geometry options");
|
||||
geom_options.add_options()
|
||||
("plan",
|
||||
"Specifies whether to include curves in the output result. Typically "
|
||||
@@ -142,20 +172,51 @@ int main(int argc, char** argv) {
|
||||
("disable-opening-subtractions",
|
||||
"Specifies whether to disable the boolean subtraction of "
|
||||
"IfcOpeningElement Representations from their RelatingElements.")
|
||||
("bounds", boost::program_options::value<std::string>(&bounds),
|
||||
"Specifies the bounding rectangle, for example 512x512, to which the "
|
||||
"output will be scaled. Only used when converting to SVG.")
|
||||
("include",
|
||||
"Specifies that the entities listed after --entities are to be included")
|
||||
"Specifies that the entities listed after --entities or --names are to be included")
|
||||
("exclude",
|
||||
"Specifies that the entities listed after --entities are to be excluded")
|
||||
("entities", boost::program_options::value< std::vector<std::string> >(&entity_vector)->multitoken(),
|
||||
"Specifies that the entities listed after --entities or --names are to be excluded")
|
||||
("entities", boost::program_options::value< std::vector<std::string> >(&entity_vector)->multitoken(),
|
||||
"A list of entities that should be included in or excluded from the "
|
||||
"geometrical output, depending on whether --ignore or --include is "
|
||||
"specified. Defaults to IfcOpeningElement and IfcSpace to be excluded.");
|
||||
|
||||
"geometrical output, depending on whether --exclude or --include is specified. "
|
||||
"Defaults to IfcOpeningElement and IfcSpace to be excluded. SVG output defaults "
|
||||
"to IfcSpace to be included."
|
||||
"The names are handled case-insensitively. Cannot be placed right before input file argument.")
|
||||
("names", boost::program_options::value< std::vector<std::string> >(&names)->multitoken(),
|
||||
"A list of names or wildcard patterns that should be included in or excluded from the "
|
||||
"geometrical output, depending on whether --exclude or --include is specified. "
|
||||
"The names are handled case-sensitively. Cannot be placed right before input file argument.")
|
||||
("no-normals",
|
||||
"Disables computation of normals. Saves time and file size and is useful "
|
||||
"in instances where you're going to recompute normals for the exported "
|
||||
"model in other modelling application in any case.")
|
||||
("deflection-tolerance", boost::program_options::value<double>(&deflection_tolerance),
|
||||
"Sets the deflection tolerance of the mesher, 1e-3 by default if not specified.")
|
||||
("generate-uvs",
|
||||
"Generates UVs (texture coordinates) by using simple box projection. Requires normals. "
|
||||
"Not guaranteed to work properly if used with --weld-vertices.");
|
||||
|
||||
std::string bounds;
|
||||
boost::program_options::options_description serializer_options("Serialization options");
|
||||
serializer_options.add_options()
|
||||
("bounds", boost::program_options::value<std::string>(&bounds),
|
||||
"Specifies the bounding rectangle, for example 512x512, to which the "
|
||||
"output will be scaled. Only used when converting to SVG.")
|
||||
("use-element-names",
|
||||
"Use entity names instead of unique IDs for naming elements upon serialization. "
|
||||
"Applicable for OBJ, DAE, and SVG output.")
|
||||
("use-element-guids",
|
||||
"Use entity GUIDs instead of unique IDs for naming elements upon serialization. "
|
||||
"Applicable for OBJ, DAE, and SVG output.")
|
||||
("use-material-names",
|
||||
"Use material names instead of unique IDs for naming materials upon serialization. "
|
||||
"Applicable for OBJ and DAE output.")
|
||||
("center-model",
|
||||
"Centers the elements upon serialization by applying the center point of "
|
||||
"all placements as an offset. Applicable for OBJ and DAE output.");
|
||||
|
||||
boost::program_options::options_description cmdline_options;
|
||||
cmdline_options.add(generic_options).add(fileio_options).add(geom_options);
|
||||
cmdline_options.add(generic_options).add(fileio_options).add(geom_options).add(serializer_options);
|
||||
|
||||
boost::program_options::positional_options_description positional_options;
|
||||
positional_options.add("input-file", 1);
|
||||
@@ -167,21 +228,30 @@ int main(int argc, char** argv) {
|
||||
options(cmdline_options).positional(positional_options).run(), vmap);
|
||||
} catch (const boost::program_options::unknown_option& e) {
|
||||
std::cerr << "[Error] Unknown option '" << e.get_option_name() << "'" << std::endl << std::endl;
|
||||
// Usage information will be emitted below
|
||||
print_usage();
|
||||
return 1;
|
||||
} catch (...) {
|
||||
// Catch other errors such as invalid command line syntax
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
boost::program_options::notify(vmap);
|
||||
|
||||
if (vmap.count("version")) {
|
||||
printVersion();
|
||||
return 0;
|
||||
} else if (vmap.count("help") || !vmap.count("input-file")) {
|
||||
printUsage(generic_options, geom_options);
|
||||
return vmap.count("help") ? 0 : 1;
|
||||
print_version();
|
||||
|
||||
if (vmap.count("version")) {
|
||||
return 0;
|
||||
} else if (vmap.count("help")) {
|
||||
print_usage(false);
|
||||
print_options(generic_options.add(geom_options).add(serializer_options));
|
||||
return 0;
|
||||
} else if (!vmap.count("input-file")) {
|
||||
std::cerr << "[Error] Input file not specified" << std::endl;
|
||||
print_usage();
|
||||
return 1;
|
||||
} else if (vmap.count("include") && vmap.count("exclude")) {
|
||||
std::cerr << "[Error] --include and --ignore can not be specified together" << std::endl;
|
||||
printUsage(generic_options, geom_options);
|
||||
std::cerr << "[Error] --include and --exclude can not be specified together" << std::endl;
|
||||
print_options(geom_options);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -197,6 +267,13 @@ int main(int argc, char** argv) {
|
||||
bool include_entities = vmap.count("include") != 0;
|
||||
const bool include_plan = vmap.count("plan") != 0;
|
||||
const bool include_model = vmap.count("model") != 0 || (!include_plan);
|
||||
const bool use_element_names = vmap.count("use-element-names") != 0;
|
||||
const bool use_element_guids = vmap.count("use-element-guids") != 0 ;
|
||||
const bool use_material_names = vmap.count("use-material-names") != 0;
|
||||
const bool no_normals = vmap.count("no-normals") != 0 ;
|
||||
bool center_model = vmap.count("center-model") != 0 ;
|
||||
const bool generate_uvs = vmap.count("generate-uvs") != 0 ;
|
||||
const bool deflection_tolerance_specified = vmap.count("deflection-tolerance") != 0 ;
|
||||
boost::optional<int> bounding_width, bounding_height;
|
||||
if (vmap.count("bounds") == 1) {
|
||||
int w, h;
|
||||
@@ -205,19 +282,20 @@ int main(int argc, char** argv) {
|
||||
bounding_height = h;
|
||||
} else {
|
||||
std::cerr << "[Error] Invalid use of --bounds" << std::endl;
|
||||
printUsage(generic_options, geom_options);
|
||||
print_options(serializer_options);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the set ifc types to be ignored from the command line.
|
||||
std::set<std::string> entities;
|
||||
for (std::vector<std::string>::const_iterator it = entity_vector.begin(); it != entity_vector.end(); ++it) {
|
||||
const std::string& mixed_case_type = *it;
|
||||
entities.insert(boost::to_lower_copy(mixed_case_type));
|
||||
}
|
||||
|
||||
std::set<std::string> entities(entity_vector.begin(), entity_vector.end());
|
||||
|
||||
const std::string input_filename = vmap["input-file"].as<std::string>();
|
||||
if (!file_exists(input_filename)) {
|
||||
std::cerr << "[Error] Input file '" << input_filename << "' does not exist" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If no output filename is specified a Wavefront OBJ file will be output
|
||||
// to maintain backwards compatibility with the obsolete IfcObj executable.
|
||||
const std::string output_filename = vmap.count("output-file") == 1
|
||||
@@ -225,21 +303,32 @@ int main(int argc, char** argv) {
|
||||
: change_extension(input_filename, DEFAULT_EXTENSION);
|
||||
|
||||
if (output_filename.size() < 5) {
|
||||
printUsage(generic_options, geom_options);
|
||||
std::cerr << "[Error] Invalid or unsupported output file '" << output_filename << "' given" << std::endl;
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (file_exists(output_filename) && !vmap.count("yes")) {
|
||||
std::string answer;
|
||||
std::cout << "A file '" << output_filename << "' already exists. Overwrite the existing file?" << std::endl;
|
||||
std::cin >> answer;
|
||||
if (!boost::iequals(answer, "yes") && !boost::iequals(answer, "y")) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string output_temp_filename = output_filename + TEMP_FILE_EXTENSION;
|
||||
|
||||
std::string output_extension = output_filename.substr(output_filename.size()-4);
|
||||
boost::to_lower(output_extension);
|
||||
|
||||
// If no entities are specified these are the defaults to skip from output
|
||||
if (entity_vector.empty()) {
|
||||
// If no entity or names filters are specified these are the defaults to skip from output
|
||||
if (entities.empty() && names.empty()) {
|
||||
entities.insert("IfcSpace");
|
||||
if (output_extension == ".svg") {
|
||||
entities.insert("ifcspace");
|
||||
include_entities = true;
|
||||
} else {
|
||||
entities.insert("ifcopeningelement");
|
||||
entities.insert("ifcspace");
|
||||
entities.insert("IfcOpeningElement");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,13 +338,14 @@ int main(int argc, char** argv) {
|
||||
if (output_extension == ".xml") {
|
||||
int exit_code = 1;
|
||||
try {
|
||||
XmlSerializer s(output_filename);
|
||||
XmlSerializer s(output_temp_filename);
|
||||
IfcParse::IfcFile f;
|
||||
if (!f.Init(input_filename)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file");
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse input file '" + input_filename + "'");
|
||||
} else {
|
||||
s.setFile(&f);
|
||||
s.finalize();
|
||||
rename_file(output_temp_filename, output_filename);
|
||||
exit_code = 0;
|
||||
}
|
||||
} catch (...) {}
|
||||
@@ -264,7 +354,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
|
||||
/// @todo Make APPLY_DEFAULT_MATERIALS configurable? Quickly tested setting this to false and using obj exporter caused the program to crash and burn.
|
||||
settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, weld_vertices);
|
||||
@@ -276,56 +366,70 @@ int main(int argc, char** argv) {
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions);
|
||||
settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan);
|
||||
settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model);
|
||||
settings.set(IfcGeom::IteratorSettings::USE_ELEMENT_NAMES, use_element_names);
|
||||
settings.set(IfcGeom::IteratorSettings::USE_ELEMENT_GUIDS, use_element_guids);
|
||||
settings.set(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES, use_material_names);
|
||||
settings.set(IfcGeom::IteratorSettings::NO_NORMALS, no_normals);
|
||||
settings.set(IfcGeom::IteratorSettings::CENTER_MODEL, center_model);
|
||||
settings.set(IfcGeom::IteratorSettings::GENERATE_UVS, generate_uvs);
|
||||
if (deflection_tolerance_specified) {
|
||||
settings.set_deflection_tolerance(deflection_tolerance);
|
||||
}
|
||||
|
||||
GeometrySerializer* serializer;
|
||||
if (output_extension == ".obj") {
|
||||
const std::string mtl_filename = output_filename.substr(0,output_filename.size()-3) + "mtl";
|
||||
const std::string mtl_temp_filename = change_extension(output_filename, "mtl") + TEMP_FILE_EXTENSION;
|
||||
if (!use_world_coords) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Using world coords when writing WaveFront OBJ files");
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
|
||||
}
|
||||
serializer = new WaveFrontOBJSerializer(output_filename, mtl_filename);
|
||||
serializer = new WaveFrontOBJSerializer(output_temp_filename, mtl_temp_filename, settings);
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
} else if (output_extension == ".dae") {
|
||||
serializer = new ColladaSerializer(output_filename);
|
||||
serializer = new ColladaSerializer(output_temp_filename, settings);
|
||||
#endif
|
||||
} else if (output_extension == ".stp") {
|
||||
serializer = new StepSerializer(output_filename);
|
||||
serializer = new StepSerializer(output_temp_filename, settings);
|
||||
} else if (output_extension == ".igs") {
|
||||
// Not sure why this is needed, but it is.
|
||||
// See: http://tracker.dev.opencascade.org/view.php?id=23679
|
||||
IGESControl_Controller::Init();
|
||||
serializer = new IgesSerializer(output_filename);
|
||||
IGESControl_Controller::Init(); // work around Open Cascade bug
|
||||
serializer = new IgesSerializer(output_temp_filename, settings);
|
||||
} else if (output_extension == ".svg") {
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
serializer = new SvgSerializer(output_filename);
|
||||
serializer = new SvgSerializer(output_temp_filename, settings);
|
||||
if (bounding_width && bounding_height) {
|
||||
((SvgSerializer*) serializer)->setBoundingRectangle(
|
||||
static_cast<double>(*bounding_width),
|
||||
static_cast<double>(*bounding_height)
|
||||
);
|
||||
static_cast<SvgSerializer*>(serializer)->setBoundingRectangle(*bounding_width, *bounding_height);
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension");
|
||||
Logger::Message(Logger::LOG_ERROR, "Unknown output filename extension '" + output_extension + "'");
|
||||
write_log();
|
||||
printUsage(generic_options, geom_options);
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!serializer->isTesselated()) {
|
||||
const bool is_tesselated = serializer->isTesselated(); // isTesselated() doesn't change at run-time
|
||||
if (!is_tesselated) {
|
||||
if (weld_vertices) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Weld vertices setting ignored when writing STEP or IGES files");
|
||||
Logger::Message(Logger::LOG_NOTICE, "Weld vertices setting ignored when writing non-tesselated output");
|
||||
}
|
||||
settings.disable_triangulation() = true;
|
||||
if (generate_uvs) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Generate UVs setting ignored when writing non-tesselated output");
|
||||
}
|
||||
if (center_model) {
|
||||
Logger::Message(Logger::LOG_NOTICE, "Center model setting ignored when writing non-tesselated output");
|
||||
}
|
||||
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
}
|
||||
|
||||
IfcGeom::Iterator<double> context_iterator(settings, input_filename);
|
||||
IfcGeom::Iterator<real_t> context_iterator(settings, input_filename);
|
||||
|
||||
try {
|
||||
if (include_entities) {
|
||||
context_iterator.includeEntities(entities);
|
||||
context_iterator.include_entity_names(names);
|
||||
} else {
|
||||
context_iterator.excludeEntities(entities);
|
||||
context_iterator.exclude_entity_names(names);
|
||||
}
|
||||
} catch (const IfcParse::IfcException& e) {
|
||||
std::cout << "[Error] " << e.what() << std::endl;
|
||||
@@ -333,7 +437,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
if (!serializer->ready()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to open output file for writing");
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to open output '" + output_filename + "' file for writing");
|
||||
write_log();
|
||||
return 1;
|
||||
}
|
||||
@@ -342,26 +446,25 @@ int main(int argc, char** argv) {
|
||||
time(&start);
|
||||
|
||||
if (!context_iterator.initialize()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse .ifc file or no geometrical entities found");
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to parse input file '" + input_filename + "' or no geometrical entities found");
|
||||
write_log();
|
||||
return 1;
|
||||
}
|
||||
|
||||
serializer->setFile(context_iterator.getFile());
|
||||
serializer->setFile(context_iterator.getFile());
|
||||
|
||||
if (convert_back_units) {
|
||||
serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<const float>(context_iterator.getUnitMagnitude()));
|
||||
serializer->setUnitNameAndMagnitude(context_iterator.getUnitName(), static_cast<float>(context_iterator.getUnitMagnitude()));
|
||||
} else {
|
||||
serializer->setUnitNameAndMagnitude("METER", 1.0f);
|
||||
}
|
||||
|
||||
serializer->writeHeader();
|
||||
|
||||
std::set<std::string> materials;
|
||||
|
||||
int old_progress = -1;
|
||||
Logger::Status("Creating geometry...");
|
||||
|
||||
std::vector<IfcGeom::Element<real_t>* > geometries;
|
||||
// The functions IfcGeom::Iterator::get() and IfcGeom::Iterator::next()
|
||||
// wrap an iterator of all geometrical products in the Ifc file.
|
||||
// IfcGeom::Iterator::get() returns an IfcGeom::TriangulationElement or
|
||||
@@ -373,30 +476,60 @@ int main(int argc, char** argv) {
|
||||
// true return value guarantees that a successfully processed product is
|
||||
// available.
|
||||
do {
|
||||
const IfcGeom::Element<double>* geom_object = context_iterator.get();
|
||||
|
||||
if (serializer->isTesselated()) {
|
||||
serializer->write(static_cast<const IfcGeom::TriangulationElement<double>*>(geom_object));
|
||||
} else {
|
||||
serializer->write(static_cast<const IfcGeom::BRepElement<double>*>(geom_object));
|
||||
}
|
||||
|
||||
const int progress = context_iterator.progress() / 2;
|
||||
if (old_progress!= progress) Logger::ProgressBar(progress);
|
||||
old_progress = progress;
|
||||
|
||||
} while (context_iterator.next());
|
||||
IfcGeom::Element<real_t> *geom_object = context_iterator.get(true); // true == take ownership, we will clean up ourselves
|
||||
geometries.push_back(geom_object);
|
||||
const int progress = context_iterator.progress() / 2;
|
||||
if (old_progress != progress) Logger::ProgressBar(progress);
|
||||
old_progress = progress;
|
||||
} while (context_iterator.next());
|
||||
|
||||
Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(geometries.size()) +
|
||||
" objects) ");
|
||||
|
||||
if (center_model) {
|
||||
double* offset = serializer->settings().offset;
|
||||
gp_XYZ center = (context_iterator.bounds_min() + context_iterator.bounds_max()) * 0.5;
|
||||
offset[0] = -center.X();
|
||||
offset[1] = -center.Y();
|
||||
offset[2] = -center.Z();
|
||||
//printf("Bounds min. (%g, %g, %g)\n", context_iterator.bounds_min().X(), context_iterator.bounds_min().Y(), context_iterator.bounds_min().Z());
|
||||
//printf("Bounds max. (%g, %g, %g)\n", context_iterator.bounds_min().X(), context_iterator.bounds_min().X(), context_iterator.bounds_min().Z());
|
||||
printf("Using model offset (%g, %g, %g)\n", offset[0], offset[1], offset[2]); //TODO Logger::Message(Logger::LOG_NOTICE, ...);
|
||||
}
|
||||
|
||||
Logger::Status("Serializing geometry...");
|
||||
|
||||
foreach(const IfcGeom::Element<real_t>* geom, geometries) {
|
||||
if (is_tesselated) {
|
||||
serializer->write(static_cast<const IfcGeom::TriangulationElement<real_t>*>(geom));
|
||||
} else {
|
||||
serializer->write(static_cast<const IfcGeom::BRepElement<real_t>*>(geom));
|
||||
}
|
||||
delete geom;
|
||||
}
|
||||
|
||||
serializer->finalize();
|
||||
|
||||
Logger::Status("\rDone serializing geometry ");
|
||||
|
||||
delete serializer;
|
||||
|
||||
Logger::Status("\rDone creating geometry ");
|
||||
rename_file(output_temp_filename, output_filename);
|
||||
|
||||
if (output_extension == ".obj") {
|
||||
std::string mtl_filename = change_extension(output_filename, "mtl");
|
||||
std::string mtl_tmp_filename = mtl_filename + TEMP_FILE_EXTENSION;
|
||||
rename_file(mtl_tmp_filename, mtl_filename);
|
||||
}
|
||||
|
||||
write_log();
|
||||
|
||||
time(&end);
|
||||
int dif = (int) difftime (end,start);
|
||||
printf ("\nConversion took %d seconds\n", dif );
|
||||
int seconds = (int)difftime(end, start);
|
||||
if (seconds < 60)
|
||||
printf("\nConversion took %d seconds\n", seconds); // TODO Logger::Message(Logger::LOG_NOTICE, ...);
|
||||
else
|
||||
printf("\nConversion took %d minute(s) %d seconds\n", seconds/60, seconds%60); // TODO Logger::Message(Logger::LOG_NOTICE, ...);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -404,7 +537,6 @@ int main(int argc, char** argv) {
|
||||
void write_log() {
|
||||
std::string log = log_stream.str();
|
||||
if (!log.empty()) {
|
||||
std::cerr << std::endl << "Log:" << std::endl;
|
||||
std::cerr << log << std::endl;
|
||||
std::cerr << "\n" << "Log:\n" << log << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,20 +20,20 @@
|
||||
#ifndef IGESSERIALIZER_H
|
||||
#define IGESSERIALIZER_H
|
||||
|
||||
#include "OpenCascadeBasedSerializer.h"
|
||||
|
||||
#include <IGESControl_Writer.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/OpenCascadeBasedSerializer.h"
|
||||
|
||||
class IgesSerializer : public OpenCascadeBasedSerializer
|
||||
{
|
||||
private:
|
||||
IGESControl_Writer writer;
|
||||
IGESControl_Writer writer;
|
||||
public:
|
||||
explicit IgesSerializer(const std::string& out_filename)
|
||||
: OpenCascadeBasedSerializer(out_filename)
|
||||
/// @note IGESControl_Controller::Init() must be called prior to instantiating IgesSerializer.
|
||||
/// See http://tracker.dev.opencascade.org/view.php?id=23679 for more information.
|
||||
IgesSerializer(const std::string& out_filename, const IfcGeom::IteratorSettings &settings)
|
||||
: OpenCascadeBasedSerializer(out_filename, settings)
|
||||
{}
|
||||
virtual ~IgesSerializer() {}
|
||||
void writeShape(const TopoDS_Shape& shape) {
|
||||
@@ -51,4 +51,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -36,14 +36,14 @@ bool OpenCascadeBasedSerializer::ready() {
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<double>* o) {
|
||||
void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement<real_t>* o) {
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) {
|
||||
gp_GTrsf gtrsf = it->Placement();
|
||||
|
||||
const gp_Trsf& o_trsf = o->transformation().data();
|
||||
gtrsf.PreMultiply(o_trsf);
|
||||
|
||||
if (o->geometry().settings().convert_back_units()) {
|
||||
if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) {
|
||||
gp_Trsf scale;
|
||||
scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude());
|
||||
gtrsf.PreMultiply(scale);
|
||||
|
||||
@@ -31,18 +31,18 @@ protected:
|
||||
const std::string out_filename;
|
||||
const char* getSymbolForUnitMagnitude(float mag);
|
||||
public:
|
||||
explicit OpenCascadeBasedSerializer(const std::string& out_filename)
|
||||
: GeometrySerializer()
|
||||
explicit OpenCascadeBasedSerializer(const std::string& out_filename, const IfcGeom::IteratorSettings &settings)
|
||||
: GeometrySerializer(settings)
|
||||
, out_filename(out_filename)
|
||||
{}
|
||||
virtual ~OpenCascadeBasedSerializer() {}
|
||||
void writeHeader() {}
|
||||
bool ready();
|
||||
virtual void writeShape(const TopoDS_Shape& shape) = 0;
|
||||
void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
|
||||
void write(const IfcGeom::BRepElement<double>* o);
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
|
||||
void write(const IfcGeom::BRepElement<real_t>* o);
|
||||
bool isTesselated() const { return false; }
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -32,8 +32,8 @@ class StepSerializer : public OpenCascadeBasedSerializer
|
||||
private:
|
||||
STEPControl_Writer writer;
|
||||
public:
|
||||
explicit StepSerializer(const std::string& out_filename)
|
||||
: OpenCascadeBasedSerializer(out_filename)
|
||||
explicit StepSerializer(const std::string& out_filename, const IfcGeom::IteratorSettings &settings)
|
||||
: OpenCascadeBasedSerializer(out_filename, settings)
|
||||
{}
|
||||
virtual ~StepSerializer() {}
|
||||
void writeShape(const TopoDS_Shape& shape) {
|
||||
|
||||
@@ -168,7 +168,8 @@ SvgSerializer::path_object& SvgSerializer::start_path(IfcSchema::IfcBuildingStor
|
||||
return p;
|
||||
}
|
||||
|
||||
void SvgSerializer::write(const IfcGeom::BRepElement<double>* o) {
|
||||
void SvgSerializer::write(const IfcGeom::BRepElement<real_t>* o)
|
||||
{
|
||||
IfcSchema::IfcBuildingStorey* storey = 0;
|
||||
IfcSchema::IfcObjectDefinition* obdef = static_cast<IfcSchema::IfcObjectDefinition*>(file->entityById(o->id()));
|
||||
|
||||
@@ -340,10 +341,14 @@ void SvgSerializer::writeHeader() {
|
||||
svg_file << "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
|
||||
}
|
||||
|
||||
std::string SvgSerializer::nameElement(const IfcGeom::Element<double>* elem) {
|
||||
std::string SvgSerializer::nameElement(const IfcGeom::Element<real_t>* elem)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
const std::string type = "product";
|
||||
oss << "id=\"" << type << "-" << elem->unique_id() << "\"";
|
||||
const std::string name = (settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_GUIDS)
|
||||
? elem->guid() : (settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_NAMES)
|
||||
? elem->name() : elem->unique_id()));
|
||||
oss << "id=\"" << type << "-" << name<< "\"";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
@@ -352,4 +357,4 @@ std::string SvgSerializer::nameElement(const IfcSchema::IfcProduct* elem) {
|
||||
const std::string type = elem->is(IfcSchema::Type::IfcBuildingStorey) ? "storey" : "product";
|
||||
oss << "id=\"product-" << IfcParse::IfcGlobalId(elem->GlobalId()).formatted() << "\"";
|
||||
return oss.str();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,15 +22,13 @@
|
||||
#ifndef SVGSERIALIZER_H
|
||||
#define SVGSERIALIZER_H
|
||||
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
#include "../ifcconvert/util.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
|
||||
#include "../ifcgeom/IfcGeomIterator.h"
|
||||
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
#include "../ifcconvert/util.h"
|
||||
|
||||
class SvgSerializer : public GeometrySerializer {
|
||||
public:
|
||||
typedef std::pair<std::string, std::vector<util::string_buffer> > path_object;
|
||||
@@ -45,8 +43,8 @@ protected:
|
||||
std::vector< boost::shared_ptr<util::string_buffer::float_item> > radii;
|
||||
IfcParse::IfcFile* file;
|
||||
public:
|
||||
explicit SvgSerializer(const std::string& out_filename)
|
||||
: GeometrySerializer()
|
||||
SvgSerializer(const std::string& out_filename, const IfcGeom::IteratorSettings &settings)
|
||||
: GeometrySerializer(settings)
|
||||
, svg_file(out_filename.c_str())
|
||||
, xmin(+std::numeric_limits<double>::infinity())
|
||||
, xmax(-std::numeric_limits<double>::infinity())
|
||||
@@ -55,25 +53,24 @@ public:
|
||||
, rescale(false)
|
||||
, file(0)
|
||||
{}
|
||||
virtual void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
|
||||
virtual void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
|
||||
virtual void addSizeComponent(const boost::shared_ptr<util::string_buffer::float_item>& fi) { radii.push_back(fi); }
|
||||
virtual void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; }
|
||||
virtual ~SvgSerializer() {}
|
||||
virtual void writeHeader();
|
||||
virtual bool ready();
|
||||
virtual void write(const IfcGeom::TriangulationElement<double>* /*o*/) {}
|
||||
virtual void write(const IfcGeom::BRepElement<double>* o);
|
||||
virtual void write(path_object& p, const TopoDS_Wire& wire);
|
||||
virtual path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id);
|
||||
virtual bool isTesselated() const { return false; }
|
||||
virtual void finalize();
|
||||
virtual void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
||||
virtual void setFile(IfcParse::IfcFile* f) { file = f; }
|
||||
virtual void setBoundingRectangle(double width, double height);
|
||||
virtual void setSectionHeight(double h) { section_height = h; }
|
||||
virtual std::string nameElement(const IfcGeom::Element<double>* elem);
|
||||
virtual std::string nameElement(const IfcSchema::IfcProduct* elem);
|
||||
void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
|
||||
void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
|
||||
void addSizeComponent(const boost::shared_ptr<util::string_buffer::float_item>& fi) { radii.push_back(fi); }
|
||||
void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; }
|
||||
void writeHeader();
|
||||
bool ready();
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* /*o*/) {}
|
||||
void write(const IfcGeom::BRepElement<real_t>* o);
|
||||
void write(path_object& p, const TopoDS_Wire& wire);
|
||||
path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id);
|
||||
bool isTesselated() const { return false; }
|
||||
void finalize();
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
||||
void setFile(IfcParse::IfcFile* f) { file = f; }
|
||||
void setBoundingRectangle(double width, double height);
|
||||
void setSectionHeight(double h) { section_height = h; }
|
||||
std::string nameElement(const IfcGeom::Element<real_t>* elem);
|
||||
std::string nameElement(const IfcSchema::IfcProduct* elem);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <limits>
|
||||
#include <iomanip>
|
||||
|
||||
#include "WavefrontObjSerializer.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomRenderStyles.h"
|
||||
|
||||
#include "WavefrontObjSerializer.h"
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iomanip>
|
||||
|
||||
bool WaveFrontOBJSerializer::ready() {
|
||||
return obj_stream.is_open() && mtl_stream.is_open();
|
||||
@@ -41,11 +42,15 @@ void WaveFrontOBJSerializer::writeHeader() {
|
||||
mtl_basename = mtl_basename.substr(slash+1);
|
||||
}
|
||||
obj_stream << "mtllib " << mtl_basename << "\n";
|
||||
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
|
||||
mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n";
|
||||
}
|
||||
|
||||
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
|
||||
mtl_stream << "newmtl " << style.name() << "\n";
|
||||
void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style)
|
||||
{
|
||||
std::string material_name = (settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
|
||||
? style.original_name() : style.name());
|
||||
IfcUtil::sanitate_material_name(material_name);
|
||||
mtl_stream << "newmtl " << material_name << "\n";
|
||||
if (style.hasDiffuse()) {
|
||||
const double* diffuse = style.diffuse();
|
||||
mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n";
|
||||
@@ -66,39 +71,50 @@ void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) {
|
||||
}
|
||||
}
|
||||
}
|
||||
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>* o) {
|
||||
|
||||
obj_stream << "g " << o->unique_id() << "\n";
|
||||
void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<real_t>* o)
|
||||
{
|
||||
const std::string name = (settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_GUIDS)
|
||||
? o->guid() : (settings().get(IfcGeom::IteratorSettings::USE_ELEMENT_NAMES)
|
||||
? o->name() : o->unique_id()));
|
||||
obj_stream << "g " << name << "\n";
|
||||
obj_stream << "s 1" << "\n";
|
||||
|
||||
obj_stream << std::setprecision(std::numeric_limits<double>::digits10);
|
||||
|
||||
const IfcGeom::Representation::Triangulation<double>& mesh = o->geometry();
|
||||
const IfcGeom::Representation::Triangulation<real_t>& mesh = o->geometry();
|
||||
|
||||
const int vcount = (int)mesh.verts().size() / 3;
|
||||
for ( std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
|
||||
const double x = *(it++);
|
||||
const double y = *(it++);
|
||||
const double z = *(it++);
|
||||
for ( std::vector<real_t>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) {
|
||||
const real_t x = *(it++) + (real_t)settings().offset[0];
|
||||
const real_t y = *(it++) + (real_t)settings().offset[1];
|
||||
const real_t z = *(it++) + (real_t)settings().offset[2];
|
||||
obj_stream << "v " << x << " " << y << " " << z << "\n";
|
||||
}
|
||||
|
||||
for ( std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
|
||||
const double x = *(it++);
|
||||
const double y = *(it++);
|
||||
const double z = *(it++);
|
||||
for ( std::vector<real_t>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end(); ) {
|
||||
const real_t x = *(it++);
|
||||
const real_t y = *(it++);
|
||||
const real_t z = *(it++);
|
||||
obj_stream << "vn " << x << " " << y << " " << z << "\n";
|
||||
}
|
||||
|
||||
for (std::vector<real_t>::const_iterator it = mesh.uvs().begin(); it != mesh.uvs().end();) {
|
||||
const real_t u = *it++;
|
||||
const real_t v = *it++;
|
||||
obj_stream << "vt " << u << " " << v << "\n";
|
||||
}
|
||||
|
||||
int previous_material_id = -2;
|
||||
std::vector<int>::const_iterator material_it = mesh.material_ids().begin();
|
||||
|
||||
const bool has_uvs = !mesh.uvs().empty();
|
||||
for ( std::vector<int>::const_iterator it = mesh.faces().begin(); it != mesh.faces().end(); ) {
|
||||
|
||||
const int material_id = *(material_it++);
|
||||
if (material_id != previous_material_id) {
|
||||
const IfcGeom::Material& material = mesh.materials()[material_id];
|
||||
const std::string material_name = material.name();
|
||||
std::string material_name = (settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
|
||||
? material.original_name() : material.name());
|
||||
IfcUtil::sanitate_material_name(material_name);
|
||||
obj_stream << "usemtl " << material_name << "\n";
|
||||
if (materials.find(material_name) == materials.end()) {
|
||||
writeMaterial(material);
|
||||
@@ -110,7 +126,9 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>*
|
||||
const int v1 = *(it++)+vcount_total;
|
||||
const int v2 = *(it++)+vcount_total;
|
||||
const int v3 = *(it++)+vcount_total;
|
||||
obj_stream << "f " << v1 << "//" << v1 << " " << v2 << "//" << v2 << " " << v3 << "//" << v3 << "\n";
|
||||
obj_stream << "f " << v1 << "/" << (has_uvs ? boost::lexical_cast<std::string>(v1) : "") << "/" << v1 << " "
|
||||
<< v2 << "/" << (has_uvs ? boost::lexical_cast<std::string>(v2) : "") << "/" << v2 << " "
|
||||
<< v3 << "/" << (has_uvs ? boost::lexical_cast<std::string>(v3) : "") << "/" << v3 << "\n";
|
||||
|
||||
}
|
||||
|
||||
@@ -129,7 +147,9 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement<double>*
|
||||
|
||||
if (material_id != previous_material_id) {
|
||||
const IfcGeom::Material& material = mesh.materials()[material_id];
|
||||
const std::string material_name = material.name();
|
||||
std::string material_name = (settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES)
|
||||
? material.original_name() : material.name());
|
||||
IfcUtil::sanitate_material_name(material_name);
|
||||
obj_stream << "usemtl " << material_name << "\n";
|
||||
if (materials.find(material_name) == materials.end()) {
|
||||
writeMaterial(material);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "../ifcconvert/GeometrySerializer.h"
|
||||
|
||||
// http://people.sc.fsu.edu/~jburkardt/txt/obj_format.txt
|
||||
class WaveFrontOBJSerializer : public GeometrySerializer {
|
||||
private:
|
||||
const std::string mtl_filename;
|
||||
@@ -34,8 +35,8 @@ private:
|
||||
unsigned int vcount_total;
|
||||
std::set<std::string> materials;
|
||||
public:
|
||||
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename)
|
||||
: GeometrySerializer()
|
||||
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename, const IfcGeom::IteratorSettings &settings)
|
||||
: GeometrySerializer(settings)
|
||||
, obj_stream(obj_filename.c_str())
|
||||
, mtl_filename(mtl_filename)
|
||||
, mtl_stream(mtl_filename.c_str())
|
||||
@@ -45,12 +46,12 @@ public:
|
||||
bool ready();
|
||||
void writeHeader();
|
||||
void writeMaterial(const IfcGeom::Material& style);
|
||||
void write(const IfcGeom::TriangulationElement<double>* o);
|
||||
void write(const IfcGeom::BRepElement<double>* /*o*/) {}
|
||||
void write(const IfcGeom::TriangulationElement<real_t>* o);
|
||||
void write(const IfcGeom::BRepElement<real_t>* /*o*/) {}
|
||||
void finalize() {}
|
||||
bool isTesselated() const { return true; }
|
||||
void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {}
|
||||
void setFile(IfcParse::IfcFile*) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/xml_parser.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#include "XmlSerializer.h"
|
||||
@@ -164,6 +163,16 @@ void descend(IfcProduct* product, ptree& tree) {
|
||||
}
|
||||
}
|
||||
|
||||
if (product->is(Type::IfcElement)) {
|
||||
IfcElement* element = static_cast<IfcElement*>(product);
|
||||
IfcOpeningElement::list::ptr openings = get_related<IfcElement, IfcRelVoidsElement, IfcOpeningElement>(
|
||||
element, &IfcElement::HasOpenings, &IfcRelVoidsElement::RelatedOpeningElement);
|
||||
|
||||
for (IfcOpeningElement::list::it it = openings->begin(); it != openings->end(); ++it) {
|
||||
descend(*it, child);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC2x3
|
||||
IfcObjectDefinition::list::ptr structures = get_related
|
||||
<IfcProduct, IfcRelDecomposes, IfcObjectDefinition>
|
||||
@@ -246,16 +255,16 @@ void XmlSerializer::finalize() {
|
||||
ptree root, header, decomposition, properties;
|
||||
|
||||
// Write the SPF header as XML nodes.
|
||||
BOOST_FOREACH(const std::string& s, file->header().file_description().description()) {
|
||||
foreach(const std::string& s, file->header().file_description().description()) {
|
||||
header.add_child("file_description.description", ptree(s));
|
||||
}
|
||||
BOOST_FOREACH(const std::string& s, file->header().file_name().author()) {
|
||||
foreach(const std::string& s, file->header().file_name().author()) {
|
||||
header.add_child("file_name.author", ptree(s));
|
||||
}
|
||||
BOOST_FOREACH(const std::string& s, file->header().file_name().organization()) {
|
||||
foreach(const std::string& s, file->header().file_name().organization()) {
|
||||
header.add_child("file_name.organization", ptree(s));
|
||||
}
|
||||
BOOST_FOREACH(const std::string& s, file->header().file_schema().schema_identifiers()) {
|
||||
foreach(const std::string& s, file->header().file_schema().schema_identifiers()) {
|
||||
header.add_child("file_schema.schema_identifiers", ptree(s));
|
||||
}
|
||||
header.put("file_description.implementation_level", file->header().file_description().implementation_level());
|
||||
@@ -288,4 +297,4 @@ void XmlSerializer::finalize() {
|
||||
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
|
||||
#endif
|
||||
boost::property_tree::write_xml(xml_filename, root, std::locale(), settings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace IfcGeom {
|
||||
for(int i = 1; i < 5; ++i) {
|
||||
for (int j = 1; j < 4; ++j) {
|
||||
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;
|
||||
_data.push_back(static_cast<P>(matrix_value));
|
||||
|
||||
@@ -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());
|
||||
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;
|
||||
try {
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
const bool faster_booleans = settings.faster_booleans();
|
||||
const bool faster_booleans = settings.get(IteratorSettings::FASTER_BOOLEANS);
|
||||
#else
|
||||
const bool faster_booleans = true;
|
||||
#endif
|
||||
@@ -1136,14 +1136,14 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_pro
|
||||
} catch(...) {
|
||||
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 ) {
|
||||
it->prepend(trsf);
|
||||
}
|
||||
trsf = gp_Trsf();
|
||||
}
|
||||
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 ) {
|
||||
it->prepend(trsf);
|
||||
}
|
||||
|
||||
@@ -86,6 +86,9 @@ namespace IfcGeom {
|
||||
template <typename P>
|
||||
class Iterator {
|
||||
private:
|
||||
Iterator(const Iterator&); // N/I
|
||||
Iterator& operator=(const Iterator&); // N/I
|
||||
|
||||
Kernel kernel;
|
||||
IteratorSettings settings;
|
||||
|
||||
@@ -110,6 +113,8 @@ namespace IfcGeom {
|
||||
std::string unit_name;
|
||||
// double?
|
||||
P unit_magnitude;
|
||||
gp_XYZ bounds_min_;
|
||||
gp_XYZ bounds_max_;
|
||||
|
||||
void initUnits() {
|
||||
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;
|
||||
bool include_entities_in_processing;
|
||||
|
||||
@@ -148,7 +154,7 @@ namespace IfcGeom {
|
||||
} catch (...) {}
|
||||
|
||||
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
|
||||
// the standard 'Design' is deprecated. So,
|
||||
// just for backwards compatibility:
|
||||
@@ -157,7 +163,7 @@ namespace IfcGeom {
|
||||
// DDS likes to output 'model view'
|
||||
context_types.insert("model view");
|
||||
}
|
||||
if (settings.include_curves()) {
|
||||
if (settings.get(IteratorSettings::INCLUDE_CURVES)) {
|
||||
context_types.insert("plan");
|
||||
}
|
||||
|
||||
@@ -247,39 +253,74 @@ namespace IfcGeom {
|
||||
done = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
int progress() {
|
||||
return 100 * done / total;
|
||||
}
|
||||
int progress() const { return 100 * done / total; }
|
||||
|
||||
const std::string& getUnitName() {
|
||||
return unit_name;
|
||||
}
|
||||
const std::string& getUnitName() const { return unit_name; }
|
||||
|
||||
const P getUnitMagnitude() {
|
||||
return unit_magnitude;
|
||||
}
|
||||
P getUnitMagnitude() const { return unit_magnitude; }
|
||||
|
||||
const std::string getLog() {
|
||||
return Logger::GetLog();
|
||||
}
|
||||
std::string getLog() const { return Logger::GetLog(); }
|
||||
|
||||
IfcParse::IfcFile* getFile() {
|
||||
return ifc_file;
|
||||
}
|
||||
IfcParse::IfcFile* getFile() const { return ifc_file; }
|
||||
|
||||
/// @note Entity names are handled case-insensitively.
|
||||
void includeEntities(const std::set<std::string>& entities) {
|
||||
populate_set(entities);
|
||||
include_entities_in_processing = true;
|
||||
}
|
||||
|
||||
/// @note Entity names are handled case-insensitively.
|
||||
void excludeEntities(const std::set<std::string>& entities) {
|
||||
populate_set(entities);
|
||||
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:
|
||||
// Move to the next IfcRepresentation
|
||||
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;
|
||||
|
||||
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>();
|
||||
products->push(products_of_prodrep);
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@@ -418,7 +459,7 @@ namespace IfcGeom {
|
||||
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>();
|
||||
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)) {
|
||||
unfiltered_products->push(*lt);
|
||||
}
|
||||
@@ -440,6 +481,14 @@ namespace IfcGeom {
|
||||
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) {
|
||||
ifcproducts->push(*jt);
|
||||
}
|
||||
@@ -494,13 +543,17 @@ namespace IfcGeom {
|
||||
return create();
|
||||
}
|
||||
|
||||
Element<P>* get() {
|
||||
// TODO: Test settings and throw
|
||||
if (current_triangulation) return current_triangulation;
|
||||
else if (current_serialization) return current_serialization;
|
||||
else if (current_shape_model) return current_shape_model;
|
||||
else return 0;
|
||||
}
|
||||
/// Gets or takes the representation of the current geometrical entity.
|
||||
/// @param take_ownership Pass in 'true' as if wishing to maintain the element lifetime yourself.
|
||||
Element<P>* get(bool take_ownership = false)
|
||||
{
|
||||
// TODO: Test settings and throw
|
||||
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) {
|
||||
|
||||
@@ -549,15 +602,15 @@ namespace IfcGeom {
|
||||
} catch (...) {}
|
||||
|
||||
if (next_shape_model) {
|
||||
if (settings.use_brep_data()) {
|
||||
if (settings.get(IteratorSettings::USE_BREP_DATA)) {
|
||||
try {
|
||||
next_serialization = new SerializedElement<P>(*next_shape_model);
|
||||
} catch (...) {
|
||||
success = false;
|
||||
}
|
||||
} else if (!settings.disable_triangulation()) {
|
||||
} else if (!settings.get(IteratorSettings::DISABLE_TRIANGULATION)) {
|
||||
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);
|
||||
} else {
|
||||
next_triangulation = new TriangulationElement<P>(*next_shape_model, current_triangulation->geometry_pointer());
|
||||
@@ -591,8 +644,9 @@ namespace IfcGeom {
|
||||
unit_name = "METER";
|
||||
unit_magnitude = 1.f;
|
||||
|
||||
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.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_MAX_FACES_TO_SEW, settings.get(IteratorSettings::SEW_SHELLS) ? 1000 : -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;
|
||||
|
||||
@@ -20,160 +20,145 @@
|
||||
#ifndef IFCGEOMITERATORSETTINGS_H
|
||||
#define IFCGEOMITERATORSETTINGS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#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 {
|
||||
public:
|
||||
// Enumeration of setting identifiers. These settings define the
|
||||
// behaviour of various aspects of IfcOpenShell.
|
||||
IteratorSettings()
|
||||
: settings_(WELD_VERTICES) // OR options that default to true here
|
||||
, deflection_tolerance_(1.e-3)
|
||||
{
|
||||
memset(offset, 0, sizeof(offset));
|
||||
}
|
||||
|
||||
// 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.
|
||||
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;
|
||||
/// Optional offset that is applied to serialized objects, (0,0,0) by default.
|
||||
double offset[3];
|
||||
|
||||
// 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:
|
||||
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;
|
||||
public:
|
||||
IteratorSettings()
|
||||
: _weld_vertices(true)
|
||||
, _use_world_coords(false)
|
||||
, _convert_back_units(false)
|
||||
, _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)
|
||||
{}
|
||||
void set_deflection_tolerance(double value)
|
||||
{
|
||||
/// @todo Using deflection tolerance of 1e-6 or smaller hangs the conversion, research more in-depth.
|
||||
/// This bug can be reproduced e.g. with the Duplex model that can be found from http://www.nibs.org/?page=bsa_commonbimfiles#project1
|
||||
deflection_tolerance_ = value;
|
||||
if (deflection_tolerance_ <= 1e-6) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Deflection tolerance cannot be set to <= 1e-6; using the default value 1e-3");
|
||||
deflection_tolerance_ = 1e-3;
|
||||
}
|
||||
}
|
||||
|
||||
const bool& weld_vertices() const { return _weld_vertices; }
|
||||
bool& weld_vertices() { return _weld_vertices; }
|
||||
const bool& use_world_coords() const { return _use_world_coords; }
|
||||
bool& use_world_coords() { return _use_world_coords; }
|
||||
const bool& convert_back_units() const { return _convert_back_units; }
|
||||
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; }
|
||||
double& deflection_tolerance() { return _deflection_tolerance; }
|
||||
|
||||
void set(int setting, bool value) {
|
||||
switch (setting) {
|
||||
case USE_WORLD_COORDS:
|
||||
_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 {
|
||||
private:
|
||||
double _unit_magnitude;
|
||||
std::string _element_type;
|
||||
public:
|
||||
ElementSettings(const IteratorSettings& settings,
|
||||
double unit_magnitude,
|
||||
const std::string& element_type)
|
||||
: IteratorSettings(settings)
|
||||
, _unit_magnitude(unit_magnitude)
|
||||
, _element_type(element_type)
|
||||
{}
|
||||
/// Get boolean value for a single settings or for a combination of settings.
|
||||
bool get(SettingField setting) const
|
||||
{
|
||||
/// @todo If unknown setting value/combination: throw IfcParse::IfcException("Invalid IteratorSetting")?
|
||||
return (settings_ & setting) != 0;
|
||||
}
|
||||
|
||||
const double& unit_magnitude() const { return _unit_magnitude; }
|
||||
const std::string& element_type() const { return _element_type; }
|
||||
};
|
||||
/// Set boolean value for a single settings or for a combination of settings.
|
||||
void set(SettingField setting, bool value)
|
||||
{
|
||||
/// @todo If unknown setting value/combination: throw IfcParse::IfcException("Invalid IteratorSetting")?
|
||||
if (value) {
|
||||
settings_ |= setting;
|
||||
} else {
|
||||
settings_ &= ~setting;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
SettingField settings_;
|
||||
double deflection_tolerance_;
|
||||
};
|
||||
|
||||
class ElementSettings : public IteratorSettings
|
||||
{
|
||||
public:
|
||||
ElementSettings(const IteratorSettings& settings,
|
||||
double unit_magnitude,
|
||||
const std::string& element_type)
|
||||
: IteratorSettings(settings)
|
||||
, unit_magnitude_(unit_magnitude)
|
||||
, element_type_(element_type)
|
||||
{
|
||||
}
|
||||
|
||||
double unit_magnitude() const { return unit_magnitude_; }
|
||||
const std::string& element_type() const { return element_type_; }
|
||||
|
||||
private:
|
||||
double unit_magnitude_;
|
||||
std::string element_type_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -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; }
|
||||
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; }
|
||||
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; }
|
||||
|
||||
@@ -41,10 +41,11 @@ namespace IfcGeom {
|
||||
const double* specular() const;
|
||||
double transparency() 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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -45,21 +45,21 @@ namespace IfcGeom {
|
||||
};
|
||||
private:
|
||||
std::string name;
|
||||
std::string original_name_;
|
||||
boost::optional<int> id;
|
||||
boost::optional<ColorComponent> diffuse, specular;
|
||||
boost::optional<double> transparency;
|
||||
boost::optional<double> specularity;
|
||||
public:
|
||||
SurfaceStyle() {
|
||||
this->name = "surface-style";
|
||||
}
|
||||
SurfaceStyle() : name("surface-style") {}
|
||||
SurfaceStyle(int id) : id(id) {
|
||||
std::stringstream sstr;
|
||||
sstr << "surface-style-" << id;
|
||||
this->name = sstr.str();
|
||||
}
|
||||
SurfaceStyle(const std::string& name) : name(name) {}
|
||||
SurfaceStyle(int id, const std::string& name) : id(id) {
|
||||
SurfaceStyle(const std::string& name) : name(name), original_name_(name) {}
|
||||
SurfaceStyle(int id, const std::string& name) : id(id), original_name_(name)
|
||||
{
|
||||
std::stringstream sstr;
|
||||
std::string sanitized = name;
|
||||
std::transform(sanitized.begin(), sanitized.end(), sanitized.begin(), ::tolower);
|
||||
@@ -76,8 +76,12 @@ namespace IfcGeom {
|
||||
return name == other.name;
|
||||
}
|
||||
|
||||
/// ID name, e.g. "surface-style-66675-metal---aluminium"
|
||||
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>& Specular() const { return specular; }
|
||||
const boost::optional<double>& Transparency() const { return transparency; }
|
||||
@@ -91,4 +95,4 @@ namespace IfcGeom {
|
||||
const SurfaceStyle* get_default_style(const std::string& ifc_type);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -38,7 +38,7 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
|
||||
const TopoDS_Shape& s = it->Shape();
|
||||
gp_GTrsf trsf = it->Placement();
|
||||
if (settings().convert_back_units()) {
|
||||
if (settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
|
||||
gp_Trsf scale;
|
||||
scale.SetScaleFactor(1.0 / settings().unit_magnitude());
|
||||
trsf.PreMultiply(scale);
|
||||
|
||||
@@ -103,6 +103,7 @@ namespace IfcGeom {
|
||||
std::vector<int> _faces;
|
||||
std::vector<int> _edges;
|
||||
std::vector<P> _normals;
|
||||
std::vector<P> uvs_;
|
||||
std::vector<int> _material_ids;
|
||||
std::vector<Material> _materials;
|
||||
VertexKeyMap welds;
|
||||
@@ -113,8 +114,10 @@ namespace IfcGeom {
|
||||
const std::vector<int>& faces() const { return _faces; }
|
||||
const std::vector<int>& edges() const { return _edges; }
|
||||
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<Material>& materials() const { return _materials; }
|
||||
|
||||
Triangulation(const BRep& shape_model)
|
||||
: Representation(shape_model.settings())
|
||||
, _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()));
|
||||
std::vector<Material>::const_iterator mit = std::find(_materials.begin(), _materials.end(), material);
|
||||
if (mit == _materials.end()) {
|
||||
@@ -182,8 +185,9 @@ namespace IfcGeom {
|
||||
BRepGProp_Face prop(face);
|
||||
std::map<int,int> dict;
|
||||
|
||||
// Vertex normals are only calculated if vertices are not welded
|
||||
const bool calculate_normals = !settings().weld_vertices();
|
||||
// Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
|
||||
const bool calculate_normals = !settings().get(IteratorSettings::WELD_VERTICES) &&
|
||||
!settings().get(IteratorSettings::NO_NORMALS);
|
||||
|
||||
for( int i = 1; i <= nodes.Length(); ++ i ) {
|
||||
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) {
|
||||
// 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
|
||||
@@ -277,14 +285,46 @@ namespace IfcGeom {
|
||||
}
|
||||
}
|
||||
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:
|
||||
// Welds vertices that belong to different faces
|
||||
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 P Y = static_cast<P>(settings().convert_back_units() ? (p.Y() / settings().unit_magnitude()) : p.Y());
|
||||
const P Z = static_cast<P>(settings().convert_back_units() ? (p.Z() / settings().unit_magnitude()) : p.Z());
|
||||
const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS);
|
||||
const P X = static_cast<P>(convert ? (p.X() / settings().unit_magnitude()) : p.X());
|
||||
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;
|
||||
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)));
|
||||
typename VertexKeyMap::const_iterator it = welds.find(key);
|
||||
if ( it != welds.end() ) return it->second;
|
||||
@@ -310,4 +350,4 @@ namespace IfcGeom {
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -318,10 +318,10 @@ int main () {
|
||||
memcpy(data, m.string().c_str(), len);
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.use_world_coords() = false;
|
||||
settings.weld_vertices() = false;
|
||||
settings.convert_back_units() = true;
|
||||
settings.include_curves() = true;
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false);
|
||||
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true);
|
||||
settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, true);
|
||||
|
||||
iterator = new IfcGeom::Iterator<float>(settings, data, (int)len);
|
||||
has_more = iterator->initialize();
|
||||
|
||||
@@ -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*/) {
|
||||
|
||||
IfcGeom::IteratorSettings settings;
|
||||
settings.use_world_coords() = false;
|
||||
settings.weld_vertices() = true;
|
||||
settings.sew_shells() = true;
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false);
|
||||
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, true);
|
||||
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
|
||||
|
||||
#ifdef _UNICODE
|
||||
int fn_buffer_size = WideCharToMultiByte(CP_UTF8, 0, name, -1, 0, 0, 0, 0);
|
||||
|
||||
@@ -69,7 +69,10 @@ void init_locale() {
|
||||
//
|
||||
// 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;
|
||||
#ifdef _MSC_VER
|
||||
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;
|
||||
fseek(stream, 0, SEEK_END);
|
||||
size = (unsigned int) ftell(stream);;
|
||||
size = (unsigned int) ftell(stream);
|
||||
rewind(stream);
|
||||
#ifdef BUF_SIZE
|
||||
offset = 0;
|
||||
@@ -96,11 +99,14 @@ IfcSpfStream::IfcSpfStream(const std::string& fn) {
|
||||
buffer = new char[size];
|
||||
#endif
|
||||
ptr = 0;
|
||||
len = 0;
|
||||
len = 0;
|
||||
ReadBuffer(false);
|
||||
}
|
||||
|
||||
IfcSpfStream::IfcSpfStream(std::istream& f, int l) {
|
||||
IfcSpfStream::IfcSpfStream(std::istream& f, int l)
|
||||
: stream(0)
|
||||
, buffer(0)
|
||||
{
|
||||
eof = false;
|
||||
size = l;
|
||||
#ifdef BUF_SIZE
|
||||
@@ -114,7 +120,10 @@ IfcSpfStream::IfcSpfStream(std::istream& f, int l) {
|
||||
len = l;
|
||||
}
|
||||
|
||||
IfcSpfStream::IfcSpfStream(void* data, int l) {
|
||||
IfcSpfStream::IfcSpfStream(void* data, int l)
|
||||
: stream(0)
|
||||
, buffer(0)
|
||||
{
|
||||
eof = false;
|
||||
size = l;
|
||||
#ifdef BUF_SIZE
|
||||
@@ -124,7 +133,7 @@ IfcSpfStream::IfcSpfStream(void* data, int l) {
|
||||
buffer = (char*) data;
|
||||
valid = true;
|
||||
ptr = 0;
|
||||
len = l;
|
||||
len = l;
|
||||
}
|
||||
|
||||
IfcSpfStream::~IfcSpfStream()
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "IfcUtil.h"
|
||||
#include "../ifcparse/IfcException.h"
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../ifcparse/IfcException.h"
|
||||
|
||||
#include "IfcUtil.h"
|
||||
|
||||
void IfcEntityList::push(IfcUtil::IfcBaseClass* l) {
|
||||
if (l) {
|
||||
@@ -143,4 +145,43 @@ bool IfcUtil::valid_binary_string(const std::string& s) {
|
||||
if (*it != '0' && *it != '1') return false;
|
||||
}
|
||||
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, "\"", """);
|
||||
boost::replace_all(str, "'", "'");
|
||||
boost::replace_all(str, "<", "<");
|
||||
boost::replace_all(str, ">", ">");
|
||||
boost::replace_all(str, "&", "&");
|
||||
}
|
||||
|
||||
void IfcUtil::unescape_xml(std::string &str)
|
||||
{
|
||||
boost::replace_all(str, """, "\"");
|
||||
boost::replace_all(str, "'", "'");
|
||||
boost::replace_all(str, "<", "<");
|
||||
boost::replace_all(str, ">", ">");
|
||||
boost::replace_all(str, "&", "&");
|
||||
}
|
||||
|
||||
+15
-3
@@ -26,15 +26,20 @@
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include "../ifcparse/Ifc4enum.h"
|
||||
#else
|
||||
#include "../ifcparse/Ifc2x3enum.h"
|
||||
#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 IfcEntityList;
|
||||
class IfcEntityListList;
|
||||
@@ -110,6 +115,13 @@ namespace IfcUtil {
|
||||
};
|
||||
|
||||
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>
|
||||
|
||||
@@ -244,8 +244,8 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
||||
IfcSchema::IfcProject* project = *projects->begin();
|
||||
|
||||
IfcGeom::Kernel kernel;
|
||||
kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.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_MAX_FACES_TO_SEW, settings.get(IfcGeom::IteratorSettings::SEW_SHELLS) ? 1000 : -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());
|
||||
|
||||
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
|
||||
for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) {
|
||||
IfcSchema::IfcRepresentation* rep = *it;
|
||||
if (!settings.exclude_solids_and_surfaces()) {
|
||||
if (!settings.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) {
|
||||
if (rep->RepresentationIdentifier() == "Body") {
|
||||
ifc_representation = rep;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (settings.include_curves()) {
|
||||
if (settings.get(IfcGeom::IteratorSettings::INCLUDE_CURVES)) {
|
||||
if (rep->RepresentationIdentifier() == "Plan" || rep->RepresentationIdentifier() == "Axis") {
|
||||
ifc_representation = rep;
|
||||
break;
|
||||
@@ -293,12 +293,12 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
||||
// TODO: Remove redundancy with IfcGeomIterator.h
|
||||
if (context->hasContextType()) {
|
||||
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("design");
|
||||
context_types.insert("model view");
|
||||
}
|
||||
if (settings.include_curves()) {
|
||||
if (settings.get(IfcGeom::IteratorSettings::INCLUDE_CURVES)) {
|
||||
context_types.insert("plan");
|
||||
}
|
||||
|
||||
@@ -347,11 +347,11 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
||||
if (!brep) {
|
||||
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);
|
||||
delete brep;
|
||||
return serialization;
|
||||
} else if (!settings.disable_triangulation()) {
|
||||
} else if (!settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) {
|
||||
IfcGeom::TriangulationElement<double>* triangulation = new IfcGeom::TriangulationElement<double>(*brep);
|
||||
delete brep;
|
||||
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::Representation::BRep brep(element_settings, instance->entity->id(), shapes);
|
||||
try {
|
||||
if (settings.use_brep_data()) {
|
||||
if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) {
|
||||
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);
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user