diff --git a/src/ifcgeom/IfcGeomIteratorImplementation.h b/src/ifcgeom/IfcGeomIteratorImplementation.h index 5cf70522f9..f52da1233a 100644 --- a/src/ifcgeom/IfcGeomIteratorImplementation.h +++ b/src/ifcgeom/IfcGeomIteratorImplementation.h @@ -153,6 +153,16 @@ namespace IfcGeom { BRepElement* current_shape_model; SerializedElement* current_serialization; + // Structures for chunking + int offset = 0; + int colour_offset = 0; + std::vector chunked_verts; + std::vector chunked_faces; + std::vector chunked_materials; + std::vector chunked_material_ids; + std::vector> chunked_colours; + std::vector> colours; + // A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator IfcSchema::IfcProduct::list::ptr ifcproducts; IfcSchema::IfcProduct::list::it ifcproduct_iterator; @@ -760,7 +770,7 @@ namespace IfcGeom { if (rt == GeometrySerializer::READ_TRIANGULATION) { cache_->write((IfcGeom::TriangulationElement*) element); } else { - cache_->write((IfcGeom::BRepElement*)element); + // cache_->write((IfcGeom::BRepElement*)element); } } #endif @@ -940,6 +950,128 @@ namespace IfcGeom { } } + void apply_matrix_to_flat_verts(const std::vector& flat_list, const std::vector& matrix, std::vector& result) { + result.clear(); + result.reserve(flat_list.size()); + + for (size_t i = 0; i < flat_list.size(); i += 3) { + double x = flat_list[i]; + double y = flat_list[i + 1]; + double z = flat_list[i + 2]; + result.push_back(x * matrix[0] + y * matrix[3] + z * matrix[6] + matrix[9]); + result.push_back(x * matrix[1] + y * matrix[4] + z * matrix[7] + matrix[10]); + result.push_back(x * matrix[2] + y * matrix[5] + z * matrix[8] + matrix[11]); + } + } + + bool process_chunk() + { + if (colours.size() == 0) { + colours.push_back({1, 1, 1, 1}); // Fallback "no material" colour + chunked_colours.push_back({1, 1, 1, 1}); + } + + const float tolerance = 0.01f; // Tolerance value for comparison + int chunk_size = 10000; + + // Only works for multithreaded right now + TriangulationElement* ret = 0; + ret = dynamic_cast(*task_result_iterator_); + + const std::vector& matrix = ret->transformation().matrix().data(); + const std::vector& geometry_verts = ret->geometry().verts(); + const std::vector& geometry_faces = ret->geometry().faces(); + const auto& materials = ret->geometry().materials(); + const auto& material_ids = ret->geometry().material_ids(); + + std::vector verts; + apply_matrix_to_flat_verts(geometry_verts, matrix, verts); + + // Redo with resize and pushback to prevent unneccessary reallocations + std::vector faces = geometry_faces; + for (size_t i = 0; i < faces.size(); ++i) { + faces[i] += offset; + } + + chunked_verts.insert(chunked_verts.end(), verts.begin(), verts.end()); + chunked_faces.insert(chunked_faces.end(), faces.begin(), faces.end()); + + std::vector material_keys; + for (const auto& material : materials) { + float alpha = 1.0; + if (material.hasTransparency() && material.transparency() > 0) { + alpha = 1.0 - material.transparency(); + } + + int i = 0; + bool is_existing_colour = false; + for (const auto& colour : colours) { + if (std::abs(colour[0] - static_cast(material.diffuse()[0])) < tolerance + && std::abs(colour[1] - static_cast(material.diffuse()[1])) < tolerance + && std::abs(colour[2] - static_cast(material.diffuse()[2])) < tolerance + && std::abs(colour[3] - alpha) < tolerance) { + is_existing_colour = true; + break; + } + i++; + } + + if ( ! is_existing_colour) { + colours.push_back({material.diffuse()[0], material.diffuse()[1], material.diffuse()[2], alpha}); + chunked_colours.push_back({material.diffuse()[0], material.diffuse()[1], material.diffuse()[2], alpha}); + } + + int chunked_index = 0; + auto it = std::find(chunked_materials.begin(), chunked_materials.end(), i); + if (it == chunked_materials.end()) { + // material not used so far in chunk + chunked_index = chunked_materials.size(); + chunked_materials.push_back(i); + } else { + // material already in chunk + chunked_index = std::distance(chunked_materials.begin(), it); + } + material_keys.push_back(chunked_index); + } + + if (materials.size() > 0) { + std::vector mat_ids(material_ids.size()); + for (int i = 0; i mat_ids(faces.size() / 3, 0); + chunked_material_ids.insert(chunked_material_ids.end(), mat_ids.begin(), mat_ids.end()); + } + + offset += verts.size() / 3; + + if (offset > chunk_size) { + return true; + } + + return false; + } + + chunk get_chunk() + { + chunk result = { + std::move(chunked_verts), + std::move(chunked_faces), + std::move(chunked_materials), + std::move(chunked_material_ids), + std::move(chunked_colours), + }; + chunked_verts.clear(); + chunked_faces.clear(); + chunked_materials.clear(); + chunked_material_ids.clear(); + chunked_colours.clear(); + offset = 0; + return result; + } + /// Gets the representation of the current geometrical entity. Element* get() { diff --git a/src/ifcgeom_schema_agnostic/IfcGeomIterator.h b/src/ifcgeom_schema_agnostic/IfcGeomIterator.h index 4f45c108a1..8adf54c585 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomIterator.h +++ b/src/ifcgeom_schema_agnostic/IfcGeomIterator.h @@ -59,6 +59,7 @@ #define IFCGEOMITERATOR_H #include "../ifcgeom_schema_agnostic/IteratorImplementation.h" +#include "../ifcgeom_schema_agnostic/chunk.h" // The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration #ifdef min @@ -138,6 +139,9 @@ namespace IfcGeom { BRepElement* get_native() { return implementation_->get_native(); } + bool process_chunk() { return implementation_->process_chunk(); } + IfcGeom::chunk get_chunk() { return implementation_->get_chunk(); } + const Element* get_object(int id) { return implementation_->get_object(id); } IfcUtil::IfcBaseClass* create() { return implementation_->create(); } diff --git a/src/ifcgeom_schema_agnostic/IteratorImplementation.h b/src/ifcgeom_schema_agnostic/IteratorImplementation.h index 7879263264..388538c20c 100644 --- a/src/ifcgeom_schema_agnostic/IteratorImplementation.h +++ b/src/ifcgeom_schema_agnostic/IteratorImplementation.h @@ -25,6 +25,7 @@ #include "../ifcgeom_schema_agnostic/IfcGeomFilter.h" #include "../ifcgeom_schema_agnostic/GeometrySerializer.h" #include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h" +#include "../ifcgeom_schema_agnostic/chunk.h" #include @@ -71,6 +72,8 @@ namespace IfcGeom { virtual IfcUtil::IfcBaseClass* next() = 0; virtual Element* get() = 0; virtual BRepElement* get_native() = 0; + virtual bool process_chunk() = 0; + virtual IfcGeom::chunk get_chunk() = 0; virtual const Element* get_object(int id) = 0; virtual IfcUtil::IfcBaseClass* create() = 0; virtual ~IteratorImplementation() {} diff --git a/src/ifcgeom_schema_agnostic/chunk.h b/src/ifcgeom_schema_agnostic/chunk.h new file mode 100644 index 0000000000..5ac1102432 --- /dev/null +++ b/src/ifcgeom_schema_agnostic/chunk.h @@ -0,0 +1,17 @@ +// Chunk.h +#ifndef CHUNK_H +#define CHUNK_H + +#include + +namespace IfcGeom { + struct chunk { + std::vector verts; + std::vector faces; + std::vector materials; + std::vector material_ids; + std::vector> colours; + }; +} + +#endif