Saltar a contenido

LogoAtom

Animación

Estudio del movimiento en GeoGebra

Inspiración y Origen

LogoAtom es una animación basada en el clásico logotipo de un átomo, con electrones girando alrededor del núcleo. La inspiración para esta animación provino del trabajo de Keishiro Ueki (keishiroueki.net), quien compartió una idea similar en redes sociales.

En un primer estudio, exploré el movimiento en GeoGebra, analizando las trayectorias y el comportamiento orbital de los electrones. Posteriormente, trasladé estos principios a p5.js, donde desarrollé la animación definitiva.

Dinámica de la Animación

La animación sigue una estructura cíclica en la que:

  • Un núcleo central permanece estático.
  • Los electrones orbitan alrededor siguiendo trayectorias que combinan círculos y triángulos rotantes.
  • Se emplean variaciones en la velocidad y ángulos de rotación para lograr un efecto dinámico.
  • Se generan intersecciones entre las órbitas, creando un efecto visual de entrelazado.
  • El sistema se mantiene en un bucle continuo para reforzar la sensación de movimiento constante.

Implementación Técnica

La animación en p5.js se basa en conceptos de geometría y transformación de coordenadas:

  • Construcción de trayectorias: Se utilizan ecuaciones trigonométricas para definir las órbitas y los desplazamientos de los electrones.
  • Vectores de movimiento: Se implementan p5.Vector para calcular posiciones dinámicas.
  • Historial de posiciones: Se almacena la trayectoria de los electrones en arrays para visualizar rastros en el movimiento.
  • Interpolación de color: Se emplean variaciones en la opacidad y color de los electrones para simular un efecto de persistencia visual.

Aplicación en el Aula

He utilizado esta animación en clase para enseñar a los alumnos sobre:

  • Conceptos de programación gráfica en p5.js.
  • El uso de GeoGebra para analizar movimientos antes de programarlos.
  • La relación entre modelos matemáticos y su implementación computacional.
  • El uso de vectores en animaciones para calcular posiciones dinámicas de manera eficiente.

Esta experiencia ha servido como un excelente ejemplo de cómo la programación puede ser utilizada para visualizar y comprender fenómenos científicos y matemáticos de manera interactiva.

Code (p5.js)

Text Only
  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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
var radio=150;
var radio2=210;
var diff=40;
var speed=2;
var rojo=100, verde=10, azul=30;
var modAng=0;

var n=3;
var ncircles=1;
var posX=0;
var posY=0;
var angle=0;

var rojosX=new Array(360*speed);
var rojosY=new Array(360*speed);

for(var t=0; t<=360*speed;t++){
rojosX[t]=new Array(ncircles);
rojosY[t]=new Array(ncircles);
for(var j=0; j<=ncircles;j++){
    rojosX[t][j]=new Array(n);
    rojosY[t][j]=new Array(n);
}

}



var t1X=new Array(ncircles);
var t1Y=new Array(ncircles);
var t2X=new Array(ncircles);
var t2Y=new Array(ncircles);



for(var j=0; j<=ncircles;j++){
t1X[j]=new Array(n);
t1Y[j]=new Array(n);
t2X[j]=new Array(n);
t2Y[j]=new Array(n);

}
let v1;
let v2;
let v3;
var sentido=1;




function setup(){
    createCanvas(1800, 1000);
    background(255);
    rojo=0;
    verde=250;
    azul=130;
    angleMode(DEGREES);
}


function draw(){

background(256);

    if(angle>360) modAng=angle%360;
    else modAng=angle;

    angle=angle+speed;
    textSize(32);
    text(angle, 10, 30);
    text(modAng, 10, 70);

    fill(0);
    stroke(0);
    strokeWeight(2);
    posX=width/2;
    posY=height/2;
    ellipse(posX,posY, 30, 30);

    for(var j=0; j<=ncircles;j++){
    for(var i=0; i<=n;i++){
        //triángulo 1
        t1X[j][i]=posX+(radio+diff*j)*cos(angle+i*360/n);
        t1Y[j][i]=posY+(radio+diff*j)*sin(angle+i*360/n);
        //triángulo 2
        t2X[j][i]=posX+(radio2+diff*j)*cos(i*360/n-angle);
        t2Y[j][i]=posY+(radio2+diff*j)*sin(i*360/n-angle);

    }
}
for(var j=0; j<ncircles;j++){
    for(var i=0; i<n;i++){
    v3=createVector(posX, posY);
    v1 = createVector(t2X[j][i]-posX, t2Y[j][i]-posY);
    v2 = createVector(t1X[j][i+1]-posX, t1Y[j][i+1]-posY);
    v3.add(v1);
    v3.add(v2);

    //ellipse(v3.x, v3.y, 10, 10);

    //rojosX
    rojosX[modAng][j][i]=v3.x;
    rojosY[modAng][j][i]=v3.y;

    fill(60);
    strokeWeight(1);
    line(t2X[j][i],t2Y[j][i],v3.x,v3.y);
    line(t1X[j][i],t1Y[j][i],v3.x,v3.y);

    fill(0);
    strokeWeight(3.5);
    //triángulo 1
    ellipse(t1X[j][i],t1Y[j][i], 10, 10);
    line(t1X[j][i],t1Y[j][i], t1X[j][i+1],t1Y[j][i+1]);
    strokeWeight(2.7);
    //triángulo 2
    ellipse(t2X[j][i],t2Y[j][i], 10, 10);
    //line(t2X[j][i],t2Y[j][i], t2X[j][i+1],t2Y[j][i+1]);
    //líneas del centro a cada punto
    line(posX,posY, t1X[j][i],t1Y[j][i]);
    //líneas del centro a cada punto
    line(posX,posY, t2X[j][i],t2Y[j][i]);
    //lineas entre triángulos
    line(t2X[j][i],t2Y[j][i], t1X[j][i+1],t1Y[j][i+1]);
    line(t2X[j][i+1],t2Y[j][i+1], t1X[j][i],t1Y[j][i]);
    }

}
var alcance=300;
var prop;
//dibujar los rojos

if(modAng>alcance){
for(var t=0; t<=modAng;t=t+speed){
    for(var j=0; j<ncircles;j++){
    for(var i=0; i<n;i++){
        strokeWeight(0);
        prop=(1-(modAng-t)/alcance)*255;
        fill(255, 0,0,prop);
        if(t==modAng) strokeWeight(1);
        if(modAng-t<alcance) ellipse(rojosX[t][j][i], rojosY[t][j][i], 10, 10);
        strokeWeight(0);
    }
    }
}
}else{

for(var t=360-(alcance-modAng); t<=360;t=t+speed){
    for(var j=0; j<ncircles;j++){
    for(var i=0; i<n;i++){
        strokeWeight(0);
        prop=(1-(modAng+360-t)/alcance)*255;
        fill(255, 0,0,prop);
        if(modAng-t<alcance) ellipse(rojosX[t][j][i], rojosY[t][j][i], 10, 10);

    }
    }
}

for(var t=0; t<=modAng;t=t+speed){
    for(var j=0; j<ncircles;j++){
    for(var i=0; i<n;i++){
        strokeWeight(0);
        //prop=(1-(modAng-t)/alcance)*255;
            prop=(1-(modAng-t)/alcance)*255;
        fill(255, 0,0,prop);
        if(t==modAng) strokeWeight(1);

        if(modAng-t<alcance) ellipse(rojosX[t][j][i], rojosY[t][j][i], 10, 10);
        strokeWeight(0);
    }
    }
}


}

}