From 7731e5c0f9c0174ee3744166a817c58f521a58ed Mon Sep 17 00:00:00 2001 From: krande Date: Wed, 27 Nov 2024 12:51:02 +0100 Subject: [PATCH 01/22] fix bug in renderer_manager.py when there are no beam elements --- src/ada/visit/renderer_manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ada/visit/renderer_manager.py b/src/ada/visit/renderer_manager.py index 20d63055..5d470842 100644 --- a/src/ada/visit/renderer_manager.py +++ b/src/ada/visit/renderer_manager.py @@ -165,8 +165,9 @@ def scene_from_fem( base_frame = graph.top_level.name if graph is not None else "root" scene = trimesh.Scene(base_frame=base_frame) if scene is None else scene + line_elems = list(fem.elements.lines) - if use_solid_beams: + if use_solid_beams and len(line_elems) > 0: from ada.fem.formats.utils import line_elem_to_beam from ada.occ.tessellating import BatchTessellator from ada.visit.gltf.optimize import concatenate_stores From b2d4c4d66c244c1cddfe2b3a4513b8d3efc0501d Mon Sep 17 00:00:00 2001 From: krande Date: Tue, 3 Dec 2024 10:20:53 +0100 Subject: [PATCH 02/22] use direction not point class for vectors --- src/ada/api/transforms.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ada/api/transforms.py b/src/ada/api/transforms.py index a6e2d3cc..fb63f381 100644 --- a/src/ada/api/transforms.py +++ b/src/ada/api/transforms.py @@ -75,9 +75,9 @@ def __post_init__(self): "Please supply at least two vectors to define a placement." ) - self.xdir = Point(*self.xdir) - self.ydir = Point(*self.ydir) - self.zdir = Point(*self.zdir) + self.xdir = Direction(*self.xdir) + self.ydir = Direction(*self.ydir) + self.zdir = Direction(*self.zdir) if self.origin is None: self.origin = Point(0, 0, 0) From d7221a1b57bbfbd519e1f9c736778172485912b8 Mon Sep 17 00:00:00 2001 From: krande Date: Wed, 4 Dec 2024 19:38:22 +0100 Subject: [PATCH 03/22] minor changes --- src/ada/api/primitives.py | 20 ++++++++++++++++++++ src/ada/api/spatial/part.py | 4 +++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/ada/api/primitives.py b/src/ada/api/primitives.py index f9636c48..6633e8f5 100644 --- a/src/ada/api/primitives.py +++ b/src/ada/api/primitives.py @@ -22,6 +22,8 @@ if TYPE_CHECKING: from OCC.Core.TopoDS import TopoDS_Shape + from ada.geom.solids import Box, ExtrudedAreaSolid + from ada.geom.surfaces import RectangleProfileDef from ada.cadit.ifc.store import IfcStore @@ -221,6 +223,24 @@ def from_p_and_dims(name, p, length, width, height, **kwargs): p2 = [p[0] + length, p[1] + width, p[2] + height] return PrimBox(name, p1, p2, **kwargs) + @staticmethod + def from_box_geom(name, box_geom: Box, **kwargs): + p1 = box_geom.position.location + p2 = p1 + Direction(box_geom.x_length, box_geom.y_length, box_geom.z_length) + return PrimBox(name, p1, p2, **kwargs) + + @staticmethod + def from_extruded_rect_profile(name, extrusion: ExtrudedAreaSolid, **kwargs): + from ada.geom.surfaces import RectangleProfileDef + + if not isinstance(extrusion.swept_area, RectangleProfileDef): + raise ValueError(f"Only RectangleProfileDef is supported for extrusion, got {extrusion.swept_area}") + + rect_profile = extrusion.swept_area + p1 = extrusion.position.location + p2 = [rect_profile.p2[0], rect_profile.p2[1], rect_profile.p2[2] + extrusion.depth] + return PrimBox(name, p1, p2, **kwargs) + @property def units(self): return self._units diff --git a/src/ada/api/spatial/part.py b/src/ada/api/spatial/part.py index 9483a49a..af3da105 100644 --- a/src/ada/api/spatial/part.py +++ b/src/ada/api/spatial/part.py @@ -650,7 +650,9 @@ def get_all_physical_objects( physical_objects.append(all_as_iterable) if by_type is not None: - res = filter(lambda x: type(x) is by_type, chain.from_iterable(physical_objects)) + if not isinstance(by_type, (list, tuple)): + by_type = (by_type,) + res = filter(lambda x: type(x) in by_type, chain.from_iterable(physical_objects)) elif by_metadata is not None: res = filter( lambda x: all(x.metadata.get(key) == value for key, value in by_metadata.items()), From e0d9d3cc72957e9e64cc16412558e7a9cafd4414 Mon Sep 17 00:00:00 2001 From: krande Date: Thu, 5 Dec 2024 12:23:47 +0100 Subject: [PATCH 04/22] include relative placement from product level on imported native ifc geometries --- src/ada/cadit/ifc/read/geom/geom_reader.py | 16 ++++++++++++++++ .../ifc/roundtripping/test_roundtrip_box.py | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/core/cadit/ifc/roundtripping/test_roundtrip_box.py diff --git a/src/ada/cadit/ifc/read/geom/geom_reader.py b/src/ada/cadit/ifc/read/geom/geom_reader.py index f268e436..80117a7c 100644 --- a/src/ada/cadit/ifc/read/geom/geom_reader.py +++ b/src/ada/cadit/ifc/read/geom/geom_reader.py @@ -1,10 +1,13 @@ from typing import Union import ifcopenshell +import numpy as np +from ifcopenshell.util.placement import get_local_placement from ada.geom import curves as geo_cu from ada.geom import solids as geo_so from ada.geom import surfaces as geo_su +from ada.geom.placement import Axis2Placement3D from .solids import extruded_solid_area, ifc_block, revolved_solid_area from .surfaces import advanced_face, triangulated_face_set @@ -19,6 +22,19 @@ def get_product_definitions(prod_def: ifcopenshell.entity_instance) -> list[GEOM continue for item in representation.Items: geometries.append(import_geometry_from_ifc_geom(item)) + + obj_placement = prod_def.ObjectPlacement + if obj_placement.PlacementRelTo: + local_placement = get_local_placement(obj_placement) + offset = [] + for i in range(0, 3): + offset.append(local_placement[i][3]) + offset = np.array(offset) + if not np.equal(offset, np.zeros(3)).all(): + for geom in geometries: + for att in geom.__dict__.values(): + if isinstance(att, Axis2Placement3D): + att.location += offset return geometries diff --git a/tests/core/cadit/ifc/roundtripping/test_roundtrip_box.py b/tests/core/cadit/ifc/roundtripping/test_roundtrip_box.py new file mode 100644 index 00000000..e9901bb9 --- /dev/null +++ b/tests/core/cadit/ifc/roundtripping/test_roundtrip_box.py @@ -0,0 +1,16 @@ +import ada +from ada.config import Config + + +def test_basic_box(): + box = ada.PrimBox('box1', (1, 2, 3), (4, 5, 6)) + a = ada.Assembly() / box + a.ifc_store.sync() + Config().update_config_globally("ifc_import_shape_geom", True) + b = ada.from_ifc(a.ifc_store.f) + results = list(b.get_all_physical_objects()) + assert len(results) == 1 + rshape = results[0] + assert rshape.name == 'box1' + rbox = ada.PrimBox.from_box_geom(rshape.name, rshape.geom.geometry, metadata=rshape.metadata) + assert rbox.p1.is_equal(box.p1) From 6a6f80b4489cda4d7210d4e0aad1f59492a42976 Mon Sep 17 00:00:00 2001 From: krande Date: Thu, 5 Dec 2024 16:49:36 +0100 Subject: [PATCH 05/22] fix int64 to ifc --- src/ada/cadit/ifc/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ada/cadit/ifc/utils.py b/src/ada/cadit/ifc/utils.py index 6072ab5e..fdec1cc5 100644 --- a/src/ada/cadit/ifc/utils.py +++ b/src/ada/cadit/ifc/utils.py @@ -272,6 +272,8 @@ def ifc_value_map(f, value): value_map = {str: "IfcText", float: "IfcReal", int: "IfcInteger", bool: "IfcBoolean"} if type(value) in (np.float64,): value = float(value) + if type(value) in (np.int64,): + value = int(value) ifc_type = value_map.get(type(value), None) if ifc_type is None: logger.warning(f'Unable to find suitable IFC type for "{type(value)}". Will convert it to string') From 6f8c242aa633deb2e51065d463a4568dce033efc Mon Sep 17 00:00:00 2001 From: krande Date: Thu, 5 Dec 2024 19:39:27 +0100 Subject: [PATCH 06/22] fix import of ifc beams --- environment.dev.yml | 1 + src/ada/cadit/ifc/read/read_beams.py | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/environment.dev.yml b/environment.dev.yml index 38c8633c..ccd64666 100644 --- a/environment.dev.yml +++ b/environment.dev.yml @@ -9,6 +9,7 @@ dependencies: - hdf5=1.14.4.3 - paradoc - code-aster + - websockets>=14* - occt=*=*novtk* - trimesh >=4.1.0 - python-dotenv diff --git a/src/ada/cadit/ifc/read/read_beams.py b/src/ada/cadit/ifc/read/read_beams.py index dfbed440..ba1b2619 100644 --- a/src/ada/cadit/ifc/read/read_beams.py +++ b/src/ada/cadit/ifc/read/read_beams.py @@ -67,9 +67,6 @@ def import_straight_beam(ifc_elem, axis, name, sec, mat, ifc_store: IfcStore) -> p1 = body.position.location local_y = calc_yvec(ref_dir, extrude_dir) p2 = p1 + extrude_dir * body.depth - if not rel_place.is_identity(): - p1 += rel_place.origin - p2 += rel_place.origin return Beam( name, From 4fc8ca57eb1a76ff619b68bf91f7fd455e283d5e Mon Sep 17 00:00:00 2001 From: krande Date: Thu, 5 Dec 2024 21:40:10 +0100 Subject: [PATCH 07/22] further work on rotated primitives --- files/ifc_files/box_rotated.ifc | 131 ++++++++++++++++++ src/ada/api/primitives.py | 3 +- src/ada/api/transforms.py | 9 ++ src/ada/cadit/ifc/read/geom/geom_reader.py | 16 --- src/ada/cadit/ifc/read/read_beams.py | 9 ++ src/ada/cadit/ifc/read/read_shapes.py | 10 ++ .../ifc/read/beams/test_ifc_read_beams.py | 10 +- .../test_read_shape_with_transformation.py | 8 ++ 8 files changed, 174 insertions(+), 22 deletions(-) create mode 100644 files/ifc_files/box_rotated.ifc diff --git a/files/ifc_files/box_rotated.ifc b/files/ifc_files/box_rotated.ifc new file mode 100644 index 00000000..73d8efd3 --- /dev/null +++ b/files/ifc_files/box_rotated.ifc @@ -0,0 +1,131 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1'); +FILE_NAME('library_components.ifc','2024-12-05T19:49:32+01:00',$,$,'IfcOpenShell 0.8.1-alpha241007','Bonsai 0.8.1-alpha241007-a422636','Nobody'); +FILE_SCHEMA(('IFC4X3_ADD2')); +ENDSEC; +DATA; +#1=IFCPROJECT('3XG5_GK21Dovk_5FSx$v8w',$,'AdaProject',$,$,$,$,(#10),#5); +#2=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); +#3=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.); +#4=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.); +#5=IFCUNITASSIGNMENT((#3,#4,#2)); +#6=IFCCARTESIANPOINT((0.,0.,0.)); +#7=IFCDIRECTION((0.,0.,1.)); +#8=IFCDIRECTION((1.,0.,0.)); +#9=IFCAXIS2PLACEMENT3D(#6,#7,#8); +#10=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#9,$); +#11=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#10,$,.MODEL_VIEW.,$); +#12=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#10,$,.GRAPH_VIEW.,$); +#13=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Box','Model',*,*,*,*,#10,$,.MODEL_VIEW.,$); +#14=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Plan',2,1.E-05,#9,$); +#15=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Plan',*,*,*,*,#14,$,.GRAPH_VIEW.,$); +#16=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Plan',*,*,*,*,#14,$,.PLAN_VIEW.,$); +#17=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Plan',*,*,*,*,#14,$,.SECTION_VIEW.,$); +#18=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Plan',*,*,*,*,#14,$,.ELEVATION_VIEW.,$); +#19=IFCACTORROLE(.ENGINEER.,$,$); +#20=IFCPERSON('AdaUser',$,$,$,$,$,(#19),$); +#21=IFCORGANIZATION('ADA','Assembly For Design and Analysis',$,$,$); +#22=IFCPERSONANDORGANIZATION(#20,#21,$); +#23=IFCAPPLICATION(#21,'XXX','ADA','ADA'); +#24=IFCOWNERHISTORY(#22,#23,.READWRITE.,$,1733390438,#22,#23,1733390438); +#25=IFCDIRECTION((0.,0.,1.)); +#26=IFCDIRECTION((1.,0.,0.)); +#27=IFCCARTESIANPOINT((0.,0.,0.)); +#28=IFCAXIS2PLACEMENT3D(#27,#25,#26); +#29=IFCLOCALPLACEMENT($,#28); +#30=IFCSITE('0mj2QmikeHxwjsg3jsrL$e',#24,'base_library_concept',$,$,#29,$,$,.ELEMENT.,$,$,$,$,$); +#31=IFCRELAGGREGATES('0mxCDkikeHxx6Ag3jsrL$e',#24,'Project Container',$,#1,(#30)); +#32=IFCPROPERTYSINGLEVALUE('project',$,IFCTEXT('AdaProject'),$); +#33=IFCPROPERTYSINGLEVALUE('schema',$,IFCTEXT('IFC4X3_add2'),$); +#34=IFCPROPERTYSET('3eQH$Ms9XATBTmxr0FozOo',#24,'Properties',$,(#32,#33)); +#35=IFCRELDEFINESBYPROPERTIES('0mxCDlikeHxwqdg3jsrL$e',#24,'Properties',$,(#30),#34); +#36=IFCDIRECTION((0.,0.,1.)); +#37=IFCDIRECTION((1.,0.,0.)); +#38=IFCCARTESIANPOINT((0.,0.,0.)); +#39=IFCAXIS2PLACEMENT3D(#38,#36,#37); +#40=IFCLOCALPLACEMENT(#29,#39); +#41=IFCSPACE('0mi$_8ikeHxwhig3jsrL$e',#24,'Topology',$,$,#40,$,$,.ELEMENT.,$,$); +#42=IFCRELAGGREGATES('0mxEgtikeHxwjUg3jsrL$e',#24,'Site Container',$,#30,(#41)); +#43=IFCDIRECTION((0.,0.,1.)); +#44=IFCDIRECTION((1.,0.,0.)); +#45=IFCCARTESIANPOINT((0.,0.,0.)); +#46=IFCAXIS2PLACEMENT3D(#45,#43,#44); +#47=IFCLOCALPLACEMENT(#40,#46); +#48=IFCBUILDINGSTOREY('0mfEFvikeHxxSLg3jsrL$e',#24,'DOORS',$,$,#47,$,$,.ELEMENT.,0.); +#49=IFCRELAGGREGATES('0mxEguikeHxvb7g3jsrL$e',#24,'Site Container',$,#41,(#48)); +#56=IFCMATERIAL('S355',$,'Steel'); +#57=IFCPROPERTYSINGLEVALUE('Grade',$,IFCTEXT('S355'),$); +#58=IFCPROPERTYSINGLEVALUE('YieldStress',$,IFCPRESSUREMEASURE(355000000.),$); +#59=IFCPROPERTYSINGLEVALUE('YoungModulus',$,IFCMODULUSOFELASTICITYMEASURE(210000000000.),$); +#60=IFCPROPERTYSINGLEVALUE('PoissonRatio',$,IFCPOSITIVERATIOMEASURE(0.3),$); +#61=IFCPROPERTYSINGLEVALUE('ThermalExpansionCoefficient',$,IFCTHERMALEXPANSIONCOEFFICIENTMEASURE(1.2E-05),$); +#62=IFCPROPERTYSINGLEVALUE('SpecificHeatCapacity',$,IFCSPECIFICHEATCAPACITYMEASURE(1.15),$); +#63=IFCPROPERTYSINGLEVALUE('MassDensity',$,IFCMASSDENSITYMEASURE(7850.),$); +#64=IFCMATERIALPROPERTIES('MaterialMechanical','A Material property description',(#57,#58,#59,#60,#61,#62,#63),#56); +#65=IFCRELASSOCIATESMATERIAL('0mi$_3ikeHxvIHg3jsrL$e',#318,'S355','Objects related to S355',(#103,#685),#56); +#78=IFCCOLOURRGB('Color1',0.8,0.8,0.8); +#79=IFCSURFACESTYLESHADING(#78,0.); +#80=IFCSURFACESTYLE('Color1',.BOTH.,(#79)); +#93=IFCCARTESIANPOINT((2.5,-0.3,0.)); +#94=IFCDIRECTION((0.,0.,1.)); +#95=IFCDIRECTION((1.,0.,0.)); +#96=IFCAXIS2PLACEMENT3D(#93,#94,#95); +#97=IFCBLOCK(#96,1.,1.4,2.2); +#98=IFCSHAPEREPRESENTATION(#11,'Body','SweptSolid',(#97)); +#99=IFCPRODUCTDEFINITIONSHAPE($,$,(#98)); +#100=IFCSURFACESTYLESHADING(#78,0.); +#101=IFCSURFACESTYLE('Color1',.BOTH.,(#100)); +#102=IFCSTYLEDITEM(#97,(#101),'Color1'); +#103=IFCBUILDINGELEMENTPROXY('0mi$_4ikeHxvhrg3jsrL$e',#406,'door1',$,$,#613,#99,$,$); +#104=IFCPROPERTYSINGLEVALUE('function',$,IFCTEXT('door'),$); +#105=IFCPROPERTYSINGLEVALUE('area',$,IFCTEXT('P100'),$); +#106=IFCPROPERTYSINGLEVALUE('flip_floor',$,IFCBOOLEAN(.F.),$); +#107=IFCPROPERTYSET('0JBkuUs05FGvS7adN_$ksa',#24,'Properties',$,(#104,#105,#106)); +#108=IFCRELDEFINESBYPROPERTIES('0mxH77ikeHxuNFg3jsrL$e',#24,'Properties',$,(#103),#107); +#121=IFCSURFACESTYLESHADING(#78,0.); +#122=IFCSURFACESTYLE('Color1',.BOTH.,(#121)); +#130=IFCRELCONTAINEDINSPATIALSTRUCTURE('0mxJZKikeHxw3ag3jsrL$e',#24,'Physical model',$,(#103,#685),#48); +#318=IFCOWNERHISTORY(#22,#23,.READWRITE.,.MODIFIED.,1733424432,#22,#684,1733390438); +#406=IFCOWNERHISTORY(#22,#23,.READWRITE.,.MODIFIED.,1733418748,#22,#598,1733390438); +#595=IFCACTORROLE(.USERDEFINED.,'CONTRIBUTOR',$); +#596=IFCTELECOMADDRESS(.USERDEFINED.,$,'WEBPAGE',$,$,$,$,'https://ifcopenshell.org',$); +#597=IFCORGANIZATION('IfcOpenShell','IfcOpenShell','IfcOpenShell is an open source software library that helps users and software developers to work with IFC data.',(#595),(#596)); +#598=IFCAPPLICATION(#597,'0.8.1-alpha241127-c9847ca','Bonsai','Bonsai'); +#609=IFCCARTESIANPOINT((-0.418019950389862,-0.290774822235107,0.)); +#610=IFCDIRECTION((0.,0.,1.)); +#611=IFCDIRECTION((1.,0.,0.)); +#612=IFCAXIS2PLACEMENT3D(#609,#610,#611); +#613=IFCLOCALPLACEMENT(#47,#612); +#681=IFCACTORROLE(.USERDEFINED.,'CONTRIBUTOR',$); +#682=IFCTELECOMADDRESS(.USERDEFINED.,$,'WEBPAGE',$,$,$,$,'https://ifcopenshell.org',$); +#683=IFCORGANIZATION('IfcOpenShell','IfcOpenShell','IfcOpenShell is an open source software library that helps users and software developers to work with IFC data.',(#681),(#682)); +#684=IFCAPPLICATION(#683,'0.8.1-alpha241007-a422636','Bonsai','Bonsai'); +#685=IFCBUILDINGELEMENTPROXY('0X7Yi2tuL9aeEL_R$sQt5K',#715,'door2',$,$,#720,#702,$,$); +#691=IFCRELDEFINESBYPROPERTIES('0K2wNptr9Cu98KrwVDzo4r',#24,'Properties',$,(#685),#692); +#692=IFCPROPERTYSET('3sZXPxagn9eQzYj42LVNP$',#693,'Properties',$,(#699,#700,#701)); +#693=IFCOWNERHISTORY(#694,#698,.READWRITE.,$,1733390438,#694,#698,1733390438); +#694=IFCPERSONANDORGANIZATION(#695,#697,$); +#695=IFCPERSON('AdaUser',$,$,$,$,$,(#696),$); +#696=IFCACTORROLE(.ENGINEER.,$,$); +#697=IFCORGANIZATION('ADA','Assembly For Design and Analysis',$,$,$); +#698=IFCAPPLICATION(#697,'XXX','ADA','ADA'); +#699=IFCPROPERTYSINGLEVALUE('function',$,IFCTEXT('door'),$); +#700=IFCPROPERTYSINGLEVALUE('area',$,IFCTEXT('P100'),$); +#701=IFCPROPERTYSINGLEVALUE('flip_floor',$,IFCBOOLEAN(.F.),$); +#702=IFCPRODUCTDEFINITIONSHAPE($,$,(#703)); +#703=IFCSHAPEREPRESENTATION(#11,'Body','SweptSolid',(#704)); +#704=IFCBLOCK(#705,1.,1.4,2.2); +#705=IFCAXIS2PLACEMENT3D(#706,#707,#708); +#706=IFCCARTESIANPOINT((2.5,-0.3,0.)); +#707=IFCDIRECTION((0.,0.,1.)); +#708=IFCDIRECTION((1.,0.,0.)); +#709=IFCSTYLEDITEM(#704,(#101),'Color1'); +#715=IFCOWNERHISTORY(#22,#23,.READWRITE.,.MODIFIED.,1733424572,#22,#684,1733390438); +#716=IFCCARTESIANPOINT((-0.418019950389862,-0.290774822235107,0.)); +#717=IFCDIRECTION((0.,0.,1.)); +#718=IFCDIRECTION((-4.37113882867379E-08,0.999999999999999,0.)); +#719=IFCAXIS2PLACEMENT3D(#716,#717,#718); +#720=IFCLOCALPLACEMENT(#47,#719); +ENDSEC; +END-ISO-10303-21; diff --git a/src/ada/api/primitives.py b/src/ada/api/primitives.py index 6633e8f5..63fcff57 100644 --- a/src/ada/api/primitives.py +++ b/src/ada/api/primitives.py @@ -210,10 +210,9 @@ def solid_occ(self): return geom_to_occ_geom(self.solid_geom()) def solid_geom(self) -> Geometry: - from ada.geom.points import Point from ada.geom.solids import Box - box = Box.from_2points(Point(*self.p1), Point(*self.p2)) + box = Box.from_2points(self.p1, self.p2) booleans = [BooleanOperation(x.primitive.solid_geom(), x.bool_op) for x in self.booleans] return Geometry(self.guid, box, self.color, bool_operations=booleans) diff --git a/src/ada/api/transforms.py b/src/ada/api/transforms.py index fb63f381..81eae3d5 100644 --- a/src/ada/api/transforms.py +++ b/src/ada/api/transforms.py @@ -125,6 +125,15 @@ def from_co_linear_points(points: list[Point] | np.ndarray, xdir=None) -> Placem def from_axis3d(axis: Axis2Placement3D) -> Placement: return Placement(origin=axis.location, xdir=axis.ref_direction, zdir=axis.axis) + @staticmethod + def from_4x4_matrix(matrix: np.ndarray) -> Placement: + return Placement( + origin=matrix[:3, 3], + xdir=matrix[:3, 0], + ydir=matrix[:3, 1], + zdir=matrix[:3, 2], + ) + def get_absolute_placement(self, include_rotations=False) -> Placement: if self.parent is None: return self diff --git a/src/ada/cadit/ifc/read/geom/geom_reader.py b/src/ada/cadit/ifc/read/geom/geom_reader.py index 80117a7c..0a3738c9 100644 --- a/src/ada/cadit/ifc/read/geom/geom_reader.py +++ b/src/ada/cadit/ifc/read/geom/geom_reader.py @@ -1,13 +1,9 @@ from typing import Union import ifcopenshell -import numpy as np -from ifcopenshell.util.placement import get_local_placement - from ada.geom import curves as geo_cu from ada.geom import solids as geo_so from ada.geom import surfaces as geo_su -from ada.geom.placement import Axis2Placement3D from .solids import extruded_solid_area, ifc_block, revolved_solid_area from .surfaces import advanced_face, triangulated_face_set @@ -23,18 +19,6 @@ def get_product_definitions(prod_def: ifcopenshell.entity_instance) -> list[GEOM for item in representation.Items: geometries.append(import_geometry_from_ifc_geom(item)) - obj_placement = prod_def.ObjectPlacement - if obj_placement.PlacementRelTo: - local_placement = get_local_placement(obj_placement) - offset = [] - for i in range(0, 3): - offset.append(local_placement[i][3]) - offset = np.array(offset) - if not np.equal(offset, np.zeros(3)).all(): - for geom in geometries: - for att in geom.__dict__.values(): - if isinstance(att, Axis2Placement3D): - att.location += offset return geometries diff --git a/src/ada/cadit/ifc/read/read_beams.py b/src/ada/cadit/ifc/read/read_beams.py index ba1b2619..b26d6aa8 100644 --- a/src/ada/cadit/ifc/read/read_beams.py +++ b/src/ada/cadit/ifc/read/read_beams.py @@ -9,6 +9,7 @@ from ada.api.curves import CurveRevolve from ada.config import logger from ada.core.vector_utils import calc_yvec, unit_vector +from ifcopenshell.util.placement import get_local_placement from .geom.geom_reader import get_product_definitions from .geom.placement import axis3d @@ -68,6 +69,13 @@ def import_straight_beam(ifc_elem, axis, name, sec, mat, ifc_store: IfcStore) -> local_y = calc_yvec(ref_dir, extrude_dir) p2 = p1 + extrude_dir * body.depth + extra_opts = {} + obj_placement = ifc_elem.ObjectPlacement + if obj_placement.PlacementRelTo: + local_placement = get_local_placement(obj_placement) + place = Placement.from_4x4_matrix(local_placement) + extra_opts["placement"] = place + return Beam( name, p1, @@ -78,6 +86,7 @@ def import_straight_beam(ifc_elem, axis, name, sec, mat, ifc_store: IfcStore) -> guid=ifc_elem.GlobalId, ifc_store=ifc_store, units=ifc_store.assembly.units, + **extra_opts, ) diff --git a/src/ada/cadit/ifc/read/read_shapes.py b/src/ada/cadit/ifc/read/read_shapes.py index 7d34f22b..6825f4a9 100644 --- a/src/ada/cadit/ifc/read/read_shapes.py +++ b/src/ada/cadit/ifc/read/read_shapes.py @@ -6,11 +6,13 @@ from OCC.Core.TopoDS import TopoDS_Compound, TopoDS_Shape from ada import Shape +from ada.api.transforms import Placement from ada.cadit.ifc.read.geom.geom_reader import get_product_definitions from ada.cadit.ifc.read.read_color import get_product_color from ada.config import Config, logger from ada.geom import Geometry from ada.visit.colors import Color +from ifcopenshell.util.placement import get_local_placement if TYPE_CHECKING: from ada.cadit.ifc.store import IfcStore @@ -35,6 +37,13 @@ def import_ifc_shape(product: ifcopenshell.entity_instance, name, ifc_store: Ifc else: geometries = None + extra_opts = {} + obj_placement = product.ObjectPlacement + if obj_placement.PlacementRelTo: + local_placement = get_local_placement(obj_placement) + place = Placement.from_4x4_matrix(local_placement) + extra_opts["placement"] = place + return Shape( name, geom=geometries, @@ -43,6 +52,7 @@ def import_ifc_shape(product: ifcopenshell.entity_instance, name, ifc_store: Ifc units=ifc_store.assembly.units, color=color, opacity=color.opacity if color is not None else 1.0, + **extra_opts ) diff --git a/tests/core/cadit/ifc/read/beams/test_ifc_read_beams.py b/tests/core/cadit/ifc/read/beams/test_ifc_read_beams.py index 3187b414..4b6c4f11 100644 --- a/tests/core/cadit/ifc/read/beams/test_ifc_read_beams.py +++ b/tests/core/cadit/ifc/read/beams/test_ifc_read_beams.py @@ -16,12 +16,14 @@ def test_read_standard_case_beams(example_files, tmp_path): assert tuple(bm_a1.n2.p) == (1.945, 0.11, 0.0) bm_a2: ada.Beam = p.get_by_name("A-2") - assert tuple(bm_a2.n1.p) == (0.0, 1.61, 0.0) - assert tuple(bm_a2.n2.p) == (2.0, 1.61, 0.0) + o = bm_a2.placement + assert tuple(o.origin + bm_a2.n1.p) == (0.0, 1.61, 0.0) + assert tuple(o.origin + bm_a2.n2.p) == (2.0, 1.61, 0.0) bm_b1: ada.Beam = p.get_by_name("B-1") - assert tuple(bm_b1.n1.p) == (-0.075, 0.075, 1.5) - assert tuple(bm_b1.n2.p) == pytest.approx((2.865, 0.318, 2.046), abs=1e-3) + o = bm_b1.placement + assert tuple(o.origin + bm_b1.n1.p) == (-0.075, 0.075, 1.5) + assert tuple(o.origin + bm_b1.n2.p) == pytest.approx((2.865, 0.318, 2.046), abs=1e-3) def test_read_extruded_solid_beams(example_files): diff --git a/tests/core/cadit/ifc/read/test_read_shape_with_transformation.py b/tests/core/cadit/ifc/read/test_read_shape_with_transformation.py index 4fdac4e1..2b63de4d 100644 --- a/tests/core/cadit/ifc/read/test_read_shape_with_transformation.py +++ b/tests/core/cadit/ifc/read/test_read_shape_with_transformation.py @@ -1,7 +1,15 @@ import ada +from ada.config import Config def test_read_shape_w_transformation(example_files): a = ada.from_ifc(example_files / "ifc_files/mapped_shapes/mapped-shape-with-transformation.ifc") _ = a.to_ifc(file_obj_only=True) print(a) + +def test_read_rotated_box(example_files): + Config().update_config_globally("ifc_import_shape_geom",True) + a = ada.from_ifc(example_files / "ifc_files/box_rotated.ifc") + door1 = a.get_by_name('door1') + door2 = a.get_by_name('door2') + print(a) From 001efa70760b277e38cdfbaa2a4b30ee15d45f69 Mon Sep 17 00:00:00 2001 From: krande Date: Mon, 9 Dec 2024 10:03:29 +0100 Subject: [PATCH 08/22] add helper method on primitive box --- src/ada/api/primitives.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ada/api/primitives.py b/src/ada/api/primitives.py index 63fcff57..f3606ab0 100644 --- a/src/ada/api/primitives.py +++ b/src/ada/api/primitives.py @@ -216,6 +216,15 @@ def solid_geom(self) -> Geometry: booleans = [BooleanOperation(x.primitive.solid_geom(), x.bool_op) for x in self.booleans] return Geometry(self.guid, box, self.color, bool_operations=booleans) + def get_bottom_points(self): + p11 = self.p1 + self.placement.origin + p2 = self.p2 + self.placement.origin + # get bottom 4 points + p12 = Point(p2.x, p11.y, p11.z) + p21 = Point(p11.x, p2.y, p11.z) + p22 = Point(p2.x, p2.y, p11.z) + return [p11, p12, p21, p22] + @staticmethod def from_p_and_dims(name, p, length, width, height, **kwargs): p1 = p @@ -226,6 +235,7 @@ def from_p_and_dims(name, p, length, width, height, **kwargs): def from_box_geom(name, box_geom: Box, **kwargs): p1 = box_geom.position.location p2 = p1 + Direction(box_geom.x_length, box_geom.y_length, box_geom.z_length) + return PrimBox(name, p1, p2, **kwargs) @staticmethod From 566636938d49e584ddfc0be125e2dc4a45d57910 Mon Sep 17 00:00:00 2001 From: krande Date: Mon, 9 Dec 2024 14:03:24 +0100 Subject: [PATCH 09/22] minor changes --- src/ada/api/spatial/assembly.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ada/api/spatial/assembly.py b/src/ada/api/spatial/assembly.py index 5217c65c..657e42d6 100644 --- a/src/ada/api/spatial/assembly.py +++ b/src/ada/api/spatial/assembly.py @@ -249,6 +249,7 @@ def to_genie_xml( from ada.cadit.gxml.write.write_xml import write_xml write_xml(self, destination_xml, writer_postprocessor=writer_postprocessor, embed_sat=embed_sat) + print(f'Genie XML file "{destination_xml}" created') def push(self, comment, bimserver_url, username, password, project, merge=False, sync=False): """Push current assembly to BimServer with a comment tag that defines the revision name""" From a004574c28cf0f5d9c29859743789a4fb3c5d4fb Mon Sep 17 00:00:00 2001 From: krande Date: Mon, 9 Dec 2024 14:26:01 +0100 Subject: [PATCH 10/22] updating acis export --- src/ada/cadit/sat/write/sat_entities.py | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/ada/cadit/sat/write/sat_entities.py b/src/ada/cadit/sat/write/sat_entities.py index 3e81ff02..db1c94f9 100644 --- a/src/ada/cadit/sat/write/sat_entities.py +++ b/src/ada/cadit/sat/write/sat_entities.py @@ -166,3 +166,30 @@ def to_string(self) -> str: centroid_str = " ".join([str(x) for x in make_ints_if_possible(self.centroid)]) normal_str = " ".join([str(x) for x in make_ints_if_possible(self.normal)]) return f"-{self.id} CachedPlaneAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${self.entity.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 {centroid_str} {normal_str} 1 #" + + +@dataclass +class PositionAttribName(SATEntity): + fused_face_attrib: FusedFaceAttribute + position_attrib: PositionAttribName + face: Face + + def to_string(self) -> str: + return f"-{self.id} position_attrib-name_attrib-gen-attrib $-1 -1 $-1 $-1 ${self.position_attrib.id} ${self.face.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 #" + +@dataclass +class FusedFaceAttribute(SATEntity): + name: StringAttribName + posattrib: PositionAttribName + stringattrib: StringAttribName + + def to_string(self) -> str: + return f"-{self.id} FusedFaceAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${self.entity.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 #" + +@dataclass +class FusedEdgeAttribute(SATEntity): + name: StringAttribName + stringattrib: StringAttribName + + def to_string(self) -> str: + return f"-{self.id} FusedEdgeAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${self.entity.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 #" \ No newline at end of file From 49094bcbca768aa00b82d155656a2677a9e2e4bd Mon Sep 17 00:00:00 2001 From: krande Date: Mon, 9 Dec 2024 16:10:25 +0100 Subject: [PATCH 11/22] use FusedFaceAttribute. --- src/ada/cadit/sat/write/sat_entities.py | 36 +++++++++++++++++++------ src/ada/cadit/sat/write/write_plate.py | 21 +++++++++++---- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/ada/cadit/sat/write/sat_entities.py b/src/ada/cadit/sat/write/sat_entities.py index db1c94f9..94a9e288 100644 --- a/src/ada/cadit/sat/write/sat_entities.py +++ b/src/ada/cadit/sat/write/sat_entities.py @@ -63,10 +63,15 @@ def to_string(self) -> str: class Loop(SATEntity): coedge: CoEdge bbox: list[float] + periphery_plane: PlaneSurface = None def to_string(self) -> str: bbox_str = " ".join(str(coord) for coord in self.bbox) - return f"-{self.id} loop $-1 -1 -1 $-1 $-1 ${self.coedge.id} $3 T {bbox_str} unknown #" + periphery = "unknown" + if self.periphery_plane is not None: + periphery = f"periphery ${self.periphery_plane.id} F" + + return f"-{self.id} loop $-1 -1 -1 $-1 $-1 ${self.coedge.id} $3 T {bbox_str} {periphery} #" @dataclass @@ -148,10 +153,10 @@ def to_string(self) -> str: class StringAttribName(SATEntity): name: str entity: SATEntity - cache_attrib: CachedPlaneAttribute = None + attrib_ref: CachedPlaneAttribute | FusedFaceAttribute = None def to_string(self) -> str: - cache_attrib = -1 if self.cache_attrib is None else self.cache_attrib.id + cache_attrib = -1 if self.attrib_ref is None else self.attrib_ref.id return f"-{self.id} string_attrib-name_attrib-gen-attrib $-1 -1 ${cache_attrib} $-1 ${self.entity.id} 2 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 @6 dnvscp @12 {self.name} #" @@ -165,26 +170,41 @@ class CachedPlaneAttribute(SATEntity): def to_string(self) -> str: centroid_str = " ".join([str(x) for x in make_ints_if_possible(self.centroid)]) normal_str = " ".join([str(x) for x in make_ints_if_possible(self.normal)]) - return f"-{self.id} CachedPlaneAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${self.entity.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 {centroid_str} {normal_str} 1 #" + if isinstance(self.entity, int): + entity = self.entity + else: + entity = self.entity.id + return f"-{self.id} CachedPlaneAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${entity} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 {centroid_str} {normal_str} 1 #" + + + @dataclass class PositionAttribName(SATEntity): - fused_face_attrib: FusedFaceAttribute position_attrib: PositionAttribName + fused_face_attrib: FusedFaceAttribute face: Face + face_bbox: list[float] + box_attrib: Literal["ExactBoxLow", "ExactBoxHigh"] + def to_string(self) -> str: - return f"-{self.id} position_attrib-name_attrib-gen-attrib $-1 -1 $-1 $-1 ${self.position_attrib.id} ${self.face.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 #" + if self.box_attrib == "ExactBoxLow": + box_attrib = "@11 ExactBoxLow "+' '.join([str(x) for x in self.face_bbox[:3]]) + else: + box_attrib = "@12 ExactBoxHigh "+ ' '.join([str(x) for x in self.face_bbox[3:]]) + + return f"-{self.id} position_attrib-name_attrib-gen-attrib $-1 -1 ${self.position_attrib.id} ${self.fused_face_attrib.id} ${self.face.id} 2 0 0 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 {box_attrib} #" @dataclass class FusedFaceAttribute(SATEntity): name: StringAttribName posattrib: PositionAttribName - stringattrib: StringAttribName + face: Face def to_string(self) -> str: - return f"-{self.id} FusedFaceAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${self.entity.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 #" + return f"-{self.id} FusedFaceAttribute-DNV-attrib $-1 -1 ${self.posattrib.id} ${self.name.id} ${self.face.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 F 1 0 0 #" @dataclass class FusedEdgeAttribute(SATEntity): diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index 43e6c7dc..90bb5214 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -49,13 +49,21 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: loop_id = id_gen.next_id() surface = se.PlaneSurface(id_gen.next_id(), pl.poly.get_centroid(), pl.poly.normal, pl.poly.xdir) + fused_face_id = id_gen.next_id() + + + posattr2_id = id_gen.next_id() + posattr1 = se.PositionAttribName(id_gen.next_id(), posattr2_id, fused_face_id, face_id, bbox, "ExactBoxHigh") + posattr2 = se.PositionAttribName(posattr2_id, posattr1, fused_face_id, face_id, bbox, "ExactBoxLow") + cached_plane_attrib = se.CachedPlaneAttribute(id_gen.next_id(), posattr2.id, name_id, pl.poly.get_centroid(), + pl.poly.normal) + + fused_face_att = se.FusedFaceAttribute(fused_face_id, name_id, posattr1, face_id) + string_attrib_name = se.StringAttribName(name_id, face_name, face_id, fused_face_att) + - cached_plane_attrib = se.CachedPlaneAttribute( - id_gen.next_id(), face_id, name_id, pl.poly.get_centroid(), pl.poly.normal - ) - string_attrib_name = se.StringAttribName(name_id, face_name, face_id, cached_plane_attrib) face = se.Face(face_id, loop_id, shell, string_attrib_name, surface) - loop = se.Loop(loop_id, id_gen.next_id(), bbox) + loop = se.Loop(loop_id, id_gen.next_id(), bbox, surface) edges = [] coedges = [] @@ -129,6 +137,9 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: string_attrib_name, cached_plane_attrib, surface, + fused_face_att, + posattr1, + posattr2, ] + coedges + edges From 2c0495c8a52cb478f9257bf40e1dec1d65a5ba52 Mon Sep 17 00:00:00 2001 From: krande Date: Mon, 9 Dec 2024 16:25:56 +0100 Subject: [PATCH 12/22] first test with fuse edge. --- src/ada/cadit/sat/write/sat_entities.py | 2 +- src/ada/cadit/sat/write/write_plate.py | 6 ++++++ src/ada/cadit/sat/write/writer.py | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ada/cadit/sat/write/sat_entities.py b/src/ada/cadit/sat/write/sat_entities.py index 94a9e288..d9c22b57 100644 --- a/src/ada/cadit/sat/write/sat_entities.py +++ b/src/ada/cadit/sat/write/sat_entities.py @@ -209,7 +209,7 @@ def to_string(self) -> str: @dataclass class FusedEdgeAttribute(SATEntity): name: StringAttribName - stringattrib: StringAttribName + entity: SATEntity def to_string(self) -> str: return f"-{self.id} FusedEdgeAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${self.entity.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 #" \ No newline at end of file diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index 90bb5214..5fd61511 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -123,6 +123,12 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: p1.point, p2.point, ) + edge_n = f"EDGE{sw.edge_name_id:08d}" + edge_string_att = se.StringAttribName(id_gen.next_id(), edge_n, edge) + fusedge = se.FusedEdgeAttribute(id_gen.next_id(), edge_string_att, edge) + sat_entities.append(edge_string_att) + sat_entities.append(fusedge) + sw.edge_name_id += 1 coedge = se.CoEdge(coedge_id, next_coedge_id, prev_coedge_id, edge, loop, "forward") coedges.append(coedge) diff --git a/src/ada/cadit/sat/write/writer.py b/src/ada/cadit/sat/write/writer.py index 4acc526d..adea33b8 100644 --- a/src/ada/cadit/sat/write/writer.py +++ b/src/ada/cadit/sat/write/writer.py @@ -72,6 +72,8 @@ class SatWriter: id_generator: IDGenerator = field(default_factory=IDGenerator) face_map: dict[str, str] = field(default_factory=dict) # face_name -> plate guid + edge_name_id: int = 0 + def __post_init__(self): bboxes = [] for part in self.part.get_all_parts_in_assembly(include_self=True): From 0bc7f40aadd6c581674b0b341779e68d1e03effa Mon Sep 17 00:00:00 2001 From: krande Date: Mon, 9 Dec 2024 17:32:53 +0100 Subject: [PATCH 13/22] further work --- src/ada/cadit/sat/write/sat_entities.py | 15 ++++++++++++--- src/ada/cadit/sat/write/write_plate.py | 13 ++++++++----- src/ada/cadit/sat/write/writer.py | 4 ++-- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/ada/cadit/sat/write/sat_entities.py b/src/ada/cadit/sat/write/sat_entities.py index d9c22b57..1d9275b1 100644 --- a/src/ada/cadit/sat/write/sat_entities.py +++ b/src/ada/cadit/sat/write/sat_entities.py @@ -113,8 +113,12 @@ class Edge(SATEntity): start_pt: ada.Point end_pt: ada.Point + attrib_name: StringAttribName = None def to_string(self) -> str: + attrib_ref = "-1" + if self.attrib_name: + attrib_ref = self.attrib_name.id start_str = " ".join([str(x) for x in make_ints_if_possible(self.start_pt)]) end_str = " ".join([str(x) for x in make_ints_if_possible(self.end_pt)]) # pos_str = f"{self.start_pt[0]} {self.start_pt[1]} {self.start_pt[2]} {self.end_pt[0]} {self.end_pt[1]} {self.end_pt[2]}" @@ -122,7 +126,7 @@ def to_string(self) -> str: length = vec.get_length() s1 = 0 s2 = make_ints_if_possible([length])[0] - return f"-{self.id} edge $-1 -1 -1 $-1 ${self.vertex_start.id} {s1} ${self.vertex_end.id} {s2} ${self.coedge.id} ${self.straight_curve.id} forward @7 unknown T {start_str} {end_str} #" + return f"-{self.id} edge ${attrib_ref} -1 -1 $-1 ${self.vertex_start.id} {s1} ${self.vertex_end.id} {s2} ${self.coedge.id} ${self.straight_curve.id} forward @7 unknown T {start_str} {end_str} #" @dataclass @@ -153,7 +157,7 @@ def to_string(self) -> str: class StringAttribName(SATEntity): name: str entity: SATEntity - attrib_ref: CachedPlaneAttribute | FusedFaceAttribute = None + attrib_ref: CachedPlaneAttribute | FusedFaceAttribute | FusedEdgeAttribute = None def to_string(self) -> str: cache_attrib = -1 if self.attrib_ref is None else self.attrib_ref.id @@ -210,6 +214,11 @@ def to_string(self) -> str: class FusedEdgeAttribute(SATEntity): name: StringAttribName entity: SATEntity + edge_idx: int + edge_seq: tuple[int, int] + edge_length: int | float def to_string(self) -> str: - return f"-{self.id} FusedEdgeAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${self.entity.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 #" \ No newline at end of file + length = make_ints_if_possible([self.edge_length])[0] + edge_spec = f"{self.edge_seq[0]} {self.edge_seq[1]} 0 {length}" + return f"-{self.id} FusedEdgeAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${self.entity.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 {edge_spec} #" \ No newline at end of file diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index 5fd61511..a0fc266b 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -89,7 +89,7 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: points = list(point_map.values()) vertex_map = {p.id: se.Vertex(id_gen.next_id(), None, p) for p in points} vertices = list(vertex_map.values()) - + edge_seq = [(1,2), (2,3), (3,4), (4,1)] for i, edge in enumerate(seg3d): coedge_id = coedge_ids[i] if i == 0: @@ -120,12 +120,15 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: v2, coedge_id, straight_curve, - p1.point, - p2.point, + start_pt=p1.point, + end_pt=p2.point, ) edge_n = f"EDGE{sw.edge_name_id:08d}" - edge_string_att = se.StringAttribName(id_gen.next_id(), edge_n, edge) - fusedge = se.FusedEdgeAttribute(id_gen.next_id(), edge_string_att, edge) + edge_str_id = id_gen.next_id() + length = ada.Direction(p1.point - p2.point).get_length() + fusedge = se.FusedEdgeAttribute(id_gen.next_id(), edge_str_id, edge, i+1, edge_seq[i], length) + edge_string_att = se.StringAttribName(edge_str_id, edge_n, edge, attrib_ref=fusedge) + edge.attrib_name = edge_string_att sat_entities.append(edge_string_att) sat_entities.append(fusedge) sw.edge_name_id += 1 diff --git a/src/ada/cadit/sat/write/writer.py b/src/ada/cadit/sat/write/writer.py index adea33b8..1adb3ec6 100644 --- a/src/ada/cadit/sat/write/writer.py +++ b/src/ada/cadit/sat/write/writer.py @@ -15,7 +15,7 @@ from ada import Assembly, Part HEADER_STR = """2000 0 1 0 -18 SESAM - gmGeometry 14 ACIS 30.0.1 NT 24 Tue Jan 17 20:39:08 2023 +18 SESAM - gmGeometry 14 ACIS 33.0.1 NT 24 Tue Jan 17 20:39:08 2023 1000 9.9999999999999995e-07 1e-10 """ @@ -72,7 +72,7 @@ class SatWriter: id_generator: IDGenerator = field(default_factory=IDGenerator) face_map: dict[str, str] = field(default_factory=dict) # face_name -> plate guid - edge_name_id: int = 0 + edge_name_id: int = 1 def __post_init__(self): bboxes = [] From 732ea93bc90d569b8fcaa61b2bbdbcfbfdced4e1 Mon Sep 17 00:00:00 2001 From: ofskrand Date: Mon, 9 Dec 2024 19:15:09 +0100 Subject: [PATCH 14/22] further work --- src/ada/cadit/sat/write/write_plate.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index a0fc266b..80356625 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -54,9 +54,12 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: posattr2_id = id_gen.next_id() posattr1 = se.PositionAttribName(id_gen.next_id(), posattr2_id, fused_face_id, face_id, bbox, "ExactBoxHigh") - posattr2 = se.PositionAttribName(posattr2_id, posattr1, fused_face_id, face_id, bbox, "ExactBoxLow") - cached_plane_attrib = se.CachedPlaneAttribute(id_gen.next_id(), posattr2.id, name_id, pl.poly.get_centroid(), - pl.poly.normal) + cache_plane_id = id_gen.next_id() + posattr2 = se.PositionAttribName(posattr2_id, cache_plane_id, posattr1, face_id, bbox, "ExactBoxLow") + + cached_plane_attrib = se.CachedPlaneAttribute( + cache_plane_id, face_id, posattr2.id, pl.poly.get_centroid(), pl.poly.normal + ) fused_face_att = se.FusedFaceAttribute(fused_face_id, name_id, posattr1, face_id) string_attrib_name = se.StringAttribName(name_id, face_name, face_id, fused_face_att) From ef53ea6905e5e7cdc8531a216c250e47f1224668 Mon Sep 17 00:00:00 2001 From: krande Date: Tue, 10 Dec 2024 13:49:23 +0100 Subject: [PATCH 15/22] fix most of the acis issues --- src/ada/cadit/sat/write/sat_entities.py | 2 +- src/ada/cadit/sat/write/write_plate.py | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/ada/cadit/sat/write/sat_entities.py b/src/ada/cadit/sat/write/sat_entities.py index 1d9275b1..dc67b926 100644 --- a/src/ada/cadit/sat/write/sat_entities.py +++ b/src/ada/cadit/sat/write/sat_entities.py @@ -220,5 +220,5 @@ class FusedEdgeAttribute(SATEntity): def to_string(self) -> str: length = make_ints_if_possible([self.edge_length])[0] - edge_spec = f"{self.edge_seq[0]} {self.edge_seq[1]} 0 {length}" + edge_spec = f"{self.edge_seq[0]} {self.edge_seq[1]} {self.edge_idx} 0 {length}" return f"-{self.id} FusedEdgeAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${self.entity.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 {edge_spec} #" \ No newline at end of file diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index 80356625..08a531e4 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -51,9 +51,8 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: surface = se.PlaneSurface(id_gen.next_id(), pl.poly.get_centroid(), pl.poly.normal, pl.poly.xdir) fused_face_id = id_gen.next_id() - posattr2_id = id_gen.next_id() - posattr1 = se.PositionAttribName(id_gen.next_id(), posattr2_id, fused_face_id, face_id, bbox, "ExactBoxHigh") + posattr1 = se.PositionAttribName(id_gen.next_id(), posattr2_id, fused_face_id, face_id, bbox, "ExactBoxHigh") cache_plane_id = id_gen.next_id() posattr2 = se.PositionAttribName(posattr2_id, cache_plane_id, posattr1, face_id, bbox, "ExactBoxLow") @@ -64,7 +63,6 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: fused_face_att = se.FusedFaceAttribute(fused_face_id, name_id, posattr1, face_id) string_attrib_name = se.StringAttribName(name_id, face_name, face_id, fused_face_att) - face = se.Face(face_id, loop_id, shell, string_attrib_name, surface) loop = se.Loop(loop_id, id_gen.next_id(), bbox, surface) @@ -73,6 +71,14 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: straight_curves = [] seg3d = pl.poly.segments3d + # By making seg3d counter clockwise area of the face will be positive (in genie checks) + seg3d_ccw = [] + for i, edge in enumerate(seg3d): + new_edge = ada.LineSegment(edge.p2, edge.p1) + seg3d_ccw.append(new_edge) + seg3d_ccw.reverse() + seg3d = seg3d_ccw + coedge_ids = [] for i, edge in enumerate(seg3d): if i == 0: @@ -92,7 +98,7 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: points = list(point_map.values()) vertex_map = {p.id: se.Vertex(id_gen.next_id(), None, p) for p in points} vertices = list(vertex_map.values()) - edge_seq = [(1,2), (2,3), (3,4), (4,1)] + edge_seq = [(1, 2), (2, 3), (3, 4), (4, 1)] for i, edge in enumerate(seg3d): coedge_id = coedge_ids[i] if i == 0: @@ -104,6 +110,7 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: else: next_coedge_id = coedge_ids[(i + 1)] prev_coedge_id = coedge_ids[(i - 1)] + # start edge_id = id_gen.next_id() p1 = point_map.get(tuple(edge.p1)) @@ -129,7 +136,9 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: edge_n = f"EDGE{sw.edge_name_id:08d}" edge_str_id = id_gen.next_id() length = ada.Direction(p1.point - p2.point).get_length() - fusedge = se.FusedEdgeAttribute(id_gen.next_id(), edge_str_id, edge, i+1, edge_seq[i], length) + fusedge = se.FusedEdgeAttribute( + id_gen.next_id(), name=edge_str_id, entity=edge, edge_idx=i + 1, edge_seq=edge_seq[i], edge_length=length + ) edge_string_att = se.StringAttribName(edge_str_id, edge_n, edge, attrib_ref=fusedge) edge.attrib_name = edge_string_att sat_entities.append(edge_string_att) @@ -163,7 +172,7 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: sat_entity_map = {entity.id: entity for entity in sat_entities} for entity in sat_entities: for key, value in entity.__dict__.items(): - if key == "id": + if key == "id" or "_idx" in key: continue if isinstance(value, int) and value in sat_entity_map.keys(): setattr(entity, key, sat_entity_map.get(value)) From add85e56870c9399c1c9d2de884b273bab9bddee Mon Sep 17 00:00:00 2001 From: krande Date: Tue, 10 Dec 2024 15:59:01 +0100 Subject: [PATCH 16/22] make acis updates optional --- src/ada/cadit/sat/write/write_plate.py | 55 ++++++++++++++------------ 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index 08a531e4..c472f972 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -13,7 +13,7 @@ from ada.cadit.sat.write.writer import SatWriter -def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: SatWriter) -> list[se.SATEntity]: +def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: SatWriter, use_dual_assembly=False) -> list[se.SATEntity]: """Convert a Plate object to a SAT entities.""" if geo_repr != GeomRepr.SHELL: @@ -49,19 +49,25 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: loop_id = id_gen.next_id() surface = se.PlaneSurface(id_gen.next_id(), pl.poly.get_centroid(), pl.poly.normal, pl.poly.xdir) - fused_face_id = id_gen.next_id() - - posattr2_id = id_gen.next_id() - posattr1 = se.PositionAttribName(id_gen.next_id(), posattr2_id, fused_face_id, face_id, bbox, "ExactBoxHigh") cache_plane_id = id_gen.next_id() - posattr2 = se.PositionAttribName(posattr2_id, cache_plane_id, posattr1, face_id, bbox, "ExactBoxLow") + if use_dual_assembly: + fused_face_id = id_gen.next_id() - cached_plane_attrib = se.CachedPlaneAttribute( - cache_plane_id, face_id, posattr2.id, pl.poly.get_centroid(), pl.poly.normal - ) + posattr2_id = id_gen.next_id() + posattr1 = se.PositionAttribName(id_gen.next_id(), posattr2_id, fused_face_id, face_id, bbox, "ExactBoxHigh") - fused_face_att = se.FusedFaceAttribute(fused_face_id, name_id, posattr1, face_id) - string_attrib_name = se.StringAttribName(name_id, face_name, face_id, fused_face_att) + posattr2 = se.PositionAttribName(posattr2_id, cache_plane_id, posattr1, face_id, bbox, "ExactBoxLow") + cached_plane_attrib = se.CachedPlaneAttribute( + cache_plane_id, face_id, posattr2.id, pl.poly.get_centroid(), pl.poly.normal + ) + fused_face_att = se.FusedFaceAttribute(fused_face_id, name_id, posattr1, face_id) + string_attrib_name = se.StringAttribName(name_id, face_name, face_id, fused_face_att) + sat_entities += [posattr1, posattr2, fused_face_att] + else: + cached_plane_attrib = se.CachedPlaneAttribute( + id_gen.next_id(), face_id, name_id, pl.poly.get_centroid(), pl.poly.normal + ) + string_attrib_name = se.StringAttribName(name_id, face_name, face_id, cached_plane_attrib) face = se.Face(face_id, loop_id, shell, string_attrib_name, surface) loop = se.Loop(loop_id, id_gen.next_id(), bbox, surface) @@ -133,17 +139,18 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: start_pt=p1.point, end_pt=p2.point, ) - edge_n = f"EDGE{sw.edge_name_id:08d}" - edge_str_id = id_gen.next_id() - length = ada.Direction(p1.point - p2.point).get_length() - fusedge = se.FusedEdgeAttribute( - id_gen.next_id(), name=edge_str_id, entity=edge, edge_idx=i + 1, edge_seq=edge_seq[i], edge_length=length - ) - edge_string_att = se.StringAttribName(edge_str_id, edge_n, edge, attrib_ref=fusedge) - edge.attrib_name = edge_string_att - sat_entities.append(edge_string_att) - sat_entities.append(fusedge) - sw.edge_name_id += 1 + if use_dual_assembly: + edge_n = f"EDGE{sw.edge_name_id:08d}" + edge_str_id = id_gen.next_id() + length = ada.Direction(p1.point - p2.point).get_length() + fusedge = se.FusedEdgeAttribute( + id_gen.next_id(), name=edge_str_id, entity=edge, edge_idx=i + 1, edge_seq=edge_seq[i], edge_length=length + ) + edge_string_att = se.StringAttribName(edge_str_id, edge_n, edge, attrib_ref=fusedge) + edge.attrib_name = edge_string_att + sat_entities.append(edge_string_att) + sat_entities.append(fusedge) + sw.edge_name_id += 1 coedge = se.CoEdge(coedge_id, next_coedge_id, prev_coedge_id, edge, loop, "forward") coedges.append(coedge) @@ -158,9 +165,7 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: string_attrib_name, cached_plane_attrib, surface, - fused_face_att, - posattr1, - posattr2, + ] + coedges + edges From 99f55ee8d4a5d4ff1e4c2427b7db8c40019bc541 Mon Sep 17 00:00:00 2001 From: ofskrand Date: Tue, 10 Dec 2024 19:06:54 +0100 Subject: [PATCH 17/22] update body bbox in acis writer --- src/ada/cadit/sat/write/write_plate.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index c472f972..dfed6098 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -38,6 +38,19 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: else: body = bodies[0] lump_id = id_gen.next_id() + # update body bbox + updated_body_bbox = [x for x in body.bbox] + for i, x in enumerate(bbox): + body_value = body.bbox[i] + local_value = bbox[i] + if i > 2: + if local_value > body_value: + updated_body_bbox[i] = local_value + else: + if local_value < body_value: + updated_body_bbox[i] = local_value + + body.bbox = updated_body_bbox shell_id = id_gen.next_id() face_id = id_gen.next_id() From 75b44c542c1e2f2e60b9e626bfa77012817050f4 Mon Sep 17 00:00:00 2001 From: krande Date: Wed, 11 Dec 2024 13:28:43 +0100 Subject: [PATCH 18/22] minor update --- src/ada/cadit/sat/write/write_plate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index dfed6098..61724c99 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -83,7 +83,10 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: string_attrib_name = se.StringAttribName(name_id, face_name, face_id, cached_plane_attrib) face = se.Face(face_id, loop_id, shell, string_attrib_name, surface) - loop = se.Loop(loop_id, id_gen.next_id(), bbox, surface) + if use_dual_assembly: + loop = se.Loop(loop_id, id_gen.next_id(), bbox, surface) + else: + loop = se.Loop(loop_id, id_gen.next_id(), bbox) edges = [] coedges = [] From 3126d08fb7530109f3fadc24035e741c0a4c590e Mon Sep 17 00:00:00 2001 From: krande Date: Wed, 11 Dec 2024 16:13:42 +0100 Subject: [PATCH 19/22] ACIS export - make sure to reference lump from shell --- src/ada/cadit/sat/write/sat_entities.py | 3 ++- src/ada/cadit/sat/write/write_plate.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ada/cadit/sat/write/sat_entities.py b/src/ada/cadit/sat/write/sat_entities.py index dc67b926..0998fca3 100644 --- a/src/ada/cadit/sat/write/sat_entities.py +++ b/src/ada/cadit/sat/write/sat_entities.py @@ -41,11 +41,12 @@ def to_string(self) -> str: @dataclass class Shell(SATEntity): face: Face + lump: Lump bbox: list[float] def to_string(self) -> str: bbox_str = " ".join(str(coord) for coord in self.bbox) - return f"-{self.id} shell $-1 -1 -1 $-1 $-1 $-1 ${self.face.id} $-1 $1 T {bbox_str} #" + return f"-{self.id} shell $-1 -1 -1 $-1 $-1 $-1 ${self.face.id} $-1 ${self.lump.id} T {bbox_str} #" @dataclass diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index 61724c99..ae5e3d9d 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -56,7 +56,7 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: face_id = id_gen.next_id() lump = se.Lump(lump_id, shell_id, body, bbox) sat_entities.append(lump) - shell = se.Shell(shell_id, face_id, bbox) + shell = se.Shell(shell_id, face_id, lump, bbox) name_id = id_gen.next_id() loop_id = id_gen.next_id() From 01ab5ada3eba1fcae66455c59af0e7eb954210a3 Mon Sep 17 00:00:00 2001 From: krande Date: Thu, 12 Dec 2024 12:29:21 +0100 Subject: [PATCH 20/22] minor updates --- pixi.lock | 218 +----------------- src/ada/api/curves.py | 4 +- src/ada/api/plates/base_pl.py | 6 +- src/ada/api/primitives.py | 5 +- src/ada/api/transforms.py | 6 +- src/ada/cadit/ifc/read/geom/geom_reader.py | 1 + src/ada/cadit/ifc/read/read_beams.py | 2 +- src/ada/cadit/ifc/read/read_shapes.py | 4 +- src/ada/cadit/sat/write/sat_entities.py | 12 +- src/ada/cadit/sat/write/write_plate.py | 12 +- src/ada/core/vector_utils.py | 13 +- .../test_read_shape_with_transformation.py | 15 +- .../ifc/roundtripping/test_roundtrip_box.py | 4 +- .../cadit/sat/test_write_write_basic_sat.py | 2 + 14 files changed, 56 insertions(+), 248 deletions(-) diff --git a/pixi.lock b/pixi.lock index 37711ae2..e8ebc4b8 100644 --- a/pixi.lock +++ b/pixi.lock @@ -2044,9 +2044,9 @@ packages: timestamp: 1650670423406 - kind: pypi name: ada-py - version: 0.3.4 + version: 0.3.5 path: . - sha256: 156dc94f8d5bf0f9971be736c8d1b9a9a5650ec3052dc3ebdebb431ca8c67cf1 + sha256: 948f06d46933623f82e71898fcc92598419d7d4b9fa2be04dbf711b54867ef27 requires_python: '>=3.10' editable: true - kind: conda @@ -2963,23 +2963,6 @@ packages: license_family: GPL size: 78781301 timestamp: 1722515407201 -- kind: conda - name: colorama - version: 0.4.6 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 - sha256: 2c1b2e9755ce3102bca8d69e8f26e4f087ece73f50418186aee7c74bef8e1698 - md5: 3faab06a954c2a04039983f2c4a50d99 - depends: - - python >=3.7 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/colorama?source=hash-mapping - size: 25170 - timestamp: 1666700778190 - kind: conda name: colorama version: 0.4.6 @@ -4030,23 +4013,6 @@ packages: - pkg:pypi/hyperframe?source=hash-mapping size: 14646 timestamp: 1619110249723 -- kind: conda - name: icu - version: '75.1' - build: he02047a_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda - sha256: 71e750d509f5fa3421087ba88ef9a7b9be11c53174af3aa4d06aff4c18b38e8e - md5: 8b189310083baabfb622af68fd9d3ae3 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: MIT - license_family: MIT - purls: [] - size: 12129203 - timestamp: 1720853576813 - kind: conda name: icu version: '75.1' @@ -6119,21 +6085,6 @@ packages: purls: [] size: 647599 timestamp: 1729571887612 -- kind: conda - name: libnsl - version: 2.0.1 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda - sha256: 26d77a3bb4dceeedc2a41bd688564fe71bf2d149fdcf117049970bc02ff1add6 - md5: 30fd6e37fe21f86f4bd26d6ee73eeec7 - depends: - - libgcc-ng >=12 - license: LGPL-2.1-only - license_family: GPL - purls: [] - size: 33408 - timestamp: 1697359010159 - kind: conda name: libnsl version: 2.0.1 @@ -6397,40 +6348,8 @@ packages: - libgcc 14.2.0 h77fa898_1 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 3893695 timestamp: 1729027746910 -- kind: conda - name: libstdcxx - version: 14.2.0 - build: hc0a3c3a_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-hc0a3c3a_1.conda - sha256: 4661af0eb9bdcbb5fb33e5d0023b001ad4be828fccdcc56500059d56f9869462 - md5: 234a5554c53625688d51062645337328 - depends: - - libgcc 14.2.0 h77fa898_1 - license: GPL-3.0-only WITH GCC-exception-3.1 - license_family: GPL - size: 3893695 - timestamp: 1729027746910 -- kind: conda - name: libstdcxx-ng - version: 14.2.0 - build: h4852527_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_1.conda - sha256: 25bb30b827d4f6d6f0522cc0579e431695503822f144043b93c50237017fffd8 - md5: 8371ac6457591af2cf6159439c1fd051 - depends: - - libstdcxx 14.2.0 hc0a3c3a_1 - license: GPL-3.0-only WITH GCC-exception-3.1 - license_family: GPL - purls: [] - size: 54105 - timestamp: 1729027780628 - kind: conda name: libstdcxx-ng version: 14.2.0 @@ -6598,21 +6517,6 @@ packages: purls: [] size: 395888 timestamp: 1727278577118 -- kind: conda - name: libxcrypt - version: 4.4.36 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c - md5: 5aa797f8787fe7a17d1b0821485b5adc - depends: - - libgcc-ng >=12 - license: LGPL-2.1-or-later - purls: [] - size: 100393 - timestamp: 1702724383534 - kind: conda name: libxcrypt version: 4.4.36 @@ -7983,23 +7887,6 @@ packages: - pkg:pypi/overrides?source=hash-mapping size: 30232 timestamp: 1706394723472 -- kind: conda - name: packaging - version: '24.1' - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda - sha256: 36aca948219e2c9fdd6d80728bcc657519e02f06c2703d8db3446aec67f51d81 - md5: cbe1bb1f21567018ce595d9c2be0f0db - depends: - - python >=3.8 - license: Apache-2.0 - license_family: APACHE - purls: - - pkg:pypi/packaging?source=hash-mapping - size: 50290 - timestamp: 1718189540074 - kind: conda name: packaging version: '24.1' @@ -8397,23 +8284,6 @@ packages: - pkg:pypi/pkgutil-resolve-name?source=hash-mapping size: 10778 timestamp: 1694617398467 -- kind: conda - name: platformdirs - version: 4.3.6 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.6-pyhd8ed1ab_0.conda - sha256: c81bdeadc4adcda216b2c7b373f0335f5c78cc480d1d55d10f21823590d7e46f - md5: fd8f2b18b65bbf62e8f653100690c8d2 - depends: - - python >=3.8 - license: MIT - license_family: MIT - purls: - - pkg:pypi/platformdirs?source=hash-mapping - size: 20625 - timestamp: 1726613611845 - kind: conda name: platformdirs version: 4.3.6 @@ -9225,23 +9095,6 @@ packages: - pkg:pypi/fastjsonschema?source=hash-mapping size: 226165 timestamp: 1718477110630 -- kind: conda - name: python-flatbuffers - version: 24.3.25 - build: pyh59ac667_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/python-flatbuffers-24.3.25-pyh59ac667_0.conda - sha256: 6a9d285fef959480eccbc69e276ede64e292c8eee35ddc727d5a0fb9a4bcc3a2 - md5: dfc884dcd61ff6543fde37a41b7d7f31 - depends: - - python >=3.6 - license: Apache-2.0 - license_family: Apache - purls: - - pkg:pypi/flatbuffers?source=hash-mapping - size: 34336 - timestamp: 1711466847930 - kind: conda name: python-flatbuffers version: 24.3.25 @@ -9335,22 +9188,6 @@ packages: - pkg:pypi/tzdata?source=hash-mapping size: 142527 timestamp: 1727140688093 -- kind: conda - name: python_abi - version: '3.12' - build: 5_cp312 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-5_cp312.conda - sha256: d10e93d759931ffb6372b45d65ff34d95c6000c61a07e298d162a3bc2accebb0 - md5: 0424ae29b104430108f5218a66db7260 - constrains: - - python 3.12.* *_cpython - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 6238 - timestamp: 1723823388266 - kind: conda name: python_abi version: '3.12' @@ -9366,22 +9203,6 @@ packages: license_family: BSD size: 6238 timestamp: 1723823388266 -- kind: conda - name: python_abi - version: '3.12' - build: 5_cp312 - build_number: 5 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/python_abi-3.12-5_cp312.conda - sha256: 9486662af81a219e96d343449eff242f38d7c5128ced5ce5acf85857265058d6 - md5: e8681f534453af7afab4cd2bc1423eec - constrains: - - python 3.12.* *_cpython - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 6730 - timestamp: 1723823139725 - kind: conda name: python_abi version: '3.12' @@ -10020,23 +9841,6 @@ packages: - pkg:pypi/send2trash?source=hash-mapping size: 23319 timestamp: 1712585816346 -- kind: conda - name: setuptools - version: 75.1.0 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/setuptools-75.1.0-pyhd8ed1ab_0.conda - sha256: 6725235722095c547edd24275053c615158d6163f396550840aebd6e209e4738 - md5: d5cd48392c67fb6849ba459c2c2b671f - depends: - - python >=3.8 - license: MIT - license_family: MIT - purls: - - pkg:pypi/setuptools?source=hash-mapping - size: 777462 - timestamp: 1727249510532 - kind: conda name: setuptools version: 75.1.0 @@ -11895,24 +11699,6 @@ packages: purls: [] size: 107439 timestamp: 1727963788936 -- kind: conda - name: zlib - version: 1.3.1 - build: hb9d3cd8_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - sha256: 5d7c0e5f0005f74112a34a7425179f4eb6e73c92f5d109e6af4ddeca407c92ab - md5: c9f075ab2f33b3bbee9e62d4ad0a6cd8 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - - libzlib 1.3.1 hb9d3cd8_2 - license: Zlib - license_family: Other - purls: [] - size: 92286 - timestamp: 1727963153079 - kind: conda name: zlib version: 1.3.1 diff --git a/src/ada/api/curves.py b/src/ada/api/curves.py index ab59ebb7..6bf5cd75 100644 --- a/src/ada/api/curves.py +++ b/src/ada/api/curves.py @@ -132,9 +132,9 @@ def _points_fix(self, points): return points @classmethod - def from_3d_points(cls, points, tol=1e-3, xdir=None, parent=None): + def from_3d_points(cls, points, tol=1e-3, xdir=None, parent=None, flip_n=False): points3d = np.array([p[:3] for p in points]) - place = Placement.from_co_linear_points(points3d, xdir=xdir) + place = Placement.from_co_linear_points(points3d, xdir=xdir, flip_n=flip_n) points2d = place.transform_global_points_to_local(points3d) radiis = {i: x for i, x in enumerate(points) if len(x) > 3} input_points = [] diff --git a/src/ada/api/plates/base_pl.py b/src/ada/api/plates/base_pl.py index cc393d80..af86512c 100644 --- a/src/ada/api/plates/base_pl.py +++ b/src/ada/api/plates/base_pl.py @@ -78,8 +78,10 @@ def __init__( self._bbox = None @staticmethod - def from_3d_points(name, points, t, mat="S420", xdir=None, color=None, metadata=None, **kwargs) -> Plate: - poly = CurvePoly2d.from_3d_points(points, xdir=xdir, **kwargs) + def from_3d_points( + name, points, t, mat="S420", xdir=None, color=None, metadata=None, flip_n=False, **kwargs + ) -> Plate: + poly = CurvePoly2d.from_3d_points(points, xdir=xdir, flip_n=flip_n, **kwargs) return Plate(name, poly, t, mat=mat, color=color, metadata=metadata, **kwargs) @staticmethod diff --git a/src/ada/api/primitives.py b/src/ada/api/primitives.py index f3606ab0..97bac9a5 100644 --- a/src/ada/api/primitives.py +++ b/src/ada/api/primitives.py @@ -22,10 +22,9 @@ if TYPE_CHECKING: from OCC.Core.TopoDS import TopoDS_Shape - from ada.geom.solids import Box, ExtrudedAreaSolid - from ada.geom.surfaces import RectangleProfileDef from ada.cadit.ifc.store import IfcStore + from ada.geom.solids import Box, ExtrudedAreaSolid class Shape(BackendGeom): @@ -239,7 +238,7 @@ def from_box_geom(name, box_geom: Box, **kwargs): return PrimBox(name, p1, p2, **kwargs) @staticmethod - def from_extruded_rect_profile(name, extrusion: ExtrudedAreaSolid, **kwargs): + def from_extruded_rect_profile(name, extrusion: ExtrudedAreaSolid, **kwargs): from ada.geom.surfaces import RectangleProfileDef if not isinstance(extrusion.swept_area, RectangleProfileDef): diff --git a/src/ada/api/transforms.py b/src/ada/api/transforms.py index 81eae3d5..229b8706 100644 --- a/src/ada/api/transforms.py +++ b/src/ada/api/transforms.py @@ -101,7 +101,7 @@ def from_axis_angle(axis: list[float], angle: float, origin: Iterable[float | in return Placement(origin=origin, xdir=m[0, :3], ydir=m[1, :3], zdir=m[2, :3]) @staticmethod - def from_co_linear_points(points: list[Point] | np.ndarray, xdir=None) -> Placement: + def from_co_linear_points(points: list[Point] | np.ndarray, xdir=None, flip_n=False) -> Placement: """Create a placement from a list of points that are co-linear.""" if not isinstance(points, np.ndarray): points = np.asarray(points) @@ -111,6 +111,8 @@ def from_co_linear_points(points: list[Point] | np.ndarray, xdir=None) -> Placem origin = points[0] n = normal_to_points_in_plane(points) + if flip_n: + n = -n if xdir is None: xdir = Direction(points[1] - points[0]).get_normalized() else: @@ -118,8 +120,6 @@ def from_co_linear_points(points: list[Point] | np.ndarray, xdir=None) -> Placem ydir = calc_yvec(xdir, n) return Placement(origin=origin, xdir=xdir, ydir=ydir, zdir=n) - # q1 = pq.Quaternion(matrix=np.asarray([xdir, ydir, n])).inverse - # return Placement.from_quaternion(q1, origin) @staticmethod def from_axis3d(axis: Axis2Placement3D) -> Placement: diff --git a/src/ada/cadit/ifc/read/geom/geom_reader.py b/src/ada/cadit/ifc/read/geom/geom_reader.py index 0a3738c9..a75e7caf 100644 --- a/src/ada/cadit/ifc/read/geom/geom_reader.py +++ b/src/ada/cadit/ifc/read/geom/geom_reader.py @@ -1,6 +1,7 @@ from typing import Union import ifcopenshell + from ada.geom import curves as geo_cu from ada.geom import solids as geo_so from ada.geom import surfaces as geo_su diff --git a/src/ada/cadit/ifc/read/read_beams.py b/src/ada/cadit/ifc/read/read_beams.py index b26d6aa8..f63ce26b 100644 --- a/src/ada/cadit/ifc/read/read_beams.py +++ b/src/ada/cadit/ifc/read/read_beams.py @@ -3,13 +3,13 @@ from typing import TYPE_CHECKING import numpy as np +from ifcopenshell.util.placement import get_local_placement from ada import Beam, Placement from ada.api.beams import BeamRevolve from ada.api.curves import CurveRevolve from ada.config import logger from ada.core.vector_utils import calc_yvec, unit_vector -from ifcopenshell.util.placement import get_local_placement from .geom.geom_reader import get_product_definitions from .geom.placement import axis3d diff --git a/src/ada/cadit/ifc/read/read_shapes.py b/src/ada/cadit/ifc/read/read_shapes.py index 6825f4a9..8359fb50 100644 --- a/src/ada/cadit/ifc/read/read_shapes.py +++ b/src/ada/cadit/ifc/read/read_shapes.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING import ifcopenshell.geom +from ifcopenshell.util.placement import get_local_placement from OCC.Core.TopoDS import TopoDS_Compound, TopoDS_Shape from ada import Shape @@ -12,7 +13,6 @@ from ada.config import Config, logger from ada.geom import Geometry from ada.visit.colors import Color -from ifcopenshell.util.placement import get_local_placement if TYPE_CHECKING: from ada.cadit.ifc.store import IfcStore @@ -52,7 +52,7 @@ def import_ifc_shape(product: ifcopenshell.entity_instance, name, ifc_store: Ifc units=ifc_store.assembly.units, color=color, opacity=color.opacity if color is not None else 1.0, - **extra_opts + **extra_opts, ) diff --git a/src/ada/cadit/sat/write/sat_entities.py b/src/ada/cadit/sat/write/sat_entities.py index 0998fca3..e3f17da1 100644 --- a/src/ada/cadit/sat/write/sat_entities.py +++ b/src/ada/cadit/sat/write/sat_entities.py @@ -182,9 +182,6 @@ def to_string(self) -> str: return f"-{self.id} CachedPlaneAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${entity} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 {centroid_str} {normal_str} 1 #" - - - @dataclass class PositionAttribName(SATEntity): position_attrib: PositionAttribName @@ -193,15 +190,15 @@ class PositionAttribName(SATEntity): face_bbox: list[float] box_attrib: Literal["ExactBoxLow", "ExactBoxHigh"] - def to_string(self) -> str: if self.box_attrib == "ExactBoxLow": - box_attrib = "@11 ExactBoxLow "+' '.join([str(x) for x in self.face_bbox[:3]]) + box_attrib = "@11 ExactBoxLow " + " ".join([str(x) for x in self.face_bbox[:3]]) else: - box_attrib = "@12 ExactBoxHigh "+ ' '.join([str(x) for x in self.face_bbox[3:]]) + box_attrib = "@12 ExactBoxHigh " + " ".join([str(x) for x in self.face_bbox[3:]]) return f"-{self.id} position_attrib-name_attrib-gen-attrib $-1 -1 ${self.position_attrib.id} ${self.fused_face_attrib.id} ${self.face.id} 2 0 0 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 {box_attrib} #" + @dataclass class FusedFaceAttribute(SATEntity): name: StringAttribName @@ -211,6 +208,7 @@ class FusedFaceAttribute(SATEntity): def to_string(self) -> str: return f"-{self.id} FusedFaceAttribute-DNV-attrib $-1 -1 ${self.posattrib.id} ${self.name.id} ${self.face.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 F 1 0 0 #" + @dataclass class FusedEdgeAttribute(SATEntity): name: StringAttribName @@ -222,4 +220,4 @@ class FusedEdgeAttribute(SATEntity): def to_string(self) -> str: length = make_ints_if_possible([self.edge_length])[0] edge_spec = f"{self.edge_seq[0]} {self.edge_seq[1]} {self.edge_idx} 0 {length}" - return f"-{self.id} FusedEdgeAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${self.entity.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 {edge_spec} #" \ No newline at end of file + return f"-{self.id} FusedEdgeAttribute-DNV-attrib $-1 -1 $-1 ${self.name.id} ${self.entity.id} 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 {edge_spec} #" diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index ae5e3d9d..4034a42a 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -13,7 +13,9 @@ from ada.cadit.sat.write.writer import SatWriter -def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: SatWriter, use_dual_assembly=False) -> list[se.SATEntity]: +def plate_to_sat_entities( + pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: SatWriter, use_dual_assembly=False +) -> list[se.SATEntity]: """Convert a Plate object to a SAT entities.""" if geo_repr != GeomRepr.SHELL: @@ -160,7 +162,12 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: edge_str_id = id_gen.next_id() length = ada.Direction(p1.point - p2.point).get_length() fusedge = se.FusedEdgeAttribute( - id_gen.next_id(), name=edge_str_id, entity=edge, edge_idx=i + 1, edge_seq=edge_seq[i], edge_length=length + id_gen.next_id(), + name=edge_str_id, + entity=edge, + edge_idx=i + 1, + edge_seq=edge_seq[i], + edge_length=length, ) edge_string_att = se.StringAttribName(edge_str_id, edge_n, edge, attrib_ref=fusedge) edge.attrib_name = edge_string_att @@ -181,7 +188,6 @@ def plate_to_sat_entities(pl: ada.Plate, face_name: str, geo_repr: GeomRepr, sw: string_attrib_name, cached_plane_attrib, surface, - ] + coedges + edges diff --git a/src/ada/core/vector_utils.py b/src/ada/core/vector_utils.py index 76a5b1c1..e573f073 100644 --- a/src/ada/core/vector_utils.py +++ b/src/ada/core/vector_utils.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Iterable +from typing import TYPE_CHECKING, Iterable import numpy as np @@ -9,6 +9,9 @@ from .exceptions import VectorNormalizeError +if TYPE_CHECKING: + from ada import Point + def angle_between(v1, v2): """ @@ -361,11 +364,15 @@ def calc_zvec(x_vec, y_vec=None) -> np.ndarray: return np.cross(x_vec, y_vec) -def get_centroid(points): +def get_centroid(points) -> Point: + from ada import Point + x, y, z = 0, 0, 0 for p in points: x += p[0] y += p[1] z += p[2] + n = len(points) - return x / n, y / n, z / n + + return Point(x / n, y / n, z / n) diff --git a/tests/core/cadit/ifc/read/test_read_shape_with_transformation.py b/tests/core/cadit/ifc/read/test_read_shape_with_transformation.py index 2b63de4d..17a0eef0 100644 --- a/tests/core/cadit/ifc/read/test_read_shape_with_transformation.py +++ b/tests/core/cadit/ifc/read/test_read_shape_with_transformation.py @@ -1,5 +1,6 @@ import ada from ada.config import Config +from ada.geom.solids import Box def test_read_shape_w_transformation(example_files): @@ -7,9 +8,15 @@ def test_read_shape_w_transformation(example_files): _ = a.to_ifc(file_obj_only=True) print(a) + def test_read_rotated_box(example_files): - Config().update_config_globally("ifc_import_shape_geom",True) + Config().update_config_globally("ifc_import_shape_geom", True) a = ada.from_ifc(example_files / "ifc_files/box_rotated.ifc") - door1 = a.get_by_name('door1') - door2 = a.get_by_name('door2') - print(a) + door1 = a.get_by_name("door1") + door2 = a.get_by_name("door2") + + geom1 = door1.geom.geometry + assert isinstance(geom1, Box) + + geom2 = door2.geom.geometry + assert isinstance(geom2, Box) diff --git a/tests/core/cadit/ifc/roundtripping/test_roundtrip_box.py b/tests/core/cadit/ifc/roundtripping/test_roundtrip_box.py index e9901bb9..ac05d496 100644 --- a/tests/core/cadit/ifc/roundtripping/test_roundtrip_box.py +++ b/tests/core/cadit/ifc/roundtripping/test_roundtrip_box.py @@ -3,7 +3,7 @@ def test_basic_box(): - box = ada.PrimBox('box1', (1, 2, 3), (4, 5, 6)) + box = ada.PrimBox("box1", (1, 2, 3), (4, 5, 6)) a = ada.Assembly() / box a.ifc_store.sync() Config().update_config_globally("ifc_import_shape_geom", True) @@ -11,6 +11,6 @@ def test_basic_box(): results = list(b.get_all_physical_objects()) assert len(results) == 1 rshape = results[0] - assert rshape.name == 'box1' + assert rshape.name == "box1" rbox = ada.PrimBox.from_box_geom(rshape.name, rshape.geom.geometry, metadata=rshape.metadata) assert rbox.p1.is_equal(box.p1) diff --git a/tests/core/cadit/sat/test_write_write_basic_sat.py b/tests/core/cadit/sat/test_write_write_basic_sat.py index e7194151..ccfcfae9 100644 --- a/tests/core/cadit/sat/test_write_write_basic_sat.py +++ b/tests/core/cadit/sat/test_write_write_basic_sat.py @@ -16,6 +16,8 @@ def test_write_basic_plate_sat(example_files, tmp_path): # Make sure the top-level lines are the same for line_a, line_b in zip(sat_str.splitlines(), reference_file.read_text().splitlines()): + if "gmGeometry" in line_a: + continue if "coedge" in line_a or "edge" in line_a or "vertex" in line_a or "point" in line_a: break assert line_a == line_b From 7458ccdfc74499796e0de4b95da1835d35e18423 Mon Sep 17 00:00:00 2001 From: krande Date: Thu, 12 Dec 2024 14:21:57 +0100 Subject: [PATCH 21/22] minor changes --- src/ada/cadit/sat/write/write_plate.py | 34 +++++++++++++++++--------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index 4034a42a..227b5373 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -5,6 +5,7 @@ import numpy as np import ada +from ada import LineSegment from ada.base.types import GeomRepr from ada.cadit.sat.utils import make_ints_if_possible from ada.cadit.sat.write import sat_entities as se @@ -97,11 +98,19 @@ def plate_to_sat_entities( seg3d = pl.poly.segments3d # By making seg3d counter clockwise area of the face will be positive (in genie checks) seg3d_ccw = [] - for i, edge in enumerate(seg3d): - new_edge = ada.LineSegment(edge.p2, edge.p1) - seg3d_ccw.append(new_edge) - seg3d_ccw.reverse() - seg3d = seg3d_ccw + # z = seg3d[0].p1.z + # new_seg3d = [ + # LineSegment((10,0,z), (10,10,z)), + # LineSegment((0,0,z), (10,0,z)), + # LineSegment((0,0,z), (0,10,z)), + # LineSegment((0,10,z), (10,10,z)), + # ] + # seg3d = new_seg3d + # for i, edge in enumerate(seg3d): + # new_edge = ada.LineSegment(edge.p2, edge.p1) + # seg3d_ccw.append(new_edge) + # seg3d_ccw.reverse() + # seg3d = seg3d_ccw coedge_ids = [] for i, edge in enumerate(seg3d): @@ -112,17 +121,18 @@ def plate_to_sat_entities( coedge_ids.append(coedge_id) point_map = {} - segments = pl.poly.segments3d - for p in segments: - if tuple(p.p1) not in point_map.keys(): - point_map[tuple(p.p1)] = se.SatPoint(id_gen.next_id(), p.p1) - if tuple(p.p2) not in point_map.keys(): - point_map[tuple(p.p2)] = se.SatPoint(id_gen.next_id(), p.p2) + + for segment in seg3d: + if tuple(segment.p1) not in point_map.keys(): + point_map[tuple(segment.p1)] = se.SatPoint(id_gen.next_id(), segment.p1) + if tuple(segment.p2) not in point_map.keys(): + point_map[tuple(segment.p2)] = se.SatPoint(id_gen.next_id(), segment.p2) points = list(point_map.values()) vertex_map = {p.id: se.Vertex(id_gen.next_id(), None, p) for p in points} vertices = list(vertex_map.values()) edge_seq = [(1, 2), (2, 3), (3, 4), (4, 1)] + for i, edge in enumerate(seg3d): coedge_id = coedge_ids[i] if i == 0: @@ -175,7 +185,7 @@ def plate_to_sat_entities( sat_entities.append(fusedge) sw.edge_name_id += 1 - coedge = se.CoEdge(coedge_id, next_coedge_id, prev_coedge_id, edge, loop, "forward") + coedge = se.CoEdge(coedge_id, prev_coedge_id, next_coedge_id, edge, loop, "forward") coedges.append(coedge) edges.append(edge) straight_curves.append(straight_curve) From 0a1c64ecd4a946603af8c610bbb8ca5f126a9db9 Mon Sep 17 00:00:00 2001 From: krande Date: Fri, 13 Dec 2024 13:48:08 +0100 Subject: [PATCH 22/22] fix lint --- src/ada/cadit/sat/write/write_plate.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/ada/cadit/sat/write/write_plate.py b/src/ada/cadit/sat/write/write_plate.py index 227b5373..fb52afb2 100644 --- a/src/ada/cadit/sat/write/write_plate.py +++ b/src/ada/cadit/sat/write/write_plate.py @@ -5,7 +5,6 @@ import numpy as np import ada -from ada import LineSegment from ada.base.types import GeomRepr from ada.cadit.sat.utils import make_ints_if_possible from ada.cadit.sat.write import sat_entities as se @@ -96,21 +95,6 @@ def plate_to_sat_entities( straight_curves = [] seg3d = pl.poly.segments3d - # By making seg3d counter clockwise area of the face will be positive (in genie checks) - seg3d_ccw = [] - # z = seg3d[0].p1.z - # new_seg3d = [ - # LineSegment((10,0,z), (10,10,z)), - # LineSegment((0,0,z), (10,0,z)), - # LineSegment((0,0,z), (0,10,z)), - # LineSegment((0,10,z), (10,10,z)), - # ] - # seg3d = new_seg3d - # for i, edge in enumerate(seg3d): - # new_edge = ada.LineSegment(edge.p2, edge.p1) - # seg3d_ccw.append(new_edge) - # seg3d_ccw.reverse() - # seg3d = seg3d_ccw coedge_ids = [] for i, edge in enumerate(seg3d): @@ -185,7 +169,7 @@ def plate_to_sat_entities( sat_entities.append(fusedge) sw.edge_name_id += 1 - coedge = se.CoEdge(coedge_id, prev_coedge_id, next_coedge_id, edge, loop, "forward") + coedge = se.CoEdge(coedge_id, prev_coedge_id, next_coedge_id, edge, loop, "forward") coedges.append(coedge) edges.append(edge) straight_curves.append(straight_curve)