x2XcarleX2x commited on
Commit
e2829c8
·
verified ·
1 Parent(s): 3c5146f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -72
app.py CHANGED
@@ -6,15 +6,13 @@ from matplotlib.animation import FuncAnimation
6
  import math
7
  from scipy.special import comb
8
  import random
9
- import json
10
  import os
11
- import subprocess
12
 
13
  # --- Funções Matemáticas (Inalteradas) ---
14
  def bernstein_poly(i, n, t):
15
  return comb(n, i) * (t**(i)) * ((1 - t)**(n - i))
16
 
17
- def bezier_curve_3d(points, n_times=60): # Fixo em 60 vetores/frames
18
  n_points = len(points)
19
  x_points, y_points, z_points = np.array([p[0] for p in points]), np.array([p[1] for p in points]), np.array([p[2] for p in points])
20
  t = np.linspace(0.0, 1.0, n_times)
@@ -27,114 +25,104 @@ def aprender_com_o_eco_3d(pontos_do_eco: list):
27
  p1, p2 = np.array(pontos_do_eco[0]), np.array(pontos_do_eco[-1])
28
  return {"velocity_vector": p2 - p1}
29
 
30
- # --- Função Principal do Gradio (O Estúdio de Animação) ---
31
 
32
- def gerar_sequencia_completa(angulo_camera: int, progress=gr.Progress(track_tqdm=True)):
33
  """
34
- Gera uma sequência de 10 ciclos, renderiza cada um como um vídeo
35
- e os concatena em um resultado final.
36
  """
37
  NUM_CICLOS = 10
38
- clipes_de_video = []
39
 
 
 
 
 
 
40
  estado = {
41
  "ponto_b": np.array([-40., 20., 10.]),
42
  "vetor_inercia": np.array([30., 10., -20.])
43
  }
 
44
 
45
- for ciclo_atual in range(NUM_CICLOS):
46
- progress(ciclo_atual / NUM_CICLOS, desc=f"Processando Ciclo {ciclo_atual + 1}/{NUM_CICLOS}")
47
-
48
  ponto_a = estado["ponto_b"]
49
  vetor_inercia_anterior = estado["vetor_inercia"]
50
  ponto_b = np.random.rand(3) * 120 - 60
51
-
 
52
  ponto_controle = ponto_a + vetor_inercia_anterior
53
  pontos_curva = [ponto_a, ponto_controle, ponto_b]
54
- x_traj, y_traj, z_traj = bezier_curve_3d(pontos_curva)
55
- total_frames = len(x_traj)
 
56
 
57
  tamanho_eco = 20
58
- # --- CORREÇÃO DO SYNTAXERROR AQUI ---
59
- pontos_eco = list(zip(x_traj[-tamanho_eco:], y_traj[-tamanho_eco:], z_traj[-tamanho_eco:]))
60
- # ------------------------------------
61
  vetor_inercia_novo = aprender_com_o_eco_3d(pontos_eco)["velocity_vector"]
62
-
63
  estado = {"ponto_b": ponto_b, "vetor_inercia": vetor_inercia_novo}
64
 
65
- fig = plt.figure(figsize=(8, 8)); ax = fig.add_subplot(111, projection='3d')
66
-
67
- cor_fundo = '#0a0a0a'; fig.patch.set_facecolor(cor_fundo); ax.set_facecolor(cor_fundo)
68
- ax.xaxis.pane.fill = False; ax.yaxis.pane.fill = False; ax.zaxis.pane.fill = False
69
- ax.grid(color='#222222', linestyle='--')
70
-
71
- ax.plot(x_traj, y_traj, z_traj, color='cyan', linewidth=1.5, alpha=0.2) # Trajetória completa mais sutil
72
- ax.scatter(*ponto_a, s=150, c='lime', alpha=0.9, edgecolors='w', linewidth=0.5)
73
- ax.scatter(*ponto_b, s=150, c='yellow', marker='X', alpha=0.9, edgecolors='w', linewidth=0.5)
74
- ax.view_init(elev=30., azim=angulo_camera)
75
- ax.set_xlim(-70, 70); ax.set_ylim(-70, 70); ax.set_zlim(-70, 70)
76
- ax.set_xticklabels([]); ax.set_yticklabels([]); ax.set_zticklabels([])
77
-
78
- bola, = ax.plot([], [], [], 'o', color='#ff4500', markersize=8, markeredgecolor='white', linewidth=2)
79
-
80
- # --- AJUSTE ESTÉTICO: RASTRO DA BOLA ---
81
- rastro, = ax.plot([], [], [], '-', color='#ff4500', linewidth=4, alpha=0.6)
82
- tamanho_rastro = 25 # O rastro terá 25 vetores de comprimento
83
- # ------------------------------------
84
-
85
- def update(frame):
86
- bola.set_data_3d([x_traj[frame]], [y_traj[frame]], [z_traj[frame]])
87
-
88
- # Atualiza o rastro para mostrar os últimos 'tamanho_rastro' pontos
89
- start_index = max(0, frame - tamanho_rastro)
90
- rastro.set_data_3d(x_traj[start_index:frame+1], y_traj[start_index:frame+1], z_traj[start_index:frame+1])
91
-
92
- return bola, rastro,
93
-
94
- ani = FuncAnimation(fig, update, frames=total_frames, interval=33, blit=True)
95
- clip_filename = f"clip_{ciclo_atual}.mp4"
96
- ani.save(clip_filename, writer='ffmpeg', fps=30, dpi=120)
97
- plt.close(fig)
98
- clipes_de_video.append(clip_filename)
99
-
100
- progress(0.95, desc="Concatenando 10 clipes em um vídeo final...")
101
 
