topologicpy 0.7.43__py3-none-any.whl → 0.7.45__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
@@ -1519,6 +1519,7 @@ class Cell():
1519
1519
 
1520
1520
  from topologicpy.Vertex import Vertex
1521
1521
  from topologicpy.Face import Face
1522
+ from topologicpy.Shell import Shell
1522
1523
  from topologicpy.Topology import Topology
1523
1524
 
1524
1525
  if not Topology.IsInstance(origin, "Vertex"):
@@ -1552,6 +1553,132 @@ class Cell():
1552
1553
  octahedron = Topology.Place(octahedron, originA=Vertex.Origin(), originB=origin)
1553
1554
  return octahedron
1554
1555
 
1556
+ @staticmethod
1557
+ def Paraboloid(origin= None, focalLength=0.125, width: float = 1, length: float = 1, height: float = 0, uSides: int = 16, vSides: int = 16,
1558
+ direction: list = [0, 0, 1], placement: str ="center", mantissa: int = 6, tolerance: float = 0.0001, silent=False):
1559
+ """
1560
+ Creates a paraboloid cell. See https://en.wikipedia.org/wiki/Paraboloid
1561
+
1562
+ Parameters
1563
+ ----------
1564
+ origin : topologic_core.Vertex , optional
1565
+ The origin location of the parabolic surface. The default is None which results in the parabolic surface being placed at (0, 0, 0).
1566
+ focalLength : float , optional
1567
+ The focal length of the parabola. The default is 0.125.
1568
+ width : float , optional
1569
+ The width of the parabolic surface. The default is 1.
1570
+ length : float , optional
1571
+ The length of the parabolic surface. The default is 1.
1572
+ height : float , optional
1573
+ The additional height of the parabolic surface. Please note this is not the height from the spring point to the apex. It is in addition to that to form a base. The default is 0.
1574
+ uSides : int , optional
1575
+ The number of sides along the width. The default is 16.
1576
+ vSides : int , optional
1577
+ The number of sides along the length. The default is 16.
1578
+ direction : list , optional
1579
+ The vector representing the up direction of the parabolic surface. The default is [0, 0, 1].
1580
+ placement : str , optional
1581
+ The description of the placement of the origin of the parabolic surface. This can be "bottom", "center", or "lowerleft". It is case insensitive. The default is "center".
1582
+ mantissa : int , optional
1583
+ The desired length of the mantissa. The default is 6.
1584
+ tolerance : float , optional
1585
+ The desired tolerance. The default is 0.0001.
1586
+ silent : bool , optional
1587
+ If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
1588
+
1589
+ Returns
1590
+ -------
1591
+ topologic_core.Shell
1592
+ The created paraboloid.
1593
+
1594
+ """
1595
+ from topologicpy.Vertex import Vertex
1596
+ from topologicpy.Topology import Topology
1597
+ from topologicpy.Face import Face
1598
+ from topologicpy.Wire import Wire
1599
+ from topologicpy.Shell import Shell
1600
+
1601
+ if origin == None:
1602
+ origin = Vertex.Origin()
1603
+
1604
+ if not Topology.IsInstance(origin, "Vertex"):
1605
+ if not silent:
1606
+ print("Cell.Paraboloid - Error: The origin input parameter is not a valid vertex. Returning None.")
1607
+ return None
1608
+ if width <= 0:
1609
+ if not silent:
1610
+ print("Cell.Paraboloid - Error: The width input parameter cannot be less than or equal to zero. Returning None.")
1611
+ return None
1612
+ if length <= 0:
1613
+ if not silent:
1614
+ print("Cell.Paraboloid - Error: The length input parameter cannot be less than or equal to zero. Returning None.")
1615
+ return None
1616
+ if height < 0:
1617
+ if not silent:
1618
+ print("Cell.Paraboloid - Error: The height input parameter cannot be negative. Returning None.")
1619
+ return None
1620
+
1621
+ para = Shell.Paraboloid(focalLength=focalLength, width=width, length=length, uSides=uSides, vSides=vSides,
1622
+ direction=[0,0,1], placement="center", mantissa=mantissa, tolerance=tolerance)
1623
+ if not Topology.IsInstance(para, "Shell"):
1624
+ if not silent:
1625
+ print("Cell.Paraboloid - Error: Could not create paraboloid. Returning None.")
1626
+ return None
1627
+ eb = Shell.ExternalBoundary(para)
1628
+ vertices = Topology.Vertices(eb)
1629
+ z_list = [Vertex.Z(v) for v in vertices]
1630
+ if focalLength > 0:
1631
+ z = max(z_list) + height
1632
+ else:
1633
+ z = min(z_list) - height
1634
+ f = Face.Rectangle(origin=Vertex.ByCoordinates(0,0,z), width=width*1.1, length=length*1.1)
1635
+ proj_vertices = []
1636
+ for v in vertices:
1637
+ proj_vertices.append(Vertex.Project(v, f))
1638
+ w = Wire.ByVertices(proj_vertices, close=True)
1639
+ sleeve = Shell.ByWires([eb, w], triangulate=False, silent=True)
1640
+ if sleeve == None:
1641
+ if not silent:
1642
+ print("Cell.Paraboloid - Error: Could not create paraboloid. Returning None.")
1643
+ return None
1644
+ f = Face.ByWire(w, tolerance=tolerance)
1645
+ faces = Topology.Faces(sleeve) + [f] + Topology.Faces(para)
1646
+ cell = Cell.ByFaces(faces, tolerance=tolerance)
1647
+ if cell == None:
1648
+ if not silent:
1649
+ print("Cell.Paraboloid - Error: Could not create paraboloid. Returning None.")
1650
+ return None
1651
+ vertices = Topology.Vertices(cell)
1652
+ x_list = [Vertex.X(v, mantissa=mantissa) for v in vertices]
1653
+ y_list = [Vertex.Y(v, mantissa=mantissa) for v in vertices]
1654
+ z_list = [Vertex.Z(v, mantissa=mantissa) for v in vertices]
1655
+ min_x = min(x_list)
1656
+ max_x = max(x_list)
1657
+ mid_x = min_x + (max_x - min_x)/2
1658
+ min_y = min(y_list)
1659
+ max_y = max(y_list)
1660
+ mid_y = min_y + (max_y - min_y)/2
1661
+ min_z = min(z_list)
1662
+ max_z = max(z_list)
1663
+ mid_z = min_z + (max_z - min_z)/2
1664
+ if placement.lower() == "center":
1665
+ x_tran = -mid_x
1666
+ y_tran = -mid_y
1667
+ z_tran = -mid_z
1668
+ elif placement.lower() == "bottom":
1669
+ x_tran = -mid_x
1670
+ y_tran = -mid_y
1671
+ z_tran = -min_z
1672
+ elif placement.lower() == "lowerleft":
1673
+ x_tran = -min_x
1674
+ y_tran = -min_y
1675
+ z_tran = -min_z
1676
+ cell = Topology.Translate(cell, x_tran, y_tran, z_tran)
1677
+ cell = Topology.Place(cell, originA=Vertex.Origin(), originB=origin)
1678
+ if not direction == [0,0,1]:
1679
+ cell = Topology.Orient(cell, origin=origin, dirA=[0,0,1], dirB=direction)
1680
+ return cell
1681
+
1555
1682
  @staticmethod
1556
1683
  def Pipe(edge, profile = None, radius: float = 0.5, sides: int = 16, startOffset: float = 0, endOffset: float = 0, endcapA = None, endcapB = None, mantissa: int = 6) -> dict:
