2011-01-12 166 views
24

Necesito un algoritmo rápido para calcular coordenadas para una línea entre dos puntos. Traté de encontrar una buena implementación de Bresenham en JavaScript, pero hay demasiadas publicaciones bastante confusas. En wikipedia - here la forma más rápida y sencilla (no hay divisiones y cálculo de errores para ambas direcciones) se presenta en pseudocódigo como esto:Algoritmo Bresenham en Javascript

function line(x0, y0, x1, y1) 
    dx := abs(x1-x0) 
    dy := abs(y1-y0) 
    if x0 < x1 then sx := 1 else sx := -1 
    if y0 < y1 then sy := 1 else sy := -1 
    err := dx-dy 

    loop 
    setPixel(x0,y0) 
    if x0 = x1 and y0 = y1 exit loop 
    e2 := 2*err 
    if e2 > -dy then 
     err := err - dy 
     x0 := x0 + sx 
    if e2 < dx then 
     err := err + dx 
     y0 := y0 + sy 
    end loop 

¿Conoce un simple y robusta implementación de JavaScript Bresenham en base a este pseudocódigo?

EDITAR

Gracias a todos! Esto es lo que vine con al final:

function calcStraightLine (startCoordinates, endCoordinates) { 
    var coordinatesArray = new Array(); 
    // Translate coordinates 
    var x1 = startCoordinates.left; 
    var y1 = startCoordinates.top; 
    var x2 = endCoordinates.left; 
    var y2 = endCoordinates.top; 
    // Define differences and error check 
    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; 
    // Set first coordinates 
    coordinatesArray.push(new Coordinates(y1, x1)); 
    // Main loop 
    while (!((x1 == x2) && (y1 == y2))) { 
     var e2 = err << 1; 
     if (e2 > -dy) { 
     err -= dy; 
     x1 += sx; 
     } 
     if (e2 < dx) { 
     err += dx; 
     y1 += sy; 
     } 
     // Set coordinates 
     coordinatesArray.push(new Coordinates(y1, x1)); 
    } 
    // Return the result 
    return coordinatesArray; 
    } 

Respuesta

42

Reescribiendo el pseudo-código suministrado en JavaScript:

function line(x0, y0, x1, y1){ 
    var dx = Math.abs(x1-x0); 
    var dy = Math.abs(y1-y0); 
    var sx = (x0 < x1) ? 1 : -1; 
    var sy = (y0 < y1) ? 1 : -1; 
    var err = dx-dy; 

    while(true){ 
    setPixel(x0,y0); // Do what you need to for this 

    if ((x0==x1) && (y0==y1)) break; 
    var e2 = 2*err; 
    if (e2 >-dy){ err -= dy; x0 += sx; } 
    if (e2 < dx){ err += dx; y0 += sy; } 
    } 
} 

Tenga en cuenta que la comparación de los flotadores directamente puede fallar a medida que paso (aunque no cuando debe dando un paso por cantidades enteros, puede ser que si cualquiera de punto final es no entero), por lo que en lugar de comparar directamente los puntos finales es posible que desee utilizar un épsilon:

if (Math.abs(x0-x1)<0.0001 && Math.abs(y0-y1)<0.0001) break; 

Esto necesariamente le hará perder hacia abajo, sin embargo, solo hazlo si estás tratando con números enteros.

+2

Se supone que Brasenham solo trabaja en enteros de todos modos. Se usa para calcular los píxeles a color para dibujar una línea. –

+1

Me gusta esta, pero creo que se puede mejorar aún más eliminando la ruptura a favor de la condición de bucle real y haciendo la multiplicación por dos con shift. –

+2

El cambio de bit puede ser un poco más rápido, pero dudo que cambiar el ciclo afecte el rendimiento. Podrías cambiarlo fácilmente a 'while (x0! = X1 || y0! = Y1)' y eliminar el 'if/break', pero tendrías que sacar otra llamada a' setPixel' antes/después del loop para manejar el punto final de la línea correctamente y la caja del borde. – Phrogz