Algoritmul liniei Bresenham

De la Wikipedia, enciclopedia liberă.
Salt la navigare Salt la căutare

Algoritmul de linie Bresenham (de unii numit algoritmul punctului mediu sau chiar cercurile Bresenham ) este un algoritm de rasterizare a liniei . În prezent este cel mai utilizat algoritm pentru rasterizarea liniilor , în principal datorită cererii sale reduse de resurse de calcul.

Descriere

Pentru a înțelege algoritmul , simplificăm problema presupunând că este între .

Să ne imaginăm că suntem la un pas algoritm, adică tocmai am stabilit ce pixel să „pornim”, de exemplu .

Acum trebuie să determinăm următorul pixel care să „pornească”, să-l numim , unde este .

Situația este cea prezentată în figura 1, unde din punctul 1 (cel în verde) trebuie să mergem la punctul 2, care poate fi găsit imediat în dreapta, cazul A sau în partea dreaptă sus, cazul B.

figura 1
  • În cazul A avem ;
  • În cazul B avem .

Să luăm în considerare punctul (Figura 2), punctul de mijloc între A și B. Dacă linia de rasterizat trece peste, vom evidenția pixelul superior B, altfel pixelul inferior A.

Figura 2

Pentru a determina dacă se află sub sau deasupra liniei, luați în considerare forma explicită a ecuației liniei:

care poate fi rescris sub forma:

Toate punctele aparținând liniei trebuie să verifice ecuația. Dar această linie împarte și două jumătăți de plan, cel alcătuit din toate punctele pentru care formula anterioară returnează o valoare pozitivă și cel pentru care returnează o valoare negativă. Un exemplu de jumătate de plan poate fi găsit în figura 3.

Figura 3

Deci, din formula anterioară putem obține valoarea deciziei , înlocuind anunțul și coordonatele din (punctul mediu dintre A și B):

care va fi:

  • , dacă punctul se află pe linia dreaptă; în acest caz putem alege indiferent fie punctul A, fie punctul B;
  • , dacă punctul este deasupra liniei; în acest caz luăm punctul A;
  • , dacă punctul este sub linie; în acest caz luăm punctul B.

În algoritm ar trebui să știm de fiecare dată dacă este pozitiv sau negativ.

Să presupunem că am ales punctul A, în acest caz punctul nostru de plecare Și , iar noul nostru punct de mijloc M este . În schimb, noua valoare a Și:

Să încercăm să scădem din noua valoare a cel Bătrân:

Simplificând obținem:

Deci, avem o modalitate de a obține noua valoare într-un mod mai simplu față de cel vechi, fără a reface de fiecare dată toate calculele.

Acum trebuie să facem ipoteza pentru cazul în care a fost ales punctul B. Avem noile noastre puncte:

  • ;
  • ;

și noua noastră valoare :

Repetăm ​​scăderea:

Simplificând obținem:

În rezumat, i s-a dat o valoare :

Trebuie doar să știm valoarea ; amintindu-ne de formula de calculat și luându-l ca punct , sau o extremă a liniei, avem:

În pasaj am scos în evidență valorile Și . Prima parte a formulei corespunde ecuației liniei aplicate unui punct de pe linie, deci știm că va fi egală cu zero. În cele din urmă rămâne:

Algoritm

Din toate aceste formule putem obține în cele din urmă algoritmul: Având două puncte Și , cu coordonatele (x 1 , y 1 ) și (x 2 , y 2 ):

 DX = x 2 - x 1
DY = y 2 - y 1

// valoarea noastră d 0
d = - 1/2 * DX + DY

// atribuiți coordonatele de pornire
x = x 1
y = y 1
draw_point (x, y)

în timp ce x < x 2 {
       dacă (d> = 0) {
        d = d -DX + DY;
        y = y + 1;
        x = x + 1;
       }
       altceva {
        d = d + DY;
        x = x + 1;
       }
       draw_point (x, y)
}

Observăm că algoritmul are numere în virgulă mobilă, care necesită resurse de calcul, o idee pentru a evita această precizie este de a dubla valorile :

 DX = x 2 - x 1
DY = y 2 - y 1

// valoarea noastră d 0
d = - DX + 2 * DY

// atribuiți coordonatele de pornire
x = x 1
y = y 1
draw_point (x, y)