1557
1684
  """
@@ -20,7 +20,7 @@ import math
20
20
  from collections import OrderedDict
21
21
  import os
22
22
  from os.path import exists
23
- from datetime import datetime
23
+ from datetime import datetime, timezone
24
24
  import warnings
25
25
 
26
26
  try:
@@ -249,18 +249,24 @@ class EnergyModel:
249
249
  weatherFilePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "assets", "EnergyModel", "GBR_London.Gatwick.037760_IWEC.epw")
250
250
  designDayFilePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "assets", "EnergyModel", "GBR_London.Gatwick.037760_IWEC.ddy")
251
251
  translator = openstudio.osversion.VersionTranslator()
252
- osmFile = openstudio.openstudioutilitiescore.toPath(osModelPath)
253
- osModel = translator.loadModel(osmFile)
252
+ # DEBUGGING
253
+ #osmFile = openstudio.openstudioutilitiescore.toPath(osModelPath)
254
+ #osModel = translator.loadModel(osmFile)
255
+ osModel = translator.loadModel(osModelPath)
254
256
  if osModel.isNull():
255
257
  print("EnergyModel.ByTopology - Error: The openstudio model is null. Returning None.")
256
258
  return None
257
259
  else:
258
260
  osModel = osModel.get()
259
- osEPWFile = openstudio.openstudioutilitiesfiletypes.EpwFile.load(openstudio.toPath(weatherFilePath))
261
+ # DEBUGGING
262
+ #osEPWFile = openstudio.openstudioutilitiesfiletypes.EpwFile.load(openstudio.toPath(weatherFilePath))
263
+ osEPWFile = openstudio.openstudioutilitiesfiletypes.EpwFile.load(weatherFilePath)
260
264
  if osEPWFile.is_initialized():
261
265
  osEPWFile = osEPWFile.get()
262
266
  openstudio.model.WeatherFile.setWeatherFile(osModel, osEPWFile)
263
- ddyModel = openstudio.openstudioenergyplus.loadAndTranslateIdf(openstudio.toPath(designDayFilePath))
267
+ # DEBUGGING
268
+ #ddyModel = openstudio.openstudioenergyplus.loadAndTranslateIdf(openstudio.toPath(designDayFilePath))
269
+ ddyModel = openstudio.openstudioenergyplus.loadAndTranslateIdf(designDayFilePath)
264
270
  if ddyModel.is_initialized():
265
271
  ddyModel = ddyModel.get()
266
272
  for ddy in ddyModel.getObjectsByType(openstudio.IddObjectType("OS:SizingPeriod:DesignDay")):
@@ -578,8 +584,9 @@ class EnergyModel:
578
584
  if not overwrite and exists(path):
579
585
  print("EnergyModel.ExportToGBXML - Error: a file already exists at the specified path and overwrite is set to False. Returning None.")
580
586
  return None
581
-
582
- return openstudio.gbxml.GbXMLForwardTranslator().modelToGbXML(model, openstudio.openstudioutilitiescore.toPath(path))
587
+ # DEBUGGING
588
+ #return openstudio.gbxml.GbXMLForwardTranslator().modelToGbXML(model, openstudio.openstudioutilitiescore.toPath(path))
589
+ return openstudio.gbxml.GbXMLForwardTranslator().modelToGbXML(model, path)
583
590
 
584
591
 
585
592
  @staticmethod
@@ -629,8 +636,10 @@ class EnergyModel:
629
636
  print("EnergyModel.ExportToOSM - Error: a file already exists at the specified path and overwrite is set to False. Returning None.")
630
637
  return None
631
638
  osCondition = False
632
- osPath = openstudio.openstudioutilitiescore.toPath(path)
633
- osCondition = model.save(osPath, overwrite)
639
+ # DEBUGGING
640
+ #osPath = openstudio.openstudioutilitiescore.toPath(path)
641
+ #osCondition = model.save(osPath, overwrite)
642
+ osCondition = model.save(path, overwrite)
634
643
  return osCondition
635
644
 
636
645
  @staticmethod
@@ -821,7 +830,7 @@ class EnergyModel:
821
830
  if removeFiles:
822
831
  deleteOldFiles(outputFolder)
823
832
  pbar = tqdm(desc='Running Simulation', total=100, leave=False)
824
- utcnow = datetime.utcnow()
833
+ utcnow = datetime.now(timezone.utc)
825
834
  timestamp = utcnow.strftime("UTC-%Y-%m-%d-%H-%M-%S")
826
835
  if not outputFolder:
827
836
  home = os.path.expanduser('~')
@@ -831,28 +840,32 @@ class EnergyModel:
831
840
  os.mkdir(outputFolder)
832
841
  pbar.update(10)
833
842
  osmPath = os.path.join(outputFolder, model.getBuilding().name().get() + ".osm")
834
- model.save(openstudio.openstudioutilitiescore.toPath(osmPath), True)
843
+ # DEBUGGING
844
+ #model.save(openstudio.openstudioutilitiescore.toPath(osmPath), True)
845
+ model.save(osmPath, True)
835
846
  oswPath = os.path.join(outputFolder, model.getBuilding().name().get() + ".osw")
836
847
  pbar.update(20)
837
- #print("oswPath = "+oswPath)
838
848
  workflow = model.workflowJSON()
839
- workflow.setSeedFile(openstudio.openstudioutilitiescore.toPath(osmPath))
849
+ # DEBUGGING
850
+ #workflow.setSeedFile(openstudio.openstudioutilitiescore.toPath(osmPath))
851
+ workflow.setSeedFile(osmPath)
840
852
  pbar.update(30)
841
- #print("Seed File Set")
842
- workflow.setWeatherFile(openstudio.openstudioutilitiescore.toPath(weatherFilePath))
853
+ # DEBUGGING
854
+ #workflow.setWeatherFile(openstudio.openstudioutilitiescore.toPath(weatherFilePath))
855
+ workflow.setWeatherFile(weatherFilePath)
843
856
  pbar.update(40)
844
- #print("Weather File Set")
845
- workflow.saveAs(openstudio.openstudioutilitiescore.toPath(oswPath))
857
+ # DEBUGGING
858
+ #workflow.saveAs(openstudio.openstudioutilitiescore.toPath(oswPath))
859
+ workflow.saveAs(oswPath)
846
860
  pbar.update(50)
847
- #print("OSW File Saved")
848
861
  cmd = osBinaryPath+" run -w " + "\"" + oswPath + "\""
849
862
  pbar.update(60)
850
863
  os.system(cmd)
851
- #print("Simulation DONE")
852
864
  sqlPath = os.path.join(os.path.join(outputFolder,"run"), "eplusout.sql")
853
865
  pbar.update(100)
854
- #print("sqlPath = "+sqlPath)
855
- osSqlFile = openstudio.SqlFile(openstudio.openstudioutilitiescore.toPath(sqlPath))
866
+ # DEBUGGING
867
+ #osSqlFile = openstudio.SqlFile(openstudio.openstudioutilitiescore.toPath(sqlPath))
868
+ osSqlFile = openstudio.SqlFile(sqlPath)
856
869
  model.setSqlFile(osSqlFile)
857
870
  pbar.close()
858
871
  return model
topologicpy/Face.py CHANGED
@@ -451,7 +451,7 @@ class Face():
451
451
  planar_shell = Shell.Planarize(shell)
452
452
  normal = Face.Normal(Topology.Faces(planar_shell)[0])
453
453
  planar_shell = Topology.Flatten(planar_shell, origin=origin, direction=normal)
454
- vertices = Shell.Vertices(planar_shell)
454
+ vertices = Topology.Vertices(planar_shell)
455
455
  new_vertices = []
456
456
  for v in vertices:
457
457
  x, y, z = Vertex.Coordinates(v)
topologicpy/Graph.py CHANGED
@@ -712,7 +712,7 @@ class Graph:
712
712
  return paths
713
713
 
714
714
  @staticmethod
715
- def AverageClusteringCoefficient(graph, mantissa=6):
715
+ def AverageClusteringCoefficient(graph, mantissa: int = 6):
716
716
  """
717
717
  Returns the average clustering coefficient of the input graph. See https://en.wikipedia.org/wiki/Clustering_coefficient.
718
718
 
@@ -1199,7 +1199,7 @@ class Graph:
1199
1199
  return bot_graph.serialize(format=format)
1200
1200
 
1201
1201
  @staticmethod
1202
- def BetweenessCentrality(graph, vertices=None, sources=None, destinations=None, tolerance=0.001):
1202
+ def BetweenessCentrality(graph, vertices=None, sources=None, destinations=None, key: str = "betweeness_centrality", mantissa: int = 6, tolerance: float = 0.001):
1203
1203
  """
1204
1204
  Returns the betweeness centrality measure of the input list of vertices within the input graph. The order of the returned list is the same as the order of the input list of vertices. If no vertices are specified, the betweeness centrality of all the vertices in the input graph is computed. See https://en.wikipedia.org/wiki/Betweenness_centrality.
1205
1205
 
@@ -1213,6 +1213,10 @@ class Graph:
1213
1213
  The input list of source vertices. The default is None which means all vertices in the input graph are considered.
1214
1214
  destinations : list , optional
1215
1215
  The input list of destination vertices. The default is None which means all vertices in the input graph are considered.
1216
+ key : str , optional
1217
+ The dictionary key under which to save the betweeness centrality score. The default is "betweneess_centrality".
1218
+ mantissa : int , optional
1219
+ The desired length of the mantissa. The default is 6.
1216
1220
  tolerance : float , optional
1217
1221
  The desired tolerance. The default is 0.0001.
1218
1222
 
@@ -1224,6 +1228,7 @@ class Graph:
1224
1228
  """
1225
1229
  from topologicpy.Vertex import Vertex
1226
1230
  from topologicpy.Topology import Topology
1231
+ from topologicpy.Dictionary import Dictionary
1227
1232
 
1228
1233
  def betweeness(vertices, topologies, tolerance=0.001):
1229
1234
  returnList = [0] * len(vertices)
@@ -1281,12 +1286,16 @@ class Graph:
1281
1286
  if path:
1282
1287
  paths.append(path)
1283
1288
 
1284
- values = betweeness(vertices, paths, tolerance=tolerance)
1285
- minValue = min(values)
1286
- maxValue = max(values)
1289
+ scores = betweeness(vertices, paths, tolerance=tolerance)
1290
+ minValue = min(scores)
1291
+ maxValue = max(scores)
1287
1292
  size = maxValue - minValue
1288
- values = [(v-minValue)/size for v in values]
1289
- return values
1293
+ scores = [round((v-minValue)/size, mantissa) for v in scores]
1294
+ for i, v in enumerate(vertices):
1295
+ d = Topology.Dictionary(v)
1296
+ d = Dictionary.SetValueAtKey(d, key, scores[i])
1297
+ v = Topology.SetDictionary(v, d)
1298
+ return scores
1290
1299
 
1291
1300
  @staticmethod
1292
1301
  def ByAdjacencyMatrixCSVPath(path: str, dictionaries: list = None, silent: bool = False):
@@ -4064,7 +4073,7 @@ class Graph:
4064
4073
  return chromatic_number(adj_matrix)
4065
4074
 
4066
4075
  @staticmethod
