naohiro701 commited on
Commit
0214ea4
·
verified ·
1 Parent(s): f540b62

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +158 -0
app.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ import streamlit as st
3
+ import numpy as np
4
+ import plotly.graph_objs as go
5
+ from dataclasses import dataclass
6
+ import time
7
+
8
+ # カスタムコンポーネントのインポート
9
+ from my_mouse_tracker import my_mouse_tracker
10
+
11
+ @dataclass
12
+ class Boid:
13
+ position: np.ndarray
14
+ velocity: np.ndarray
15
+
16
+ def initialize_boids(num_boids, width, height, speed):
17
+ boids = []
18
+ for _ in range(num_boids):
19
+ position = np.array([np.random.uniform(0, width), np.random.uniform(0, height)])
20
+ angle = np.random.uniform(0, 2*np.pi)
21
+ velocity = np.array([np.cos(angle), np.sin(angle)]) * speed
22
+ boids.append(Boid(position, velocity))
23
+ return boids
24
+
25
+ def update_boids(boids, width, height, alignment_factor, cohesion_factor, separation_factor,
26
+ perception_radius, max_speed, mouse_pos=None, mouse_influence=0.05):
27
+ new_boids = []
28
+ for boid in boids:
29
+ alignment = np.zeros(2)
30
+ cohesion = np.zeros(2)
31
+ separation = np.zeros(2)
32
+ total = 0
33
+ for other in boids:
34
+ distance = np.linalg.norm(other.position - boid.position)
35
+ if other != boid and distance < perception_radius:
36
+ alignment += other.velocity
37
+ cohesion += other.position
38
+ separation += (boid.position - other.position) / distance
39
+ total += 1
40
+ if total > 0:
41
+ alignment = (alignment / total) * alignment_factor
42
+ cohesion = ((cohesion / total) - boid.position) * cohesion_factor
43
+ separation = (separation / total) * separation_factor
44
+ boid.velocity += alignment + cohesion + separation
45
+ # マウスの影響
46
+ if mouse_pos is not None:
47
+ direction_to_mouse = mouse_pos - boid.position
48
+ distance_to_mouse = np.linalg.norm(direction_to_mouse)
49
+ if distance_to_mouse < perception_radius:
50
+ # 避ける動作
51
+ boid.velocity -= (direction_to_mouse / distance_to_mouse) * mouse_influence
52
+ # 速度の制限
53
+ speed = np.linalg.norm(boid.velocity)
54
+ if speed > max_speed:
55
+ boid.velocity = (boid.velocity / speed) * max_speed
56
+ # 位置の更新
57
+ boid.position += boid.velocity
58
+ # 境界条件(トーラス型)
59
+ boid.position[0] %= width
60
+ boid.position[1] %= height
61
+ new_boids.append(boid)
62
+ return new_boids
63
+
64
+ def plot_boids(boids, width, height, mouse_pos=None):
65
+ x = [boid.position[0] for boid in boids]
66
+ y = [boid.position[1] for boid in boids]
67
+ trace = go.Scatter(
68
+ x=x,
69
+ y=y,
70
+ mode='markers',
71
+ marker=dict(size=8, color='blue'),
72
+ )
73
+ layout = go.Layout(
74
+ xaxis=dict(range=[0, width], autorange=False, zeroline=False, showgrid=False),
75
+ yaxis=dict(range=[0, height], autorange=False, zeroline=False, showgrid=False),
76
+ margin=dict(l=0, r=0, t=0, b=0),
77
+ height=600,
78
+ width=600,
79
+ shapes=[],
80
+ )
81
+ # マウス位置の表示
82
+ if mouse_pos is not None:
83
+ layout['shapes'] = [
84
+ dict(
85
+ type="circle",
86
+ xref="x",
87
+ yref="y",
88
+ x0=mouse_pos[0]-10,
89
+ y0=mouse_pos[1]-10,
90
+ x1=mouse_pos[0]+10,
91
+ y1=mouse_pos[1]+10,
92
+ line=dict(color="red"),
93
+ )
94
+ ]
95
+ fig = go.Figure(data=[trace], layout=layout)
96
+ return fig
97
+
98
+ def main():
99
+ st.set_page_config(page_title="Boidsシミュレーション", layout="wide")
100
+ st.title("インタラクティブBoidsシミュレーション")
101
+ st.markdown("マウスの位置に反応する魚の群れをシミュレートします。")
102
+
103
+ # サイドバーのパラメータ設定
104
+ st.sidebar.header("パラメータ設定")
105
+ num_boids = st.sidebar.slider("ボイドの数", 10, 500, 100)
106
+ width = st.sidebar.slider("キャンバスの幅", 300, 1200, 800)
107
+ height = st.sidebar.slider("キャンバスの高さ", 300, 1200, 800)
108
+ speed = st.sidebar.slider("初期速度", 0.5, 5.0, 2.0)
109
+ alignment_factor = st.sidebar.slider("整列係数", 0.0, 2.0, 1.0)
110
+ cohesion_factor = st.sidebar.slider("結合係数", 0.0, 2.0, 1.0)
111
+ separation_factor = st.sidebar.slider("分離係数", 0.0, 2.0, 1.5)
112
+ perception_radius = st.sidebar.slider("認識半径", 10, 200, 50)
113
+ max_speed = st.sidebar.slider("最大速度", 1.0, 10.0, 4.0)
114
+ simulation_speed = st.sidebar.slider("シミュレーション速度(秒)", 0.01, 1.0, 0.1)
115
+ mouse_influence = st.sidebar.slider("マウスの影響力", 0.0, 1.0, 0.05)
116
+
117
+ # マウス位置の取得
118
+ mouse_event = my_mouse_tracker()
119
+ if mouse_event:
120
+ mouse_x, mouse_y = mouse_event['x'], mouse_event['y']
121
+ # ウィンドウサイズとキャンバスサイズをマッピング
122
+ # ここでは仮にウィンドウサイズがキャンバスサイズと同じと���定
123
+ mouse_pos = np.array([mouse_x, mouse_y])
124
+ else:
125
+ mouse_pos = None
126
+
127
+ # セッションステートの初期化
128
+ if 'boids' not in st.session_state:
129
+ st.session_state.boids = initialize_boids(num_boids, width, height, speed)
130
+ st.session_state.last_update = time.time()
131
+
132
+ # パラメータの変更時にボイドを再初期化
133
+ current_params = (num_boids, width, height, speed)
134
+ if st.session_state.get('params', None) != current_params:
135
+ st.session_state.boids = initialize_boids(num_boids, width, height, speed)
136
+ st.session_state.last_update = time.time()
137
+ st.session_state.params = current_params
138
+
139
+ # シミュレーションの更新
140
+ current_time = time.time()
141
+ if current_time - st.session_state.last_update > simulation_speed:
142
+ st.session_state.boids = update_boids(
143
+ st.session_state.boids, width, height,
144
+ alignment_factor, cohesion_factor,
145
+ separation_factor, perception_radius,
146
+ max_speed, mouse_pos, mouse_influence
147
+ )
148
+ st.session_state.last_update = current_time
149
+
150
+ # ビジュアライゼーションの表示
151
+ fig = plot_boids(st.session_state.boids, width, height, mouse_pos)
152
+ st.plotly_chart(fig, use_container_width=True)
153
+
154
+ # 自動リロード
155
+ st.experimental_rerun()
156
+
157
+ if __name__ == "__main__":
158
+ main()