topologicpy 0.7.49__py3-none-any.whl → 0.7.51__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
topologicpy/Color.py CHANGED
@@ -371,7 +371,7 @@ class Color:
371
371
  Parameters
372
372
  ----------
373
373
  color : list
374
- The input color list. This is assumed to be in the format [r, g, b] or [r, g, b, a]
374
+ The input color list. This is assumed to be in the format [r, g, b] or [r, g, b, a] where the range is from 0 to 255.
375
375
  alpha : float , optional
376
376
  The transparency value. 0.0 means the color is fully transparent, 1.0 means the color is fully opaque. The default is 1.0.
377
377
  useAlpha : bool , optional
topologicpy/Dictionary.py CHANGED
@@ -642,10 +642,8 @@ class Dictionary():
642
642
  The value found at the input key in the input dictionary.
643
643
 
644
644
  """
645
- import json
646
645
  from topologicpy.Topology import Topology
647
646
 
648
-
649
647
  if not Topology.IsInstance(dictionary, "Dictionary") and not isinstance(dictionary, dict):
650
648
  print("Dictionary.ValueAtKey - Error: The input dictionary parameter is not a valid topologic or python dictionary. Returning None.")
651
649
  return None
topologicpy/Face.py CHANGED
@@ -2373,7 +2373,7 @@ class Face():
2373
2373
  from topologicpy.Face import Face
2374
2374
 
2375
2375
  if not Topology.IsInstance(face, "Face"):
2376
- print("Shell.ByMeshFace - Error: The input face parameter is not a valid face. Returning None.")
2376
+ print("Face.Triangulate - Error: The input face parameter is not a valid face. Returning None.")
2377
2377
  return None
2378
2378
  if not meshSize:
2379
2379
  bounding_face = Face.BoundingRectangle(face)
@@ -2477,9 +2477,11 @@ class Face():
2477
2477
  wire = Face.ExternalBoundary(f)
2478
2478
  wire = Wire.Invert(wire)
2479
2479
  f = Face.ByWire(wire)
2480
- finalFaces.append(f)
2480
+ if Topology.IsInstance(f, "Face"):
2481
+ finalFaces.append(f)
2481
2482
  else:
2482
- finalFaces.append(f)
2483
+ if Topology.IsInstance(f, "face"):
2484
+ finalFaces.append(f)
2483
2485
  face_normal = Face.Normal(face)
2484
2486
  return_faces = []
2485
2487
  for ff in finalFaces:
topologicpy/Plotly.py CHANGED
@@ -372,12 +372,11 @@ class Plotly:
372
372
  v_label = ""
373
373
  v_group = ""
374
374
  d = Topology.Dictionary(v)
375
- v_group = Dictionary.ValueAtKey(d, key=vertexGroupKey)
376
375
  if d:
377
376
  if vertexLabelKey:
378
377
  v_label = str(Dictionary.ValueAtKey(d, key=vertexLabelKey)) or ""
379
378
  if vertexGroupKey:
380
- v_group = Dictionary.ValueAtKey(d, key=vertexGroupKey) or None
379
+ v_group = Dictionary.ValueAtKey(d, key=vertexGroupKey) or ""
381
380
  try:
382
381
  v_groupList.append(vertexGroups.index(v_group))
383
382
  except:
@@ -439,14 +438,10 @@ class Plotly:
439
438
  e_group = ""
440
439
  d = Topology.Dictionary(e)
441
440
  if d:
442
- try:
441
+ if not edgeLabelKey == None:
443
442
  e_label = str(Dictionary.ValueAtKey(d, key=edgeLabelKey)) or ""
444
- except:
445
- e_label = ""
446
- try:
443
+ if not edgeGroupKey == None:
447
444
  e_group = str(Dictionary.ValueAtKey(d, key=edgeGroupKey)) or ""
448
- except:
449
- e_group = ""
450
445
  try:
451
446
  e_groupList.append(edgeGroups.index(e_group))
452
447
  except:
@@ -490,12 +485,12 @@ class Plotly:
490
485
  @staticmethod
491
486
  def DataByTopology(topology,
492
487
  showVertices=True, vertexSize=1.1, vertexColor="black",
493
- vertexLabelKey=None, vertexGroupKey=None, vertexGroups=[],
488
+ vertexLabelKey=None, showVertexLabel=False, vertexGroupKey=None, vertexGroups=[],
494
489
  vertexMinGroup=None, vertexMaxGroup=None,
495
490
  showVertexLegend=False, vertexLegendLabel="Topology Vertices", vertexLegendRank=1,
496
491
  vertexLegendGroup=1,
497
492
  showEdges=True, edgeWidth=1, edgeColor="black",
498
- edgeLabelKey=None, edgeGroupKey=None, edgeGroups=[],
493
+ edgeLabelKey=None, showEdgeLabel=False, edgeGroupKey=None, edgeGroups=[],
499
494
  edgeMinGroup=None, edgeMaxGroup=None,
500
495
  showEdgeLegend=False, edgeLegendLabel="Topology Edges", edgeLegendRank=2,
501
496
  edgeLegendGroup=2,
@@ -633,7 +628,7 @@ class Plotly:
633
628
  def closest_index(input_value, values):
634
629
  return int(min(range(len(values)), key=lambda i: abs(values[i] - input_value)))
635
630
 
636
- def vertexData(vertices, dictionaries=[], color="black", size=1.1, labelKey=None, groupKey=None, minGroup=None, maxGroup=None, groups=[], legendLabel="Topology Vertices", legendGroup=1, legendRank=1, showLegend=True, colorScale="Viridis"):
631
+ def vertexData(vertices, dictionaries=[], color="black", size=1.1, labelKey=None, showVertexLabel = False, groupKey=None, minGroup=None, maxGroup=None, groups=[], legendLabel="Topology Vertices", legendGroup=1, legendRank=1, showLegend=True, colorScale="Viridis"):
637
632
  x = []
638
633
  y = []
639
634
  z = []
@@ -664,16 +659,14 @@ class Plotly:
664
659
  if len(dictionaries) > 0:
665
660
  d = dictionaries[m]
666
661
  if d:
667
- try:
662
+ if not labelKey == None:
668
663
  label = str(Dictionary.ValueAtKey(d, key=labelKey)) or ""
669
- except:
670
- label = ""
671
- try:
672
- group = Dictionary.ValueAtKey(d, key=groupKey) or None
673
- except:
674
- group = ""
664
+ if not groupKey == None:
665
+ group = Dictionary.ValueAtKey(d, key=groupKey) or ""
675
666
  try:
676
- if type(group) == int or type(group) == float:
667
+ if group == "":
668
+ color = 'white'
669
+ elif type(group) == int or type(group) == float:
677
670
  if group < minGroup:
678
671
  group = minGroup
679
672
  if group > maxGroup:
@@ -696,13 +689,17 @@ class Plotly:
696
689
  groupList = color
697
690
  if len(labels) < 1:
698
691
  labels = ""
692
+ if showVertexLabel == True:
693
+ mode = "markers+text"
694
+ else:
695
+ mode = "markers"
699
696
  vData= go.Scatter3d(x=x,
700
697
  y=y,
701
698
  z=z,
702
699
  name=legendLabel,
703
700
  showlegend=showLegend,
704
701
  marker=dict(color=groupList, size=vertexSize),
705
- mode='markers',
702
+ mode=mode,
706
703
  legendgroup=legendGroup,
707
704
  legendrank=legendRank,
708
705
  text=labels,
@@ -711,7 +708,7 @@ class Plotly:
711
708
  )
712
709
  return vData
713
710
 
714
- def edgeData(vertices, edges, dictionaries=None, color="black", width=1, labelKey=None, groupKey=None, minGroup=None, maxGroup=None, groups=[], legendLabel="Topology Edges", legendGroup=2, legendRank=2, showLegend=True, colorScale="Viridis"):
711
+ def edgeData(vertices, edges, dictionaries=None, color="black", width=1, labelKey=None, showEdgeLabel = False, groupKey=None, minGroup=None, maxGroup=None, groups=[], legendLabel="Topology Edges", legendGroup=2, legendRank=2, showLegend=True, colorScale="Viridis"):
715
712
  x = []
716
713
  y = []
717
714
  z = []
@@ -744,15 +741,13 @@ class Plotly:
744
741
  if len(dictionaries) > 0:
745
742
  d = dictionaries[m]
746
743
  if d:
747
- try:
744
+ if not labelKey == None:
748
745
  label = str(Dictionary.ValueAtKey(d, key=labelKey)) or ""
749
- except:
750
- label = ""
751
- try:
752
- group = Dictionary.ValueAtKey(d, key=groupKey) or None
753
- except:
754
- group = ""
746
+ if not groupKey == None:
747
+ group = Dictionary.ValueAtKey(d, key=groupKey) or ""
755
748
  try:
749
+ if group == "":
750
+ color = 'white'
756
751
  if type(group) == int or type(group) == float:
757
752
  if group < minGroup:
758
753
  group = minGroup
@@ -778,13 +773,17 @@ class Plotly:
778
773
  groupList = color
779
774
  if len(labels) < 1:
780
775
  labels = ""
776
+ if showEdgeLabel == True:
777
+ mode = "lines+text"
778
+ else:
779
+ mode = "lines"
781
780
  eData = go.Scatter3d(x=x,
782
781
  y=y,
783
782
  z=z,
784
783
  name=legendLabel,
785
784
  showlegend=showLegend,
786
785
  marker_size=0,
787
- mode="lines",
786
+ mode=mode,
788
787
  line=dict(color=groupList, width=edgeWidth),
789
788
  legendgroup=legendGroup,
790
789
  legendrank=legendRank,
@@ -834,16 +833,14 @@ class Plotly:
834
833
  if len(dictionaries) > 0:
835
834
  d = dictionaries[m]
836
835
  if d:
837
- try:
836
+ if not labelKey == None:
838
837
  label = str(Dictionary.ValueAtKey(d, key=labelKey)) or ""
839
- except:
840
- label = ""
841
- try:
838
+ if not groupKey == None:
842
839
  group = Dictionary.ValueAtKey(d, key=groupKey) or None
843
- except:
844
- group = ""
845
840
  try:
846
- if type(group) == int or type(group) == float:
841
+ if group == "":
842
+ color = 'white'
843
+ elif type(group) == int or type(group) == float:
847
844
  if group < minGroup:
848
845
  group = minGroup
849
846
  if group > maxGroup:
@@ -955,7 +952,7 @@ class Plotly:
955
952
  d = Topology.Dictionary(tp_v)
956
953
  v_dictionaries.append(d)
957
954
  vertices.append([Vertex.X(tp_v, mantissa=mantissa), Vertex.Y(tp_v, mantissa=mantissa), Vertex.Z(tp_v, mantissa=mantissa)])
958
- data.append(vertexData(vertices, dictionaries=v_dictionaries, color=vertexColor, size=vertexSize, labelKey=vertexLabelKey, groupKey=vertexGroupKey, minGroup=vertexMinGroup, maxGroup=vertexMaxGroup, groups=vertexGroups, legendLabel=vertexLegendLabel, legendGroup=vertexLegendGroup, legendRank=vertexLegendRank, showLegend=showVertexLegend, colorScale=colorScale))
955
+ data.append(vertexData(vertices, dictionaries=v_dictionaries, color=vertexColor, size=vertexSize, labelKey=vertexLabelKey, showVertexLabel=showVertexLabel, groupKey=vertexGroupKey, minGroup=vertexMinGroup, maxGroup=vertexMaxGroup, groups=vertexGroups, legendLabel=vertexLegendLabel, legendGroup=vertexLegendGroup, legendRank=vertexLegendRank, showLegend=showVertexLegend, colorScale=colorScale))
959
956
 
960
957
  if showEdges and Topology.Type(topology) > Topology.TypeID("Vertex"):
961
958
  if Topology.Type(topology) == Topology.TypeID("Edge"):
@@ -971,7 +968,7 @@ class Plotly:
971
968
  geo = Topology.Geometry(e_cluster, mantissa=mantissa)
972
969
  vertices = geo['vertices']
973
970
  edges = geo['edges']
974
- data.append(edgeData(vertices, edges, dictionaries=e_dictionaries, color=edgeColor, width=edgeWidth, labelKey=edgeLabelKey, groupKey=edgeGroupKey, minGroup=edgeMinGroup, maxGroup=edgeMaxGroup, groups=edgeGroups, legendLabel=edgeLegendLabel, legendGroup=edgeLegendGroup, legendRank=edgeLegendRank, showLegend=showEdgeLegend, colorScale=colorScale))
971
+ data.append(edgeData(vertices, edges, dictionaries=e_dictionaries, color=edgeColor, width=edgeWidth, labelKey=edgeLabelKey, showEdgeLabel=showEdgeLabel, groupKey=edgeGroupKey, minGroup=edgeMinGroup, maxGroup=edgeMaxGroup, groups=edgeGroups, legendLabel=edgeLegendLabel, legendGroup=edgeLegendGroup, legendRank=edgeLegendRank, showLegend=showEdgeLegend, colorScale=colorScale))
975
972
 
976
973
  if showFaces and Topology.Type(topology) >= Topology.TypeID("Face"):
977
974
  if Topology.IsInstance(topology, "Face"):
topologicpy/Topology.py CHANGED
@@ -1477,8 +1477,144 @@ class Topology():
1477
1477
  st = None
1478
1478
  return st
1479
1479
 
1480
+
1481
+ @staticmethod
1482
+ def ByGeometry(vertices=[], edges=[], faces=[], topologyType = None, tolerance=0.0001):
1483
+ """
1484
+ Create a topology by the input lists of vertices, edges, and faces.
1485
+
1486
+ Parameters
1487
+ ----------
1488
+ vertices : list
1489
+ The input list of vertices in the form of [x, y, z]
1490
+ edges : list , optional
1491
+ The input list of edges in the form of [i, j] where i and j are vertex indices.
1492
+ faces : list , optional
1493
+ The input list of faces in the form of [i, j, k, l, ...] where the items in the list are vertex indices. The face is assumed to be closed to the last vertex is connected to the first vertex automatically.
1494
+ topologyType : str , optional
1495
+ The desired topology type. The options are: "Vertex", "Edge", "Wire", "Face", "Shell", "Cell", "CellComplex". If set to None, a "Cluster" will be returned. The default is None.
1496
+ tolerance : float , optional
1497
+ The desired tolerance. The default is 0.0001.
1498
+
1499
+ Returns
1500
+ -------
1501
+ topology : topologic_core.Topology
1502
+ The created topology. The topology will have a dictionary embedded in it that records the input attributes (color, id, lengthUnit, name, type)
1503
+
1504
+ """
1505
+ from topologicpy.Vertex import Vertex
1506
+ from topologicpy.Edge import Edge
1507
+ from topologicpy.Wire import Wire
1508
+ from topologicpy.Face import Face
1509
+ from topologicpy.Shell import Shell
1510
+ from topologicpy.Cell import Cell
1511
+ from topologicpy.CellComplex import CellComplex
1512
+ from topologicpy.Cluster import Cluster
1513
+
1514
+ def topologyByFaces(faces, topologyType, tolerance):
1515
+ if len(faces) == 1:
1516
+ return faces[0]
1517
+
1518
+ output = None
1519
+ if topologyType == "cell":
1520
+ c = Cell.ByFaces(faces, tolerance=tolerance)
1521
+ if Topology.IsInstance(c, "Cell"):
1522
+ output = c
1523
+ else:
1524
+ cc = CellComplex.ByFaces(faces, tolerance=tolerance)
1525
+ if Topology.IsInstance(cc, "CellComplex"):
1526
+ output = CellComplex.ExternalBoundary(cc)
1527
+ elif topologyType == "cellcomplex":
1528
+ output = CellComplex.ByFaces(faces, tolerance=tolerance)
1529
+ if Topology.IsInstance(output, "CellComplex"):
1530
+ cells = Topology.Cells(output)
1531
+ if len(cells) == 1:
1532
+ output = cells[0]
1533
+ else:
1534
+ output = Cluster.ByTopologies(faces)
1535
+ elif topologyType == "shell":
1536
+ output = Shell.ByFaces(faces, tolerance=tolerance) # This can return a list
1537
+ if Topology.IsInstance(output, "Shell"):
1538
+ return output
1539
+ elif topologyType == None:
1540
+ output = Cluster.ByTopologies(faces)
1541
+
1542
+ return output
1543
+
1544
+ def topologyByEdges(edges, topologyType):
1545
+ if len(edges) == 1:
1546
+ return edges[0]
1547
+
1548
+ output = Cluster.ByTopologies(edges)
1549
+ if topologyType.lower() == "wire":
1550
+ output = Topology.SelfMerge(output, tolerance=tolerance)
1551
+ if Topology.IsInstance(output, "Wire"):
1552
+ return output
1553
+ return None
1554
+ return output
1555
+
1556
+ vertices = [v for v in vertices if v]
1557
+ edges = [e for e in edges if e]
1558
+ faces = [f for f in faces if f]
1559
+
1560
+ if not vertices:
1561
+ return None
1562
+
1563
+ topVerts = [Vertex.ByCoordinates(v[0], v[1], v[2]) for v in vertices]
1564
+ topEdges = []
1565
+ topFaces = []
1566
+
1567
+ if not topologyType == None:
1568
+ topologyType = topologyType.lower()
1569
+
1570
+ if topologyType == "vertex":
1571
+ if len(topVerts) >= 1:
1572
+ return topVerts[0]
1573
+ else:
1574
+ return None
1575
+ elif topologyType == "edge":
1576
+ if len(edges) >= 1 and len(vertices) >= 2:
1577
+ return Edge.ByVertices(topVerts[edges[0][0]], topVerts[edges[0][1]], tolerance=tolerance)
1578
+ else:
1579
+ return None
1580
+
1581
+ if topologyType == "wire" and edges:
1582
+ topEdges = [Edge.ByVertices([topVerts[e[0]], topVerts[e[1]]], tolerance=tolerance) for e in edges]
1583
+ if topEdges:
1584
+ returnTopology = topologyByEdges(topEdges, topologyType)
1585
+ elif faces:
1586
+ for aFace in faces:
1587
+ faceEdges = [Edge.ByVertices([topVerts[aFace[i]], topVerts[aFace[i + 1]]], tolerance=tolerance) for i in range(len(aFace) - 1)]
1588
+ # Connect the last vertex to the first one
1589
+ faceEdges.append(Edge.ByVertices([topVerts[aFace[-1]], topVerts[aFace[0]]], tolerance=tolerance))
1590
+
1591
+ if len(faceEdges) > 2:
1592
+ faceWire = Wire.ByEdges(faceEdges, tolerance=tolerance)
1593
+ try:
1594
+ topFace = Face.ByWire(faceWire, tolerance=tolerance, silent=True)
1595
+ if Topology.IsInstance(topFace, "Face"):
1596
+ topFaces.append(topFace)
1597
+ elif isinstance(topFace, list):
1598
+ topFaces.extend(topFace)
1599
+ except:
1600
+ pass
1601
+ if topFaces:
1602
+ returnTopology = topologyByFaces(topFaces, topologyType=topologyType, tolerance=tolerance)
1603
+ elif edges:
1604
+ topEdges = [Edge.ByVertices([topVerts[e[0]], topVerts[e[1]]], tolerance=tolerance) for e in edges]
1605
+ if topEdges:
1606
+ returnTopology = topologyByEdges(topEdges, topologyType)
1607
+ else:
1608
+ returnTopology = Cluster.ByTopologies(topVerts)
1609
+ return returnTopology
1610
+
1611
+
1612
+
1613
+
1614
+
1615
+
1480
1616
  @staticmethod
1481
- def ByGeometry(vertices=[], edges=[], faces=[], color=[1.0, 1.0, 1.0, 1.0], id=None, name=None, lengthUnit="METERS", outputMode="default", tolerance=0.0001):
1617
+ def ByGeometry_old(vertices=[], edges=[], faces=[], color=[1.0, 1.0, 1.0, 1.0], id=None, name=None, lengthUnit="METERS", outputMode="default", tolerance=0.0001):
1482
1618
  """
