topologicpy 0.8.26__py3-none-any.whl → 0.8.29__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/Face.py CHANGED
@@ -1927,6 +1927,34 @@ class Face():
1927
1927
  else:
1928
1928
  inverted_face = Face.ByWires(inverted_wire, internal_boundaries, tolerance=tolerance)
1929
1929
  return inverted_face
1930
+ @staticmethod
1931
+ def IsConvex(face, mantissa: int = 6, silent: bool = False) -> bool:
1932
+ """
1933
+ Returns True if the input face is convex. Returns False otherwise.
1934
+
1935
+ Parameters
1936
+ ----------
1937
+ face : topologic_core.Face
1938
+ The input face.
1939
+ mantissa : int , optional
1940
+ The length of the desired mantissa. The default is 6.
1941
+ silent : bool , optional
1942
+ If set to True no warnings or errors are printed. The default is False.
1943
+ Returns
1944
+ -------
1945
+ bool
1946
+ True if the nput face is convex. False otherwise.
1947
+
1948
+ """
1949
+ from topologicpy.Topology import Topology
1950
+
1951
+ if not Topology.IsInstance(face, "face"):
1952
+ if not silent:
1953
+ print("Face.IsConvex - Error: The input face parameter is not a valid topologic face. Returning None.")
1954
+ return None
1955
+ eb = Face.ExternalBoundary(face)
1956
+ eb = Face.ByWire(eb)
1957
+ return all(Face.InteriorAngles(eb)) < 180
1930
1958
 
1931
1959
  @staticmethod
1932
1960
  def IsCoplanar(faceA, faceB, mantissa: int = 6, tolerance: float = 0.0001) -> bool:
@@ -2468,9 +2496,9 @@ class Face():
2468
2496
  flat_face = Topology.Difference(flat_face, Face.ByWire(obs))
2469
2497
 
2470
2498
  # Check that the viewpoint is inside the face
2471
- if not Vertex.IsInternal(flat_vertex, flat_face):
2472
- print("Face.Isovist - Error: The viewpoint is not inside the face. Returning None.")
2473
- return None
2499
+ # if not Vertex.IsInternal(flat_vertex, flat_face):
2500
+ # print("Face.Isovist - Error: The viewpoint is not inside the face. Returning None.")
2501
+ # return None
2474
2502
  targets = Topology.Vertices(flat_face)
2475
2503
  distances = []
2476
2504
  for target in targets:
@@ -3544,7 +3572,7 @@ class Face():
3544
3572
  return Face.ByWire(wire, tolerance=tolerance)
3545
3573
 
3546
3574
  @staticmethod
