-
Notifications
You must be signed in to change notification settings - Fork 0
/
test.py
147 lines (118 loc) · 4.7 KB
/
test.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import numpy as np
import plotly.graph_objects as go
import streamlit as st
# Constants for icosahedron
GOLDEN_RATIO = (1 + np.sqrt(5)) / 2
VERTICES = np.array([
(-1, GOLDEN_RATIO, 0), (1, GOLDEN_RATIO, 0), (-1, -GOLDEN_RATIO, 0), (1, -GOLDEN_RATIO, 0),
(0, -1, GOLDEN_RATIO), (0, 1, GOLDEN_RATIO), (0, -1, -GOLDEN_RATIO), (0, 1, -GOLDEN_RATIO),
(GOLDEN_RATIO, 0, -1), (GOLDEN_RATIO, 0, 1), (-GOLDEN_RATIO, 0, -1), (-GOLDEN_RATIO, 0, 1)
])
FACES = np.array([
(0, 11, 5), (0, 5, 1), (0, 1, 7), (0, 7, 10), (0, 10, 11),
(1, 5, 9), (5, 11, 4), (11, 10, 2), (10, 7, 6), (7, 1, 8),
(3, 9, 4), (3, 4, 2), (3, 2, 6), (3, 6, 8), (3, 8, 9),
(4, 9, 5), (2, 4, 11), (6, 2, 10), (8, 6, 7), (9, 8, 1)
])
# Function to convert spherical to cartesian coordinates
def spherical_to_cartesian(lat, lon, r=1):
x = r * np.cos(np.radians(lat)) * np.cos(np.radians(lon))
y = r * np.cos(np.radians(lat)) * np.sin(np.radians(lon))
z = r * np.sin(np.radians(lat))
return x, y, z
# Function to create a spherical triangle
def create_spherical_triangle(v1, v2, v3, color='red'): # Default to red
# Normalize vertices to unit sphere
v1 = v1 / np.linalg.norm(v1)
v2 = v2 / np.linalg.norm(v2)
v3 = v3 / np.linalg.norm(v3)
# Create arcs between vertices
arc1 = create_arc(v1, v2)
arc2 = create_arc(v2, v3)
arc3 = create_arc(v3, v1)
# Combine arcs into a single trace
x = np.concatenate((arc1[:, 0], arc2[:, 0], arc3[:, 0]))
y = np.concatenate((arc1[:, 1], arc2[:, 1], arc3[:, 1]))
z = np.concatenate((arc1[:, 2], arc2[:, 2], arc3[:, 2]))
return go.Scatter3d(x=x, y=y, z=z, mode='lines', line=dict(color=color, width=2))
# Function to create a great circle arc between two points
def create_arc(start, end, n=50):
# Calculate rotation axis and angle
axis = np.cross(start, end)
angle = np.arccos(np.dot(start, end))
# Generate points along the arc
t = np.linspace(0, angle, n)
# Pre-allocate array for arc points
arc = np.zeros((n, 3))
# Calculate rotation for each point on the arc
for i in range(n):
rot_mat = rotation_matrix(axis, t[i])
arc[i, :] = np.matmul(rot_mat, start[:, np.newaxis]).squeeze()
return arc
# Function to create a rotation matrix
def rotation_matrix(axis, angle):
axis = axis / np.linalg.norm(axis)
a = np.cos(angle)
b = np.sin(angle)
c = 1 - a
return np.array([
[a + axis[0] ** 2 * c, axis[0] * axis[1] * c - axis[2] * b, axis[0] * axis[2] * c + axis[1] * b],
[axis[1] * axis[0] * c + axis[2] * b, a + axis[1] ** 2 * c, axis[1] * axis[2] * c - axis[0] * b],
[axis[2] * axis[0] * c - axis[1] * b, axis[2] * axis[1] * c + axis[0] * b, a + axis[2] ** 2 * c]
])
# Function to subdivide a triangle into four smaller triangles
def subdivide_triangle(v1, v2, v3):
midpoint1 = (v1 + v2) / 2
midpoint2 = (v2 + v3) / 2
midpoint3 = (v3 + v1) / 2
return [
(v1, midpoint1, midpoint3),
(midpoint1, v2, midpoint2),
(midpoint2, v3, midpoint3),
(midpoint1, midpoint2, midpoint3)
]
# Streamlit app
st.title("Interactive Spherical Icosahedron")
# Initialize session state
if 'triangles' not in st.session_state:
st.session_state.triangles = []
for i in range(20):
v1 = VERTICES[FACES[i, 0]]
v2 = VERTICES[FACES[i, 1]]
v3 = VERTICES[FACES[i, 2]]
st.session_state.triangles.append((v1, v2, v3))
# Selection input for selecting triangle
selected_triangle_index = st.sidebar.selectbox("Select Triangle Index:", options=range(len(st.session_state.triangles)))
selected_triangle = st.session_state.triangles[selected_triangle_index]
# Subdivide selected triangle
if st.sidebar.button("Subdivide Selected Triangle"):
subdivided_triangles = subdivide_triangle(*selected_triangle)
st.session_state.triangles.pop(selected_triangle_index)
st.session_state.triangles.extend(subdivided_triangles)
# Create Plotly figure
fig = go.Figure()
# Add sphere
u, v = np.mgrid[0:2 * np.pi:40j, 0:np.pi:20j]
x = np.cos(u) * np.sin(v)
y = np.sin(u) * np.sin(v)
z = np.cos(v)
fig.add_trace(go.Surface(x=x, y=y, z=z, colorscale=[[0, 'rgb(200,200,200)'], [1, 'rgb(200,200,200)']],
showscale=False, opacity=0.3))
# Add icosahedron triangles
for i, triangle in enumerate(st.session_state.triangles):
color = 'blue' if i == selected_triangle_index else 'red'
fig.add_trace(create_spherical_triangle(*triangle, color=color))
# Update layout
fig.update_layout(
title_text='Spherical Icosahedron',
scene=dict(
xaxis_title='X',
yaxis_title='Y',
zaxis_title='Z',
aspectmode='data'
),
height=600,
width=800
)
# Display figure in Streamlit
st.plotly_chart(fig)