topologicpy 0.8.25__py3-none-any.whl → 0.8.28__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 = [],
@@ -4487,7 +4685,7 @@ class Graph:
4487
4685
  weightClosenessCentrality: float = 0.0,
4488
4686
  weightDegreeCentrality: float = 0.0,
4489
4687
  weightDiameter: float = 0.0,
4490
- weightEigenCentrality: float = 0.0,
4688
+ weightEigenVectorCentrality: float = 0.0,
4491
4689
  weightGlobalClusteringCoefficient: float = 0.0,
4492
4690
  weightPageRank: float = 0.0,
4493
4691
  weightStructure: float = 0.0,
@@ -4521,8 +4719,8 @@ class Graph:
4521
4719
  The desired weight for degree centrality similarity (graph-level and node-level). Default is 0.0.
4522
4720
  weightDiameter : float , optional
4523
4721
  The desired weight for diameter similarity (graph-level and node-level). Default is 0.0.
4524
- weightEigenCentrality : float , optional
4525
- The desired weight for eigen centrality similarity (graph-level and node-level). Default is 0.0.
4722
+ weightEigenVectorCentrality : float , optional
4723
+ The desired weight for eigenvector centrality similarity (graph-level and node-level). Default is 0.0.
4526
4724
  weightGeometry : float , optional
4527
4725
  The desired weight for geometric similarity (vertex positions). Default is 0.0.
4528
4726
  weightGlobalClusteringCoefficient : float , optional
@@ -4559,7 +4757,7 @@ class Graph:
4559
4757
  "betwenness_centrality"
4560
4758
  "closeness_centrality"
4561
4759
  "degree_centrality"
4562
- "eigen_centrality"
4760
+ "eigenvector_centrality"
4563
4761
  "geometry"
4564
4762
  "global_clustering_coefficient"
4565
4763
  "jaccard"
@@ -4722,9 +4920,9 @@ class Graph:
4722
4920
  diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
4723
4921
  return round((1 - diff), mantissa)
4724
4922
 
4725
- def eigen_centrality_similarity(graphA, graphB, mantissa=6):
4726
- v1 = safe_mean(Graph.EigenCentrality(graphA))
4727
- v2 = safe_mean(Graph.EigenCentrality(graphB))
4923
+ def eigenvector_centrality_similarity(graphA, graphB, mantissa=6):
4924
+ v1 = safe_mean(Graph.EigenVectorCentrality(graphA))
4925
+ v2 = safe_mean(Graph.EigenVectorCentrality(graphB))
4728
4926
  if v1 == 0 and v2 == 0:
4729
4927
  return 1
4730
4928
  diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
@@ -4807,7 +5005,7 @@ class Graph:
4807
5005
  weightClosenessCentrality,
4808
5006
  weightDegreeCentrality,
4809
5007
  weightDiameter,
4810
- weightEigenCentrality,
5008
+ weightEigenVectorCentrality,
4811
5009
  weightGlobalClusteringCoefficient,
4812
5010
  weightPageRank,
4813
5011
  weightStructure,
@@ -4819,7 +5017,7 @@ class Graph:
4819
5017
  closeness_centrality_score = closeness_centrality_similarity(graphA, graphB, mantissa=mantissa) if weightClosenessCentrality else 0
4820
5018
  degree_centrality_score = degree_centrality_similarity(graphA, graphB, mantissa=mantissa) if weightDegreeCentrality else 0
4821
5019
  diameter_score = diameter_similarity(graphA, graphB, mantissa=mantissa) if weightDiameter else 0
4822
- eigen_centrality_score = eigen_centrality_similarity(graphA, graphB, mantissa=mantissa) if weightEigenCentrality else 0
5020
+ eigenvector_centrality_score = eigenvector_centrality_similarity(graphA, graphB, mantissa=mantissa) if weightEigenVectorCentrality else 0
4823
5021
  global_clustering_coefficient_score = global_clustering_coefficient_similarity(graphA, graphB, mantissa=mantissa) if weightGlobalClusteringCoefficient else 0
4824
5022
  geometry_score = geometry_similarity(graphA, graphB, mantissa=mantissa) if weightGeometry else 0
4825
5023
  jaccard_score = weighted_jaccard_similarity(graphA, graphB, vertexIDKey=vertexIDKey, edgeWeightKey=edgeWeightKey, mantissa=mantissa) if weightJaccard else 0
@@ -4834,7 +5032,7 @@ class Graph:
4834
5032
  closeness_centrality_score * weightClosenessCentrality +
4835
5033
  degree_centrality_score * weightDegreeCentrality +
