topologicpy 0.8.90__py3-none-any.whl → 0.8.92__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/Cell.py CHANGED
@@ -1753,7 +1753,7 @@ class Cell():
1753
1753
  if placement.lower() == "bottom":
1754
1754
  egg = Topology.Translate(egg, 0, 0, height/2)
1755
1755
  elif placement.lower() == "lowerleft":
1756
- bb = Cell.BoundingBox(egg)
1756
+ bb = Topology.BoundingBox(egg)
1757
1757
  d = Topology.Dictionary(bb)
1758
1758
  width = Dictionary.ValueAtKey(d, 'width')
1759
1759
  length = Dictionary.ValueAtKey(d, 'length')
topologicpy/Graph.py CHANGED
@@ -22,6 +22,7 @@ import warnings
22
22
 
23
23
  from collections import namedtuple
24
24
  from multiprocessing import Process, Queue
25
+ from typing import Any
25
26
 
26
27
  try:
27
28
  import numpy as np
@@ -15540,7 +15541,16 @@ class Graph:
15540
15541
  return graph
15541
15542
 
15542
15543
  @staticmethod
15543
- def ShortestPath(graph, vertexA, vertexB, vertexKey="", edgeKey="Length", tolerance=0.0001):
15544
+ def ShortestPath(graph,
15545
+ vertexA,
15546
+ vertexB,
15547
+ vertexKey: str = "",
15548
+ edgeKey: str = "Length",
15549
+ transferDictionaries: bool = False,
15550
+ straighten: bool = False,
15551
+ face: Any = None,
15552
+ tolerance: float = 0.0001,
15553
+ silent: bool = False):
15544
15554
  """
15545
15555
  Returns the shortest path that connects the input vertices. The shortest path will take into consideration both the vertexKey and the edgeKey if both are specified and will minimize the total "cost" of the path. Otherwise, it will take into consideration only whatever key is specified.
15546
15556
 
@@ -15556,8 +15566,19 @@ class Graph:
15556
15566
  The vertex key to minimise. If set the vertices dictionaries will be searched for this key and the associated value will be used to compute the shortest path that minimized the total value. The value must be numeric. Default is None.
15557
15567
  edgeKey : string , optional
15558
15568
  The edge key to minimise. If set the edges dictionaries will be searched for this key and the associated value will be used to compute the shortest path that minimized the total value. The value of the key must be numeric. If set to "length" (case insensitive), the shortest path by length is computed. Default is "length".
15569
+ transferDictionaries : bool , optional
15570
+ If set to True, the dictionaries from the graph vertices will be transferred to the vertices of the shortest path. Otherwise, they won't. Default is False.
15571
+ Note: Edge dictionaries are not transferred (In straightened paths, the path edges are no longer the same as
15572
+ the original graph edges. Thus, you must implement your own logic to transfer edge dictionaries if needed).
15573
+ straighten : bool , optional
15574
+ If set to True, the path will be straightened as much as possible while remaining inside the specified face.
15575
+ Thus, the face input must be a valid topologic Face that is planar and residing on the XY plane. Default is False.
15576
+ face : topologic_core.Face , optional
15577
+ The face on which the path resides. This is used for straightening the path. Default is None.
15559
15578
  tolerance : float , optional
15560
15579
  The desired tolerance. Default is 0.0001.
15580
+ silent : bool , optional
15581
+ If set to True, error and warning messages are suppressed. Default is False.
15561
15582
 
15562
15583
  Returns
15563
15584
  -------
@@ -15570,14 +15591,22 @@ class Graph:
15570
15591
  from topologicpy.Topology import Topology
15571
15592
 
15572
15593
  if not Topology.IsInstance(graph, "Graph"):
15573
- print("Graph.ShortestPath - Error: The input graph is not a valid graph. Returning None.")
15594
+ if not silent:
15595
+ print("Graph.ShortestPath - Error: The input graph is not a valid graph. Returning None.")
15574
15596
  return None
15575
15597
  if not Topology.IsInstance(vertexA, "Vertex"):
15576
- print("Graph.ShortestPath - Error: The input vertexA is not a valid vertex. Returning None.")
15598
+ if not silent:
15599
+ print("Graph.ShortestPath - Error: The input vertexA is not a valid vertex. Returning None.")
15577
15600
  return None
15578
15601
  if not Topology.IsInstance(vertexB, "Vertex"):
15579
- print("Graph.ShortestPath - Error: The input vertexB is not a valid vertex. Returning None.")
15602
+ if not silent:
15603
+ print("Graph.ShortestPath - Error: The input vertexB is not a valid vertex. Returning None.")
15580
15604
  return None
15605
+ if straighten == True:
15606
+ if not Topology.IsInstance(face, "face"):
15607
+ if not silent:
15608
+ print("Graph.ShortestPath - Error: Straighten is set to True, but the face parameter is not a valid toopologic face. Returning None.")
15609
+ return None
15581
15610
  if edgeKey:
15582
15611
  if edgeKey.lower() == "length":
15583
15612
  edgeKey = "Length"
@@ -15593,74 +15622,18 @@ class Graph:
15593
15622
  if Topology.IsInstance(shortest_path, "Wire"):
15594
15623
  shortest_path = Wire.Reverse(shortest_path)
15595
15624
  shortest_path = Wire.OrientEdges(shortest_path, Wire.StartVertex(shortest_path), tolerance=tolerance)
15625
+ if Topology.IsInstance(shortest_path, "wire"):
15626
+ if straighten == True and Topology.IsInstance(face, "face"):
15627
+ shortest_path = Wire.StraightenInFace(shortest_path, face)
15628
+ if transferDictionaries == True:
15629
+ path_verts = Topology.Vertices(shortest_path)
15630
+ for p_v in path_verts:
15631
+ g_v = Graph.NearestVertex(graph, p_v)
15632
+ p_v = Topology.SetDictionary(p_v, Topology.Dictionary(g_v))
15596
15633
  return shortest_path
15597
15634
  except:
15598
15635
  return None
15599
15636
 
15600
- @staticmethod
15601
- def shortestPathInFace(graph, face, vertexA, vertexB, mode: int = 0, meshSize: float = None, tolerance: float = 0.0001, silent: bool = False):
15602
- """
15603
- Returns the shortest path that connects the input vertices.
15604
-
15605
- Parameters
15606
- ----------
15607
- face : topologic_core.Face
15608
- The input face. This is assumed to be planar and resting on the XY plane (z = 0)
15609
- vertexA : topologic_core.Vertex
15610
- The first input vertex.
15611
- vertexB : topologic_core.Vertex
15612
- The second input vertex.
15613
- mode : int , optional
15614
- The desired mode of meshing algorithm. Several options are available:
15615
- 0: Classic
15616
- 1: MeshAdapt
15617
- 3: Initial Mesh Only
15618
- 5: Delaunay
15619
- 6: Frontal-Delaunay
15620
- 7: BAMG
15621
- 8: Fontal-Delaunay for Quads
15622
- 9: Packing of Parallelograms
15623
- All options other than 0 (Classic) use the gmsh library. See https://gmsh.info/doc/texinfo/gmsh.html#Mesh-options
15624
- WARNING: The options that use gmsh can be very time consuming and can create very heavy geometry.
15625
- meshSize : float , optional
15626
- The desired size of the mesh when using the "mesh" option. If set to None, it will be
15627
- calculated automatically and set to 10% of the overall size of the face.
15628
- tolerance : float , optional
15629
- The desired tolerance. Default is 0.0001.
15630
- silent : bool , optional
15631
- If set to True, error and warning messages are suppressed. Default is False.
15632
-
15633
- Returns
15634
- -------
15635
- topologic_core.Wire
15636
- The shortest path between the input vertices.
15637
-
15638
- """
15639
- from topologicpy.Wire import Wire
15640
- from topologicpy.Topology import Topology
15641
-
15642
- if not Topology.IsInstance(face, "face"):
15643
- if not silent:
15644
- print("Face.ShortestPath - Error: The input face parameter is not a topologic face. Returning None.")
15645
- return None
15646
- if not Topology.IsInstance(vertexA, "vertex"):
15647
- if not silent:
15648
- print("Face.ShortestPath - Error: The input vertexA parameter is not a topologic vertex. Returning None.")
15649
- return None
15650
- if not Topology.IsInstance(vertexB, "vertex"):
15651
- if not silent:
15652
- print("Face.ShortestPath - Error: The input vertexB parameter is not a topologic vertex. Returning None.")
15653
- return None
15654
-
15655
- sp = Graph.ShortestPath(graph, vertexA, vertexB)
15656
- if sp == None:
15657
- if not silent:
15658
- print("Face.ShortestPath - Error: Could not find the shortest path. Returning None.")
15659
- return None
15660
-
15661
- new_path = Wire.StraightenInFace(sp, face, tolerance = tolerance)
15662
- return new_path
15663
-
15664
15637
  @staticmethod
15665
15638
  def ShortestPaths(graph, vertexA, vertexB, vertexKey="", edgeKey="length", timeLimit=10,
15666
15639
  pathLimit=10, tolerance=0.0001):
topologicpy/Topology.py CHANGED
@@ -11935,13 +11935,13 @@ class Topology():
11935
11935
  final_str = verts_str+edges_str+dict_str
11936
11936
  uuid_str = uuid.uuid5(namespace_uuid, final_str)
11937
11937
  else:
11938
- cellComplexes = Topology.CellComplexes(topology)
11939
- cells = Topology.Cells(topology)
11940
- shells = Topology.Shells(topology)
11941
- faces = Topology.Faces(topology)
11942
- wires = Topology.Wires(topology)
11943
- edges = Topology.Edges(topology)
11944
- vertices = Topology.Vertices(topology)
11938
+ cellComplexes = Topology.CellComplexes(topology, silent=True)
11939
+ cells = Topology.Cells(topology, silent=True)
11940
+ shells = Topology.Shells(topology, silent=True)
11941
+ faces = Topology.Faces(topology, silent=True)
11942
+ wires = Topology.Wires(topology, silent=True)
11943
+ edges = Topology.Edges(topology, silent=True)
11944
+ vertices = Topology.Vertices(topology, silent=True)
11945
11945
  apertures = Topology.Apertures(topology, subTopologyType="all")
11946
11946
  subTopologies = cellComplexes+cells+shells+faces+wires+edges+vertices+apertures
11947
11947
  dictionaries = [Dictionary.PythonDictionary(Topology.Dictionary(topology))]
topologicpy/Wire.py CHANGED
@@ -946,6 +946,168 @@ class Wire():
946
946
  vertices = Topology.Vertices(cluster)
947
947
  return Wire.ByVertices(vertices, close=close, tolerance=tolerance, silent=silent)
948
948
 
949
+
950
+ @staticmethod
951
+ def Cage(origin=None,
952
+ width: float = 1.0, length: float = 1.0, height: float = 1.0,
953
+ uSides: int = 2, vSides: int = 2, wSides: int = 2,
954
+ direction: list = [0, 0, 1], placement: str = "center",
955
+ mantissa: int = 6, tolerance: float = 0.0001):
956
+ """
957
+ Creates a prismatic 3D cage as a Wire, with edges only on the outer
958
+ surfaces of the volume (no interior lines).
959
+
960
+ Parameters
961
+ ----------
962
+ origin : topologic_core.Vertex , optional
963
+ The placement origin of the cage:
964
+ - If placement == "center": the geometric center of the cage
965
+ is placed at this origin.
966
+ - If placement == "corner": the minimum corner of the cage
967
+ is placed at this origin.
968
+ If None, the cage is created around (0, 0, 0) accordingly.
969
+ width : float , optional
970
+ The size of the cage in the local X direction. Default is 1.0.
971
+ length : float , optional
972
+ The size of the cage in the local Y direction. Default is 1.0.
973
+ height : float , optional
974
+ The size of the cage in the local Z direction. Default is 1.0.
975
+ uSides : int , optional
976
+ The number of subdivisions in the local X direction. Must be >= 1.
977
+ Default is 2.
978
+ vSides : int , optional
979
+ The number of subdivisions in the local Y direction. Must be >= 1.
980
+ Default is 2.
981
+ wSides : int , optional
982
+ The number of subdivisions in the local Z direction. Must be >= 1.
983
+ Default is 2.
984
+ direction : list , optional
985
+ The vector representing the up direction of the lattice. Default is [0, 0, 1].
986
+ placement : str , optional
987
+ The description of the placement of the origin of the lattice. This can be "bottom", "center", or "lowerleft". It is case insensitive. Default is "center".
988
+ mantissa : int , optional
989
+ The number of decimal places to round the result to. Default is 6.
990
+ tolerance : float , optional
991
+ The desired tolerance. Default is 0.0001.
992
+
993
+ Returns
994
+ -------
995
+ topologic_core.Wire or None
996
+ The resulting cage Wire, or None if inputs are invalid.
997
+ """
998
+ from topologicpy.Vertex import Vertex
999
+ from topologicpy.Edge import Edge
1000
+ from topologicpy.Wire import Wire
1001
+ from topologicpy.Topology import Topology
1002
+ from topologicpy.Vector import Vector
1003
+ import math
1004
+
1005
+ # -------------------------
1006
+ # Validation
1007
+ # -------------------------
1008
+ if uSides < 1 or vSides < 1 or wSides < 1:
1009
+ print("Wire.Cage - Error: uSides, vSides, and wSides must be >= 1. Returning None.")
1010
+ return None
1011
+
1012
+ if origin is None:
1013
+ origin = Vertex.ByCoordinates(0, 0, 0)
1014
+
1015
+ # Local origin at (0,0,0) for construction and rotation
1016
+ local_origin = Vertex.ByCoordinates(0, 0, 0)
1017
+
1018
+ # -------------------------
1019
+ # Local Placement Offsets
1020
+ # -------------------------
1021
+ # We construct the cage in a local coordinate system.
1022
+ if str(placement).lower() == "center":
1023
+ ox = -width * 0.5
1024
+ oy = -length * 0.5
1025
+ oz = -height * 0.5
1026
+ elif str(placement).lower() == "bottom":
1027
+ ox = -width * 0.5
1028
+ oy = -length * 0.5
1029
+ oz = 0
1030
+ else: # "lowerleft"
1031
+ ox = 0.0
1032
+ oy = 0.0
1033
+ oz = 0.0
1034
+
1035
+ # -------------------------
1036
+ # Step Sizes
1037
+ # -------------------------
1038
+ du = width / uSides
1039
+ dv = length / vSides
1040
+ dw = height / wSides
1041
+
1042
+ # -------------------------
1043
+ # Grid Coordinates (local)
1044
+ # -------------------------
1045
+ xs = [round(ox + i * du, mantissa) for i in range(uSides + 1)]
1046
+ ys = [round(oy + j * dv, mantissa) for j in range(vSides + 1)]
1047
+ zs = [round(oz + k * dw, mantissa) for k in range(wSides + 1)]
1048
+
1049
+ edges = []
1050
+
1051
+ # ------------------------------------------------------------------
1052
+ # X-direction edges on boundary surfaces (y,z)
1053
+ # Edge from (x_min, y_j, z_k) to (x_max, y_j, z_k)
1054
+ # Only if j is boundary OR k is boundary → lies on outer surface.
1055
+ # ------------------------------------------------------------------
1056
+ for j in range(vSides + 1):
1057
+ for k in range(wSides + 1):
1058
+ if j in (0, vSides) or k in (0, wSides):
1059
+ y = ys[j]
1060
+ z = zs[k]
1061
+ v0 = Vertex.ByCoordinates(xs[0], y, z)
1062
+ v1 = Vertex.ByCoordinates(xs[-1], y, z)
1063
+ edges.append(Edge.ByVertices(v0, v1))
1064
+
1065
+ # ------------------------------------------------------------------
1066
+ # Y-direction edges on boundary surfaces (x,z)
1067
+ # Edge from (x_i, y_min, z_k) to (x_i, y_max, z_k)
1068
+ # Only if i is boundary OR k is boundary.
1069
+ # ------------------------------------------------------------------
1070
+ for i in range(uSides + 1):
1071
+ for k in range(wSides + 1):
1072
+ if i in (0, uSides) or k in (0, wSides):
1073
+ x = xs[i]
1074
+ z = zs[k]
1075
+ v0 = Vertex.ByCoordinates(x, ys[0], z)
1076
+ v1 = Vertex.ByCoordinates(x, ys[-1], z)
1077
+ edges.append(Edge.ByVertices(v0, v1))
1078
+
1079
+ # ------------------------------------------------------------------
1080
+ # Z-direction edges on boundary surfaces (x,y)
1081
+ # Edge from (x_i, y_j, z_min) to (x_i, y_j, z_max)
1082
+ # Only if i is boundary OR j is boundary.
1083
+ # ------------------------------------------------------------------
1084
+ for i in range(uSides + 1):
1085
+ for j in range(vSides + 1):
1086
+ if i in (0, uSides) or j in (0, vSides):
1087
+ x = xs[i]
1088
+ y = ys[j]
1089
+ v0 = Vertex.ByCoordinates(x, y, zs[0])
1090
+ v1 = Vertex.ByCoordinates(x, y, zs[-1])
1091
+ edges.append(Edge.ByVertices(v0, v1))
1092
+
1093
+ # -------------------------
1094
+ # Build Wire in Local Space
1095
+ # -------------------------
1096
+ if not edges:
1097
+ print("Wire.Cage - Warning: No edges created. Returning None.")
1098
+ return None
1099
+
1100
+ cage = Wire.ByEdges(edges)
1101
+
1102
+ # -------------------------
1103
+ # Orient and Place
1104
+ # -------------------------
1105
+ cage = Topology.Orient(cage, origin=Vertex.Origin(), dirA=[0, 0, 1], dirB=direction)
1106
+ cage = Topology.Place(cage, originA=Vertex.Origin(), originB=origin)
1107
+
1108
+ return cage
1109
+
1110
+
949
1111
  @staticmethod
950
1112
  def Circle(origin= None, radius: float = 0.5, sides: int = 16, fromAngle: float = 0.0, toAngle: float = 360.0, close: bool = True, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001, silent: bool = False):
951
1113
  """
