Merge branch 'master' into performance_improvements

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