2011-01-12 11 views
24

Potrzebuję szybkiego algorytmu do obliczania współrzędnych dla linii między dwoma punktami. Próbowałem znaleźć dobrą implementację JavaScript Bresenham, ale jest zbyt wiele i dość mylących publikacji. W Wikipedia - here najszybszy i najbardziej prosty formularz (bez podziałów i obliczania błędu dla obu kierunkach) prezentowana jest w Pseudokod tak:Algorytm Bresenhama w 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 

Wiesz o prostej i solidnej realizacji JavaScript Bresenham opartego na tej Pseudokod?

EDIT

Dzięki wszystkim! To właśnie przyszedł z na koniec:

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; 
    } 

Odpowiedz

42

przepisywania dostarczonego pseudo-kod w 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; } 
    } 
} 

Należy zauważyć, że porównując bezpośrednio pływaków może powiedzie się jak krok (choć nie powinien, gdy intensywniejszej przez ilościach całkowitych, to może albo jeżeli punkt końcowy nie jest liczbą całkowitą), więc zamiast bezpośredniego porównywania punktów końcowych może chcesz użyć epsilon:

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

to koniecznie wolno ci w dół, tak, więc rób to tylko, jeśli masz do czynienia z nie-liczbami całkowitymi.

+2

Brasenham ma działać tylko na liczbach całkowitych. Służy do obliczenia, które piksele należy pokolorować, aby narysować linię. –

+1

Podoba mi się ten, ale myślę, że można go jeszcze poprawić, usuwając przerwę na korzyść prawdziwej pętli i wykonując mnożenie przez dwa z przesunięciem. –

+2

Przesunięcie bitowe może być szybsze, ale wątpię, aby zmiana pętli wpłynęła na wydajność. Możesz łatwo zmienić go na 'while (x0! = X1 || y0! = Y1)' i usunąć 'if/break', ale musisz wyciągnąć inne wywołanie' setPixel' przed/po pętli do obsługi punkt końcowy linii prawidłowo i obudowa krawędzi. – Phrogz