4067
- def Color(graph, oldKey: str = "color", newKey: str = "color", maxColors: int = None, tolerance: float = 0.0001):
4076
+ def Color(graph, oldKey: str = "color", key: str = "color", maxColors: int = None, tolerance: float = 0.0001):
4068
4077
  """
4069
4078
  Colors the input vertices within the input graph. The saved value is an integer rather than an actual color. See Color.ByValueInRange to convert to an actual color.
4070
4079
  Any vertices that have been pre-colored will not be affected. See https://en.wikipedia.org/wiki/Graph_coloring.
@@ -4075,7 +4084,7 @@ class Graph:
4075
4084
  The input graph.
4076
4085
  oldKey : str , optional
4077
4086
  The existing dictionary key to use to read any pre-existing color information. The default is "color".
4078
- newKey : str , optional
4087
+ key : str , optional
4079
4088
  The new dictionary key to use to write out new color information. The default is "color".
4080
4089
  maxColors : int , optional
4081
4090
  The desired maximum number of colors to use. If set to None, the chromatic number of the graph is used. The default is None.
@@ -4152,7 +4161,7 @@ class Graph:
4152
4161
  colors = graph_coloring(adj_mat, maxColors, colors)
4153
4162
  for i, v in enumerate(vertices):
4154
4163
  d = Topology.Dictionary(v)
4155
- d = Dictionary.SetValueAtKey(d, newKey, colors[i])
4164
+ d = Dictionary.SetValueAtKey(d, key, colors[i])
4156
4165
  v = Topology.SetDictionary(v, d)
4157
4166
  return graph
4158
4167
 
@@ -4259,7 +4268,7 @@ class Graph:
4259
4268
  return graph
4260
4269
 
4261
4270
  @staticmethod
4262
- def ClosenessCentrality(graph, vertices=None, tolerance = 0.0001):
4271
+ def ClosenessCentrality(graph, vertices=None, key: str = "closeness_centrality", mantissa: int = 6, tolerance = 0.0001):
4263
4272
  """
4264
4273
  Return the closeness centrality measure of the input list of vertices within the input graph. The order of the returned list is the same as the order of the input list of vertices. If no vertices are specified, the closeness centrality of all the vertices in the input graph is computed. See https://en.wikipedia.org/wiki/Closeness_centrality.
4265
4274
 
@@ -4269,6 +4278,10 @@ class Graph:
4269
4278
  The input graph.
4270
4279
  vertices : list , optional
4271
4280
  The input list of vertices. The default is None.
4281
+ key : str , optional
4282
+ The dictionary key under which to save the closeness centrality score. The default is "closeness_centrality".
4283
+ mantissa : int , optional
4284
+ The desired length of the mantissa. The default is 6.
4272
4285
  tolerance : float , optional
4273
4286
  The desired tolerance. The default is 0.0001.
4274
4287
 
@@ -4279,6 +4292,7 @@ class Graph:
4279
4292
 
4280
4293
  """
4281
4294
  from topologicpy.Topology import Topology
4295
+ from topologicpy.Dictionary import Dictionary
4282
4296
 
4283
4297
  if not Topology.IsInstance(graph, "Graph"):
4284
4298
  print("Graph.ClosenessCentrality - Error: The input graph is not a valid graph. Returning None.")
@@ -4293,7 +4307,7 @@ class Graph:
4293
4307
  return None
4294
4308
  n = len(graphVertices)
4295
4309
 
4296
- returnList = []
4310
+ scores = []
4297
4311
  try:
4298
4312
  for va in tqdm(vertices, desc="Computing Closeness Centrality", leave=False):
4299
4313
  top_dist = 0
@@ -4304,9 +4318,9 @@ class Graph:
4304
4318
  d = Graph.TopologicalDistance(graph, va, vb, tolerance)
4305
4319
  top_dist += d
4306
4320
  if top_dist == 0:
4307
- returnList.append(0)
4321
+ scores.append(0)
4308
4322
  else:
4309
- returnList.append((n-1)/top_dist)
4323
+ scores.append(round((n-1)/top_dist, mantissa))
4310
4324
  except:
4311
4325
  print("Graph.ClosenessCentrality - Warning: Could not use tqdm.")
4312
4326
  for va in vertices:
@@ -4318,10 +4332,14 @@ class Graph:
4318
4332
  d = Graph.TopologicalDistance(graph, va, vb, tolerance)
4319
4333
  top_dist += d
4320
4334
  if top_dist == 0:
4321
- returnList.append(0)
4335
+ scores.append(0)
4322
4336
  else:
4323
- returnList.append((n-1)/top_dist)
4324
- return returnList
4337
+ scores.append(round((n-1)/top_dist, mantissa))
4338
+ for i, v in enumerate(vertices):
4339
+ d = Topology.Dictionary(v)
4340
+ d = Dictionary.SetValueAtKey(d, key, scores[i])
4341
+ v = Topology.SetDictionary(v, d)
4342
+ return scores
4325
4343
 
4326
4344
  @staticmethod
4327
4345
  def Connect(graph, verticesA, verticesB, tolerance=0.0001):
@@ -4430,6 +4448,61 @@ class Graph:
4430
4448
  return None
4431
4449
  return graph.ContainsVertex(vertex, tolerance)
4432
4450
 
4451
+
4452
+ @staticmethod
4453
+ def Degree(graph, vertices=None, key: str = "degree", edgeKey: str = None, mantissa: int = 6, tolerance = 0.0001):
4454
+ """
4455
+ Return the degree measure of the input list of vertices within the input graph. The order of the returned list is the same as the order of the input list of vertices. If no vertices are specified, the closeness centrality of all the vertices in the input graph is computed. See https://en.wikipedia.org/wiki/Degree_(graph_theory).
4456
+
4457
+ Parameters
4458
+ ----------
4459
+ graph : topologic_core.Graph
4460
+ The input graph.
4461
+ vertices : list , optional
4462
+ The input list of vertices. The default is None.
4463
+ key : str , optional
4464
+ The dictionary key under which to save the closeness centrality score. The default is "degree".
4465
+ edgeKey : str , optional
4466
+ If specified, the value in the connected edges' dictionary specified by the edgeKey string will be aggregated to calculate
4467
+ the vertex degree. If a numeric value cannot be retrieved from an edge, a value of 1 is used instead. This is used in weighted graphs.
4468
+ mantissa : int , optional
4469
+ The desired length of the mantissa. The default is 6.
4470
+ tolerance : float , optional
4471
+ The desired tolerance. The default is 0.0001.
4472
+
4473
+ Returns
4474
+ -------
4475
+ list
4476
+ The degree of the input list of vertices within the input graph.
4477
+
4478
+ """
4479
+ from topologicpy.Topology import Topology
4480
+ from topologicpy.Dictionary import Dictionary
4481
+
4482
+ if not Topology.IsInstance(graph, "Graph"):
4483
+ print("Graph.ClosenessCentrality - Error: The input graph is not a valid graph. Returning None.")
4484
+ return None
4485
+ graphVertices = Graph.Vertices(graph)
4486
+ if not isinstance(vertices, list):
4487
+ vertices = graphVertices
4488
+ else:
4489
+ vertices = [v for v in vertices if Topology.IsInstance(v, "Vertex")]
4490
+ if len(vertices) < 1:
4491
+ print("Graph.Degree - Error: The input list of vertices does not contain any valid vertices. Returning None.")
4492
+ return None
4493
+ n = len(graphVertices)
4494
+
4495
+ scores = []
4496
+ for i, v in enumerate(vertices):
4497
+ degree = Graph.VertexDegree(graph, v, edgeKey= edgeKey, tolerance = tolerance)
4498
+ if isinstance(degree, float):
4499
+ degree = round(degree, mantissa)
4500
+ d = Topology.Dictionary(v)
4501
+ d = Dictionary.SetValueAtKey(d, key, degree)
4502
+ v = Topology.SetDictionary(v, d)
4503
+ scores.append(degree)
4504
+ return scores
4505
+
4433
4506
  @staticmethod
4434
4507
  def DegreeSequence(graph):
4435
4508
  """
@@ -4479,7 +4552,7 @@ class Graph:
4479
4552
  return graph.Density()
4480
4553
 
4481
4554
  @staticmethod
4482
- def DepthMap(graph, vertices=None, tolerance=0.0001):
4555
+ def DepthMap(graph, vertices=None, key: str = "depth", type: str = "topological", mantissa: int = 6, tolerance: float = 0.0001):
4483
4556
  """
4484
4557
  Return the depth map of the input list of vertices within the input graph. The returned list contains the total of the topological distances of each vertex to every other vertex in the input graph. The order of the depth map list is the same as the order of the input list of vertices. If no vertices are specified, the depth map of all the vertices in the input graph is computed.
4485
4558
 
@@ -4489,6 +4562,12 @@ class Graph:
4489
4562
  The input graph.
4490
4563
  vertices : list , optional
4491
4564
  The input list of vertices. The default is None.
4565
+ key : str , optional
4566
+ The dictionary key under which to save the depth score. The default is "depth".
4567
+ type : str , optional
4568
+ The type of depth distance to calculate. The options are "topological" or "metric". The default is "topological". See https://www.spacesyntax.online/overview-2/analysis-of-spatial-relations/.
4569
+ mantissa : int , optional
4570
+ The desired length of the mantissa. The default is 6.
4492
4571
  tolerance : float , optional
4493
4572
  The desired tolerance. The default is 0.0001.
4494
4573
 
@@ -4499,6 +4578,7 @@ class Graph:
4499
4578
 
4500
4579
  """
