topologicpy 0.8.49__py3-none-any.whl → 0.8.51__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/Graph.py CHANGED
@@ -838,6 +838,47 @@ class Graph:
838
838
  adjList.append(tempRow)
839
839
  return adjList
840
840
 
841
+ @staticmethod
842
+ def AdjacentEdges(graph, edge, silent: bool = False):
843
+ """
844
+ Returns the list of edges connected to the input edge.
845
+
846
+ Parameters
847
+ ----------
848
+ graph : topologic_core.Graph
849
+ The input graph.
850
+ edge : topologic_core.Edge
851
+ the input edge.
852
+ silent : bool , optional
853
+ If set to True, error and warning messages are suppressed. Default is False.
854
+
855
+ Returns
856
+ -------
857
+ list
858
+ The list of adjacent edges.
859
+
860
+ """
861
+ from topologicpy.Edge import Edge
862
+ from topologicpy.Topology import Topology
863
+
864
+ if not Topology.IsInstance(graph, "Graph"):
865
+ if not silent:
866
+ print("Graph.AdjacentEdges - Error: The input graph is not a valid graph. Returning None.")
867
+ return None
868
+ if not Topology.IsInstance(edge, "Edge"):
869
+ if not silent:
870
+ print("Graph.AdjacentEdges - Error: The input edge is not a valid edge. Returning None.")
871
+ return None
872
+ edges = []
873
+ sv = Edge.StartVertex(edge)
874
+ ev = Edge.EndVertex(edge)
875
+ edges.extend(Graph.Edges(graph, [sv]))
876
+ edges.extend(Graph.Edges(graph, [ev]))
877
+ print(edges)
878
+ edges = [e for e in edges if not Topology.IsSame(e, edge)]
879
+ # Complete the algorithm here
880
+ return edges
881
+
841
882
  @staticmethod
842
883
  def AdjacentVertices(graph, vertex, silent: bool = False):
843
884
  """
@@ -6214,53 +6255,79 @@ class Graph:
6214
6255
  return scores
6215
6256
 
6216
6257
  @staticmethod
6217
- def Diameter(graph):
6258
+ def Diameter(graph, silent: bool = False):
6218
6259
  """
6219
- Returns the diameter of the input graph. See https://mathworld.wolfram.com/GraphDiameter.html.
6260
+ Returns the diameter of the input (unweighted, undirected) graph.
6261
+
6262
+ The diameter is the maximum, over all pairs of vertices, of the length of a
6263
+ shortest path between them. If the graph is disconnected, this returns the
6264
+ maximum finite eccentricity across connected components and prints a warning
6265
+ unless `silent=True`.
6220
6266
 
6221
6267
  Parameters
6222
6268
  ----------
6223
6269
  graph : topologic_core.Graph
6224
6270
  The input graph.
6271
+ silent : bool , optional
6272
+ If set to True, error and warning messages are suppressed. Default is False.
6225
6273
 
6226
6274
  Returns
6227
6275
  -------
6228
6276
  int