3547
- def Triangulate(face, mode: int = 0, meshSize: float = None, mantissa: int = 6, tolerance: float = 0.0001) -> list:
3575
+ def Triangulate(face, mode: int = 0, meshSize: float = None, mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False) -> list:
3548
3576
  """
3549
3577
  Triangulates the input face and returns a list of faces.
3550
3578
 
@@ -3571,6 +3599,8 @@ class Face():
3571
3599
  The desired length of the mantissa. The default is 6.
3572
3600
  tolerance : float , optional
3573
3601
  The desired tolerance. The default is 0.0001.
3602
+ silent : bool , optional
3603
+ If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
3574
3604
 
3575
3605
  Returns
3576
3606
  -------
@@ -3638,7 +3668,8 @@ class Face():
3638
3668
  from topologicpy.Topology import Topology
3639
3669
 
3640
3670
  if not Topology.IsInstance(face, "Face"):
3641
- print("Face.Triangulate - Error: The input face parameter is not a valid face. Returning None.")
3671
+ if not silent:
3672
+ print("Face.Triangulate - Error: The input face parameter is not a valid face. Returning None.")
3642
3673
  return None
3643
3674
  if not meshSize:
3644
3675
  bounding_face = Face.BoundingRectangle(face)
@@ -3713,7 +3744,8 @@ class Face():
3713
3744
  return faces
3714
3745
 
3715
3746
  if not Topology.IsInstance(face, "Face"):
3716
- print("Face.Triangulate - Error: The input face parameter is not a valid face. Returning None.")
3747
+ if not silent:
3748
+ print("Face.Triangulate - Error: The input face parameter is not a valid face. Returning None.")
3717
3749
  return None
3718
3750
  vertices = Topology.Vertices(face)
3719
3751
  if len(vertices) == 3: # Already a triangle
topologicpy/Graph.py CHANGED
@@ -2455,6 +2455,204 @@ class Graph:
2455
2455
 
2456
2456
  @staticmethod
2457
2457
  def ByIFCFile(file,
2458
+ includeTypes: list = [],
2459
+ excludeTypes: list = [],
2460
+ includeRels: list = [],
2461
+ excludeRels: list = [],
2462
+ transferDictionaries: bool = False,
2463
+ useInternalVertex: bool = False,
2464
+ storeBREP: bool = False,
2465
+ removeCoplanarFaces: bool = False,
2466
+ xMin: float = -0.5, yMin: float = -0.5, zMin: float = -0.5,
2467
+ xMax: float = 0.5, yMax: float = 0.5, zMax: float = 0.5,
2468
+ epsilon: float = 0.0001,
2469
+ tolerance: float = 0.0001,
2470
+ silent: bool = False):
2471
+
2472
+ """
2473
+ Create a Graph from an IFC file. This code is partially based on code from Bruno Postle.
2474
+
2475
+ Parameters
2476
+ ----------
2477
+ file : file
2478
+ The input IFC file
2479
+ includeTypes : list , optional
2480
+ A list of IFC object types to include in the graph. The default is [] which means all object types are included.
2481
+ excludeTypes : list , optional
2482
+ A list of IFC object types to exclude from the graph. The default is [] which mean no object type is excluded.
2483
+ includeRels : list , optional
2484
+ A list of IFC relationship types to include in the graph. The default is [] which means all relationship types are included.
2485
+ excludeRels : list , optional
2486
+ A list of IFC relationship types to exclude from the graph. The default is [] which mean no relationship type is excluded.
2487
+ transferDictionaries : bool , optional
2488
+ NOT USED. If set to True, the dictionaries from the IFC file will be transferred to the topology. Otherwise, they won't. The default is False.
2489
+ useInternalVertex : bool , optional
2490
+ If set to True, use an internal vertex to represent the subtopology. Otherwise, use its centroid. The default is False.
2491
+ storeBREP : bool , optional
2492
+ If set to True, store the BRep of the subtopology in its representative vertex. The default is False.
2493
+ removeCoplanarFaces : bool , optional
2494
+ If set to True, coplanar faces are removed. Otherwise they are not. The default is False.
2495
+ xMin : float, optional
2496
+ The desired minimum value to assign for a vertex's X coordinate. The default is -0.5.
2497
+ yMin : float, optional
2498
+ The desired minimum value to assign for a vertex's Y coordinate. The default is -0.5.
2499
+ zMin : float, optional
2500
+ The desired minimum value to assign for a vertex's Z coordinate. The default is -0.5.
2501
+ xMax : float, optional
2502
+ The desired maximum value to assign for a vertex's X coordinate. The default is 0.5.
2503
+ yMax : float, optional
2504
+ The desired maximum value to assign for a vertex's Y coordinate. The default is 0.5.
2505
+ zMax : float, optional
2506
+ The desired maximum value to assign for a vertex's Z coordinate. The default is 0.5.
2507
+ tolerance : float , optional
2508
+ The desired tolerance. The default is 0.0001.
2509
+
2510
+ Returns
2511
+ -------
2512
+ topologic_core.Graph
2513
+ The created graph.
2514
+
2515
+ """
2516
+
2517
+ from topologicpy.Vertex import Vertex
2518
+ from topologicpy.Edge import Edge
2519
+ from topologicpy.Dictionary import Dictionary
2520
+ from topologicpy.Topology import Topology
2521
+
2522
+ def vertex_at_key_value(vertices, key, value):
2523
+ for v in vertices:
2524
+ d = Topology.Dictionary(v)
2525
+ d_value = Dictionary.ValueAtKey(d, key)
2526
+ if value == d_value:
2527
+ return v
2528
+ return None
2529
+
2530
+ def get_vertices(includeTypes=[], excludeTypes=[], removeCoplanarFaces=False, storeBREP=False, useInternalVertex=useInternalVertex, epsilon=0.0001, tolerance=0.0001):
2531
+ # Get the topologies
2532
+ topologies = Topology.ByIFCFile(file,
2533
+ includeTypes=includeTypes,
2534
+ excludeTypes=excludeTypes,
2535
+ transferDictionaries=True,
2536
+ removeCoplanarFaces=removeCoplanarFaces,
2537
+ epsilon=epsilon,
2538
+ tolerance=tolerance)
2539
+ vertices = []
2540
+ for topology in topologies:
2541
+ if Topology.IsInstance(topology, "Topology"):
2542
+ if useInternalVertex == True:
2543
+ v = Topology.InternalVertex(topology)
2544
+ else:
2545
+ v = Topology.Centroid(topology)
2546
+ d = Topology.Dictionary(topology)
2547
+ if storeBREP:
2548
+ d = Dictionary.SetValueAtKey(d, "BREP", Topology.BREPString(topology))
2549
+ if Topology.IsInstance(v, "vertex"):
2550
+ v = Topology.SetDictionary(v, Topology.Dictionary(topology))
2551
+ vertices.append(v)
2552
+ else:
2553
+ if not silent:
2554
+ ifc_id = Dictionary.ValueAtKey(Topology.Dictionary(topology), "IFC_global_id", 0)
2555
+ print(f"Graph.ByIFCFile - Warning: Could not create a vertex for entity {ifc_id}. Skipping")
2556
+ return vertices
2557
+
2558
+ # Get the relationships
2559
+ def get_relationships(ifc_file, includeRels=[], excludeRels=[]):
2560
+ include_set = set(s.lower() for s in includeRels)
2561
+ exclude_set = set(s.lower() for s in excludeRels)
2562
+
2563
+ relationships = [
2564
+ rel for rel in ifc_file.by_type("IfcRelationship")
2565
+ if (rel.is_a().lower() not in exclude_set) and
2566
+ (not include_set or rel.is_a().lower() in include_set)
2567
+ ]
2568
+
2569
+ return relationships
2570
+ def get_edges(ifc_relationships, vertices):
2571
+ tuples = []
2572
+ edges = []
2573
+
2574
+ for ifc_rel in ifc_relationships:
2575
+ source = None
2576
+ destinations = []
2577
+ if ifc_rel.is_a("IfcRelConnectsPorts"):
2578
+ source = ifc_rel.RelatingPort
2579
+ destinations = ifc_rel.RelatedPorts
2580
+ elif ifc_rel.is_a("IfcRelConnectsPortToElement"):
2581
+ source = ifc_rel.RelatingPort
2582
+ destinations = [ifc_rel.RelatedElement]
2583
+ elif ifc_rel.is_a("IfcRelAggregates"):
2584
+ source = ifc_rel.RelatingObject
2585
+ destinations = ifc_rel.RelatedObjects
2586
+ elif ifc_rel.is_a("IfcRelNests"):
2587
+ source = ifc_rel.RelatingObject
2588
+ destinations = ifc_rel.RelatedObjects
2589
+ elif ifc_rel.is_a("IfcRelAssignsToGroup"):
2590
+ source = ifc_rel.RelatingGroup
2591
+ destinations = ifc_rel.RelatedObjects
2592
+ elif ifc_rel.is_a("IfcRelConnectsPathElements"):
2593
+ source = ifc_rel.RelatingElement
2594
+ destinations = [ifc_rel.RelatedElement]
2595
+ elif ifc_rel.is_a("IfcRelConnectsStructuralMember"):
2596
+ source = ifc_rel.RelatingStructuralMember
2597
+ destinations = [ifc_rel.RelatedStructuralConnection]
2598
+ elif ifc_rel.is_a("IfcRelContainedInSpatialStructure"):
2599
+ source = ifc_rel.RelatingStructure
2600
+ destinations = ifc_rel.RelatedElements
2601
+ elif ifc_rel.is_a("IfcRelFillsElement"):
2602
+ source = ifc_rel.RelatingOpeningElement
2603
+ destinations = [ifc_rel.RelatedBuildingElement]
2604
+ elif ifc_rel.is_a("IfcRelSpaceBoundary"):
2605
+ source = ifc_rel.RelatingSpace
2606
+ destinations = [ifc_rel.RelatedBuildingElement]
2607
+ elif ifc_rel.is_a("IfcRelVoidsElement"):
2608
+ source = ifc_rel.RelatingBuildingElement
2609
+ destinations = [ifc_rel.RelatedOpeningElement]
2610
+ elif ifc_rel.is_a("IfcRelDefinesByProperties") or ifc_rel.is_a("IfcRelAssociatesMaterial") or ifc_rel.is_a("IfcRelDefinesByType"):
2611
+ source = None
2612
+ destinations = None
2613
+ else:
2614
+ print("Graph.ByIFCFile - Warning: The relationship", ifc_rel, "is not supported. Skipping.")
2615
+ if source:
2616
+ sv = vertex_at_key_value(vertices, key="IFC_global_id", value=getattr(source, 'GlobalId', 0))
2617
+ if sv:
2618
+ si = Vertex.Index(sv, vertices, tolerance=tolerance)
2619
+ if not si == None:
2620
+ for destination in destinations:
2621
+ if destination == None:
2622
+ continue
2623
+ ev = vertex_at_key_value(vertices, key="IFC_global_id", value=getattr(destination, 'GlobalId', 0))
2624
+ if ev:
2625
+ ei = Vertex.Index(ev, vertices, tolerance=tolerance)
2626
+ if not ei == None:
2627
+ if not si == ei:
2628
+ if not [si,ei] in tuples:
2629
+ tuples.append([si,ei])
2630
+ tuples.append([ei,si])
2631
+ e = Edge.ByVertices([sv,ev])
2632
+ if Topology.IsInstance(e, "edge"):
2633
+ d = Dictionary.ByKeysValues(["IFC_global_id", "IFC_name", "IFC_type"], [ifc_rel.id(), ifc_rel.Name, ifc_rel.is_a()])
2634
+ e = Topology.SetDictionary(e, d)
2635
+ edges.append(e)
2636
+ else:
2637
+ if not silent:
2638
+ if not silent:
2639
+ print(f"Graph.ByIFCFile - Warning: Could not create an edge for relationship {ifc_rel.id()}. Skipping")
2640
+
2641
+ return edges
2642
+
2643
+ vertices = get_vertices(includeTypes=includeTypes,
2644
+ excludeTypes=excludeTypes,
2645
+ removeCoplanarFaces=removeCoplanarFaces,
2646
+ storeBREP=storeBREP,
2647
+ useInternalVertex=useInternalVertex,
2648
+ epsilon=epsilon,
2649
+ tolerance=0.0001)
2650
+ relationships = get_relationships(file, includeRels=includeRels, excludeRels=excludeRels)
2651
+ edges = get_edges(relationships, vertices)
2652
+ return Graph.ByVerticesEdges(vertices, edges)
2653
+
2654
+ @staticmethod
2655
+ def ByIFCFile_old(file,
2458
2656
  includeTypes: list = [],
2459
2657
  excludeTypes: list = [],
2460
2658
  includeRels: list = [],
topologicpy/Grid.py CHANGED
@@ -286,12 +286,11 @@ class Grid():
286
286
  vTempVec = Vector.Multiply(uvVector, v, tolerance=tolerance)
287
287
  gridVertex = Vertex.ByCoordinates(Vertex.X(origin, mantissa=mantissa)+uTempVec[0], Vertex.Y(origin, mantissa=mantissa)+vTempVec[1], Vertex.Z(origin, mantissa=mantissa)+uTempVec[2])
288
288
  if clip and Topology.IsInstance(face, "Face"):
289
- gridVertex = gridVertex.Intersect(face, False)
290
- if Topology.IsInstance(gridVertex, "Vertex"):
291
- d = Dictionary.ByKeysValues(["u","v"],[u,v])
292
- if d:
293
- gridVertex.SetDictionary(d)
294
- gridVertices.append(gridVertex)
289
+ if Vertex.IsInternal(gridVertex, face):
290
+ d = Dictionary.ByKeysValues(["u","v"],[u,v])
291
+ if d:
292
+ gridVertex.SetDictionary(d)
293
+ gridVertices.append(gridVertex)
295
294
  grid = None
296
295
  if len(gridVertices) > 0:
297
296
  grid = Cluster.ByTopologies(gridVertices)
@@ -347,12 +346,17 @@ class Grid():
347
346
  for v in vRange:
348
347
  gridVertex = Face.VertexByParameters(face, u, v)
349
348
  if clip and Topology.IsInstance(face, "Face"):
350
- gridVertex = gridVertex.Intersect(face, False)
351
- if Topology.IsInstance(gridVertex, "Vertex"):
352
- d = Dictionary.ByKeysValues(["u","v"],[u,v])
353
- if d:
354
- gridVertex.SetDictionary(d)
355
- gridVertices.append(gridVertex)
349
+ if Vertex.IsInternal(gridVertex, face):
350
+ d = Dictionary.ByKeysValues(["u","v"],[u,v])
351
+ if d:
352
+ gridVertex.SetDictionary(d)
353
+ gridVertices.append(gridVertex)
354
+ # gridVertex = gridVertex.Intersect(face, False)
355
+ # if Topology.IsInstance(gridVertex, "Vertex"):
356
+ # d = Dictionary.ByKeysValues(["u","v"],[u,v])
357
+ # if d:
358
+ # gridVertex.SetDictionary(d)
359
+ # gridVertices.append(gridVertex)
356
360
  grid = None
357
361
  if len(gridVertices) > 0:
358
362
  grid = Cluster.ByTopologies(gridVertices)
topologicpy/Plotly.py CHANGED
@@ -592,6 +592,7 @@ class Plotly:
592
592
  mode = "markers+text"
593
593
  else:
594
594
  mode = "markers"
595
+
595
596
  vData2 = go.Scatter3d(x=x,
596
597
  y=y,
597
598
  z=z,
@@ -603,11 +604,13 @@ class Plotly:
603
604
  opacity=1,
604
605
  sizemode="diameter"),
605
606
  mode=mode,
607
+ customdata = labels,
606
608
  legendgroup=legendGroup,
607
609
  legendrank=legendRank,
608
610
  text=labels,
609
611
  hoverinfo='text',
610
- hovertext=labels
612
+ hovertext=labels,
613
+ hovertemplate=["Click "+label for label in labels]
611
614
  )
612
615
  if borderWidth > 0 or borderWidthKey:
613
616
  vData1 = go.Scatter3d(x=x,
@@ -676,14 +679,13 @@ class Plotly:
676
679
  labels = []
677
680
  for j, elements_cluster in enumerate(elements_clusters):
678
681
  d_color = color
679
- labels.append("Edge_"+str(j+1).zfill(n))
680
682
  d = dict_clusters[j][0] # All dicitonaries have same values in dictionaries, so take first one.
681
683
  if d:
682
684
  if not colorKey == None:
683
685
  d_color = Dictionary.ValueAtKey(d, key=colorKey) or color
684
686
  d_color = Color.AnyToHex(d_color)
685
687
  if not labelKey == None:
686
- label = str(Dictionary.ValueAtKey(d, key=labelKey)) or ""
688
+ labels.append(str(Dictionary.ValueAtKey(d, labelKey, "")))
687
689
  if not widthKey == None:
688
690
  e_width = Dictionary.ValueAtKey(d, key=widthKey)
689
691
  if not e_width == None:
@@ -727,8 +729,10 @@ class Plotly:
727
729
  line=dict(color=d_color, width=width),
728
730
  legendgroup=legendGroup,
729
731
  legendrank=legendRank,
730
- text=label,
731
- hoverinfo='text')
732
+ text=labels,
733
+ customdata=labels,
734
+ hoverinfo='text',
735
+ hovertext=labels)
732
736
  traces.append(trace)
733
737
  else:
734
738
  x = []
@@ -809,7 +813,8 @@ class Plotly:
809
813
  faceLegendLabel="Topology Faces",
810
814
  faceLegendRank=3,
811
815
  faceLegendGroup=3,
812
- intensityKey=None, intensities=[], colorScale="viridis", mantissa=6, tolerance=0.0001):
816
+ intensityKey=None, intensities=[], colorScale="viridis",
817
+ mantissa=6, tolerance=0.0001, silent=False):
813
818
  """
814
819
  Creates plotly face, edge, and vertex data.
815
820
 
@@ -1188,7 +1193,7 @@ class Plotly:
1188
1193
  f_dictionaries = []
1189
1194
  all_triangles = []
1190
1195
  for tp_face in tp_faces:
1191
- triangles = Face.Triangulate(tp_face, tolerance=tolerance)
1196
+ triangles = Face.Triangulate(tp_face, tolerance=tolerance, silent=silent)
1192
1197
  if isinstance(triangles, list):
1193
1198
  for tri in triangles:
1194
1199
  if faceColorKey or faceOpacityKey or faceLabelKey or faceGroupKey: