topologicpy 0.8.48__py3-none-any.whl → 0.8.50__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/CellComplex.py +1 -1
- topologicpy/Graph.py +290 -11
- topologicpy/Plotly.py +1 -1
- topologicpy/Shell.py +137 -0
- topologicpy/Topology.py +31 -18
- topologicpy/Wire.py +1 -1
- topologicpy/version.py +1 -1
- {topologicpy-0.8.48.dist-info → topologicpy-0.8.50.dist-info}/METADATA +1 -1
- {topologicpy-0.8.48.dist-info → topologicpy-0.8.50.dist-info}/RECORD +12 -12
- {topologicpy-0.8.48.dist-info → topologicpy-0.8.50.dist-info}/WHEEL +0 -0
- {topologicpy-0.8.48.dist-info → topologicpy-0.8.50.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.48.dist-info → topologicpy-0.8.50.dist-info}/top_level.txt +0 -0
topologicpy/CellComplex.py
CHANGED
@@ -296,7 +296,7 @@ class CellComplex():
|
|
296
296
|
offset = minOffset
|
297
297
|
|
298
298
|
while attempts < maxAttempts:
|
299
|
-
expanded_faces = [Face.ByOffset(f, offset=-offset) for f in faces]
|
299
|
+
expanded_faces = [Face.ByOffset(f, offset=-offset, silent=silent) for f in faces]
|
300
300
|
try:
|
301
301
|
cc = CellComplex.ByFaces(expanded_faces, silent=True)
|
302
302
|
if Topology.IsInstance(cc, "cellComplex"):
|
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
|
"""
|
@@ -8159,24 +8200,28 @@ class Graph:
|
|
8159
8200
|
Returns:
|
8160
8201
|
A numpy array representing the adjacency matrix.
|
8161
8202
|
"""
|
8203
|
+
|
8162
8204
|
|
8205
|
+
|
8163
8206
|
# Get the number of nodes from the edge list.
|
8164
|
-
|
8165
|
-
|
8166
|
-
|
8207
|
+
if len(edge_list) > 0:
|
8208
|
+
flat_list = Helper.Flatten(edge_list)
|
8209
|
+
flat_list = [x for x in flat_list if not x == None]
|
8210
|
+
num_nodes = max(flat_list) + 1
|
8167
8211
|
|
8168
|
-
|
8169
|
-
|
8212
|
+
# Create an adjacency matrix.
|
8213
|
+
adjacency_matrix = np.zeros((num_nodes, num_nodes))
|
8170
8214
|
|
8171
|
-
|
8172
|
-
|
8173
|
-
|
8174
|
-
|
8215
|
+
# Fill in the adjacency matrix.
|
8216
|
+
for edge in edge_list:
|
8217
|
+
adjacency_matrix[edge[0], edge[1]] = 1
|
8218
|
+
adjacency_matrix[edge[1], edge[0]] = 1
|
8175
8219
|
|
8176
|
-
|
8220
|
+
return adjacency_matrix
|
8221
|
+
else:
|
8222
|
+
return None
|
8177
8223
|
|
8178
8224
|
def tree_from_edge_list(edge_list, root_index=0):
|
8179
|
-
|
8180
8225
|
adj_matrix = edge_list_to_adjacency_matrix(edge_list)
|
8181
8226
|
num_nodes = adj_matrix.shape[0]
|
8182
8227
|
root = _Tree(str(root_index))
|
@@ -12457,7 +12502,241 @@ class Graph:
|
|
12457
12502
|
net.show_buttons()
|
12458
12503
|
net.show(path, notebook=notebook)
|
12459
12504
|
return None
|
12505
|
+
|
12506
|
+
@staticmethod
|
12507
|
+
def Quotient(topology,
|
12508
|
+
topologyType: str = "vertex",
|
12509
|
+
key: str = None,
|
12510
|
+
groupLabelKey: str = None,
|
12511
|
+
groupCountKey: str = "count",
|
12512
|
+
weighted: bool = False,
|
12513
|
+
edgeWeightKey: str = "weight",
|
12514
|
+
idKey: str = None,
|
12515
|
+
silent: bool = False):
|
12516
|
+
"""
|
12517
|
+
Construct the quotient graph induced by grouping sub-topologies (Cells/Faces/Edges/Vertices)
|
12518
|
+
by a dictionary value. Two groups are connected if any member of one is adjacent to any member
|
12519
|
+
of the other via Topology.AdjacentTopologies. If weighted=True, edge weights count the number
|
12520
|
+
of distinct member-level adjacencies across groups. See https://en.wikipedia.org/wiki/Quotient_graph
|
12521
|
+
|
12522
|
+
Parameters
|
12523
|
+
----------
|
12524
|
+
topology : topologic_core.Topology or topologic_core.Graph
|
12525
|
+
The input topology or graph.
|
12526
|
+
topologyType : str
|
12527
|
+
The type of subtopology for which to search. This can be one of "vertex", "edge", "face", "cell". It is case-insensitive.
|
12528
|
+
key : str , optional
|
12529
|
+
Dictionary key used to form groups. If None, all items fall into one group.
|
12530
|
+
groupLabelKey : str , optional
|
12531
|
+
Vertex-dictionary key storing the group label. Default is "group_label".
|
12532
|
+
groupCountKey : str , optional
|
12533
|
+
Vertex-dictionary key storing the group size. Default is "count".
|
12534
|
+
weighted : bool , optional
|
12535
|
+
If True, store counts of cross-group adjacencies on edges under edgeWeightKey. Default is False.
|
12536
|
+
edgeWeightKey : str , optional
|
12537
|
+
Edge-dictionary key storing the weight when weighted=True. Default "weight".
|
12538
|
+
idKey : str , optional
|
12539
|
+
Optional dictionary key that uniquely identifies each sub-topology. If provided and present
|
12540
|
+
on both members, lookup is O(1) without calling Topology.IsSame. If missing, falls back to Topology.IsSame. Default is None.
|
12541
|
+
silent : bool , optional
|
12542
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
12543
|
+
|
12544
|
+
Returns
|
12545
|
+
-------
|
12546
|
+
topologic_core.Graph
|
12547
|
+
"""
|
12548
|
+
from topologicpy.Topology import Topology
|
12549
|
+
from topologicpy.Dictionary import Dictionary
|
12550
|
+
from topologicpy.Vertex import Vertex
|
12551
|
+
from topologicpy.Edge import Edge
|
12552
|
+
from topologicpy.Graph import Graph
|
12553
|
+
|
12554
|
+
if not Topology.IsInstance(topology, "Topology") and not Topology.IsInstance(topology, "Graph"):
|
12555
|
+
if not silent:
|
12556
|
+
print("Graph.Quotient - Error: The input topology parameter is not a valid Topology or Graph. Returning None.")
|
12557
|
+
return None
|
12558
|
+
if topologyType.lower() not in {"vertex", "edge", "face", "cell"}:
|
12559
|
+
if not silent:
|
12560
|
+
print("Graph.Quotient - Error: topologyType must be one of 'Cell','Face','Edge','Vertex'. Returning None.")
|
12561
|
+
return None
|
12562
|
+
if not isinstance(key, str):
|
12563
|
+
if not silent:
|
12564
|
+
print("Graph.Quotient - Error: The input key parameter is not a valid string. Returning None.")
|
12565
|
+
return None
|
12566
|
+
if groupLabelKey == None:
|
12567
|
+
groupLabelKey = key
|
12568
|
+
if not isinstance(groupLabelKey, str):
|
12569
|
+
if not silent:
|
12570
|
+
print("Graph.Quotient - Error: The input groupLabelKey parameter is not a valid string. Returning None.")
|
12571
|
+
return None
|
12572
|
+
if not isinstance(groupCountKey, str):
|
12573
|
+
if not silent:
|
12574
|
+
print("Graph.Quotient - Error: The input groupCountKey parameter is not a valid string. Returning None.")
|
12575
|
+
return None
|
12576
|
+
if not isinstance(weighted, bool):
|
12577
|
+
if not silent:
|
12578
|
+
print("Graph.Quotient - Error: The input weighted parameter is not a valid boolean. Returning None.")
|
12579
|
+
return None
|
12580
|
+
if not isinstance(edgeWeightKey, str):
|
12581
|
+
if not silent:
|
12582
|
+
print("Graph.Quotient - Error: The input edgeWeightKey parameter is not a valid string. Returning None.")
|
12583
|
+
return None
|
12460
12584
|
|
12585
|
+
# 1) Collect sub-topologies
|
12586
|
+
getters = {
|
12587
|
+
"vertex": Topology.Vertices,
|
12588
|
+
"edge": Topology.Edges,
|
12589
|
+
"face": Topology.Faces,
|
12590
|
+
"cell": Topology.Cells,
|
12591
|
+
}
|
12592
|
+
subs = getters[topologyType.lower()](topology)
|
12593
|
+
if not subs:
|
12594
|
+
if not silent:
|
12595
|
+
print("Graph.Quotient - Error: No subtopologies found. Returning None.")
|
12596
|
+
return None
|
12597
|
+
|
12598
|
+
# 2) Optional O(1) index via a unique idKey in dictionaries
|
12599
|
+
def _get_dict(st):
|
12600
|
+
try:
|
12601
|
+
return Topology.Dictionary(st)
|
12602
|
+
except Exception:
|
12603
|
+
return None
|
12604
|
+
|
12605
|
+
id_index = {}
|
12606
|
+
if idKey is not None:
|
12607
|
+
for i, st in enumerate(subs):
|
12608
|
+
d = _get_dict(st)
|
12609
|
+
if d is None:
|
12610
|
+
continue
|
12611
|
+
try:
|
12612
|
+
uid = Dictionary.ValueAtKey(d, idKey)
|
12613
|
+
except Exception:
|
12614
|
+
uid = None
|
12615
|
+
if uid is not None and uid not in id_index:
|
12616
|
+
id_index[uid] = i # first seen wins
|
12617
|
+
|
12618
|
+
# 3) Labels for grouping
|
12619
|
+
def _label(st):
|
12620
|
+
if key is None:
|
12621
|
+
return None
|
12622
|
+
d = _get_dict(st)
|
12623
|
+
if d is None:
|
12624
|
+
return None
|
12625
|
+
try:
|
12626
|
+
return Dictionary.ValueAtKey(d, key)
|
12627
|
+
except Exception:
|
12628
|
+
return None
|
12629
|
+
|
12630
|
+
labels = [_label(st) for st in subs]
|
12631
|
+
|
12632
|
+
# 4) Partition indices by label
|
12633
|
+
groups = {}
|
12634
|
+
for i, lbl in enumerate(labels):
|
12635
|
+
groups.setdefault(lbl, []).append(i)
|
12636
|
+
|
12637
|
+
group_labels = list(groups.keys())
|
12638
|
+
label_to_group_idx = {lbl: gi for gi, lbl in enumerate(group_labels)}
|
12639
|
+
item_to_group_idx = {i: label_to_group_idx[lbl] for lbl, idxs in groups.items() for i in idxs}
|
12640
|
+
|
12641
|
+
# Helper to resolve neighbor index j for a given neighbor topology nb
|
12642
|
+
def _neighbor_index(nb):
|
12643
|
+
# Try idKey shortcut
|
12644
|
+
if idKey is not None:
|
12645
|
+
d = _get_dict(nb)
|
12646
|
+
if d is not None:
|
12647
|
+
try:
|
12648
|
+
uid = Dictionary.ValueAtKey(d, idKey)
|
12649
|
+
except Exception:
|
12650
|
+
uid = None
|
12651
|
+
if uid is not None:
|
12652
|
+
j = id_index.get(uid)
|
12653
|
+
if j is not None:
|
12654
|
+
return j
|
12655
|
+
# Fallback: linear scan using Topology.IsSame
|
12656
|
+
for j, st in enumerate(subs):
|
12657
|
+
try:
|
12658
|
+
if Topology.IsSame(nb, st):
|
12659
|
+
return j
|
12660
|
+
except Exception:
|
12661
|
+
continue
|
12662
|
+
return None
|
12663
|
+
|
12664
|
+
# 5) Group adjacency with optional weights
|
12665
|
+
# Use a set to ensure each unordered member-pair is counted once
|
12666
|
+
seen_member_pairs = set()
|
12667
|
+
group_edges = {} # (a,b) -> weight
|
12668
|
+
|
12669
|
+
for i, st in enumerate(subs):
|
12670
|
+
try:
|
12671
|
+
neighs = Topology.AdjacentTopologies(st, topology, topologyType)
|
12672
|
+
except Exception:
|
12673
|
+
neighs = []
|
12674
|
+
gi = item_to_group_idx[i]
|
12675
|
+
for nb in neighs:
|
12676
|
+
j = _neighbor_index(nb)
|
12677
|
+
if j is None or j == i:
|
12678
|
+
continue
|
12679
|
+
aij = (i, j) if i < j else (j, i)
|
12680
|
+
if aij in seen_member_pairs:
|
12681
|
+
continue
|
12682
|
+
seen_member_pairs.add(aij)
|
12683
|
+
|
12684
|
+
gj = item_to_group_idx[j]
|
12685
|
+
if gi == gj:
|
12686
|
+
continue
|
12687
|
+
a, b = (gi, gj) if gi < gj else (gj, gi)
|
12688
|
+
group_edges[(a, b)] = group_edges.get((a, b), 0) + 1
|
12689
|
+
|
12690
|
+
# 6) One vertex per group at mean of member centroids
|
12691
|
+
group_vertices = []
|
12692
|
+
for lbl in group_labels:
|
12693
|
+
idxs = groups[lbl]
|
12694
|
+
pts = []
|
12695
|
+
for i in idxs:
|
12696
|
+
try:
|
12697
|
+
c = Topology.Centroid(subs[i])
|
12698
|
+
pts.append(c)
|
12699
|
+
except Exception:
|
12700
|
+
pass
|
12701
|
+
if pts:
|
12702
|
+
try:
|
12703
|
+
xs = [Vertex.X(p) for p in pts]
|
12704
|
+
ys = [Vertex.Y(p) for p in pts]
|
12705
|
+
zs = [Vertex.Z(p) for p in pts]
|
12706
|
+
v = Vertex.ByCoordinates(sum(xs)/len(xs), sum(ys)/len(ys), sum(zs)/len(zs))
|
12707
|
+
except Exception:
|
12708
|
+
v = Vertex.ByCoordinates(0, 0, 0)
|
12709
|
+
else:
|
12710
|
+
v = Vertex.ByCoordinates(0, 0, 0)
|
12711
|
+
|
12712
|
+
try:
|
12713
|
+
d = Dictionary.ByKeysValues([groupLabelKey, groupCountKey], [lbl, len(idxs)])
|
12714
|
+
v = Topology.SetDictionary(v, d)
|
12715
|
+
except Exception:
|
12716
|
+
pass
|
12717
|
+
|
12718
|
+
group_vertices.append(v)
|
12719
|
+
|
12720
|
+
group_vertices = Vertex.Separate(group_vertices, minDistance = 0.1, strength=0.5, silent=silent)
|
12721
|
+
|
12722
|
+
# 7) Edges, with optional weights
|
12723
|
+
edges = []
|
12724
|
+
for (a, b), w in group_edges.items():
|
12725
|
+
try:
|
12726
|
+
e = Edge.ByStartVertexEndVertex(group_vertices[a], group_vertices[b])
|
12727
|
+
if weighted:
|
12728
|
+
try:
|
12729
|
+
d = Dictionary.ByKeysValues([edgeWeightKey], [w])
|
12730
|
+
e = Topology.SetDictionary(e, d)
|
12731
|
+
except Exception:
|
12732
|
+
pass
|
12733
|
+
edges.append(e)
|
12734
|
+
except Exception:
|
12735
|
+
continue
|
12736
|
+
|
12737
|
+
|
12738
|
+
return Graph.ByVerticesEdges(group_vertices, edges)
|
12739
|
+
|
12461
12740
|
@staticmethod
|
12462
12741
|
def RemoveEdge(graph, edge, tolerance=0.0001):
|
12463
12742
|
"""
|
topologicpy/Plotly.py
CHANGED
@@ -558,7 +558,7 @@ class Plotly:
|
|
558
558
|
if not temp_color == None:
|
559
559
|
colors[m] = Color.AnyToHex(temp_color)
|
560
560
|
if not labelKey == None:
|
561
|
-
labels[m] = Dictionary.ValueAtKey(d, key=labelKey, defaultValue=" ")
|
561
|
+
labels[m] = str(Dictionary.ValueAtKey(d, key=labelKey, defaultValue=" "))
|
562
562
|
if not sizeKey == None:
|
563
563
|
sizes[m] = float(Dictionary.ValueAtKey(d, key=sizeKey, defaultValue=sizes[m]))
|
564
564
|
if sizes[m] == None:
|
topologicpy/Shell.py
CHANGED
@@ -1097,6 +1097,143 @@ class Shell():
|
|
1097
1097
|
return True
|
1098
1098
|
return False
|
1099
1099
|
|
1100
|
+
@staticmethod
|
1101
|
+
def MobiusStrip(origin = None,
|
1102
|
+
radius: float=0.5,
|
1103
|
+
height: float=1,
|
1104
|
+
uSides=32,
|
1105
|
+
vSides=1,
|
1106
|
+
twists: int = 1,
|
1107
|
+
direction: list = [0, 0, 1],
|
1108
|
+
placement: str = "center",
|
1109
|
+
tolerance: float = 0.0001,
|
1110
|
+
silent: bool = False):
|
1111
|
+
|
1112
|
+
|
1113
|
+
"""
|
1114
|
+
Creates a Möbius strip. See: https://en.wikipedia.org/wiki/M%C3%B6bius_strip
|
1115
|
+
|
1116
|
+
Parameters
|
1117
|
+
----------
|
1118
|
+
origin : topologic_core.Vertex , optional
|
1119
|
+
The location of the origin of the Möbius strip. Default is None which results in the Möbius strip being placed at (0, 0, 0).
|
1120
|
+
radius : float , optional
|
1121
|
+
The radius of the Möbius strip. Default is 0.5.
|
1122
|
+
height : float , optional
|
1123
|
+
The height of the Möbius strip. Default is 1.
|
1124
|
+
uSides : int , optional
|
1125
|
+
The number of circle segments of the Möbius strip. Default is 16.
|
1126
|
+
vSides : int , optional
|
1127
|
+
The number of vertical segments of the Möbius strip. Default is 1.
|
1128
|
+
twists : int , optional
|
1129
|
+
The number of twists (multiples of a 180 degree rotation) of the Möbius strip. Default is 1.
|
1130
|
+
direction : list , optional
|
1131
|
+
The vector representing the up direction of the Möbius strip. Default is [0, 0, 1].
|
1132
|
+
placement : str , optional
|
1133
|
+
Not implemented. The description of the placement of the origin of the Möbius strip. This can be "bottom", "center", or "lowerleft". It is case insensitive. Default is "bottom".
|
1134
|
+
tolerance : float , optional
|
1135
|
+
The desired tolerance. Default is 0.0001.
|
1136
|
+
silent : bool , optional
|
1137
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
1138
|
+
|
1139
|
+
Returns
|
1140
|
+
-------
|
1141
|
+
topologic_core.Cell
|
1142
|
+
The created cell.
|
1143
|
+
|
1144
|
+
"""
|
1145
|
+
from topologicpy.Vertex import Vertex
|
1146
|
+
from topologicpy.Edge import Edge
|
1147
|
+
from topologicpy.Wire import Wire
|
1148
|
+
from topologicpy.Topology import Topology
|
1149
|
+
|
1150
|
+
if not isinstance(radius, int) and not isinstance(radius, float):
|
1151
|
+
if not silent:
|
1152
|
+
print("Shell.MobiusStrip - Error: The radius input parameter is not a valid number. Returning None.")
|
1153
|
+
return None
|
1154
|
+
if not isinstance(height, int) and not isinstance(height, float):
|
1155
|
+
if not silent:
|
1156
|
+
print("Shell.MobiusStrip - Error: The height input parameter is not a valid number. Returning None.")
|
1157
|
+
return None
|
1158
|
+
if not isinstance(uSides, int):
|
1159
|
+
if not silent:
|
1160
|
+
print("Shell.MobiusStrip - Error: The uSides input parameter is not a valid integer. Returning None.")
|
1161
|
+
return None
|
1162
|
+
if not isinstance(vSides, int):
|
1163
|
+
if not silent:
|
1164
|
+
print("Shell.MobiusStrip - Error: The vSides input parameter is not a valid integer. Returning None.")
|
1165
|
+
return None
|
1166
|
+
if not isinstance(twists, int):
|
1167
|
+
if not silent:
|
1168
|
+
print("Shell.MobiusStrip - Error: The twists input parameter is not a valid integer. Returning None.")
|
1169
|
+
return None
|
1170
|
+
if radius <= tolerance:
|
1171
|
+
if not silent:
|
1172
|
+
print("Shell.MobiusStrip - Error: The radius input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
|
1173
|
+
return None
|
1174
|
+
if height <= tolerance:
|
1175
|
+
if not silent:
|
1176
|
+
print("Shell.MobiusStrip - Error: The height input parameter must be a positive number greater than the tolerance input parameter. Returning None.")
|
1177
|
+
return None
|
1178
|
+
if uSides <= 3:
|
1179
|
+
if not silent:
|
1180
|
+
print("Shell.MobiusStrip - Error: The uSides input parameter must be a positive integer greater than 2. Returning None.")
|
1181
|
+
return None
|
1182
|
+
if vSides < 1:
|
1183
|
+
if not silent:
|
1184
|
+
print("Shell.MobiusStrip - Error: The vSides input parameter must be a positive integer greater than 0. Returning None.")
|
1185
|
+
return None
|
1186
|
+
if origin == None:
|
1187
|
+
origin = Vertex.Origin()
|
1188
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1189
|
+
if not silent:
|
1190
|
+
print("Shell.MobiusStrip - Error: The origin input parameter is not a valid topologic Vertex. Returning None.")
|
1191
|
+
return None
|
1192
|
+
if not isinstance(direction, list):
|
1193
|
+
if not silent:
|
1194
|
+
print("Shell.MobiusStrip - Error: The direction input parameter is not a valid list. Returning None.")
|
1195
|
+
return None
|
1196
|
+
if not len(direction) == 3:
|
1197
|
+
if not silent:
|
1198
|
+
print("Shell.MobiusStrip - Error: The direction input parameter is not a valid vector. Returning None.")
|
1199
|
+
return None
|
1200
|
+
|
1201
|
+
total_angle = 180*twists
|
1202
|
+
cir = Wire.Circle(origin=origin, radius=radius, sides=uSides)
|
1203
|
+
c_verts = Topology.Vertices(cir)
|
1204
|
+
wires = []
|
1205
|
+
for i, v in enumerate(c_verts):
|
1206
|
+
vb = Vertex.ByCoordinates(Vertex.X(v), Vertex.Y(v), -height*0.5)
|
1207
|
+
vt = Vertex.ByCoordinates(Vertex.X(v), Vertex.Y(v), height*0.5)
|
1208
|
+
e = Edge.ByVertices([vb, vt])
|
1209
|
+
d = Edge.Normal(Edge.ByVertices(Vertex.Origin(), v))
|
1210
|
+
angle = float(total_angle)/float(uSides)*float(i)
|
1211
|
+
e = Topology.Rotate(e, origin=v, axis=d, angle=angle)
|
1212
|
+
verts = []
|
1213
|
+
for j in range(vSides+1):
|
1214
|
+
vp = Edge.VertexByParameter(e, float(j)/float(vSides))
|
1215
|
+
verts.append(vp)
|
1216
|
+
w = Wire.ByVertices(verts, close=False, silent=True)
|
1217
|
+
wires.append(w)
|
1218
|
+
# Create the last wire
|
1219
|
+
if i == 0:
|
1220
|
+
e = Edge.ByVertices([vb, vt])
|
1221
|
+
e = Topology.Rotate(e, origin=v, axis=d, angle=total_angle)
|
1222
|
+
verts = []
|
1223
|
+
for j in range(vSides+1):
|
1224
|
+
vp = Edge.VertexByParameter(e, float(j)/float(vSides))
|
1225
|
+
verts.append(vp)
|
1226
|
+
last_wire = Wire.ByVertices(verts, close=False, silent=True)
|
1227
|
+
|
1228
|
+
wires.append(last_wire)
|
1229
|
+
m = Shell.ByWires(wires, silent=silent, tolerance=tolerance)
|
1230
|
+
if not Topology.IsInstance(m, "Shell"):
|
1231
|
+
if not silent:
|
1232
|
+
print("Shell.MobiusStrip - Error: Could not create a mobius strip. Returning None.")
|
1233
|
+
return None
|
1234
|
+
m = Topology.Orient(m, origin=origin, dirA=[0, 0, 1], dirB=direction)
|
1235
|
+
return m
|
1236
|
+
|
1100
1237
|
@staticmethod
|
1101
1238
|
def Paraboloid(origin= None, focalLength=0.125, width: float = 1, length: float = 1, uSides: int = 16, vSides: int = 16,
|
1102
1239
|
direction: list = [0, 0, 1], placement: str ="center", mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
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
|
-
|
374
|
-
|
375
|
-
|
376
|
+
if Topology.IsInstance(hostTopology, "graph"):
|
377
|
+
adjacentTopologies = Graph.AdjacentVertices(hostTopology, topology)
|
378
|
+
else:
|
376
379
|
try:
|
377
|
-
_ = topology.
|
380
|
+
_ = topology.AdjacentVertices(hostTopology, adjacentTopologies) # Hook to Core
|
378
381
|
except:
|
379
|
-
|
382
|
+
try:
|
383
|
+
_ = topology.Vertices(hostTopology, adjacentTopologies) # Hook to Core
|
384
|
+
except:
|
385
|
+
error = True
|
380
386
|
elif topologyType.lower() == "edge":
|
381
|
-
|
382
|
-
|
383
|
-
|
387
|
+
if Topology.IsInstance(hostTopology, "graph"):
|
388
|
+
adjacentTopologies = Graph.Edges(hostTopology, [topology])
|
389
|
+
print("Topology.AdjacentTopologies - adjacentTopologies:", adjacentTopologies)
|
390
|
+
else:
|
384
391
|
try:
|
385
|
-
_ =
|
392
|
+
_ = topologic.VertexUtility.AdjacentEdges(topology, hostTopology, adjacentTopologies) # Hook to Core
|
386
393
|
except:
|
387
|
-
|
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
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
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/Wire.py
CHANGED
@@ -3003,7 +3003,7 @@ class Wire():
|
|
3003
3003
|
for i in range(1, sides):
|
3004
3004
|
vertices.append(Edge.VertexByParameter(edge, i*unitDistance))
|
3005
3005
|
vertices.append(Edge.EndVertex(edge))
|
3006
|
-
return Wire.ByVertices(vertices,
|
3006
|
+
return Wire.ByVertices(vertices, close=False, tolerance=tolerance)
|
3007
3007
|
|
3008
3008
|
@staticmethod
|
3009
3009
|
def LShape(origin=None,
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.8.
|
1
|
+
__version__ = '0.8.50'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.50
|
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
|
@@ -3,7 +3,7 @@ topologicpy/Aperture.py,sha256=wNn5miB_IrGCBYuQ18HXQYRva20dUC3id4AJCulL7to,2723
|
|
3
3
|
topologicpy/BVH.py,sha256=JA4bb-9hgMfVZ_syzmSmTL3ueCq-0vMUGMPZxNcawAY,13023
|
4
4
|
topologicpy/CSG.py,sha256=09la1-xzS9vr-WnV7tpJ0I-mkZ-XY0MRSd5iB50Nfgw,15556
|
5
5
|
topologicpy/Cell.py,sha256=gldsBl3LnrvTRS4SnK9aAM8k_kS1aNovTjUNHxQRNKk,175319
|
6
|
-
topologicpy/CellComplex.py,sha256=
|
6
|
+
topologicpy/CellComplex.py,sha256=Kbz63rGeE08bJfMXFvB-AptoKHiaCK5OtiV1wz8Y-Fk,68081
|
7
7
|
topologicpy/Cluster.py,sha256=G49AuhJHQ1s819cB5MtVdmAGgkag19IC3dRP1ub1Wh4,58608
|
8
8
|
topologicpy/Color.py,sha256=hzSmgBWhiuYc55RSipkQNIgGtgyhC5BqY8AakNYEK-U,24486
|
9
9
|
topologicpy/Context.py,sha256=G3CwMvN8Jw2rnQRwB-n4MaQq_wLS0vPimbXKwsdMJ80,3055
|
@@ -12,27 +12,27 @@ 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=
|
15
|
+
topologicpy/Graph.py,sha256=Idp-Wmm_ziofg_mJyJHhw6Qm0xRd-etTzaVNxp3EreU,686857
|
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
|
19
19
|
topologicpy/Matrix.py,sha256=bOofT34G3YHu9aMIWx60YHAJga4R0GbDjsZBUD4Hu_k,22706
|
20
20
|
topologicpy/Neo4j.py,sha256=J8jU_mr5-mWC0Lg_D2dMjMlx1rY_eh8ks_aubUuTdWw,22319
|
21
|
-
topologicpy/Plotly.py,sha256=
|
21
|
+
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=
|
25
|
+
topologicpy/Shell.py,sha256=e6R7JdzYL1ubO0xXJs5P_UiiNHccN5SjQhQfGPPgHBg,96793
|
26
26
|
topologicpy/Speckle.py,sha256=-eiTqJugd7pHiHpD3pDUcDO6CGhVyPV14HFRzaqEoaw,18187
|
27
27
|
topologicpy/Sun.py,sha256=8S6dhCKfOhUGVny-jEk87Q08anLYMB1JEBKRGCklvbQ,36670
|
28
|
-
topologicpy/Topology.py,sha256=
|
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
|
-
topologicpy/Wire.py,sha256=
|
31
|
+
topologicpy/Wire.py,sha256=gjgQUGHdBdXUIijgZc_VIW0E39w-smaVhhdl0jF63fQ,230466
|
32
32
|
topologicpy/__init__.py,sha256=RMftibjgAnHB1vdL-muo71RwMS4972JCxHuRHOlU428,928
|
33
|
-
topologicpy/version.py,sha256=
|
34
|
-
topologicpy-0.8.
|
35
|
-
topologicpy-0.8.
|
36
|
-
topologicpy-0.8.
|
37
|
-
topologicpy-0.8.
|
38
|
-
topologicpy-0.8.
|
33
|
+
topologicpy/version.py,sha256=jLQwp8ZJ2hrMvKdSSwJuigGT_jHflNoJKrmd0A0MBrM,23
|
34
|
+
topologicpy-0.8.50.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
|
35
|
+
topologicpy-0.8.50.dist-info/METADATA,sha256=bOOGHTn6e-sOwgpqkBLm1YWvhnNNUMdjgfQZzqLHM9g,10535
|
36
|
+
topologicpy-0.8.50.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
37
|
+
topologicpy-0.8.50.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
38
|
+
topologicpy-0.8.50.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|