6229
- The diameter of the input graph.
6230
-
6277
+ The diameter of the input graph, or None if the graph is empty.
6231
6278
  """
6279
+ from collections import deque
6232
6280
  from topologicpy.Topology import Topology
6233
6281
 
6282
+ # Basic checks
6234
6283
  if not Topology.IsInstance(graph, "Graph"):
6235
- print("Graph.Diameter - Error: The input graph is not a valid graph. Returning None.")
6284
+ if not silent:
6285
+ print("Graph.Diameter - Error: The input graph is not a valid graph. Returning None.")
6236
6286
  return None
6237
-
6238
- def dfs(node, visited):
6239
- visited.add(node)
6240
- max_depth = 0
6241
- farthest_node = node
6242
- for neighbor in adj_dict[node]:
6243
- if neighbor not in visited:
6244
- depth, end_node = dfs(neighbor, visited)
6245
- if depth + 1 > max_depth:
6246
- max_depth = depth + 1
6247
- farthest_node = end_node
6248
- return max_depth, farthest_node
6249
6287
 
6250
- adj_dict = Graph.AdjacencyDictionary(graph, includeWeights=False)
6251
-
6252
- # Step 1: Pick an arbitrary starting node (first node in the graph)
6253
- start_node = next(iter(adj_dict))
6254
-
6255
- # Step 2: Run DFS to find the farthest node from the start_node
6256
- visited = set()
6257
- _, farthest_node = dfs(start_node, visited)
6258
-
6259
- # Step 3: Run DFS from the farthest node found to get the maximum depth
6260
- visited.clear()
6261
- diameter, _ = dfs(farthest_node, visited)
6288
+ # Build adjacency dictionary (as sets) and force undirected symmetry
6289
+ adj_raw = Graph.AdjacencyDictionary(graph, includeWeights=False)
6290
+ if not adj_raw: # empty graph
6291
+ if not silent:
6292
+ print("Graph.Diameter - Warning: The graph has no vertices. Returning None.")
6293
+ return None
6294
+
6295
+ adj = {u: set(neighbors) for u, neighbors in adj_raw.items()}
6296
+ # Ensure symmetry (in case the underlying graph stored directed edges)
6297
+ for u, nbrs in list(adj.items()):
6298
+ for v in nbrs:
6299
+ adj.setdefault(v, set()).add(u)
6300
+ adj[u].add(v)
6301
+
6302
+ def bfs_eccentricity(start):
6303
+ """Return distances map from start and its eccentricity."""
6304
+ dist = {start: 0}
6305
+ q = deque([start])
6306
+ while q:
6307
+ u = q.popleft()
6308
+ for v in adj.get(u, ()):
6309
+ if v not in dist:
6310
+ dist[v] = dist[u] + 1
6311
+ q.append(v)
6312
+ ecc = max(dist.values()) if dist else 0
6313
+ return dist, ecc
6314
+
6315
+ diameter = 0
6316
+ n = len(adj)
6317
+ disconnected = False
6318
+
6319
+ for s in adj:
6320
+ dist, ecc = bfs_eccentricity(s)
6321
+ if len(dist) < n:
6322
+ disconnected = True
6323
+ if ecc > diameter:
6324
+ diameter = ecc
6325
+
6326
+ if disconnected and not silent:
6327
+ print("Graph.Diameter - Warning: The graph is disconnected. Returning the maximum finite diameter across connected components.")
6262
6328
 
6263
6329
  return diameter
6330
+
6264
6331
 
6265
6332
  @staticmethod
6266
6333
  def Dictionary(graph):
@@ -12464,7 +12531,7 @@ class Graph:
12464
12531
 
12465
12532
  @staticmethod
12466
12533
  def Quotient(topology,
12467
- topologyType: str = None,
12534
+ topologyType: str = "vertex",
12468
12535
  key: str = None,
12469
12536
  groupLabelKey: str = None,
12470
12537
  groupCountKey: str = "count",
@@ -12480,8 +12547,8 @@ class Graph:
12480
12547
 
12481
12548
  Parameters
12482
12549
  ----------
12483
- topology : topologic_core.Topology
12484
- The input topology.
12550
+ topology : topologic_core.Topology or topologic_core.Graph
12551
+ The input topology or graph.
12485
12552
  topologyType : str
12486
12553
  The type of subtopology for which to search. This can be one of "vertex", "edge", "face", "cell". It is case-insensitive.
12487
12554
  key : str , optional
@@ -12510,9 +12577,9 @@ class Graph:
12510
12577
  from topologicpy.Edge import Edge
12511
12578
  from topologicpy.Graph import Graph
12512
12579
 
12513
- if not Topology.IsInstance(topology, "Topology"):
12580
+ if not Topology.IsInstance(topology, "Topology") and not Topology.IsInstance(topology, "Graph"):
12514
12581
  if not silent:
12515
- print("Graph.Quotient - Error: The input topology parameter is not a valid Topology. Returning None.")
12582
+ print("Graph.Quotient - Error: The input topology parameter is not a valid Topology or Graph. Returning None.")
12516
12583
  return None
12517
12584
  if topologyType.lower() not in {"vertex", "edge", "face", "cell"}:
12518
12585
  if not silent:
@@ -12676,6 +12743,8 @@ class Graph:
12676
12743
 
12677
12744
  group_vertices.append(v)
12678
12745
 
12746
+ group_vertices = Vertex.Separate(group_vertices, minDistance = 0.1, strength=0.5, silent=silent)
12747
+
12679
12748
  # 7) Edges, with optional weights
12680
12749
  edges = []
12681
12750
  for (a, b), w in group_edges.items():
@@ -12691,6 +12760,7 @@ class Graph:
12691
12760
  except Exception:
12692
12761
  continue
12693
12762
 
12763
+
12694
12764
  return Graph.ByVerticesEdges(group_vertices, edges)
12695
12765
 
12696
12766
  @staticmethod
@@ -13410,7 +13480,85 @@ class Graph:
13410
13480
  queue.append((neighbor, distance + 1))
13411
13481
 
13412
13482
  return None # Target not reachable
13413
-
13483
+
13484
+ @staticmethod
13485
+ def Tietze(radius: float = 0.5, height: float = 1):
13486
+ """
13487
+ Creates a Tietze's graph mapped on a mobius strip of the same input radius and height. See https://en.wikipedia.org/wiki/Tietze%27s_graph
13488
+
13489
+ Parameters
13490
+ ----------
13491
+ radius : float , optional
13492
+ The desired radius of the mobius strip on which the graph is mapped. Default is 0.5.
13493
+ height : float , optional
13494
+ The desired height of the mobius strip on which the graph is mapped. Default is 1.
13495
+
13496
+ Returns
13497
+ -------
13498
+ topologicpy.Graph
13499
+ The created Tietze's graph.
13500
+
13501
+ """
13502
+ from topologicpy.Dictionary import Dictionary
13503
+ from topologicpy.Edge import Edge
13504
+ from topologicpy.Shell import Shell
13505
+ from topologicpy.Graph import Graph
13506
+ from topologicpy.Topology import Topology
13507
+
13508
+ m = Shell.MobiusStrip(radius=radius, height=height, uSides=12, vSides=3)
13509
+ eb = Shell.ExternalBoundary(m)
13510
+ verts = Topology.Vertices(eb)
13511
+ new_verts = []
13512
+ for i in range(0, len(verts), 2): #The mobius strip has 24 edges, we need half of that (12).
13513
+ new_verts.append(verts[i])
13514
+
13515
+ graph_edges = []
13516
+ for r in range(0,6):
13517
+ s = (r + 6)
13518
+ e = Edge.ByVertices(new_verts[r], new_verts[s])
13519
+ if r == 0:
13520
+ v1 = Edge.VertexByParameter(e, 2/3)
13521
+ v2 = Edge.EndVertex(e)
13522
+ e = Edge.ByVertices(v1, v2)
13523
+ elif r == 1:
13524
+ v3 = Edge.VertexByParameter(e, 1/3)
13525
+ v4 = Edge.VertexByParameter(e, 2/3)
13526
+ e = Edge.ByVertices(v3, v4)
13527
+ elif r == 2:
13528
+ v5 = Edge.StartVertex(e)
13529
+ v6 = Edge.VertexByParameter(e, 1/3)
13530
+ e = Edge.ByVertices(v5, v6)
13531
+ elif r == 3:
13532
+ v7 = Edge.VertexByParameter(e, 1/3)
13533
+ v8 = Edge.VertexByParameter(e, 2/3)
13534
+ e = Edge.ByVertices(v7, v8)
13535
+ elif r == 4:
13536
+ v9 = Edge.VertexByParameter(e, 2/3)
13537
+ v10 = Edge.EndVertex(e)
13538
+ e = Edge.ByVertices(v9, v10)
13539
+ elif r == 5:
13540
+ v11 = Edge.VertexByParameter(e, 1/3)
13541
+ v12 = Edge.VertexByParameter(e, 2/3)
13542
+ e = Edge.ByVertices(v11, v12)
13543
+ graph_edges.append(e)
13544
+
13545
+ graph_vertices= [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12]
13546
+ graph_edges.append(Edge.ByVertices(v10, v2))
13547
+ graph_edges.append(Edge.ByVertices(v5, v10))
13548
+ graph_edges.append(Edge.ByVertices(v2, v5))
13549
+ graph_edges.append(Edge.ByVertices(v1, v4))
13550
+ graph_edges.append(Edge.ByVertices(v4, v8))
13551
+ graph_edges.append(Edge.ByVertices(v8, v9))
13552
+ graph_edges.append(Edge.ByVertices(v9, v12))
13553
+ graph_edges.append(Edge.ByVertices(v12, v3))
13554
+ graph_edges.append(Edge.ByVertices(v3, v6))
13555
+ graph_edges.append(Edge.ByVertices(v6, v7))
13556
+ graph_edges.append(Edge.ByVertices(v7, v11))
13557
+ graph_edges.append(Edge.ByVertices(v11, v1))
13558
+ graph_edges = [Edge.Reverse(e) for e in graph_edges] #This makes them look better when sagitta is applied.
13559
+ graph = Graph.ByVerticesEdges(graph_vertices, graph_edges)
13560
+ return graph
13561
+
13414
13562
  @staticmethod
13415
13563
  def TopologicalDistance(graph, vertexA, vertexB, tolerance=0.0001):
13416
13564
  """
