topologicpy 0.8.31__py3-none-any.whl → 0.8.35__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
topologicpy/Face.py CHANGED
@@ -1004,58 +1004,75 @@ class Face():
1004
1004
  else:
1005
1005
  internalBoundaries = Cluster.Wires(internalBoundariesCluster)
1006
1006
  return Face.ByWires(externalBoundary, internalBoundaries, tolerance=tolerance, silent=silent)
1007
-
1007
+
1008
1008
  @staticmethod
1009
- def NorthArrow(origin= None, radius: float = 0.5, sides: int = 16, direction: list = [0, 0, 1], northAngle: float = 0.0,
1010
- placement: str = "center", tolerance: float = 0.0001):
1009
+ def CHS(origin= None, radius: float = 0.5, thickness: float = 0.25, sides: int = 16, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001, silent: bool = False):
1011
1010
  """
1012
- Creates a north arrow.
1011
+ Creates a circular hollow section (CHS).
1013
1012
 
1014
1013
  Parameters
1015
1014
  ----------
1016
1015
  origin : topologic_core.Vertex, optional
1017
- The location of the origin of the circle. The default is None which results in the circle being placed at (0, 0, 0).
1016
+ The location of the origin of the CHS. The default is None which results in the CHS being placed at (0, 0, 0).
1018
1017
  radius : float , optional
1019
- The radius of the circle. The default is 1.
1020
- sides : int , optional
1021
- The number of sides of the circle. The default is 16.
1018
+ The outer radius of the CHS. The default is 0.5.
1019
+ thickness : float , optional
1020
+ The thickness of the CHS. The default is 0.25.
1022
1021
  direction : list , optional
1023
- The vector representing the up direction of the circle. The default is [0, 0, 1].
1024
- northAngle : float , optional
1025
- The angular offset in degrees from the positive Y axis direction. The angle is measured in a counter-clockwise fashion where 0 is positive Y, 90 is negative X, 180 is negative Y, and 270 is positive X.
1022
+ The vector representing the up direction of the CHS. The default is [0, 0, 1].
1026
1023
  placement : str , optional
1027
- The description of the placement of the origin of the circle. This can be "center", "lowerleft", "upperleft", "lowerright", or "upperright". It is case insensitive. The default is "center".
1024
+ The description of the placement of the origin of the CHS. This can be "center", "lowerleft", "upperleft", "lowerright", "upperright". It is case insensitive. The default is "center".
1028
1025
  tolerance : float , optional
1029
1026
  The desired tolerance. The default is 0.0001.
1027
+ silent : bool , optional
1028
+ If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
1030
1029
 
1031
1030
  Returns
1032
1031
  -------
1033
1032
  topologic_core.Face
1034
- The created circle.
1033
+ The created face.
1035
1034
 
1036
1035
  """
1037
- from topologicpy.Topology import Topology
1038
1036
  from topologicpy.Vertex import Vertex
1039
- if not Topology.IsInstance(origin, "Vertex"):
1037
+ from topologicpy.Wire import Wire
1038
+ from topologicpy.Topology import Topology
1039
+
1040
+ if thickness >= radius:
1041
+ if not silent:
1042
+ print("Face.SHS - Error: The thickness value is larger than or equal to the outer radius value. Returning None.")
1043
+ return None
1044
+ if origin == None:
1040
1045
  origin = Vertex.Origin()
1041
1046
 
1042
- c = Face.Circle(origin=origin, radius=radius, sides=sides, direction=[0, 0, 1], placement="center", tolerance=tolerance)
1043
- r = Face.Rectangle(origin=origin, width=radius*0.01,length=radius*1.2, placement="lowerleft")
1044
- r = Topology.Translate(r, -0.005*radius,0,0)
1045
- arrow = Topology.Difference(c, r, tolerance=tolerance)
1046
- arrow = Topology.Rotate(arrow, origin=Vertex.Origin(), axis=[0, 0, 1], angle=northAngle)
1047
+ outer_wire = Wire.Circle(origin=Vertex.Origin(), radius=radius, sides=sides, direction=[0,0,1], placement="center", tolerance=tolerance)
1048
+ inner_wire = Wire.Circle(origin=Vertex.Origin(), radius=radius-thickness, sides=sides, direction=[0,0,1], placement="center", tolerance=tolerance)
1049
+ return_face = Face.ByWires(outer_wire, [inner_wire])
1050
+ if not Topology.IsInstance(return_face, "face"):
1051
+ if not silent:
1052
+ print("Face.CHS - Error: Could not create the face for the CHS. Returning None.")
1053
+ return None
1054
+
1055
+ xOffset = 0
1056
+ yOffset = 0
1057
+ zOffset = 0
1047
1058
  if placement.lower() == "lowerleft":
