Skip to content

Commit de51bd6

Browse files
authored
Face coordinate system - Enhancement/723 (#818)
* Added bounding_dimension property to 3D objects to get the bounding box dimension * removed a print * - completed the FaceCoordinateSystem - created the BaseCoordinateSystem common to FaceCoordinateSystem and CoordinateSystem * importing Face coordinate system from project file is now supported * black checking * added unit tests * black checking * added examples * black checking * codespell check * increased the number of unit tests. Fixed bug in _get_type_from_id. Fixed bug in _get_coordinate_data * black checking. Code cleanup * improved unittests * black checking * codecov checking * black checking * added option always_move_to_end for face coordinate system * increased coverage * fixed coordinate system unit test
1 parent 0451aef commit de51bd6

File tree

8 files changed

+4505
-130
lines changed

8 files changed

+4505
-130
lines changed

_unittest/example_models/Coordinate_System.aedt

Lines changed: 1268 additions & 0 deletions
Large diffs are not rendered by default.

_unittest/example_models/Coordinate_System1.aedt

Lines changed: 711 additions & 0 deletions
Large diffs are not rendered by default.

_unittest/example_models/Coordinate_System2.aedt

Lines changed: 1011 additions & 0 deletions
Large diffs are not rendered by default.

_unittest/example_models/Coordinate_System3.aedt

Lines changed: 737 additions & 0 deletions
Large diffs are not rendered by default.

_unittest/test_02_3D_modeler.py

Lines changed: 121 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Setup paths for module imports
22
from _unittest.conftest import BasisTest, pyaedt_unittest_check_desktop_error
3+
from pyaedt.modeler.Modeler import FaceCoordinateSystem
34

45
try:
56
import pytest # noqa: F401
@@ -271,7 +272,7 @@ def test_39_create_coaxial(self):
271272
assert isinstance(coax[1].id, int)
272273
assert isinstance(coax[2].id, int)
273274

274-
def test_40_create_coordinate(self):
275+
def test_40_create_coordinate_system(self):
275276
cs = self.aedtapp.modeler.create_coordinate_system()
276277
assert cs
277278
assert cs.update()
@@ -287,13 +288,83 @@ def test_40_create_coordinate(self):
287288
assert cs.change_cs_mode(0)
288289
assert cs.delete()
289290

291+
def test_40a_create_face_coordinate_system(self):
292+
box = self.aedtapp.modeler.create_box([0, 0, 0], [2, 2, 2])
293+
face = box.faces[0]
294+
fcs = self.aedtapp.modeler.create_face_coordinate_system(face, face.edges[0], face.edges[1])
295+
assert fcs
296+
assert fcs.face_id == face.id
297+
assert fcs.update()
298+
assert fcs.delete()
299+
fcs2 = self.aedtapp.modeler.create_face_coordinate_system(face, face, face.edges[1].vertices[0])
300+
assert fcs2
301+
assert fcs2.delete()
302+
fcs2 = self.aedtapp.modeler.create_face_coordinate_system(
303+
face, face.edges[0].vertices[0], face.edges[1].vertices[0]
304+
)
305+
assert fcs2
306+
assert fcs2.delete()
307+
fcs3 = self.aedtapp.modeler.create_face_coordinate_system(
308+
face, face.edges[1].vertices[1], face.edges[1].vertices[0]
309+
)
310+
assert fcs3
311+
assert fcs3.delete()
312+
fcs4 = self.aedtapp.modeler.create_face_coordinate_system(face, face.edges[2], face.edges[3], name="test")
313+
assert fcs4
314+
assert fcs4.name == "test"
315+
assert fcs4.delete()
316+
fcs5 = self.aedtapp.modeler.create_face_coordinate_system(face, face.edges[2], face.edges[3], axis="Y")
317+
assert fcs5
318+
assert fcs5.props["WhichAxis"] == "Y"
319+
assert fcs5.delete()
320+
fcs6 = self.aedtapp.modeler.create_face_coordinate_system(face, face.edges[2], face.edges[3], rotation=14.3)
321+
assert fcs6
322+
assert fcs6.props["ZRotationAngle"] == "14.3deg"
323+
assert fcs6.delete()
324+
fcs7 = self.aedtapp.modeler.create_face_coordinate_system(face, face.edges[2], face.edges[3], offset=[0.2, 0.3])
325+
assert fcs7
326+
assert fcs7.props["XOffset"] == "0.2" + self.aedtapp.modeler.model_units
327+
assert fcs7.props["YOffset"] == "0.3" + self.aedtapp.modeler.model_units
328+
assert fcs7.delete()
329+
fcs8 = self.aedtapp.modeler.create_face_coordinate_system(face.id, face.edges[0].id, face.edges[1].id)
330+
assert fcs8
331+
assert fcs8.delete()
332+
fcs9 = self.aedtapp.modeler.create_face_coordinate_system(face.id, face.edges[0].vertices[0].id, face.id)
333+
assert fcs9
334+
assert fcs9.delete()
335+
fcs10 = self.aedtapp.modeler.create_face_coordinate_system(
336+
face, face.edges[2], face.edges[3], always_move_to_end=False
337+
)
338+
assert fcs10
339+
assert fcs10.props["MoveToEnd"] is False
340+
assert fcs10.delete()
341+
fcs = FaceCoordinateSystem(self.aedtapp.modeler)
342+
assert fcs._part_name is None
343+
assert fcs._get_type_from_id(box.id) == "3dObject"
344+
assert fcs._get_type_from_id(face.id) == "Face"
345+
assert fcs._get_type_from_id(face.edges[0].id) == "Edge"
346+
assert fcs._get_type_from_id(face.edges[0].vertices[0].id) == "Vertex"
347+
assert fcs._get_type_from_object(box) == "3dObject"
348+
assert fcs._get_type_from_object(face) == "Face"
349+
assert fcs._get_type_from_object(face.edges[0]) == "Edge"
350+
assert fcs._get_type_from_object(face.edges[0].vertices[0]) == "Vertex"
351+
290352
def test_41_rename_coordinate(self):
291353
cs = self.aedtapp.modeler.create_coordinate_system(name="oldname")
292354
assert cs.name == "oldname"
293355
assert cs.rename("newname")
294356
assert cs.name == "newname"
295357
assert cs.delete()
296358

359+
def test_41a_rename_face_coordinate(self):
360+
box = self.aedtapp.modeler.create_box([0, 0, 0], [2, 2, 2])
361+
face = box.faces[0]
362+
fcs = self.aedtapp.modeler.create_face_coordinate_system(face, face.edges[0], face.edges[1], name="oldname")
363+
assert fcs.name == "oldname"
364+
assert fcs.rename("newname")
365+
assert fcs.name == "newname"
366+
assert fcs.delete()
367+
297368
def test_42A_update_coordinate_system(self):
298369
for cs in self.aedtapp.modeler.coordinate_systems:
299370
cs.delete()
@@ -310,11 +381,36 @@ def test_42A_update_coordinate_system(self):
310381
cs2.props["Theta"] = 30
311382
assert cs2.update()
312383
cs2.ref_cs = "Global"
313-
cs2.update()
384+
assert cs2.update()
314385
assert tuple(self.aedtapp.modeler.oeditor.GetCoordinateSystems()) == ("Global", "CS1", "CS2")
315386
assert len(self.aedtapp.modeler.coordinate_systems) == 2
316387
assert cs2.delete()
317388

389+
def test_42A_update_face_coordinate_system(self):
390+
for cs in self.aedtapp.modeler.coordinate_systems:
391+
cs.delete()
392+
box = self.aedtapp.modeler.create_box([0, 0, 0], [2, 2, 2])
393+
face = box.faces[0]
394+
fcs = self.aedtapp.modeler.create_face_coordinate_system(face, face.edges[0], face.edges[1], name="FCS1")
395+
assert fcs
396+
fcs.props["XOffset"] = "0.2mm"
397+
fcs.props["YOffset"] = "0.3mm"
398+
assert fcs.props["XOffset"] == "0.2mm"
399+
assert fcs.props["YOffset"] == "0.3mm"
400+
assert fcs.update()
401+
fcs.props["ZRotationAngle"] = "14.3deg"
402+
assert fcs.update()
403+
assert fcs.props["ZRotationAngle"] == "14.3deg"
404+
fcs.props["WhichAxis"] = "Y"
405+
assert fcs.update()
406+
assert fcs.props["WhichAxis"] == "Y"
407+
fcs.props["MoveToEnd"] = False
408+
assert fcs.update()
409+
assert fcs.props["MoveToEnd"] is False
410+
assert tuple(self.aedtapp.modeler.oeditor.GetCoordinateSystems()) == ("Global", "FCS1")
411+
assert len(self.aedtapp.modeler.coordinate_systems) == 1
412+
assert fcs.delete()
413+
318414
def test_42B_set_as_working_cs(self):
319415
for cs in self.aedtapp.modeler.coordinate_systems:
320416
cs.delete()
@@ -323,10 +419,31 @@ def test_42B_set_as_working_cs(self):
323419
assert cs1.set_as_working_cs()
324420
assert cs2.set_as_working_cs()
325421

422+
def test_42C_set_as_working_face_cs(self):
423+
for cs in self.aedtapp.modeler.coordinate_systems:
424+
cs.delete()
425+
box = self.aedtapp.modeler.create_box([0, 0, 0], [2, 2, 2])
426+
face = box.faces[0]
427+
fcs1 = self.aedtapp.modeler.create_face_coordinate_system(face, face.edges[0], face.edges[1])
428+
fcs2 = self.aedtapp.modeler.create_face_coordinate_system(face, face, face.edges[1])
429+
assert fcs1.set_as_working_cs()
430+
assert fcs2.set_as_working_cs()
431+
326432
def test_43_set_working_coordinate_system(self):
327433
cs1 = self.aedtapp.modeler.create_coordinate_system(name="new1")
328-
self.aedtapp.modeler.set_working_coordinate_system("Global")
329-
self.aedtapp.modeler.set_working_coordinate_system("new1")
434+
assert self.aedtapp.modeler.set_working_coordinate_system("Global")
435+
assert self.aedtapp.modeler.set_working_coordinate_system("new1")
436+
assert self.aedtapp.modeler.set_working_coordinate_system("Global")
437+
assert self.aedtapp.modeler.set_working_coordinate_system(cs1)
438+
439+
def test_43_set_working_face_coordinate_system(self):
440+
box = self.aedtapp.modeler.create_box([0, 0, 0], [2, 2, 2])
441+
face = box.faces[0]
442+
fcs = self.aedtapp.modeler.create_face_coordinate_system(face, face, face.edges[1], name="new2")
443+
assert self.aedtapp.modeler.set_working_coordinate_system("Global")
444+
assert self.aedtapp.modeler.set_working_coordinate_system("new2")
445+
assert self.aedtapp.modeler.set_working_coordinate_system("Global")
446+
assert self.aedtapp.modeler.set_working_coordinate_system(fcs)
330447

331448
def test_44_sweep_around_axis(self):
332449
rect1 = self.aedtapp.modeler.primitives.create_rectangle(

_unittest/test_13_LoadAEDTFile.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
# Setup paths for module imports
2-
from _unittest.conftest import local_path, scratch_path
2+
from _unittest.conftest import local_path, scratch_path, desktop_version
33

44
# Import required modules
55
from pyaedt.generic.filesystem import Scratch
66
from pyaedt.generic.LoadAEDTFile import load_entire_aedt_file
7+
from pyaedt import Hfss
78
import base64
89
import filecmp
910
import os
1011
import sys
12+
import gc
1113

1214

1315
def _write_jpg(design_info, scratch):
@@ -75,3 +77,41 @@ def test_02_check_design_names(self):
7577
def test_03_check_first_design_jpg(self):
7678
jpg_file = _write_jpg(self.design_info[0], self.local_scratch.path)
7779
assert filecmp.cmp(jpg_file, os.path.join(local_path, "example_models", "Cassegrain_Hybrid.jpg"))
80+
81+
82+
class TestProjectFileWithCoordinateSystems:
83+
def setup_class(self):
84+
with Scratch(scratch_path) as self.local_scratch:
85+
aedt_file = os.path.join(local_path, "example_models", "Coordinate_System.aedt")
86+
self.test_project = self.local_scratch.copyfile(aedt_file)
87+
aedt_file = os.path.join(local_path, "example_models", "Coordinate_System1.aedt")
88+
self.test_project1 = self.local_scratch.copyfile(aedt_file)
89+
aedt_file = os.path.join(local_path, "example_models", "Coordinate_System2.aedt")
90+
self.test_project2 = self.local_scratch.copyfile(aedt_file)
91+
aedt_file = os.path.join(local_path, "example_models", "Coordinate_System3.aedt")
92+
self.test_project3 = self.local_scratch.copyfile(aedt_file)
93+
self.aedtapp = Hfss(specified_version=desktop_version)
94+
95+
def teardown_class(self):
96+
self.aedtapp._desktop.ClearMessages("", "", 3)
97+
self.local_scratch.remove()
98+
gc.collect()
99+
100+
def test_01_check_can_load_aedt_file_with_multiple_coord_systems(self):
101+
# implicitly this will test to make sure no exception is thrown by load_entire_aedt_file
102+
assert load_entire_aedt_file(self.test_project)
103+
104+
def test_02_check_coordinate_system_retrival(self):
105+
self.aedtapp.load_project(self.test_project, close_active_proj=True)
106+
cs = self.aedtapp.modeler.coordinate_systems
107+
assert cs
108+
self.aedtapp.load_project(self.test_project1, close_active_proj=True)
109+
cs = self.aedtapp.modeler.coordinate_systems
110+
assert cs
111+
self.aedtapp.load_project(self.test_project2, close_active_proj=True)
112+
cs = self.aedtapp.modeler.coordinate_systems
113+
assert cs
114+
self.aedtapp.load_project(self.test_project3, close_active_proj=True)
115+
cs = self.aedtapp.modeler.coordinate_systems
116+
assert cs
117+
self.aedtapp.close_project()

examples/01-Modeling-Setup/HFSS_CoordinateSystem.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,71 @@
123123

124124
cs5 = hfss.modeler.create_coordinate_system(name="CS5", mode="axisrotation", u=[1, 0, 0], theta=123)
125125

126+
###############################################################################
127+
# Create a Face Coordinate System
128+
# -------------------------------------------------------------------
129+
# Face coordinate systems are bound to an object face.
130+
# Here we create first a box and then a Face Coordinate System is defined on one of its faces.
131+
# To create the face coordinate system a reference face, the axis starting and ending points must be specified.
132+
box = hfss.modeler.create_box([0, 0, 0], [2, 2, 2])
133+
face = box.faces[0]
134+
fcs1 = hfss.modeler.create_face_coordinate_system(
135+
face=face, origin=face.edges[0], axis_position=face.edges[1], name="FCS1"
136+
)
137+
138+
###############################################################################
139+
# Create a Face Coordinate System centered on the face
140+
# -------------------------------------------------------------------
141+
# Here we create a Face Coordinate System centered on the face and with the X axis pointing to the edge vertex.
142+
fcs2 = hfss.modeler.create_face_coordinate_system(
143+
face=face, origin=face, axis_position=face.edges[0].vertices[0], name="FCS2"
144+
)
145+
146+
###############################################################################
147+
# Swap the X and Y axis of a Face coordinate system
148+
# -------------------------------------------------------------------
149+
# As default the X axis is pointing `axis_position`. Optionally the Y axis can be selected.
150+
fcs3 = hfss.modeler.create_face_coordinate_system(face=face, origin=face, axis_position=face.edges[0], axis="Y")
151+
152+
# The axis can also be changed after the coordinate system is created.
153+
fcs3.props["WhichAxis"] = "X"
154+
fcs3.update()
155+
156+
###############################################################################
157+
# Apply a rotation around the Z axis.
158+
# -------------------------------------------------------------------
159+
# The Z axis of a Face Coordinate System is always orthogonal to the face.
160+
# A rotation can be applied at definition. The rotation is expressed in degrees.
161+
fcs4 = hfss.modeler.create_face_coordinate_system(face=face, origin=face, axis_position=face.edges[1], rotation=10.3)
162+
163+
# The rotation can also be changed after the coordinate system is created.
164+
fcs4.props["ZRotationAngle"] = "3deg"
165+
fcs4.update()
166+
167+
###############################################################################
168+
# Apply an offset to the X and Y axis of a Face coordinate system
169+
# -------------------------------------------------------------------
170+
# The offset is respect the Face Coordinate System itself.
171+
fcs5 = hfss.modeler.create_face_coordinate_system(
172+
face=face, origin=face, axis_position=face.edges[2], offset=[0.5, 0.3]
173+
)
174+
175+
# The offset can also be changed after the coordinate system is created.
176+
fcs5.props["XOffset"] = "0.2mm"
177+
fcs5.props["YOffset"] = "0.1mm"
178+
fcs5.update()
179+
180+
###############################################################################
181+
# Create a coordinate system relative to a Face coordinate system
182+
# -------------------------------------------------------------------
183+
# Coordinate Systems and Face Coordinate Systems interact each other.
184+
face = box.faces[1]
185+
fcs6 = hfss.modeler.create_face_coordinate_system(face=face, origin=face, axis_position=face.edges[0])
186+
cs_fcs = hfss.modeler.create_coordinate_system(
187+
name="CS_FCS", origin=[0, 0, 0], reference_cs=fcs6.name, mode="view", view="iso"
188+
)
189+
190+
126191
###############################################################################
127192
# Get All Coordinate Systems
128193
# --------------------------

0 commit comments

Comments
 (0)