1483
1619
  Create a topology by the input lists of vertices, edges, and faces.
1484
1620
 
@@ -2201,7 +2337,215 @@ class Topology():
2201
2337
  return Topology.ByDXFFile(file, sides=sides)
2202
2338
 
2203
2339
  @staticmethod
2204
- def ByIFCFile(file, includeTypes=[], excludeTypes=[], transferDictionaries=False, removeCoplanarFaces=False):
2340
+ def ByIFCFile(file, includeTypes=[], excludeTypes=[], transferDictionaries=False, removeCoplanarFaces=False, epsilon=0.0001, tolerance=0.0001):
2341
+ """
2342
+ Create a list of topologies by importing them from an IFC file.
2343
+
2344
+ Parameters
2345
+ ----------
2346
+ file : file object
2347
+ The input IFC file.
2348
+ includeTypes : list , optional
2349
+ 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 [].
2350
+ excludeTypes : list , optional
2351
+ The list of IFC object types to exclude. It is case insensitive. If set to an empty list, no types are excluded. The default is [].
2352
+ transferDictionaries : bool , optional
2353
+ If set to True, the dictionaries from the IFC file will be transferred to the topology. Otherwise, they won't. The default is False.
2354
+ removeCoplanarFaces : bool , optional
2355
+ If set to True, coplanar faces are removed. Otherwise they are not. The default is False.
2356
+ epsilon : float , optional
2357
+ The desired epsilon (another form of tolerance) for finding if two faces are coplanar. The default is 0.0001.
2358
+ tolerance : float , optional
2359
+ The desired tolerance. The default is 0.0001.
2360
+ Returns
2361
+ -------
2362
+ list
2363
+ The created list of topologies.
2364
+
2365
+ """
2366
+
2367
+ import ifcopenshell
2368
+ from topologicpy.Dictionary import Dictionary
2369
+
2370
+ def get_psets(entity):
2371
+ # Initialize the PSET dictionary for this entity
2372
+ psets = {}
2373
+
2374
+ # Check if the entity has a GlobalId
2375
+ if not hasattr(entity, 'GlobalId'):
2376
+ raise ValueError("The provided entity does not have a GlobalId.")
2377
+
2378
+ # Get the property sets related to this entity
2379
+ for definition in entity.IsDefinedBy:
2380
+ if definition.is_a('IfcRelDefinesByProperties'):
2381
+ property_set = definition.RelatingPropertyDefinition
2382
+
2383
+ # Check if it is a property set
2384
+ if property_set.is_a('IfcPropertySet'):
2385
+ pset_name = "IFC_"+property_set.Name
2386
+
2387
+ # Dictionary to hold individual properties
2388
+ properties = {}
2389
+
2390
+ # Iterate over the properties in the PSET
2391
+ for prop in property_set.HasProperties:
2392
+ if prop.is_a('IfcPropertySingleValue'):
2393
+ # Get the property name and value
2394
+ prop_name = "IFC_"+prop.Name
2395
+ prop_value = prop.NominalValue.wrappedValue if prop.NominalValue else None
2396
+ properties[prop_name] = prop_value
2397
+
2398
+ # Add this PSET to the dictionary for this entity
2399
+ psets[pset_name] = properties
2400
+ return psets
2401
+
2402
+ def get_color_transparency_material(entity):
2403
+ import random
2404
+
2405
+ # Set default Material Name and ID
2406
+ material_list = []
2407
+ # Set default transparency based on entity type or material
2408
+ default_transparency = 0.0
2409
+
2410
+ # Check if the entity is an opening or made of glass
2411
+ is_a = entity.is_a().lower()
2412
+ if "opening" in is_a or "window" in is_a or "door" in is_a or "space" in is_a:
2413
+ default_transparency = 0.7
2414
+ elif "space" in is_a:
2415
+ default_transparency = 0.8
2416
+
2417
+ # Check if the entity has constituent materials (e.g., glass)
2418
+ else:
2419
+ # Check for associated materials (ConstituentMaterial or direct material assignment)
2420
+ materials_checked = False
2421
+ if hasattr(entity, 'HasAssociations'):
2422
+ for rel in entity.HasAssociations:
2423
+ if rel.is_a('IfcRelAssociatesMaterial'):
2424
+ material = rel.RelatingMaterial
2425
+ if material.is_a('IfcMaterial') and 'glass' in material.Name.lower():
2426
+ default_transparency = 0.5
2427
+ materials_checked = True
2428
+ elif material.is_a('IfcMaterialLayerSetUsage'):
2429
+ material_layers = material.ForLayerSet.MaterialLayers
2430
+ for layer in material_layers:
2431
+ material_list.append(layer.Material.Name)
2432
+ if 'glass' in layer.Material.Name.lower():
2433
+ default_transparency = 0.5
2434
+ materials_checked = True
2435
+
2436
+ # Check for ConstituentMaterial if available
2437
+ if hasattr(entity, 'HasAssociations') and not materials_checked:
2438
+ for rel in entity.HasAssociations:
2439
+ if rel.is_a('IfcRelAssociatesMaterial'):
2440
+ material = rel.RelatingMaterial
2441
+ if material.is_a('IfcMaterialConstituentSet'):
2442
+ for constituent in material.MaterialConstituents:
2443
+ material_list.append(constituent.Material.Name)
2444
+ if 'glass' in constituent.Material.Name.lower():
2445
+ default_transparency = 0.5
2446
+ materials_checked = True
2447
+
2448
+ # Check if the entity has ShapeAspects with associated materials or styles
2449
+ if hasattr(entity, 'HasShapeAspects') and not materials_checked:
2450
+ for shape_aspect in entity.HasShapeAspects:
2451
+ if hasattr(shape_aspect, 'StyledByItem') and shape_aspect.StyledByItem:
2452
+ for styled_item in shape_aspect.StyledByItem:
2453
+ for style in styled_item.Styles:
2454
+ if style.is_a('IfcSurfaceStyle'):
2455
+ for surface_style in style.Styles:
2456
+ if surface_style.is_a('IfcSurfaceStyleRendering'):
2457
+ transparency = getattr(surface_style, 'Transparency', default_transparency)
2458
+ if transparency > 0:
2459
+ default_transparency = transparency
2460
+
2461
+ # Try to get the actual color and transparency if defined
2462
+ if hasattr(entity, 'Representation') and entity.Representation:
2463
+ for rep in entity.Representation.Representations:
2464
+ for item in rep.Items:
2465
+ if hasattr(item, 'StyledByItem') and item.StyledByItem:
2466
+ for styled_item in item.StyledByItem:
2467
+ if hasattr(styled_item, 'Styles'):
2468
+ for style in styled_item.Styles:
2469
+ if style.is_a('IfcSurfaceStyle'):
2470
+ for surface_style in style.Styles:
2471
+ if surface_style.is_a('IfcSurfaceStyleRendering'):
2472
+ color = surface_style.SurfaceColour
2473
+ transparency = getattr(surface_style, 'Transparency', default_transparency)
2474
+ return (color.Red*255, color.Green*255, color.Blue*255), transparency, material_list
2475
+
2476
+ # If no color is defined, return a consistent random color based on the entity type
2477
+ if "wall" in is_a:
2478
+ color = (0.4, 0.4, 0.4)
2479
+ elif "slab" in is_a:
2480
+ color = (0.6, 0.6, 0.6)
2481
+ elif "space" in is_a:
2482
+ color = (250, 250, 250)
2483
+ else:
2484
+ random.seed(hash(is_a))
2485
+ color = (random.random(), random.random(), random.random())
2486
+
2487
+ return color, default_transparency, material_list
2488
+
2489
+ def convert_to_topology(entity, settings):
2490
+ if hasattr(entity, "Representation") and entity.Representation:
2491
+ for rep in entity.Representation.Representations:
2492
+ if rep.is_a("IfcShapeRepresentation"):
2493
+ # Generate the geometry for this entity
2494
+ shape = ifcopenshell.geom.create_shape(settings, entity)
2495
+ shape_geometry = shape.geometry
2496
+ verts = shape_geometry.verts
2497
+ verts = [ [verts[i], verts[i + 1], verts[i + 2]] for i in range(0, len(verts), 3)]
2498
+ edges = shape_geometry.edges
2499
+ edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)]
2500
+ faces = shape_geometry.faces
2501
+ faces = [ [faces[i], faces[i + 1], faces[i + 2]] for i in range(0, len(faces), 3)]
2502
+ # Convert geometry to Topologic format
2503
+ #shape_topology = ifc_to_topologic_geometry(verts, edges, faces)
2504
+ #shape_topology = Topology.SelfMerge(Topology.ByGeometry(verts, edges, faces))
2505
+ shape_topology = Topology.ByGeometry(verts, edges, faces, topologyType="CellComplex")
2506
+ if removeCoplanarFaces == True:
2507
+ shape_topology = Topology.RemoveCoplanarFaces(shape_topology, epsilon=0.0001)
2508
+
2509
+ # Store relevant information
2510
+ color, transparency, material_list = get_color_transparency_material(entity)
2511
+ entity_dict = {
2512
+ "TOPOLOGIC_id": str(Topology.UUID(shape_topology)),
2513
+ "TOPOLOGIC_name": getattr(entity, 'Name', "Untitled"),
2514
+ "TOPOLOGIC_type": Topology.TypeAsString(shape_topology),
2515
+ "TOPOLOGIC_color": color,
2516
+ "TOPOLOGIC_opacity": 1.0 - transparency,
2517
+ "IFC_global_id": getattr(entity, 'GlobalId', 0),
2518
+ "IFC_name": getattr(entity, 'Name', "Untitled"),
2519
+ "IFC_type": entity.is_a(),
2520
+ "IFC_material_list": material_list,
2521
+ }
2522
+ topology_dict = Dictionary.ByPythonDictionary(entity_dict)
2523
+ # Get PSETs dictionary
2524
+ pset_python_dict = get_psets(entity)
2525
+ pset_dict = Dictionary.ByPythonDictionary(pset_python_dict)
2526
+ topology_dict = Dictionary.ByMergedDictionaries([topology_dict, pset_dict])
2527
+ shape_topology = Topology.SetDictionary(shape_topology, topology_dict)
2528
+ return shape_topology
2529
+ return None
2530
+
2531
+ # Main Code
2532
+ topologies = []
2533
+ settings = ifcopenshell.geom.settings()
2534
+ settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.SOLID)
2535
+ settings.set(settings.USE_WORLD_COORDS, True)
2536
+ products = file.by_type("IfcProduct")
2537
+ entities = []
2538
+ for product in products:
2539
+ is_a = product.is_a()
2540
+ if (is_a in includeTypes or len(includeTypes) == 0) and (not is_a in excludeTypes):
2541
+ entities.append(product)
2542
+ topologies = []
2543
+ for entity in entities:
2544
+ topologies.append(convert_to_topology(entity, settings))
2545
+ return topologies
2546
+
2547
+ @staticmethod
2548
+ def _ByIFCFile_old(file, includeTypes=[], excludeTypes=[], transferDictionaries=False, removeCoplanarFaces=False):
2205
2549
  """
2206
2550
  Create a topology by importing it from an IFC file.
2207
2551
 
@@ -2227,7 +2571,11 @@ class Topology():
2227
2571
  from topologicpy.Cluster import Cluster
2228
2572
  from topologicpy.Dictionary import Dictionary
2229
2573
  import uuid
2230
-
2574
+ import random
2575
+ import hashlib
2576
+ import re
2577
+ import numpy as np
2578
+
2231
2579
  try:
2232
2580
  import ifcopenshell
2233
2581
  import ifcopenshell.geom
@@ -2247,61 +2595,342 @@ class Topology():
2247
2595
  if not file:
2248
2596
  print("Topology.ByIFCFile - Error: the input file parameter is not a valid file. Returning None.")
2249
2597
  return None
2250
- includeTypes = [s.lower() for s in includeTypes]
2251
- excludeTypes = [s.lower() for s in excludeTypes]
2252
- topologies = []
2253
- settings = ifcopenshell.geom.settings()
2254
- settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
2255
- settings.set(settings.USE_WORLD_COORDS, True)
2256
- iterator = ifcopenshell.geom.iterator(settings, file, multiprocessing.cpu_count())
2257
- if iterator.initialize():
2258
- while True:
2259
- shape = iterator.get()
2260
- is_a = shape.type.lower()
2261
- if (is_a in includeTypes or len(includeTypes) == 0) and (not is_a in excludeTypes):
2262
- try:
2263
- verts = shape.geometry.verts
2264
- edges = shape.geometry.edges
2265
- faces = shape.geometry.faces
2598
+
2599
+ def clean_key(string):
2600
+ # Replace any character that is not a letter, digit, or underscore with an underscore
2601
+ cleaned_string = re.sub(r'[^a-zA-Z0-9_]', '_', string)
2602
+ return cleaned_string
2603
+
2604
+ def transform_wall_vertices(wall):
2605
+
2606
+ # Relatives Placement abrufen und ausgeben
2607
+ if wall.ObjectPlacement and wall.ObjectPlacement.RelativePlacement:
2608
+ relative_placement = wall.ObjectPlacement.RelativePlacement
2609
+ if relative_placement.is_a('IFCAXIS2PLACEMENT3D'):
2610
+ location = relative_placement.Location
2611
+ ref_direction = relative_placement.RefDirection
2612
+ print("Relative Placement Location:", location.Coordinates)
2613
+ if ref_direction:
2614
+ print("Relative Placement RefDirection:", ref_direction.DirectionRatios)
2615
+ else:
2616
+ print("Relative Placement RefDirection: None")
2617
+
2618
+ # IFCPRODUCTDEFINITIONSHAPE der Wand abrufen
2619
+ product_definition_shape = wall.Representation
2620
+ if not product_definition_shape:
2621
+ print("Keine Repräsentation gefunden.")
2622
+ return
2623
+
2624
+ # Initialisieren von Variablen für Representation Type und Layer-Infos
2625
+ representation_type = None
2626
+ diverse_representation = False
2627
+ layer_details = []
2628
+
2629
+ if hasattr(product_definition_shape, 'HasShapeAspects'):
2630
+ for aspect in product_definition_shape.HasShapeAspects:
2631
+ for representation in aspect.ShapeRepresentations:
2632
+ if representation.is_a('IFCSHAPEREPRESENTATION'):
2633
+ for item in representation.Items:
2634
+ if item.is_a('IFCEXTRUDEDAREASOLID'):
2635
+ # Profilbeschreibung abrufen
2636
+ profile = item.SweptArea
2637
+ if profile.is_a('IFCARBITRARYCLOSEDPROFILEDEF'):
2638
+ if not representation_type:
2639
+ representation_type = "ArbitraryClosedProfil"
2640
+ elif representation_type != "ArbitraryClosedProfil":
2641
+ diverse_representation = True
2642
+
2643
+ # Profilpunkte abrufen
2644
+ if hasattr(profile, 'OuterCurve') and profile.OuterCurve.is_a('IFCINDEXEDPOLYCURVE'):
2645
+ indexed_polycurve = profile.OuterCurve
2646
+ if hasattr(indexed_polycurve, 'Points') and indexed_polycurve.Points.is_a('IFCCARTESIANPOINTLIST2D'):
2647
+ point_list_2d = indexed_polycurve.Points
2648
+ points = point_list_2d.CoordList
2649
+ layer_info["Profilpunkte"] = points
2650
+ else:
2651
+ diverse_representation = True
2652
+
2653
+ # Location und RefDirection abrufen
2654
+ if item.Position.is_a('IFCAXIS2PLACEMENT3D'):
2655
+ axis_placement = item.Position
2656
+ location = axis_placement.Location
2657
+ ref_direction = axis_placement.RefDirection
2658
+ layer_info["Location"] = location.Coordinates
2659
+ if ref_direction:
2660
+ layer_info["RefDirection"] = ref_direction.DirectionRatios
2661
+ else:
2662
+ layer_info["RefDirection"] = None
2663
+
2664
+ layer_details.append(layer_info)
2665
+
2666
+ # Representation Type ausgeben
2667
+ if diverse_representation:
2668
+ representation_type = "divers"
2669
+ print("Representation Type der Wand:", representation_type)
2670
+
2671
+ # Layer-Details ausgeben
2672
+ for index, layer in enumerate(layer_details):
2673
+ print(f"\nLayer {index + 1} Details:")
2674
+ print("Material:", layer.get("Material", "Nicht verfügbar"))
2675
+ print("Extrusionsstärke:", layer.get("Extrusionsstärke", "Nicht verfügbar"))
2676
+ print("Profilpunkte:", layer.get("Profilpunkte", "Nicht verfügbar"))
2677
+ print("Location:", layer.get("Location", "Nicht verfügbar"))
2678
+ print("RefDirection:", layer.get("RefDirection", "Nicht verfügbar"))
2679
+
2680
+
2681
+
2682
+
2683
+
2684
+
2685
+ def extract_matrix_from_placement(placement):
2686
+ """Constructs a transformation matrix from an IFC Local Placement."""
2687
+ # Initialize identity matrix
2688
+ matrix = np.identity(4)
2689
+
2690
+ # Check if the placement is IfcLocalPlacement
2691
+ if placement.is_a("IfcLocalPlacement"):
2692
+ relative_placement = placement.RelativePlacement
2693
+
2694
+ if relative_placement.is_a("IfcAxis2Placement3D"):
2695
+ location = relative_placement.Location.Coordinates
2696
+ z_dir = relative_placement.Axis.DirectionRatios if relative_placement.Axis else [0, 0, 1]
2697
+ x_dir = relative_placement.RefDirection.DirectionRatios if relative_placement.RefDirection else [1, 0, 0]
2698
+
2699
+ # Compute y direction (cross product of z and x)
2700
+ y_dir = np.cross(z_dir, x_dir)
2701
+
2702
+ # Construct the rotation matrix
2703
+ rotation_matrix = np.array([
2704
+ [x_dir[0], y_dir[0], z_dir[0], 0],
2705
+ [x_dir[1], y_dir[1], z_dir[1], 0],
2706
+ [x_dir[2], y_dir[2], z_dir[2], 0],
2707
+ [0, 0, 0, 1]
2708
+ ])
2709
+
2710
+ # Translation vector
2711
+ translation_vector = np.array([
2712
+ [1, 0, 0, location[0]],
2713
+ [0, 1, 0, location[1]],
2714
+ [0, 0, 1, location[2]],
2715
+ [0, 0, 0, 1]
2716
+ ])
2717
+
2718
+ # Combine the rotation matrix and the translation vector
2719
+ matrix = np.dot(translation_vector, rotation_matrix)
2720
+
2721
+ return matrix
2722
+
2723
+ def apply_transformation(verts, matrix):
2724
+ """Applies a 4x4 transformation matrix to a list of vertices."""
2725
+ transformed_verts = []
2726
+ for vert in verts:
2727
+ print("vert:", vert)
2728
+ v = np.array([vert[0], vert[1], vert[2], 1.0])
2729
+ transformed_v = np.dot(matrix, v)
2730
+ transformed_verts.append([transformed_v[0], transformed_v[1], transformed_v[2]])
2731
+ return transformed_verts
2732
+
2733
+ def get_entity_transformation_matrix(entity):
2734
+ """Extracts the transformation matrix from an IFC entity."""
2735
+ matrix = np.identity(4) # Default to an identity matrix
2736
+ if hasattr(entity, "ObjectPlacement") and entity.ObjectPlacement:
2737
+ placement = entity.ObjectPlacement
2738
+ matrix = extract_matrix_from_placement(placement)
2739
+ return matrix
2740
+
2741
+ # Function to generate a unique random color based on material ID
2742
+ def generate_color_for_material(material_id):
2743
+ # Use a hash function to get a consistent "random" seed
2744
+ hash_object = hashlib.sha1(material_id.encode())
2745
+ seed = int(hash_object.hexdigest(), 16) % (10 ** 8)
2746
+ random.seed(seed)
2747
+ # Generate a random color
2748
+ r = random.random()
2749
+ g = random.random()
2750
+ b = random.random()
2751
+ return [r, g, b]
2752
+
2753
+ # Function to get the material IDs associated with an entity
2754
+ def get_material_ids_of_entity(entity):
2755
+ return_dict = {}
2756
+ material_names = []
2757
+ material_ids = []
2758
+ if hasattr(entity, "HasAssociations"):
2759
+ for association in entity.HasAssociations:
2760
+ if association.is_a("IfcRelAssociatesMaterial"):
2761
+ material = association.RelatingMaterial
2762
+ try:
2763
+ material_name = material.Name
2764
+ except:
2765
+ material_name = material.to_string()
2766
+ if material.is_a("IfcMaterial"):
2767
+ material_ids.append(material.id())
2768
+ material_names.append(material_name)
2769
+ return_dict[clean_key(material_name)] = material.id
2770
+ elif material.is_a("IfcMaterialList"):
2771
+ for mat in material.Materials:
2772
+ material_ids.append(mat.id())
2773
+ try:
2774
+ material_name = mat.Name
2775
+ except:
2776
+ material_name = mat.to_string()
2777
+ material_names.append(material_name)
2778
+ return_dict[clean_key(material_name)] = mat.id
2779
+ elif material.is_a("IfcMaterialLayerSetUsage") or material.is_a("IfcMaterialLayerSet"):
2780
+ for layer in material.ForLayerSet.MaterialLayers:
2781
+ material_ids.append(layer.Material.id())
2782
+ try:
2783
+ material_name = layer.Name
2784
+ except:
2785
+ material_name = layer.to_string()
2786
+ material_names.append(material_name)
2787
+ return_dict[clean_key(material_name)] = layer.Material.id()
2788
+ elif material.is_a("IfcMaterialConstituentSet"):
2789
+ for constituent in material.MaterialConstituents:
2790
+ material_ids.append(constituent.Material.id())
2791
+ try:
2792
+ material_name = constituent.Material.Name
2793
+ except:
2794
+ material_name = constituent.Material.to_string()
2795
+ material_names.append(material_name)
2796
+ return_dict[clean_key(material_name)] = constituent.Material.id()
2797
+
2798
+ return return_dict
2799
+
2800
+ def get_wall_layers(wall, matrix=None, transferDictionaries=False):
2801
+ settings = ifcopenshell.geom.settings()
2802
+ settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
2803
+ settings.set(settings.USE_WORLD_COORDS, False)
2804
+
2805
+ # IFCPRODUCTDEFINITIONSHAPE der Wand abrufen
2806
+ product_definition_shape = wall.Representation
2807
+ if not product_definition_shape:
2808
+ print("Topology.ByIFCFile - Error: The object has no representation. Returning None")
2809
+ return None
2810
+
2811
+ if hasattr(product_definition_shape, 'HasShapeAspects'):
2812
+ for aspect in product_definition_shape.HasShapeAspects:
2813
+ material_name = aspect.Name
2814
+ for representation in aspect.ShapeRepresentations:
2815
+ print(dir(representation))
2816
+ axis_placement = representation.Position
2817
+ location = axis_placement.Location
2818
+ ref_direction = axis_placement.RefDirection
2819
+ print("Location:", location)
2820
+ print("Direction", ref_direction)
2821
+ aspect_matrix = get_entity_transformation_matrix(representation)
2822
+ print("Aspect Matrix:", aspect_matrix)
2823
+ shape = ifcopenshell.geom.create_shape(settings, representation)
2824
+ verts = shape.verts
2825
+ edges = shape.edges
2826
+ faces = shape.faces
2266
2827
  grouped_verts = [ [verts[i], verts[i + 1], verts[i + 2]] for i in range(0, len(verts), 3)]
2828
+ grouped_verts = apply_transformation(grouped_verts, aspect_matrix)
2267
2829
  grouped_edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)]
2268
2830
  grouped_faces = [ [faces[i], faces[i + 1], faces[i + 2]] for i in range(0, len(faces), 3)]
2269
- topology = Topology.ByGeometry(grouped_verts, grouped_edges, grouped_faces)
2270
- if removeCoplanarFaces:
2271
- topology = Topology.RemoveCoplanarFaces(topology)
2272
- topologies.append(topology)
2831
+ topology = Topology.SelfMerge(Topology.ByGeometry(grouped_verts, grouped_edges, grouped_faces))
2832
+ #matrix = shape.transformation.matrix
2833
+ #topology = Topology.Transform(topology, matrix)
2834
+ d = get_material_ids_of_entity(wall)
2835
+ material_id = d.get(clean_key(material_name), 0)
2273
2836
  if transferDictionaries:
2274
2837
  keys = []
2275
2838
  values = []
2276
- keys.append("TOPOLOGIC_color")
2277
- values.append([1.0, 1.0, 1.0, 1.0])
2839
+ try:
2840
+ entity_name = entity.Name
2841
+ except:
2842
+ entity_name = entity.to_str()
2278
2843
  keys.append("TOPOLOGIC_id")
2279
2844
  values.append(str(uuid.uuid4()))
2280
2845
  keys.append("TOPOLOGIC_name")
2281
- values.append(shape.name)
2846
+ values.append(entity_name)
2282
2847
  keys.append("TOPOLOGIC_type")
2283
2848
  values.append(Topology.TypeAsString(topology))
2284
2849
  keys.append("IFC_id")
2285
- values.append(str(shape.id))
2286
- keys.append("IFC_guid")
2287
- values.append(str(shape.guid))
2288
- keys.append("IFC_unique_id")
2289
- values.append(str(shape.unique_id))
2850
+ values.append(str(aspect.id))
2851
+ #keys.append("IFC_guid")
2852
+ #values.append(str(aspect.guid))
2853
+ #keys.append("IFC_unique_id")
2854
+ #values.append(str(aspect.unique_id))
2290
2855
  keys.append("IFC_name")
2291
- values.append(shape.name)
2292
- keys.append("IFC_type")
2293
- values.append(shape.type)
2856
+ values.append(entity_name)
2857
+ #keys.append("IFC_type")
2858
+ #values.append(aspect.type)
2859
+ keys.append("IFC_material_id")
2860
+ values.append(material_id)
2861
+ keys.append("IFC_material_name")
2862
+ values.append(material_name)
2863
+ keys.append("TOPOLOGIC_color")
2864
+ color = generate_color_for_material(str(material_id))
2865
+ values.append(color)
2294
2866
  d = Dictionary.ByKeysValues(keys, values)
2295
2867
  topology = Topology.SetDictionary(topology, d)
2296
- topologies.append(topology)
2297
- except:
2298
- pass
2299
- if not iterator.next():
2300
- break
2868
+
2869
+ return topology
2870
+
2871
+
2872
+ includeTypes = [s.lower() for s in includeTypes]
2873
+ excludeTypes = [s.lower() for s in excludeTypes]
2874
+ topologies = []
2875
+ settings = ifcopenshell.geom.settings()
2876
+ settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.SOLID)
2877
+ settings.set(settings.USE_WORLD_COORDS, True)
2878
+ for entity in file.by_type('IfcProduct'): # You might want to refine the types you check
2879
+ if hasattr(entity, "Representation") and entity.Representation:
2880
+ print("Number of Representations:", len(entity.Representation.Representations))
2881
+ for rep in entity.Representation.Representations:
2882
+ print("Rep:", rep)
2883
+ print(dir(rep))
2884
+ matrix = get_entity_transformation_matrix(entity)
2885
+ print(matrix)
2886
+ if rep.is_a("IfcShapeRepresentation"):
2887
+ # Generate the geometry for this entity
2888
+ shape = ifcopenshell.geom.create_shape(settings, rep)
2889
+ verts = shape.verts
2890
+ edges = shape.edges
2891
+ faces = shape.faces
2892
+ grouped_verts = [ [verts[i], verts[i + 1], verts[i + 2]] for i in range(0, len(verts), 3)]
2893
+ #grouped_verts = apply_transformation(grouped_verts, matrix)
2894
+ grouped_edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)]
2895
+ grouped_faces = [ [faces[i], faces[i + 1], faces[i + 2]] for i in range(0, len(faces), 3)]
2896
+ topology = Topology.SelfMerge(Topology.ByGeometry(grouped_verts, grouped_edges, grouped_faces))
2897
+ if removeCoplanarFaces:
2898
+ topology = Topology.RemoveCoplanarFaces(topology)
2899
+ if transferDictionaries:
2900
+ keys = []
2901
+ values = []
2902
+ keys.append("TOPOLOGIC_id")
2903
+ values.append(str(uuid.uuid4()))
2904
+ keys.append("TOPOLOGIC_name")
2905
+ values.append(shape.name)
2906
+ keys.append("TOPOLOGIC_type")
2907
+ values.append(Topology.TypeAsString(topology))
2908
+ keys.append("IFC_id")
2909
+ values.append(str(shape.id))
2910
+ keys.append("IFC_guid")
2911
+ values.append(str(shape.guid))
2912
+ keys.append("IFC_unique_id")
2913
+ values.append(str(shape.unique_id))
2914
+ keys.append("IFC_name")
2915
+ values.append(shape.name)
2916
+ keys.append("IFC_type")
2917
+ values.append(shape.type)
2918
+ material_dict = get_material_ids_of_entity(entity)
2919
+ keys.append("IFC_materials")
2920
+ values.append(material_dict)
2921
+ #keys.append("IFC_material_name")
2922
+ #values.append(material_name)
2923
+ #keys.append("TOPOLOGIC_color")
2924
+ #color = generate_color_for_material(str(material_ids))
2925
+ #values.append(color)
2926
+ d = Dictionary.ByKeysValues(keys, values)
2927
+ topology = Topology.SetDictionary(topology, d)
2928
+ topology = Topology.Transform(topology, matrix)
2929
+ topologies.append(topology)
2301
2930
  return topologies
2302
2931
 
2303
2932
  @staticmethod
2304
- def ByIFCPath(path, includeTypes=[], excludeTypes=[], transferDictionaries=False, removeCoplanarFaces=False):
2933
+ def ByIFCPath(path, includeTypes=[], excludeTypes=[], transferDictionaries=False, removeCoplanarFaces=False, epsilon=0.0001, tolerance=0.0001):
2305
2934
  """
