topologicpy 0.7.81__py3-none-any.whl → 0.7.82__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 +215 -5
- topologicpy/version.py +1 -1
- {topologicpy-0.7.81.dist-info → topologicpy-0.7.82.dist-info}/METADATA +1 -1
- {topologicpy-0.7.81.dist-info → topologicpy-0.7.82.dist-info}/RECORD +7 -7
- {topologicpy-0.7.81.dist-info → topologicpy-0.7.82.dist-info}/LICENSE +0 -0
- {topologicpy-0.7.81.dist-info → topologicpy-0.7.82.dist-info}/WHEEL +0 -0
- {topologicpy-0.7.81.dist-info → topologicpy-0.7.82.dist-info}/top_level.txt +0 -0
topologicpy/Face.py
CHANGED
@@ -1649,7 +1649,7 @@ class Face():
|
|
1649
1649
|
return are_planes_coplanar(plane_a, plane_b, tolerance=tolerance)
|
1650
1650
|
|
1651
1651
|
@staticmethod
|
1652
|
-
def Isovist(face, vertex, obstacles: list = [], direction: list = [0,1,0], fov: float = 360, transferDictionaries: bool = False, mantissa: int = 6, tolerance: float = 0.0001):
|
1652
|
+
def Isovist(face, vertex, obstacles: list = [], direction: list = [0,1,0], fov: float = 360, transferDictionaries: bool = False, metrics: bool = False, mantissa: int = 6, tolerance: float = 0.0001):
|
1653
1653
|
"""
|
1654
1654
|
Returns the face representing the isovist projection from the input viewpoint.
|
1655
1655
|
This method assumes all input is in 2D. Z coordinates are ignored.
|
@@ -1673,6 +1673,23 @@ class Face():
|
|
1673
1673
|
The acceptable range is 1 to 360. The default is 360.
|
1674
1674
|
transferDictionaries : bool , optional
|
1675
1675
|
If set to True, the dictionaries of the encountered edges will be transfered to the isovist edges. The default is False.
|
1676
|
+
metrics : bool , optional
|
1677
|
+
If set to True, the following metrics are calculated and stored in the dictionary of the returned isovist. The keys of the values are:
|
1678
|
+
- viewpoint : list , the x , y , z coordinates of the location of the viewpoint.
|
1679
|
+
- direction : list , the direction of the view.
|
1680
|
+
- fov : int, Field of view angle.
|
1681
|
+
- area : float , the area of the isovist.
|
1682
|
+
- perimeter : float , the perimeter length of the isovist
|
1683
|
+
- compactness : float , how closely the shape of the isovist approximates a circle (the most compact geometric shape).
|
1684
|
+
- d_max : float, Maximum Visibility Distance. the length of the longest straight line that can be seen from the viewpoint.
|
1685
|
+
- v_max : list, Furthest Point measures the x , y , z coordinates of the furthest visible point from the viewpoint.
|
1686
|
+
- v_d : list, Visibility Distribution quantifies the angular distribution (in degrees) of visible points across the isovist.
|
1687
|
+
This metric can tell you whether the visibility from a point is more spread out or concentrated in a certain direction. A uniform visibility distribution indicates a more balanced visual field, while a skewed distribution suggests that the observer's line of sight is constrained in certain directions.
|
1688
|
+
- v_density : float, Viewpoint Density which refers to the number of visible points per unit area within the isovist.
|
1689
|
+
- symmetry : float, Symmetry measures how balanced or symmetrical the isovist is around the point of observation.
|
1690
|
+
- d_f : float, Fractal Dimension measures the complexity of the isovist's boundary.
|
1691
|
+
- e_c : float , Edge Complexity measures how complex the edges of the isovist boundary are.
|
1692
|
+
- theta : float, Mean Visual Field Angle measures the average angular extent of the visible area from the observation point.
|
1676
1693
|
mantissa : int , optional
|
1677
1694
|
The desired length of the mantissa. The default is 6.
|
1678
1695
|
tolerance : float , optional:
|
@@ -1695,7 +1712,129 @@ class Face():
|
|
1695
1712
|
from topologicpy.Dictionary import Dictionary
|
1696
1713
|
from topologicpy.Helper import Helper
|
1697
1714
|
|
1698
|
-
|
1715
|
+
import math
|
1716
|
+
import numpy as np
|
1717
|
+
|
1718
|
+
def calculate_angle(viewpoint, vertex):
|
1719
|
+
# Calculate the angle between the viewpoint and the vertex in the 2D plane
|
1720
|
+
# Viewpoint is (x, y, z), and vertex is (x, y)
|
1721
|
+
dx = vertex[0] - viewpoint[0]
|
1722
|
+
dy = vertex[1] - viewpoint[1]
|
1723
|
+
|
1724
|
+
# Return the angle in radians using the arctangent of the y/x difference
|
1725
|
+
return math.degrees(math.atan2(dy, dx))
|
1726
|
+
|
1727
|
+
def visibility_distribution(viewpoint, isovist_vertices):
|
1728
|
+
angles = []
|
1729
|
+
# Calculate the angle of each vertex with respect to the viewpoint
|
1730
|
+
for vertex in isovist_vertices:
|
1731
|
+
angle = calculate_angle(viewpoint, vertex)
|
1732
|
+
angles.append(angle)
|
1733
|
+
# Sort the angles to analyze the distribution
|
1734
|
+
angles = np.sort(angles)
|
1735
|
+
return list(angles)
|
1736
|
+
|
1737
|
+
def isovist_symmetry(viewpoint, isovist_vertices):
|
1738
|
+
"""
|
1739
|
+
Calculates the symmetry of the isovist polygon.
|
1740
|
+
|
1741
|
+
Parameters:
|
1742
|
+
- viewpoint: a tuple (x, y) of the viewpoint.
|
1743
|
+
- isovist_vertices: a list of tuples, each representing a vertex (x, y) of the isovist polygon.
|
1744
|
+
|
1745
|
+
Returns:
|
1746
|
+
- symmetry value: A measure of the symmetry of the isovist.
|
1747
|
+
"""
|
1748
|
+
angles = [calculate_angle(viewpoint, vertex) for vertex in isovist_vertices]
|
1749
|
+
angles.sort()
|
1750
|
+
|
1751
|
+
# Calculate angular deviations from the mean direction
|
1752
|
+
mean_angle = np.mean(angles)
|
1753
|
+
angular_deviation = np.std(angles)
|
1754
|
+
symmetry = angular_deviation / mean_angle if mean_angle != 0 else 0
|
1755
|
+
return float(symmetry)
|
1756
|
+
|
1757
|
+
# Fractal Dimension (D_f) using Box-counting
|
1758
|
+
def fractal_dimension(isovist_vertices):
|
1759
|
+
"""
|
1760
|
+
Calculates the fractal dimension of the isovist boundary using box-counting.
|
1761
|
+
|
1762
|
+
Parameters:
|
1763
|
+
- isovist_vertices: a list of tuples, each representing a vertex (x, y) of the isovist polygon.
|
1764
|
+
|
1765
|
+
Returns:
|
1766
|
+
- fractal dimension: A measure of the boundary's complexity.
|
1767
|
+
"""
|
1768
|
+
# Convert isovist vertices into a boundary path (x, y coordinates)
|
1769
|
+
boundary_points = np.array(isovist_vertices)
|
1770
|
+
|
1771
|
+
# Box-counting approach
|
1772
|
+
sizes = np.logspace(0, 2, 10) # Varying box sizes (log scale)
|
1773
|
+
sizes[sizes == 0] = 1e-10 # Replace zero counts with a small value
|
1774
|
+
counts = []
|
1775
|
+
|
1776
|
+
for size in sizes:
|
1777
|
+
count = 0
|
1778
|
+
for i in range(len(boundary_points)):
|
1779
|
+
if np.abs(boundary_points[i][0] - boundary_points[(i+1)%len(boundary_points)][0]) > size or \
|
1780
|
+
np.abs(boundary_points[i][1] - boundary_points[(i+1)%len(boundary_points)][1]) > size:
|
1781
|
+
count += 1
|
1782
|
+
counts.append(count)
|
1783
|
+
|
1784
|
+
# To avoid log(0), add a small constant to counts
|
1785
|
+
counts = np.array(counts)
|
1786
|
+
counts = np.where(counts == 0, 1e-10, counts)
|
1787
|
+
# Linear regression of log(count) vs log(size) to estimate fractal dimension
|
1788
|
+
log_sizes = np.log(sizes)
|
1789
|
+
log_counts = np.log(counts)
|
1790
|
+
|
1791
|
+
# Perform linear regression (log-log scale)
|
1792
|
+
slope, _ = np.polyfit(log_sizes, log_counts, 1)
|
1793
|
+
|
1794
|
+
return slope
|
1795
|
+
|
1796
|
+
# Edge Complexity (E_C)
|
1797
|
+
def edge_complexity(isovist_vertices):
|
1798
|
+
"""
|
1799
|
+
Calculates the edge complexity of the isovist boundary.
|
1800
|
+
|
1801
|
+
Parameters:
|
1802
|
+
- isovist_vertices: a list of tuples, each representing a vertex (x, y) of the isovist polygon.
|
1803
|
+
|
1804
|
+
Returns:
|
1805
|
+
- edge complexity: A measure of the complexity of the boundary.
|
1806
|
+
"""
|
1807
|
+
angles = []
|
1808
|
+
for i in range(len(isovist_vertices)):
|
1809
|
+
p1 = isovist_vertices[i]
|
1810
|
+
p2 = isovist_vertices[(i + 1) % len(isovist_vertices)]
|
1811
|
+
p3 = isovist_vertices[(i + 2) % len(isovist_vertices)]
|
1812
|
+
|
1813
|
+
# Calculate the angle between each consecutive edge
|
1814
|
+
angle = np.arctan2(p3[1] - p2[1], p3[0] - p2[0]) - np.arctan2(p1[1] - p2[1], p1[0] - p2[0])
|
1815
|
+
angles.append(np.abs(angle))
|
1816
|
+
|
1817
|
+
# Complexity is the number of abrupt angle changes
|
1818
|
+
complexity = np.sum(np.array(angles) > np.pi / 4) # e.g., large changes in angles
|
1819
|
+
return float(complexity)
|
1820
|
+
|
1821
|
+
# Mean Visual Field Angle (θ)
|
1822
|
+
def mean_visual_field_angle(viewpoint, isovist_vertices):
|
1823
|
+
"""
|
1824
|
+
Calculates the mean visual field angle from the viewpoint to the isovist vertices.
|
1825
|
+
|
1826
|
+
Parameters:
|
1827
|
+
- viewpoint: a tuple (x, y) of the viewpoint.
|
1828
|
+
- isovist_vertices: a list of tuples, each representing a vertex (x, y) of the isovist polygon.
|
1829
|
+
|
1830
|
+
Returns:
|
1831
|
+
- mean visual field angle in degrees.
|
1832
|
+
"""
|
1833
|
+
angles = [calculate_angle(viewpoint, vertex) for vertex in isovist_vertices]
|
1834
|
+
# Return the average angle
|
1835
|
+
return np.mean(angles)
|
1836
|
+
|
1837
|
+
def vertex_part_of_face(vertex, face, tolerance):
|
1699
1838
|
vertices = Topology.Vertices(face)
|
1700
1839
|
for v in vertices:
|
1701
1840
|
if Vertex.Distance(vertex, v) < tolerance:
|
@@ -1756,7 +1895,7 @@ class Face():
|
|
1756
1895
|
faces = Topology.Faces(shell)
|
1757
1896
|
final_faces = []
|
1758
1897
|
for f in faces:
|
1759
|
-
if
|
1898
|
+
if vertex_part_of_face(flat_vertex, f, tolerance=0.001):
|
1760
1899
|
final_faces.append(f)
|
1761
1900
|
shell = Shell.ByFaces(final_faces)
|
1762
1901
|
return_face = Topology.RemoveCoplanarFaces(shell, epsilon=0.1)
|
@@ -1815,8 +1954,79 @@ class Face():
|
|
1815
1954
|
d_result = Dictionary.ByMergedDictionaries([d_i, d_j])
|
1816
1955
|
i_edge = Topology.SetDictionary(i_edge, d_result)
|
1817
1956
|
used[j] == 1
|
1818
|
-
|
1819
|
-
|
1957
|
+
|
1958
|
+
return_face = Topology.Unflatten(simpler_face, origin=origin, direction=normal)
|
1959
|
+
return_face = Topology.Unflatten(return_face, origin=origin, direction=normal)
|
1960
|
+
if metrics == True:
|
1961
|
+
# 1 Viewpoint
|
1962
|
+
viewpoint = Vertex.Coordinates(vertex, mantissa=mantissa)
|
1963
|
+
# 2 Direction
|
1964
|
+
# direction is given
|
1965
|
+
# 3 Field of View (FOV)
|
1966
|
+
# fov is given
|
1967
|
+
# 4 Area
|
1968
|
+
area = round(abs(Face.Area(return_face)), mantissa)
|
1969
|
+
# 5 Perimeter
|
1970
|
+
perimeter = round(Wire.Length(Face.Wires(return_face)[0]), mantissa)
|
1971
|
+
# 6 Compactness
|
1972
|
+
compactness = round(Face.Compactness(return_face), mantissa)
|
1973
|
+
# 7 Maximum Distance (d_max)
|
1974
|
+
vertices = Topology.Vertices(return_face)
|
1975
|
+
furthest_vertex = vertices[0]
|
1976
|
+
d_max = round(Vertex.Distance(vertex, vertices[0]), mantissa)
|
1977
|
+
# 8 Furthest Visible Vertex
|
1978
|
+
coords = []
|
1979
|
+
for v in vertices:
|
1980
|
+
coords.append(Vertex.Coordinates(v, mantissa=mantissa))
|
1981
|
+
dis = Vertex.Distance(vertex, v, mantissa=mantissa)
|
1982
|
+
if dis > d_max:
|
1983
|
+
d_max = dis
|
1984
|
+
furthest_vertex = v
|
1985
|
+
v_max = Vertex.Coordinates(furthest_vertex, mantissa=mantissa)
|
1986
|
+
# 9 Visibility Distribution (v_d)
|
1987
|
+
v_d = visibility_distribution(viewpoint, coords)
|
1988
|
+
v_d = [round(x) for x in v_d]
|
1989
|
+
# 10 Viewpoint density
|
1990
|
+
v_density = round(float(len(vertices)) / abs(Face.Area(return_face)), mantissa)
|
1991
|
+
# 11 Isovist Symmetry
|
1992
|
+
symmetry = round(isovist_symmetry(viewpoint, coords), mantissa)
|
1993
|
+
# 12 Fractal Dimension
|
1994
|
+
d_f = round(fractal_dimension(coords), mantissa)
|
1995
|
+
# 13 Edge Complexity
|
1996
|
+
e_c = round(edge_complexity(coords), mantissa)
|
1997
|
+
# 14 Mean Visual Field Angle
|
1998
|
+
theta = round(mean_visual_field_angle(viewpoint, coords), mantissa)
|
1999
|
+
keys = ["viewpoint",
|
2000
|
+
"direction",
|
2001
|
+
"fov",
|
2002
|
+
"area",
|
2003
|
+
"perimeter",
|
2004
|
+
"compactness",
|
2005
|
+
"d_max",
|
2006
|
+
"v_max",
|
2007
|
+
"v_d",
|
2008
|
+
"v_density",
|
2009
|
+
"symmetry",
|
2010
|
+
"d_f",
|
2011
|
+
"e_c",
|
2012
|
+
"theta"]
|
2013
|
+
values = [viewpoint,
|
2014
|
+
direction,
|
2015
|
+
fov,
|
2016
|
+
area,
|
2017
|
+
perimeter,
|
2018
|
+
compactness,
|
2019
|
+
d_max,
|
2020
|
+
v_max,
|
2021
|
+
v_d,
|
2022
|
+
v_density,
|
2023
|
+
symmetry,
|
2024
|
+
d_f,
|
2025
|
+
e_c,
|
2026
|
+
theta]
|
2027
|
+
d = Dictionary.ByKeysValues(keys, values)
|
2028
|
+
return_face = Topology.SetDictionary(return_face, d)
|
2029
|
+
return return_face
|
1820
2030
|
|
1821
2031
|
@staticmethod
|
1822
2032
|
def MedialAxis(face, resolution: int = 0, externalVertices: bool = False, internalVertices: bool = False, toLeavesOnly: bool = False, angTolerance: float = 0.1, tolerance: float = 0.0001):
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.7.
|
1
|
+
__version__ = '0.7.82'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.7.
|
3
|
+
Version: 0.7.82
|
4
4
|
Summary: An AI-Powered Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
|
5
5
|
Author-email: Wassim Jabi <wassim.jabi@gmail.com>
|
6
6
|
License: AGPL v3 License
|
@@ -10,7 +10,7 @@ topologicpy/DGL.py,sha256=Dd6O08D-vSxpjHYgKm45JpKiaeGvWlg1BRMzYMAXGNc,138991
|
|
10
10
|
topologicpy/Dictionary.py,sha256=0AsGoz48pGTye_F4KcJopNjD9STeQ50LHc6PPvERFaA,31932
|
11
11
|
topologicpy/Edge.py,sha256=9u9SdUxuenLUIK26xwFvPoYV34p0dCfXmHHBxdgvAdM,67164
|
12
12
|
topologicpy/EnergyModel.py,sha256=AqTtmXE35SxvRXhG3vYAQd7GQDW-6HtjYPHua6ME4Eg,53762
|
13
|
-
topologicpy/Face.py,sha256=
|
13
|
+
topologicpy/Face.py,sha256=Y13hw84bjJO8bzEG7sB7PRDxcSqqmGZnNAbIhIUQ1Ys,136243
|
14
14
|
topologicpy/Graph.py,sha256=ZhMVB6ntuhIgTrKLUPryeAJFFBF0cnRsNgESbaohOiw,416914
|
15
15
|
topologicpy/Grid.py,sha256=9N6PE84qCm40TRi2WtlVZSBwXXr47zHpscEpZHg_JW4,18205
|
16
16
|
topologicpy/Helper.py,sha256=vUWbnZJxn0e9YsFUNyJ5Dee8Nh6TmDp9uCzCk4e0qAA,21897
|
@@ -28,9 +28,9 @@ topologicpy/Vector.py,sha256=A1g83zDHep58iVPY8WQ8iHNrSOfGWFEzvVeDuMnjDNY,33078
|
|
28
28
|
topologicpy/Vertex.py,sha256=mcLJaWFCct03dkVmT25wAl6k0k2EaYvB1PWNO9WQHWg,73465
|
29
29
|
topologicpy/Wire.py,sha256=o6MlOjubkJ_f5s1tUamizCsoPKvcQ2OudtJv0yCF-2o,186477
|
30
30
|
topologicpy/__init__.py,sha256=vlPCanUbxe5NifC4pHcnhSzkmmYcs_UrZrTlVMsxcFs,928
|
31
|
-
topologicpy/version.py,sha256=
|
32
|
-
topologicpy-0.7.
|
33
|
-
topologicpy-0.7.
|
34
|
-
topologicpy-0.7.
|
35
|
-
topologicpy-0.7.
|
36
|
-
topologicpy-0.7.
|
31
|
+
topologicpy/version.py,sha256=rXEi2ZZcGFgf2u3AMH7tyJUFE9nvS8L279fdB54xeCk,23
|
32
|
+
topologicpy-0.7.82.dist-info/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
|
33
|
+
topologicpy-0.7.82.dist-info/METADATA,sha256=CZZqWePZAWM-hGdFkhmjQf9qbm3Ub_fKCPzHnu7RYvk,10513
|
34
|
+
topologicpy-0.7.82.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
35
|
+
topologicpy-0.7.82.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
36
|
+
topologicpy-0.7.82.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|