|
|
import gradio as gr |
|
|
import numpy as np |
|
|
import matplotlib.pyplot as plt |
|
|
import math |
|
|
from scipy.special import comb |
|
|
|
|
|
|
|
|
|
|
|
def bernstein_poly(i, n, t): |
|
|
""" O polinômio de Bernstein, base para as curvas de Bézier. """ |
|
|
return comb(n, i) * (t**(i)) * ((1 - t)**(n - i)) |
|
|
|
|
|
def bezier_curve(points, n_times=1000): |
|
|
""" Gera uma curva de Bézier a partir de uma lista de pontos de controle. """ |
|
|
n_points = len(points) |
|
|
x_points = np.array([p[0] for p in points]) |
|
|
y_points = np.array([p[1] for p in points]) |
|
|
t = np.linspace(0.0, 1.0, n_times) |
|
|
polynomial_array = np.array([bernstein_poly(i, n_points - 1, t) for i in range(0, n_points)]) |
|
|
x_vals = np.dot(x_points, polynomial_array) |
|
|
y_vals = np.dot(y_points, polynomial_array) |
|
|
return x_vals, y_vals |
|
|
|
|
|
def aprender_com_o_eco(pontos_do_eco: list) -> dict: |
|
|
""" Calcula a essência do movimento (direção e vetor) do eco. """ |
|
|
if len(pontos_do_eco) < 2: |
|
|
return {"bearing_rad": 0, "velocity_vector": np.array([0, 0])} |
|
|
p1, p2 = np.array(pontos_do_eco[0]), np.array(pontos_do_eco[-1]) |
|
|
vetor_velocidade = p2 - p1 |
|
|
bearing_radianos = math.atan2(vetor_velocidade[1], vetor_velocidade[0]) |
|
|
return {"bearing_rad": bearing_radianos, "velocity_vector": vetor_velocidade} |
|
|
|
|
|
|
|
|
|
|
|
def gerar_grafico_dinamico(inflexao1_x, inflexao1_y, inflexao2_x, inflexao2_y, destino_x, destino_y, eco_vetores): |
|
|
""" |
|
|
Gera e plota a jornada com os caminhos da Criança A e B sendo totalmente dinâmicos. |
|
|
""" |
|
|
|
|
|
p1_inicio = np.array([0, 0]) |
|
|
|
|
|
|
|
|
p2_inflexao1 = np.array([inflexao1_x, inflexao1_y]) |
|
|
p3_inflexao2 = np.array([inflexao2_x, inflexao2_y]) |
|
|
|
|
|
|
|
|
|
|
|
p4_encontro = np.array([75, 45]) |
|
|
|
|
|
|
|
|
p5_destino = np.array([destino_x, destino_y]) |
|
|
|
|
|
|
|
|
pontos_curva_a = [p1_inicio, p2_inflexao1, p3_inflexao2, p4_encontro] |
|
|
x_a, y_a = bezier_curve(pontos_curva_a, n_times=1000) |
|
|
|
|
|
|
|
|
NUMERO_DE_VETORES_ECO = int(eco_vetores) |
|
|
if NUMERO_DE_VETORES_ECO < 2: NUMERO_DE_VETORES_ECO = 2 |
|
|
|
|
|
x_eco = x_a[-NUMERO_DE_VETORES_ECO:] |
|
|
y_eco = y_a[-NUMERO_DE_VETORES_ECO:] |
|
|
pontos_do_eco = list(zip(x_eco, y_eco)) |
|
|
|
|
|
|
|
|
essencia_movimento = aprender_com_o_eco(pontos_do_eco) |
|
|
vetor_aprendido = essencia_movimento["velocity_vector"] |
|
|
|
|
|
|
|
|
ponto_controle_b = p4_encontro + vetor_aprendido |
|
|
pontos_curva_b = [p4_encontro, ponto_controle_b, p5_destino] |
|
|
x_b, y_b = bezier_curve(pontos_curva_b, n_times=1000) |
|
|
|
|
|
|
|
|
fig, ax = plt.subplots(figsize=(12, 9)) |
|
|
fig.patch.set_facecolor('black') |
|
|
ax.set_facecolor('black') |
|
|
|
|
|
ax.spines['bottom'].set_color('white') |
|
|
ax.spines['left'].set_color('white') |
|
|
ax.spines['top'].set_color('black') |
|
|
ax.spines['right'].set_color('black') |
|
|
ax.tick_params(axis='x', colors='white') |
|
|
ax.tick_params(axis='y', colors='white') |
|
|
|
|
|
ax.plot(x_a, y_a, label='Caminho da Criança A (Seu Input)', color='cyan', linewidth=2) |
|
|
ax.plot(x_b, y_b, label='Continuidade da Criança B (Gerado)', color='lime', linewidth=2, linestyle='--') |
|
|
ax.plot(x_eco, y_eco, label=f'Eco de Memória ({NUMERO_DE_VETORES_ECO} vetores)', color='magenta', linewidth=4) |
|
|
|
|
|
pontos_controle_completos = np.array([p1_inicio, p2_inflexao1, p3_inflexao2, p4_encontro, ponto_controle_b, p5_destino]) |
|
|
ax.plot(pontos_controle_completos[:, 0], pontos_controle_completos[:, 1], 'o--', color='lightcoral', markersize=8, alpha=0.6, label='Estrutura de Controle') |
|
|
|
|
|
ax.plot(p4_encontro[0], p4_encontro[1], 'o', color='yellow', markersize=12, markeredgecolor='black', label='Ponto de Encontro (Fixo)') |
|
|
ax.plot(p5_destino[0], p5_destino[1], 'X', color='red', markersize=12, markeredgecolor='white', label='Destino da Criança B') |
|
|
|
|
|
ax.set_title('Laboratório de Continuidade Causal', color='white', fontsize=16) |
|
|
ax.set_xlabel('Eixo X', color='white', fontsize=12) |
|
|
ax.set_ylabel('Eixo Y', color='white', fontsize=12) |
|
|
legend = ax.legend(facecolor='#111111', edgecolor='white', framealpha=0.5) |
|
|
for text in legend.get_texts(): |
|
|
text.set_color('white') |
|
|
|
|
|
ax.grid(True, linestyle='--', color='gray', alpha=0.3) |
|
|
ax.set_aspect('equal', adjustable='box') |
|
|
|
|
|
caminho_figura = "laboratorio_completo.png" |
|
|
plt.savefig(caminho_figura, bbox_inches='tight', pad_inches=0.1, dpi=100, transparent=True) |
|
|
plt.close(fig) |
|
|
|
|
|
info_vetor = f"Vetor de Inércia Aprendido: ({vetor_aprendido[0]:.2f}, {vetor_aprendido[1]:.2f}) | Direção: {math.degrees(essencia_movimento['bearing_rad']):.2f}°" |
|
|
|
|
|
return caminho_figura, info_vetor |
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Base(primary_hue="teal")) as demo: |
|
|
gr.Markdown( |
|
|
""" |
|
|
# 🔬 Laboratório de Continuidade Causal (Versão Completa) |
|
|
Molde a trajetória completa! Use os controles para definir tanto o **caminho da Criança A** (o passado) quanto o **destino da Criança B** (o futuro). |
|
|
Observe como a inércia é calculada e aplicada para qualquer estilo de movimento. |
|
|
""" |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
gr.Markdown("### 🎮 Controles da Simulação") |
|
|
|
|
|
with gr.Accordion("Definir Caminho da Criança A (O Passado)", open=True): |
|
|
gr.Markdown("Começa em `[0,0]` e termina no ponto fixo de encontro `[75,45]`.") |
|
|
inflexao1_x = gr.Slider(-50, 150, value=25, label="Vetor 2 (Inflexão 1) - X", visible=False) |
|
|
inflexao1_y = gr.Slider(-50, 150, value=15, label="Vetor 2 (Inflexão 1) - Y") |
|
|
inflexao2_x = gr.Slider(-50, 150, value=50, label="Vetor 3 (Inflexão 2) - X", visible=False) |
|
|
inflexao2_y = gr.Slider(-50, 150, value=30, label="Vetor 3 (Inflexão 2) - Y") |
|
|
|
|
|
with gr.Accordion("Definir Caminho da Criança B (O Futuro)", open=True): |
|
|
destino_x_input = gr.Slider(-50, 150, value=100, label="Destino Final (X)", visible=False) |
|
|
destino_y_input = gr.Slider(-50, 150, value=90, label="Destino Final (Y)") |
|
|
|
|
|
with gr.Accordion("Configurações do Aprendizado", open=False): |
|
|
eco_input = gr.Slider(2, 300, value=150, step=1, label="Nº de Vetores no Eco de Memória") |
|
|
|
|
|
with gr.Column(scale=2): |
|
|
gr.Markdown("### 📊 Visualização da Jornada") |
|
|
info_output = gr.Textbox(label="Dados do Aprendizado (Calculado)", interactive=False) |
|
|
plot_output = gr.Image(label="Gráfico da Continuidade", type="filepath") |
|
|
|
|
|
|
|
|
inputs = [inflexao1_x, inflexao1_y, inflexao2_x, inflexao2_y, destino_x_input, destino_y_input, eco_input] |
|
|
|
|
|
|
|
|
for component in inputs: |
|
|
component.change(fn=gerar_grafico_dinamico, inputs=inputs, outputs=[plot_output, info_output]) |
|
|
|
|
|
|
|
|
demo.load(fn=gerar_grafico_dinamico, inputs=inputs, outputs=[plot_output, info_output]) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch() |