2306
2935
  Create a topology by importing it from an IFC file path.
2307
2936
 
@@ -2317,7 +2946,10 @@ class Topology():
2317
2946
  If set to True, the dictionaries from the IFC file will be transferred to the topology. Otherwise, they won't. The default is False.
2318
2947
  removeCoplanarFaces : bool , optional
2319
2948
  If set to True, coplanar faces are removed. Otherwise they are not. The default is False.
2320
-
2949
+ epsilon : float , optional
2950
+ The desired epsilon (another form of tolerance) for finding if two faces are coplanar. The default is 0.0001.
2951
+ tolerance : float , optional
2952
+ The desired tolerance. The default is 0.0001.
2321
2953
  Returns
2322
2954
  -------
2323
2955
  list
@@ -2336,7 +2968,7 @@ class Topology():
2336
2968
  if not file:
2337
2969
  print("Topology.ByIFCPath - Error: the input file parameter is not a valid file. Returning None.")
2338
2970
  return None
2339
- return Topology.ByIFCFile(file, includeTypes=includeTypes, excludeTypes=excludeTypes, transferDictionaries=transferDictionaries, removeCoplanarFaces=removeCoplanarFaces)
2971
+ return Topology.ByIFCFile(file, includeTypes=includeTypes, excludeTypes=excludeTypes, transferDictionaries=transferDictionaries, removeCoplanarFaces=removeCoplanarFaces, epsilon=epsilon, tolerance=tolerance)
2340
2972
 
