From d721cd149ebd023d42b78e8c79ca56bbd12bad76 Mon Sep 17 00:00:00 2001 From: Massimo Capodiferro <77293250+maxcapodi78@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:02:09 +0200 Subject: [PATCH] FEAT: Added chamfers and fillet methods to Object3d (#4763) Co-authored-by: maxcapodi78 Co-authored-by: Maxime Rey <87315832+MaxJPRey@users.noreply.github.com> --- _unittest/test_07_Object3D.py | 7 +- _unittest/test_08_Primitives3D.py | 4 + _unittest/test_09_Primitives2D.py | 9 ++- _unittest/test_14_AedtLogger.py | 2 +- pyaedt/modeler/cad/Primitives.py | 20 +++-- pyaedt/modeler/cad/object3d.py | 124 ++++++++++++++++++++++++++++++ 6 files changed, 157 insertions(+), 9 deletions(-) diff --git a/_unittest/test_07_Object3D.py b/_unittest/test_07_Object3D.py index defe68471da..13d2e6a3011 100644 --- a/_unittest/test_07_Object3D.py +++ b/_unittest/test_07_Object3D.py @@ -286,8 +286,13 @@ def test_10_chamfer(self): assert test test = initial_object.edges[4].chamfer(chamfer_type=4) assert not test - self.aedtapp.modeler.delete(initial_object) + initial_object = self.aedtapp.modeler.create_box([0, 0, 0], [10, 10, 5], "ChamferTest2", "Copper") + assert initial_object.chamfer(edges=initial_object.faces[0].edges[0], chamfer_type=3) + initial_object = self.aedtapp.modeler.create_box([0, 0, 0], [10, 10, 5], "ChamferTest3", "Copper") + assert initial_object.chamfer(edges=initial_object.faces[0].edges[0], chamfer_type=1) + initial_object = self.aedtapp.modeler.create_box([0, 0, 0], [10, 10, 5], "ChamferTest4", "Copper") + assert initial_object.chamfer(edges=initial_object.faces[2].edges[0], chamfer_type=2) def test_11_fillet(self): initial_object = self.aedtapp.modeler.create_box([0, 0, 0], [10, 10, 5], "FilletTest", "Copper") diff --git a/_unittest/test_08_Primitives3D.py b/_unittest/test_08_Primitives3D.py index 605d28a632b..d8c8dedb945 100644 --- a/_unittest/test_08_Primitives3D.py +++ b/_unittest/test_08_Primitives3D.py @@ -693,6 +693,8 @@ def test_42_chamfer(self): assert o.edges[0].chamfer(chamfer_type=3) self.aedtapp._odesign.Undo() assert not o.edges[0].chamfer(chamfer_type=4) + o2 = self.create_copper_box(name="MyBox2") + assert o2.chamfer(edges=o2.edges) def test_43_fillet_and_undo(self): o = self.create_copper_box(name="MyBox") @@ -701,6 +703,8 @@ def test_43_fillet_and_undo(self): assert o.edges[0].fillet() r = self.create_rectangle(name="MyRect") assert not r.edges[0].fillet() + o2 = self.create_copper_box(name="MyBox2") + assert o2.fillet(edges=o2.edges) def test_44_create_polyline_basic_segments(self): prim3D = self.aedtapp.modeler diff --git a/_unittest/test_09_Primitives2D.py b/_unittest/test_09_Primitives2D.py index 1f5965accdd..e448859e878 100644 --- a/_unittest/test_09_Primitives2D.py +++ b/_unittest/test_09_Primitives2D.py @@ -64,11 +64,18 @@ def test_05_create_poly(self): def test_chamfer_vertex(self): o = self.create_rectangle("Rectangle1") - o.vertices[0].chamfer() + assert o.vertices[0].chamfer() + o2 = self.create_rectangle("Rectangle2") + assert o2.chamfer(o2.vertices) + assert not o2.chamfer(edges=o2.edges) + assert not o2.chamfer() def test_fillet_vertex(self): o = self.create_rectangle("Rectangle1") o.vertices[0].fillet() + o2 = self.create_rectangle("Rectangle2") + assert o2.fillet(o2.vertices) + assert not o2.fillet(edges=o2.edges) def test_06_create_region(self): if self.aedtapp.modeler["Region"]: diff --git a/_unittest/test_14_AedtLogger.py b/_unittest/test_14_AedtLogger.py index 6693386a6b7..09f246b13ec 100644 --- a/_unittest/test_14_AedtLogger.py +++ b/_unittest/test_14_AedtLogger.py @@ -237,7 +237,7 @@ def test_log_when_accessing_non_existing_object(self, caplog): ) with pytest.raises(AttributeError): app.get_object_material_properties("MS1", "conductivity") - assert ("Global", logging.ERROR, "Object 'MS1' not found.") in caplog.record_tuples + assert ("Global", logging.ERROR, " assignment = MS1 ") in caplog.record_tuples class CaptureStdOut: diff --git a/pyaedt/modeler/cad/Primitives.py b/pyaedt/modeler/cad/Primitives.py index c4e2e605fb0..0dc53cd065f 100644 --- a/pyaedt/modeler/cad/Primitives.py +++ b/pyaedt/modeler/cad/Primitives.py @@ -123,7 +123,6 @@ def __setitem__(self, key, value): if self.__obj_type == "o": self.__parent._object_names_to_ids[value.name] = key - @pyaedt_function_handler() def __getitem__(self, item): if item in dict.keys(self): return dict.__getitem__(self, item) @@ -208,11 +207,20 @@ def __getitem__(self, partId): return partId try: return self.objects[partId] - except Exception: - if partId in self.user_defined_components.keys(): - return self.user_defined_components[partId] - self.logger.error("Object '{}' not found.".format(partId)) - return None + except KeyError: + pass + try: + return self.user_defined_components[partId] + except KeyError: + pass + try: + return self.planes[partId] + except KeyError: + pass + try: + return self.points[partId] + except KeyError: + return def __init__(self, app, is3d=True): self._app = app diff --git a/pyaedt/modeler/cad/object3d.py b/pyaedt/modeler/cad/object3d.py index e1804478c70..423a30436b7 100644 --- a/pyaedt/modeler/cad/object3d.py +++ b/pyaedt/modeler/cad/object3d.py @@ -1914,3 +1914,127 @@ def _change_property(self, vPropChange): def __str__(self): return self.name + + @pyaedt_function_handler() + def fillet(self, vertices=None, edges=None, radius=0.1, setback=0.0): + """Add a fillet to the selected edges in 3D/vertices in 2D. + + Parameters + ---------- + vertices : list, optional + List of vertices to fillet. Default is ``None``. + edges : list, optional + List of edges to fillet. Default is ``None``. + radius : float, optional + Radius of the fillet. The default is ``0.1``. + setback : float, optional + Setback value for the file. The default is ``0.0``. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + References + ---------- + + >>> oEditor.Fillet + + """ + if not vertices and not edges: + self.logger.error("Either vertices or edges have to be provided as input.") + return False + edge_id_list = [] + vertex_id_list = [] + if edges is not None: + edge_id_list = self._primitives.convert_to_selections(edges, return_list=True) + if vertices is not None: + vertex_id_list = self._primitives.convert_to_selections(vertices, return_list=True) + + vArg1 = ["NAME:Selections", "Selections:=", self.name, "NewPartsModelFlag:=", "Model"] + vArg2 = ["NAME:FilletParameters"] + vArg2.append("Edges:="), vArg2.append(edge_id_list) + vArg2.append("Vertices:="), vArg2.append(vertex_id_list) + vArg2.append("Radius:="), vArg2.append(self._primitives._arg_with_dim(radius)) + vArg2.append("Setback:="), vArg2.append(self._primitives._arg_with_dim(setback)) + self._oeditor.Fillet(vArg1, ["NAME:Parameters", vArg2]) + if self.name in list(self._oeditor.GetObjectsInGroup("UnClassified")): + self._primitives._odesign.Undo() + self.logger.error("Operation failed, generating an unclassified object. Check and retry.") + return False + return True + + @pyaedt_function_handler() + def chamfer(self, vertices=None, edges=None, left_distance=1, right_distance=None, angle=45, chamfer_type=0): + """Add a chamfer to the selected edges in 3D/vertices in 2D. + + Parameters + ---------- + vertices : list, optional + List of vertices to chamfer. + edges : list, optional + List of edges to chamfer. + left_distance : float, optional + Left distance from the edge. The default is ``1``. + right_distance : float, optional + Right distance from the edge. The default is ``None``. + angle : float, optional. + Angle value for chamfer types 2 and 3. The default is ``0``. + chamfer_type : int, optional + Type of the chamfer. Options are: + * 0 - Symmetric + * 1 - Left Distance-Right Distance + * 2 - Left Distance-Angle + * 3 - Right Distance-Angle + + The default is ``0``. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + References + ---------- + + >>> oEditor.Chamfer + + """ + edge_id_list = [] + vertex_id_list = [] + if edges is not None: + edge_id_list = self._primitives.convert_to_selections(edges, return_list=True) + if vertices is not None: + vertex_id_list = self._primitives.convert_to_selections(vertices, return_list=True) + if vertex_id_list == edge_id_list == []: + self.logger.error("Vertices or Edges have to be provided as input.") + return False + vArg1 = ["NAME:Selections", "Selections:=", self.name, "NewPartsModelFlag:=", "Model"] + vArg2 = ["NAME:ChamferParameters"] + vArg2.append("Edges:="), vArg2.append(edge_id_list) + vArg2.append("Vertices:="), vArg2.append(vertex_id_list) + vArg2.append("LeftDistance:="), vArg2.append(self._primitives._arg_with_dim(left_distance)) + if not right_distance: + right_distance = left_distance + if chamfer_type == 0: + vArg2.append("RightDistance:="), vArg2.append(self._primitives._arg_with_dim(right_distance)) + vArg2.append("ChamferType:="), vArg2.append("Symmetric") + elif chamfer_type == 1: + vArg2.append("RightDistance:="), vArg2.append(self._primitives._arg_with_dim(right_distance)) + vArg2.append("ChamferType:="), vArg2.append("Left Distance-Right Distance") + elif chamfer_type == 2: + vArg2.append("Angle:="), vArg2.append(str(angle) + "deg") + vArg2.append("ChamferType:="), vArg2.append("Left Distance-Right Distance") + elif chamfer_type == 3: + vArg2.append("LeftDistance:="), vArg2.append(str(angle) + "deg") + vArg2.append("RightDistance:="), vArg2.append(self._primitives._arg_with_dim(right_distance)) + vArg2.append("ChamferType:="), vArg2.append("Right Distance-Angle") + else: + self.logger.error("Wrong Type Entered. Type must be integer from 0 to 3") + return False + self._oeditor.Chamfer(vArg1, ["NAME:Parameters", vArg2]) + if self.name in list(self._oeditor.GetObjectsInGroup("UnClassified")): + self._primitives._odesign.Undo() + self.logger.error("Operation Failed generating Unclassified object. Check and retry") + return False + return True