@@ -3199,6 +3361,124 @@ class Wire():
3199
3361
  i_shape = Topology.Orient(i_shape, origin=origin, dirA=[0, 0, 1], dirB=direction)
3200
3362
  return i_shape
3201
3363
 
3364
+
3365
+
3366
+ @staticmethod
3367
+ def Lattice(origin=None,
3368
+ width: float = 1.0, length: float = 1.0, height: float = 1.0,
3369
+ uSides: int = 2, vSides: int = 2, wSides: int = 2,
3370
+ direction: list = [0, 0, 1], placement: str = "center",
3371
+ mantissa: int = 6, tolerance: float = 0.0001):
3372
+ """
3373
+ Creates a prismatic 3D lattice as a Wire.
3374
+
3375
+ Parameters
3376
+ ----------
3377
+ origin : topologic_core.Vertex , optional
3378
+ Placement origin.
3379
+ width, length, height : float
3380
+ Lattice extents.
3381
+ uSides, vSides, wSides : int
3382
+ Divisions along X, Y, Z.
3383
+ direction : list , optional
3384
+ The vector representing the up direction of the lattice. Default is [0, 0, 1].
3385
+ placement : str , optional
3386
+ The description of the placement of the origin of the lattice. This can be "bottom", "center", or "lowerleft". It is case insensitive. Default is "center".
3387
+ mantissa : int , optional
3388
+ The number of decimal places to round the result to. Default is 6.
3389
+ tolerance : float , optional
3390
+ The desired tolerance. Default is 0.0001.
3391
+
3392
+ Returns
3393
+ -------
3394
+ topologic_core.Wire
3395
+ """
3396
+
3397
+ from topologicpy.Vertex import Vertex
3398
+ from topologicpy.Edge import Edge
3399
+ from topologicpy.Wire import Wire
3400
+ from topologicpy.Topology import Topology
3401
+ from topologicpy.Vector import Vector
3402
+ import math
3403
+
3404
+ # -------------------------
3405
+ # Validation
3406
+ # -------------------------
3407
+ if uSides < 1 or vSides < 1 or wSides < 1:
3408
+ return None
3409
+
3410
+ if origin is None:
3411
+ origin = Vertex.ByCoordinates(0, 0, 0)
3412
+
3413
+ # -------------------------
3414
+ # Placement Offsets
3415
+ # -------------------------
3416
+ if placement.lower() == "center":
3417
+ ox = -width * 0.5
3418
+ oy = -length * 0.5
3419
+ oz = -height * 0.5
3420
+ elif placement.lower() == "bottom":
3421
+ ox = -width * 0.5
3422
+ oy = -length * 0.5
3423
+ oz = 0
3424
+ else:
3425
+ ox = oy = oz = 0.0
3426
+
3427
+ # -------------------------
3428
+ # Step Sizes
3429
+ # -------------------------
3430
+ du = width / uSides
3431
+ dv = length / vSides
3432
+ dw = height / wSides
3433
+
3434
+ # -------------------------
3435
+ # Precompute Grid Coordinates
3436
+ # -------------------------
3437
+ xs = [round(ox + i * du, mantissa) for i in range(uSides + 1)]
3438
+ ys = [round(oy + j * dv, mantissa) for j in range(vSides + 1)]
3439
+ zs = [round(oz + k * dw, mantissa) for k in range(wSides + 1)]
3440
+
3441
+ edges = []
3442
+
3443
+ # -------------------------
3444
+ # X-Direction Lines
3445
+ # -------------------------
3446
+ for y in ys:
3447
+ for z in zs:
3448
+ v0 = Vertex.ByCoordinates(xs[0], y, z)
3449
+ v1 = Vertex.ByCoordinates(xs[-1], y, z)
3450
+ edges.append(Edge.ByVertices(v0, v1))
3451
+
3452
+ # -------------------------
3453
+ # Y-Direction Lines
3454
+ # -------------------------
3455
+ for x in xs:
3456
+ for z in zs:
3457
+ v0 = Vertex.ByCoordinates(x, ys[0], z)
3458
+ v1 = Vertex.ByCoordinates(x, ys[-1], z)
3459
+ edges.append(Edge.ByVertices(v0, v1))
3460
+
3461
+ # -------------------------
3462
+ # Z-Direction Lines
3463
+ # -------------------------
3464
+ for x in xs:
3465
+ for y in ys:
3466
+ v0 = Vertex.ByCoordinates(x, y, zs[0])
3467
+ v1 = Vertex.ByCoordinates(x, y, zs[-1])
3468
+ edges.append(Edge.ByVertices(v0, v1))
3469
+
3470
+ # -------------------------
3471
+ # Build Wire
3472
+ # -------------------------
3473
+ lattice = Wire.ByEdges(edges)
3474
+
3475
+ # -------------------------
3476
+ # Orient and Place
3477
+ # -------------------------
3478
+ lattice = Topology.Orient(lattice, origin=Vertex.Origin(), dirA=[0, 0, 1], dirB=direction)
3479
+ lattice = Topology.Place(lattice, originA=Vertex.Origin(), originB=origin)
3480
+ return lattice
3481
+
3202
3482
  @staticmethod
