From 53cd5f834e5a29cb0406a2527e6db91195dbbb54 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 14 Apr 2025 13:27:25 +0500 Subject: [PATCH] add_mesh_representation - reuse shape builder + numpy input support --- .../api/geometry/add_mesh_representation.py | 56 +++++++------------ 1 file changed, 19 insertions(+), 37 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_mesh_representation.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_mesh_representation.py index ddda0c7b8a..9a4b41a4df 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_mesh_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_mesh_representation.py @@ -17,6 +17,9 @@ # along with IfcOpenShell. If not, see . import ifcopenshell.util.unit +import numpy as np +import numpy.typing as npt +from ifcopenshell.util.shape_builder import ShapeBuilder, SequenceOfVectors, VectorType from typing import Optional, TypeVar T = TypeVar("T") @@ -26,11 +29,11 @@ COORD_3D = tuple[float, float, float] def add_mesh_representation( file: ifcopenshell.file, context: ifcopenshell.entity_instance, - vertices: list[list[COORD_3D]], + vertices: list[SequenceOfVectors], edges: Optional[list[list[tuple[int, int]]]] = None, # Optional faces is not supported currently. faces: list[list[list[int]]] = None, - coordinate_offset: Optional[COORD_3D] = None, + coordinate_offset: Optional[VectorType] = None, unit_scale: Optional[float] = None, force_faceted_brep: bool = False, ) -> ifcopenshell.entity_instance: @@ -68,28 +71,34 @@ def add_mesh_representation( usecase = Usecase() usecase.file = file + + # Process arguments. if unit_scale is None: unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file) - return usecase.execute(context, vertices, faces, cooridnate_offset, unit_scale, force_faceted_brep) + np_vertices = np.array(vertices, dtype=np.float64) * (1 / unit_scale) + if coordinate_offset is not None: + np_vertices += coordinate_offset + + return usecase.execute(context, np_vertices, faces, force_faceted_brep) class Usecase: file: ifcopenshell.file + vertices: npt.NDArray[np.float64] + """In project units.""" + def execute( self, context: ifcopenshell.entity_instance, - vertices: list[list[COORD_3D]], + vertices: npt.NDArray[np.float64], faces: list[list[list[int]]], - coordinate_offset: Optional[COORD_3D], - unit_scale: float, force_faceted_brep: bool, ) -> ifcopenshell.entity_instance: + self.builder = ShapeBuilder(self.file) self.vertices = vertices self.faces = faces self.context = context - self.coordinate_offset = coordinate_offset - self.unit_scale = unit_scale self.force_faceted_brep = force_faceted_brep return self.create_mesh_representation() @@ -101,23 +110,7 @@ class Usecase: def create_faceted_brep(self) -> ifcopenshell.entity_instance: items: list[ifcopenshell.entity_instance] = [] for i in range(0, len(self.vertices)): - vertices = [ - self.file.create_entity("IfcCartesianPoint", self.convert_si_to_unit(v)) for v in self.vertices[i] - ] - faces: list[ifcopenshell.entity_instance] = [ - self.file.create_entity( - "IfcFace", - [ - self.file.create_entity( - "IfcFaceOuterBound", - self.file.create_entity("IfcPolyLoop", [vertices[v] for v in f]), - True, - ) - ], - ) - for f in self.faces[i] - ] - items.append(self.file.create_entity("IfcFacetedBrep", self.file.create_entity("IfcClosedShell", faces))) + items.append(self.builder.faceted_brep(self.vertices[i], self.faces[i])) return self.file.create_entity( "IfcShapeRepresentation", self.context, @@ -129,11 +122,7 @@ class Usecase: def create_polygonal_face_set(self) -> ifcopenshell.entity_instance: items: list[ifcopenshell.entity_instance] = [] for i in range(0, len(self.vertices)): - coordinates = self.file.create_entity( - "IfcCartesianPointList3D", [self.convert_si_to_unit(v) for v in self.vertices[i]] - ) - faces = [self.file.create_entity("IfcIndexedPolygonalFace", [v + 1 for v in f]) for f in self.faces[i]] - items.append(self.file.create_entity("IfcPolygonalFaceSet", coordinates, None, faces)) + items.append(self.builder.polygonal_face_set(self.vertices[i], self.faces[i])) return self.file.create_entity( "IfcShapeRepresentation", self.context, @@ -141,10 +130,3 @@ class Usecase: "Tessellation", items, ) - - def convert_si_to_unit(self, co: T) -> T: - if isinstance(co, (tuple, list)): - return [self.convert_si_to_unit(o) for o in co] - if self.coordinate_offset: - return (co / self.unit_scale) + self.coordinate_offset - return co / self.unit_scale