From 80bc1b5dab06803cbc8d86bb7ee0c25e91422538 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 5 May 2013 08:49:25 +0000 Subject: [PATCH] [Work in progress] Start adding support for IfcSurfaceStyleShading and -Rendering --- cmake/CMakeLists.txt | 1 + src/ifcconvert/ColladaSerializer.cpp | 165 +++++++++++++----- src/ifcconvert/ColladaSerializer.h | 37 ++-- src/ifcconvert/IfcConvert.cpp | 17 +- src/ifcconvert/OpenCascadeBasedSerializer.cpp | 6 +- src/ifcconvert/OpenCascadeBasedSerializer.h | 3 +- src/ifcconvert/WavefrontObjSerializer.cpp | 67 +++++-- src/ifcconvert/WavefrontObjSerializer.h | 3 +- src/ifcgeom/IfcGeom.h | 13 +- src/ifcgeom/IfcGeomFunctions.cpp | 46 ++--- src/ifcgeom/IfcGeomObjects.cpp | 50 +++--- src/ifcgeom/IfcGeomObjects.h | 33 ++-- src/ifcgeom/IfcGeomShapes.cpp | 40 +++-- src/ifcgeom/IfcRegister.cpp | 6 +- src/ifcgeom/IfcRegisterConvertShape.h | 2 +- src/ifcgeom/IfcRegisterGeomHeader.h | 2 +- win/IfcGeom.vcproj | 12 ++ 17 files changed, 308 insertions(+), 195 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 0925215314..d1a50f9cdb 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -112,6 +112,7 @@ ADD_LIBRARY(IfcGeom STATIC ../src/ifcgeom/IfcGeomFunctions.cpp ../src/ifcgeom/IfcGeomHelpers.cpp ../src/ifcgeom/IfcGeomObjects.cpp + ../src/ifcgeom/IfcGeomRenderStyles.cpp ../src/ifcgeom/IfcGeomShapes.cpp ../src/ifcgeom/IfcGeomWires.cpp ../src/ifcgeom/IfcRegister.cpp diff --git a/src/ifcconvert/ColladaSerializer.cpp b/src/ifcconvert/ColladaSerializer.cpp index ec8ebbb77c..aaea6f75a2 100644 --- a/src/ifcconvert/ColladaSerializer.cpp +++ b/src/ifcconvert/ColladaSerializer.cpp @@ -17,8 +17,22 @@ * * ********************************************************************************/ +#include + #include "ColladaSerializer.h" +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 == '_')) { + id.push_back(c); + } + } + return id; +} + void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector& floats, const char* coords /* = "XYZ" */) { COLLADASW::FloatSource source(mSW); source.setId(mesh_id + suffix); @@ -35,13 +49,15 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const source.finish(); } -void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::vector& positions, const std::vector& normals, const std::vector& indices) { +void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::string mesh_id, const std::string& default_material_name, const std::vector& positions, const std::vector& normals, const std::vector& indices, const std::vector material_ids, const std::vector& materials) { 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(); + addFloatSource(mesh_id, COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX, positions); - if (!normals.empty()) { - // 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. + if (has_normals) { addFloatSource(mesh_id, COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, normals); } @@ -50,23 +66,42 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write(const std::str vertices.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::POSITION, "#" + mesh_id + COLLADASW::LibraryGeometries::POSITIONS_SOURCE_ID_SUFFIX)); vertices.add(); - COLLADASW::Triangles triangles(mSW); - triangles.setCount(indices.size() / 3); - int offset = 0; - triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX,"#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset++ ) ); - if (!normals.empty()) { - triangles.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::NORMAL,"#" + mesh_id + COLLADASW::LibraryGeometries::NORMALS_SOURCE_ID_SUFFIX, offset++ ) ); - } - triangles.prepareToAppendValues(); - for (auto it = indices.begin(); it != indices.end(); ++it) { - const auto& idx = *it; - if (!normals.empty()) { - triangles.appendValues(idx, idx); - } else { - triangles.appendValues(idx); + std::vector::const_iterator index_range_start = indices.begin(); + std::vector::const_iterator material_it = material_ids.begin(); + int previous_material_id = -2; + for (std::vector::const_iterator it = indices.begin(); ; it += 3) { + const int current_material_id = material_it == material_ids.end() + ? -3 + : *(material_it++); + const int num_triangles = std::distance(index_range_start, it) / 3; + if ((previous_material_id != current_material_id && num_triangles > 0) || (it == indices.end())) { + COLLADASW::Triangles triangles(mSW); + triangles.setMaterial(collada_id(previous_material_id == -1 + ? default_material_name + : materials[previous_material_id]->Name())); + triangles.setCount(num_triangles); + int offset = 0; + 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.prepareToAppendValues(); + for (std::vector::const_iterator jt = index_range_start; jt != it; ++jt) { + const int idx = *jt; + if (has_normals) { + triangles.appendValues(idx, idx); + } else { + triangles.appendValues(idx); + } + } + triangles.finish(); + index_range_start = it; + } + previous_material_id = current_material_id; + if (it == indices.end()) { + break; } } - triangles.finish(); closeMesh(); closeGeometry(); @@ -76,7 +111,7 @@ 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_id, const std::string& material_id, const std::vector& matrix) { +void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector& material_ids, const std::vector& matrix) { if (!scene_opened) { openVisualScene(scene_id); scene_opened = true; @@ -85,7 +120,7 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& no COLLADASW::Node node(mSW); node.setNodeId(node_id); node.setNodeName(node_name); - node.setType(COLLADASW::Node::DEFAULT); + node.setType(COLLADASW::Node::NODE); // 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. @@ -98,11 +133,12 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add(const std::string& no node.start(); node.addMatrix(matrix_array); - COLLADASW::InstanceGeometry instanceGeometry(mSW); - instanceGeometry.setUrl ("#" + geom_id); - COLLADASW::InstanceMaterial material ("ColorMaterial", "#" + material_id); - instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material); + instanceGeometry.setUrl ("#" + geom_name); + for (std::vector::const_iterator it = material_ids.begin(); it != material_ids.end(); ++it) { + COLLADASW::InstanceMaterial material (*it, "#" + *it); + instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material); + } instanceGeometry.add(); node.end(); } @@ -117,36 +153,50 @@ void ColladaSerializer::ColladaExporter::ColladaScene::write() { } } -void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const SurfaceStyle& style) { - openEffect(style.Name() + "-fx"); +void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::SurfaceStyle* style) { + openEffect(collada_id(style->Name()) + "-fx"); COLLADASW::EffectProfile effect(mSW); effect.setShaderType(COLLADASW::EffectProfile::LAMBERT); - effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(style.Diffuse().R(),style.Diffuse().G(),style.Diffuse().B()))); + if (style->Diffuse()) { + const IfcGeom::SurfaceStyle::ColorComponent& diffuse = *style->Diffuse(); + effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(diffuse.R(),diffuse.G(),diffuse.B()))); + } + if (style->Specular()) { + const IfcGeom::SurfaceStyle::ColorComponent& specular = *style->Specular(); + effect.setSpecular(COLLADASW::ColorOrTexture(COLLADASW::Color(specular.R(),specular.G(),specular.B()))); + } + if (style->Specularity()) { + effect.setShininess(*style->Specularity()); + } + if (style->Transparency()) { + const double transparency = *style->Transparency(); + if (transparency > 0) { + effect.setTransparency(transparency); + } + } addEffectProfile(effect); + closeEffect(); } void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close() { closeLibrary(); } -void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const SurfaceStyle& style) { - if (!contains(style.Name())) { +void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::SurfaceStyle* style) { + if (!contains(style)) { effects.write(style); surface_styles.push_back(style); } } -bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const std::string& name) { - for (auto it = surface_styles.begin(); it != surface_styles.end(); ++it) { - if (it->Name() == name) return true; - } - return false; +bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeom::SurfaceStyle* style) { + return std::find(surface_styles.begin(), surface_styles.end(), style) != surface_styles.end(); } void ColladaSerializer::ColladaExporter::ColladaMaterials::write() { effects.close(); for (auto it = surface_styles.begin(); it != surface_styles.end(); ++it) { - const std::string& material_name = it->Name(); + const std::string& material_name = collada_id((*it)->Name()); openMaterial(material_name); addInstanceEffect("#" + material_name + "-fx"); closeLibrary(); @@ -164,9 +214,34 @@ void ColladaSerializer::ColladaExporter::startDocument() { asset.add(); } -void ColladaSerializer::ColladaExporter::writeTesselated(const std::string& type, int obj_id, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& indices) { - if (!materials.contains(type)) materials.add(GetDefaultMaterial(type)); - deferreds.push_back(DeferedObject(type, obj_id, matrix, vertices, normals, indices)); +void ColladaSerializer::ColladaExporter::writeTesselated(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& indices, const std::vector& material_ids, const std::vector& _materials) { + const IfcGeom::SurfaceStyle* default_for_type = IfcGeom::get_default_style(type); + std::vector material_references; + const bool needs_default = std::find(material_ids.begin(), material_ids.end(), -1) != material_ids.end(); + if (needs_default) { + if (!materials.contains(default_for_type)) { + materials.add(default_for_type); + } + material_references.push_back(collada_id(default_for_type->Name())); + } + for (std::vector::const_iterator it = _materials.begin(); it != _materials.end(); ++it) { + const IfcGeom::SurfaceStyle* const surface_style_pointer = *it; + if (!materials.contains(surface_style_pointer)) { + materials.add(surface_style_pointer); + } + material_references.push_back(collada_id(surface_style_pointer->Name())); + } + deferreds.push_back(DeferredObject(guid, name, type, obj_id, matrix, vertices, normals, indices, material_ids, _materials, material_references)); +} + +const std::string ColladaSerializer::ColladaExporter::DeferredObject::Name() const { + std::stringstream ss; + if (!this->name.empty()) { + ss << this->obj_id << "_" << this->name; + } else { + ss << this->guid; + } + return collada_id(ss.str()); } void ColladaSerializer::ColladaExporter::endDocument() { @@ -174,15 +249,13 @@ void ColladaSerializer::ColladaExporter::endDocument() { // only at this point all objects are written to the stream. materials.write(); for (auto it = deferreds.begin(); it != deferreds.end(); ++it) { - std::stringstream ss; ss << "object" << it->obj_id; - const std::string object_id = ss.str(); - geometries.write(object_id, it->vertices, it->normals, it->indices); + const std::string object_name = it->Name(); + geometries.write(object_name, it->type, it->vertices, it->normals, it->indices, it->material_ids, it->materials); } geometries.close(); for (auto it = deferreds.begin(); it != deferreds.end(); ++it) { - std::stringstream ss; ss << "object" << it->obj_id; - const std::string object_id = ss.str(); - scene.add(object_id, object_id, object_id, it->type, it->matrix); + const std::string object_name = it->Name(); + scene.add(object_name, object_name, object_name, it->material_references, it->matrix); } scene.write(); stream.endDocument(); @@ -197,7 +270,7 @@ void ColladaSerializer::writeHeader() { } void ColladaSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) { - exporter.writeTesselated(o->type, o->id, o->matrix, o->mesh->verts, o->mesh->normals, o->mesh->faces); + exporter.writeTesselated(o->guid, o->name, o->type, o->id, o->matrix, o->mesh->verts, o->mesh->normals, o->mesh->faces, o->mesh->materials, o->mesh->surface_styles); } void ColladaSerializer::finalize() { diff --git a/src/ifcconvert/ColladaSerializer.h b/src/ifcconvert/ColladaSerializer.h index 1c2aa1e9b2..5ffe248f86 100644 --- a/src/ifcconvert/ColladaSerializer.h +++ b/src/ifcconvert/ColladaSerializer.h @@ -36,7 +36,6 @@ #include "../ifcgeom/IfcGeomObjects.h" #include "../ifcconvert/GeometrySerializer.h" -#include "../ifcconvert/SurfaceStyle.h" class ColladaSerializer : public GeometrySerializer { @@ -51,7 +50,7 @@ private: : COLLADASW::LibraryGeometries(&stream) {} void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector& floats, const char* coords = "XYZ"); - void write(const std::string mesh_id, const std::vector& positions, const std::vector& normals, const std::vector& indices); + void write(const std::string mesh_id, const std::string& default_material_name, const std::vector& positions, const std::vector& normals, const std::vector& indices, const std::vector material_ids, const std::vector& materials); void close(); }; class ColladaScene : public COLLADASW::LibraryVisualScenes @@ -65,7 +64,7 @@ private: , scene_id(scene_id) , scene_opened(false) {} - void add(const std::string& node_id, const std::string& node_name, const std::string& geom_id, const std::string& material_id, const std::vector& matrix); + void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, const std::vector& material_ids, const std::vector& matrix); void write(); }; class ColladaMaterials : public COLLADASW::LibraryMaterials @@ -77,37 +76,47 @@ private: explicit ColladaEffects(COLLADASW::StreamWriter& stream) : COLLADASW::LibraryEffects(&stream) {} - void write(const SurfaceStyle& style); + void write(const IfcGeom::SurfaceStyle* style); void close(); }; - std::vector surface_styles; + std::vector surface_styles; ColladaEffects effects; public: explicit ColladaMaterials(COLLADASW::StreamWriter& stream) : COLLADASW::LibraryMaterials(&stream) , effects(stream) {} - void add(const SurfaceStyle& style); - bool contains(const std::string& name); + void add(const IfcGeom::SurfaceStyle* style); + bool contains(const IfcGeom::SurfaceStyle* style); void write(); }; - class DeferedObject { + class DeferredObject { public: - const std::string type; + const std::string guid, name, type; int obj_id; const std::vector matrix; const std::vector vertices; const std::vector normals; const std::vector indices; - DeferedObject(const std::string& type, int obj_id, const std::vector& matrix, const std::vector& vertices, - const std::vector& normals, const std::vector& indices) - : type(type) + const std::vector material_ids; + const std::vector materials; + const std::vector material_references; + DeferredObject(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector& matrix, const std::vector& vertices, + const std::vector& normals, const std::vector& indices, const std::vector& material_ids, + const std::vector& materials, const std::vector& material_references) + : guid(guid) + , name(name) + , type(type) , obj_id(obj_id) , matrix(matrix) , vertices(vertices) , normals(normals) , indices(indices) + , material_ids(material_ids) + , materials(materials) + , material_references(material_references) {} + const std::string Name() const; }; COLLADABU::NativeString filename; COLLADASW::StreamWriter stream; @@ -122,10 +131,10 @@ private: , scene(scene_name, stream) , materials(stream) {} - std::vector deferreds; + std::vector deferreds; virtual ~ColladaExporter() {} void startDocument(); - void writeTesselated(const std::string& type, int obj_id, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& indices); + void writeTesselated(const std::string& guid, const std::string& name, const std::string& type, int obj_id, const std::vector& matrix, const std::vector& vertices, const std::vector& normals, const std::vector& indices, const std::vector& material_ids, const std::vector& materials); void endDocument(); }; ColladaExporter exporter; diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 7ddaa11c3e..51ff85587d 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -35,7 +35,6 @@ #include "../ifcgeom/IfcGeomObjects.h" -#include "../ifcconvert/SurfaceStyle.h" #include "../ifcconvert/ColladaSerializer.h" #include "../ifcconvert/IgesSerializer.h" #include "../ifcconvert/StepSerializer.h" @@ -271,18 +270,4 @@ int main(int argc, char** argv) { time(&end); int dif = (int) difftime (end,start); printf ("\nConversion took %d seconds\n", dif ); -} - -SurfaceStyle GetDefaultMaterial(const std::string& s) { - if (s == "IfcSite" ) { return SurfaceStyle("IfcSite", 0.75,0.8,0.65); } - if (s == "IfcSlab" ) { return SurfaceStyle("IfcSlab", 0.4, 0.4,0.4 ); } - if (s == "IfcWallStandardCase") { return SurfaceStyle("IfcWallStandardCase",0.9, 0.9,0.9 ); } - if (s == "IfcWall" ) { return SurfaceStyle("IfcWall", 0.9, 0.9,0.9 ); } - if (s == "IfcWindow" ) { return SurfaceStyle("IfcWindow", 0.75,0.8,0.75, 1.0,1.0,1.0, 0.0,0.0,0.0, 500.0, 0.3); } - if (s == "IfcDoor" ) { return SurfaceStyle("IfcDoor", 0.55,0.3,0.15); } - if (s == "IfcBeam" ) { return SurfaceStyle("IfcBeam", 0.75,0.7,0.7 ); } - if (s == "IfcRailing" ) { return SurfaceStyle("IfcRailing", 0.65,0.6,0.6 ); } - if (s == "IfcMember" ) { return SurfaceStyle("IfcMember", 0.65,0.6,0.6 ); } - if (s == "IfcPlate" ) { return SurfaceStyle("IfcPlate", 0.8, 0.8,0.8 ); } - return SurfaceStyle(s); -} +} \ No newline at end of file diff --git a/src/ifcconvert/OpenCascadeBasedSerializer.cpp b/src/ifcconvert/OpenCascadeBasedSerializer.cpp index 0b437a2710..d7248b0632 100644 --- a/src/ifcconvert/OpenCascadeBasedSerializer.cpp +++ b/src/ifcconvert/OpenCascadeBasedSerializer.cpp @@ -35,10 +35,10 @@ bool OpenCascadeBasedSerializer::ready() { } void OpenCascadeBasedSerializer::writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) { - for (IfcGeom::ShapeList::const_iterator it = o->mesh->begin(); it != o->mesh->end(); ++ it) { - gp_GTrsf gtrsf = *it->first; + for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->mesh->begin(); it != o->mesh->end(); ++ it) { + gp_GTrsf gtrsf = it->Placement(); gtrsf.PreMultiply(o->trsf); - const TopoDS_Shape& s = *it->second; + const TopoDS_Shape& s = it->Shape(); bool trsf_valid = false; gp_Trsf trsf; diff --git a/src/ifcconvert/OpenCascadeBasedSerializer.h b/src/ifcconvert/OpenCascadeBasedSerializer.h index 2b07ee5a39..5087bc1023 100644 --- a/src/ifcconvert/OpenCascadeBasedSerializer.h +++ b/src/ifcconvert/OpenCascadeBasedSerializer.h @@ -23,7 +23,6 @@ #include "../ifcgeom/IfcGeomObjects.h" #include "../ifcconvert/GeometrySerializer.h" -#include "../ifcconvert/SurfaceStyle.h" class OpenCascadeBasedSerializer : public GeometrySerializer { protected: @@ -35,7 +34,7 @@ public: {} virtual ~OpenCascadeBasedSerializer() {} void writeHeader() {} - void writeMaterial(const SurfaceStyle& style) {} + void writeMaterial(const IfcGeom::SurfaceStyle& style) {} bool ready(); virtual void writeShape(const TopoDS_Shape& shape) = 0; void writeTesselated(const IfcGeomObjects::IfcGeomObject* o) {} diff --git a/src/ifcconvert/WavefrontObjSerializer.cpp b/src/ifcconvert/WavefrontObjSerializer.cpp index 6882a19049..1a5b5a417c 100644 --- a/src/ifcconvert/WavefrontObjSerializer.cpp +++ b/src/ifcconvert/WavefrontObjSerializer.cpp @@ -17,7 +17,7 @@ * * ********************************************************************************/ -#include "../ifcconvert/SurfaceStyle.h" +#include "../ifcgeom/IfcGeomRenderStyles.h" #include "WavefrontOBJSerializer.h" @@ -41,40 +41,69 @@ void WaveFrontOBJSerializer::writeHeader() { mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << std::endl; } -void WaveFrontOBJSerializer::writeMaterial(const SurfaceStyle& style) { - mtl_stream << "newmtl " << style.Name() << std::endl - << "Kd " << style.Diffuse().R() << " " << style.Diffuse().G() << " " << style.Diffuse().B() << std::endl - << "Ks " << style.Specular().R() << " " << style.Specular().G() << " " << style.Specular().B() << std::endl - << "Ka " << style.Ambient().R() << " " << style.Ambient().G() << " " << style.Ambient().B() << std::endl - << "Ns " << style.Specularity() << std::endl - << "Tr " << style.Transparency() << std::endl - << "d " << style.Transparency() << std::endl - << "D " << style.Transparency() << std::endl; +void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::SurfaceStyle& style) { + mtl_stream << "newmtl " << style.Name() << std::endl; + if (style.Diffuse()) { + const IfcGeom::SurfaceStyle::ColorComponent& diffuse = *style.Diffuse(); + mtl_stream << "Kd " << diffuse.R() << " " << diffuse.G() << " " << diffuse.B() << std::endl; + } + if (style.Specular()) { + const IfcGeom::SurfaceStyle::ColorComponent& specular = *style.Specular(); + mtl_stream << "Ks " << specular.R() << " " << specular.G() << " " << specular.B() << std::endl; + } + if (style.Specularity()) { + mtl_stream << "Ns " << (*style.Specularity()) << std::endl; + } + if (style.Transparency()) { + const double transparency = 1.0 - *style.Transparency(); + if (transparency < 1) { + mtl_stream << "Tr " << transparency << std::endl; + mtl_stream << "d " << transparency << std::endl; + mtl_stream << "D " << transparency << std::endl; + } + } } - void WaveFrontOBJSerializer::writeTesselated(const IfcGeomObjects::IfcGeomObject* o) { const std::string name = o->name.empty() ? o->guid : o->name; obj_stream << "g " << name << std::endl; obj_stream << "s 1" << std::endl; - obj_stream << "usemtl " << o->type << std::endl; - if (materials.find(o->type) == materials.end()) { - writeMaterial(GetDefaultMaterial(o->type)); - materials.insert(o->type); - } + const int vcount = o->mesh->verts.size() / 3; - for ( IfcGeomObjects::FltIt it = o->mesh->verts.begin(); it != o->mesh->verts.end(); ) { + for ( std::vector::const_iterator it = o->mesh->verts.begin(); it != o->mesh->verts.end(); ) { const double x = *(it++); const double y = *(it++); const double z = *(it++); obj_stream << "v " << x << " " << y << " " << z << std::endl; } - for ( IfcGeomObjects::FltIt it = o->mesh->normals.begin(); it != o->mesh->normals.end(); ) { + for ( std::vector::const_iterator it = o->mesh->normals.begin(); it != o->mesh->normals.end(); ) { const double x = *(it++); const double y = *(it++); const double z = *(it++); obj_stream << "vn " << x << " " << y << " " << z << std::endl; } - for ( IfcGeomObjects::IntIt it = o->mesh->faces.begin(); it != o->mesh->faces.end(); ) { + + int previous_material_id = -2; + std::vector::const_iterator material_it = o->mesh->materials.begin(); + + for ( std::vector::const_iterator it = o->mesh->faces.begin(); it != o->mesh->faces.end(); ) { + + const int material_id = *(material_it++); + if (material_id != previous_material_id) { + const IfcGeom::SurfaceStyle* material_style = 0; + if (material_id >= 0) { + material_style = o->mesh->surface_styles[material_id]; + } else { + material_style = IfcGeom::get_default_style(o->type); + } + const std::string material_name = material_style->Name(); + obj_stream << "usemtl " << material_name << std::endl; + if (materials.find(material_name) == materials.end()) { + writeMaterial(*material_style); + materials.insert(material_name); + } + previous_material_id = material_id; + } + const int v1 = *(it++)+vcount_total; const int v2 = *(it++)+vcount_total; const int v3 = *(it++)+vcount_total; diff --git a/src/ifcconvert/WavefrontObjSerializer.h b/src/ifcconvert/WavefrontObjSerializer.h index 9dd5b9c115..5c811b6011 100644 --- a/src/ifcconvert/WavefrontObjSerializer.h +++ b/src/ifcconvert/WavefrontObjSerializer.h @@ -25,7 +25,6 @@ #include #include "../ifcconvert/GeometrySerializer.h" -#include "../ifcconvert/SurfaceStyle.h" class WaveFrontOBJSerializer : public GeometrySerializer { private: @@ -45,7 +44,7 @@ public: virtual ~WaveFrontOBJSerializer() {} bool ready(); void writeHeader(); - void writeMaterial(const SurfaceStyle& style); + void writeMaterial(const IfcGeom::SurfaceStyle& style); void writeTesselated(const IfcGeomObjects::IfcGeomObject* o); void writeShapeModel(const IfcGeomObjects::IfcGeomShapeModelObject* o) {} void finalize() {} diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index a9a94b185e..754fbd9cf0 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -40,7 +40,7 @@ #include "../ifcparse/IfcParse.h" #include "../ifcparse/IfcUtil.h" -#include "../ifcgeom/IfcShapeList.h" +#include "../ifcgeom/IfcRepresentationShapeItem.h" namespace IfcGeom { @@ -76,14 +76,15 @@ namespace IfcGeom { }; bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face); - bool convert_shapes(const IfcUtil::IfcBaseClass* L, ShapeList& result); + bool convert_shapes(const IfcUtil::IfcBaseClass* L, IfcRepresentationShapeItems& result); bool is_shape_collection(const IfcUtil::IfcBaseClass* L); - const TopoDS_Shape* convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result); + bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result); bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result); bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result); bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Face& result); - bool convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes); - bool convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes); + bool convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes); + bool convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes); + Ifc2x3::IfcSurfaceStyleShading* get_surface_style(Ifc2x3::IfcRepresentationItem* item); bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid); bool is_compound(const TopoDS_Shape& shape); bool is_convex(const TopoDS_Wire& wire); @@ -97,6 +98,8 @@ namespace IfcGeom { void SetValue(GeomValue var, double value); double GetValue(GeomValue var); Ifc2x3::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntities es); + + namespace Cache { void Purge(); diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index d3ee6aa1a2..78c0db355f 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -131,9 +131,9 @@ const TopoDS_Shape& IfcGeom::ensure_fit_for_subtraction(const TopoDS_Shape& shap } bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, - const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes) { + const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes) { // Iterate over IfcOpeningElements - IfcGeom::ShapeList opening_shapes; + IfcGeom::IfcRepresentationShapeItems opening_shapes; unsigned int last_size = 0; for ( Ifc2x3::IfcRelVoidsElement::it it = openings->begin(); it != openings->end(); ++ it ) { Ifc2x3::IfcRelVoidsElement::ptr v = *it; @@ -156,17 +156,17 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x const unsigned int current_size = (const unsigned int) opening_shapes.size(); for ( unsigned int i = last_size; i < current_size; ++ i ) { - opening_shapes[i].first->PreMultiply(opening_trsf); + opening_shapes[i].move(opening_trsf); } last_size = current_size; } } // Iterate over the shapes of the IfcProduct - for ( IfcGeom::ShapeList::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { + for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { TopoDS_Shape entity_shape_solid; - const TopoDS_Shape& entity_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(*(it3->second),entity_shape_solid); - const gp_GTrsf& entity_shape_gtrsf = *(it3->first); + const TopoDS_Shape& entity_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); + const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); TopoDS_Shape entity_shape; if ( entity_shape_gtrsf.Form() == gp_Other ) { Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity); @@ -176,10 +176,10 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x } // Iterate over the shapes of the IfcOpeningElements - for ( IfcGeom::ShapeList::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) { + for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) { TopoDS_Shape opening_shape_solid; - const TopoDS_Shape& opening_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(*(it4->second),opening_shape_solid); - const gp_GTrsf& opening_shape_gtrsf = *(it4->first); + const TopoDS_Shape& opening_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(it4->Shape(),opening_shape_solid); + const gp_GTrsf& opening_shape_gtrsf = it4->Placement(); if ( opening_shape_gtrsf.Form() == gp_Other ) { Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to opening of:",entity->entity); } @@ -218,19 +218,14 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x } } - cut_shapes.push_back(IfcGeom::LocationShape(new gp_GTrsf(),new TopoDS_Shape(entity_shape))); - } - - // Delete references to opening transformations, but keep shapes in the cache - for ( IfcGeom::ShapeList::const_iterator it5 = opening_shapes.begin(); it5 != opening_shapes.end(); ++ it5 ) { - delete it5->first; + cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(entity_shape, &it3->Style())); } return true; } bool IfcGeom::convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, - const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes) { + const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes) { // Create a compound of all opening shapes in order to speed up the boolean operations TopoDS_Compound opening_compound; @@ -252,32 +247,29 @@ bool IfcGeom::convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcProductRepresentation::ptr prodrep = fes->Representation(); Ifc2x3::IfcRepresentation::list reps = prodrep->Representations(); - IfcGeom::ShapeList opening_shapes; + IfcGeom::IfcRepresentationShapeItems opening_shapes; for ( Ifc2x3::IfcRepresentation::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) { IfcGeom::convert_shapes(*it2,opening_shapes); } for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) { - gp_GTrsf& gtrsf = *opening_shapes[i].first; + gp_GTrsf gtrsf = opening_shapes[i].Placement(); gtrsf.PreMultiply(opening_trsf); const TopoDS_Shape& opening_shape = gtrsf.Form() == gp_Other - ? BRepBuilderAPI_GTransform(*opening_shapes[i].second,gtrsf,true).Shape() - : (*opening_shapes[i].second).Moved(gtrsf.Trsf()); + ? BRepBuilderAPI_GTransform(opening_shapes[i].Shape(),gtrsf,true).Shape() + : (opening_shapes[i].Shape()).Moved(gtrsf.Trsf()); builder.Add(opening_compound,opening_shape); } - for ( IfcGeom::ShapeList::const_iterator it5 = opening_shapes.begin(); it5 != opening_shapes.end(); ++ it5 ) { - delete it5->first; - } } } // Iterate over the shapes of the IfcProduct - for ( IfcGeom::ShapeList::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { + for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { TopoDS_Shape entity_shape_solid; - const TopoDS_Shape& entity_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(*(it3->second),entity_shape_solid); - const gp_GTrsf& entity_shape_gtrsf = *(it3->first); + const TopoDS_Shape& entity_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); + const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); TopoDS_Shape entity_shape; if ( entity_shape_gtrsf.Form() == gp_Other ) { Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity); @@ -294,7 +286,7 @@ bool IfcGeom::convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const BRepCheck_Analyzer analyser(brep_cut_result); is_valid = analyser.IsValid() != 0; if ( is_valid ) { - cut_shapes.push_back(IfcGeom::LocationShape(new gp_GTrsf(),new TopoDS_Shape(brep_cut_result))); + cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(brep_cut_result, &it3->Style())); } } if ( !is_valid ) { diff --git a/src/ifcgeom/IfcGeomObjects.cpp b/src/ifcgeom/IfcGeomObjects.cpp index e82158e5be..b9aca028cc 100644 --- a/src/ifcgeom/IfcGeomObjects.cpp +++ b/src/ifcgeom/IfcGeomObjects.cpp @@ -53,13 +53,13 @@ bool use_faster_booleans = false; bool disable_subtractions = false; bool disable_triangulation = false; -int IfcGeomObjects::IfcRepresentationTriangulation::addvert(const gp_XYZ& p) { +int IfcGeomObjects::IfcRepresentationTriangulation::addvert(int material_index, const gp_XYZ& p) { const float X = convert_back_units ? (float) (p.X() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.X(); const float Y = convert_back_units ? (float) (p.Y() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Y(); const float Z = convert_back_units ? (float) (p.Z() / IfcGeom::GetValue(IfcGeom::GV_LENGTH_UNIT)) : (float)p.Z(); int i = (int) verts.size() / 3; if ( weld_vertices ) { - const VertKey key = VertKey(X,std::pair(Y,Z)); + const VertKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z))); VertKeyMap::const_iterator it = welds.find(key); if ( it != welds.end() ) return it->second; i = (int) welds.size(); @@ -83,9 +83,9 @@ IfcGeomObjects::IfcRepresentationBrepData::IfcRepresentationBrepData(const IfcRe TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); - for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { - const TopoDS_Shape& s = *(*it).second; - const gp_GTrsf& trsf = *(*it).first; + for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { + const TopoDS_Shape& s = it->Shape(); + const gp_GTrsf& trsf = it->Placement(); bool trsf_valid = false; gp_Trsf _trsf; try { @@ -107,10 +107,21 @@ IfcGeomObjects::IfcRepresentationBrepData::IfcRepresentationBrepData(const IfcRe IfcGeomObjects::IfcRepresentationTriangulation::IfcRepresentationTriangulation(const IfcRepresentationShapeModel& shapes) : id(shapes.getId()) { - for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { + for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { - const TopoDS_Shape& s = *it->second; - const gp_GTrsf& trsf = *it->first; + int surface_style_id = -1; + if (it->hasStyle()) { + std::vector::const_iterator jt = std::find(surface_styles.begin(), surface_styles.end(), &it->Style()); + if (jt == surface_styles.end()) { + surface_style_id = surface_styles.size(); + surface_styles.push_back(&it->Style()); + } else { + surface_style_id = jt - surface_styles.begin(); + } + } + + const TopoDS_Shape& s = it->Shape(); + const gp_GTrsf& trsf = it->Placement(); // Triangulate the shape try { @@ -150,7 +161,7 @@ IfcGeomObjects::IfcRepresentationTriangulation::IfcRepresentationTriangulation(c for( int i = 1; i <= nodes.Length(); ++ i ) { coords.push_back(nodes(i).Transformed(loc).XYZ()); trsf.Transforms(*coords.rbegin()); - dict[i] = addvert(*coords.rbegin()); + dict[i] = addvert(surface_style_id, *coords.rbegin()); if ( calculate_normals ) { const gp_Pnt2d& uv = uvs(i); @@ -189,6 +200,8 @@ IfcGeomObjects::IfcRepresentationTriangulation::IfcRepresentationTriangulation(c faces.push_back(dict[n2]); faces.push_back(dict[n3]); + materials.push_back(surface_style_id); + addedge(n1,n2,edgecount,edges_temp); addedge(n2,n3,edgecount,edges_temp); addedge(n3,n1,edgecount,edges_temp); @@ -369,7 +382,7 @@ IfcGeomObjects::IfcGeomShapeModelObject* create_shape_model_for_next_entity() { } IfcGeomObjects::IfcRepresentationShapeModel* shape; - IfcGeom::ShapeList shapes; + IfcGeom::IfcRepresentationShapeItems shapes; if ( !IfcGeom::convert_shapes(shaperep,shapes) ) { _nextShape(); @@ -412,15 +425,11 @@ IfcGeomObjects::IfcGeomShapeModelObject* create_shape_model_for_next_entity() { } if ( !disable_subtractions && openings && openings->Size() ) { - IfcGeom::ShapeList opened_shapes; + IfcGeom::IfcRepresentationShapeItems opened_shapes; try { if ( use_faster_booleans ) { bool succes = IfcGeom::convert_openings_fast(ifc_product,openings,shapes,trsf,opened_shapes); if ( ! succes ) { - for ( IfcGeom::ShapeList::const_iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) { - delete it->first; - delete it->second; - } opened_shapes.clear(); IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes); } @@ -431,18 +440,15 @@ IfcGeomObjects::IfcGeomShapeModelObject* create_shape_model_for_next_entity() { Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",ifc_product->entity); } if ( use_world_coords ) { - for ( IfcGeom::ShapeList::const_iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) { - it->first->PreMultiply(trsf); + for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) { + it->move(trsf); } trsf = gp_Trsf(); } shape = new IfcGeomObjects::IfcRepresentationShapeModel(shaperep->entity->id(),opened_shapes,true); - for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { - delete it->first; - } } else if ( use_world_coords ) { - for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { - it->first->PreMultiply(trsf); + for ( IfcGeom::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++ it ) { + it->move(trsf); } trsf = gp_Trsf(); shape = new IfcGeomObjects::IfcRepresentationShapeModel(shaperep->entity->id(),shapes); diff --git a/src/ifcgeom/IfcGeomObjects.h b/src/ifcgeom/IfcGeomObjects.h index 5e8a1ede2c..f0f48dc0e7 100644 --- a/src/ifcgeom/IfcGeomObjects.h +++ b/src/ifcgeom/IfcGeomObjects.h @@ -63,7 +63,7 @@ #include #include "../ifcparse/IfcParse.h" -#include "../ifcgeom/IfcShapeList.h" +#include "../ifcgeom/IfcRepresentationShapeItem.h" namespace IfcGeomObjects { @@ -107,11 +107,9 @@ namespace IfcGeomObjects { // End of settings enumeration. - // Some typedefs for convenience - typedef std::vector::const_iterator IntIt; - typedef std::vector::const_iterator FltIt; - // A nested pair of doubles to be able to store an XYZ coordinate in a map. - typedef std::pair< float,std::pair > VertKey; + // A nested pair of floats and a material index to be able to store an XYZ coordinate in a map. + // TODO: Make this a std::tuple when compilers add support for that. + typedef std::pair > > VertKey; typedef std::map VertKeyMap; typedef std::pair Edge; @@ -119,25 +117,18 @@ namespace IfcGeomObjects { private: unsigned int id; bool owns_shapes; - const IfcGeom::ShapeList shapes; + const IfcGeom::IfcRepresentationShapeItems shapes; IfcRepresentationShapeModel(const IfcRepresentationShapeModel& other); IfcRepresentationShapeModel& operator=(const IfcRepresentationShapeModel& other); public: - IfcRepresentationShapeModel(unsigned int id, const IfcGeom::ShapeList& shapes, bool owns_shapes = false) + IfcRepresentationShapeModel(unsigned int id, const IfcGeom::IfcRepresentationShapeItems& shapes, bool owns_shapes = false) : id(id) , shapes(shapes) , owns_shapes(owns_shapes) {} - ~IfcRepresentationShapeModel() { - for ( IfcGeom::ShapeList::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { - delete it->first; - if (owns_shapes) { - delete it->second; - } - } - } - IfcGeom::ShapeList::const_iterator begin() const { return shapes.begin(); } - IfcGeom::ShapeList::const_iterator end() const { return shapes.end(); } + virtual ~IfcRepresentationShapeModel() {} + IfcGeom::IfcRepresentationShapeItems::const_iterator begin() const { return shapes.begin(); } + IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes.end(); } const unsigned int& getId() const { return id; } }; @@ -146,6 +137,7 @@ namespace IfcGeomObjects { int id; std::string brep_data; IfcRepresentationBrepData(const IfcRepresentationShapeModel& s); + virtual ~IfcRepresentationBrepData() {} }; class IfcRepresentationTriangulation { @@ -155,11 +147,14 @@ namespace IfcGeomObjects { std::vector faces; std::vector edges; std::vector normals; + std::vector materials; + std::vector surface_styles; VertKeyMap welds; IfcRepresentationTriangulation(const IfcRepresentationShapeModel& s); + virtual ~IfcRepresentationTriangulation() {} private: - int addvert(const gp_XYZ& p); + int addvert(int material_index, const gp_XYZ& p); inline void addedge(int n1, int n2, std::map,int>& edgecount, std::vector >& edges_temp) { const Edge e = Edge( (std::min)(n1,n2),(std::max)(n1,n2) ); if ( edgecount.find(e) == edgecount.end() ) edgecount[e] = 1; diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index dccb1a5147..6cc28af945 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -92,20 +92,22 @@ bool IfcGeom::convert(const Ifc2x3::IfcExtrudedAreaSolid::ptr l, TopoDS_Shape& s shape.Move(trsf); return ! shape.IsNull(); } -bool IfcGeom::convert(const Ifc2x3::IfcFacetedBrep::ptr l, ShapeList& shape) { +bool IfcGeom::convert(const Ifc2x3::IfcFacetedBrep::ptr l, IfcRepresentationShapeItems& shape) { TopoDS_Shape s; - if ( const TopoDS_Shape* shape_id = IfcGeom::convert_shape(l->Outer(),s) ) { - shape.push_back(LocationShape(new gp_GTrsf(),shape_id)); + if (IfcGeom::convert_shape(l->Outer(),s) ) { + shape.push_back(IfcRepresentationShapeItem(s, get_style(l->Outer()))); return true; } return false; } -bool IfcGeom::convert(const Ifc2x3::IfcFaceBasedSurfaceModel::ptr l, ShapeList& shapes) { +bool IfcGeom::convert(const Ifc2x3::IfcFaceBasedSurfaceModel::ptr l, IfcRepresentationShapeItems& shapes) { Ifc2x3::IfcConnectedFaceSet::list facesets = l->FbsmFaces(); + const SurfaceStyle* collective_style = get_style(l); for( Ifc2x3::IfcConnectedFaceSet::it it = facesets->begin(); it != facesets->end(); ++ it ) { TopoDS_Shape s; - if ( const TopoDS_Shape* shape_id = IfcGeom::convert_shape(*it,s) ) { - shapes.push_back(LocationShape(new gp_GTrsf(),shape_id)); + const SurfaceStyle* shell_style = get_style(*it); + if (IfcGeom::convert_shape(*it,s)) { + shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style)); } } return true; @@ -135,12 +137,17 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr l, TopoDS_ shape = BRepAlgoAPI_Common(halfspace,prism); return true; } -bool IfcGeom::convert(const Ifc2x3::IfcShellBasedSurfaceModel::ptr l, ShapeList& shapes) { +bool IfcGeom::convert(const Ifc2x3::IfcShellBasedSurfaceModel::ptr l, IfcRepresentationShapeItems& shapes) { IfcUtil::IfcAbstractSelect::list shells = l->SbsmBoundary(); + const SurfaceStyle* collective_style = get_style(l); for( IfcUtil::IfcAbstractSelect::it it = shells->begin(); it != shells->end(); ++ it ) { TopoDS_Shape s; - if ( const TopoDS_Shape* shape_id = IfcGeom::convert_shape(*it,s) ) { - shapes.push_back(LocationShape(new gp_GTrsf(),shape_id)); + const SurfaceStyle* shell_style = 0; + if ((*it)->is(Ifc2x3::Type::IfcRepresentationItem)) { + shell_style = get_style((Ifc2x3::IfcRepresentationItem*)*it); + } + if (IfcGeom::convert_shape(*it,s)) { + shapes.push_back(IfcRepresentationShapeItem(s, shell_style ? shell_style : collective_style)); } } return true; @@ -334,7 +341,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh } return true; } -bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, ShapeList& shapes) { +bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, IfcRepresentationShapeItems& shapes) { gp_GTrsf gtrsf; Ifc2x3::IfcCartesianTransformationOperator::ptr transform = l->MappingTarget(); if ( transform->is(Ifc2x3::Type::IfcCartesianTransformationOperator3DnonUniform) ) { @@ -367,19 +374,22 @@ bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, ShapeList& shapes) { const unsigned int previous_size = (const unsigned int) shapes.size(); bool b = IfcGeom::convert_shapes(map->MappedRepresentation(),shapes); for ( unsigned int i = previous_size; i < shapes.size(); ++ i ) { - shapes[i].first->Multiply(gtrsf); + shapes[i].move(gtrsf); } return b; } -bool IfcGeom::convert(const Ifc2x3::IfcShapeRepresentation::ptr l, ShapeList& shapes) { + +bool IfcGeom::convert(const Ifc2x3::IfcShapeRepresentation::ptr l, IfcRepresentationShapeItems& shapes) { Ifc2x3::IfcRepresentationItem::list items = l->Items(); if ( ! items->Size() ) return false; for ( Ifc2x3::IfcRepresentationItem::it it = items->begin(); it != items->end(); ++ it ) { - if ( IfcGeom::is_shape_collection(*it) ) IfcGeom::convert_shapes(*it,shapes); + Ifc2x3::IfcRepresentationItem* representation_item = *it; + if ( IfcGeom::is_shape_collection(representation_item) ) IfcGeom::convert_shapes(*it,shapes); else { TopoDS_Shape s; - if ( const TopoDS_Shape* shape_id = IfcGeom::convert_shape(*it,s)) - shapes.push_back(LocationShape(new gp_GTrsf(),shape_id)); + if (IfcGeom::convert_shape(representation_item,s)) { + shapes.push_back(IfcRepresentationShapeItem(s, get_style(representation_item))); + } } } return true; diff --git a/src/ifcgeom/IfcRegister.cpp b/src/ifcgeom/IfcRegister.cpp index 07e2f63f67..52b433c510 100644 --- a/src/ifcgeom/IfcRegister.cpp +++ b/src/ifcgeom/IfcRegister.cpp @@ -31,7 +31,7 @@ namespace IfcGeom { using namespace Ifc2x3; using namespace IfcUtil; -bool IfcGeom::convert_shapes(const IfcBaseClass* l, ShapeList& r) { +bool IfcGeom::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) { #include "IfcRegisterConvertShapes.h" Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); return false; @@ -40,10 +40,10 @@ bool IfcGeom::is_shape_collection(const IfcBaseClass* l) { #include "IfcRegisterIsShapeCollection.h" return false; } -const TopoDS_Shape* IfcGeom::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) { +bool IfcGeom::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) { const unsigned int id = l->entity->id(); std::map::const_iterator it = Cache::Shape.find(id); - if ( it != Cache::Shape.end() ) { r = it->second; return &(it->second); } + if ( it != Cache::Shape.end() ) { r = it->second; return true; } #include "IfcRegisterConvertShape.h" Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); return 0; diff --git a/src/ifcgeom/IfcRegisterConvertShape.h b/src/ifcgeom/IfcRegisterConvertShape.h index 67c381ac93..8cb8e35496 100644 --- a/src/ifcgeom/IfcRegisterConvertShape.h +++ b/src/ifcgeom/IfcRegisterConvertShape.h @@ -4,7 +4,7 @@ try { \ if ( convert((T*)l,r) ) { \ Cache::Shape[id] = r; \ - return &(Cache::Shape[id]); \ + return true; \ } \ } catch(...) { } \ Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \ diff --git a/src/ifcgeom/IfcRegisterGeomHeader.h b/src/ifcgeom/IfcRegisterGeomHeader.h index f87265aad4..e8588b0fa8 100644 --- a/src/ifcgeom/IfcRegisterGeomHeader.h +++ b/src/ifcgeom/IfcRegisterGeomHeader.h @@ -1,6 +1,6 @@ #include "IfcRegisterUndef.h" #define CLASS(T,V) bool convert(const T::ptr L, V& r); -#define SHAPES(T) CLASS(T,ShapeList) +#define SHAPES(T) CLASS(T,IfcRepresentationShapeItems) #define SHAPE(T) CLASS(T,TopoDS_Shape) #define WIRE(T) CLASS(T,TopoDS_Wire) #define FACE(T) CLASS(T,TopoDS_Face) diff --git a/win/IfcGeom.vcproj b/win/IfcGeom.vcproj index fd1cd0f5b7..e0a97425e5 100644 --- a/win/IfcGeom.vcproj +++ b/win/IfcGeom.vcproj @@ -170,6 +170,10 @@ RelativePath="..\src\ifcgeom\IfcGeomObjects.cpp" > + + @@ -196,6 +200,10 @@ RelativePath="..\src\ifcgeom\IfcGeomObjects.h" > + + @@ -236,6 +244,10 @@ RelativePath="..\src\ifcgeom\IfcRegisterUndef.h" > + +