3203
3483
  def Length(wire, mantissa: int = 6) -> float:
3204
3484
  """
@@ -4964,34 +5244,32 @@ class Wire():
4964
5244
  return sv
4965
5245
 
4966
5246
  @staticmethod
4967
- def StraightenInFace(wire, face, tolerance: float = 0.0001):
5247
+ def Straighten(wire, host, obstacles: list = None, portals: list = None,
5248
+ tolerance: float = 0.0001, silent: bool = False):
4968
5249
  """
4969
5250
  Returns a new Wire obtained by recursively replacing segments of the
4970
- input wire with the longest possible straight edge that is fully
4971
- embedded in the given face.
4972
-
4973
- For each starting vertex v_i along the wire, this method searches for
4974
- the furthest vertex v_j (j > i) such that the straight Edge between
4975
- v_i and v_j satisfies:
4976
-
4977
- Topology.Difference(edge, face) == None
4978
-
4979
- i.e. the edge lies completely within (or on the boundary of) the face.
4980
- All edges of the original wire between vertex indices i and j are then
4981
- replaced by this straight edge, and the process is repeated recursively
4982
- from index j.
5251
+ input wire with the longest possible straight edge that:
5252
+ 1. Is fully embedded in the given host.
5253
+ 2. Avoids intersection with an optional list of obstacle topologies.
5254
+ 3. Continues to pass through (intersects) an optional list of portal
5255
+ topologies that the original input wire intersects.
4983
5256
 