4501
4580
  from topologicpy.Topology import Topology
4581
+ from topologicpy.Dictionary import Dictionary
4502
4582
 
4503
4583
  if not Topology.IsInstance(graph, "Graph"):
4504
4584
  print("Graph.DepthMap - Error: The input graph is not a valid graph. Returning None.")
@@ -4511,17 +4591,21 @@ class Graph:
4511
4591
  if len(vertices) < 1:
4512
4592
  print("Graph.DepthMap - Error: The input list of vertices does not contain any valid vertices. Returning None.")
4513
4593
  return None
4514
- depthMap = []
4594
+ scores = []
4515
4595
  for va in vertices:
4516
4596
  depth = 0
4517
4597
  for vb in graphVertices:
4518
4598
  if Topology.IsSame(va, vb):
4519
4599
  dist = 0
4520
4600
  else:
4521
- dist = Graph.TopologicalDistance(graph, va, vb, tolerance)
4601
+ dist = Graph.Distance(graph, va, vb, type=type, mantissa=mantissa, tolerance=tolerance)
4522
4602
  depth = depth + dist
4523
- depthMap.append(depth)
4524
- return depthMap
4603
+ depth = round(depth, mantissa)
4604
+ d = Topology.Dictionary(va)
4605
+ d = Dictionary.SetValueAtKey(d, key, depth)
4606
+ va = Topology.SetDictionary(va, d)
4607
+ scores.append(depth)
4608
+ return scores
4525
4609
 
4526
4610
  @staticmethod
4527
4611
  def Diameter(graph):
@@ -4570,7 +4654,7 @@ class Graph:
4570
4654
  return graph.GetDictionary()
4571
4655
 
4572
4656
  @staticmethod
4573
- def Distance(graph, vertexA, vertexB, tolerance=0.0001):
4657
+ def Distance(graph, vertexA, vertexB, type: str = "topological", mantissa: int = 6, tolerance: float = 0.0001):
4574
4658
  """
4575
4659
  Returns the shortest-path distance between the input vertices. See https://en.wikipedia.org/wiki/Distance_(graph_theory).
4576
4660
 
@@ -4582,16 +4666,22 @@ class Graph:
4582
4666
  The first input vertex.
4583
4667
  vertexB : topologic_core.Vertex
4584
4668
  The second input vertex.
4669
+ type : str , optional
4670
+ The type of depth distance to calculate. The options are "topological" or "metric". The default is "topological". See https://www.spacesyntax.online/overview-2/analysis-of-spatial-relations/.
4671
+ mantissa : int , optional
4672
+ The desired length of the mantissa. The default is 6.
4585
4673
  tolerance : float , optional
4586
4674
  The desired tolerance. The default is 0.0001.
4587
4675
 
4588
4676
  Returns
4589
4677
  -------
4590
- int
4591
- The shortest-path distance between the input vertices.
4678
+ float
4679
+ The shortest-path metric distance between the input vertices.
4592
4680
 
4593
4681
  """
4594
4682
  from topologicpy.Topology import Topology
4683
+ from topologicpy.Wire import Wire
4684
+ from topologicpy.Edge import Edge
4595
4685
 
4596
4686
  if not Topology.IsInstance(graph, "Graph"):
4597
4687
  print("Graph.Distance - Error: The input graph is not a valid graph. Returning None.")
@@ -4602,8 +4692,11 @@ class Graph:
4602
4692
  if not Topology.IsInstance(vertexB, "Vertex"):
4603
4693
  print("Graph.Distance - Error: The input vertexB is not a valid vertex. Returning None.")
4604
4694
  return None
4605
- return graph.TopologicalDistance(vertexA, vertexB, tolerance)
4606
-
4695
+
4696
+ if "topo" in type.lower():
4697
+ return Graph.TopologicalDistance(graph, vertexA, vertexB, tolerance=tolerance)
4698
+ return Graph.MetricDistance(graph, vertexA, vertexB, mantissa=mantissa, tolerance=tolerance)
4699
+
4607
4700
  @staticmethod
4608
4701
  def Edge(graph, vertexA, vertexB, tolerance=0.0001):
4609
4702
  """
@@ -6520,7 +6613,7 @@ class Graph:
6520
6613
  return json_string
6521
6614
 
6522
6615
  @staticmethod
6523
- def LocalClusteringCoefficient(graph, vertices: list = None, mantissa: int = 6, tolerance: float = 0.0001):
6616
+ def LocalClusteringCoefficient(graph, vertices: list = None, key: str = "lcc", mantissa: int = 6, tolerance: float = 0.0001):
6524
6617
  """
6525
6618
  Returns the local clustering coefficient of the input list of vertices within the input graph. See https://en.wikipedia.org/wiki/Clustering_coefficient.
6526
6619
 
@@ -6530,6 +6623,8 @@ class Graph:
6530
6623
  The input graph.
6531
6624
  vertices : list , optional
6532
6625
  The input list of vertices. If set to None, the local clustering coefficient of all vertices will be computed. The default is None.
6626
+ key : str , optional
6627
+ The dictionary key under which to save the local clustering coefficient score. The default is "lcc".
6533
6628
  mantissa : int , optional
6534
6629
  The desired length of the mantissa. The default is 6.
6535
6630
  tolerance : float , optional
@@ -6543,6 +6638,7 @@ class Graph:
6543
6638
  """
6544
6639
  from topologicpy.Vertex import Vertex
6545
6640
  from topologicpy.Topology import Topology
6641
+ from topologicpy.Dictionary import Dictionary
6546
6642
 
6547
6643
  def local_clustering_coefficient(adjacency_matrix, node):
6548
6644
  """
@@ -6585,14 +6681,18 @@ class Graph:
6585
6681
  return None
6586
6682
  g_vertices = Graph.Vertices(graph)
6587
6683
  adjacency_matrix = Graph.AdjacencyMatrix(graph)
6588
- lcc = []
6684
+ scores = []
6589
6685
  for v in vertices:
6590
6686
  i = Vertex.Index(v, g_vertices, tolerance=tolerance)
6591
6687
  if not i == None:
6592
- lcc.append(round(local_clustering_coefficient(adjacency_matrix, i), mantissa))
6688
+ lcc_score = round(local_clustering_coefficient(adjacency_matrix, i), mantissa)
6689
+ d = Topology.Dictionary(v)
6690
+ d = Dictionary.SetValueAtKey(d, key, lcc_score)
6691
+ v = Topology.SetDictionary(v, d)
6692
+ scores.append(lcc_score)
6593
6693
  else:
6594
- lcc.append(None)
6595
- return lcc
6694
+ scores.append(None)
6695
+ return scores
6596
6696
 
6597
6697
  @staticmethod
6598
6698
  def LongestPath(graph, vertexA, vertexB, vertexKey=None, edgeKey=None, costKey=None, timeLimit=10, tolerance=0.0001):
@@ -6889,6 +6989,52 @@ class Graph:
6889
6989
  'edgeDictionaries': e_dicts
6890
6990
  }
6891
6991
 
6992
+ @staticmethod
6993
+ def MetricDistance(graph, vertexA, vertexB, mantissa: int = 6, tolerance: float = 0.0001):
6994
+ """
6995
+ Returns the shortest-path distance between the input vertices. See https://en.wikipedia.org/wiki/Distance_(graph_theory).
6996
+
6997
+ Parameters
6998
+ ----------
6999
+ graph : topologic_core.Graph
7000
+ The input graph.
7001
+ vertexA : topologic_core.Vertex
7002
+ The first input vertex.
7003
+ vertexB : topologic_core.Vertex
7004
+ The second input vertex.
7005
+ mantissa : int , optional
7006
+ The desired length of the mantissa. The default is 6.
7007
+ tolerance : float , optional
7008
+ The desired tolerance. The default is 0.0001.
7009
+
7010
+ Returns
7011
+ -------
7012
+ float
7013
+ The shortest-path metric distance between the input vertices.
7014
+
7015
+ """
7016
+ from topologicpy.Topology import Topology
7017
+ from topologicpy.Wire import Wire
7018
+ from topologicpy.Edge import Edge
7019
+
7020
+ if not Topology.IsInstance(graph, "Graph"):
7021
+ print("Graph.MetricDistance - Error: The input graph is not a valid graph. Returning None.")
7022
+ return None
7023
+ if not Topology.IsInstance(vertexA, "Vertex"):
7024
+ print("Graph.MetricDistance - Error: The input vertexA is not a valid vertex. Returning None.")
7025
+ return None
7026
+ if not Topology.IsInstance(vertexB, "Vertex"):
7027
+ print("Graph.MetricDistance - Error: The input vertexB is not a valid vertex. Returning None.")
7028
+ return None
7029
+ sp = Graph.ShortestPath(graph, vertexA, vertexB, vertexKey="", edgeKey="Length", tolerance=tolerance)
7030
+ if Topology.IsInstance(sp, "Wire"):
7031
+ dist = round(Wire.Length(sp), mantissa)
7032
+ elif Topology.IsInstance(sp, "Edge"):
7033
+ dist = round(Edge.Length(sp), mantissa)
7034
+ else:
7035
+ dist = float('inf')
7036
+ return dist
7037
+
6892
7038
  @staticmethod
6893
7039
  def MinimumDelta(graph):