1048
- arrow = Topology.Translate(arrow, radius, radius, 0)
1059
+ xOffset = radius
1060
+ yOffset = radius
1049
1061
  elif placement.lower() == "upperleft":
1050
- arrow = Topology.Translate(arrow, radius, -radius, 0)
1062
+ xOffset = radius
1063
+ yOffset = -radius
1051
1064
  elif placement.lower() == "lowerright":
1052
- arrow = Topology.Translate(arrow, -radius, radius, 0)
1065
+ xOffset = -radius
1066
+ yOffset = radius
1053
1067
  elif placement.lower() == "upperright":
1054
- arrow = Topology.Translate(arrow, -radius, -radius, 0)
1055
- arrow = Topology.Place(arrow, originA=Vertex.Origin(), originB=origin)
1056
- arrow = Topology.Orient(arrow, origin=origin, dirA=[0,0,1], dirB=direction)
1057
- return arrow
1058
-
1068
+ xOffset = -radius
1069
+ yOffset = -radius
1070
+ return_face = Topology.Translate(return_face, x=xOffset, y=yOffset, z=zOffset)
1071
+ return_face = Topology.Place(return_face, originA=Vertex.Origin(), originB=origin)
1072
+ if direction != [0, 0, 1]:
1073
+ return_face = Topology.Orient(return_face, origin=origin, dirA=[0, 0, 1], dirB=direction)
1074
+ return return_face
1075
+
1059
1076
  @staticmethod
1060
1077
  def Circle(origin= None, radius: float = 0.5, sides: int = 16, fromAngle: float = 0.0, toAngle: float = 360.0, direction: list = [0, 0, 1],
1061
1078
  placement: str = "center", tolerance: float = 0.0001):
@@ -1218,19 +1235,19 @@ class Face():
1218
1235
 
1219
1236
  if not isinstance(width, int) and not isinstance(width, float):
1220
1237
  if not silent:
1221
- print("Wire.CrossShape - Error: The width input parameter is not a valid number. Returning None.")
1238
+ print("Face.CrossShape - Error: The width input parameter is not a valid number. Returning None.")
1222
1239
  return None
1223
1240
  if not isinstance(length, int) and not isinstance(length, float):
1224
1241
  if not silent:
1225
- print("Wire.CrossShape - Error: The length input parameter is not a valid number. Returning None.")
1242
+ print("Face.CrossShape - Error: The length input parameter is not a valid number. Returning None.")
1226
1243
  return None
1227
1244
  if not isinstance(a, int) and not isinstance(a, float):
1228
1245
  if not silent:
1229
- print("Wire.CrossShape - Error: The a input parameter is not a valid number. Returning None.")
1246
+ print("Face.CrossShape - Error: The a input parameter is not a valid number. Returning None.")
1230
1247
  return None
1231
1248
  if not isinstance(b, int) and not isinstance(b, float):
1232
1249
  if not silent:
1233
- print("Wire.CrossShape - Error: The b input parameter is not a valid number. Returning None.")
1250
+ print("Face.CrossShape - Error: The b input parameter is not a valid number. Returning None.")
1234
1251
  return None
1235
1252
  if c == None:
1236
1253
  c = width/2
@@ -1238,72 +1255,72 @@ class Face():
1238
1255
  d = length/2
1239
1256
  if not isinstance(c, int) and not isinstance(c, float):
1240
1257
  if not silent:
1241
- print("Wire.CrossShape - Error: The c input parameter is not a valid number. Returning None.")
1258
+ print("Face.CrossShape - Error: The c input parameter is not a valid number. Returning None.")
1242
1259
  return None
1243
1260
  if not isinstance(d, int) and not isinstance(d, float):
1244
1261
  if not silent:
