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 +38 -6
- topologicpy/Graph.py +247 -30
- topologicpy/Grid.py +16 -12
- topologicpy/Plotly.py +3 -2
- topologicpy/Shell.py +36 -0
- topologicpy/Topology.py +301 -249
- topologicpy/Vertex.py +95 -0
- topologicpy/version.py +1 -1
- {topologicpy-0.8.25.dist-info → topologicpy-0.8.28.dist-info}/METADATA +1 -1
- {topologicpy-0.8.25.dist-info → topologicpy-0.8.28.dist-info}/RECORD +13 -13
- {topologicpy-0.8.25.dist-info → topologicpy-0.8.28.dist-info}/WHEEL +1 -1
- {topologicpy-0.8.25.dist-info → topologicpy-0.8.28.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.25.dist-info → topologicpy-0.8.28.dist-info}/top_level.txt +0 -0
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
|
-
|
2473
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
4525
|
-
The desired weight for
|
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
|
-
"
|
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
|
4726
|
-
v1 = safe_mean(Graph.
|
4727
|
-
v2 = safe_mean(Graph.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
"
|
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
|
-
|
5243
|
-
|
5244
|
-
values = [round(v, mantissa) for v in list(
|
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(
|
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
|
-
|
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
|
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 "
|
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 "
|
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.
|
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
|
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
|
-
|
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 +=
|
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] -
|
10733
|
+
if all(abs(new_scores[i] - values[i]) <= tolerance for i in range(len(vertices))):
|
10530
10734
|
break
|
10531
10735
|
|
10532
|
-
|
10736
|
+
values = new_scores
|
10533
10737
|
if normalize == True:
|
10534
|
-
|
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
|
-
|
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,
|
10756
|
+
d = Dictionary.SetValueAtKey(d, key, values[i])
|
10540
10757
|
v = Topology.SetDictionary(v, d)
|
10541
|
-
return
|
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
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
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
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
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",
|
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
|
"""
|