4984
5257
  Parameters
4985
5258
  ----------
4986
5259
  wire : topologic_core.Wire
4987
5260
  The input path wire whose vertices define the route to be
4988
5261
  straightened.
4989
- face : topologic_core.Face
4990
- The face within which the straightened edges must lie.
5262
+ host : topologic_core.Topology
5263
+ The host within which the straightened edges must lie.
5264
+ obstacles : list, optional
5265
+ The list of topologies with which the straightened edges must not intersect.
5266
+ portals : list, optional
5267
+ The list of topologies with which the straightened edges must intersect.
5268
+ Portals with which the original wire does NOT intersect are ignored.
4991
5269
  tolerance : float , optional
4992
- Numerical tolerance used for internal robustness checks. The
4993
- Topology.Difference call itself is left with its default tolerance.
4994
- Default is 1e-6.
5270
+ The desired tolerance. Default is 0.0001.
5271
+ silent : bool , optional
5272
+ If set to True, error and warning messages are suppressed. Default is False.
4995
5273
 
4996
5274
  Returns
4997
5275
  -------
@@ -5001,8 +5279,45 @@ class Wire():
5001
5279
  from topologicpy.Vertex import Vertex
5002
5280
  from topologicpy.Edge import Edge
5003
5281
  from topologicpy.Wire import Wire