4836
5034
  diameter_score * weightDiameter +
4837
- eigen_centrality_score * weightEigenCentrality +
5035
+ eigenvector_centrality_score * weightEigenVectorCentrality +
4838
5036
  geometry_score * weightGeometry +
4839
5037
  global_clustering_coefficient_score * weightGlobalClusteringCoefficient +
4840
5038
  jaccard_score * weightJaccard +
@@ -4854,7 +5052,7 @@ class Graph:
4854
5052
  "betwenness_centrality": round(betweenness_centrality_score, mantissa),
4855
5053
  "closeness_centrality": round(closeness_centrality_score, mantissa),
4856
5054
  "degree_centrality": round(degree_centrality_score, mantissa),
4857
- "eigen_centrality": round(eigen_centrality_score, mantissa),
5055
+ "eigenvector_centrality": round(eigenvector_centrality_score, mantissa),
4858
5056
  "geometry": round(geometry_score, mantissa),
4859
5057
  "global_clustering_coefficient": round(global_clustering_coefficient_score, mantissa),
4860
5058
  "jaccard": round(jaccard_score, mantissa),
@@ -5239,9 +5437,9 @@ class Graph:
5239
5437
  if "len" in weightKey.lower() or "dis" in weightKey.lower():
5240
5438
  weightKey = "length"
5241
5439
  nx_graph = Graph.NetworkXGraph(graph)
5242
- elements = Graph.Vertices(graph)
5243
- elements_dict = nx.closeness_centrality(nx_graph, distance=weightKey, wf_improved=nxCompatible)
5244
- values = [round(v, mantissa) for v in list(elements_dict.values())]
5440
+ vertices = Graph.Vertices(graph)
5441
+ vertices_dict = nx.closeness_centrality(nx_graph, distance=weightKey, wf_improved=nxCompatible)
5442
+ values = [round(v, mantissa) for v in list(vertices_dict.values())]
5245
5443
  if normalize == True:
5246
5444
  if mantissa > 0: # We cannot round numbers from 0 to 1 with a mantissa = 0.
5247
5445
  values = [round(v, mantissa) for v in Helper.Normalize(values)]
@@ -5254,10 +5452,10 @@ class Graph:
5254
5452
  max_value = max(values)
5255
5453
 
5256
5454
  for i, value in enumerate(values):
5257
- d = Topology.Dictionary(elements[i])
5455
+ d = Topology.Dictionary(vertices[i])
5258
5456
  color = Color.AnyToHex(Color.ByValueInRange(value, minValue=min_value, maxValue=max_value, colorScale=colorScale))
5259
5457
  d = Dictionary.SetValuesAtKeys(d, [key, colorKey], [value, color])
5260
- elements[i] = Topology.SetDictionary(elements[i], d)
5458
+ vertices[i] = Topology.SetDictionary(vertices[i], d)
5261
5459
 
5262
5460
  return values
5263
5461
 
@@ -6051,7 +6249,7 @@ class Graph:
6051
6249
  return list(dict.fromkeys(edges)) # remove duplicates
6052
6250
 
6053
6251
  @staticmethod