6894
7040
  """
@@ -7312,7 +7458,7 @@ class Graph:
7312
7458
  return outgoing_vertices
7313
7459
 
7314
7460
  @staticmethod
7315
- def PageRank(graph, alpha=0.85, maxIterations=100, normalize=True, directed=False, mantissa=6, tolerance=0.0001):
7461
+ def PageRank(graph, alpha: float = 0.85, maxIterations: int = 100, normalize: bool = True, directed: bool = False, key: str = "page_rank", mantissa: int = 6, tolerance: float = 0.0001):
7316
7462
  """
7317
7463
  Calculates PageRank scores for nodes in a directed graph. see https://en.wikipedia.org/wiki/PageRank.
7318
7464
 
@@ -7328,6 +7474,8 @@ class Graph:
7328
7474
  If set to True, the results will be normalized from 0 to 1. Otherwise, they won't be. The default is True.
7329
7475
  directed : bool , optional
7330
7476
  If set to True, the graph is considered as a directed graph. Otherwise, it will be considered as an undirected graph. The default is False.
7477
+ key : str , optional
7478
+ The dictionary key under which to save the page_rank score. The default is "page_rank"
7331
7479
  mantissa : int , optional
7332
7480
  The desired length of the mantissa.
7333
7481
  tolerance : float , optional
@@ -7340,6 +7488,8 @@ class Graph:
7340
7488
  """
7341
7489
  from topologicpy.Vertex import Vertex
7342
7490
  from topologicpy.Helper import Helper
7491
+ from topologicpy.Dictionary import Dictionary
7492
+ from topologicpy.Topology import Topology
7343
7493
 
7344
7494
  vertices = Graph.Vertices(graph)
7345
7495
  num_vertices = len(vertices)
@@ -7368,6 +7518,10 @@ class Graph:
7368
7518
  scores = Helper.Normalize(scores, mantissa=mantissa)
7369
7519
  else:
7370
7520
  scores = [round(x, mantissa) for x in scores]
7521
+ for i, v in enumerate(vertices):
7522
+ d = Topology.Dictionary(v)
7523
+ d = Dictionary.SetValueAtKey(d, key, scores[i])
7524
+ v = Topology.SetDictionary(v, d)
7371
7525
  return scores
7372
7526
 
7373
7527
  @staticmethod
@@ -7756,13 +7910,14 @@ class Graph:
7756
7910
  gsv = Graph.NearestVertex(graph, vertexA)
7757
7911
  gev = Graph.NearestVertex(graph, vertexB)
7758
7912
  shortest_path = graph.ShortestPath(gsv, gev, vertexKey, edgeKey)
7759
- if Topology.IsInstance(shortest_path, "Edge"):
7760
- shortest_path = Wire.ByEdges([shortest_path])
7761
- sv = Topology.Vertices(shortest_path)[0]
7762
- if Vertex.Distance(sv, gev) < tolerance: # Path is reversed. Correct it.
7763
- if Topology.IsInstance(shortest_path, "Wire"):
7764
- shortest_path = Wire.Reverse(shortest_path)
7765
- shortest_path = Wire.OrientEdges(shortest_path, Wire.StartVertex(shortest_path), tolerance=tolerance)
7913
+ if not shortest_path == None:
7914
+ if Topology.IsInstance(shortest_path, "Edge"):
7915
+ shortest_path = Wire.ByEdges([shortest_path])
7916
+ sv = Topology.Vertices(shortest_path)[0]
7917
+ if Vertex.Distance(sv, gev) < tolerance: # Path is reversed. Correct it.
7918
+ if Topology.IsInstance(shortest_path, "Wire"):
7919
+ shortest_path = Wire.Reverse(shortest_path)
7920
+ shortest_path = Wire.OrientEdges(shortest_path, Wire.StartVertex(shortest_path), tolerance=tolerance)
7766
7921
  return shortest_path
7767
7922
  except:
7768
7923
  return None
topologicpy/Plotly.py CHANGED
@@ -366,15 +366,12 @@ class Plotly:
366
366
  v_label = ""
367
367
  v_group = ""
368
368
  d = Topology.Dictionary(v)
369
+ v_group = Dictionary.ValueAtKey(d, key=vertexGroupKey)
369
370
  if d:
370
- try:
371
+ if vertexLabelKey:
371
372
  v_label = str(Dictionary.ValueAtKey(d, key=vertexLabelKey)) or ""
372
- except:
373
- v_label = ""
374
- try:
375
- v_group = Dictionary.ValueAtKey(d, key=vertexGroupKey)
376
- except:
377
- v_group = None
373
+ if vertexGroupKey:
374
+ v_group = Dictionary.ValueAtKey(d, key=vertexGroupKey) or None
378
375
  try:
379
376
  v_groupList.append(vertexGroups.index(v_group))
380
377
  except:
topologicpy/PyG.py CHANGED
@@ -30,11 +30,27 @@ from sklearn.metrics import accuracy_score
30
30
  from tqdm.auto import tqdm
31
31
  import gc
32
32
 
33
+ import torch
34
+ from torch.utils.data import Dataset
35
+
36
+ import torch
37
+ from torch.utils.data import Dataset
33
38
 
34
39
  class CustomGraphDataset(Dataset):
35
- def __init__(self, root, node_level=False, graph_level=True, node_attr_key='feat',
36
- edge_attr_key='feat', transform=None, pre_transform=None):
37
- super(CustomGraphDataset, self).__init__(root, transform, pre_transform)
40
+ def __init__(self, root=None, data_list=None, indices=None, node_level=False, graph_level=True,
41
+ node_attr_key='feat', edge_attr_key='feat'):
42
+ """
43
+ Initializes the CustomGraphDataset.
44
+
45
+ Parameters:
46
+ - root: Root directory of the dataset (used only if data_list is None)
47
+ - data_list: List of preprocessed data objects (used if provided)
48
+ - indices: List of indices to select a subset of the data
49
+ - node_level: Boolean flag indicating if the dataset is node-level
50
+ - graph_level: Boolean flag indicating if the dataset is graph-level
51
+ - node_attr_key: Key for node attributes
52
+ - edge_attr_key: Key for edge attributes
53
+ """
38
54
  assert not (node_level and graph_level), "Both node_level and graph_level cannot be True at the same time"
39
55
  assert node_level or graph_level, "Both node_level and graph_level cannot be False at the same time"
40
56
 
@@ -43,15 +59,20 @@ class CustomGraphDataset(Dataset):
43
59
  self.node_attr_key = node_attr_key
44
60
  self.edge_attr_key = edge_attr_key
45
61
 
46
- self.graph_df = pd.read_csv(os.path.join(root, 'graphs.csv'))
47
- self.nodes_df = pd.read_csv(os.path.join(root, 'nodes.csv'))
48
- self.edges_df = pd.read_csv(os.path.join(root, 'edges.csv'))
49
-
50
- self.data_list = self.process_all()
62
+ if data_list is not None:
63
+ self.data_list = data_list # Use the provided data list
64
+ elif root is not None:
65
+ # Load and process data from root directory if data_list is not provided
66
+ self.graph_df = pd.read_csv(os.path.join(root, 'graphs.csv'))
67
+ self.nodes_df = pd.read_csv(os.path.join(root, 'nodes.csv'))
68
+ self.edges_df = pd.read_csv(os.path.join(root, 'edges.csv'))
69
+ self.data_list = self.process_all()
70
+ else:
71
+ raise ValueError("Either a root directory or a data_list must be provided.")
51
72
 
52
- @property
53
- def raw_file_names(self):
54
- return ['graphs.csv', 'nodes.csv', 'edges.csv']
73
+ # Filter data_list based on indices if provided
74
+ if indices is not None:
75
+ self.data_list = [self.data_list[i] for i in indices]
55
76
 
56
77
  def process_all(self):
57
78
  data_list = []
@@ -73,12 +94,9 @@ class CustomGraphDataset(Dataset):
73
94
  else:
74
95
  edge_attr = None
75
96
 
76
-
77
-
78
97
  if self.graph_level:
79
98
  label_value = self.graph_df[self.graph_df['graph_id'] == graph_id]['label'].values[0]
80
99
 
81
- # Check if the label is an integer or a float and cast accordingly
82
100
  if isinstance(label_value, int):
83
101
  y = torch.tensor([label_value], dtype=torch.long)
84
102
  elif isinstance(label_value, float):
@@ -89,7 +107,6 @@ class CustomGraphDataset(Dataset):
89
107
  elif self.node_level:
90
108
  label_values = graph_nodes['label'].values
91
109
 
92
- # Check if the labels are integers or floats and cast accordingly
93
110
  if issubclass(label_values.dtype.type, int):
94
111
  y = torch.tensor(label_values, dtype=torch.long)
95
112
  elif issubclass(label_values.dtype.type, float):
@@ -97,12 +114,6 @@ class CustomGraphDataset(Dataset):
97
114
  else:
98
115
  raise ValueError(f"Unexpected label types: {label_values.dtype}. Expected int or float.")
99
116
 
100
-
101
- # if self.graph_level:
102
- # y = torch.tensor([self.graph_df[self.graph_df['graph_id'] == graph_id]['label'].values[0]], dtype=torch.long)
103
- # elif self.node_level:
104
- # y = torch.tensor(graph_nodes['label'].values, dtype=torch.long)
105
-
106
117
  data = Data(x=x, edge_index=edge_index, y=y)
107
118
  if edge_attr is not None:
108
119
  data.edge_attr = edge_attr
@@ -111,14 +122,103 @@ class CustomGraphDataset(Dataset):
111
122
 
112
123
  return data_list
113
124
 
114
- def len(self):
125
+ def __len__(self):
115
126
  return len(self.data_list)
116
127
 
117
- def get(self, idx):
128
+ def __getitem__(self, idx):
118
129
  return self.data_list[idx]
119
130
 
120
- def __getitem__(self, idx):
121
- return self.get(idx)
131
+
132
+
133
+
134
+ # class CustomGraphDataset(Dataset):
135
+ # def __init__(self, root, node_level=False, graph_level=True, node_attr_key='feat',
136
+ # edge_attr_key='feat', transform=None, pre_transform=None):
137
+ # super(CustomGraphDataset, self).__init__(root, transform, pre_transform)
138
+ # assert not (node_level and graph_level), "Both node_level and graph_level cannot be True at the same time"
139
+ # assert node_level or graph_level, "Both node_level and graph_level cannot be False at the same time"
140
+
141
+ # self.node_level = node_level
142
+ # self.graph_level = graph_level
143
+ # self.node_attr_key = node_attr_key
144
+ # self.edge_attr_key = edge_attr_key
145
+
146
+ # self.graph_df = pd.read_csv(os.path.join(root, 'graphs.csv'))
147
+ # self.nodes_df = pd.read_csv(os.path.join(root, 'nodes.csv'))
148
+ # self.edges_df = pd.read_csv(os.path.join(root, 'edges.csv'))
149
+
150
+ # self.data_list = self.process_all()
151
+
152
+ # @property
153
+ # def raw_file_names(self):
154
+ # return ['graphs.csv', 'nodes.csv', 'edges.csv']
155
+
156
+ # def process_all(self):
157
+ # data_list = []
158
+ # for graph_id in self.graph_df['graph_id'].unique():
159
+ # graph_nodes = self.nodes_df[self.nodes_df['graph_id'] == graph_id]
160
+ # graph_edges = self.edges_df[self.edges_df['graph_id'] == graph_id]
161
+
162
+ # if self.node_attr_key in graph_nodes.columns and not graph_nodes[self.node_attr_key].isnull().all():
163
+ # x = torch.tensor(graph_nodes[self.node_attr_key].values.tolist(), dtype=torch.float)
164
+ # if x.ndim == 1:
165
+ # x = x.unsqueeze(1) # Ensure x has shape [num_nodes, *]
166
+ # else:
167
+ # x = None
168
+
169
+ # edge_index = torch.tensor(graph_edges[['src_id', 'dst_id']].values.T, dtype=torch.long)
170
+
171
+ # if self.edge_attr_key in graph_edges.columns and not graph_edges[self.edge_attr_key].isnull().all():
172
+ # edge_attr = torch.tensor(graph_edges[self.edge_attr_key].values.tolist(), dtype=torch.float)
173
+ # else:
174
+ # edge_attr = None
175
+
176
+
177
+
178
+ # if self.graph_level:
179
+ # label_value = self.graph_df[self.graph_df['graph_id'] == graph_id]['label'].values[0]
180
+
181
+ # # Check if the label is an integer or a float and cast accordingly
182
+ # if isinstance(label_value, int):
183
+ # y = torch.tensor([label_value], dtype=torch.long)
184
+ # elif isinstance(label_value, float):
185
+ # y = torch.tensor([label_value], dtype=torch.float)
186
+ # else:
187
+ # raise ValueError(f"Unexpected label type: {type(label_value)}. Expected int or float.")
188
+
189
+ # elif self.node_level:
190
+ # label_values = graph_nodes['label'].values
191
+
192
+ # # Check if the labels are integers or floats and cast accordingly
193
+ # if issubclass(label_values.dtype.type, int):
194
+ # y = torch.tensor(label_values, dtype=torch.long)
195
+ # elif issubclass(label_values.dtype.type, float):
196
+ # y = torch.tensor(label_values, dtype=torch.float)
197
+ # else:
198
+ # raise ValueError(f"Unexpected label types: {label_values.dtype}. Expected int or float.")
199
+
200
+
201
+ # # if self.graph_level:
202
+ # # y = torch.tensor([self.graph_df[self.graph_df['graph_id'] == graph_id]['label'].values[0]], dtype=torch.long)
203
+ # # elif self.node_level:
204
+ # # y = torch.tensor(graph_nodes['label'].values, dtype=torch.long)
205
+
206
+ # data = Data(x=x, edge_index=edge_index, y=y)
207
+ # if edge_attr is not None:
208
+ # data.edge_attr = edge_attr
209
+
210
+ # data_list.append(data)
211
+
212
+ # return data_list
213
+
214
+ # def len(self):
215
+ # return len(self.data_list)
216
+
217
+ # def get(self, idx):
218
+ # return self.data_list[idx]
219
+
220
+ # def __getitem__(self, idx):
221
+ # return self.get(idx)
122
222
 
123
223
  class _Hparams:
124
224
  def __init__(self, model_type="ClassifierHoldout", optimizer_str="Adam", amsgrad=False, betas=(0.9, 0.999), eps=1e-6, lr=0.001, lr_decay= 0, maximize=False, rho=0.9, weight_decay=0, cv_type="Holdout", split=[0.8,0.1, 0.1], k_folds=5, hl_widths=[32], conv_layer_type='SAGEConv', pooling="AvgPooling", batch_size=32, epochs=1,
@@ -375,7 +475,8 @@ class _GraphRegressorKFold:
375
475
 
376
476
  def _initialize_model(self, hparams, dataset):
377
477
  if hparams.conv_layer_type.lower() == 'sageconv':
378
- return _SAGEConv(dataset.num_node_features, hparams.hl_widths, 1, hparams.pooling).to(self.device)
478
+ return _SAGEConv(dataset[0].num_node_features, hparams.hl_widths, 1, hparams.pooling).to(self.device)
479
+ #return _SAGEConv(dataset.num_node_features, hparams.hl_widths, 1, hparams.pooling).to(self.device)
379
480
  else:
380
481
  raise NotImplementedError
381
482
 
@@ -1485,7 +1586,7 @@ class PyG:
1485
1586
  """