topologicpy/Shell.py CHANGED
@@ -1175,7 +1175,7 @@ class Shell():
1175
1175
  if not silent:
1176
1176
  print("Shell.MobiusStrip - Error: The height input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
1177
1177
  return None
1178
- if uSides <= 3:
1178
+ if uSides < 3:
1179
1179
  if not silent:
1180
1180
  print("Shell.MobiusStrip - Error: The uSides input parameter must be a positive integer greater than 2. Returning None.")
1181
1181
  return None
topologicpy/Topology.py CHANGED
@@ -339,7 +339,7 @@ class Topology():
339
339
 
340
340
  Parameters
341
341
  ----------
342
- topology : topologic_core.Topology
342
+ topology : topologic_core.Topology or topologic_core.graph
343
343
  The input topology.
344
344
  hostTopology : topologic_core.Topology
345
345
  The host topology in which to search.
@@ -352,11 +352,14 @@ class Topology():
352
352
  The list of adjacent topologies.
353
353
 
354
354
  """
355
+
356
+ from topologicpy.Graph import Graph
357
+
355
358
  if not Topology.IsInstance(topology, "Topology"):
356
359
  print("Topology.AdjacentTopologies - Error: the input topology parameter is not a valid topology. Returning None.")
357
360
  return None
358
- if not Topology.IsInstance(hostTopology, "Topology"):
359
- print("Topology.AdjacentTopologies - Error: the input hostTopology parameter is not a valid topology. Returning None.")
361
+ if not Topology.IsInstance(hostTopology, "Topology") and not Topology.IsInstance(hostTopology, "Graph"):
362
+ print("Topology.AdjacentTopologies - Error: the input hostTopology parameter is not a valid topology or graph. Returning None.")
360
363
  return None
361
364
  if not topologyType:
362
365
  topologyType = Topology.TypeAsString(topology).lower()
@@ -370,21 +373,28 @@ class Topology():
370
373
  error = False
371
374
  if Topology.IsInstance(topology, "Vertex"):
372
375
  if topologyType.lower() == "vertex":
373
- try:
374
- _ = topology.AdjacentVertices(hostTopology, adjacentTopologies) # Hook to Core
375
- except:
376
+ if Topology.IsInstance(hostTopology, "graph"):
377
+ adjacentTopologies = Graph.AdjacentVertices(hostTopology, topology)
378
+ else:
376
379
  try:
377
- _ = topology.Vertices(hostTopology, adjacentTopologies) # Hook to Core
380
+ _ = topology.AdjacentVertices(hostTopology, adjacentTopologies) # Hook to Core
378
381
  except:
379
- error = True
382
+ try:
383
+ _ = topology.Vertices(hostTopology, adjacentTopologies) # Hook to Core
384
+ except:
385
+ error = True
380
386
  elif topologyType.lower() == "edge":
381
- try:
382
- _ = topologic.VertexUtility.AdjacentEdges(topology, hostTopology, adjacentTopologies) # Hook to Core
383
- except:
387
+ if Topology.IsInstance(hostTopology, "graph"):
388
+ adjacentTopologies = Graph.Edges(hostTopology, [topology])
389
+ print("Topology.AdjacentTopologies - adjacentTopologies:", adjacentTopologies)
390
+ else:
384
391
  try:
385
- _ = topology.Edges(hostTopology, adjacentTopologies) # Hook to Core
392
+ _ = topologic.VertexUtility.AdjacentEdges(topology, hostTopology, adjacentTopologies) # Hook to Core
386
393
  except:
387
- error = True
394
+ try:
395
+ _ = topology.Edges(hostTopology, adjacentTopologies) # Hook to Core
396
+ except:
397
+ error = True
388
398
  elif topologyType.lower() == "wire":
389
399
  try:
390
400
  _ = topologic.VertexUtility.AdjacentWires(topology, hostTopology, adjacentTopologies) # Hook to Core
@@ -432,10 +442,13 @@ class Topology():
432
442
  except:
433
443
  error = True
434
444
  elif topologyType.lower() == "edge":
435
- try:
436
- _ = topology.AdjacentEdges(hostTopology, adjacentTopologies) # Hook to Core
437
- except:
438
- error = True
445
+ if Topology.IsInstance(hostTopology, "graph"):
446
+ adjacentTopologies = Graph.AdjacentEdges(hostTopology, topology)
447
+ else:
448
+ try:
449
+ _ = topology.AdjacentEdges(hostTopology, adjacentTopologies) # Hook to Core
450
+ except:
451
+ error = True
439
452
  elif topologyType.lower() == "wire":
440
453
  try:
441
454
  _ = topologic.EdgeUtility.AdjacentWires(topology, adjacentTopologies) # Hook to Core
@@ -5391,7 +5404,7 @@ class Topology():
5391
5404
  tVertices = []
5392
5405
  if transposeAxes:
5393
5406
  for v in vertices:
5394
- tVertices.append([v[0], v[2], v[1]])
5407
+ tVertices.append([v[0], -v[2], v[1]])
5395
5408
  vertices = tVertices
5396
5409
  for v in vertices:
5397
5410
  lines.append("v " + str(v[0]) + " " + str(v[1]) + " " + str(v[2]))
topologicpy/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.8.49'
1
+ __version__ = '0.8.51'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: topologicpy
3
- Version: 0.8.49
3
+ Version: 0.8.51
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
@@ -12,7 +12,7 @@ topologicpy/Dictionary.py,sha256=Z4YQ88tONWd-0X0dENQ8IZqIOa9mbBqhJkTBsHmft2g,446
12
12
  topologicpy/Edge.py,sha256=DifItuyabFDUFC7CVMlt2DeMFMNaGOqCg43iU9CPP0A,74029
13
13
  topologicpy/EnergyModel.py,sha256=IiBJNx7F9-8TPMaQn1iQON1ZtTv2nT5kbZHxM_gBCTQ,53773
14
14
  topologicpy/Face.py,sha256=aX9EcR3JGbLITElhd25J0Z8m9U8KkmbYivGg3oZN-Uw,202296
15
- topologicpy/Graph.py,sha256=vK5mj90cc_cwC5suodSuYDrXCX3njp_SV4SiTyQzvuE,685271
15
+ topologicpy/Graph.py,sha256=o6aK18tCTkfzsNFOTAU-wIPG2p3g_vpm6n7YHc44bYU,691239
16
16
  topologicpy/Grid.py,sha256=3OsBMyHh4w8gpFOTMKHMNTpo62V0CwRNu5cwm87yDUA,18421
17
17
  topologicpy/Helper.py,sha256=aGmndgmEztjVNU-wW9OoHDel7wzapprM0TjA7f2AoS8,31188
18
18
  topologicpy/Honeybee.py,sha256=C7Am0kCK3a5rt7Jpu2EIgqeR114ZJWtsx4_DBcr5hQA,21716
@@ -22,17 +22,17 @@ topologicpy/Plotly.py,sha256=RXGeEBwVs8unJaT9vv_FBmAFfKd-1Z5x3V8oeKE43Bs,122924
22
22
  topologicpy/Polyskel.py,sha256=oVfM4lqSMPTjnkHfsRU9VI8Blt6Vf0LVPkD9ebz7Wmw,27082
23
23
  topologicpy/PyG.py,sha256=wOsoBFxMgwZYWjj86OMkz_PJuQ02locV_djhSDD6dVc,109644
24
24
  topologicpy/ShapeGrammar.py,sha256=KYsKDLXWdflAcYMAIz84AUF-GMkbTmaBDd2-ovbilqU,23336
25
- topologicpy/Shell.py,sha256=e6R7JdzYL1ubO0xXJs5P_UiiNHccN5SjQhQfGPPgHBg,96793
25
+ topologicpy/Shell.py,sha256=ioO4raCJfXtYldQg-adpcLVeJPEA6od6cAA5ro7t6r4,96792
26
26
  topologicpy/Speckle.py,sha256=-eiTqJugd7pHiHpD3pDUcDO6CGhVyPV14HFRzaqEoaw,18187
27
27
  topologicpy/Sun.py,sha256=8S6dhCKfOhUGVny-jEk87Q08anLYMB1JEBKRGCklvbQ,36670
28
- topologicpy/Topology.py,sha256=x6NTJ8AFIeFq3emZRT7FA_6NgNd-aavd4i9ws704AAU,470541
28
+ topologicpy/Topology.py,sha256=MoEszjDhEiCVYTO4IFxYsYjYj4Vg5TnWUcnoPMNj-Nc,471350
29
29
  topologicpy/Vector.py,sha256=pEC8YY3TeHGfGdeNgvdHjgMDwxGabp5aWjwYC1HSvMk,42236
30
30
  topologicpy/Vertex.py,sha256=0f6HouARKaCuxhdxsUEYi8T9giJycnWhQ8Cn70YILBA,84885
31
31
  topologicpy/Wire.py,sha256=gjgQUGHdBdXUIijgZc_VIW0E39w-smaVhhdl0jF63fQ,230466
32
32
  topologicpy/__init__.py,sha256=RMftibjgAnHB1vdL-muo71RwMS4972JCxHuRHOlU428,928
33
- topologicpy/version.py,sha256=QtAkT5hlIePCtadXLl4JDdKbyvuiJ4-dBo60LPK6aDE,23
34
- topologicpy-0.8.49.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
35
- topologicpy-0.8.49.dist-info/METADATA,sha256=xrO1G5MVgzF8yZXxfihp6syuWrK7z_aBao9_chfUw6U,10535
36
- topologicpy-0.8.49.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
- topologicpy-0.8.49.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
38
- topologicpy-0.8.49.dist-info/RECORD,,
33
+ topologicpy/version.py,sha256=xWa9BLlvIYvhh3MnyCUV3ug10L4hsf2fDMNf9z_dCY4,23
34
+ topologicpy-0.8.51.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
35
+ topologicpy-0.8.51.dist-info/METADATA,sha256=6kYuhs7iebTG3MIvoPQyA558AmaRzFkRce7CKgKBgr0,10535
36
+ topologicpy-0.8.51.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
+ topologicpy-0.8.51.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
38
+ topologicpy-0.8.51.dist-info/RECORD,,