topologicpy 0.8.29__py3-none-any.whl → 0.8.30__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/Topology.py +83 -123
- topologicpy/version.py +1 -1
- {topologicpy-0.8.29.dist-info → topologicpy-0.8.30.dist-info}/METADATA +1 -1
- {topologicpy-0.8.29.dist-info → topologicpy-0.8.30.dist-info}/RECORD +7 -7
- {topologicpy-0.8.29.dist-info → topologicpy-0.8.30.dist-info}/WHEEL +1 -1
- {topologicpy-0.8.29.dist-info → topologicpy-0.8.30.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.29.dist-info → topologicpy-0.8.30.dist-info}/top_level.txt +0 -0
topologicpy/Topology.py
CHANGED
@@ -2118,17 +2118,15 @@ class Topology():
|
|
2118
2118
|
return Topology.ByDXFFile(file, sides=sides)
|
2119
2119
|
|
2120
2120
|
@staticmethod
|
2121
|
-
def ByIFCFile(
|
2121
|
+
def ByIFCFile(ifc_file, includeTypes=[], excludeTypes=[], transferDictionaries=False,
|
2122
2122
|
removeCoplanarFaces=False,
|
2123
|
-
xMin: float = -0.5, yMin: float = -0.5, zMin: float = -0.5,
|
2124
|
-
xMax: float = 0.5, yMax: float = 0.5, zMax: float = 0.5,
|
2125
2123
|
epsilon=0.0001, tolerance=0.0001, silent=False):
|
2126
2124
|
"""
|
2127
2125
|
Create a topology by importing it from an IFC file.
|
2128
2126
|
|
2129
2127
|
Parameters
|
2130
2128
|
----------
|
2131
|
-
|
2129
|
+
ifc_file : file object
|
2132
2130
|
The input IFC file.
|
2133
2131
|
includeTypes : list , optional
|
2134
2132
|
The list of IFC object types to include. It is case insensitive. If set to an empty list, all types are included. The default is [].
|
@@ -2138,18 +2136,6 @@ class Topology():
|
|
2138
2136
|
If set to True, the dictionaries from the IFC file will be transferred to the topology. Otherwise, they won't. The default is False.
|
2139
2137
|
removeCoplanarFaces : bool , optional
|
2140
2138
|
If set to True, coplanar faces are removed. Otherwise they are not. The default is False.
|
2141
|
-
xMin : float, optional
|
2142
|
-
The desired minimum value to assign for a vertex's X coordinate. The default is -0.5.
|
2143
|
-
yMin : float, optional
|
2144
|
-
The desired minimum value to assign for a vertex's Y coordinate. The default is -0.5.
|
2145
|
-
zMin : float, optional
|
2146
|
-
The desired minimum value to assign for a vertex's Z coordinate. The default is -0.5.
|
2147
|
-
xMax : float, optional
|
2148
|
-
The desired maximum value to assign for a vertex's X coordinate. The default is 0.5.
|
2149
|
-
yMax : float, optional
|
2150
|
-
The desired maximum value to assign for a vertex's Y coordinate. The default is 0.5.
|
2151
|
-
zMax : float, optional
|
2152
|
-
The desired maximum value to assign for a vertex's Z coordinate. The default is 0.5.
|
2153
2139
|
epsilon : float , optional
|
2154
2140
|
The desired epsilon (another form of tolerance) for finding if two faces are coplanar. The default is 0.01.
|
2155
2141
|
tolerance : float , optional
|
@@ -2162,119 +2148,89 @@ class Topology():
|
|
2162
2148
|
The created list of topologies.
|
2163
2149
|
|
2164
2150
|
"""
|
2151
|
+
import multiprocessing
|
2165
2152
|
import ifcopenshell
|
2166
2153
|
import ifcopenshell.geom
|
2167
|
-
from topologicpy.Vertex import Vertex
|
2168
|
-
from topologicpy.Wire import Wire
|
2169
2154
|
from topologicpy.Face import Face
|
2170
2155
|
from topologicpy.Cluster import Cluster
|
2171
2156
|
from topologicpy.Topology import Topology
|
2172
2157
|
from topologicpy.Dictionary import Dictionary
|
2173
|
-
|
2174
|
-
|
2175
|
-
|
2176
|
-
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
exclude = [t.lower() for t in excludeTypes]
|
2181
|
-
return (not include or is_a in include) and (is_a not in exclude)
|
2182
|
-
|
2183
|
-
with ThreadPoolExecutor() as executor:
|
2184
|
-
products = list(file.by_type("IfcProduct"))
|
2185
|
-
valid_entities = list(executor.map(lambda p: p if is_valid(p) else None, products))
|
2186
|
-
valid_entities = [e for e in valid_entities if e is not None]
|
2187
|
-
|
2158
|
+
|
2159
|
+
# 1 Guard against including and excluding the same types
|
2160
|
+
includeTypes = [s.lower() for s in includeTypes]
|
2161
|
+
excludeTypes = [s.lower() for s in excludeTypes]
|
2162
|
+
if len(includeTypes) > 0 and len(excludeTypes) > 0:
|
2163
|
+
excludeTypes = [s for s in excludeTypes if s not in includeTypes]
|
2164
|
+
# 2 Setup geometry settings
|
2188
2165
|
settings = ifcopenshell.geom.settings()
|
2189
2166
|
settings.set(settings.USE_WORLD_COORDS, True)
|
2167
|
+
# A string representation of the OCC representation
|
2168
|
+
settings.set("iterator-output", ifcopenshell.ifcopenshell_wrapper.NATIVE)
|
2169
|
+
# A string representation of the OCC representation
|
2190
2170
|
settings.set("iterator-output", ifcopenshell.ifcopenshell_wrapper.SERIALIZED)
|
2171
|
+
|
2172
|
+
# 3 Create iterator
|
2173
|
+
it = ifcopenshell.geom.iterator(settings, ifc_file, multiprocessing.cpu_count())
|
2174
|
+
if not it.initialize():
|
2175
|
+
if not silent:
|
2176
|
+
print("Topology.ByIFCFile")
|
2177
|
+
raise RuntimeError("Geometry iterator failed to initialize")
|
2191
2178
|
|
2179
|
+
# 4) Loop over shapes
|
2192
2180
|
topologies = []
|
2193
|
-
|
2194
|
-
|
2195
|
-
|
2196
|
-
|
2197
|
-
|
2198
|
-
if
|
2199
|
-
|
2200
|
-
topology = Topology.ByBREPString(
|
2201
|
-
|
2202
|
-
|
2203
|
-
|
2204
|
-
|
2181
|
+
|
2182
|
+
while True:
|
2183
|
+
shape = it.get()
|
2184
|
+
element = ifc_file.by_guid(shape.guid)
|
2185
|
+
element_type = element.is_a().lower()
|
2186
|
+
if ((element_type in includeTypes) or (len(includeTypes) == 0)) and ((not element_type in excludeTypes) or (len(excludeTypes) == 0)):
|
2187
|
+
geom = shape.geometry
|
2188
|
+
topology = Topology.ByBREPString(geom.brep_data)
|
2189
|
+
faces = Topology.Faces(topology)
|
2190
|
+
new_faces = []
|
2191
|
+
for face in faces:
|
2192
|
+
eb = Face.ExternalBoundary(face)
|
2193
|
+
ib = Face.InternalBoundaries(face)
|
2194
|
+
f = Face.ByWires(eb, ib)
|
2195
|
+
new_faces.append(f)
|
2196
|
+
topology = Topology.SelfMerge(Cluster.ByTopologies(new_faces))
|
2205
2197
|
if removeCoplanarFaces:
|
2206
2198
|
topology = Topology.RemoveCoplanarFaces(topology, epsilon=epsilon, tolerance=tolerance)
|
2207
|
-
|
2208
|
-
|
2209
|
-
|
2210
|
-
|
2211
|
-
|
2212
|
-
|
2213
|
-
|
2214
|
-
|
2215
|
-
|
2216
|
-
|
2217
|
-
|
2218
|
-
|
2219
|
-
|
2220
|
-
|
2221
|
-
|
2222
|
-
|
2223
|
-
|
2224
|
-
|
2225
|
-
|
2226
|
-
|
2227
|
-
|
2228
|
-
|
2229
|
-
|
2230
|
-
|
2231
|
-
|
2232
|
-
|
2233
|
-
|
2234
|
-
|
2235
|
-
|
2236
|
-
|
2237
|
-
|
2238
|
-
|
2239
|
-
|
2240
|
-
final_dict = Dictionary.ByMergedDictionaries([final_dict, pset_dict])
|
2241
|
-
|
2242
|
-
topology = Topology.SetDictionary(topology, final_dict)
|
2243
|
-
|
2244
|
-
topologies.append(topology)
|
2245
|
-
|
2246
|
-
final_topologies = []
|
2247
|
-
for topology in topologies:
|
2248
|
-
faces = []
|
2249
|
-
|
2250
|
-
for w in Topology.Wires(topology):
|
2251
|
-
# Skip trivial wires (e.g. edges)
|
2252
|
-
if len(Topology.Vertices(w)) < 3:
|
2253
|
-
continue
|
2254
|
-
|
2255
|
-
# Only attempt face creation if the wire is closed
|
2256
|
-
if Wire.IsClosed(w) and Wire.IsManifold(w):
|
2257
|
-
f = Face.ByWire(w)
|
2258
|
-
if f:
|
2259
|
-
faces.append(f)
|
2260
|
-
continue
|
2261
|
-
|
2262
|
-
# fallback: keep wire
|
2263
|
-
faces.append(w)
|
2199
|
+
if transferDictionaries:
|
2200
|
+
element_dict = {
|
2201
|
+
"TOPOLOGIC_id": str(Topology.UUID(topology)),
|
2202
|
+
"TOPOLOGIC_name": getattr(element, 'Name', "Untitled"),
|
2203
|
+
"TOPOLOGIC_type": Topology.TypeAsString(topology),
|
2204
|
+
"IFC_global_id": getattr(element, 'GlobalId', 0),
|
2205
|
+
"IFC_name": getattr(element, 'Name', "Untitled"),
|
2206
|
+
"IFC_type": element_type
|
2207
|
+
}
|
2208
|
+
|
2209
|
+
# Optionally add property sets
|
2210
|
+
psets = {}
|
2211
|
+
if hasattr(element, 'IsDefinedBy'):
|
2212
|
+
for rel in element.IsDefinedBy:
|
2213
|
+
if rel.is_a('IfcRelDefinesByProperties'):
|
2214
|
+
pdef = rel.RelatingPropertyDefinition
|
2215
|
+
if pdef and pdef.is_a('IfcPropertySet'):
|
2216
|
+
key = f"IFC_{pdef.Name}"
|
2217
|
+
props = {}
|
2218
|
+
for prop in pdef.HasProperties:
|
2219
|
+
if prop.is_a('IfcPropertySingleValue') and prop.NominalValue:
|
2220
|
+
props[f"IFC_{prop.Name}"] = prop.NominalValue.wrappedValue
|
2221
|
+
psets[key] = props
|
2222
|
+
|
2223
|
+
final_dict = Dictionary.ByPythonDictionary(element_dict)
|
2224
|
+
if psets:
|
2225
|
+
pset_dict = Dictionary.ByPythonDictionary(psets)
|
2226
|
+
final_dict = Dictionary.ByMergedDictionaries([final_dict, pset_dict])
|
2227
|
+
|
2228
|
+
topology = Topology.SetDictionary(topology, final_dict)
|
2229
|
+
topologies.append(topology)
|
2230
|
+
if not it.next():
|
2231
|
+
break
|
2264
2232
|
|
2265
|
-
|
2266
|
-
if len(faces) == 1:
|
2267
|
-
final_topology = faces[0]
|
2268
|
-
else:
|
2269
|
-
final_topology = Topology.SelfMerge(Cluster.ByTopologies(faces))
|
2270
|
-
if final_topology == None:
|
2271
|
-
final_topology = Cluster.ByTopologies(faces)
|
2272
|
-
if transferDictionaries:
|
2273
|
-
d = Topology.Dictionary(topology)
|
2274
|
-
final_topology = Topology.SetDictionary(final_topology, d)
|
2275
|
-
|
2276
|
-
final_topologies.append(final_topology)
|
2277
|
-
return final_topologies
|
2233
|
+
return topologies
|
2278
2234
|
|
2279
2235
|
@staticmethod
|
2280
2236
|
def _ByIFCFile_old(file, includeTypes=[], excludeTypes=[], transferDictionaries=False, removeCoplanarFaces=False):
|
@@ -6590,15 +6546,19 @@ class Topology():
|
|
6590
6546
|
return False, None
|
6591
6547
|
# Done with Exclusion Tests.
|
6592
6548
|
|
6593
|
-
|
6594
|
-
|
6595
|
-
|
6596
|
-
largest_faces_a = Topology.LargestFaces(topologyA)
|
6597
|
-
largest_faces_b = Topology.LargestFaces(topologyB)
|
6549
|
+
if Topology.IsInstance(topologyA, "face"):
|
6550
|
+
largest_faces_a = [topologyA]
|
6551
|
+
largest_faces_b = [topologyB]
|
6598
6552
|
else:
|
6599
|
-
|
6600
|
-
|
6601
|
-
|
6553
|
+
faces_a = Topology.Faces(topologyA)
|
6554
|
+
faces_b = Topology.Faces(topologyB)
|
6555
|
+
if len(faces_a) > 0 and len(faces_b) > 0:
|
6556
|
+
largest_faces_a = Topology.LargestFaces(topologyA)
|
6557
|
+
largest_faces_b = Topology.LargestFaces(topologyB)
|
6558
|
+
else:
|
6559
|
+
if not silent:
|
6560
|
+
print("Topology.IsSimilar - Error: The topologies do not have faces. Returning None.")
|
6561
|
+
return False, None
|
6602
6562
|
|
6603
6563
|
# Process largest faces
|
6604
6564
|
for face_a in largest_faces_a:
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.8.
|
1
|
+
__version__ = '0.8.30'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.30
|
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
|
@@ -25,14 +25,14 @@ topologicpy/ShapeGrammar.py,sha256=JwE__VcKum5X3r33WwToEWtpJdFuhzZYyNhU2ob15ss,2
|
|
25
25
|
topologicpy/Shell.py,sha256=h8S2nP1e0JtMxeOdAFZVhOYTJWTW8vlZRM5lxK0gu2o,89577
|
26
26
|
topologicpy/Speckle.py,sha256=-eiTqJugd7pHiHpD3pDUcDO6CGhVyPV14HFRzaqEoaw,18187
|
27
27
|
topologicpy/Sun.py,sha256=_VBBAUIDhvpkp72JBZlv7k9qx9jYubm3yM56UZ1Nc6c,36837
|
28
|
-
topologicpy/Topology.py,sha256=
|
28
|
+
topologicpy/Topology.py,sha256=De_-naqB-hBPjcFeDQjbKUS7QzfhVxWJzu-7IMqLojc,476669
|
29
29
|
topologicpy/Vector.py,sha256=mx7fgABdioikPWM9HzXKzmqfx3u_XBcU_jlLD4qK2x8,42407
|
30
30
|
topologicpy/Vertex.py,sha256=UMDhERrLH6b4WOu4pl0UgYzcfp9-NvmASLtKXwetO_4,84687
|
31
31
|
topologicpy/Wire.py,sha256=eRs4PM7h4yU5v6umPh0oBJR4cN8BwsqlVroaFdnvK4w,228499
|
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=jN0mlk8vix45n9If_9Klf_t7fIZ7At3hYPz3_y-xov4,23
|
34
|
+
topologicpy-0.8.30.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
|
35
|
+
topologicpy-0.8.30.dist-info/METADATA,sha256=RlkwNXmDCcLnsl11dRg0HUVn5D2vEq9BmcH2mJ4zRMU,10535
|
36
|
+
topologicpy-0.8.30.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
37
|
+
topologicpy-0.8.30.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
38
|
+
topologicpy-0.8.30.dist-info/RECORD,,
|
File without changes
|
File without changes
|