1486
1587
 
1487
1588
  import torch
1488
- from torch.utils.data import random_split, Subset
1589
+ from torch.utils.data import random_split
1489
1590
  train_ratio, val_ratio, test_ratio = split
1490
1591
  assert abs(train_ratio + val_ratio + test_ratio - 1.0) < 1e-6, "Ratios must add up to 1."
1491
1592
 
@@ -1506,9 +1607,10 @@ class PyG:
1506
1607
  val_indices = indices[train_len:train_len + val_len]
1507
1608
  test_indices = indices[train_len + val_len:train_len + val_len + test_len]
1508
1609
 
1509
- train_dataset = Subset(dataset, train_indices)
1510
- val_dataset = Subset(dataset, val_indices)
1511
- test_dataset = Subset(dataset, test_indices)
1610
+ # Create new instances of CustomGraphDataset using the indices
1611
+ train_dataset = CustomGraphDataset(data_list=dataset.data_list, indices=train_indices)
1612
+ val_dataset = CustomGraphDataset(data_list=dataset.data_list, indices=val_indices)
1613
+ test_dataset = CustomGraphDataset(data_list=dataset.data_list, indices=test_indices)
1512
1614
 
1513
1615
  return train_dataset, val_dataset, test_dataset
1514
1616
 
topologicpy/Shell.py CHANGED
@@ -269,7 +269,7 @@ class Shell():
269
269
  return None
270
270
 
271
271
  @staticmethod
272
- def ByFaces(faces: list, tolerance: float = 0.0001):
272
+ def ByFaces(faces: list, tolerance: float = 0.0001, silent=False):
273
273
  """
274
274
  Creates a shell from the input list of faces.
275
275
 
@@ -279,6 +279,8 @@ class Shell():
279
279
  The input list of faces.
280
280
  tolerance : float , optional
281
281
  The desired tolerance. The default is 0.0001.
282
+ silent : bool , optional
283
+ If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
282
284
 
283
285
  Returns
284
286
  -------
@@ -300,7 +302,8 @@ class Shell():
300
302
  if Topology.IsInstance(shell, "Shell"):
301
303
  return shell
302
304
  else:
303
- print("Shell.ByFaces - Error: Could not create shell. Returning None.")
305
+ if not silent:
306
+ print("Shell.ByFaces - Error: Could not create shell. Returning None.")
304
307
  return None
305
308
  else:
306
309
  return shell
@@ -396,9 +399,11 @@ class Shell():
396
399
  topologic_core.Shell
397
400
  The creates shell.
398
401
  """
402
+ from topologicpy.Vertex import Vertex
399
403
  from topologicpy.Edge import Edge
400
404
  from topologicpy.Wire import Wire
401
405
  from topologicpy.Face import Face
406
+ from topologicpy.Cluster import Cluster
402
407
  from topologicpy.Topology import Topology
403
408
 
404
409
  if not isinstance(wires, list):
@@ -440,6 +445,24 @@ class Shell():
440
445
  e5 = Edge.ByVertices([e1.StartVertex(), e2.EndVertex()], tolerance=tolerance, silent=silent)
441
446
  faces.append(Face.ByWire(Wire.ByEdges([e1, e5, e4], tolerance=tolerance), tolerance=tolerance))
