mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Store edges representation item ids in Triangulation
This commit is contained in:
@@ -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
|
# 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_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.add(num_vertices)
|
||||||
mesh.vertices.foreach_set("co", verts)
|
mesh.vertices.foreach_set("co", verts)
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ namespace IfcGeom {
|
|||||||
std::vector<int> material_ids_;
|
std::vector<int> material_ids_;
|
||||||
std::vector<ifcopenshell::geometry::taxonomy::style::ptr> materials_;
|
std::vector<ifcopenshell::geometry::taxonomy::style::ptr> materials_;
|
||||||
std::vector<int> item_ids_;
|
std::vector<int> item_ids_;
|
||||||
|
std::vector<int> edges_item_ids_;
|
||||||
size_t weld_offset_;
|
size_t weld_offset_;
|
||||||
VertexKeyMap welds;
|
VertexKeyMap welds;
|
||||||
|
|
||||||
@@ -137,6 +138,7 @@ namespace IfcGeom {
|
|||||||
const std::vector<int>& material_ids() const { return material_ids_; }
|
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<ifcopenshell::geometry::taxonomy::style::ptr>& materials() const { return materials_; }
|
||||||
const std::vector<int>& item_ids() const { return item_ids_; }
|
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);
|
Triangulation(const BRep& shape_model);
|
||||||
|
|
||||||
@@ -152,6 +154,7 @@ namespace IfcGeom {
|
|||||||
const std::vector<int>& material_ids,
|
const std::vector<int>& material_ids,
|
||||||
const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& materials,
|
const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& materials,
|
||||||
const std::vector<int>& item_ids
|
const std::vector<int>& item_ids
|
||||||
|
, const std::vector<int>& edges_item_ids
|
||||||
)
|
)
|
||||||
: Representation(settings, entity, id)
|
: Representation(settings, entity, id)
|
||||||
, verts_(verts)
|
, verts_(verts)
|
||||||
@@ -162,6 +165,7 @@ namespace IfcGeom {
|
|||||||
, material_ids_(material_ids)
|
, material_ids_(material_ids)
|
||||||
, materials_(materials)
|
, materials_(materials)
|
||||||
, item_ids_(item_ids)
|
, item_ids_(item_ids)
|
||||||
|
, edges_item_ids_(edges_item_ids)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual ~Triangulation() {}
|
virtual ~Triangulation() {}
|
||||||
@@ -204,16 +208,18 @@ namespace IfcGeom {
|
|||||||
material_ids_.push_back(style);
|
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(i0);
|
||||||
edges_.push_back(i1);
|
edges_.push_back(i1);
|
||||||
|
|
||||||
material_ids_.push_back(style);
|
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(i0);
|
||||||
edges_.push_back(i1);
|
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);
|
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?
|
// @todo should be != 2?
|
||||||
if (p.second == 1 && emitted_edges.find(p.first) == emitted_edges.end()) {
|
if (p.second == 1 && emitted_edges.find(p.first) == emitted_edges.end()) {
|
||||||
// non manifold edge, face boundary
|
// 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()) {
|
if (settings.get<settings::WeldVertices>().get()) {
|
||||||
// only relevant while welding, because otherwise vertices are not shared among distinct faces
|
// only relevant while welding, because otherwise vertices are not shared among distinct faces
|
||||||
emitted_edges.insert(p.first);
|
emitted_edges.insert(p.first);
|
||||||
@@ -386,7 +386,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto& sgmt : segments) {
|
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;
|
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)
|
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."""
|
"""Get representation item ids for the geometry faces."""
|
||||||
return np.frombuffer(geometry.item_ids_buffer, dtype="i")
|
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]:
|
def get_shape_vertices(shape: ShapeType, geometry: ShapeType) -> npt.NDArray[np.float64]:
|
||||||
"""Get the shape's vertices as a numpy array
|
"""Get the shape's vertices as a numpy array
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
import test.bootstrap
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.api.unit
|
|
||||||
import ifcopenshell.api.root
|
|
||||||
import ifcopenshell.api.context
|
import ifcopenshell.api.context
|
||||||
import ifcopenshell.api.project
|
|
||||||
import ifcopenshell.geom
|
|
||||||
import ifcopenshell.api.owner.settings
|
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
|
from typing import get_args
|
||||||
|
|
||||||
|
|
||||||
@@ -47,6 +51,77 @@ class TestGeomSettings:
|
|||||||
assert "USE_PYTHON_OPENCASCADE" not in repr(settings)
|
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:
|
class TestAssignObject:
|
||||||
def test_no_welding_on_distinct_items(self):
|
def test_no_welding_on_distinct_items(self):
|
||||||
self.file = ifcopenshell.api.project.create_file()
|
self.file = ifcopenshell.api.project.create_file()
|
||||||
|
|||||||
@@ -647,6 +647,10 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
|||||||
return vector_to_buffer(self->item_ids());
|
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 {
|
std::pair<const char*, size_t> verts_buffer() const {
|
||||||
return vector_to_buffer(self->verts());
|
return vector_to_buffer(self->verts());
|
||||||
}
|
}
|
||||||
@@ -703,6 +707,7 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
|||||||
edges_buffer = property(edges_buffer)
|
edges_buffer = property(edges_buffer)
|
||||||
material_ids_buffer = property(material_ids_buffer)
|
material_ids_buffer = property(material_ids_buffer)
|
||||||
item_ids_buffer = property(item_ids_buffer)
|
item_ids_buffer = property(item_ids_buffer)
|
||||||
|
edges_item_ids_buffer = property(edges_item_ids_buffer)
|
||||||
verts_buffer = property(verts_buffer)
|
verts_buffer = property(verts_buffer)
|
||||||
normals_buffer = property(normals_buffer)
|
normals_buffer = property(normals_buffer)
|
||||||
colors_buffer = property(colors_buffer)
|
colors_buffer = property(colors_buffer)
|
||||||
|
|||||||
@@ -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 uvcoords = read_dataset<double>(meshGroup, DATASET_NAME_UVCOORDS);
|
||||||
auto material_ids = read_dataset<int>(meshGroup, DATASET_NAME_MATERIAL_IDS);
|
auto material_ids = read_dataset<int>(meshGroup, DATASET_NAME_MATERIAL_IDS);
|
||||||
auto item_ids = read_dataset<int>(meshGroup, DATASET_NAME_ITEM_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;
|
std::vector<surface_style_serialization> surface_styles;
|
||||||
|
|
||||||
@@ -435,6 +436,7 @@ IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& g
|
|||||||
material_ids,
|
material_ids,
|
||||||
surface_style_ptrs,
|
surface_style_ptrs,
|
||||||
item_ids
|
item_ids
|
||||||
|
, edges_item_ids
|
||||||
));
|
));
|
||||||
|
|
||||||
triangulation_cache_.insert({ representation_id_str, triangulation_geometry });
|
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_EDGES = "edges";
|
||||||
const H5std_string HdfSerializer::DATASET_NAME_MATERIAL_IDS = "material_ids";
|
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_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_MATERIALS = "materials";
|
||||||
const H5std_string HdfSerializer::DATASET_NAME_OCCT = "brep";
|
const H5std_string HdfSerializer::DATASET_NAME_OCCT = "brep";
|
||||||
const H5std_string HdfSerializer::DATASET_NAME_PLACEMENT = "placement";
|
const H5std_string HdfSerializer::DATASET_NAME_PLACEMENT = "placement";
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ private:
|
|||||||
static const H5std_string DATASET_NAME_EDGES;
|
static const H5std_string DATASET_NAME_EDGES;
|
||||||
static const H5std_string DATASET_NAME_MATERIAL_IDS;
|
static const H5std_string DATASET_NAME_MATERIAL_IDS;
|
||||||
static const H5std_string DATASET_NAME_ITEM_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_MATERIALS;
|
||||||
static const H5std_string DATASET_NAME_OCCT;
|
static const H5std_string DATASET_NAME_OCCT;
|
||||||
static const H5std_string DATASET_NAME_PLACEMENT;
|
static const H5std_string DATASET_NAME_PLACEMENT;
|
||||||
|
|||||||
Reference in New Issue
Block a user