topologicpy 0.7.61__py3-none-any.whl → 0.7.63__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/Cluster.py +26 -5
- topologicpy/Edge.py +24 -9
- topologicpy/Face.py +7 -1
- topologicpy/Graph.py +5 -3
- topologicpy/Neo4j.py +13 -13
- topologicpy/Plotly.py +7 -3
- topologicpy/Topology.py +4 -2
- topologicpy/Wire.py +221 -33
- topologicpy/version.py +1 -1
- {topologicpy-0.7.61.dist-info → topologicpy-0.7.63.dist-info}/METADATA +2 -2
- {topologicpy-0.7.61.dist-info → topologicpy-0.7.63.dist-info}/RECORD +14 -14
- {topologicpy-0.7.61.dist-info → topologicpy-0.7.63.dist-info}/LICENSE +0 -0
- {topologicpy-0.7.61.dist-info → topologicpy-0.7.63.dist-info}/WHEEL +0 -0
- {topologicpy-0.7.61.dist-info → topologicpy-0.7.63.dist-info}/top_level.txt +0 -0
topologicpy/Cluster.py
CHANGED
@@ -165,29 +165,50 @@ class Cluster():
|
|
165
165
|
from topologicpy.Dictionary import Dictionary
|
166
166
|
from topologicpy.Topology import Topology
|
167
167
|
from topologicpy.Helper import Helper
|
168
|
+
import inspect
|
168
169
|
|
169
170
|
if len(args) == 0:
|
170
|
-
|
171
|
+
if not silent:
|
172
|
+
print("Cluster.ByTopologies - Error: The input topologies parameter is an empty list. Returning None.")
|
173
|
+
curframe = inspect.currentframe()
|
174
|
+
calframe = inspect.getouterframes(curframe, 2)
|
175
|
+
print('caller name:', calframe[1][3])
|
171
176
|
return None
|
172
177
|
if len(args) == 1:
|
173
178
|
topologies = args[0]
|
174
179
|
if isinstance(topologies, list):
|
175
180
|
if len(topologies) == 0:
|
176
|
-
|
181
|
+
if not silent:
|
182
|
+
print("Cluster.ByTopologies - Error: The input topologies parameter is an empty list. Returning None.")
|
183
|
+
curframe = inspect.currentframe()
|
184
|
+
calframe = inspect.getouterframes(curframe, 2)
|
185
|
+
print('caller name:', calframe[1][3])
|
177
186
|
return None
|
178
187
|
else:
|
179
188
|
topologyList = [x for x in topologies if Topology.IsInstance(x, "Topology")]
|
180
189
|
if len(topologies) == 0:
|
181
|
-
|
190
|
+
if not silent:
|
191
|
+
print("Cluster.ByTopologies - Error: The input topologies parameter does not contain any valid topologies. Returning None.")
|
192
|
+
curframe = inspect.currentframe()
|
193
|
+
calframe = inspect.getouterframes(curframe, 2)
|
194
|
+
print('caller name:', calframe[1][3])
|
182
195
|
return None
|
183
196
|
else:
|
184
|
-
|
197
|
+
if not silent:
|
198
|
+
print("Cluster.ByTopologies - Warning: The input topologies parameter contains only one topology. Returning the same topology.")
|
199
|
+
curframe = inspect.currentframe()
|
200
|
+
calframe = inspect.getouterframes(curframe, 2)
|
201
|
+
print('caller name:', calframe[1][3])
|
185
202
|
return topologies
|
186
203
|
else:
|
187
204
|
topologyList = Helper.Flatten(list(args))
|
188
205
|
topologyList = [x for x in topologyList if Topology.IsInstance(x, "Topology")]
|
189
206
|
if len(topologyList) == 0:
|
190
|
-
|
207
|
+
if not silent:
|
208
|
+
print("Cluster.ByTopologies - Error: The input parameters do not contain any valid topologies. Returning None.")
|
209
|
+
curframe = inspect.currentframe()
|
210
|
+
calframe = inspect.getouterframes(curframe, 2)
|
211
|
+
print('caller name:', calframe[1][3])
|
191
212
|
return None
|
192
213
|
cluster = topologic.Cluster.ByTopologies(topologyList, False) # Hook to Core
|
193
214
|
dictionaries = []
|
topologicpy/Edge.py
CHANGED
@@ -293,7 +293,8 @@ class Edge():
|
|
293
293
|
import inspect
|
294
294
|
|
295
295
|
if len(args) == 0:
|
296
|
-
|
296
|
+
if not silent:
|
297
|
+
print("Edge.ByVertices - Error: The input vertices parameter is an empty list. Returning None.")
|
297
298
|
return None
|
298
299
|
if len(args) == 1:
|
299
300
|
vertices = args[0]
|
@@ -1107,7 +1108,7 @@ class Edge():
|
|
1107
1108
|
return Edge.Direction(normal_edge)
|
1108
1109
|
|
1109
1110
|
@staticmethod
|
1110
|
-
def NormalEdge(edge, length: float = 1.0, u: float = 0.5, angle: float = 0.0):
|
1111
|
+
def NormalEdge(edge, length: float = 1.0, u: float = 0.5, angle: float = 0.0, tolerance: float = 0.0001, silent: bool = False):
|
1111
1112
|
"""
|
1112
1113
|
Returns the normal (perpendicular) vector to the input edge as an edge.
|
1113
1114
|
|
@@ -1125,7 +1126,11 @@ class Edge():
|
|
1125
1126
|
angle : float , optional
|
1126
1127
|
The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge
|
1127
1128
|
by the angle value around the axis defined by the input edge. The default is 0.0.
|
1128
|
-
|
1129
|
+
tolerance : float , optional
|
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.
|
1133
|
+
|
1129
1134
|
Returns
|
1130
1135
|
-------
|
1131
1136
|
topologic_core.Edge
|
@@ -1153,8 +1158,13 @@ class Edge():
|
|
1153
1158
|
# Otherwise, calculate the normal by crossing with the Z-axis
|
1154
1159
|
z_axis = np.array([0, 0, 1])
|
1155
1160
|
normal_vector = np.cross(direction_vector, z_axis)
|
1161
|
+
|
1162
|
+
# Check if the normal vector is effectively zero before normalization
|
1163
|
+
if np.isclose(norm(normal_vector), 0):
|
1164
|
+
return normal_vector
|
1156
1165
|
|
1157
|
-
|
1166
|
+
# Normalize the normal vector
|
1167
|
+
normal_vector /= norm(normal_vector)
|
1158
1168
|
return normal_vector
|
1159
1169
|
|
1160
1170
|
def calculate_normal_line(start_vertex, end_vertex):
|
@@ -1168,10 +1178,12 @@ class Edge():
|
|
1168
1178
|
return start_vertex, normal_end_vertex
|
1169
1179
|
|
1170
1180
|
if not Topology.IsInstance(edge, "Edge"):
|
1171
|
-
|
1181
|
+
if not silent:
|
1182
|
+
print("Edge.NormalEdge - Error: The input edge parameter is not a valid edge. Returning None.")
|
1172
1183
|
return None
|
1173
1184
|
if length <= 0.0:
|
1174
|
-
|
1185
|
+
if not silent:
|
1186
|
+
print("Edge.NormalEdge - Error: The input length parameter is not a positive number greater than zero. Returning None.")
|
1175
1187
|
return None
|
1176
1188
|
|
1177
1189
|
# Get start and end vertex coordinates
|
@@ -1186,10 +1198,13 @@ class Edge():
|
|
1186
1198
|
ev = Vertex.ByCoordinates(list(normal_line_end))
|
1187
1199
|
|
1188
1200
|
# Create an edge from the start to the end of the normal vector
|
1189
|
-
normal_edge = Edge.ByVertices([sv, ev])
|
1190
|
-
|
1201
|
+
normal_edge = Edge.ByVertices([sv, ev], tolerance=tolerance, silent=silent)
|
1202
|
+
if normal_edge == None:
|
1203
|
+
if not silent:
|
1204
|
+
print("Edge.NormalEdge - Error: Could not create edge. Returning None.")
|
1205
|
+
return None
|
1191
1206
|
# Set the length of the normal edge
|
1192
|
-
normal_edge = Edge.SetLength(normal_edge, length, bothSides=False)
|
1207
|
+
normal_edge = Edge.SetLength(normal_edge, length, bothSides=False, tolerance=tolerance)
|
1193
1208
|
|
1194
1209
|
# Rotate the normal edge around the input edge by the specified angle
|
1195
1210
|
edge_direction = Edge.Direction(edge)
|
topologicpy/Face.py
CHANGED
@@ -665,7 +665,7 @@ class Face():
|
|
665
665
|
from topologicpy.Cluster import Cluster
|
666
666
|
from topologicpy.Topology import Topology
|
667
667
|
from topologicpy.Dictionary import Dictionary
|
668
|
-
import
|
668
|
+
import inspect
|
669
669
|
|
670
670
|
def triangulateWire(wire):
|
671
671
|
wire = Topology.RemoveCollinearEdges(wire)
|
@@ -678,10 +678,16 @@ class Face():
|
|
678
678
|
if not Topology.IsInstance(wire, "Wire"):
|
679
679
|
if not silent:
|
680
680
|
print("Face.ByWire - Error: The input wire parameter is not a valid topologic wire. Returning None.")
|
681
|
+
curframe = inspect.currentframe()
|
682
|
+
calframe = inspect.getouterframes(curframe, 2)
|
683
|
+
print('caller name:', calframe[1][3])
|
681
684
|
return None
|
682
685
|
if not Wire.IsClosed(wire):
|
683
686
|
if not silent:
|
684
687
|
print("Face.ByWire - Error: The input wire parameter is not a closed topologic wire. Returning None.")
|
688
|
+
curframe = inspect.currentframe()
|
689
|
+
calframe = inspect.getouterframes(curframe, 2)
|
690
|
+
print('caller name:', calframe[1][3])
|
685
691
|
return None
|
686
692
|
|
687
693
|
edges = Wire.Edges(wire)
|
topologicpy/Graph.py
CHANGED
@@ -8119,7 +8119,8 @@ class Graph:
|
|
8119
8119
|
camera=[-1.25, -1.25, 1.25],
|
8120
8120
|
center=[0, 0, 0], up=[0, 0, 1],
|
8121
8121
|
projection="perspective",
|
8122
|
-
tolerance=0.0001
|
8122
|
+
tolerance=0.0001,
|
8123
|
+
silent=False):
|
8123
8124
|
"""
|
8124
8125
|
Shows the graph using Plotly.
|
8125
8126
|
|
@@ -8218,9 +8219,10 @@ class Graph:
|
|
8218
8219
|
The desired up vector. The default is [0, 0, 1].
|
8219
8220
|
projection : str , optional
|
8220
8221
|
The desired type of projection. The options are "orthographic" or "perspective". It is case insensitive. The default is "perspective"
|
8221
|
-
|
8222
8222
|
tolerance : float , optional
|
8223
8223
|
The desired tolerance. The default is 0.0001.
|
8224
|
+
silent : bool , optional
|
8225
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
8224
8226
|
|
8225
8227
|
Returns
|
8226
8228
|
-------
|
@@ -8234,7 +8236,7 @@ class Graph:
|
|
8234
8236
|
print("Graph.Show - Error: The input graph is not a valid graph. Returning None.")
|
8235
8237
|
return None
|
8236
8238
|
|
8237
|
-
data= Plotly.DataByGraph(graph, sagitta=sagitta, absolute=absolute, sides=sides, vertexColor=vertexColor, vertexSize=vertexSize, vertexLabelKey=vertexLabelKey, vertexGroupKey=vertexGroupKey, vertexGroups=vertexGroups, showVertices=showVertices, showVertexLabels=showVertexLabels, showVertexLegend=showVertexLegend, edgeColor=edgeColor, edgeWidth=edgeWidth, edgeLabelKey=edgeLabelKey, edgeGroupKey=edgeGroupKey, edgeGroups=edgeGroups, showEdges=showEdges, showEdgeLabels=showEdgeLabels, showEdgeLegend=showEdgeLegend, colorScale=colorScale)
|
8239
|
+
data= Plotly.DataByGraph(graph, sagitta=sagitta, absolute=absolute, sides=sides, vertexColor=vertexColor, vertexSize=vertexSize, vertexLabelKey=vertexLabelKey, vertexGroupKey=vertexGroupKey, vertexGroups=vertexGroups, showVertices=showVertices, showVertexLabels=showVertexLabels, showVertexLegend=showVertexLegend, edgeColor=edgeColor, edgeWidth=edgeWidth, edgeLabelKey=edgeLabelKey, edgeGroupKey=edgeGroupKey, edgeGroups=edgeGroups, showEdges=showEdges, showEdgeLabels=showEdgeLabels, showEdgeLegend=showEdgeLegend, colorScale=colorScale, silent=silent)
|
8238
8240
|
fig = Plotly.FigureByData(data, width=width, height=height, xAxis=xAxis, yAxis=yAxis, zAxis=zAxis, axisSize=axisSize, backgroundColor=backgroundColor,
|
8239
8241
|
marginLeft=marginLeft, marginRight=marginRight, marginTop=marginTop, marginBottom=marginBottom, tolerance=tolerance)
|
8240
8242
|
Plotly.Show(fig, renderer=renderer, camera=camera, center=center, up=up, projection=projection)
|
topologicpy/Neo4j.py
CHANGED
@@ -42,8 +42,8 @@ class Neo4j:
|
|
42
42
|
|
43
43
|
Parameters
|
44
44
|
----------
|
45
|
-
neo4jGraph : neo4j._sync.driver.BoltDriver
|
46
|
-
The input neo4j
|
45
|
+
neo4jGraph : neo4j._sync.driver.BoltDriver or neo4jGraph, neo4j._sync.driver.Neo4jDriver
|
46
|
+
The input neo4j driver.
|
47
47
|
cypher : str, optional
|
48
48
|
If set to a non-empty string, a Cypher query will be run on the neo4j graph database to return a sub-graph. Default is None.
|
49
49
|
xMin : float, optional
|
@@ -164,8 +164,8 @@ class Neo4j:
|
|
164
164
|
|
165
165
|
Returns
|
166
166
|
-------
|
167
|
-
neo4j._sync.driver.BoltDriver
|
168
|
-
The returned neo4j
|
167
|
+
neo4j._sync.driver.BoltDriver or neo4jGraph, neo4j._sync.driver.Neo4jDriver
|
168
|
+
The returned neo4j driver.
|
169
169
|
|
170
170
|
"""
|
171
171
|
return GraphDatabase.driver(url, auth=(username, password))
|
@@ -177,13 +177,13 @@ class Neo4j:
|
|
177
177
|
|
178
178
|
Parameters
|
179
179
|
----------
|
180
|
-
neo4jGraph : neo4j._sync.driver.BoltDriver
|
181
|
-
The input neo4j
|
180
|
+
neo4jGraph : neo4j._sync.driver.BoltDriver or neo4jGraph, neo4j._sync.driver.Neo4jDriver
|
181
|
+
The input neo4j driver.
|
182
182
|
|
183
183
|
Returns
|
184
184
|
-------
|
185
|
-
neo4j._sync.driver.BoltDriver
|
186
|
-
The returned neo4j
|
185
|
+
neo4j._sync.driver.BoltDriver or neo4jGraph, neo4j._sync.driver.Neo4jDriver
|
186
|
+
The returned neo4j driver.
|
187
187
|
|
188
188
|
"""
|
189
189
|
with neo4jGraph.session() as session:
|
@@ -223,8 +223,8 @@ class Neo4j:
|
|
223
223
|
|
224
224
|
Parameters
|
225
225
|
----------
|
226
|
-
neo4jGraph : neo4j._sync.driver.BoltDriver
|
227
|
-
The input neo4j
|
226
|
+
neo4jGraph : neo4j._sync.driver.BoltDriver or neo4jGraph, neo4j._sync.driver.Neo4jDriver
|
227
|
+
The input neo4j driver.
|
228
228
|
vertexLabelKey : str , optional
|
229
229
|
The returned vertices are labelled according to the dictionary values stored under this key.
|
230
230
|
If the vertexLabelKey does not exist, it will be created and the vertices are labelled numerically using the format defaultVertexLabel_XXX. The default is "label".
|
@@ -254,8 +254,8 @@ class Neo4j:
|
|
254
254
|
|
255
255
|
Returns
|
256
256
|
-------
|
257
|
-
neo4j._sync.driver.BoltDriver
|
258
|
-
The returned neo4j
|
257
|
+
neo4j._sync.driver.BoltDriver or neo4jGraph, neo4j._sync.driver.Neo4jDriver
|
258
|
+
The returned neo4j driver.
|
259
259
|
|
260
260
|
"""
|
261
261
|
from topologicpy.Vertex import Vertex
|
@@ -279,7 +279,7 @@ class Neo4j:
|
|
279
279
|
|
280
280
|
return sanitized
|
281
281
|
|
282
|
-
if not isinstance(neo4jGraph, neo4j._sync.driver.BoltDriver):
|
282
|
+
if not isinstance(neo4jGraph, neo4j._sync.driver.BoltDriver) and not isinstance(neo4jGraph, neo4j._sync.driver.Neo4jDriver):
|
283
283
|
if not silent:
|
284
284
|
print("Neo4j.ByGraph - Error: The input neo4jGraph is not a valid neo4j graph. Returning None.")
|
285
285
|
return None
|
topologicpy/Plotly.py
CHANGED
@@ -293,7 +293,8 @@ class Plotly:
|
|
293
293
|
showEdgeLabels: bool = False,
|
294
294
|
showEdgeLegend: bool = False,
|
295
295
|
colorScale: str = "viridis",
|
296
|
-
mantissa: int = 6
|
296
|
+
mantissa: int = 6,
|
297
|
+
silent: bool = False):
|
297
298
|
"""
|
298
299
|
Creates plotly vertex and edge data from the input graph.
|
299
300
|
|
@@ -354,6 +355,9 @@ class Plotly:
|
|
354
355
|
If set to True the edge legend will be drawn. Otherwise, it will not be drawn. The default is False.
|
355
356
|
colorScale : str , optional
|
356
357
|
The desired type of plotly color scales to use (e.g. "Viridis", "Plasma"). The default is "Viridis". For a full list of names, see https://plotly.com/python/builtin-colorscales/.
|
358
|
+
silent : bool , optional
|
359
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
360
|
+
|
357
361
|
Returns
|
358
362
|
-------
|
359
363
|
list
|
@@ -446,11 +450,11 @@ class Plotly:
|
|
446
450
|
if sagitta > 0:
|
447
451
|
for edge in edges:
|
448
452
|
d = Topology.Dictionary(edge)
|
449
|
-
arc = Wire.ArcByEdge(edge, sagitta=sagitta, absolute=absolute, sides=sides, close=False)
|
453
|
+
arc = Wire.ArcByEdge(edge, sagitta=sagitta, absolute=absolute, sides=sides, close=False, silent=silent)
|
450
454
|
if Topology.IsInstance(arc, "Wire"):
|
451
455
|
arc_edges = Topology.Edges(arc)
|
452
456
|
for arc_edge in arc_edges:
|
453
|
-
arc_edge = Topology.SetDictionary(arc_edge, d)
|
457
|
+
arc_edge = Topology.SetDictionary(arc_edge, d, silent=silent)
|
454
458
|
new_edges.append(arc_edge)
|
455
459
|
else:
|
456
460
|
new_edges.append(edge)
|
topologicpy/Topology.py
CHANGED
@@ -6252,7 +6252,7 @@ class Topology():
|
|
6252
6252
|
return newTopology
|
6253
6253
|
|
6254
6254
|
@staticmethod
|
6255
|
-
def RemoveCollinearEdges(topology, angTolerance=0.1, tolerance=0.0001):
|
6255
|
+
def RemoveCollinearEdges(topology, angTolerance: float = 0.1, tolerance: float = 0.0001, silent: bool = False):
|
6256
6256
|
"""
|
6257
6257
|
Removes the collinear edges of the input topology
|
6258
6258
|
|
@@ -6264,6 +6264,8 @@ class Topology():
|
|
6264
6264
|
The desired angular tolerance. The default is 0.1.
|
6265
6265
|
tolerance : float , optional
|
6266
6266
|
The desired tolerance. The default is 0.0001.
|
6267
|
+
silent : bool , optional
|
6268
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
6267
6269
|
|
6268
6270
|
Returns
|
6269
6271
|
-------
|
@@ -6284,7 +6286,7 @@ class Topology():
|
|
6284
6286
|
if Topology.IsInstance(topology, "Vertex") or Topology.IsInstance(topology, "Edge"): #Vertex or Edge or Cluster, return the original topology
|
6285
6287
|
return return_topology
|
6286
6288
|
elif Topology.IsInstance(topology, "Wire"):
|
6287
|
-
return_topology = Wire.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance)
|
6289
|
+
return_topology = Wire.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance, silent=silent)
|
6288
6290
|
return return_topology
|
6289
6291
|
elif Topology.IsInstance(topology, "Face"):
|
6290
6292
|
return_topology = Face.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance)
|
topologicpy/Wire.py
CHANGED
@@ -206,7 +206,11 @@ class Wire():
|
|
206
206
|
length = sagitta
|
207
207
|
else:
|
208
208
|
length = Edge.Length(edge)*sagitta
|
209
|
-
norm = Edge.NormalEdge(edge, length=length)
|
209
|
+
norm = Edge.NormalEdge(edge, length=length, silent=silent)
|
210
|
+
if norm == None:
|
211
|
+
if not silent:
|
212
|
+
print("Wire.ArcByEdge - Warning: Could not create an arc. Returning the original edge.")
|
213
|
+
return edge
|
210
214
|
cv = Edge.EndVertex(norm)
|
211
215
|
return Wire.Arc(sv, cv, ev, sides=sides, close=close)
|
212
216
|
|
@@ -467,15 +471,15 @@ class Wire():
|
|
467
471
|
print("Wire.ByOffset - Error: The input wire parameter is not a valid wire. Returning None.")
|
468
472
|
return None
|
469
473
|
|
470
|
-
temp_face = Face.ByWire(wire)
|
471
|
-
original_area = Face.Area(temp_face)
|
474
|
+
#temp_face = Face.ByWire(wire)
|
475
|
+
#original_area = Face.Area(temp_face)
|
472
476
|
if reverse == True:
|
473
477
|
fac = -1
|
474
478
|
else:
|
475
479
|
fac = 1
|
476
480
|
origin = Topology.Centroid(wire)
|
477
481
|
temp_vertices = [Topology.Vertices(wire)[0], Topology.Vertices(wire)[1], Topology.Centroid(wire)]
|
478
|
-
temp_face = Face.ByWire(Wire.ByVertices(temp_vertices, close=True))
|
482
|
+
temp_face = Face.ByWire(Wire.ByVertices(temp_vertices, close=True), silent=silent)
|
479
483
|
temp_normal = Face.Normal(temp_face)
|
480
484
|
flat_wire = Topology.Flatten(wire, direction=temp_normal, origin=origin)
|
481
485
|
normal = Face.Normal(temp_face)
|
@@ -644,38 +648,204 @@ class Wire():
|
|
644
648
|
if not Wire.IsManifold(return_wire) and bisectors == False:
|
645
649
|
if not silent:
|
646
650
|
print("Wire.ByOffset - Warning: The resulting wire is non-manifold, please check your offsets.")
|
647
|
-
print("Wire.ByOffset - Warning: Pursuing a workaround, but it might take
|
651
|
+
print("Wire.ByOffset - Warning: Pursuing a workaround, but it might take longer to complete.")
|
648
652
|
|
649
653
|
#cycles = Wire.Cycles(return_wire, maxVertices = len(final_vertices))
|
650
654
|
temp_wire = Topology.SelfMerge(Cluster.ByTopologies(wire_edges))
|
651
655
|
cycles = Wire.Cycles(temp_wire, maxVertices = len(final_vertices))
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
656
|
+
if len(cycles) > 0:
|
657
|
+
distances = []
|
658
|
+
for cycle in cycles:
|
659
|
+
cycle_centroid = Topology.Centroid(cycle)
|
660
|
+
distance = Vertex.Distance(origin, cycle_centroid)
|
661
|
+
distances.append(distance)
|
662
|
+
cycles = Helper.Sort(cycles, distances)
|
663
|
+
# Get the top three or less
|
664
|
+
cycles = cycles[:min(3, len(cycles))]
|
665
|
+
areas = [Face.Area(Face.ByWire(cycle)) for cycle in cycles]
|
666
|
+
cycles = Helper.Sort(cycles, areas)
|
667
|
+
return_cycle = Wire.Reverse(cycles[-1])
|
668
|
+
test_cycle = Wire.Simplify(return_cycle, tolerance=epsilon)
|
669
|
+
if Topology.IsInstance(test_cycle, "Wire"):
|
670
|
+
return_cycle = test_cycle
|
671
|
+
return_cycle = Wire.RemoveCollinearEdges(return_cycle, silent=silent)
|
672
|
+
sel_edges = []
|
673
|
+
for temp_edge in wire_edges:
|
674
|
+
x = Topology.Centroid(temp_edge)
|
675
|
+
d = Topology.Dictionary(temp_edge)
|
676
|
+
x = Topology.SetDictionary(x, d, silent=True)
|
677
|
+
sel_edges.append(x)
|
678
|
+
return_cycle = Topology.TransferDictionariesBySelectors(return_cycle, Topology.Vertices(return_wire), tranVertices=True, tolerance=tolerance, numWorkers=numWorkers)
|
679
|
+
return_cycle = Topology.TransferDictionariesBySelectors(return_cycle, sel_edges, tranEdges=True, tolerance=tolerance, numWorkers=numWorkers)
|
680
|
+
return_wire = return_cycle
|
681
|
+
|
674
682
|
return_wire = Topology.Unflatten(return_wire, direction=normal, origin=origin)
|
675
683
|
if transferDictionaries == True:
|
676
684
|
return_wire = Topology.SetDictionary(return_wire, Topology.Dictionary(wire), silent=True)
|
677
685
|
return return_wire
|
678
686
|
|
687
|
+
@staticmethod
|
688
|
+
def ByOffsetArea(wire,
|
689
|
+
area,
|
690
|
+
offsetKey="offset",
|
691
|
+
minOffsetKey="minOffset",
|
692
|
+
maxOffsetKey="maxOffset",
|
693
|
+
defaultMinOffset=0,
|
694
|
+
defaultMaxOffset=1,
|
695
|
+
maxIterations = 1,
|
696
|
+
tolerance=0.0001,
|
697
|
+
silent = False):
|
698
|
+
"""
|
699
|
+
Creates an offset wire from the input wire based on the input area.
|
700
|
+
|
701
|
+
Parameters
|
702
|
+
----------
|
703
|
+
wire : topologic_core.Wire
|
704
|
+
The input wire.
|
705
|
+
area : float
|
706
|
+
The desired area of the created wire.
|
707
|
+
offsetKey : str , optional
|
708
|
+
The edge dictionary key under which to store the offset value. The default is "offset".
|
709
|
+
minOffsetKey : str , optional
|
710
|
+
The edge dictionary key under which to find the desired minimum edge offset value. If a value cannot be found, the defaultMinOffset input parameter value is used instead. The default is "minOffset".
|
711
|
+
maxOffsetKey : str , optional
|
712
|
+
The edge dictionary key under which to find the desired maximum edge offset value. If a value cannot be found, the defaultMaxOffset input parameter value is used instead. The default is "maxOffset".
|
713
|
+
defaultMinOffset : float , optional
|
714
|
+
The desired minimum edge offset distance. The default is 0.
|
715
|
+
defaultMaxOffset : float , optional
|
716
|
+
The desired maximum edge offset distance. The default is 1.
|
717
|
+
maxIterations: int , optional
|
718
|
+
The desired maximum number of iterations to attempt to converge on a solution. The default is 1.
|
719
|
+
tolerance : float , optional
|
720
|
+
The desired tolerance. The default is 0.0001.
|
721
|
+
silent : bool , optional
|
722
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
723
|
+
|
724
|
+
Returns
|
725
|
+
-------
|
726
|
+
topologic_core.Wire
|
727
|
+
The created wire.
|
728
|
+
|
729
|
+
"""
|
730
|
+
from topologicpy.Wire import Wire
|
731
|
+
from topologicpy.Face import Face
|
732
|
+
from topologicpy.Topology import Topology
|
733
|
+
from topologicpy.Dictionary import Dictionary
|
734
|
+
import numpy as np
|
735
|
+
from scipy.optimize import minimize
|
736
|
+
|
737
|
+
def compute_offset_amounts(wire,
|
738
|
+
area,
|
739
|
+
offsetKey="offset",
|
740
|
+
minOffsetKey="minOffset",
|
741
|
+
maxOffsetKey="maxOffset",
|
742
|
+
defaultMinOffset=0,
|
743
|
+
defaultMaxOffset=1,
|
744
|
+
maxIterations = 10000,
|
745
|
+
maxTime = 10,
|
746
|
+
tolerance=0.0001):
|
747
|
+
|
748
|
+
initial_offsets = []
|
749
|
+
bounds = []
|
750
|
+
for edge in edges:
|
751
|
+
d = Topology.Dictionary(edge)
|
752
|
+
minOffset = Dictionary.ValueAtKey(d, minOffsetKey) or defaultMinOffset
|
753
|
+
maxOffset = Dictionary.ValueAtKey(d, maxOffsetKey) or defaultMaxOffset
|
754
|
+
# Initial guess: small negative offsets to shrink the polygon, within the constraints
|
755
|
+
initial_offsets.append((minOffset + maxOffset) / 2)
|
756
|
+
# Bounds based on the constraints for each edge
|
757
|
+
bounds.append((minOffset, maxOffset))
|
758
|
+
|
759
|
+
# Convert initial_offsets to np.array for efficiency
|
760
|
+
initial_offsets = np.array(initial_offsets)
|
761
|
+
iteration_count = [0] # List to act as a mutable counter
|
762
|
+
|
763
|
+
def objective_function(offsets):
|
764
|
+
for i, edge in enumerate(edges):
|
765
|
+
d = Topology.Dictionary(edge)
|
766
|
+
d = Dictionary.SetValueAtKey(d, offsetKey, offsets[i])
|
767
|
+
edge = Topology.SetDictionary(edge, d)
|
768
|
+
|
769
|
+
# Offset the wire
|
770
|
+
new_wire = Wire.ByOffset(wire, offsetKey=offsetKey, silent=silent)
|
771
|
+
# Check for an illegal wire. In that case, return a very large loss value.
|
772
|
+
if not Topology.IsInstance(new_wire, "Wire"):
|
773
|
+
return (float("inf"))
|
774
|
+
if not Wire.IsManifold(new_wire):
|
775
|
+
return (float("inf"))
|
776
|
+
if not Wire.IsClosed(new_wire):
|
777
|
+
return (float("inf"))
|
778
|
+
new_face = Face.ByWire(new_wire)
|
779
|
+
# Calculate the area of the new wire/face
|
780
|
+
new_area = Face.Area(new_face)
|
781
|
+
|
782
|
+
# The objective is the difference between the target hole area and the actual hole area
|
783
|
+
# We want this difference to be as close to 0 as possible
|
784
|
+
loss = (new_area - area) ** 2
|
785
|
+
# If the loss is less than the tolerance, accept the result and return a loss of 0.
|
786
|
+
if loss < tolerance:
|
787
|
+
return 0
|
788
|
+
# Otherwise, return the actual loss value.
|
789
|
+
return loss
|
790
|
+
|
791
|
+
# Callback function to track and display iteration number
|
792
|
+
def iteration_callback(xk):
|
793
|
+
iteration_count[0] += 1 # Increment the counter
|
794
|
+
if not silent:
|
795
|
+
print(f"Wire.ByOffsetArea - Information: Iteration {iteration_count[0]}")
|
796
|
+
|
797
|
+
# Use scipy optimization/minimize to find the correct offsets, respecting the min/max bounds
|
798
|
+
result = minimize(objective_function,
|
799
|
+
initial_offsets,
|
800
|
+
method = "Powell",
|
801
|
+
bounds=bounds,
|
802
|
+
options={ 'maxiter': maxIterations},
|
803
|
+
callback=iteration_callback
|
804
|
+
)
|
805
|
+
|
806
|
+
# Return the offsets
|
807
|
+
return result.x
|
808
|
+
|
809
|
+
if not Topology.IsInstance(wire, "Wire"):
|
810
|
+
if not silent:
|
811
|
+
print("Wire.OffsetByArea - Error: The input wire parameter is not a valid wire. Returning None.")
|
812
|
+
return None
|
813
|
+
|
814
|
+
if not Wire.IsManifold(wire):
|
815
|
+
if not silent:
|
816
|
+
print("Wire.OffsetByArea - Error: The input wire parameter is not a manifold wire. Returning None.")
|
817
|
+
return None
|
818
|
+
|
819
|
+
if not Wire.IsClosed(wire):
|
820
|
+
if not silent:
|
821
|
+
print("Wire.OffsetByArea - Error: The input wire parameter is not a closed wire. Returning None.")
|
822
|
+
return None
|
823
|
+
|
824
|
+
edges = Topology.Edges(wire)
|
825
|
+
# Compute the offset amounts
|
826
|
+
offsets = compute_offset_amounts(wire,
|
827
|
+
area = area,
|
828
|
+
offsetKey = offsetKey,
|
829
|
+
minOffsetKey = minOffsetKey,
|
830
|
+
maxOffsetKey = maxOffsetKey,
|
831
|
+
defaultMinOffset = defaultMinOffset,
|
832
|
+
defaultMaxOffset = defaultMaxOffset,
|
833
|
+
maxIterations = maxIterations,
|
834
|
+
tolerance = tolerance)
|
835
|
+
# Set the edge dictionaries correctly according to the specified offsetKey
|
836
|
+
for i, edge in enumerate(edges):
|
837
|
+
d = Topology.Dictionary(edge)
|
838
|
+
d = Dictionary.SetValueAtKey(d, offsetKey, offsets[i])
|
839
|
+
edge = Topology.SetDictionary(edge, d)
|
840
|
+
|
841
|
+
# Offset the wire
|
842
|
+
return_wire = Wire.ByOffset(wire, offsetKey=offsetKey, silent=silent)
|
843
|
+
if not Topology.IsInstance(wire, "Wire"):
|
844
|
+
if not silent:
|
845
|
+
print("Wire.OffsetByArea - Error: Could not create the offset wire. Returning None.")
|
846
|
+
return None
|
847
|
+
return return_wire
|
848
|
+
|
679
849
|
@staticmethod
|
680
850
|
def ByVertices(vertices: list, close: bool = True, tolerance: float = 0.0001):
|
681
851
|
"""
|
@@ -1865,7 +2035,7 @@ class Wire():
|
|
1865
2035
|
return status
|
1866
2036
|
|
1867
2037
|
@staticmethod
|
1868
|
-
def IsManifold(wire) -> bool:
|
2038
|
+
def IsManifold(wire, silent: bool = False) -> bool:
|
1869
2039
|
"""
|
1870
2040
|
Returns True if the input wire is manifold. Returns False otherwise. A manifold wire is one where its vertices have a degree of 1 or 2.
|
1871
2041
|
|
@@ -1873,6 +2043,8 @@ class Wire():
|
|
1873
2043
|
----------
|
1874
2044
|
wire : topologic_core.Wire
|
1875
2045
|
The input wire.
|
2046
|
+
silent : bool , optional
|
2047
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
1876
2048
|
|
1877
2049
|
Returns
|
1878
2050
|
-------
|
@@ -1881,9 +2053,14 @@ class Wire():
|
|
1881
2053
|
|
1882
2054
|
"""
|
1883
2055
|
from topologicpy.Vertex import Vertex
|
2056
|
+
import inspect
|
1884
2057
|
|
1885
2058
|
if not Topology.IsInstance(wire, "Wire"):
|
1886
|
-
|
2059
|
+
if not silent:
|
2060
|
+
print("Wire.IsManifold - Error: The input wire parameter is not a valid topologic wire. Returning None.")
|
2061
|
+
curframe = inspect.currentframe()
|
2062
|
+
calframe = inspect.getouterframes(curframe, 2)
|
2063
|
+
print('caller name:', calframe[1][3])
|
1887
2064
|
return None
|
1888
2065
|
|
1889
2066
|
vertices = Wire.Vertices(wire)
|
@@ -2574,7 +2751,7 @@ class Wire():
|
|
2574
2751
|
return baseWire
|
2575
2752
|
|
2576
2753
|
@staticmethod
|
2577
|
-
def RemoveCollinearEdges(wire, angTolerance: float = 0.1, tolerance: float = 0.0001):
|
2754
|
+
def RemoveCollinearEdges(wire, angTolerance: float = 0.1, tolerance: float = 0.0001, silent: bool = False):
|
2578
2755
|
"""
|
2579
2756
|
Removes any collinear edges in the input wire.
|
2580
2757
|
|
@@ -2586,6 +2763,8 @@ class Wire():
|
|
2586
2763
|
The desired angular tolerance. The default is 0.1.
|
2587
2764
|
tolerance : float , optional
|
2588
2765
|
The desired tolerance. The default is 0.0001.
|
2766
|
+
silent : bool , optional
|
2767
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
2589
2768
|
|
2590
2769
|
Returns
|
2591
2770
|
-------
|
@@ -2598,6 +2777,7 @@ class Wire():
|
|
2598
2777
|
from topologicpy.Wire import Wire
|
2599
2778
|
from topologicpy.Cluster import Cluster
|
2600
2779
|
from topologicpy.Topology import Topology
|
2780
|
+
import inspect
|
2601
2781
|
|
2602
2782
|
def cleanup(wire, tolerance):
|
2603
2783
|
vertices = Topology.Vertices(wire)
|
@@ -2611,8 +2791,9 @@ class Wire():
|
|
2611
2791
|
ev = vertices[Vertex.Index(ev, vertices, tolerance=tolerance)]
|
2612
2792
|
if Vertex.Distance(sv, ev) > tolerance:
|
2613
2793
|
new_edges.append(Edge.ByVertices([sv,ev]))
|
2614
|
-
|
2615
|
-
|
2794
|
+
if len(new_edges) > 0:
|
2795
|
+
return Topology.SelfMerge(Cluster.ByTopologies(new_edges, silent=silent), tolerance=tolerance)
|
2796
|
+
return wire
|
2616
2797
|
|
2617
2798
|
def rce(wire, angTolerance=0.1):
|
2618
2799
|
if not Topology.IsInstance(wire, "Wire"):
|
@@ -2641,6 +2822,13 @@ class Wire():
|
|
2641
2822
|
final_wire = Edge.ByStartVertexEndVertex(wire_verts[0], wire_verts[1], tolerance=tolerance, silent=True)
|
2642
2823
|
return final_wire
|
2643
2824
|
|
2825
|
+
if not Topology.IsInstance(wire, "Wire"):
|
2826
|
+
if not silent:
|
2827
|
+
print("Wire.RemoveCollinearEdges - Error: The input wire parameter is not a valid wire. Returning None.")
|
2828
|
+
curframe = inspect.currentframe()
|
2829
|
+
calframe = inspect.getouterframes(curframe, 2)
|
2830
|
+
print('caller name:', calframe[1][3])
|
2831
|
+
return None
|
2644
2832
|
new_wire = cleanup(wire, tolerance=tolerance)
|
2645
2833
|
if not Wire.IsManifold(new_wire):
|
2646
2834
|
wires = Wire.Split(new_wire)
|
@@ -2661,7 +2849,7 @@ class Wire():
|
|
2661
2849
|
else:
|
2662
2850
|
return wire
|
2663
2851
|
elif len(returnWires) > 1:
|
2664
|
-
returnWire = Topology.SelfMerge(Cluster.ByTopologies(returnWires))
|
2852
|
+
returnWire = Topology.SelfMerge(Cluster.ByTopologies(returnWires, silent=silent))
|
2665
2853
|
if Topology.IsInstance(returnWire, "Edge"):
|
2666
2854
|
return Wire.ByEdges([returnWire], tolerance=tolerance)
|
2667
2855
|
elif Topology.IsInstance(returnWire, "Wire"):
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.7.
|
1
|
+
__version__ = '0.7.63'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.7.
|
4
|
-
Summary: An
|
3
|
+
Version: 0.7.63
|
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: MIT License
|
7
7
|
|
@@ -3,34 +3,34 @@ topologicpy/Aperture.py,sha256=p9pUzTQSBWoUaDiug1V1R1hnEIEwYSXFg2t7iRAmNRY,2723
|
|
3
3
|
topologicpy/BVH.py,sha256=dfVQyn5OPN1_50nusS0AxAcmUfqTzpl0vWT7RBEz-WM,12870
|
4
4
|
topologicpy/Cell.py,sha256=_vEYx1kNc3JZJUCCS8nhLM_j8EV4SyZYt3DjNHNRoDw,107707
|
5
5
|
topologicpy/CellComplex.py,sha256=YNmNkH6IUplM9f7agZQd6IL2xnHf5ds3JkGQk4jiSXQ,48029
|
6
|
-
topologicpy/Cluster.py,sha256=
|
6
|
+
topologicpy/Cluster.py,sha256=P9hAtZQjPugnIRJcviQNFBbdDqpMFADJK87_tR0CIAI,56108
|
7
7
|
topologicpy/Color.py,sha256=FrxX2yILqWvYrqD8kBaknfMfOR_phJOmhvTvFc07bY4,18065
|
8
8
|
topologicpy/Context.py,sha256=ppApYKngZZCQBFWaxIMi2z2dokY23c935IDCBosxDAE,3055
|
9
9
|
topologicpy/DGL.py,sha256=Dd6O08D-vSxpjHYgKm45JpKiaeGvWlg1BRMzYMAXGNc,138991
|
10
10
|
topologicpy/Dictionary.py,sha256=cURg452wwk2WeSxWY46ncgAUo5XD1c2c5EtO6ESZHaY,27304
|
11
|
-
topologicpy/Edge.py,sha256=
|
11
|
+
topologicpy/Edge.py,sha256=FACD8Bm2nL2uTHIeRMVXfRF0cYeqhZ-lCZPHAfjAIPg,66927
|
12
12
|
topologicpy/EnergyModel.py,sha256=NM3_nAdY9_YDtbp9CaEZ0x0xVsetTqVDzm_VSjmq_mI,53746
|
13
|
-
topologicpy/Face.py,sha256=
|
14
|
-
topologicpy/Graph.py,sha256=
|
13
|
+
topologicpy/Face.py,sha256=OyzEWdXl8yScHlyG3jDqcI31d_QlAt3SDma8AtkLQFs,116746
|
14
|
+
topologicpy/Graph.py,sha256=4b8bzlyXmh0Ef9rjiEjl8wmh_9vAxoE5xiSiGvGjG9Q,411392
|
15
15
|
topologicpy/Grid.py,sha256=3-sn7CHWGcXk18XCnHjsUttNJTWwmN63g_Insj__p04,18218
|
16
16
|
topologicpy/Helper.py,sha256=i-AfI29NMsZXBaymjilfvxQbuS3wpYbpPw4RWu1YCHs,16358
|
17
17
|
topologicpy/Honeybee.py,sha256=Oc8mfGBNSjs6wxkPzCKmEw1ZPQPbp9XtiYWaAF62oSk,21893
|
18
18
|
topologicpy/Matrix.py,sha256=umgR7An919-wGInXJ1wpqnoQ2jCPdyMe2rcWTZ16upk,8079
|
19
|
-
topologicpy/Neo4j.py,sha256=
|
20
|
-
topologicpy/Plotly.py,sha256=
|
19
|
+
topologicpy/Neo4j.py,sha256=t52hgE9cVsqkGc7m7fjRsLnyfRHakVHwdvF4ms7ow78,22342
|
20
|
+
topologicpy/Plotly.py,sha256=k-gluqX4Na3zlYCDl_6A0gqeFoGR-0Oy6fLiT-Zqlyk,108362
|
21
21
|
topologicpy/Polyskel.py,sha256=EFsuh2EwQJGPLiFUjvtXmAwdX-A4r_DxP5hF7Qd3PaU,19829
|
22
22
|
topologicpy/PyG.py,sha256=LU9LCCzjxGPUM31qbaJXZsTvniTtgugxJY7y612t4A4,109757
|
23
23
|
topologicpy/Shell.py,sha256=joahFtpRQTWJpQOmi3qU4Xe0Sx2XXeayHlXTNx8CzMk,87610
|
24
24
|
topologicpy/Speckle.py,sha256=rUS6PCaxIjEF5_fUruxvMH47FMKg-ohcoU0qAUb-yNM,14267
|
25
25
|
topologicpy/Sun.py,sha256=42tDWMYpwRG7Z2Qjtp94eRgBuqySq7k8TgNUZDK7QxQ,36837
|
26
|
-
topologicpy/Topology.py,sha256=
|
26
|
+
topologicpy/Topology.py,sha256=DsRPV0iWUY2NIlxdvLLDBkkDY3xw8oYvmzQEEfJUusQ,398136
|
27
27
|
topologicpy/Vector.py,sha256=A1g83zDHep58iVPY8WQ8iHNrSOfGWFEzvVeDuMnjDNY,33078
|
28
28
|
topologicpy/Vertex.py,sha256=bLY60YWoMsgCgHk7F7k9F93Sq2FJ6AzUcTfJ83NZfHA,71107
|
29
|
-
topologicpy/Wire.py,sha256=
|
29
|
+
topologicpy/Wire.py,sha256=x2ut3Pej3fTBv1nPzQMsJ8asWFy4WKIjrAUPA0boesU,171628
|
30
30
|
topologicpy/__init__.py,sha256=D7ky87CAQMiS2KE6YLvcTLkTgA2PY7rASe6Z23pjp9k,872
|
31
|
-
topologicpy/version.py,sha256=
|
32
|
-
topologicpy-0.7.
|
33
|
-
topologicpy-0.7.
|
34
|
-
topologicpy-0.7.
|
35
|
-
topologicpy-0.7.
|
36
|
-
topologicpy-0.7.
|
31
|
+
topologicpy/version.py,sha256=MZJ0DcglO3LqgTS4xIW_NWvmDzvvzxd1VdjKOHudVIk,23
|
32
|
+
topologicpy-0.7.63.dist-info/LICENSE,sha256=BRNw73R2WdDBICtwhI3wm3cxsaVqLTAGuRwrTltcfxs,1068
|
33
|
+
topologicpy-0.7.63.dist-info/METADATA,sha256=EsGaYJ2wOBoqKTUUzAmNE_G0taxa5TW-Eg7UJzZqyYs,10920
|
34
|
+
topologicpy-0.7.63.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
35
|
+
topologicpy-0.7.63.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
36
|
+
topologicpy-0.7.63.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|