442
447
  faces.append(Face.ByWire(Wire.ByEdges([e2, e5, e3], tolerance=tolerance), tolerance=tolerance))
448
+ elif e3:
449
+ verts = [Edge.StartVertex(e1), Edge.EndVertex(e1), Edge.StartVertex(e3), Edge.EndVertex(e3), Edge.StartVertex(e2), Edge.EndVertex(e2)]
450
+ verts = Vertex.Fuse(verts, tolerance=tolerance)
451
+ w = Wire.ByVertices(verts, close=True)
452
+ if Topology.IsInstance(w, "Wire"):
453
+ faces.append(Face.ByWire(w, tolerance=tolerance))
454
+ else:
455
+ if not silent:
456
+ print("Shell.ByWires - Warning: Could not create face.")
457
+ elif e4:
458
+ verts = [Edge.StartVertex(e1), Edge.EndVertex(e1), Edge.StartVertex(e4), Edge.EndVertex(e4), Edge.StartVertex(e2), Edge.EndVertex(e2)]
459
+ verts = Vertex.Fuse(verts, tolerance=tolerance)
460
+ w = Wire.ByVertices(verts, close=True)
461
+ if Topology.IsInstance(w, "Wire"):
462
+ faces.append(Face.ByWire(w, tolerance=tolerance))
463
+ else:
464
+ if not silent:
465
+ print("Shell.ByWires - Warning: Could not create face.")
443
466
  else:
444
467
  for j in range (len(w1_edges)):
445
468
  e1 = w1_edges[j]
@@ -466,10 +489,30 @@ class Shell():
466
489
  except:
467
490
  faces.append(Face.ByWire(Wire.ByEdges([e1, e3, e2, e4], tolerance=tolerance), tolerance=tolerance))
468
491
  elif e3:
469
- faces.append(Face.ByWire(Wire.ByEdges([e1, e3, e2], tolerance=tolerance), tolerance=tolerance))
492
+ verts = [Edge.StartVertex(e1), Edge.EndVertex(e1), Edge.StartVertex(e3), Edge.EndVertex(e3), Edge.StartVertex(e2), Edge.EndVertex(e2)]
493
+ verts = Vertex.Fuse(verts, tolerance=tolerance)
494
+ w = Wire.ByVertices(verts, close=True)
495
+ if Topology.IsInstance(w, "Wire"):
496
+ faces.append(Face.ByWire(w, tolerance=tolerance))
497
+ else:
498
+ if not silent:
499
+ print("Shell.ByWires - Warning: Could not create face.")
470
500
  elif e4:
471
- faces.append(Face.ByWire(Wire.ByEdges([e1, e4, e2], tolerance=tolerance), tolerance=tolerance))
472
- return Shell.ByFaces(faces, tolerance=tolerance)
501
+ verts = [Edge.StartVertex(e1), Edge.EndVertex(e1), Edge.StartVertex(e4), Edge.EndVertex(e4), Edge.StartVertex(e2), Edge.EndVertex(e2)]
502
+ verts = Vertex.Fuse(verts, tolerance=tolerance)
503
+ w = Wire.ByVertices(verts, close=True)
504
+ if Topology.IsInstance(w, "Wire"):
505
+ faces.append(Face.ByWire(w, tolerance=tolerance))
506
+ else:
507
+ if not silent:
508
+ print("Shell.ByWires - Warning: Could not create face.")
509
+
510
+ shell = Shell.ByFaces(faces, tolerance=tolerance, silent=silent)
511
+ if shell == None:
512
+ if not silent:
513
+ print("Shell.ByWires - Warning: Could not create shell. Returning a cluster of faces instead.")
514
+ return Cluster.ByTopologies(faces)
515
+ return shell
473
516
 
474
517
  @staticmethod
475
518
  def ByWiresCluster(cluster, triangulate: bool = True, tolerance: float = 0.0001, silent: bool = False):
@@ -1058,10 +1101,10 @@ class Shell():
1058
1101
 
1059
1102
 
1060
1103
  @staticmethod
1061
- def ParabolicSurface(origin= None, focalLength=0.125, width: float = 1, length: float = 1, uSides: int = 16, vSides: int = 16,
1062
- direction: list = [0, 0, 1], placement: str ="center", mantissa: int = 6, tolerance: float = 0.0001):
1104
+ def Paraboloid(origin= None, focalLength=0.125, width: float = 1, length: float = 1, uSides: int = 16, vSides: int = 16,
1105
+ direction: list = [0, 0, 1], placement: str ="center", mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
1063
1106
  """
1064
- Creates a parabolic surface.
1107
+ Creates a paraboloid. See https://en.wikipedia.org/wiki/Paraboloid
1065
1108
 
1066
1109
  Parameters
1067
1110
  ----------
@@ -1085,11 +1128,13 @@ class Shell():
1085
1128
  The desired length of the mantissa. The default is 6.
1086
1129
  tolerance : float , optional
1087
1130
  The desired tolerance. The default is 0.0001.
1131
+ silent : bool , optional
1132
+ If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
1088
1133
 
1089
1134
  Returns
1090
1135
  -------
1091
1136
  topologic_core.Shell
1092
- The created parabolic surface.
1137
+ The created paraboloid.
1093
1138
 
1094
1139
  """
1095
1140
  from topologicpy.Vertex import Vertex
@@ -1197,6 +1242,7 @@ class Shell():
1197
1242
  from topologicpy.Vertex import Vertex
1198
1243
  from topologicpy.Face import Face
1199
1244
  from topologicpy.Topology import Topology
1245
+
1200
1246
  if not Topology.IsInstance(origin, "Vertex"):
1201
1247
  origin = Vertex.ByCoordinates(0, 0, 0)
1202
1248
  if not Topology.IsInstance(origin, "Vertex"):
topologicpy/Topology.py CHANGED
@@ -2627,6 +2627,7 @@ class Topology():
2627
2627
  if ap != None:
2628
2628
  apertures.append(ap)
2629
2629
  context = Context.ByTopologyParameters(topology, u=0.5, v=0.5, w=0.5)
2630
+
2630
2631
  for ap in apertures:
2631
2632
  _ = Aperture.ByTopologyContext(ap, context)
2632
2633
  return topology
@@ -2828,7 +2829,7 @@ class Topology():
2828
2829
  defaultColor: list = [255,255,255],
2829
2830
  defaultOpacity: float = 1.0,
2830
2831
  transposeAxes: bool = True,
2831
- removeCoplanarFaces: bool = True,
2832
+ removeCoplanarFaces: bool = False,
2832
2833
  selfMerge: bool = True,
2833
2834
  mantissa : int = 6,
2834
2835
  tolerance: float = 0.0001):
@@ -2887,7 +2888,7 @@ class Topology():
2887
2888
  @staticmethod
2888
2889
  def ByOBJPath(objPath,
2889
2890
  defaultColor: list = [255,255,255], defaultOpacity: float = 1.0,
2890
- transposeAxes: bool = True, removeCoplanarFaces: bool = True,
2891
+ transposeAxes: bool = True, removeCoplanarFaces: bool = False,
2891
2892
  selfMerge: bool = False,
2892
2893
  mantissa : int = 6, tolerance: float = 0.0001):
2893
2894
  """
@@ -3122,16 +3123,19 @@ class Topology():
3122
3123
  selector = Topology.SetDictionary(selector, d)
3123
3124
  face_selectors.append(selector)
3124
3125
 
3125
- topology = Cluster.ByTopologies(object_faces, tolerance=tolerance)
3126
- if selfMerge:
3127
- topology = Topology.SelfMerge(topology)
3128
- if removeCoplanarFaces:
3129
- topology = Topology.RemoveCoplanarFaces(topology, tolerance=tolerance)
3130
- d = Dictionary.ByKeysValues(['name', 'color', 'opacity'], [object_name, object_color, object_opacity])
3131
- topology = Topology.SetDictionary(topology, d)
3132
- if len(face_selectors) > 0:
3133
- topology = Topology.TransferDictionariesBySelectors(topology, selectors=face_selectors, tranFaces=True, tolerance=tolerance)
3134
- return_topologies.append(topology)
3126
+ topology = Cluster.ByTopologies(object_faces)
3127
+ if Topology.IsInstance(topology, "Topology"):
3128
+ if selfMerge:
3129
+ topology = Topology.SelfMerge(topology)
3130
+ if Topology.IsInstance(topology, "Topology"):
3131
+ if removeCoplanarFaces:
3132
+ topology = Topology.RemoveCoplanarFaces(topology, tolerance=tolerance)
3133
+ if Topology.IsInstance(topology, "Topology"):
3134
+ d = Dictionary.ByKeysValues(['name', 'color', 'opacity'], [object_name, object_color, object_opacity])
3135
+ topology = Topology.SetDictionary(topology, d)
3136
+ if len(face_selectors) > 0:
3137
+ topology = Topology.TransferDictionariesBySelectors(topology, selectors=face_selectors, tranFaces=True, tolerance=tolerance)
3138
+ return_topologies.append(topology)
3135
3139
  return return_topologies
3136
3140
 
3137
3141
  @staticmethod
@@ -6308,7 +6312,7 @@ class Topology():
6308
6312
  rot_vertices = [Vertex.ByCoordinates(rot_v) for rot_v in rot_vertices]
6309
6313
  new_topology = Topology.ReplaceVertices(topology, verticesA=Topology.Vertices(topology), verticesB=rot_vertices)
6310
6314
  new_topology = Topology.SelfMerge(new_topology, tolerance=tolerance)
6311
- if len(Dictionary.Keys(d) > 0):
6315
+ if len(Dictionary.Keys(d)) > 0:
6312
6316
  new_topology = Topology.SetDictionary(new_topology, d)
6313
6317
  return new_topology
6314
6318
  if len(Dictionary.Keys(d)) > 0:
@@ -7482,10 +7486,13 @@ class Topology():
7482
7486
  """