6054
- def EigenCentrality(graph, normalize: bool = False, key: str = "eigen_centrality", colorKey: str = "ec_color", colorScale: str = "viridis", mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
6252
+ def EigenVectorCentrality(graph, normalize: bool = False, key: str = "eigen_vector_centrality", colorKey: str = "evc_color", colorScale: str = "viridis", mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
6055
6253
  """
6056
6254
  Returns the eigenvector centrality of the input graph. The order of the returned list is the same as the order of vertices.
6057
6255
 
@@ -6064,9 +6262,9 @@ class Graph:
6064
6262
  normalize : bool, optional
6065
6263
  If set to True, the centrality values are normalized to be in the range 0 to 1. The default is False.
6066
6264
  key : str, optional
6067
- The desired dictionary key under which to store the eigenvector centrality score. The default is "eigen_centrality".
6265
+ The desired dictionary key under which to store the eigenvector centrality score. The default is "eigen_vector_centrality".
6068
6266
  colorKey : str, optional
6069
- The desired dictionary key under which to store the eigenvector centrality color. The default is "ec_color".
6267
+ The desired dictionary key under which to store the eigenvector centrality color. The default is "evc_color".
6070
6268
  colorScale : str, optional
6071
6269
  The desired type of Plotly color scale to use (e.g., "viridis", "plasma"). Default is "viridis".
6072
6270
  For a full list of names, see https://plotly.com/python/builtin-colorscales/.
@@ -6092,7 +6290,7 @@ class Graph:
6092
6290
 
6093
6291
  if not Topology.IsInstance(graph, "graph"):
6094
6292
  if not silent:
6095
- print("Graph.EigenCentrality - Error: The input graph is not a valie Topologic Graph. Returning None.")
6293
+ print("Graph.EigenVectorCentrality - Error: The input graph is not a valie Topologic Graph. Returning None.")
6096
6294
  return None
6097
6295
  adjacency_matrix = Graph.AdjacencyMatrix(graph)
6098
6296
  vertices = Graph.Vertices(graph)
@@ -10474,9 +10672,9 @@ class Graph:
10474
10672
  return outgoing_vertices
10475
10673
 
10476
10674
  @staticmethod
10477
- def PageRank(graph, alpha: float = 0.85, maxIterations: int = 100, normalize: bool = True, directed: bool = False, key: str = "page_rank", mantissa: int = 6, tolerance: float = 0.0001):
10675
+ def PageRank(graph, alpha: float = 0.85, maxIterations: int = 100, normalize: bool = True, directed: bool = False, key: str = "page_rank", colorKey="pr_color", colorScale="viridis", mantissa: int = 6, tolerance: float = 0.0001):
10478
10676
  """
10479
- Calculates PageRank scores for nodes in a directed graph. see https://en.wikipedia.org/wiki/PageRank.
10677
+ Calculates PageRank scores for vertices in a directed graph. see https://en.wikipedia.org/wiki/PageRank.
10480
10678
 
10481
10679
  Parameters
10482
10680
  ----------
@@ -10492,6 +10690,11 @@ class Graph:
10492
10690
  If set to True, the graph is considered as a directed graph. Otherwise, it will be considered as an undirected graph. The default is False.
10493
10691
  key : str , optional
10494
10692
  The dictionary key under which to store the page_rank score. The default is "page_rank"
10693
+ colorKey : str , optional
10694
+ The desired dictionary key under which to store the pagerank color. The default is "pr_color".
10695
+ colorScale : str , optional
10696
+ The desired type of plotly color scales to use (e.g. "viridis", "plasma"). The default is "viridis". For a full list of names, see https://plotly.com/python/builtin-colorscales/.
10697
+ In addition to these, three color-blind friendly scales are included. These are "protanopia", "deuteranopia", and "tritanopia" for red, green, and blue colorblindness respectively.
10495
10698
  mantissa : int , optional
10496
10699
  The desired length of the mantissa.
10497
10700
  tolerance : float , optional
@@ -10506,6 +10709,7 @@ class Graph:
10506
10709
  from topologicpy.Helper import Helper
10507
10710
  from topologicpy.Dictionary import Dictionary
10508
10711
  from topologicpy.Topology import Topology
10712
+ from topologicpy.Color import Color
10509
10713
 
10510
10714
  vertices = Graph.Vertices(graph)
10511
10715
  num_vertices = len(vertices)
@@ -10513,7 +10717,7 @@ class Graph:
10513
10717
  print("Graph.PageRank - Error: The input graph parameter has no vertices. Returning None")
10514
10718
  return None
10515
10719
  initial_score = 1.0 / num_vertices
10516
- scores = [initial_score for vertex in vertices]
10720
+ values = [initial_score for vertex in vertices]
10517
10721
  for _ in range(maxIterations):
10518
10722
  new_scores = [0 for vertex in vertices]
10519
10723
  for i, vertex in enumerate(vertices):
@@ -10522,23 +10726,36 @@ class Graph:
10522
10726
  if len(Graph.IncomingVertices(graph, incoming_vertex, directed=directed)) > 0:
10523
10727
  vi = Vertex.Index(incoming_vertex, vertices, tolerance=tolerance)
10524
10728
  if not vi == None:
10525
- incoming_score += scores[vi] / len(Graph.IncomingVertices(graph, incoming_vertex, directed=directed))
10729
+ incoming_score += values[vi] / len(Graph.IncomingVertices(graph, incoming_vertex, directed=directed))
10526
10730
  new_scores[i] = alpha * incoming_score + (1 - alpha) / num_vertices
10527
10731
 
10528
10732
  # Check for convergence
10529
- if all(abs(new_scores[i] - scores[i]) <= tolerance for i in range(len(vertices))):
10733
+ if all(abs(new_scores[i] - values[i]) <= tolerance for i in range(len(vertices))):
10530
10734
  break
10531
10735
 
10532
- scores = new_scores
10736
+ values = new_scores
10533
10737
  if normalize == True:
10534
- scores = Helper.Normalize(scores, mantissa=mantissa)
10738
+ if mantissa > 0: # We cannot round numbers from 0 to 1 with a mantissa = 0.
10739
+ values = [round(v, mantissa) for v in Helper.Normalize(values)]
10740
+ else:
10741
+ values = Helper.Normalize(values)
10742
+ min_value = 0
10743
+ max_value = 1
10535
10744
  else:
10536
- scores = [round(x, mantissa) for x in scores]
10745
+ min_value = min(values)
10746
+ max_value = max(values)
10747
+
10748
+ for i, value in enumerate(values):
10749
+ d = Topology.Dictionary(vertices[i])
10750
+ color = Color.AnyToHex(Color.ByValueInRange(value, minValue=min_value, maxValue=max_value, colorScale=colorScale))
10751
+ d = Dictionary.SetValuesAtKeys(d, [key, colorKey], [value, color])
10752
+ vertices[i] = Topology.SetDictionary(vertices[i], d)
10753
+
10537
10754
  for i, v in enumerate(vertices):
10538
10755
  d = Topology.Dictionary(v)
10539
- d = Dictionary.SetValueAtKey(d, key, scores[i])
10756
+ d = Dictionary.SetValueAtKey(d, key, values[i])
10540
10757
  v = Topology.SetDictionary(v, d)
10541
- return scores
10758
+ return values
10542
10759
 
10543
10760
  @staticmethod
10544
10761
  def Partition(graph, method: str = "Betweenness", n: int = 2, m: int = 10, key: str ="partition",
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
@@ -809,7 +809,8 @@ class Plotly:
809
809
  faceLegendLabel="Topology Faces",
810
810
  faceLegendRank=3,
811
811
  faceLegendGroup=3,
812
- intensityKey=None, intensities=[], colorScale="viridis", mantissa=6, tolerance=0.0001):
812
+ intensityKey=None, intensities=[], colorScale="viridis",
813
+ mantissa=6, tolerance=0.0001, silent=False):
813
814
  """
814
815
  Creates plotly face, edge, and vertex data.
815
816
 
@@ -1188,7 +1189,7 @@ class Plotly:
1188
1189
  f_dictionaries = []
1189
1190
  all_triangles = []
1190
1191
  for tp_face in tp_faces:
1191
- triangles = Face.Triangulate(tp_face, tolerance=tolerance)
1192
+ triangles = Face.Triangulate(tp_face, tolerance=tolerance, silent=silent)
1192
1193
  if isinstance(triangles, list):
1193
1194
  for tri in triangles:
1194
1195
  if faceColorKey or faceOpacityKey or faceLabelKey or faceGroupKey:
topologicpy/Shell.py CHANGED
@@ -1846,6 +1846,42 @@ class Shell():
1846
1846
  final_result = Shell.ByFaces(final_faces, tolerance=tolerance)
1847
1847
  return final_result
1848
1848
 
1849
+ @staticmethod
1850
+ def Square(origin= None, size: float = 1.0,
1851
+ uSides: int = 2, vSides: int = 2, direction: list = [0, 0, 1],
1852
+ placement: str = "center", tolerance: float = 0.0001):
1853
+ """
1854
+ Creates a square.
1855
+
1856
+ Parameters
1857
+ ----------
1858
+ origin : topologic_core.Vertex , optional
1859
+ The location of the origin of the square. The default is None which results in the square being placed at (0, 0, 0).
1860
+ size : float , optional
1861
+ The size of the square. The default is 1.0.
1862
+ length : float , optional
1863
+ The length of the square. The default is 1.0.
1864
+ uSides : int , optional
1865
+ The number of sides along the width. The default is 2.
1866
+ vSides : int , optional
1867
+ The number of sides along the length. The default is 2.
1868
+ direction : list , optional
1869
+ The vector representing the up direction of the square. The default is [0, 0, 1].
1870
+ placement : str , optional
1871
+ The description of the placement of the origin of the square. This can be "center", or "lowerleft". It is case insensitive. The default is "center".
1872
+ tolerance : float , optional
1873
+ The desired tolerance. The default is 0.0001.
1874
+
1875
+ Returns
1876
+ -------
1877
+ topologic_core.Shell
1878
+ The created shell square.
1879
+
1880
+ """
1881
+ return Shell.Rectangle(origin=origin, width=size, length=size,
1882
+ uSides=uSides, vSides=vSides, direction=direction,
1883
+ placement=placement, tolerance=tolerance)
1884
+
1849
1885
  @staticmethod
1850
1886
  def Vertices(shell) -> list:
1851
1887
  """