1245
- print("Wire.CrossShape - Error: The d input parameter is not a valid number. Returning None.")
1262
+ print("Face.CrossShape - Error: The d input parameter is not a valid number. Returning None.")
1246
1263
  if width <= tolerance:
1247
1264
  if not silent:
1248
- print("Wire.CrossShape - Error: The width input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1265
+ print("Face.CrossShape - Error: The width input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1249
1266
  return None
1250
1267
  if length <= tolerance:
1251
1268
  if not silent:
1252
- print("Wire.CrossShape - Error: The length input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1269
+ print("Face.CrossShape - Error: The length input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1253
1270
  return None
1254
1271
  if a <= tolerance:
1255
1272
  if not silent:
1256
- print("Wire.CrossShape - Error: The a input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1273
+ print("Face.CrossShape - Error: The a input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1257
1274
  return None
1258
1275
  if b <= tolerance:
1259
1276
  if not silent:
1260
- print("Wire.CrossShape - Error: The b input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1277
+ print("Face.CrossShape - Error: The b input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1261
1278
  return None
1262
1279
  if c <= tolerance:
1263
1280
  if not silent:
1264
- print("Wire.CrossShape - Error: The c input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1281
+ print("Face.CrossShape - Error: The c input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1265
1282
  return None
1266
1283
  if d <= tolerance:
1267
1284
  if not silent:
1268
- print("Wire.CrossShape - Error: The d input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1285
+ print("Face.CrossShape - Error: The d input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1269
1286
  return None
1270
1287
  if a >= (width - tolerance*2):
1271
1288
  if not silent:
1272
- print("Wire.CrossShape - Error: The a input parameter must be less than the width input parameter. Returning None.")
1289
+ print("Face.CrossShape - Error: The a input parameter must be less than the width input parameter. Returning None.")
1273
1290
  return None
1274
1291
  if b >= (length - tolerance*2):
1275
1292
  if not silent:
1276
- print("Wire.CrossShape - Error: The b input parameter must be less than the length input parameter. Returning None.")
1293
+ print("Face.CrossShape - Error: The b input parameter must be less than the length input parameter. Returning None.")
1277
1294
  return None
1278
1295
  if c <= (tolerance + a/2):
1279
1296
  if not silent:
1280
- print("Wire.CrossShape - Error: The c input parameter must be more than half the a input parameter. Returning None.")
1297
+ print("Face.CrossShape - Error: The c input parameter must be more than half the a input parameter. Returning None.")
1281
1298
  return None
1282
1299
  if d <= (tolerance + b/2):
1283
1300
  if not silent:
1284
- print("Wire.CrossShape - Error: The c input parameter must be more than half the b input parameter. Returning None.")
1301
+ print("Face.CrossShape - Error: The c input parameter must be more than half the b input parameter. Returning None.")
1285
1302
  return None
1286
1303
  if c >= (width - tolerance - a/2):
1287
1304
  if not silent:
1288
- print("Wire.CrossShape - Error: The c input parameter must be less than the width minus half the a input parameter. Returning None.")
1305
+ print("Face.CrossShape - Error: The c input parameter must be less than the width minus half the a input parameter. Returning None.")
1289
1306
  return None
1290
1307
  if d >= (length - tolerance - b/2):
1291
1308
  if not silent:
1292
- print("Wire.CrossShape - Error: The c input parameter must be less than the width minus half the b input parameter. Returning None.")
1309
+ print("Face.CrossShape - Error: The c input parameter must be less than the width minus half the b input parameter. Returning None.")
1293
1310
  return None
1294
1311
  if origin == None:
1295
1312
  origin = Vertex.Origin()
1296
1313
  if not Topology.IsInstance(origin, "vertex"):
1297
1314
  if not silent:
1298
- print("Wire.CrossShape - Error: The origin input parameter is not a valid topologic vertex. Returning None.")
1315
+ print("Face.CrossShape - Error: The origin input parameter is not a valid topologic vertex. Returning None.")
1299
1316
  return None
1300
1317
  if not isinstance(direction, list):
1301
1318
  if not silent:
1302
- print("Wire.CrossShape - Error: The direction input parameter is not a valid list. Returning None.")
1319
+ print("Face.CrossShape - Error: The direction input parameter is not a valid list. Returning None.")
1303
1320
  return None
1304
1321
  if not len(direction) == 3:
1305
1322
  if not silent:
1306
- print("Wire.CrossShape - Error: The direction input parameter is not a valid vector. Returning None.")
1323
+ print("Face.CrossShape - Error: The direction input parameter is not a valid vector. Returning None.")
1307
1324
  return None
1308
1325
  cross_shape_wire = Wire.CrossShape(origin=origin,
1309
1326
  width=width,
@@ -1667,7 +1684,7 @@ class Face():
1667
1684
  return True
1668
1685
 
1669
1686
  @staticmethod
1670
- def Fillet(face, radius: float = 0, radiusKey: str = None, tolerance: float = 0.0001, silent: bool = False):
1687
+ def Fillet(face, radius: float = 0, sides: int = 16, radiusKey: str = None, tolerance: float = 0.0001, silent: bool = False):
1671
1688
  """
1672
1689
  Fillets (rounds) the interior and exterior corners of the input face given the input radius. See https://en.wikipedia.org/wiki/Fillet_(mechanics)
1673
1690
 
@@ -1675,8 +1692,10 @@ class Face():
1675
1692
  ----------
1676
1693
  face : topologic_core.Face
1677
1694
  The input face.
1678
- radius : float
1679
- The desired radius of the fillet.
1695
+ radius : float , optional
1696
+ The desired radius of the fillet. The default is 0.
1697
+ sides : int , optional
1698
+ The number of sides (segments) of the fillet. The default is 16.
1680
1699
  radiusKey : str , optional
1681
1700
  If specified, the dictionary of the vertices will be queried for this key to specify the desired fillet radius. The default is None.
1682
1701
  tolerance : float , optional
@@ -1704,7 +1723,7 @@ class Face():
1704
1723
  f_vertices = Topology.Vertices(face)
1705
1724
  if isinstance(radiusKey, str):
1706
1725
  eb = Topology.TransferDictionariesBySelectors(eb, selectors=f_vertices, tranVertices=True)
1707
- eb = Wire.Fillet(eb, radius=radius, radiusKey=radiusKey, tolerance=tolerance)
1726
+ eb = Wire.Fillet(eb, radius=radius, sides=sides, radiusKey=radiusKey, tolerance=tolerance, silent=True)
1708
1727
  if not Topology.IsInstance(eb, "Wire"):
1709
1728
  if not silent:
1710
1729
  print("Face.Fillet - Error: The operation failed. Returning None.")
@@ -1716,7 +1735,7 @@ class Face():
1716
1735
  if isinstance(radiusKey, str):
1717
1736
  ib = Topology.TransferDictionariesBySelectors(ib, selectors=f_vertices, tranVertices=True)
1718
1737
 
1719
- ib_wire = Wire.Fillet(ib, radius=radius, radiusKey=radiusKey, tolerance=tolerance, silent=silent)
1738
+ ib_wire = Wire.Fillet(ib, radius=radius, sides=sides, radiusKey=radiusKey, tolerance=tolerance, silent=True)
1720
1739
  if Topology.IsInstance(ib, "Wire"):
1721
1740
  ib_wires.append(ib_wire)
1722
1741
  else:
@@ -3129,6 +3148,57 @@ class Face():
3129
3148
  ev = Topology.TranslateByDirectionDistance(iv, vec, length)
3130
3149
  return Edge.ByVertices([iv, ev], tolerance=tolerance, silent=silent)
3131
3150
 
3151
+ @staticmethod
3152
+ def NorthArrow(origin= None, radius: float = 0.5, sides: int = 16, direction: list = [0, 0, 1], northAngle: float = 0.0,
3153
+ placement: str = "center", tolerance: float = 0.0001):
3154
+ """
3155
+ Creates a north arrow.
3156
+
3157
+ Parameters
3158
+ ----------
3159
+ origin : topologic_core.Vertex, optional
3160
+ The location of the origin of the circle. The default is None which results in the circle being placed at (0, 0, 0).
3161
+ radius : float , optional
3162
+ The radius of the circle. The default is 1.
3163
+ sides : int , optional
3164
+ The number of sides of the circle. The default is 16.
3165
+ direction : list , optional
3166
+ The vector representing the up direction of the circle. The default is [0, 0, 1].
3167
+ northAngle : float , optional
3168
+ The angular offset in degrees from the positive Y axis direction. The angle is measured in a counter-clockwise fashion where 0 is positive Y, 90 is negative X, 180 is negative Y, and 270 is positive X.
3169
+ placement : str , optional
3170
+ The description of the placement of the origin of the circle. This can be "center", "lowerleft", "upperleft", "lowerright", or "upperright". It is case insensitive. The default is "center".
3171
+ tolerance : float , optional
3172
+ The desired tolerance. The default is 0.0001.
3173
+
3174
+ Returns
3175
+ -------
3176
+ topologic_core.Face
3177
+ The created circle.
3178
+
3179
+ """
3180
+ from topologicpy.Topology import Topology
3181
+ from topologicpy.Vertex import Vertex
3182
+ if not Topology.IsInstance(origin, "Vertex"):
3183
+ origin = Vertex.Origin()
3184
+
3185
+ c = Face.Circle(origin=origin, radius=radius, sides=sides, direction=[0, 0, 1], placement="center", tolerance=tolerance)
3186
+ r = Face.Rectangle(origin=origin, width=radius*0.01,length=radius*1.2, placement="lowerleft")
3187
+ r = Topology.Translate(r, -0.005*radius,0,0)
3188
+ arrow = Topology.Difference(c, r, tolerance=tolerance)
3189
+ arrow = Topology.Rotate(arrow, origin=Vertex.Origin(), axis=[0, 0, 1], angle=northAngle)
3190
+ if placement.lower() == "lowerleft":
3191
+ arrow = Topology.Translate(arrow, radius, radius, 0)
3192
+ elif placement.lower() == "upperleft":
3193
+ arrow = Topology.Translate(arrow, radius, -radius, 0)
3194
+ elif placement.lower() == "lowerright":
3195
+ arrow = Topology.Translate(arrow, -radius, radius, 0)
3196
+ elif placement.lower() == "upperright":
3197
+ arrow = Topology.Translate(arrow, -radius, -radius, 0)
3198
+ arrow = Topology.Place(arrow, originA=Vertex.Origin(), originB=origin)
3199
+ arrow = Topology.Orient(arrow, origin=origin, dirA=[0,0,1], dirB=direction)
3200
+ return arrow
3201
+
3132
3202
  @staticmethod
3133
3203
  def PlaneEquation(face, mantissa: int = 6) -> dict:
3134
3204
  """
@@ -3332,6 +3402,201 @@ class Face():
3332
3402
  ib = [Wire.RemoveCollinearEdges(w, angTolerance=angTolerance, tolerance=tolerance, silent=silent) for w in Face.InternalBoundaries(face)]
3333
3403
  return Face.ByWires(eb, ib)
3334
3404
 
3405
+ @staticmethod
3406
+ def RHS(origin= None, width: float = 1.0, length: float = 1.0, thickness: float = 0.25, outerFillet: float = 0.0, innerFillet: float = 0.0, sides: int = 16, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001, silent: bool = False):
3407
+ """
3408
+ Creates a rectangluar hollow section (RHS).
3409
+
3410
+ Parameters
3411
+ ----------
3412
+ origin : topologic_core.Vertex, optional
3413
+ The location of the origin of the RHS. The default is None which results in the RHS being placed at (0, 0, 0).
3414
+ width : float , optional
3415
+ The width of the RHS. The default is 1.0.
3416
+ length : float , optional
3417
+ The length of the RHS. The default is 1.0.
3418
+ thickness : float , optional
3419
+ The thickness of the RHS. The default is 0.25.
3420
+ outerFillet : float , optional
3421
+ The outer fillet multiplication factor based on the thickness (e.g. 1t). The default is 0.
3422
+ innerFillet : float , optional
3423
+ The inner fillet multiplication factor based on the thickness (e.g. 1.5t). The default is 0.
3424
+ sides : int , optional
3425
+ The desired number of sides of the fillets. The default is 16.
3426
+ direction : list , optional
3427
+ The vector representing the up direction of the RHS. The default is [0, 0, 1].
3428
+ placement : str , optional
3429
+ The description of the placement of the origin of the RHS. This can be "center", "lowerleft", "upperleft", "lowerright", "upperright". It is case insensitive. The default is "center".
3430
+ tolerance : float , optional
3431
+ The desired tolerance. The default is 0.0001.
3432
+ silent : bool , optional
3433
+ If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
3434
+
3435
+ Returns
3436
+ -------
3437
+ topologic_core.Face
3438
+ The created face.
3439
+
3440
+ """
3441
+ from topologicpy.Vertex import Vertex
3442
+ from topologicpy.Wire import Wire
3443
+ from topologicpy.Topology import Topology
3444
+
3445
+ if 2*thickness >= width:
3446
+ if not silent:
3447
+ print("Face.RHS - Error: Twice the thickness value is larger than or equal to the width value. Returning None.")
3448
+ return None
3449
+ if 2*thickness >= width:
3450
+ if not silent:
3451
+ print("Face.RHS - Error: Twice the thickness value is larger than or equal to the length value. Returning None.")
3452
+ return None
3453
+ outer_dimension = min(width, length)
3454
+ fillet_dimension = 2*outerFillet*thickness
3455
+ if fillet_dimension > outer_dimension:
3456
+ if not silent:
3457
+ print("Face.RHS = Error: The outer fillet radius input value is too large given the desired dimensions of the RHS. Returning None.")
3458
+ return None
3459
+ inner_dimension = min(width, length) - 2*thickness
3460
+ fillet_dimension = 2*innerFillet*thickness
3461
+ if fillet_dimension > inner_dimension:
3462
+ if not silent:
3463
+ print("Face.RHS = Error: The inner fillet radius input value is too large given the desired dimensions of the RHS. Returning None.")
3464
+ return None
3465
+ if origin == None:
3466
+ origin = Vertex.Origin()
3467
+
3468
+ outer_wire = Wire.Rectangle(origin=Vertex.Origin(), width=width, length=length, direction=[0,0,1], placement="center", tolerance=tolerance, silent=silent)
3469
+ inner_wire = Wire.Rectangle(origin=Vertex.Origin(), width=width-thickness*2, length=length-thickness*2, direction=[0,0,1], placement="center", tolerance=tolerance, silent=silent)
3470
+ if outerFillet > 0:
3471
+ outer_wire = Wire.Fillet(outer_wire, radius=outerFillet*thickness, sides=sides, silent=silent)
3472
+ if innerFillet > 0:
3473
+ inner_wire = Wire.Fillet(inner_wire, radius=innerFillet*thickness, sides=sides, silent=silent)
3474
+ return_face = Face.ByWires(outer_wire, [inner_wire], silent=silent)
3475
+ if not Topology.IsInstance(return_face, "face"):
3476
+ if not silent:
3477
+ print("Face.RHS - Error: Could not create the face for the RHS. Returning None.")
3478
+ return None
3479
+
3480
+ xOffset = 0
3481
+ yOffset = 0
3482
+ zOffset = 0
3483
+ if placement.lower() == "lowerleft":
3484
+ xOffset = width*0.5
3485
+ yOffset = length*0.5
3486
+ elif placement.lower() == "upperleft":
3487
+ xOffset = width*0.5
3488
+ yOffset = -length*0.5
3489
+ elif placement.lower() == "lowerright":
3490
+ xOffset = -width*0.5
3491
+ yOffset = length*0.5
3492
+ elif placement.lower() == "upperright":
3493
+ xOffset = -width*0.5
3494
+ yOffset = -length*0.5
3495
+ return_face = Topology.Translate(return_face, x=xOffset, y=yOffset, z=zOffset)
3496
+ return_face = Topology.Place(return_face, originA=Vertex.Origin(), originB=origin)
3497
+ if direction != [0, 0, 1]:
3498
+ return_face = Topology.Orient(return_face, origin=origin, dirA=[0, 0, 1], dirB=direction)
3499
+ return return_face
3500
+
3501
+ @staticmethod
3502
+ def Ring(origin= None, radius: float = 0.5, thickness: float = 0.25, sides: int = 16, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001, silent: bool = False):
3503
+ """
3504
+ Creates a circular ring. This is an alias method for creating a circular hollow section (CHS).
3505
+
3506
+ Parameters
3507
+ ----------
3508
+ origin : topologic_core.Vertex, optional
3509
+ The location of the origin of the ring. The default is None which results in the ring being placed at (0, 0, 0).
3510
+ radius : float , optional
3511
+ The outer radius of the ring. The default is 0.5.
3512
+ thickness : float , optional
3513
+ The thickness of the ring. The default is 0.25.
3514
+ direction : list , optional
3515
+ The vector representing the up direction of the ring. The default is [0, 0, 1].
3516
+ placement : str , optional
3517
+ The description of the placement of the origin of the ring. This can be "center", "lowerleft", "upperleft", "lowerright", "upperright". It is case insensitive. The default is "center".
3518
+ tolerance : float , optional
3519
+ The desired tolerance. The default is 0.0001.
3520
+ silent : bool , optional
3521
+ If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
3522
+
3523
+ Returns
3524
+ -------
3525
+ topologic_core.Face
3526
+ The created face.
3527
+
3528
+ """
3529
+
3530
+ if thickness >= radius:
3531
+ if not silent:
3532
+ print("Face.Ring - Error: The thickness value is larger than or equal to the outer radius value. Returning None.")
3533
+ return None
3534
+ return Face.CHS(origin=origin,
3535
+ radius=radius,
3536
+ thickness=thickness,
3537
+ sides=sides,
3538
+ direction=direction,
3539
+ placement=placement,
3540
+ tolerance=tolerance,
3541
+ silent=silent)
3542
+ @staticmethod
3543
+ def SHS(origin= None, size: float = 1.0, thickness: float = 0.25, outerFillet: float = 0.0, innerFillet: float = 0.0, sides: int = 16, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001, silent: bool = False):
3544
+ """
3545
+ Creates a square hollow section (SHS).
3546
+
3547
+ Parameters
3548
+ ----------
3549
+ origin : topologic_core.Vertex, optional
3550
+ The location of the origin of the SHS. The default is None which results in the SHS being placed at (0, 0, 0).
3551
+ size : float , optional
3552
+ The outer size of the SHS. The default is 1.0.
3553
+ thickness : float , optional
3554
+ The thickness of the SHS. The default is 0.25.
3555
+ outerFillet : float , optional
3556
+ The outer fillet multiplication factor based on the thickness (e.g. 1t). The default is 0.
3557
+ innerFillet : float , optional
3558
+ The inner fillet multiplication factor based on the thickness (e.g. 1.5t). The default is 0.
3559
+ sides : int , optional
3560
+ The desired number of sides of the fillets. The default is 16.
3561
+ direction : list , optional
3562
+ The vector representing the up direction of the SHS. The default is [0, 0, 1].
3563
+ placement : str , optional
3564
+ The description of the placement of the origin of the SHS. This can be "center", "lowerleft", "upperleft", "lowerright", "upperright". It is case insensitive. The default is "center".
3565
+ tolerance : float , optional
3566
+ The desired tolerance. The default is 0.0001.
3567
+ silent : bool , optional
3568
+ If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
3569
+
3570
+ Returns
3571
+ -------
3572
+ topologic_core.Face
3573
+ The created face.
3574
+
3575
+ """
3576
+ from topologicpy.Vertex import Vertex
3577
+ from topologicpy.Wire import Wire
3578
+ from topologicpy.Topology import Topology
3579
+
3580
+ if 2*thickness >= size:
3581
+ if not silent:
3582
+ print("Face.SHS - Error: Twice the thickness value is larger than or equal to the outer size value. Returning None.")
3583
+ return None
3584
+ fillet_dimension = 2*outerFillet*thickness
3585
+ if fillet_dimension > size:
3586
+ if not silent:
3587
+ print("Face.RHS = Error: The outer fillet radius input value is too large given the desired dimensions of the RHS. Returning None.")
3588
+ return None
3589
+ inner_dimension = size - 2*thickness
3590
+ fillet_dimension = 2*innerFillet*thickness
3591
+ if fillet_dimension > inner_dimension:
3592
+ if not silent:
3593
+ print("Face.RHS = Error: The inner fillet radius input value is too large given the desired dimensions of the RHS. Returning None.")
3594
+ return None
3595
+ if origin == None:
3596
+ origin = Vertex.Origin()
3597
+
3598
+ return Face.RHS(origin = origin, width = size, length = size, thickness = thickness, outerFillet = outerFillet, innerFillet = innerFillet, sides = sides, direction = direction, placement = placement, tolerance = tolerance, silent = silent)
3599
+
3335
3600
  @staticmethod
3336
3601
  def Simplify(face, tolerance=0.0001):
3337
3602
  """
topologicpy/Graph.py CHANGED
@@ -523,7 +523,7 @@ class Graph:
523
523
  _ = graph.AddVertices(vertices, tolerance) # Hook to Core
524
524
  return graph
525
525
 
526
- def AdjacencyDictionary(graph, vertexLabelKey: str = None, edgeKey: str = "Length", includeWeights: bool = False, reverse: bool = False, mantissa: int = 6):
526
+ def AdjacencyDictionary(graph, vertexLabelKey: str = None, edgeKey: str = "Length", includeWeights: bool = False, mantissa: int = 6):
527
527
  """
528
528
  Returns the adjacency dictionary of the input Graph.
529
529
 
@@ -537,9 +537,7 @@ class Graph:
537
537
  edgeKey : str , optional
538
538
  If set, the edges' dictionaries will be searched for this key to set their weight. If the key is set to "length" (case insensitive), the length of the edge will be used as its weight. If set to None, a weight of 1 will be used. The default is "Length".
539
539
  includeWeights : bool , optional
540
- If set to True, edge weights are included. Otherwise, they are not. The default is False.
541
- reverse : bool , optional
542
- If set to True, the vertices are sorted in reverse order (only if vertexKey is set). Otherwise, they are not. The default is False.
540
+ If set to True, edge weights are included. Otherwise, they are not. The default is False.
543
541
  mantissa : int , optional
544
542
  The desired length of the mantissa. The default is 6.
545
543
 
@@ -578,9 +576,6 @@ class Graph:
578
576
  labels.append(value)
579
577
  vertices = Helper.Sort(vertices, labels)
580
578
  labels.sort()
581
- if reverse == True:
582
- vertices.reverse()
583
- labels.reverse()
584
579
  order = len(vertices)
585
580
  adjDict = {}
586
581
  for i in range(order):
topologicpy/Helper.py CHANGED
@@ -286,6 +286,58 @@ class Helper:
286
286
  flat_list = flat_list + Helper.Flatten(item)
287
287
  return flat_list
288
288
 
289
+ @staticmethod
290
+ def Grow(seed_idx, group_size, adjacency, visited_global):
291
+ """
292
+ Attempts to grow a spatially connected group of a specified size starting from a given seed index.
293
+
294
+ This method uses a breadth-first search strategy to explore neighboring indices from the seed index,
295
+ guided by the provided adjacency dictionary. It avoids reusing indices that are globally visited.
296
+ The growth continues until the desired group size is reached or no further expansion is possible.
297
+
298
+ Parameters
299
+ ----------
300
+ seed_idx : int
301
+ The index from which to start growing the group.
302
+ group_size : int
303
+ The target size of the group to be grown.
304
+ adjacency : dict
305
+ A dictionary mapping each index to a list of adjacent indices. This defines the connectivity.
306
+ visited_global : set
307
+ A set of indices that have already been used in previously grown groups and should be avoided.
308
+
309
+ Returns
310
+ -------
311
+ list[int] or None
312
+ A list of indices representing a connected group of the specified size if successful, otherwise None.
313
+
314
+ Notes
315
+ -----
316
+ This method is intended for internal use in functions that generate connected subgroups
317
+ of spatial elements (e.g., cells) based on adjacency. The result may vary between runs due to random shuffling
318
+ of neighbor order to diversify outputs.
319
+ """
320
+ from collections import deque
321
+ import random
322
+
323
+ group = [seed_idx]
324
+ visited = set(group)
325
+ queue = deque([seed_idx])
326
+
327
+ while queue and len(group) < group_size:
328
+ current = queue.popleft()
329
+ neighbors = adjacency.get(current, [])
330
+ random.shuffle(neighbors)
331
+ for neighbor in neighbors:
332
+ if neighbor not in visited and neighbor not in visited_global:
333
+ group.append(neighbor)
334
+ visited.add(neighbor)
335
+ queue.append(neighbor)
336
+ if len(group) >= group_size:
337
+ break
338
+
339
+ return group if len(group) == group_size else None
340
+
289
341
  @staticmethod
290
342
  def Iterate(listA):
291
343
  """