7483
7487
  from topologicpy.Graph import Graph
7484
7488
 
7489
+
7485
7490
  if Topology.IsInstance(topology, "Vertex"):
7486
7491
  return []
7487
7492
  if Topology.IsInstance(topology, "Graph"):
7488
7493
  return Graph.Vertices(topology)
7494
+ if topology == None:
7495
+ return None
7489
7496
  return Topology.SubTopologies(topology=topology, subTopologyType="vertex")
7490
7497
 
7491
7498
  @staticmethod
@@ -7875,7 +7882,6 @@ class Topology():
7875
7882
  if Topology.IsInstance(topology, "Cell"):
7876
7883
  sinkCells = [topology]
7877
7884
  elif hidimSink >= Topology.TypeID("Cell"):
7878
- print("Transfering Dictionaries to Cells")
7879
7885
  sinkCells = Topology.Cells(topology)
7880
7886
  _ = Topology.TransferDictionaries(selectors, sinkCells, tolerance=tolerance, numWorkers=numWorkers)
7881
7887
  return topology
topologicpy/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.7.43'
1
+ __version__ = '0.7.45'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: topologicpy
3
- Version: 0.7.43
3
+ Version: 0.7.45
4
4
  Summary: An Advanced Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
5
5
  Author-email: Wassim Jabi <wassim.jabi@gmail.com>
6
6
  License: MIT License
@@ -1,6 +1,6 @@
1
1
  topologicpy/ANN.py,sha256=XAuUjNvDRK1hhXfo82S-zXmnAPZGEdHJMRdfpu0aJ8I,47901
2
2
  topologicpy/Aperture.py,sha256=p9pUzTQSBWoUaDiug1V1R1hnEIEwYSXFg2t7iRAmNRY,2723
3
- topologicpy/Cell.py,sha256=c6LeEY6-gMNByIHGC_rb2wm9ogg93VhwYK3zJ8IB78U,99798
3
+ topologicpy/Cell.py,sha256=ITQ9EdWEGNKW57EJTewmIhlgk8hk8McM8ZA5oDmubMk,105866
4
4
  topologicpy/CellComplex.py,sha256=x474N-lo1krpdIGrWRAFRdDup5a_1V-mLORTS6ZGZ7M,48227
5
5
  topologicpy/Cluster.py,sha256=TZXuxzdaUr6OHSWnjWpjCOMlVj6YHBH8aUVbDVsncVA,54999
6
6
  topologicpy/Color.py,sha256=UlmRcCSOhqcM_OyMWz4t3Kr75KcgXDhz3uctAJ2n7Ic,18031
@@ -8,28 +8,28 @@ topologicpy/Context.py,sha256=ppApYKngZZCQBFWaxIMi2z2dokY23c935IDCBosxDAE,3055
8
8
  topologicpy/DGL.py,sha256=Dd6O08D-vSxpjHYgKm45JpKiaeGvWlg1BRMzYMAXGNc,138991
9
9
  topologicpy/Dictionary.py,sha256=KqJ29YyE23Y3Xc6XmKLSCZXRfBvm-OEOxlMZ4dt-rfM,27094
10
10
  topologicpy/Edge.py,sha256=vhYHkobSLGSWV-oe2oJFFDobqFToDyb7s71yQ840AAA,65166
11
- topologicpy/EnergyModel.py,sha256=ni0H1JgvLl1-q90yK9Sm1qj5P1fTuidlimEIcwuj6qE,53287
12
- topologicpy/Face.py,sha256=d1Im4ogxuaVmZyb6hgv5muwQwahLtGzOar_a3og1a_I,115376
13
- topologicpy/Graph.py,sha256=p3VoVH6yygNV2wwzpsi4tm6yOfwRbtmsbnsAu2opLjQ,393517
11
+ topologicpy/EnergyModel.py,sha256=XcCP55VW5WHDIIKcURijmBOZEgNUDEn_V9h5EejkntA,53876
12
+ topologicpy/Face.py,sha256=pn0LGusTPKLrHEMhY94_Bs3rc4wUpIyEqyW9q-ftdG0,115379
13
+ topologicpy/Graph.py,sha256=3TB0bfESpBsGnI7CspeeZqC5v1hVY9SwAgvczFJxT_4,401612
14
14
  topologicpy/Grid.py,sha256=3-sn7CHWGcXk18XCnHjsUttNJTWwmN63g_Insj__p04,18218
15
15
  topologicpy/Helper.py,sha256=i-AfI29NMsZXBaymjilfvxQbuS3wpYbpPw4RWu1YCHs,16358
16
16
  topologicpy/Honeybee.py,sha256=vcBECJlgWVjNNdD9ZmjNik_pA1Y_ZNoOorsQb2CiyGA,21965
17
17
  topologicpy/Matrix.py,sha256=umgR7An919-wGInXJ1wpqnoQ2jCPdyMe2rcWTZ16upk,8079
18
18
  topologicpy/Neo4j.py,sha256=YvtF7RYUMATEZ8iHwFwK_MOxEDyARby2DTI2CCK6-cI,19694
19
- topologicpy/Plotly.py,sha256=U6Lo7hyDoStRKQXqlhb2LM-rR_bfBulxetRT2wMBmhI,105391
19
+ topologicpy/Plotly.py,sha256=Q1jrHXFFNwzA6lMa5V0sH7I5p5KRp5y_WohDnhIlB2E,105354
20
20
  topologicpy/Polyskel.py,sha256=EFsuh2EwQJGPLiFUjvtXmAwdX-A4r_DxP5hF7Qd3PaU,19829
21
- topologicpy/PyG.py,sha256=Dd0fiEbM_KR-sEHKCodmURBFFvckB6j7x4oBcCC5Q2o,102171
22
- topologicpy/Shell.py,sha256=NZyHYTvV0pXx18AoMbVs8y-7if8teETItv5ZOJq6gzE,84672
21
+ topologicpy/PyG.py,sha256=0yeECsMz-dqhhZSv52s_xPCO_3BcEXUK7z1YFDN9qoo,106987
22
+ topologicpy/Shell.py,sha256=aKdWIAqmLKPyi80f2PtH3_1iMfQRW0Eklbqol9cOPWM,87601
23
23
  topologicpy/Speckle.py,sha256=rUS6PCaxIjEF5_fUruxvMH47FMKg-ohcoU0qAUb-yNM,14267
24
24
  topologicpy/Sun.py,sha256=InnKtX8eKwtAgcScuABH6yp0ljmWh5m_fDR4-n3jJMY,36869
25
- topologicpy/Topology.py,sha256=5KGQ8jSiURMk9syoMLc3mrIONCfj_pfvCfHTKgPcLOM,366047
25
+ topologicpy/Topology.py,sha256=XyXMuw1jTFdHJbuYNub_ngr9mFHmKxejUR7fe6denlk,366314
26
26
  topologicpy/Vector.py,sha256=WQQUbwrg7VKImtxuBUi2i-FRiPT77WlrzLP05gdXKM8,33079
27
27
  topologicpy/Vertex.py,sha256=EQdVYHmW85_pZdHZB3N8pEi0GiadCCkF3z_oqohA7B0,71161
28
28
  topologicpy/Wire.py,sha256=9EJE0Iq3nGz5X7Suy6xxjmuOpfV49By6WH98UAL_7m4,153532
29
29
  topologicpy/__init__.py,sha256=D7ky87CAQMiS2KE6YLvcTLkTgA2PY7rASe6Z23pjp9k,872
30
- topologicpy/version.py,sha256=7JOl9BjjPK0ib5M5rAuj9I5xjEoYF6YsFAS_dvAYEzg,23
31
- topologicpy-0.7.43.dist-info/LICENSE,sha256=BRNw73R2WdDBICtwhI3wm3cxsaVqLTAGuRwrTltcfxs,1068
32
- topologicpy-0.7.43.dist-info/METADATA,sha256=NCprd1lCZf1afHBHxA5uol5btFYvJFZeiIdoIJtQ5aI,10916
33
- topologicpy-0.7.43.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
34
- topologicpy-0.7.43.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
35
- topologicpy-0.7.43.dist-info/RECORD,,
30
+ topologicpy/version.py,sha256=M-0kJd97wNsL6CZrI2htV9HFPeXVaDWIQkIhzYnuc-Q,23
31
+ topologicpy-0.7.45.dist-info/LICENSE,sha256=BRNw73R2WdDBICtwhI3wm3cxsaVqLTAGuRwrTltcfxs,1068
32
+ topologicpy-0.7.45.dist-info/METADATA,sha256=4AAcme8ANBpGbJpb0G9Rw12I7lL95TmhfYP_GTz9sK4,10916
33
+ topologicpy-0.7.45.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
34
+ topologicpy-0.7.45.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
35
+ topologicpy-0.7.45.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.2.0)
2
+ Generator: setuptools (73.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5