3131from ansys .aedt .core .modeler .geometry_operators import GeometryOperators
3232
3333
34- class EdgeTypePrimitive (PyAedtBase ):
35- """Provides common methods for EdgePrimitive and FacePrimitive."""
34+ class ModifiablePrimitive (PyAedtBase ):
35+ """Base class for geometric primitives that support modification operations.
36+
37+ Provides fillet and chamfer operations for:
38+ - EdgePrimitive (3D designs only)
39+ - VertexPrimitive (2D designs only)
40+
41+ """
3642
3743 @pyaedt_function_handler ()
38- def fillet (self , radius = 0.1 , setback = 0.0 ):
44+ def fillet (self , radius : float = 0.1 , setback : float = 0.0 ) -> bool :
3945 """Add a fillet to the selected edges in 3D/vertices in 2D.
4046
4147 Parameters
@@ -81,7 +87,9 @@ def fillet(self, radius=0.1, setback=0.0):
8187 return True
8288
8389 @pyaedt_function_handler ()
84- def chamfer (self , left_distance = 1 , right_distance = None , angle = 45 , chamfer_type = 0 ):
90+ def chamfer (
91+ self , left_distance : float = 1 , right_distance : float | None = None , angle : float = 45 , chamfer_type : int = 0
92+ ) -> bool :
8593 """Add a chamfer to the selected edges in 3D/vertices in 2D.
8694
8795 Parameters
@@ -179,7 +187,7 @@ def chamfer(self, left_distance=1, right_distance=None, angle=45, chamfer_type=0
179187 return True
180188
181189
182- class VertexPrimitive (EdgeTypePrimitive , PyAedtBase ):
190+ class VertexPrimitive (ModifiablePrimitive , PyAedtBase ):
183191 """Contains the vertex object within the AEDT Desktop Modeler.
184192
185193 Parameters
@@ -234,7 +242,7 @@ def __repr__(self):
234242 return str (self .id )
235243
236244
237- class EdgePrimitive (EdgeTypePrimitive , PyAedtBase ):
245+ class EdgePrimitive (ModifiablePrimitive , PyAedtBase ):
238246 """Contains the edge object within the AEDT Desktop Modeler.
239247
240248 Parameters
@@ -251,6 +259,78 @@ def __init__(self, object3d, edge_id):
251259 self ._object3d = object3d
252260 self .oeditor = object3d ._oeditor
253261
262+ def __str__ (self ):
263+ return str (self .id )
264+
265+ def __repr__ (self ):
266+ return str (self .id )
267+
268+ def __iter__ (self ):
269+ """Return an iterator for the vertices of the edge.
270+
271+ Returns
272+ -------
273+ iterator
274+ Iterator over the vertices of the edge.
275+
276+ Examples
277+ --------
278+ >>> for vertex in edge:
279+ ... print(f"Vertex ID: {vertex.id}, Position: {vertex.position}")
280+ """
281+ return iter (self .vertices )
282+
283+ def __getitem__ (self , index ):
284+ """Get a vertex by index.
285+
286+ Parameters
287+ ----------
288+ index : int
289+
290+ Returns
291+ -------
292+ :class:`ansys.aedt.core.modeler.cad.elements_3d.VertexPrimitive`
293+ Vertex at the specified index.
294+
295+ Examples
296+ --------
297+ >>> first_vertex = edge[0]
298+ >>> last_vertex = edge[-1]
299+ """
300+ return self .vertices [index ]
301+
302+ def __contains__ (self , item : int | VertexPrimitive ) -> bool :
303+ """Check if a vertex is contained in the edge.
304+
305+ Parameters
306+ ----------
307+ item : :class:`ansys.aedt.core.modeler.cad.elements_3d.VertexPrimitive` or int
308+ Vertex object or vertex ID to check for containment.
309+
310+ Returns
311+ -------
312+ bool
313+ ``True`` if the item is part of this edge, ``False`` otherwise.
314+
315+ Examples
316+ --------
317+ >>> edge = obj.edges[0]
318+ >>> vertex = obj.vertices[0]
319+ >>> if vertex in edge:
320+ ... print("Vertex is part of this edge")
321+
322+ >>> # Check by vertex ID
323+ >>> vertex_id = 123
324+ >>> if vertex_id in edge:
325+ ... print("Vertex ID is part of this edge")
326+ """
327+ if isinstance (item , VertexPrimitive ):
328+ item_id = item .id
329+ return any (v .id == item_id for v in self )
330+ elif isinstance (item , int ):
331+ return any (v .id == item for v in self )
332+ return False
333+
254334 @property
255335 def name (self ):
256336 """Name of the object."""
@@ -364,12 +444,6 @@ def length(self):
364444 except Exception :
365445 return False
366446
367- def __str__ (self ):
368- return str (self .id )
369-
370- def __repr__ (self ):
371- return str (self .id )
372-
373447 @pyaedt_function_handler ()
374448 def create_object (self , non_model = False ):
375449 """Return a new object from the selected edge.
@@ -412,6 +486,150 @@ def move_along_normal(self, offset=1.0):
412486 return False
413487 return self ._object3d ._primitives .move_edge (self , offset )
414488
489+ @pyaedt_function_handler ()
490+ def fillet (self , radius = 0.1 , setback = 0.0 ):
491+ """Add a fillet to the selected edges in 3D/vertices in 2D.
492+
493+ Parameters
494+ ----------
495+ radius : float, optional
496+ Radius of the fillet. The default is ``0.1``.
497+ setback : float, optional
498+ Setback value for the file. The default is ``0.0``.
499+
500+ Returns
501+ -------
502+ bool
503+ ``True`` when successful, ``False`` when failed.
504+
505+ References
506+ ----------
507+ >>> oEditor.Fillet
508+
509+ """
510+ edge_id_list = []
511+ vertex_id_list = []
512+
513+ if isinstance (self , VertexPrimitive ):
514+ vertex_id_list = [self .id ]
515+ else :
516+ if self ._object3d .is3d :
517+ edge_id_list = [self .id ]
518+ else :
519+ self ._object3d .logger .error ("Fillet is possible only on a vertex in 2D designs." )
520+ return False
521+
522+ vArg1 = ["NAME:Selections" , "Selections:=" , self ._object3d .name , "NewPartsModelFlag:=" , "Model" ]
523+ vArg2 = ["NAME:FilletParameters" ]
524+ vArg2 .append ("Edges:=" ), vArg2 .append (edge_id_list )
525+ vArg2 .append ("Vertices:=" ), vArg2 .append (vertex_id_list )
526+ vArg2 .append ("Radius:=" ), vArg2 .append (self ._object3d ._primitives ._app .value_with_units (radius ))
527+ vArg2 .append ("Setback:=" ), vArg2 .append (self ._object3d ._primitives ._app .value_with_units (setback ))
528+ self ._object3d ._oeditor .Fillet (vArg1 , ["NAME:Parameters" , vArg2 ])
529+ if self ._object3d .name in list (self ._object3d ._oeditor .GetObjectsInGroup ("UnClassified" )):
530+ self ._object3d ._primitives ._odesign .Undo ()
531+ self ._object3d .logger .error ("Operation failed, generating an unclassified object. Check and retry." )
532+ return False
533+ return True
534+
535+ @pyaedt_function_handler ()
536+ def chamfer (self , left_distance = 1 , right_distance = None , angle = 45 , chamfer_type = 0 ):
537+ """Add a chamfer to the selected edges in 3D/vertices in 2D.
538+
539+ Parameters
540+ ----------
541+ left_distance : float, optional
542+ Left distance from the edge. The default is ``1``.
543+ right_distance : float, optional
544+ Right distance from the edge. The default is ``None``.
545+ angle : float, optional.
546+ Angle value for chamfer types 2 and 3. The default is ``0``.
547+ chamfer_type : int, optional
548+ Type of the chamfer. Options are:
549+ * 0 - Symmetric
550+ * 1 - Left Distance-Right Distance
551+ * 2 - Left Distance-Angle
552+ * 3 - Right Distance-Angle
553+
554+ The default is ``0``.
555+
556+ Returns
557+ -------
558+ bool
559+ ``True`` when successful, ``False`` when failed.
560+
561+ References
562+ ----------
563+ >>> oEditor.Chamfer
564+
565+ """
566+ edge_id_list = []
567+ vertex_id_list = []
568+
569+ if isinstance (self , VertexPrimitive ):
570+ vertex_id_list = [self .id ]
571+ else :
572+ if self ._object3d .is3d :
573+ edge_id_list = [self .id ]
574+ else :
575+ self ._object3d .logger .error ("chamfer is possible only on Vertex in 2D Designs " )
576+ return False
577+ vArg1 = ["NAME:Selections" , "Selections:=" , self ._object3d .name , "NewPartsModelFlag:=" , "Model" ]
578+ vArg2 = ["NAME:ChamferParameters" ]
579+ vArg2 .append ("Edges:=" ), vArg2 .append (edge_id_list )
580+ vArg2 .append ("Vertices:=" ), vArg2 .append (vertex_id_list )
581+ if right_distance is None :
582+ right_distance = left_distance
583+ if chamfer_type == 0 :
584+ if left_distance != right_distance :
585+ self ._object3d .logger .error (
586+ "Do not set right distance or ensure that left distance equals right distance."
587+ )
588+ (
589+ vArg2 .append ("LeftDistance:=" ),
590+ vArg2 .append (self ._object3d ._primitives ._app .value_with_units (left_distance )),
591+ )
592+ (
593+ vArg2 .append ("RightDistance:=" ),
594+ vArg2 .append (self ._object3d ._primitives ._app .value_with_units (right_distance )),
595+ )
596+ vArg2 .append ("ChamferType:=" ), vArg2 .append ("Symmetric" )
597+ elif chamfer_type == 1 :
598+ (
599+ vArg2 .append ("LeftDistance:=" ),
600+ vArg2 .append (self ._object3d ._primitives ._app .value_with_units (left_distance )),
601+ )
602+ (
603+ vArg2 .append ("RightDistance:=" ),
604+ vArg2 .append (self ._object3d ._primitives ._app .value_with_units (right_distance )),
605+ )
606+ vArg2 .append ("ChamferType:=" ), vArg2 .append ("Left Distance-Right Distance" )
607+ elif chamfer_type == 2 :
608+ (
609+ vArg2 .append ("LeftDistance:=" ),
610+ vArg2 .append (self ._object3d ._primitives ._app .value_with_units (left_distance )),
611+ )
612+ # NOTE: Seems like there is a bug in the API as Angle can't be used
613+ vArg2 .append ("RightDistance:=" ), vArg2 .append (f"{ angle } deg" )
614+ vArg2 .append ("ChamferType:=" ), vArg2 .append ("Left Distance-Angle" )
615+ elif chamfer_type == 3 :
616+ # NOTE: Seems like there is a bug in the API as Angle can't be used
617+ vArg2 .append ("LeftDistance:=" ), vArg2 .append (f"{ angle } deg" )
618+ (
619+ vArg2 .append ("RightDistance:=" ),
620+ vArg2 .append (self ._object3d ._primitives ._app .value_with_units (right_distance )),
621+ )
622+ vArg2 .append ("ChamferType:=" ), vArg2 .append ("Right Distance-Angle" )
623+ else :
624+ self ._object3d .logger .error ("Wrong chamfer_type provided. Value must be an integer from 0 to 3." )
625+ return False
626+ self ._object3d ._oeditor .Chamfer (vArg1 , ["NAME:Parameters" , vArg2 ])
627+ if self ._object3d .name in list (self ._object3d ._oeditor .GetObjectsInGroup ("UnClassified" )):
628+ self ._object3d .odesign .Undo ()
629+ self ._object3d .logger .error ("Operation Failed generating Unclassified object. Check and retry" )
630+ return False
631+ return True
632+
415633
416634class FacePrimitive (PyAedtBase ):
417635 """Contains the face object within the AEDT Desktop Modeler.
0 commit comments