2341
2973
  '''
2342
2974
  @staticmethod
@@ -5460,6 +6092,20 @@ class Topology():
5460
6092
  flat_topology = Topology.Translate(topology, -Vertex.X(origin, mantissa=mantissa), -Vertex.Y(origin, mantissa=mantissa), -Vertex.Z(origin, mantissa=mantissa))
5461
6093
  tran_mat = Vector.TransformationMatrix(direction, up)
5462
6094
  flat_topology = Topology.Transform(flat_topology, tran_mat)
6095
+ flat_topology = Topology.SetDictionary(flat_topology, Topology.Dictionary(topology), silent=True)
6096
+ flat_vertices = Topology.Vertices(flat_topology)
6097
+ vertices = Topology.Vertices(topology)
6098
+ flat_edges = Topology.Edges(flat_topology)
6099
+ edges = Topology.Edges(topology)
6100
+ faces = []
6101
+ flat_faces = []
6102
+ if Topology.IsInstance(topology, "Face"):
6103
+ flat_faces = Topology.Faces(flat_topology)
6104
+ faces = Topology.Faces(topology)
6105
+ elements = vertices+edges+faces
6106
+ flat_elements = flat_vertices+flat_edges+flat_faces
6107
+ for i, f, in enumerate(flat_elements):
6108
+ f = Topology.SetDictionary(f, Topology.Dictionary(elements[i]), silent=True)
5463
6109
  return flat_topology
5464
6110
 
5465
6111
  @staticmethod
@@ -6906,20 +7552,30 @@ class Topology():
6906
7552
 
6907
7553
  """
6908
7554
  from topologicpy.Dictionary import Dictionary
7555
+ import inspect
6909
7556
 
6910
7557
  if not Topology.IsInstance(topology, "Topology") and not Topology.IsInstance(topology, "Graph"):
6911
7558
  if not silent:
6912
7559
  print("Topology.SetDictionary - Error: the input topology parameter is not a valid topology or graph. Returning None.")
7560
+ curframe = inspect.currentframe()
7561
+ calframe = inspect.getouterframes(curframe, 2)
7562
+ print('caller name:', calframe[1][3])
6913
7563
  return None
6914
7564
  if isinstance(dictionary, dict):
6915
7565
  dictionary = Dictionary.ByPythonDictionary(dictionary)
6916
7566
  if not Topology.IsInstance(dictionary, "Dictionary"):
6917
7567
  if not silent:
6918
7568
  print("Topology.SetDictionary - Warning: the input dictionary parameter is not a valid dictionary. Returning original input.")
7569
+ curframe = inspect.currentframe()
7570
+ calframe = inspect.getouterframes(curframe, 2)
7571
+ print('caller name:', calframe[1][3])
6919
7572
  return topology
6920
7573
  if len(dictionary.Keys()) < 1:
6921
7574
  if not silent:
6922
7575
  print("Topology.SetDictionary - Warning: the input dictionary parameter is empty. Returning original input.")
7576
+ curframe = inspect.currentframe()
7577
+ calframe = inspect.getouterframes(curframe, 2)
7578
+ print('caller name:', calframe[1][3])
6923
7579
  return topology
6924
7580
  _ = topology.SetDictionary(dictionary)
6925
7581
  return topology
@@ -7122,13 +7778,15 @@ class Topology():
7122
7778
  colorKey = "color",
7123
7779
  opacityKey = "opacity",
7124
7780
  showVertices=True, vertexSize=1.1, vertexColor="black",
7125
- vertexLabelKey=None, vertexGroupKey=None, vertexGroups=[],
7781
+ vertexLabelKey=None, showVertexLabel= False,
7782
+ vertexGroupKey=None, vertexGroups=[],
7126
7783
  vertexMinGroup=None, vertexMaxGroup=None,
7127
7784
  showVertexLegend=False, vertexLegendLabel="Topology Vertices", vertexLegendRank=1,
7128
7785
  vertexLegendGroup=1,
7129
7786
 
7130
7787
  showEdges=True, edgeWidth=1, edgeColor="black",
7131
- edgeLabelKey=None, edgeGroupKey=None, edgeGroups=[],
7788
+ edgeLabelKey=None, showEdgeLabel = False,
7789
+ edgeGroupKey=None, edgeGroups=[],
7132
7790
  edgeMinGroup=None, edgeMaxGroup=None,
7133
7791
  showEdgeLegend=False, edgeLegendLabel="Topology Edges", edgeLegendRank=2,
7134
7792
  edgeLegendGroup=2,
@@ -7173,6 +7831,8 @@ class Topology():
7173
7831
  The default is "black".
7174
7832
  vertexLabelKey : str , optional
7175
7833
  The dictionary key to use to display the vertex label. The default is None.
7834
+ showVertexLabels : bool , optional
7835
+ If set to True, the vertex labels are shown permenantely on screen. Otherwise, they are not. The default is False.
7176
7836
  vertexGroupKey : str , optional
7177
7837
  The dictionary key to use to display the vertex group. The default is None.
7178
7838
  vertexGroups : list , optional
@@ -7204,6 +7864,8 @@ class Topology():
7204
7864
  The default is "black".
7205
7865
  edgeLabelKey : str , optional
7206
7866
  The dictionary key to use to display the edge label. The default is None.
7867
+ showEdgeLabels : bool , optional
7868
+ If set to True, the edge labels are shown permenantely on screen. Otherwise, they are not. The default is False.
7207
7869
  edgeGroupKey : str , optional
7208
7870
  The dictionary key to use to display the edge group. The default is None.
7209
7871
  edgeGroups : list , optional
@@ -7356,12 +8018,12 @@ class Topology():
7356
8018
  faceOpacity = Dictionary.ValueAtKey(d, opacityKey) or faceOpacity
7357
8019
  data += Plotly.DataByTopology(topology=topology,
7358
8020
  showVertices=showVertices, vertexSize=vertexSize, vertexColor=vertexColor,
7359
- vertexLabelKey=vertexLabelKey, vertexGroupKey=vertexGroupKey, vertexGroups=vertexGroups,
8021
+ vertexLabelKey=vertexLabelKey, showVertexLabel=showVertexLabel, vertexGroupKey=vertexGroupKey, vertexGroups=vertexGroups,
7360
8022
  vertexMinGroup=vertexMinGroup, vertexMaxGroup=vertexMaxGroup,
7361
8023
  showVertexLegend=showVertexLegend, vertexLegendLabel=vertexLegendLabel, vertexLegendRank=vertexLegendRank,
7362
8024
  vertexLegendGroup=vertexLegendGroup,
7363
8025
  showEdges=showEdges, edgeWidth=edgeWidth, edgeColor=edgeColor,
7364
- edgeLabelKey=edgeLabelKey, edgeGroupKey=edgeGroupKey, edgeGroups=edgeGroups,
8026
+ edgeLabelKey=edgeLabelKey, showEdgeLabel=showEdgeLabel, edgeGroupKey=edgeGroupKey, edgeGroups=edgeGroups,
7365
8027
  edgeMinGroup=edgeMinGroup, edgeMaxGroup=edgeMaxGroup,
7366
8028
  showEdgeLegend=showEdgeLegend, edgeLegendLabel=edgeLegendLabel, edgeLegendRank=edgeLegendRank,
7367
8029
  edgeLegendGroup=edgeLegendGroup,
@@ -8494,11 +9156,30 @@ class Topology():
8494
9156
 
8495
9157
  """
8496
9158
  import uuid
9159
+ from topologicpy.Dictionary import Dictionary
8497
9160
 
8498
9161
  predefined_namespace_dns = uuid.UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
8499
9162
  namespace_uuid = uuid.uuid5(predefined_namespace_dns, namespace)
8500
- brep_string = Topology.BREPString(topology)
8501
- return uuid.uuid5(namespace_uuid, brep_string)
9163
+ cellComplexes = Topology.CellComplexes(topology)
9164
+ cells = Topology.Cells(topology)
9165
+ Shells = Topology.Shells(topology)
9166
+ Faces = Topology.Faces(topology)
9167
+ Wires = Topology.Wires(topology)
9168
+ Edges = Topology.Edges(topology)
9169
+ Vertices = Topology.Vertices(topology)
9170
+ Apertures = Topology.Apertures(topology, subTopologyType="all")
9171
+ subTopologies = cellComplexes+cells+Shells+Faces+Wires+Edges+Vertices+Apertures
9172
+ dictionaries = [Dictionary.PythonDictionary(Topology.Dictionary(topology))]
9173
+ dictionaries += [Dictionary.PythonDictionary(Topology.Dictionary(s)) for s in subTopologies]
9174
+ dict_str = str(dictionaries)
9175
+ top_geom = Topology.Geometry(topology, mantissa=6)
9176
+ verts_str = str(top_geom['vertices'])
9177
+ edges_str = str(top_geom['edges'])
9178
+ faces_str = str(top_geom['faces'])
9179
+ geo_str = verts_str+edges_str+faces_str
9180
+ final_str = geo_str+dict_str
9181
+ uuid_str = uuid.uuid5(namespace_uuid, final_str)
9182
+ return str(uuid_str)
8502
9183
 
8503
9184
  @staticmethod
8504
9185
  def View3D(*topologies, uuid = None, nameKey="name", colorKey="color", opacityKey="opacity", defaultColor=[256,256,256], defaultOpacity=0.5, transposeAxes: bool = True, mode: int = 0, meshSize: float = None, overwrite: bool = False, mantissa: int = 6, tolerance: float = 0.0001):
topologicpy/Wire.py CHANGED
@@ -373,13 +373,14 @@ class Wire():
373
373
  normal = Face.Normal(temp_face)
374
374
  flat_wire = Topology.Flatten(wire, direction=normal, origin=origin)
375
375
  edges = Topology.Edges(flat_wire)
376
+ original_edges = Topology.Edges(wire)
376
377
  offsets = []
377
378
  offset_edges = []
378
379
  final_vertices = []
379
380
  bisectors_list = []
380
381
  edge_dictionaries = []
381
- for edge in edges:
382
- d = Topology.Dictionary(edge)
382
+ for i, edge in enumerate(edges):
383
+ d = Topology.Dictionary(original_edges[i])
383
384
  d_offset = Dictionary.ValueAtKey(d, offsetKey)
384
385
  if d_offset == None:
385
386
  d_offset = offset
@@ -406,7 +407,7 @@ class Wire():
406
407
  if bisectors == True:
407
408
  bisectors_list.append(Edge.ByVertices(v_a, v1))
408
409
  if transferDictionaries == True:
409
- v1 = Topology.SetDictionary(v1, Topology.Dictionary(v_a))
410
+ v1 = Topology.SetDictionary(v1, Topology.Dictionary(v_a), silent=True)
410
411
  edge_dictionaries.append(Topology.Dictionary(edges[i]))
411
412
  final_vertices.append(v1)
412
413
  else:
@@ -463,15 +464,15 @@ class Wire():
463
464
  v1_2 = Topology.TranslateByDirectionDistance(Edge.StartVertex(o_edge_a),
464
465
  direction = Edge.Direction(o_edge_a),
465
466
  distance = d_stepOffsetB)
467
+ if transferDictionaries == True:
468
+ v1_1 = Topology.SetDictionary(v1_1, Topology.Dictionary(v_a), silent=True)
469
+ v1_2 = Topology.SetDictionary(v1_2, Topology.Dictionary(v_a), silent=True)
470
+ edge_dictionaries.append(Topology.Dictionary(v_a))
471
+ edge_dictionaries.append(Topology.Dictionary(edges[i]))
466
472
  bisectors_list.append(Edge.ByVertices(v_a, v1_1))
467
473
  bisectors_list.append(Edge.ByVertices(v_a, v1_2))
468
474
  final_vertices.append(v1_1)
469
475
  final_vertices.append(v1_2)
470
- if transferDictionaries == True:
471
- v1_1 = Topology.SetDictionary(v1_1, Topology.Dictionary(v_a))
472
- v1_2 = Topology.SetDictionary(v1_2, Topology.Dictionary(v_a))
473
- edge_dictionaries.append(Topology.Dictionary(v_a))
474
- edge_dictionaries.append(Topology.Dictionary(edges[i]))
475
476
  v_a = Edge.EndVertex(edges[-1])
476
477
  if Wire.IsClosed(wire) == False:
477
478
  v1 = Edge.EndVertex(offset_edges[-1])
@@ -481,12 +482,7 @@ class Wire():
481
482
  if bisectors == True:
482
483
  bisectors_list.append(Edge.ByVertices(v_a, v1))
483
484
 
484
-
485
485
  return_wire = Wire.ByVertices(final_vertices, close=Wire.IsClosed(wire))
486
- wire_edges = Topology.Edges(return_wire)
487
- if transferDictionaries == True:
488
- for i, wire_edge in enumerate(wire_edges):
489
- wire_edge = Topology.SetDictionary(wire_edge, edge_dictionaries[i], silent=True)
490
486
  if not Topology.IsInstance(return_wire, "Wire"):
491
487
  if not silent:
492
488
  print("Wire.ByOffset - Warning: The resulting wire is not well-formed, please check your offsets.")
@@ -494,6 +490,18 @@ class Wire():
494
490
  if not Wire.IsManifold(return_wire) and bisectors == False:
495
491
  if not silent:
496
492
  print("Wire.ByOffset - Warning: The resulting wire is non-manifold, please check your offsets.")
493
+ wire_edges = Topology.Edges(return_wire)
494
+
495
+ if transferDictionaries == True:
496
+ if not len(wire_edges) == len(edge_dictionaries):
497
+ if not silent:
498
+ print("Length of Wire Edges:", len(wire_edges))
499
+ print("Length of Edge Dictionaries:", len(edge_dictionaries))
500
+ print("Wire.ByOffset - Warning: The resulting wire is not well-formed, offsets may not be applied correctly. Please check your offsets.")
501
+ for i, wire_edge in enumerate(wire_edges):
502
+ if len(edge_dictionaries) > 0:
503
+ temp_dictionary = edge_dictionaries[min(i,len(edge_dictionaries)-1)]
504
+ wire_edge = Topology.SetDictionary(wire_edge, temp_dictionary, silent=True)
497
505
  if bisectors == True:
498
506
  temp_return_wire = Topology.SelfMerge(Cluster.ByTopologies(Topology.Edges(return_wire)+bisectors_list))
499
507
  if transferDictionaries == True:
@@ -738,7 +746,7 @@ class Wire():
738
746
  if not(([i1, i2] in g_edges) or ([i2, i1] in g_edges)):
739
747
  g_edges.append([i1, i2])
740
748
  used.append(end)
741
- new_wire = Topology.ByGeometry(vertices=g_vertices, edges=g_edges, faces=[], outputMode="wire")
749
+ new_wire = Topology.SelfMerge(Topology.ByGeometry(vertices=g_vertices, edges=g_edges, faces=[]))
742
750
  return new_wire
743
751
 
744
752
  @staticmethod
topologicpy/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.7.49'
1
+ __version__ = '0.7.51'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: topologicpy
3
- Version: 0.7.49
3
+ Version: 0.7.51
4
4
  Summary: An Advanced 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
@@ -3,33 +3,33 @@ topologicpy/Aperture.py,sha256=p9pUzTQSBWoUaDiug1V1R1hnEIEwYSXFg2t7iRAmNRY,2723
3
3
  topologicpy/Cell.py,sha256=uZ1gNVlfVtpi6sNgyfazP_nqe7mPjarE7MYzf8KoEI4,107930
4
4
  topologicpy/CellComplex.py,sha256=x474N-lo1krpdIGrWRAFRdDup5a_1V-mLORTS6ZGZ7M,48227
5
5
  topologicpy/Cluster.py,sha256=TZXuxzdaUr6OHSWnjWpjCOMlVj6YHBH8aUVbDVsncVA,54999
6
- topologicpy/Color.py,sha256=UlmRcCSOhqcM_OyMWz4t3Kr75KcgXDhz3uctAJ2n7Ic,18031
6
+ topologicpy/Color.py,sha256=FrxX2yILqWvYrqD8kBaknfMfOR_phJOmhvTvFc07bY4,18065
7
7
  topologicpy/Context.py,sha256=ppApYKngZZCQBFWaxIMi2z2dokY23c935IDCBosxDAE,3055
8
8
  topologicpy/DGL.py,sha256=Dd6O08D-vSxpjHYgKm45JpKiaeGvWlg1BRMzYMAXGNc,138991
9
- topologicpy/Dictionary.py,sha256=KqJ29YyE23Y3Xc6XmKLSCZXRfBvm-OEOxlMZ4dt-rfM,27094
9
+ topologicpy/Dictionary.py,sha256=X_WARSYtWtYIsEUKdLH-plZmGZ3pHz_FBFxxeHGHdrU,27065
10
10
  topologicpy/Edge.py,sha256=vhYHkobSLGSWV-oe2oJFFDobqFToDyb7s71yQ840AAA,65166
11
11
  topologicpy/EnergyModel.py,sha256=XcCP55VW5WHDIIKcURijmBOZEgNUDEn_V9h5EejkntA,53876
12
- topologicpy/Face.py,sha256=pn0LGusTPKLrHEMhY94_Bs3rc4wUpIyEqyW9q-ftdG0,115379
12
+ topologicpy/Face.py,sha256=7GCYo4ATkMW1skiv4gXOVARM29A7Buim9lTQu57B22Y,115489
13
13
  topologicpy/Graph.py,sha256=1dtcE342b6d7cTiMbtUWWOud6Vu0vHaf4HP2eG_-iqg,402544
14
14
  topologicpy/Grid.py,sha256=3-sn7CHWGcXk18XCnHjsUttNJTWwmN63g_Insj__p04,18218
15
15
  topologicpy/Helper.py,sha256=i-AfI29NMsZXBaymjilfvxQbuS3wpYbpPw4RWu1YCHs,16358
16
16
  topologicpy/Honeybee.py,sha256=vcBECJlgWVjNNdD9ZmjNik_pA1Y_ZNoOorsQb2CiyGA,21965
17
17
  topologicpy/Matrix.py,sha256=umgR7An919-wGInXJ1wpqnoQ2jCPdyMe2rcWTZ16upk,8079
18
18
  topologicpy/Neo4j.py,sha256=YvtF7RYUMATEZ8iHwFwK_MOxEDyARby2DTI2CCK6-cI,19694
19
- topologicpy/Plotly.py,sha256=o0JWE51lViK-UJUpIpf2Yusk_vTX5hfNMyFXFinKSRg,106048
19
+ topologicpy/Plotly.py,sha256=gfGadsDBgXOeefzzceXkVshqONuPtkGiW-XNVuT2rrA,106193
20
20
  topologicpy/Polyskel.py,sha256=EFsuh2EwQJGPLiFUjvtXmAwdX-A4r_DxP5hF7Qd3PaU,19829
21
21
  topologicpy/PyG.py,sha256=3U59QObO56EBwrvaplGeLZhbTao0gJCYhWm3oTpjFAE,109505
22
22
  topologicpy/Shell.py,sha256=joahFtpRQTWJpQOmi3qU4Xe0Sx2XXeayHlXTNx8CzMk,87610
23
23
  topologicpy/Speckle.py,sha256=rUS6PCaxIjEF5_fUruxvMH47FMKg-ohcoU0qAUb-yNM,14267
24
24
  topologicpy/Sun.py,sha256=42tDWMYpwRG7Z2Qjtp94eRgBuqySq7k8TgNUZDK7QxQ,36837
25
- topologicpy/Topology.py,sha256=j_1vCdrOMRi525lqFn63hIJYuD3ZQ8AhHiB8vIiz0zU,379524
25
+ topologicpy/Topology.py,sha256=100DUg9EUcFg3K9wlNdaKrXcFEZLvqHsexs3R-8pbYw,416196
26
26
  topologicpy/Vector.py,sha256=WQQUbwrg7VKImtxuBUi2i-FRiPT77WlrzLP05gdXKM8,33079
27
27
  topologicpy/Vertex.py,sha256=bLY60YWoMsgCgHk7F7k9F93Sq2FJ6AzUcTfJ83NZfHA,71107
28
- topologicpy/Wire.py,sha256=9EJE0Iq3nGz5X7Suy6xxjmuOpfV49By6WH98UAL_7m4,153532
28
+ topologicpy/Wire.py,sha256=h-vcKAuyHVvfX34nJx4bVF-AxeaUCx4NbVzGBq98M9o,154201
29
29
  topologicpy/__init__.py,sha256=D7ky87CAQMiS2KE6YLvcTLkTgA2PY7rASe6Z23pjp9k,872
30
- topologicpy/version.py,sha256=hRb_Cf1UnQBFBHqRUC49s9X_xlGuyOLU_zTL7Xm-1Oc,23
31
- topologicpy-0.7.49.dist-info/LICENSE,sha256=BRNw73R2WdDBICtwhI3wm3cxsaVqLTAGuRwrTltcfxs,1068
32
- topologicpy-0.7.49.dist-info/METADATA,sha256=yp1EQDMypWHv6U5kmf0R7RFA8gAc9eX2fxfHqKA7FHw,10918
33
- topologicpy-0.7.49.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
34
- topologicpy-0.7.49.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
35
- topologicpy-0.7.49.dist-info/RECORD,,
30
+ topologicpy/version.py,sha256=Nl_BpJIhLQbbkeSiv2q5IgytCINu26pAUqkPjuq0FPg,23
31
+ topologicpy-0.7.51.dist-info/LICENSE,sha256=BRNw73R2WdDBICtwhI3wm3cxsaVqLTAGuRwrTltcfxs,1068
32
+ topologicpy-0.7.51.dist-info/METADATA,sha256=E68AdA4I73vasiialUPW6sDhhX4xFhYSwysUl_7ZR1g,10918
33
+ topologicpy-0.7.51.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
34
+ topologicpy-0.7.51.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
35
+ topologicpy-0.7.51.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (73.0.1)
2
+ Generator: setuptools (74.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5