în timp ce x < x 2 {
       dacă (d> = 0) {
        d = d -2 * DX + 2 * DY;
        y = y + 1;
        x = x + 1;
       }
       altceva {
        d = d + 2 * DY;
        x = x + 1;
       }
       draw_point (x, y)
}

Apoi am obținut un algoritm care funcționează cu numere, numere întregi și simplu de implementat. Dacă am avea x 1 > x 2 atunci în loc să creștem o micșorăm în timp ce valorile deciziei rămân aceleași, chiar dacă y 1 > y 2 valorile deciziei nu variază, deoarece linia presupune o pantă de valoare opusă celei cazului y 1 <y 2 și x 1 <x 2 , doar creșterea de că, în loc să crească, scade și valoarea deciziei rămâne neschimbată, deoarece tratăm linia atât dacă x 1 > x 2, cât și y 1 > y 2 ca și cum ar fi în primul caz studiat, în primul caz ambele DX și DY sunt mai mari de zero, atunci vom lua valoarea absolută, mai jos obținem algoritmul:

 DX = x 2 - x 1
DY = y 2 - y 1

// pentru a nu scrie întotdeauna valorile absolute Schimb DY și DX cu alte variabile
a = abs (DY)
b = -abs (DX)

// valoarea noastră d 0
d = 2 * a + b
// atribuiți coordonatele de pornire
x = x 1
y = y 1
draw_point (x, y)

// seq sunt măririle lui x și y
s = 1
q = 1
dacă (x 1 > x 2 ) q = -1
dacă (y 1 > y 2 ) s = -1

în timp ce x < x 2 {
       dacă (d> = 0) {
        d = 2 * (a + b) + d
        y = y + s;
        x = x + q;
       }
       altceva {
        d = 2 * a + d;
        x = x + q;
       }
       draw_point (x, y)
}

Cu aceasta am obținut liniile cu valoarea de . Cu valoare de trebuie să facem unele modificări deoarece | DY / DX |> 1 și acest lucru se întâmplă când DY> DX în acest caz aproximarea liniei cu algoritmul pe care l-am găsit este foarte proastă, deoarece doar DX este tratat ca o buclă, avem pentru a generaliza algoritmul în cazurile în care putem avea DY> DX. Dacă rotim linia cu 90 de grade putem vedea că este ca și cum ar fi trebuit să aplicăm același algoritm anterior cu coordonatele celor două puncte pentru a alege x în loc de , atunci, în acest caz, tratăm DY ca DX și DY ca DX, deci trebuie doar să schimbăm DX și DY și să menținem valorile deciziei neschimbate, în buclă putem avea DX> DY sau DY> DX, dar, din moment ce îl schimbăm, va fi întotdeauna fie DX> DY, ​​atunci în cazul în care d> = 0 vom avea că ambele coordonate cresc sau scad cu 1, deci acest caz rămâne același, cazul se schimbă în schimb în acest caz, de fapt, trebuie să decidem dacă creștem numai sau numai pe baza cazului pe care îl avem. În cazul normal crește , în cazul DY> DX, acestea se schimbă și cresc , din această logică putem deriva algoritmul pentru liniile generale care este următorul:

 swap = 0;
DX = x 2 - x 1 ;
DY = y 2 - y 1 ;

// deoarece schimb DY și DX, am întotdeauna DX> = DY, așa că pentru a ști ce coordonată trebuie să schimb, folosesc o variabilă
if (abs (DX) < abs (DY)) {
   swap (DX, DY);
   swap = 1;
}

// pentru a nu scrie întotdeauna valorile absolute Schimb DY și DX cu alte variabile
a = abs (DY);
b = -abs (DX);

// atribuiți coordonatele de pornire
x = x 1 ;
y = y 1 ;

// valoarea noastră d 0
d = 2 * a + b;

// seq sunt măririle / micșorările lui x și y
q = 1;
s = 1;
dacă (x 1 > x 2 ) q = -1;
dacă (y 1 > y 2 ) s = -1;
draw_point (x, y);
draw_point (x 2 , y 2 );
pentru (k = 0; k < -b; k + = 1) {
   dacă (d> 0) {
       x = x + q; y = y + s;
       d = d + 2 * (a + b);
   }
   altceva {
       x = x + q;
       if (swap == 1) {y = y + s; x = x - q; }
       d = d + 2 * a;
   }
   draw_point (x, y);
}

Alte proiecte

Matematica Portalul de matematică : accesați intrările Wikipedia care se ocupă de matematică