En fin, no está de más un repaso rápido al A-B-C de trigonometría y su aplicación inmediata, ya que el 90% de los casos se resuelven con el 1% del conocimiento.
Lo que voy a poner es el resultado, los que estén interesados en el desarrollo de la fórmula, que le pregunten a un matemático.
Partimos de un objeto coordenada
// **** Coord Object ****Empezando por lo más básico, seno y coseno...
function Coord(x, y) {
this.x = x;
this.y = y;
}
* Pitágoras y los tiángulos. A partir de un origen o, una distancia d y un ángulo a respecto a la horizontal necesito saber la coordenada (x,y) para colocar algo allí.
var c = new Coord(o.x + d * Math.cos(a), o.y + d * Math.sin(a));* Ángulo entre 2 objetos. Teniendo 2 coordenadas m y o, necesito saber el ángulo que hacen entre sí siendo m la coordenada del ratón por ejemplo y o la coordenada del centro del objeto con el que quiero comparar m.
var a = Math.atan2(m.y - o.y, m.x - o.x);* Distancia entre 2 puntos c1 y c2. Ni que decir tiene, que ambos deben estar en las mismas unidades.
var d = Math.sqrt(Math.pow((c2.x - c1.x), 2) + Math.pow((c2.y - c1.y), 2));* Traslaciones. Necesito mover un punto c1 en una cantidad indicada por el vector o siendo el resultado c2. Ya se que es una chorradita, pero esta es la manera general de realizar transformaciones afines. La matriz de la traslación sería.
| 1 0 o.x | | c1.x | | c1.x + o.x |
| 0 1 o.y | | c1.y | = | c1.y + o.y |
| 0 0 1 | | 1 | | 1 |
Con todo ésto, para trasladar, solo habría que hacer
var c2 = new Coord(c1.x + o.x, c1.y + o.y);* Transformaciones. Escalados, deformaciones, proyecciones, transformaciones en espejo, etc... Aquí es donde tiene sentido la "chorradita" de la traslación, ya que ésta es un caso particular de transformación. Todas ellas se pueden combinar simplemente poniendo el valor correcto en la posición de la matriz de antes. Para más detalles, la wikipedia.
* Rotaciones. Otro caso especial de transformación. Para realizarlas, necesitamos definir una matriz de rotación (suponemos 2 dimensiones aunque para 3, es muy parecido). Si se quiere rotar un punto c1 un ángulo a alrededor de otro punto origen o (estamos dando una traslación como implícita, ojo), la matriz sería la siguiente, dando como resultado c2. Ojo, hay que pre-trasladar el punto de interés c1 al origen de la referencia (punto o) antes de empezar ya que o será nuestro (0, 0) para la rotación. Luego se hace la traslación contraria.
| Math.cos(a) -Math.sin(a) | | c1.x - o.x | = | c2.x |Por lo tanto, expresándolo todo junto programáticamete
| Math.sin(a) Math.cos(a) | | c1.y - o.y | | c2.y |
var c2 = new Coord(0, 0); // Voy a separarlo en 2 líneas por claridadPara 3 dimensiones, os lo dejo como deberes, pero es más de lo mismo.
c2.x = o.x + (Math.cos(a) * (c1.x - o.x)) - (Math.sin(a) * (c1.y - o.y));
c2.y = o.y + (Math.sin(a) * (c1.x - o.x)) + (Math.cos(a) * (c1.y - o.y));
* Trazado de líneas (a.k.a. trasladar un objeto desde el punto a al punto b). Solo una palabra... Bresenham. Es un algoritmo óptimo únicamente con aritmética entera. Pseudocódigo del algoritmo plagiado vilmente desde la wikipedia:
function line(x0, x1, y0, y1)Para los vagos (como yo), ya escrito en javascript:
boolean steep := abs(y1 - y0) > abs(x1 - x0)
if steep then swap(x0, y0), swap(x1, y1)
if x0 > x1 then swap(x0, x1), swap(y0, y1)
int deltax := abs(x1 - x0)
int deltay := abs(y1 - y0)
int error := deltax / 2
int ystep
int y := y0
int inc
if x0 < x1 then inc := 1 else inc := -1
if y0 < y1 then ystep := 1 else ystep := -1
for x from x0 to x1 with increment inc
if steep then plot(y,x) else plot(x,y)
error := error - deltay
if error < 0 then
y := y + ystep
error := error + deltax
function calcStraightLine (c1, c2) {* Trazado de circunferencias. Para dibujarlo se hace por simetría en los 8 octantes usando el algoritmo del punto medio.
var coords = new Array();
var x1 = c1.x; var y1 = c1.y; var x2 = c2.x; var y2 = c2.y;
// Calcula las diferencias t el chequeo de error
var dx = Math.abs(x2 - x1);
var dy = Math.abs(y2 - y1);
var sx = (x1 < x2) ? 1 : -1;
var sy = (y1 < y2) ? 1 : -1;
var err = dx - dy;
// Fija la coordenara origen
coords.push(new Coordinates(y1, x1));
// Bucle principal
while (!((x1 == x2) && (y1 == y2))) {
var e2 = err << 1;
if (e2 > -dy) {
err -= dy;
x1 += sx;
}
if (e2 < dx) {
err += dx;
y1 += sy;
}
// Guarda la coordenada calculada
coords.push(new Coordinates(y1, x1));
}
return coords;
}
Hasta aquí hemos llegado.
Funcion PuntoMedio (int xc, yc, float R)
Pintar Pixel (0, R)
Calcular p0 = 5/4 – R // si R es entero, p0 = 1-r
Para cada xk
si pk < 0
Pintar Pixel (xk+1, yk)
pk+1 = pk + 2xk + 3
si pk > 0
Pintar Pixel (xk+1, yk-1)
pk+1 = pk + 2xk – 2yk+ 5
Determinar por simetría los puntos de los otros 7 octantes
Pintar Pixel (x+xc, y+yc)
Exelente gracias, me sirvio.
ResponderEliminar