5004
- from topologicpy.Face import Face
5282
+ from topologicpy.Cluster import Cluster
5005
5283
  from topologicpy.Topology import Topology
5284
+
5285
+ # Defensive defaults
5286
+ if obstacles is None:
5287
+ obstacles = []
5288
+ if portals is None:
5289
+ portals = []
5290
+
5291
+ # ----------------------------------------------------------------------
5292
+ # Basic validation
5293
+ # ----------------------------------------------------------------------
5294
+ if not Topology.IsInstance(wire, "Wire"):
5295
+ if not silent:
5296
+ print("Wire.Straighten - Error: The input wire parameter is not a valid Wire. Returning None.")
5297
+ return None
5298
+
5299
+ if not Topology.IsInstance(host, "Topology"):
5300
+ if not silent:
5301
+ print("Wire.Straighten - Error: The input host parameter is not a valid Topology. Returning None.")
5302
+ return None
5303
+
5304
+ if not isinstance(portals, list):
5305
+ if not silent:
5306
+ print("Wire.Straighten - Error: The input portals parameter is not a valid list. Returning None.")
5307
+ return None
5308
+
5309
+ if not isinstance(obstacles, list):
5310
+ if not silent:
5311
+ print("Wire.Straighten - Error: The input obstacles parameter is not a valid list. Returning None.")
5312
+ return None
5313
+
5314
+ # Filter valid obstacles and portals
5315
+ obstacle_list = [o for o in obstacles if Topology.IsInstance(o, "Topology")]
5316
+ portal_list = [p for p in portals if Topology.IsInstance(p, "Topology")]
5317
+
5318
+ # Make a cluster of the obstacles (if any)
5319
+ ob_cluster = Cluster.ByTopologies(obstacle_list) if obstacle_list else None
5320
+
5006
5321
  # Get ordered vertices of the wire
5007
5322
  vertices = Topology.Vertices(wire)
5008
5323
  n = len(vertices)
@@ -5011,75 +5326,249 @@ class Wire():
5011
5326
  # Nothing to straighten
5012
5327
  return wire
5013
5328
 
5014
- def _edge_inside_face(v_start, v_end):
5329
+ # ----------------------------------------------------------------------
5330
+ # Helper: check if a straight edge between two vertices is valid
5331
+ # ----------------------------------------------------------------------
5332
+ def _edge_is_valid(v_start, v_end):
5015
5333
  """
5016
5334
  Returns True if the straight edge between v_start and v_end is
5017
- fully embedded in the face, i.e. Topology.Difference(edge, face)
5018
- returns None.
5335
+ fully embedded in the host and does not intersect the obstacles.
5019
5336
  """
5020
- if v_start is v_end:
5337
+ # Avoid constructing degenerate edges
5338
+ if Topology.IsSame(v_start, v_end):
5021
5339
  return True
5022
- edge = Edge.ByStartVertexEndVertex(v_start, v_end)
5023
- diff = Topology.Difference(edge, face)
5024
- return diff is None
5025
5340
 
5026
- def _find_longest_valid_index(start_idx):
5027
- """
5028
- For a fixed start_idx, search for the largest index j >= start_idx+1
5029
- such that the direct edge (vertices[start_idx], vertices[j]) is
5030
- fully inside the face.
5341
+ edge = Edge.ByStartVertexEndVertex(v_start, v_end, tolerance=tolerance)
5342
+ if not Topology.IsInstance(edge, "Edge"):
5343
+ return False
5344
+
5345
+ diff = Topology.Difference(edge, host)
5346
+ if diff is not None:
5347
+ # Part of the edge lies outside the host
5348
+ return False
5349
+
5350
+ if ob_cluster is not None:
5351
+ inter = Topology.Intersect(edge, ob_cluster)
5352
+ if inter is not None:
5353
+ # Edge hits an obstacle
5354
+ return False
5031
5355
 
5032
- If for any reason no such j exists (which should not happen if the
5033
- original wire lies in the face), it falls back to start_idx + 1.
5356
+ return True
5357
+
5358
+ # ----------------------------------------------------------------------
5359
+ # Helper: for a fixed start index, find the furthest valid vertex index
5360
+ # ----------------------------------------------------------------------
5361
+ def _find_longest_valid_index(start_idx, local_vertices):
5362
+ """
5363
+ Given a list of vertices local_vertices (a sub-path),
5364
+ for a fixed start_idx, search for the largest index j >= start_idx+1
5365
+ such that the direct edge (local_vertices[start_idx], local_vertices[j])
5366
+ is valid.
5034
5367
  """
5035
- v_start = vertices[start_idx]
5368
+ m = len(local_vertices)
5369
+ v_start = local_vertices[start_idx]
5036
5370
  best_j = None
5037
5371
 
5038
- for j in range(start_idx + 1, n):
5039
- v_end = vertices[j]
5040
- if _edge_inside_face(v_start, v_end):
5372
+ for j in range(start_idx + 1, m):
5373
+ v_end = local_vertices[j]
5374
+ if _edge_is_valid(v_start, v_end):
5041
5375
  best_j = j
5042
- # Do NOT break on failure: a further vertex might still
5043
- # be reachable by a straight edge that stays in the face.
5376
+ # Do NOT break on failure: a further vertex might still be valid.
5044
5377
 
5045
5378
  if best_j is None:
5046
5379
  # Fallback: use the immediate next vertex to avoid stalling
5047
- best_j = min(start_idx + 1, n - 1)
5380
+ best_j = min(start_idx + 1, m - 1)
5048
5381
 
5049
5382
  return best_j
5050
5383
 
5051
- def _straighten_recursive(start_idx, out_vertices):
5384
+ # ----------------------------------------------------------------------
5385
+ # Helper: straighten a list of vertices (single segment, no portals)
5386
+ # ----------------------------------------------------------------------
5387
+ def _straighten_vertices(local_vertices):
5052
5388
  """
