topologicpy 0.7.8__py3-none-any.whl → 0.7.10__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/Edge.py +6 -2
- topologicpy/Face.py +39 -18
- topologicpy/Graph.py +161 -32
- topologicpy/Topology.py +1 -1
- topologicpy/Wire.py +2 -1
- topologicpy/version.py +1 -1
- topologicpy-0.7.10.dist-info/LICENSE +21 -0
- topologicpy-0.7.10.dist-info/METADATA +112 -0
- {topologicpy-0.7.8.dist-info → topologicpy-0.7.10.dist-info}/RECORD +11 -11
- topologicpy-0.7.8.dist-info/LICENSE +0 -661
- topologicpy-0.7.8.dist-info/METADATA +0 -751
- {topologicpy-0.7.8.dist-info → topologicpy-0.7.10.dist-info}/WHEEL +0 -0
- {topologicpy-0.7.8.dist-info → topologicpy-0.7.10.dist-info}/top_level.txt +0 -0
topologicpy/Edge.py
CHANGED
@@ -221,7 +221,7 @@ class Edge():
|
|
221
221
|
"""
|
222
222
|
from topologicpy.Vertex import Vertex
|
223
223
|
from topologicpy.Topology import Topology
|
224
|
-
|
224
|
+
|
225
225
|
edge = None
|
226
226
|
if not Topology.IsInstance(vertexA, "Vertex"):
|
227
227
|
if not silent:
|
@@ -297,7 +297,11 @@ class Edge():
|
|
297
297
|
if not silent:
|
298
298
|
print("Edge.ByVertices - Error: The input vertices parameter has less than two vertices. Returning None.")
|
299
299
|
return None
|
300
|
-
|
300
|
+
edge = Edge.ByStartVertexEndVertex(vertexList[0], vertexList[-1], tolerance=tolerance, silent=silent)
|
301
|
+
if not edge:
|
302
|
+
if not silent:
|
303
|
+
print("Edge.ByVertices - Error: Could not create an edge. Returning None.")
|
304
|
+
return edge
|
301
305
|
|
302
306
|
@staticmethod
|
303
307
|
def ByVerticesCluster(cluster, tolerance: float = 0.0001):
|
topologicpy/Face.py
CHANGED
@@ -1254,7 +1254,7 @@ class Face():
|
|
1254
1254
|
return Vector.IsCollinear(dirA, dirB)
|
1255
1255
|
|
1256
1256
|
@staticmethod
|
1257
|
-
def Isovist(face, vertex, obstacles =
|
1257
|
+
def Isovist(face, vertex, obstacles: list = [], direction: list = [0,1,0], fov: float = 360, mantissa: int = 6, tolerance: float = 0.0001):
|
1258
1258
|
"""
|
1259
1259
|
Returns the face representing the isovist projection from the input viewpoint.
|
1260
1260
|
This method assumes all input is in 2D. Z coordinates are ignored.
|
@@ -1267,14 +1267,17 @@ class Face():
|
|
1267
1267
|
The vertex representing the location of the viewpoint of the isovist.
|
1268
1268
|
obstacles : list , optional
|
1269
1269
|
A list of wires representing the obstacles within the face. All obstacles are assumed to be within the
|
1270
|
-
boundary of the face.
|
1271
|
-
|
1272
|
-
The
|
1273
|
-
|
1274
|
-
positive Y
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1270
|
+
boundary of the face. The default is [].
|
1271
|
+
direction : list, optional
|
1272
|
+
The vector representing the direction (in the XY plane) in which the observer is facing. The Z component is ignored.
|
1273
|
+
The direction follows the Vector.CompassAngle convention where [0,1,0] (North) is considered to be
|
1274
|
+
in the positive Y direction, [1,0,0] (East) is considered to be in the positive X-direction.
|
1275
|
+
Angles are measured in a clockwise fashion. The default is [0,1,0] (North).
|
1276
|
+
fov : float , optional
|
1277
|
+
The horizontal field of view (fov) angle in degrees. See https://en.wikipedia.org/wiki/Field_of_view.
|
1278
|
+
The acceptable range is 1 to 360. The default is 360.
|
1279
|
+
mantissa : int , optional
|
1280
|
+
The desired length of the mantissa. The default is 6.
|
1278
1281
|
tolerance : float , optional:
|
1279
1282
|
The desired tolerance. The default is 0.0001.
|
1280
1283
|
|
@@ -1282,7 +1285,7 @@ class Face():
|
|
1282
1285
|
-------
|
1283
1286
|
topologic_core.Face
|
1284
1287
|
The face representing the isovist projection from the input viewpoint.
|
1285
|
-
|
1288
|
+
|
1286
1289
|
"""
|
1287
1290
|
from topologicpy.Vertex import Vertex
|
1288
1291
|
from topologicpy.Edge import Edge
|
@@ -1291,7 +1294,8 @@ class Face():
|
|
1291
1294
|
from topologicpy.Shell import Shell
|
1292
1295
|
from topologicpy.Cluster import Cluster
|
1293
1296
|
from topologicpy.Topology import Topology
|
1294
|
-
|
1297
|
+
from topologicpy.Vector import Vector
|
1298
|
+
|
1295
1299
|
def vertexPartofFace(vertex, face, tolerance):
|
1296
1300
|
vertices = []
|
1297
1301
|
_ = face.Vertices(None, vertices)
|
@@ -1299,15 +1303,20 @@ class Face():
|
|
1299
1303
|
if Vertex.Distance(vertex, v) < tolerance:
|
1300
1304
|
return True
|
1301
1305
|
return False
|
1302
|
-
|
1306
|
+
|
1303
1307
|
if not Topology.IsInstance(face, "Face"):
|
1304
1308
|
print("Face.Isovist - Error: The input boundary parameter is not a valid Face. Returning None")
|
1305
1309
|
return None
|
1306
1310
|
if not Topology.IsInstance(vertex, "Vertex"):
|
1307
1311
|
print("Face.Isovist - Error: The input viewPoint parameter is not a valid Vertex. Returning None")
|
1308
1312
|
return None
|
1313
|
+
if fov < 1 or fov > 360:
|
1314
|
+
print("Face.Isovist - Error: The input fov parameter is outside the acceptable range of 0 to 360 degrees. Returning None")
|
1315
|
+
return None
|
1309
1316
|
if isinstance(obstacles, list):
|
1310
1317
|
obstacles = [obs for obs in obstacles if Topology.IsInstance(obs, "Wire")]
|
1318
|
+
else:
|
1319
|
+
obstacles = []
|
1311
1320
|
for obs in obstacles:
|
1312
1321
|
face = Topology.Difference(face, Face.ByWire(obs))
|
1313
1322
|
targets = Topology.Vertices(face)
|
@@ -1319,8 +1328,8 @@ class Face():
|
|
1319
1328
|
edges = []
|
1320
1329
|
for target in targets:
|
1321
1330
|
if Vertex.Distance(vertex, target) > tolerance:
|
1322
|
-
e = Edge.ByVertices(vertex, target)
|
1323
|
-
e = Edge.SetLength(e, length=max_d, bothSides=False)
|
1331
|
+
e = Edge.ByVertices(vertex, target, silent=True)
|
1332
|
+
e = Edge.SetLength(e, length=max_d, bothSides=False, tolerance=tolerance)
|
1324
1333
|
edges.append(e)
|
1325
1334
|
shell = Topology.Slice(face, Cluster.ByTopologies(edges))
|
1326
1335
|
faces = Topology.Faces(shell)
|
@@ -1330,13 +1339,25 @@ class Face():
|
|
1330
1339
|
final_faces.append(face)
|
1331
1340
|
shell = Shell.ByFaces(final_faces)
|
1332
1341
|
return_face = Topology.RemoveCoplanarFaces(shell)
|
1333
|
-
|
1342
|
+
compAngle = 0
|
1343
|
+
if fov == 360:
|
1344
|
+
c = Wire.Circle(origin= vertex, radius=max_d, sides=180, close = True)
|
1345
|
+
pie = Face.ByWire(c)
|
1346
|
+
else:
|
1347
|
+
compAngle = Vector.CompassAngle(Vector.North(), direction, mantissa=mantissa, tolerance=tolerance) - 90
|
1348
|
+
fromAngle = -fov*0.5 - compAngle
|
1349
|
+
toAngle = fov*0.5 - compAngle
|
1334
1350
|
c = Wire.Circle(origin= vertex, radius=max_d, sides=180, fromAngle=fromAngle, toAngle=toAngle, close = False)
|
1335
|
-
e1 = Edge.ByVertices(Wire.StartVertex(c), vertex)
|
1336
|
-
e2 = Edge.ByVertices(Wire.EndVertex(c), vertex)
|
1351
|
+
e1 = Edge.ByVertices(Wire.StartVertex(c), vertex, silent=True)
|
1352
|
+
e2 = Edge.ByVertices(Wire.EndVertex(c), vertex, silent=True)
|
1337
1353
|
edges = Topology.Edges(c) + [e1,e2]
|
1338
1354
|
pie = Face.ByWire(Topology.SelfMerge(Cluster.ByTopologies(edges)))
|
1339
|
-
|
1355
|
+
return_face = Topology.Intersect(pie, return_face)
|
1356
|
+
if not Topology.IsInstance(return_face, "face"):
|
1357
|
+
return_face = Topology.SelfMerge(return_face)
|
1358
|
+
if return_face == None:
|
1359
|
+
print("Face.Isovist - Error: Could not create isovist. Returning None.")
|
1360
|
+
return None
|
1340
1361
|
return return_face
|
1341
1362
|
|
1342
1363
|
@staticmethod
|
topologicpy/Graph.py
CHANGED
@@ -20,6 +20,9 @@ import time
|
|
20
20
|
import os
|
21
21
|
import warnings
|
22
22
|
|
23
|
+
from collections import namedtuple
|
24
|
+
from multiprocessing import Process, Queue
|
25
|
+
|
23
26
|
try:
|
24
27
|
import numpy as np
|
25
28
|
except:
|
@@ -62,6 +65,133 @@ except:
|
|
62
65
|
except:
|
63
66
|
warnings.warn("Graph - Error: Could not import tqdm.")
|
64
67
|
|
68
|
+
|
69
|
+
GraphQueueItem = namedtuple('GraphQueueItem', ['edges'])
|
70
|
+
|
71
|
+
class WorkerProcessPool(object):
|
72
|
+
"""
|
73
|
+
Create and manage a list of Worker processes. Each worker process
|
74
|
+
creates a 2D navigation graph.
|
75
|
+
"""
|
76
|
+
def __init__(self,
|
77
|
+
num_workers,
|
78
|
+
message_queue,
|
79
|
+
used,
|
80
|
+
face,
|
81
|
+
sources,
|
82
|
+
destinations,
|
83
|
+
tolerance=0.0001):
|
84
|
+
self.num_workers = num_workers
|
85
|
+
self.message_queue = message_queue
|
86
|
+
self.used = used
|
87
|
+
self.face = face
|
88
|
+
self.sources = sources
|
89
|
+
self.destinations = destinations
|
90
|
+
self.tolerance = tolerance
|
91
|
+
self.process_list = []
|
92
|
+
|
93
|
+
def startProcesses(self):
|
94
|
+
num_item_per_worker = len(self.sources) // self.num_workers
|
95
|
+
for i in range(self.num_workers):
|
96
|
+
if i == self.num_workers - 1:
|
97
|
+
begin = i * num_item_per_worker
|
98
|
+
sub_sources = self.sources[begin:]
|
99
|
+
else:
|
100
|
+
begin = i * num_item_per_worker
|
101
|
+
end = begin + num_item_per_worker
|
102
|
+
sub_sources = self.sources[begin : end]
|
103
|
+
wp = WorkerProcess(begin,
|
104
|
+
self.message_queue,
|
105
|
+
self.used,
|
106
|
+
self.face,
|
107
|
+
sub_sources,
|
108
|
+
self.destinations,
|
109
|
+
self.tolerance)
|
110
|
+
wp.start()
|
111
|
+
self.process_list.append(wp)
|
112
|
+
|
113
|
+
def stopProcesses(self):
|
114
|
+
for p in self.process_list:
|
115
|
+
p.join()
|
116
|
+
self.process_list = []
|
117
|
+
|
118
|
+
def join(self):
|
119
|
+
for p in self.process_list:
|
120
|
+
p.join()
|
121
|
+
|
122
|
+
|
123
|
+
class WorkerProcess(Process):
|
124
|
+
"""
|
125
|
+
Creates a 2D navigation graph from a subset of sources and the list of destinations.
|
126
|
+
"""
|
127
|
+
def __init__(self,
|
128
|
+
start_index,
|
129
|
+
message_queue,
|
130
|
+
used,
|
131
|
+
face,
|
132
|
+
sources,
|
133
|
+
destinations,
|
134
|
+
tolerance=0.0001):
|
135
|
+
Process.__init__(self, target=self.run)
|
136
|
+
self.start_index = start_index
|
137
|
+
self.message_queue = message_queue
|
138
|
+
self.used = used
|
139
|
+
self.face = face
|
140
|
+
self.sources = sources
|
141
|
+
self.destinations = destinations
|
142
|
+
self.tolerance = tolerance
|
143
|
+
|
144
|
+
def run(self):
|
145
|
+
from topologicpy.Topology import Topology
|
146
|
+
from topologicpy.Vertex import Vertex
|
147
|
+
from topologicpy.Edge import Edge
|
148
|
+
|
149
|
+
edges = []
|
150
|
+
face = Topology.ByBREPString(self.face)
|
151
|
+
sources = [Topology.ByBREPString(s) for s in self.sources]
|
152
|
+
destinations = [Topology.ByBREPString(s) for s in self.destinations]
|
153
|
+
for i in range(len(sources)):
|
154
|
+
source = sources[i]
|
155
|
+
index_b = Vertex.Index(source, destinations)
|
156
|
+
for j in range(len(destinations)):
|
157
|
+
destination = destinations[j]
|
158
|
+
index_a = Vertex.Index(destination, sources)
|
159
|
+
if self.used[i + self.start_index][j] == 1 or self.used[j][i + self.start_index]:
|
160
|
+
continue
|
161
|
+
if Vertex.Distance(source, destination) > self.tolerance:
|
162
|
+
edge = Edge.ByVertices([source, destination])
|
163
|
+
e = Topology.Boolean(edge, face, operation="intersect")
|
164
|
+
if Topology.IsInstance(e, "Edge"):
|
165
|
+
edges.append(edge)
|
166
|
+
self.used[i + self.start_index][j] = 1
|
167
|
+
if not index_a == None and not index_b == None:
|
168
|
+
self.used[j][i + self.start_index] = 1
|
169
|
+
if len(edges) > 0:
|
170
|
+
edges_str = [Topology.BREPString(s) for s in edges]
|
171
|
+
self.message_queue.put(GraphQueueItem(edges_str))
|
172
|
+
|
173
|
+
|
174
|
+
class MergingProcess(Process):
|
175
|
+
"""
|
176
|
+
Receive message from other processes and merging the result
|
177
|
+
"""
|
178
|
+
def __init__(self, message_queue):
|
179
|
+
Process.__init__(self, target=self.wait_message)
|
180
|
+
self.message_queue = message_queue
|
181
|
+
self.final_edges = []
|
182
|
+
|
183
|
+
def wait_message(self):
|
184
|
+
while True:
|
185
|
+
try:
|
186
|
+
item = self.message_queue.get()
|
187
|
+
if item is None:
|
188
|
+
self.message_queue.put(GraphQueueItem(self.final_edges))
|
189
|
+
break
|
190
|
+
self.final_edges.extend(item.edges)
|
191
|
+
except Exception as e:
|
192
|
+
print(str(e))
|
193
|
+
|
194
|
+
|
65
195
|
class _Tree:
|
66
196
|
def __init__(self, node="", *children):
|
67
197
|
self.node = node
|
@@ -6724,7 +6854,7 @@ class Graph:
|
|
6724
6854
|
return mst
|
6725
6855
|
|
6726
6856
|
@staticmethod
|
6727
|
-
def NavigationGraph(face, sources=None, destinations=None, tolerance=0.0001,
|
6857
|
+
def NavigationGraph(face, sources=None, destinations=None, tolerance=0.0001, numWorkers=None):
|
6728
6858
|
"""
|
6729
6859
|
Creates a 2D navigation graph.
|
6730
6860
|
|
@@ -6738,8 +6868,8 @@ class Graph:
|
|
6738
6868
|
The input list of destinations (vertices). Navigation edges will connect these vertices to sources.
|
6739
6869
|
tolerance : float , optional
|
6740
6870
|
The desired tolerance. The default is 0.0001.
|
6741
|
-
|
6742
|
-
|
6871
|
+
numWorkers : int, optional
|
6872
|
+
Number of workers run in parallel to process. The default is None which sets the number to twice the number of CPU cores.
|
6743
6873
|
|
6744
6874
|
Returns
|
6745
6875
|
-------
|
@@ -6747,15 +6877,15 @@ class Graph:
|
|
6747
6877
|
The navigation graph.
|
6748
6878
|
|
6749
6879
|
"""
|
6750
|
-
|
6751
|
-
from topologicpy.
|
6880
|
+
|
6881
|
+
from topologicpy.Topology import Topology
|
6752
6882
|
from topologicpy.Wire import Wire
|
6753
6883
|
from topologicpy.Face import Face
|
6754
|
-
from topologicpy.Graph import Graph
|
6755
6884
|
from topologicpy.Cluster import Cluster
|
6756
|
-
|
6757
|
-
|
6758
|
-
|
6885
|
+
|
6886
|
+
if not numWorkers:
|
6887
|
+
import multiprocessing
|
6888
|
+
numWorkers = multiprocessing.cpu_count()*2
|
6759
6889
|
|
6760
6890
|
if not Topology.IsInstance(face, "Face"):
|
6761
6891
|
print("Graph.NavigationGraph - Error: The input face parameter is not a valid face. Returning None")
|
@@ -6776,8 +6906,6 @@ class Graph:
|
|
6776
6906
|
print("Graph.NavigationGraph - Error: The input sources parameter does not contain any vertices. Returning None")
|
6777
6907
|
return None
|
6778
6908
|
destinations = [v for v in destinations if Topology.IsInstance(v, "Vertex")]
|
6779
|
-
#if len(destinations) < 1: #Nothing to navigate to, so return a graph made of sources
|
6780
|
-
#return Graph.ByVerticesEdges(sources, [])
|
6781
6909
|
|
6782
6910
|
# Add obstuse angles of external boundary to viewpoints
|
6783
6911
|
e_boundary = Face.ExternalBoundary(face)
|
@@ -6804,27 +6932,28 @@ class Graph:
|
|
6804
6932
|
temp_row.append(0)
|
6805
6933
|
used.append(temp_row)
|
6806
6934
|
|
6807
|
-
|
6808
|
-
|
6809
|
-
|
6810
|
-
|
6811
|
-
|
6812
|
-
for
|
6813
|
-
|
6814
|
-
|
6815
|
-
|
6816
|
-
|
6817
|
-
|
6818
|
-
|
6819
|
-
|
6820
|
-
|
6821
|
-
|
6822
|
-
|
6823
|
-
|
6824
|
-
|
6825
|
-
|
6826
|
-
|
6827
|
-
|
6935
|
+
queue = Queue()
|
6936
|
+
mergingProcess = MergingProcess(queue)
|
6937
|
+
mergingProcess.start()
|
6938
|
+
|
6939
|
+
sources_str = [Topology.BREPString(s) for s in sources]
|
6940
|
+
destinations_str = [Topology.BREPString(s) for s in destinations]
|
6941
|
+
face_str = Topology.BREPString(face)
|
6942
|
+
workerProcessPool = WorkerProcessPool(numWorkers,
|
6943
|
+
queue,
|
6944
|
+
used,
|
6945
|
+
face_str,
|
6946
|
+
sources_str,
|
6947
|
+
destinations_str,
|
6948
|
+
tolerance)
|
6949
|
+
workerProcessPool.startProcesses()
|
6950
|
+
workerProcessPool.join()
|
6951
|
+
|
6952
|
+
queue.put_nowait(None)
|
6953
|
+
it = queue.get()
|
6954
|
+
final_edges = [Topology.ByBREPString(edge_str) for edge_str in it.edges]
|
6955
|
+
mergingProcess.join()
|
6956
|
+
|
6828
6957
|
if len(i_boundaries) > 0:
|
6829
6958
|
holes_edges = Topology.Edges(Cluster.ByTopologies(i_boundaries))
|
6830
6959
|
final_edges += holes_edges
|
topologicpy/Topology.py
CHANGED
@@ -6718,7 +6718,7 @@ class Topology():
|
|
6718
6718
|
tolerance : float , optional
|
6719
6719
|
The desired tolerance. The default is 0.0001.
|
6720
6720
|
numWorkers : int, optional
|
6721
|
-
Number of workers run in parallel to process.
|
6721
|
+
Number of workers run in parallel to process. The default is None which sets the number to twice the number of CPU cores.
|
6722
6722
|
|
6723
6723
|
Returns
|
6724
6724
|
-------
|
topologicpy/Wire.py
CHANGED
@@ -2203,7 +2203,8 @@ class Wire(Topology):
|
|
2203
2203
|
sv = vertices[Vertex.Index(sv, vertices)]
|
2204
2204
|
ev = Edge.EndVertex(edge)
|
2205
2205
|
ev = vertices[Vertex.Index(ev, vertices)]
|
2206
|
-
|
2206
|
+
if Vertex.Distance(sv, ev) > tolerance:
|
2207
|
+
new_edges.append(Edge.ByVertices([sv,ev]))
|
2207
2208
|
new_wire = Topology.SelfMerge(Cluster.ByTopologies(new_edges), tolerance=tolerance)
|
2208
2209
|
return new_wire
|
2209
2210
|
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.7.
|
1
|
+
__version__ = '0.7.10'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 Wassim Jabi
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -0,0 +1,112 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: topologicpy
|
3
|
+
Version: 0.7.10
|
4
|
+
Summary: An Advanced Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
|
5
|
+
Author-email: Wassim Jabi <wassim.jabi@gmail.com>
|
6
|
+
License: MIT License
|
7
|
+
|
8
|
+
Copyright (c) 2024 Wassim Jabi
|
9
|
+
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
12
|
+
in the Software without restriction, including without limitation the rights
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
15
|
+
furnished to do so, subject to the following conditions:
|
16
|
+
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
18
|
+
copies or substantial portions of the Software.
|
19
|
+
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
26
|
+
SOFTWARE.
|
27
|
+
|
28
|
+
Project-URL: Homepage, https://github.com/wassimj/TopologicPy
|
29
|
+
Project-URL: Bug Tracker, https://github.com/wassimj/TopologicPy/issues
|
30
|
+
Project-URL: Documentation, https://topologic.app/topologicpy_doc/
|
31
|
+
Classifier: Programming Language :: Python :: 3
|
32
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
33
|
+
Classifier: Operating System :: OS Independent
|
34
|
+
Requires-Python: <3.14,>=3.8
|
35
|
+
Description-Content-Type: text/markdown
|
36
|
+
License-File: LICENSE
|
37
|
+
Requires-Dist: numpy >=1.18.0
|
38
|
+
Requires-Dist: scipy >=1.4.1
|
39
|
+
Requires-Dist: pandas
|
40
|
+
Requires-Dist: tqdm
|
41
|
+
Requires-Dist: plotly
|
42
|
+
Requires-Dist: lark
|
43
|
+
Requires-Dist: topologic-core >=7.0.1
|
44
|
+
Provides-Extra: test
|
45
|
+
Requires-Dist: pytest-xdist >=2.4.0 ; extra == 'test'
|
46
|
+
|
47
|
+
# topologicpy
|
48
|
+
|
49
|
+
<img src="https://topologic.app/wp-content/uploads/2023/02/topologicpy-logo-no-loop.gif" alt="topologicpy logo" width="250" loop="1">
|
50
|
+
|
51
|
+
# An Advanced Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction
|
52
|
+
|
53
|
+
## Introduction
|
54
|
+
Welcome to topologicpy (rhymes with apple pie). topologicpy is an open-source python 3 implementation of [Topologic](https://topologic.app) which is a powerful spatial modelling and analysis software library that revolutionizes the way you design architectural spaces, buildings, and artefacts. Topologic's advanced features enable you to create hierarchical and topological information-rich 3D representations that offer unprecedented flexibility and control in your design process. With the integration of geometry, topology, information, and artificial intelligence, Topologic enriches Building Information Models with Building *Intelligence* Models.
|
55
|
+
|
56
|
+
Two of Topologic's main strengths are its support for *defeaturing* and *encoded meshing*. By simplifying the geometry of a model and removing small or unnecessary details not needed for analysis, defeaturing allows for faster and more accurate analysis while maintaining topological consistency. This feature enables you to transform low-quality, heavy BIM models into high-quality, lightweight representations ready for rigorous analysis effortlessly. Encoded meshing allows you to use the same base elements available in your commercial BIM platform to cleanly build 3D information-encoded models that match your exacting specifications.
|
57
|
+
|
58
|
+
Topologic's versatility extends to entities with mixed dimensionalities, enabling structural models, for example, to be represented coherently. Lines can represent columns and beams, surfaces can represent walls and slabs, and volumes can represent solids. Even non-building entities like structural loads can be efficiently attached to the structure. This approach creates mixed-dimensional models that are highly compatible with structural analysis simulation software.
|
59
|
+
|
60
|
+
Topologic's graph-based representation makes it a natural fit for integrating with Graph Machine Learning (GML), an exciting new branch of artificial intelligence. With GML, you can process vast amounts of connected data and extract valuable insights quickly and accurately. Topologic's intelligent algorithms for graph and node classification take GML to the next level by using the extracted data to classify building typologies, predict associations, and complete missing information in building information models. This integration empowers you to leverage the historical knowledge embedded in your databases and make informed decisions about your current design projects. With Topologic and GML, you can streamline your workflow, enhance your productivity, and achieve your project goals with greater efficiency and precision.
|
61
|
+
|
62
|
+
Experience Topologic's comprehensive and well-documented Application Protocol Interface (API) and enjoy the freedom and flexibility that Topologic offers in your architectural design process. Topologic uses cutting-edge C++-based non-manifold topology (NMT) core technology ([Open CASCADE](https://www.opencascade.com/)), and python bindings. Interacting with Topologic is easily accomplished through a command-Line interface and scripts, visual data flow programming (VDFP) plugins for popular BIM software, and cloud-based interfaces through [Streamlit](https://streamlit.io/). You can easily interact with Topologic in various ways to perform design and analysis tasks or even seamlessly customize and embed it in your own in-house software and workflows. Plus, Topologic includes several industry-standard methods for data transport including IFC, OBJ, BREP, HBJSON, CSV, as well serializing through cloud-based services such as [Speckle](https://speckle.systems/).
|
63
|
+
|
64
|
+
Topologic’s open-source philosophy and licensing ([AGPLv3](https://www.gnu.org/licenses/agpl-3.0.en.html)) enables you to achieve your design vision with minimal incremental costs, ensuring a high return on investment. You control and own your information outright, and nothing is ever trapped in an expensive subscription model. Topologic empowers you to build and share data apps with ease, giving you the flexibility to choose between local or cloud-based options and the peace of mind to focus on what matters most.
|
65
|
+
|
66
|
+
Join the revolution in architectural design with Topologic. Try it today and see the difference for yourself.
|
67
|
+
|
68
|
+
## Installation
|
69
|
+
topologicpy can be installed using the **pip** command as such:
|
70
|
+
|
71
|
+
`pip install topologicpy --upgrade`
|
72
|
+
|
73
|
+
## Prerequisites
|
74
|
+
|
75
|
+
topologicpy depends on the following python libraries which will be installed automatically from pip:
|
76
|
+
|
77
|
+
<details>
|
78
|
+
<summary>
|
79
|
+
<b>Expand to view dependencies</b>
|
80
|
+
</summary>
|
81
|
+
* [numpy](http://numpy.org) >= 1.24.0
|
82
|
+
* [scipy](http://scipy.org) >= 1.10.0
|
83
|
+
* [plotly](http://plotly.com/) >= 5.11.0
|
84
|
+
* [ifcopenshell](http://ifcopenshell.org/) >=0.7.9
|
85
|
+
* [ipfshttpclient](https://pypi.org/project/ipfshttpclient/) >= 0.7.0
|
86
|
+
* [web3](https://web3py.readthedocs.io/en/stable/) >=5.30.0
|
87
|
+
* [openstudio](https://openstudio.net/) >= 3.4.0
|
88
|
+
* [topologic_core](https://pypi.org/project/topologic_core/) >= 6.0.6
|
89
|
+
* [lbt-ladybug](https://pypi.org/project/lbt-ladybug/) >= 0.25.161
|
90
|
+
* [lbt-honeybee](https://pypi.org/project/lbt-honeybee/) >= 0.6.12
|
91
|
+
* [honeybee-energy](https://pypi.org/project/honeybee-energy/) >= 1.91.49
|
92
|
+
* [json](https://docs.python.org/3/library/json.html) >= 2.0.9
|
93
|
+
* [py2neo](https://py2neo.org/) >= 2021.2.3
|
94
|
+
* [pyvisgraph](https://github.com/TaipanRex/pyvisgraph) >= 0.2.1
|
95
|
+
* [specklepy](https://github.com/specklesystems/specklepy) >= 2.7.6
|
96
|
+
* [pandas](https://pandas.pydata.org/) >= 1.4.2
|
97
|
+
* [scipy](https://scipy.org/) >= 1.8.1
|
98
|
+
* [dgl](https://github.com/dmlc/dgl) >= 0.8.2
|
99
|
+
|
100
|
+
</details>
|
101
|
+
|
102
|
+
## How to start using Topologic
|
103
|
+
1. Open your favourite python editor ([jupyter notebook](https://jupyter.org/) is highly recommended)
|
104
|
+
1. Type 'import topologicpy'
|
105
|
+
1. Start using the API
|
106
|
+
|
107
|
+
## API Documentation
|
108
|
+
API documentation can be found at [https://topologic.app/topologicpy_doc/](https://topologic.app/topologicpy_doc/)
|
109
|
+
|
110
|
+
topologicpy: © 2023 Wassim Jabi
|
111
|
+
|
112
|
+
Topologic: © 2023 Cardiff University and UCL
|
@@ -6,10 +6,10 @@ topologicpy/Color.py,sha256=UlmRcCSOhqcM_OyMWz4t3Kr75KcgXDhz3uctAJ2n7Ic,18031
|
|
6
6
|
topologicpy/Context.py,sha256=ppApYKngZZCQBFWaxIMi2z2dokY23c935IDCBosxDAE,3055
|
7
7
|
topologicpy/DGL.py,sha256=RpkLnAzjg6arY7cEMs2pDFYzRdkerVg1Wbm9hcE3QaM,138991
|
8
8
|
topologicpy/Dictionary.py,sha256=pMbfE2RYGCNpVr2x58qiHRc-aBWnp1jLlyzwS9nz6-w,25891
|
9
|
-
topologicpy/Edge.py,sha256=
|
9
|
+
topologicpy/Edge.py,sha256=EiOgg2HtuR-YtL5cpFcLcL1Y3A2Y-m4qPNtLjHGRZBQ,52407
|
10
10
|
topologicpy/EnergyModel.py,sha256=ni0H1JgvLl1-q90yK9Sm1qj5P1fTuidlimEIcwuj6qE,53287
|
11
|
-
topologicpy/Face.py,sha256=
|
12
|
-
topologicpy/Graph.py,sha256=
|
11
|
+
topologicpy/Face.py,sha256=XqBi_wrR8qhxE8UdT-GhIoRnmaxo64E9Etm9iELjX5A,98729
|
12
|
+
topologicpy/Graph.py,sha256=IFEGU0MCE4_fPe2j8sx1vuXPKMjGaov5wTlgRAwB7ns,384631
|
13
13
|
topologicpy/Grid.py,sha256=2uDFDxg4NqROC-7bNi1BjK5Uz__BPH13afJ-VDBRW0M,18466
|
14
14
|
topologicpy/Helper.py,sha256=07V9IFu5ilMpvAdZVhIbdBOjBJSRTtJ0BfR1IoRaRXU,17743
|
15
15
|
topologicpy/Honeybee.py,sha256=dlr5OEH93q51ZmEgvi8PXGfCHBDAjIZ1cm38Rft1Bz4,20235
|
@@ -20,14 +20,14 @@ topologicpy/Polyskel.py,sha256=MYHKFOQBlUNqoUhAdOcKRIHpSk0dWWVrZgXK34NkvFM,15936
|
|
20
20
|
topologicpy/Shell.py,sha256=uPf5Ch8wQ-pbKvXMY_DV9tPXyz4BPmofFVYdIzbWFh4,76960
|
21
21
|
topologicpy/Speckle.py,sha256=rUS6PCaxIjEF5_fUruxvMH47FMKg-ohcoU0qAUb-yNM,14267
|
22
22
|
topologicpy/Sun.py,sha256=3tYb8kssU882lE1gEWg2mxDvCCY_LAVElkyUT6wa-ZU,36935
|
23
|
-
topologicpy/Topology.py,sha256=
|
23
|
+
topologicpy/Topology.py,sha256=sXvhiMShOjOp0aILjEU6uNDqKm3zEAEdrN_IJgDK47c,308819
|
24
24
|
topologicpy/Vector.py,sha256=2OXmty9CKZZzfsg5T4ckml-lPUUvgDvqokcKDsZVN9Y,29806
|
25
25
|
topologicpy/Vertex.py,sha256=WjQZf-r8h_Cjwkt_qNN483FCUql20fbv72Ymiq7ZYtw,67462
|
26
|
-
topologicpy/Wire.py,sha256=
|
26
|
+
topologicpy/Wire.py,sha256=TTGVySZAbo0cY_Ykoqyv6FiQHBBHzRGOKITjRNkdzSg,139107
|
27
27
|
topologicpy/__init__.py,sha256=D7ky87CAQMiS2KE6YLvcTLkTgA2PY7rASe6Z23pjp9k,872
|
28
|
-
topologicpy/version.py,sha256=
|
29
|
-
topologicpy-0.7.
|
30
|
-
topologicpy-0.7.
|
31
|
-
topologicpy-0.7.
|
32
|
-
topologicpy-0.7.
|
33
|
-
topologicpy-0.7.
|
28
|
+
topologicpy/version.py,sha256=yDniQ0XMYyXTl9AyH9Sr2sBx5o3HhQZmldHel-_qTEc,23
|
29
|
+
topologicpy-0.7.10.dist-info/LICENSE,sha256=BRNw73R2WdDBICtwhI3wm3cxsaVqLTAGuRwrTltcfxs,1068
|
30
|
+
topologicpy-0.7.10.dist-info/METADATA,sha256=VxeJ8w5ZkcWATvgpOBWfYR3qdsZGmU0EAeYavY7JjUI,8405
|
31
|
+
topologicpy-0.7.10.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
32
|
+
topologicpy-0.7.10.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
33
|
+
topologicpy-0.7.10.dist-info/RECORD,,
|