102
- with open("lista_de_clipes.txt", "w") as f:
103
- for clip in clipes_de_video:
104
- f.write(f"file '{os.path.abspath(clip)}'\n")
105
-
106
- video_final = "sequencia_convergencia_final.mp4"
107
- comando = f"ffmpeg -y -f concat -safe 0 -i lista_de_clipes.txt -c copy {video_final}"
108
- subprocess.run(comando, shell=True, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
109
-
110
- for clip in clipes_de_video: os.remove(clip)
111
- os.remove("lista_de_clipes.txt")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  return video_final
114
 
115
  # --- Interface Gradio (Inalterada) ---
116
 
117
- with gr.Blocks(theme=gr.themes.Base(primary_hue="blue")) as demo:
118
  gr.Markdown(
119
  """
120
- # 🎬 Estúdio de Animação de Convergência 3D
121
- Clique no botão para gerar uma sequência contínua de **10 ciclos**. Cada ciclo tem **60 vetores**.
122
- O sistema irá renderizar cada ciclo e concatenar todos em um único vídeo de demonstração.
123
  """
124
  )
125
 
126
  with gr.Row():
127
  with gr.Column(scale=1):
128
  gr.Markdown("### 🎮 Controles")
129
- angulo_camera_slider = gr.Slider(-180, 180, value=45, label="Ângulo da Câmera (Fixo)")
130
- generate_btn = gr.Button("🚀 Gerar Sequência Completa (10 Ciclos)", variant="primary")
131
 
132
  with gr.Column(scale=2):
133
  gr.Markdown("### 📽️ Vídeo Final")
134
- video_output = gr.Video(label="Animação da Sequência Completa", autoplay=True)
135
 
136
  generate_btn.click(
137
- fn=gerar_sequencia_completa,
138
  inputs=[angulo_camera_slider],
139
  outputs=[video_output]
140
  )
 
6
  import math
7
  from scipy.special import comb
8
  import random
 
9
  import os
 
10
 
11
  # --- Funções Matemáticas (Inalteradas) ---
12
  def bernstein_poly(i, n, t):
13
  return comb(n, i) * (t**(i)) * ((1 - t)**(n - i))
14
 
15
+ def bezier_curve_3d(points, n_times=60):
16
  n_points = len(points)
17
  x_points, y_points, z_points = np.array([p[0] for p in points]), np.array([p[1] for p in points]), np.array([p[2] for p in points])
18
  t = np.linspace(0.0, 1.0, n_times)
 
25
  p1, p2 = np.array(pontos_do_eco[0]), np.array(pontos_do_eco[-1])
26
  return {"velocity_vector": p2 - p1}
27
 
28
+ # --- Função Principal do Gradio (O Estúdio da Jornada Contínua) ---
29
 
30
+ def gerar_jornada_completa(angulo_camera: int, progress=gr.Progress(track_tqdm=True)):
31
  """
32
+ Gera uma única trajetória contínua para 10 ciclos e a renderiza
33
+ como um único vídeo animado.
34
  """
35
  NUM_CICLOS = 10
 
36
 
37
+ # Listas para armazenar a jornada completa
38
+ x_jornada_total, y_jornada_total, z_jornada_total = [], [], []
39
+ checkpoints = []
40
+
41
+ # Estado inicial da simulação
42
  estado = {
43
  "ponto_b": np.array([-40., 20., 10.]),
44
  "vetor_inercia": np.array([30., 10., -20.])
45
  }
46
+ checkpoints.append(estado["ponto_b"])
47
 
48
+ progress(0, desc="Calculando trajetória para 10 ciclos...")
49
+ # --- 1. CALCULAR TUDO PRIMEIRO ---
50
+ for i in range(NUM_CICLOS):
51
  ponto_a = estado["ponto_b"]
52
  vetor_inercia_anterior = estado["vetor_inercia"]
53
  ponto_b = np.random.rand(3) * 120 - 60
54
+ checkpoints.append(ponto_b)
55
+
56
  ponto_controle = ponto_a + vetor_inercia_anterior
57
  pontos_curva = [ponto_a, ponto_controle, ponto_b]
58
+ x_ciclo, y_ciclo, z_ciclo = bezier_curve_3d(pontos_curva)
59
+
60
+ x_jornada_total.extend(x_ciclo); y_jornada_total.extend(y_ciclo); z_jornada_total.extend(z_ciclo)
61
 
62
  tamanho_eco = 20
63
+ pontos_eco = list(zip(x_ciclo[-tamanho_eco:], y_ciclo[-tamanho_eco:], z_ciclo[-tamanho_eco:]))
 
 
64
  vetor_inercia_novo = aprender_com_o_eco_3d(pontos_eco)["velocity_vector"]
 
65
  estado = {"ponto_b": ponto_b, "vetor_inercia": vetor_inercia_novo}
66
 
67
+ total_frames = len(x_jornada_total)
68
+ progress(0.2, desc=f"Trajetória de {total_frames} vetores calculada. Iniciando renderização...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
+ # --- 2. RENDERIZAÇÃO ÚNICA ---
71
+ fig = plt.figure(figsize=(8, 8)); ax = fig.add_subplot(111, projection='3d')
72
+ cor_fundo = '#0a0a0a'; fig.patch.set_facecolor(cor_fundo); ax.set_facecolor(cor_fundo)
73
+ ax.xaxis.pane.fill = False; ax.yaxis.pane.fill = False; ax.zaxis.pane.fill = False
74
+ ax.grid(color='#222222', linestyle='--')
75
+ ax.view_init(elev=30., azim=angulo_camera)
76
+ ax.set_xlim(-70, 70); ax.set_ylim(-70, 70); ax.set_zlim(-70, 70)
77
+ ax.set_xticklabels([]); ax.set_yticklabels([]); ax.set_zticklabels([])
78
+
79
+ # Desenha todos os checkpoints
80
+ checkpoints_np = np.array(checkpoints)
81
+ ax.scatter(checkpoints_np[0,0], checkpoints_np[0,1], checkpoints_np[0,2], s=150, c='yellow', marker='X', alpha=0.9, label='')
82
+ ax.scatter(checkpoints_np[1:,0], checkpoints_np[1:,1], checkpoints_np[1:,2], s=150, c='yellow', marker='X', alpha=0.9, label='')
83
+
84
+ # Inicializa os elementos animados
85
+ bola, = ax.plot([], [], [], 'o', color='#ff4500', markersize=8, markeredgecolor='white', linewidth=2)
86
+ rastro, = ax.plot([], [], [], '-', color='#ff4500', linewidth=4, alpha=0.6)
87
+ tamanho_rastro = 40
88
+
89
+ def update(frame):
90
+ bola.set_data_3d([x_jornada_total[frame]], [y_jornada_total[frame]], [z_jornada_total[frame]])
91
+ start_index = max(0, frame - tamanho_rastro)
92
+ rastro.set_data_3d(x_jornada_total[start_index:frame+1], y_jornada_total[start_index:frame+1], z_jornada_total[start_index:frame+1])
93
+ return bola, rastro,
94
+
95
+ # --- 3. UMA ÚNICA ANIMAÇÃO E UM ÚNICO VÍDEO ---
96
+ ani = FuncAnimation(fig, update, frames=total_frames, interval=33, blit=True)
97
+ video_final = "jornada_continua.mp4"
98
+ ani.save(video_final, writer='ffmpeg', fps=30, dpi=120, progress_callback=lambda i, n: progress(0.2 + 0.8 * (i/n), desc=f"Renderizando vetor {i+1}/{n}"))
99
+ plt.close(fig)
100
 
101
  return video_final
102
 
103
  # --- Interface Gradio (Inalterada) ---
104
 
105
+ with gr.Blocks(theme=gr.themes.Base(primary_hue="orange")) as demo:
106
  gr.Markdown(
107
  """
108
+ # 🎬 Estúdio da Jornada Contínua 3D
109
+ Clique no botão para gerar uma **jornada ininterrupta de 10 ciclos**.
110
+ O sistema irá calcular toda a trajetória e renderizá-la como um único vídeo, mostrando a continuidade do rastro da bola.
111
  """
112
  )
113
 
114
  with gr.Row():
115
  with gr.Column(scale=1):
116
  gr.Markdown("### 🎮 Controles")
117
+ angulo_camera_slider = gr.Slider(-180, 180, value=30, label="Ângulo da Câmera (Fixo)")
118
+ generate_btn = gr.Button("🚀 Gerar Jornada Completa", variant="primary")
119
 
120
  with gr.Column(scale=2):
121
  gr.Markdown("### 📽️ Vídeo Final")
122
+ video_output = gr.Video(label="Animação da Jornada Contínua", autoplay=True)
123
 
124
  generate_btn.click(
125
+ fn=gerar_jornada_completa,
126
  inputs=[angulo_camera_slider],
127
  outputs=[video_output]
128
  )