5053
- Recursive helper.
5389
+ Straightens a simple path defined by local_vertices (no portal constraints).
5390
+ Returns a new list of vertices.
5391
+ """
5392
+ m = len(local_vertices)
5393
+ if m <= 2:
5394
+ return local_vertices[:]
5395
+
5396
+ out_vertices = []
5397
+ idx = 0
5398
+ while idx < m - 1:
5399
+ out_vertices.append(local_vertices[idx])
5400
+ idx = _find_longest_valid_index(idx, local_vertices)
5401
+
5402
+ # Ensure the last vertex is present
5403
+ if not Topology.IsSame(out_vertices[-1], local_vertices[-1]):
5404
+ out_vertices.append(local_vertices[-1])
5405
+
5406
+ return out_vertices
5407
+
5408
+ # ----------------------------------------------------------------------
5409
+ # Portal support
5410
+ # ----------------------------------------------------------------------
5411
+ def _portal_cuts():
5412
+ """
5413
+ Returns a sorted list of (u, v_on_wire) where:
5414
+ - u is the parameter along the wire in [0, 1]
5415
+ - v_on_wire is a vertex on the wire at the same location
5054
5416
 
5055
- Appends the chosen vertices to out_vertices. At each step, it
5056
- decides how far it can jump from start_idx with a single straight
5057
- edge inside the face, then recurses from that new index.
5417
+ Only portals that actually intersect the original wire are considered.
5058
5418
  """
5059
- # Base case: we are at the last vertex
5060
- if start_idx == n - 1:
5061
- out_vertices.append(vertices[start_idx])
5062
- return
5419
+ cuts = []
5063
5420
 
5064
- # Find furthest valid index reachable from start_idx
5065
- next_idx = _find_longest_valid_index(start_idx)
5421
+ if not portal_list:
5422
+ return cuts
5066
5423
 
5067
- # Add the starting vertex for this segment
5068
- out_vertices.append(vertices[start_idx])
5424
+ for portal in portal_list:
5425
+ inter = Topology.Intersect(wire, portal)
5426
+ if not Topology.IsInstance(inter, "Topology"):
5427
+ # This portal does not intersect the wire, ignore it
5428
+ continue
5069
5429
 
5070
- # Recurse from the chosen furthest index
5071
- _straighten_recursive(next_idx, out_vertices)
5430
+ centroid = Topology.Centroid(inter)
5431
+ if not Topology.IsInstance(centroid, "Vertex"):
5432
+ continue
5072
5433
 
5073
- # Run the recursion
5074
- new_vertices = []
5075
- _straighten_recursive(0, new_vertices)
5434
+ # First try parameter at centroid directly
5435
+ u_target = Wire.ParameterAtVertex(wire, centroid, silent=True)
5436
+
5437
+ if u_target is not None:
5438
+ v_on_wire = centroid
5439
+ else:
5440
+ # Fall back to the closest point on the wire
5441
+ shortest_edge = Topology.ShortestEdge(centroid, wire, silent=True)
5442
+ if not Topology.IsInstance(shortest_edge, "Edge"):
5443
+ # Can't locate a good cut point for this portal
5444
+ continue
5445
+ v_on_wire = Edge.EndVertex(shortest_edge)
5446
+ if not Topology.IsInstance(v_on_wire, "Vertex"):
5447
+ continue
5448
+ u_target = Wire.ParameterAtVertex(wire, v_on_wire, silent=True)
5449
+
5450
+ # If still None, skip this portal
5451
+ if u_target is None:
5452
+ continue
5453
+
5454
+ # Keep u in [0,1], ignoring exact endpoints
5455
+ if 0.0 < u_target < 1.0:
5456
+ cuts.append((u_target, v_on_wire))
5457
+
5458
+ # Sort by parameter, ensure uniqueness
5459
+ cuts = sorted(cuts, key=lambda x: x[0])
5460
+ unique_cuts = []
5461
+ last_u = None
5462
+ for u, v in cuts:
5463
+ if last_u is None or abs(u - last_u) > tolerance:
5464
+ unique_cuts.append((u, v))
5465
+ last_u = u
5466
+
5467
+ return unique_cuts
5468
+
5469
+ def _subdivide_by_portals():
5470
+ """
5471
+ Splits the original wire into sub-wires between portal cuts.
5472
+ Each sub-wire is a wire segment between:
5473
+ start -> first portal,
5474
+ portal i -> portal i+1,
5475
+ last portal -> end.
5476
+ """
5477
+ cuts = _portal_cuts()
5478
+ if not cuts:
5479
+ return [wire] # No usable portal intersections
5480
+
5481
+ # Extract only parameters, append 0.0 and 1.0 for full coverage
5482
+ params = [u for (u, _) in cuts]
5483
+ params = [0.0] + params + [1.0]
5076
5484
 
5077
- # In case of any numerical quirks, ensure the last original vertex is present
5078
- if new_vertices[-1] is not vertices[-1]:
5079
- new_vertices.append(vertices[-1])
5485
+ verts_orig = Topology.Vertices(wire)
5486
+ sub_wires = []
5080
5487
 
5081
- # Build the new straightened wire
5082
- return Wire.ByVertices(new_vertices, close=False)
5488
+ for a, b in zip(params[:-1], params[1:]):
5489
+ if b - a <= tolerance:
5490
+ continue # Degenerate segment
5491
+
5492
+ # Build the vertex list for this segment
5493
+ seg_vertices = []
5494
+
5495
+ # Start vertex at parameter a
5496
+ v_a = Wire.VertexByParameter(wire, a)
5497
+ if Topology.IsInstance(v_a, "Vertex"):
5498
+ seg_vertices.append(v_a)
5499
+
5500
+ # Intermediate original vertices whose parameter lies between a and b
5501
+ for v in verts_orig:
5502
+ u = Wire.ParameterAtVertex(wire, v, silent=True)
5503
+ if u is None:
5504
+ continue
5505
+ if a < u < b:
5506
+ seg_vertices.append(v)
5507
+
5508
+ # End vertex at parameter b
5509
+ v_b = Wire.VertexByParameter(wire, b)
5510
+ if Topology.IsInstance(v_b, "Vertex"):
5511
+ seg_vertices.append(v_b)
5512
+
5513
+ # Make sure we have at least two vertices
5514
+ if len(seg_vertices) >= 2:
5515
+ sub_wires.append(Wire.ByVertices(seg_vertices, close=False, silent=True))
5516
+
5517
+ if not sub_wires:
5518
+ # Fallback: return the original wire if subdivision failed
5519
+ return [wire]
5520
+
5521
+ return sub_wires
5522
+
5523
+ # ----------------------------------------------------------------------
5524
+ # Main logic
5525
+ # ----------------------------------------------------------------------
5526
+ # If there are portals, divide the wire into segments between portals,
5527
+ # then straighten each segment independently and reassemble.
5528
+ if portal_list:
5529
+ result_vertices = []
5530
+ sub_wires = _subdivide_by_portals()
5531
+
5532
+ for i, sub_wire in enumerate(sub_wires):
5533
+ if not Topology.IsInstance(sub_wire, "Wire"):
5534
+ continue
5535
+
5536
+ sub_verts = Topology.Vertices(sub_wire)
5537
+ if len(sub_verts) <= 2:
5538
+ straight_verts = sub_verts
5539
+ else:
5540
+ # IMPORTANT: recursive call with portals=[]
5541
+ straight_wire = Wire.Straighten(sub_wire, host=host,
5542
+ obstacles=obstacles,
5543
+ portals=[],
5544
+ tolerance=tolerance,
5545
+ silent=silent)
5546
+ if not Topology.IsInstance(straight_wire, "Wire"):
5547
+ straight_verts = sub_verts
5548
+ else:
5549
+ straight_verts = Topology.Vertices(straight_wire)
5550
+
5551
+ if not straight_verts:
5552
+ continue
5553
+
5554
+ # Avoid duplicate vertices between consecutive segments
5555
+ if not result_vertices:
5556
+ result_vertices.extend(straight_verts)
5557
+ else:
5558
+ result_vertices.extend(straight_verts[1:])
5559
+
5560
+ if len(result_vertices) < 2:
5561
+ # Fallback
5562
+ return wire
5563
+
5564
+ return Wire.ByVertices(result_vertices, close=False, silent=True)
5565
+
5566
+ # No portals: simple global straightening
5567
+ new_vertices = _straighten_vertices(vertices)
5568
+ if len(new_vertices) < 2:
5569
+ return wire
5570
+
5571
+ return Wire.ByVertices(new_vertices, close=False, silent=True)
5083
5572
 
5084
5573
  @staticmethod
5085
5574
  def Trapezoid(origin= None, widthA: float = 1.0, widthB: float = 0.75, offsetA: float = 0.0, offsetB: float = 0.0, length: float = 1.0, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
@@ -5440,6 +5929,105 @@ class Wire():
5440
5929
 
5441
5930
  return Wire.VertexByParameter(wire, u=compute_u(u))
5442
5931
 
5932
+
5933
+
5934
+ @staticmethod
5935
+ def ParameterAtVertex(wire, vertex, mantissa : int = 6, tolerance: float = 0.0001, silent: bool = False):
5936
+ """
5937
+ Returns the u-parameter of a vertex located on a manifold wire.
5938
+ u ranges from 0.0 (start) to 1.0 (end).
5939
+
5940
+ Parameters
5941
+ ----------
5942
+ wire : topologic_core.Wire
5943
+ The input wire.
5944
+ vertex : topologic_core.Vertex
5945
+ A vertex that lies somewhere on the wire.
5946
+ mantissa : int , optional
5947
+ The number of decimal places to round the result to. Default is 6.
5948
+ tolerance : float, optional
5949
+ Distance tolerance for matching the vertex to an edge. Default is 0.0001.
5950
+ silent : bool , optional
5951
+ If set to True, error and warning messages are suppressed. Default is False.
5952
+
5953
+ Returns
5954
+ -------
5955
+ float or None
5956
+ The global u-parameter ∈ [0, 1] of the vertex, or None on error.
5957
+ """
5958
+ from topologicpy.Topology import Topology
5959
+ from topologicpy.Vertex import Vertex
5960
+ from topologicpy.Edge import Edge
5961
+ from topologicpy.Wire import Wire
5962
+
5963
+ # --- Input validation ----------------------------------------------------
5964
+ if not Topology.IsInstance(wire, "Wire"):
5965
+ if not silent:
5966
+ print("Wire.ParameterAtVertex - Error: Input wire is not a valid wire. Returning None.")
5967
+ return None
5968
+
5969
+ if not Topology.IsInstance(vertex, "Vertex"):
5970
+ if not silent:
5971
+ print("Wire.ParameterAtVertex - Error: Input vertex is not a valid wertex. Returning None.")
5972
+ return None
5973
+
5974
+ if not Wire.IsManifold(wire):
5975
+ if not silent:
5976
+ print("Wire.ParameterAtVertex - Error: Input wire is non-manifold. Returning None.")
5977
+ return None
5978
+
5979
+ # --- Prepare wire edges ---------------------------------------------------
5980
+ edges = Wire.Edges(wire)
5981
+ if not edges:
5982
+ if not silent:
5983
+ print("Wire.ParameterAtVertex - Error: Wire has no edges. Returning None.")
5984
+ return None
5985
+
5986
+ edge_lengths = [Edge.Length(e) for e in edges]
5987
+ total_length = sum(edge_lengths)
5988
+ if total_length == 0:
5989
+ if not silent:
5990
+ print("Wire.ParameterAtVertex - Error: Wire has zero length. Returning None.")
5991
+ return None
5992
+
5993
+ # --- Special cases: endpoint vertices ------------------------------------
5994
+ if Vertex.Distance(vertex, Wire.StartVertex(wire)) <= tolerance:
5995
+ return 0.0
5996
+ if Vertex.Distance(vertex, Wire.EndVertex(wire)) <= tolerance:
5997
+ return 1.0
5998
+
5999
+ # --- Locate the edge containing the vertex -------------------------------
6000
+ accumulated = 0.0
6001
+
6002
+ for edge, e_length in zip(edges, edge_lengths):
6003
+
6004
+ # Check if vertex lies on this edge
6005
+ d = Vertex.Distance(vertex, edge)
6006
+ if d <= tolerance:
6007
+
6008
+ # Compute local parameter on this edge
6009
+ sv = Edge.StartVertex(edge)
6010
+ ev = Edge.EndVertex(edge)
6011
+
6012
+ # Local distances
6013
+ dist_sv = Vertex.Distance(sv, vertex)
6014
+ dist_ev = Vertex.Distance(ev, vertex)
6015
+
6016
+ if dist_sv + dist_ev == 0:
6017
+ local_u = 0.0
6018
+ else:
6019
+ local_u = dist_sv / (dist_sv + dist_ev)
6020
+
6021
+ # Global parameter u
6022
+ global_u = (accumulated + local_u * e_length) / total_length
6023
+ return round(global_u, mantissa)
6024
+
6025
+ accumulated += e_length
6026
+
6027
+ if not silent:
6028
+ print("Wire.ParameterAtVertex - Error: Vertex does not appear to lie on the wire. Returning None.")
6029
+ return None
6030
+
5443
6031
  @staticmethod
5444
6032
  def VertexByParameter(wire, u: float = 0):
5445
6033
  """
