Store edges representation item ids in Triangulation

This commit is contained in:
Andrej730
2024-09-25 15:15:47 +05:00
parent aad66f94a3
commit dd9de98290
8 changed files with 109 additions and 10 deletions
+1 -1
View File
@@ -915,7 +915,7 @@ class Loader(bonsai.core.tool.Loader):
#
# we do `.tolist()` because Blender can't assign `np.int32` to it's custom attributes
mesh["ios_edges"] = list(set(tuple(e) for e in ifcopenshell.util.shape.get_edges(geometry).tolist()))
mesh["ios_item_ids"] = ifcopenshell.util.shape.get_representation_item_ids(geometry).tolist()
mesh["ios_item_ids"] = ifcopenshell.util.shape.get_faces_representation_item_ids(geometry).tolist()
mesh.vertices.add(num_vertices)
mesh.vertices.foreach_set("co", verts)
+8 -2
View File
@@ -117,6 +117,7 @@ namespace IfcGeom {
std::vector<int> material_ids_;
std::vector<ifcopenshell::geometry::taxonomy::style::ptr> materials_;
std::vector<int> item_ids_;
std::vector<int> edges_item_ids_;
size_t weld_offset_;
VertexKeyMap welds;
@@ -137,6 +138,7 @@ namespace IfcGeom {
const std::vector<int>& material_ids() const { return material_ids_; }
const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& materials() const { return materials_; }
const std::vector<int>& item_ids() const { return item_ids_; }
const std::vector<int>& edges_item_ids() const { return edges_item_ids_; }
Triangulation(const BRep& shape_model);
@@ -152,6 +154,7 @@ namespace IfcGeom {
const std::vector<int>& material_ids,
const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& materials,
const std::vector<int>& item_ids
, const std::vector<int>& edges_item_ids
)
: Representation(settings, entity, id)
, verts_(verts)
@@ -162,6 +165,7 @@ namespace IfcGeom {
, material_ids_(material_ids)
, materials_(materials)
, item_ids_(item_ids)
, edges_item_ids_(edges_item_ids)
{}
virtual ~Triangulation() {}
@@ -204,16 +208,18 @@ namespace IfcGeom {
material_ids_.push_back(style);
}
void addEdge(int style, int i0, int i1) {
void addEdge(int item_id, int style, int i0, int i1) {
edges_.push_back(i0);
edges_.push_back(i1);
material_ids_.push_back(style);
edges_item_ids_.push_back(item_id);
}
void registerEdge(int i0, int i1) {
void registerEdge(int item_id, int i0, int i1) {
edges_.push_back(i0);
edges_.push_back(i1);
edges_item_ids_.push_back(item_id);
}
void registerEdgeCount(int n1, int n2, std::map<std::pair<int, int>, int>& edgecount);
@@ -303,7 +303,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
// @todo should be != 2?
if (p.second == 1 && emitted_edges.find(p.first) == emitted_edges.end()) {
// non manifold edge, face boundary
t->registerEdge(p.first.first, p.first.second);
t->registerEdge(item_id, p.first.first, p.first.second);
if (settings.get<settings::WeldVertices>().get()) {
// only relevant while welding, because otherwise vertices are not shared among distinct faces
emitted_edges.insert(p.first);
@@ -386,7 +386,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
}
for (auto& sgmt : segments) {
t->addEdge(surface_style_id, sgmt.first, sgmt.second);
t->addEdge(item_id, surface_style_id, sgmt.first, sgmt.second);
}
previous = current;
@@ -300,11 +300,20 @@ def get_normals(geometry: ShapeType) -> npt.NDArray[np.float64]:
return np.frombuffer(geometry.normals_buffer, dtype="d").reshape(-1, 3)
def get_representation_item_ids(geometry: ShapeType) -> npt.NDArray[np.int32]:
def get_faces_representation_item_ids(geometry: ShapeType) -> npt.NDArray[np.int32]:
"""Get representation item ids for the geometry faces."""
return np.frombuffer(geometry.item_ids_buffer, dtype="i")
def get_edges_representation_item_ids(geometry: ShapeType) -> npt.NDArray[np.int32]:
"""Get representation item ids for the geometry edges.
Can be useful for geometry without faces and in general is more universal
since it's possible that geometry will have elements with and without faces.
"""
return np.frombuffer(geometry.edges_item_ids_buffer, dtype="i")
def get_shape_vertices(shape: ShapeType, geometry: ShapeType) -> npt.NDArray[np.float64]:
"""Get the shape's vertices as a numpy array
@@ -1,11 +1,15 @@
import pytest
import test.bootstrap
import ifcopenshell
import ifcopenshell.api.unit
import ifcopenshell.api.root
import ifcopenshell.api.context
import ifcopenshell.api.project
import ifcopenshell.geom
import ifcopenshell.api.owner.settings
import ifcopenshell.api.project
import ifcopenshell.api.root
import ifcopenshell.api.unit
import ifcopenshell.geom
import ifcopenshell.ifcopenshell_wrapper as W
import ifcopenshell.util.shape
from ifcopenshell.util.shape_builder import ShapeBuilder, V
from typing import get_args
@@ -47,6 +51,77 @@ class TestGeomSettings:
assert "USE_PYTHON_OPENCASCADE" not in repr(settings)
class TestTriangulationAttributes(test.bootstrap.IFC4):
def test_faces_representation_item_ids(self):
ifc_file = ifcopenshell.file()
ifcopenshell.api.root.create_entity(ifc_file, ifc_class="IfcProject", name="Test")
context = ifcopenshell.api.context.add_context(ifc_file, context_type="Model")
builder = ShapeBuilder(ifc_file)
extrusion = builder.extrude(builder.rectangle(), magnitude=1.0)
representation = builder.get_representation(context, extrusion)
settings = ifcopenshell.geom.settings()
shape = ifcopenshell.geom.create_shape(settings, representation)
faces_item_ids = ifcopenshell.util.shape.get_faces_representation_item_ids(shape)
faces = ifcopenshell.util.shape.get_faces(shape)
assert set(faces_item_ids) == {extrusion.id()}
assert len(faces) == 12 # Cube has 12 tris.
assert len(faces_item_ids) == len(faces)
edges_item_ids = ifcopenshell.util.shape.get_edges_representation_item_ids(shape)
edges = ifcopenshell.util.shape.get_edges(shape)
assert set(edges_item_ids) == {extrusion.id()}
assert len(edges) == 12 # Cube has 12 edges.
assert len(edges_item_ids) == len(edges)
def test_curve_representation_item_ids(self):
ifc_file = ifcopenshell.file()
ifcopenshell.api.root.create_entity(ifc_file, ifc_class="IfcProject", name="Test")
context = ifcopenshell.api.context.add_context(ifc_file, context_type="Model")
builder = ShapeBuilder(ifc_file)
curve = builder.rectangle()
representation = builder.get_representation(context, curve)
settings = ifcopenshell.geom.settings()
settings.set("dimensionality", W.CURVES_SURFACES_AND_SOLIDS)
shape = ifcopenshell.geom.create_shape(settings, representation)
faces_item_ids = ifcopenshell.util.shape.get_faces_representation_item_ids(shape)
assert len(faces_item_ids) == 0
edges_item_ids = ifcopenshell.util.shape.get_edges_representation_item_ids(shape)
edges = ifcopenshell.util.shape.get_edges(shape)
assert set(edges_item_ids) == {curve.id()}
assert len(edges) == 4
assert len(edges_item_ids) == len(edges)
def test_mixed_representation_item_ids(self):
ifc_file = ifcopenshell.file()
ifcopenshell.api.root.create_entity(ifc_file, ifc_class="IfcProject", name="Test")
context = ifcopenshell.api.context.add_context(ifc_file, context_type="Model")
builder = ShapeBuilder(ifc_file)
curve = builder.rectangle()
fill = ifc_file.create_entity("IfcAnnotationFillArea", builder.rectangle())
representation = builder.get_representation(context, (curve, fill))
settings = ifcopenshell.geom.settings()
settings.set("dimensionality", W.CURVES_SURFACES_AND_SOLIDS)
shape = ifcopenshell.geom.create_shape(settings, representation)
faces_item_ids = ifcopenshell.util.shape.get_faces_representation_item_ids(shape)
faces = ifcopenshell.util.shape.get_faces(shape)
assert len(faces) == 2 # Fill area will produce a triangulated face.
assert set(faces_item_ids) == {fill.id()}
assert len(faces_item_ids) == len(faces)
edges_item_ids = ifcopenshell.util.shape.get_edges_representation_item_ids(shape)
edges = ifcopenshell.util.shape.get_edges(shape)
assert set(edges_item_ids) == {fill.id(), curve.id()}
assert len(edges) == 8 # 4 edges rectangle curve + 4 edges fill area
assert len(edges_item_ids) == len(edges)
class TestAssignObject:
def test_no_welding_on_distinct_items(self):
self.file = ifcopenshell.api.project.create_file()
+5
View File
@@ -647,6 +647,10 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
return vector_to_buffer(self->item_ids());
}
std::pair<const char*, size_t> edges_item_ids_buffer() const {
return vector_to_buffer(self->edges_item_ids());
}
std::pair<const char*, size_t> verts_buffer() const {
return vector_to_buffer(self->verts());
}
@@ -703,6 +707,7 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
edges_buffer = property(edges_buffer)
material_ids_buffer = property(material_ids_buffer)
item_ids_buffer = property(item_ids_buffer)
edges_item_ids_buffer = property(edges_item_ids_buffer)
verts_buffer = property(verts_buffer)
normals_buffer = property(normals_buffer)
colors_buffer = property(colors_buffer)
+3
View File
@@ -398,6 +398,7 @@ IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& g
auto uvcoords = read_dataset<double>(meshGroup, DATASET_NAME_UVCOORDS);
auto material_ids = read_dataset<int>(meshGroup, DATASET_NAME_MATERIAL_IDS);
auto item_ids = read_dataset<int>(meshGroup, DATASET_NAME_ITEM_IDS);
auto edges_item_ids = read_dataset<int>(meshGroup, DATASET_NAME_EDGES_ITEM_IDS);
std::vector<surface_style_serialization> surface_styles;
@@ -435,6 +436,7 @@ IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& g
material_ids,
surface_style_ptrs,
item_ids
, edges_item_ids
));
triangulation_cache_.insert({ representation_id_str, triangulation_geometry });
@@ -696,6 +698,7 @@ const H5std_string HdfSerializer::DATASET_NAME_INDICES = "indices";
const H5std_string HdfSerializer::DATASET_NAME_EDGES = "edges";
const H5std_string HdfSerializer::DATASET_NAME_MATERIAL_IDS = "material_ids";
const H5std_string HdfSerializer::DATASET_NAME_ITEM_IDS = "item_ids";
const H5std_string HdfSerializer::DATASET_NAME_EDGES_ITEM_IDS = "edges_item_ids";
const H5std_string HdfSerializer::DATASET_NAME_MATERIALS = "materials";
const H5std_string HdfSerializer::DATASET_NAME_OCCT = "brep";
const H5std_string HdfSerializer::DATASET_NAME_PLACEMENT = "placement";
+1
View File
@@ -47,6 +47,7 @@ private:
static const H5std_string DATASET_NAME_EDGES;
static const H5std_string DATASET_NAME_MATERIAL_IDS;
static const H5std_string DATASET_NAME_ITEM_IDS;
static const H5std_string DATASET_NAME_EDGES_ITEM_IDS;
static const H5std_string DATASET_NAME_MATERIALS;
static const H5std_string DATASET_NAME_OCCT;
static const H5std_string DATASET_NAME_PLACEMENT;