topologicpy/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.8.90'
1
+ __version__ = '0.8.92'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: topologicpy
3
- Version: 0.8.90
3
+ Version: 0.8.92
4
4
  Summary: An AI-Powered Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
5
5
  Author-email: Wassim Jabi <wassim.jabi@gmail.com>
6
6
  License: AGPL v3 License
@@ -2,7 +2,7 @@ topologicpy/ANN.py,sha256=gpflv4lFypOW789vO7mSkMLaMF_ZftVOCqCvtGr6-JA,47873
2
2
  topologicpy/Aperture.py,sha256=wNn5miB_IrGCBYuQ18HXQYRva20dUC3id4AJCulL7to,2723
3
3
  topologicpy/BVH.py,sha256=ts0Ru24ILjjfHa54SYNhMc8Jkyxwej1DV0Jv7P_6BoU,22513
4
4
  topologicpy/CSG.py,sha256=09la1-xzS9vr-WnV7tpJ0I-mkZ-XY0MRSd5iB50Nfgw,15556
5
- topologicpy/Cell.py,sha256=EHDCod7OJyiSw2oI7ttlO46bDET9N6RaQsPZLF7LP2k,198779
5
+ topologicpy/Cell.py,sha256=8GGeRJDoWV2qr__x41axOTIqtkep3U3VXRzM3qsQpPA,198783
6
6
  topologicpy/CellComplex.py,sha256=B8bAW6M5fClfXb9nSLDhrgtNRlU888Z4EcUzBZtBqss,68558
7
7
  topologicpy/Cluster.py,sha256=Vi5qn9dc9FRdZk1X5KrrU5YS8r4YDDA19C_nKo1IfA0,63725
8
8
  topologicpy/Color.py,sha256=hzSmgBWhiuYc55RSipkQNIgGtgyhC5BqY8AakNYEK-U,24486
@@ -12,7 +12,7 @@ topologicpy/Dictionary.py,sha256=goODXIM6AoC5Qn_d8LGc5pRoxZKgIWbkn3IOEbsQ4c4,449
12
12
  topologicpy/Edge.py,sha256=aiRd1xZgG2GGYHxva0bM-kDy3AVmwGA_S2pMur8EeMg,74911
13
13
  topologicpy/EnergyModel.py,sha256=MEai1GF1hINeH5bhclJj_lpMU3asFTvW2RlPm40GNj4,57794
14
14
  topologicpy/Face.py,sha256=qAl36LcwiyRclMM2pI9NyWHzmgNlaykXiJx1wu10RmA,201317
15
- topologicpy/Graph.py,sha256=c-n_9xKXizbyGGWBw62fECsqMo-UoqvQJz6nw82DWgA,811337
15
+ topologicpy/Graph.py,sha256=Tokxg55wHmx5hd9eai7EMRUdptADLt7HmJNrhq00UZk,810723
16
16
  topologicpy/Grid.py,sha256=3OsBMyHh4w8gpFOTMKHMNTpo62V0CwRNu5cwm87yDUA,18421
17
17
  topologicpy/Helper.py,sha256=NsmMlbbKFPRX6jfoko-ZQVQ7MBsfVp9FD0ZvC2U7q-8,32002
18
18
  topologicpy/Honeybee.py,sha256=dBk01jIvxjQMGHqSarM1Cukv16ot4Op7Dwlitn2OMoc,48990
@@ -26,14 +26,14 @@ topologicpy/ShapeGrammar.py,sha256=q_BvMKOBDW3GVSRjPLIGAZkHW2egw3mTOPzIyEpYOLg,2
26
26
  topologicpy/Shell.py,sha256=2EPzDT_t0IAjBRYPDuKNAz_Ax_HaEkvNpXBxDkPdcTg,101084
27
27
  topologicpy/Speckle.py,sha256=-eiTqJugd7pHiHpD3pDUcDO6CGhVyPV14HFRzaqEoaw,18187
28
28
  topologicpy/Sun.py,sha256=ezisiHfc2nd7A_8w0Ykq2VgbS0A9WNSg-tBwvfTQAVM,36735
29
- topologicpy/Topology.py,sha256=E_AyPPCIx_Eq-UT74QS3LKFXIwdwekRjJJGTo1CRMRY,548577
29
+ topologicpy/Topology.py,sha256=Q2uivQaKrvfYX1e1sRZkNi1HXWrrVDqDKRhF9esUnog,548668
30
30
  topologicpy/Vector.py,sha256=pEC8YY3TeHGfGdeNgvdHjgMDwxGabp5aWjwYC1HSvMk,42236
31
31
  topologicpy/Vertex.py,sha256=26TrlX9OCZUN-lMlZG3g4RHTWBqw69NW4AOEgRz_YMo,91269
32
- topologicpy/Wire.py,sha256=Rhqw0CGEWIMVL1ICQqkCp9G-VnhhHLhEiDDR00fAn_s,248919
32
+ topologicpy/Wire.py,sha256=OzMTI5vxJ8XJPgwDAB31666Dz2Sp7H_U9oCnm81gPQA,272312
33
33
  topologicpy/__init__.py,sha256=RMftibjgAnHB1vdL-muo71RwMS4972JCxHuRHOlU428,928
34
- topologicpy/version.py,sha256=Vg4EZKvQvJEbHjPwL_FRDJq1bK9YEoQB3n1ijcuv9Dk,23
35
- topologicpy-0.8.90.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
36
- topologicpy-0.8.90.dist-info/METADATA,sha256=Zk31JGzXHHQe7HU4kLuQ6SvCj6EnOW3PolmmmV1EepE,10535
37
- topologicpy-0.8.90.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
- topologicpy-0.8.90.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
39
- topologicpy-0.8.90.dist-info/RECORD,,
34
+ topologicpy/version.py,sha256=S19MYIjxGesLc99Q4qttRtyqcN1JTaTrknAmmrZH4S8,23
35
+ topologicpy-0.8.92.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
36
+ topologicpy-0.8.92.dist-info/METADATA,sha256=AUltiuak0trtBqGFWTznW6Xlc_irgAW7Y-9QUsGRXX8,10535
37
+ topologicpy-0.8.92.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
+ topologicpy-0.8.92.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
39
+ topologicpy-0.8.92.dist-info/RECORD,,