rita tjocka, anti-aliaserade linjer?

Permalänk
Medlem

rita tjocka, anti-aliaserade linjer?

Jag har lånat kod härifrån för 1px-linjer: http://www.codeproject.com/KB/GDI/antialias.aspx , och det fungerar fint.

Frågan är då hur man gör det med tjocka, är det bara att rita de 1px-linjerna vid sidan av de tjocka? Hur gör man det isåfall? Jag har kommit en bit på vägen, men lyckas inte få ut linjen som är perpendikulär mot den aktuella, för att hitta kanten på linjen, illustration här: http://tux.servegame.org/~webbdesing/linje.png

Där de röda prickarna är de kända koordinaterna, och de röda linjerna är de jag vill rita ut..

Permalänk
Medlem

Jag har ingen kunskap på området men efter att ha kollat upp Wu's algoritm på Wikipedia så har jag ett förslag.

Ta en titt på pseudokoden i artikeln:

// main loop for x from xpxl1 + 1 to xpxl2 - 1 do plot(x, ipart(intery), rfpart(intery)) plot(x, ipart(intery) + 1, fpart(intery)) intery = intery + gradient repeat

Mitt förslag är följande ändringar, antag att det finns en variabel w för bredden på linjen:

// main loop for x from xpxl1 + 1 to xpxl2 - 1 do plot(x, ipart(intery), rfpart(intery)) for foo from 1 to (w - 1) do plot(x, ipart(intery) + w, 1) repeat plot(x, ipart(intery) + w, fpart(intery)) //**ändrad intery = intery + gradient repeat

Notera den nya loopen i mitten och ändringen i en av de existerande raderna.

Du har ju redan implementerat algoritmen så det lär inte vara några större problem för dig att införa mina föreslagna ändringar. Själv är jag nyfiken på om de ens funkar. Har inte tänkt över det så värst mycket så det är möjligt att jag fått ett hjärnsläpp.

Får vara fräck och fråga vad det ska användas till?

EDIT: klantade mig igår kväll, glömde ändra koden i foo-loopen, den är fixad nu.

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Didonk
*snip*
Får vara fräck och fråga vad det ska användas till?

Ska testa det där imorrn, verkar intressant.. är för trött nu dock..
Det är till ett ritprogram jag håller på att utveckla till Symbian UIQ3-mobiler, bland annat SE M600 och SE P1i. Än så länge har jag en penna med olika storlek, och även genomskinlighet på den. Sudd, fyllverktyg (bucket fill), linjer, bezier-linjer, cirklar (ellipser), rektanglar, färgväljare, zoom, blur (buggig dock, blurrar bara horisontellt..) och undo/redo..

Bild på GUI:t: http://www.esato.com/board/ui/VFFmjy1c7nf2QhhP016A.jpg

alla verktyg finns inte som knappar, och GUI:t är väldigt ointuitivt och inte så värst förklarande. De fyra slidersarna är penstorlek, Röd, Grön, Blå och Alfa.

En bild jag fixat ihop: http://tux.servegame.org/~webbdesing/tux_hkpaint.png

Permalänk
Medlem

Skulle du inte kunna göra en polygon eller path (polygon där en edge kan vara en bezierkurva) av linjen istället? Då kan du ju använda din kod för tunna linjer för att rita konturerna med AA, men rita innanmätet av linjen genom att fylla polygonen.

Visa signatur

Alla män är dödliga. Sokrates var dödlig. Alltså är alla män Sokrates.

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av selotodo
Skulle du inte kunna göra en polygon eller path (polygon där en edge kan vara en bezierkurva) av linjen istället? Då kan du ju använda din kod för tunna linjer för att rita konturerna med AA, men rita innanmätet av linjen genom att fylla polygonen.

Fylla den med bucket fill med andra ord? Det skulle nog gå, men då skulle det väl bli lite såhär pga AA-linjerna?: http://tux.servegame.org/~webbdesing/litefail.png

Då måste jag ändå hitta dom två röda linjerna som jag illustrerade på förra bilden också, som jag inte vet exakt hur man gör...

Permalänk

Skulle man inte kunna ta linjen som är 1px och endast göra den tjockare. Det vill säga att man flyttar de genomskinliga pixlarna ovanför den verkliga linjen uppåt och och sen fyller i mellanrummet med svart.

Man kan även rendera linjen i högre upplösning för att sedan skala ner den innan man ritar ut den.

Permalänk
Medlem

Korkskruv: Det är precis så mitt kodexempel är tänkt att fungera.

ErkHK: Har du fått det att fungera än?

Edit: Klantade mig i min första post, glömde ändra koden i loopen, den är fixad nu.

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Didonk
Korkskruv: Det är precis så mitt kodexempel är tänkt att fungera.

ErkHK: Har du fått det att fungera än?

Edit: Klantade mig i min första post, glömde ändra koden i loopen, den är fixad nu.

hmm.. Nae inte direkt: http://tux.servegame.org/~webbdesing/fail.png

Den rätta linjen demonstrerar hur jag vill att det ska se ut, jag lade till den i the gimp. Här är koden jag använder (det är säkert fel nånstans):

void Pen::DrawWuLine( CFbsBitmap & screen, int X0, int Y0, int X1, int Y1, TRgb clrLine, TInt penSize) { /* Make sure the line runs top to bottom */ if (Y0 > Y1) { int Temp = Y0; Y0 = Y1; Y1 = Temp; Temp = X0; X0 = X1; X1 = Temp; } /* Draw the initial pixel, which is always exactly intersected by the line and so needs no weighting */ DrawPixel(screen, X0, Y0, clrLine ); int XDir, DeltaX = X1 - X0; if( DeltaX >= 0 ) { XDir = 1; } else { XDir = -1; DeltaX = 0 - DeltaX; /* make DeltaX positive */ } /* Special-case horizontal, vertical, and diagonal lines, which require no weighting because they go right through the center of every pixel */ int DeltaY = Y1 - Y0; if (DeltaY == 0) { /* Horizontal line */ while (DeltaX-- != 0) { X0 += XDir; DrawPixel(screen, X0, Y0, clrLine ); for(int w = 1; w < penSize - 1; w++) DrawPixel(screen, X0, Y0+w, clrLine); } return; } if (DeltaX == 0) { /* Vertical line */ do { Y0++; DrawPixel(screen, X0, Y0, clrLine ); for(int w = 1; w < penSize - 1; w++) DrawPixel(screen, X0, Y0+w, clrLine); } while (--DeltaY != 0); return; } if (DeltaX == DeltaY) { /* Diagonal line */ do { X0 += XDir; Y0++; DrawPixel(screen, X0, Y0, clrLine ); for(int w = 1; w < penSize - 1; w++) DrawPixel(screen, X0, Y0+w, clrLine); } while (--DeltaY != 0); return; } unsigned short ErrorAdj; unsigned short ErrorAccTemp, Weighting; /* Line is not horizontal, diagonal, or vertical */ unsigned short ErrorAcc = 0; /* initialize the line error accumulator to 0 */ TInt rl = (clrLine.Value() & 0xff0000) >> 16; TInt gl = (clrLine.Value() & 0x00ff00) >> 8; TInt bl = (clrLine.Value() & 0xff); double grayl = rl * 0.299 + gl * 0.587 + bl * 0.114; /* Is this an X-major or Y-major line? */ if (DeltaY > DeltaX) { /* Y-major line; calculate 16-bit fixed-point fractional part of a pixel that X advances each time Y advances 1 pixel, truncating the result so that we won't overrun the endpoint along the X axis */ ErrorAdj = ((unsigned long) DeltaX << 16) / (unsigned long) DeltaY; /* Draw all pixels other than the first and last */ while (--DeltaY) { ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */ ErrorAcc += ErrorAdj; /* calculate error for next pixel */ if (ErrorAcc <= ErrorAccTemp) { /* The error accumulator turned over, so advance the X coord */ X0 += XDir; } Y0++; /* Y-major, so always advance Y */ /* The IntensityBits most significant bits of ErrorAcc give us the intensity weighting for this pixel, and the complement of the weighting for the paired pixel */ Weighting = ErrorAcc >> 8; ASSERT( Weighting < 256 ); ASSERT( ( Weighting ^ 255 ) < 256 ); //get the color screen.LockHeap(); TUint32 * tmp = screen.DataAddress(); TUint32 clrBackground = tmp[X0+Y0*240]; screen.UnlockHeap(); TInt rb = (clrBackground & 0xff0000) >> 16; TInt gb = (clrBackground & 0x00ff00) >> 8; TInt bb = (clrBackground & 0xff); double grayb = rb * 0.299 + gb * 0.587 + bb * 0.114; double rr = ( rb > rl ? ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting: (Weighting ^ 255)) ) / 255.0 * ( rb - rl ) + rl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting:(Weighting ^ 255)) ) / 255.0 * ( rl - rb ) + rb ) ) ); double gr = ( gb > gl ? ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting: (Weighting ^ 255)) ) / 255.0 * ( gb - gl ) + gl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting:(Weighting ^ 255)) ) / 255.0 * ( gl - gb ) + gb ) ) ); double br = ( bb > bl ? ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting: (Weighting ^ 255)) ) / 255.0 * ( bb - bl ) + bl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting:(Weighting ^ 255)) ) / 255.0 * ( bl - bb ) + bb ) ) ); DrawPixel(screen, X0, Y0, TRgb(rr,gr,br)); for(int w = 1;w < penSize-1; w++) { DrawPixel(screen, X0, Y0+w, clrLine); } //get the color screen.LockHeap(); tmp = screen.DataAddress(); clrBackground = tmp[X0+XDir+(Y0+penSize)*240]; screen.UnlockHeap(); rb = (clrBackground & 0xff0000) >> 16; gb = (clrBackground & 0x00ff00) >> 8; bb = (clrBackground & 0xff); grayb = rb * 0.299 + gb * 0.587 + bb * 0.114; rr = ( rb > rl ? (/* ( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255): Weighting) ) / 255.0 * ( rb - rl ) + rl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255):Weighting) ) / 255.0 * ( rl - rb ) + rb ) ) ); gr = ( gb > gl ? ( /*( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255): Weighting) ) / 255.0 * ( gb - gl ) + gl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255):Weighting) ) / 255.0 * ( gl - gb ) + gb ) ) ); br = ( bb > bl ? ( /*( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255): Weighting) ) / 255.0 * ( bb - bl ) + bl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255):Weighting) ) / 255.0 * ( bl - bb ) + bb ) ) ); DrawPixel(screen, X0 + XDir, Y0+penSize, TRgb(rr,gr,br)); } /* Draw the final pixel, which is always exactly intersected by the line and so needs no weighting */ DrawPixel(screen, X1, Y1, clrLine); return; } //else if(deltax > deltay) /* It's an X-major line; calculate 16-bit fixed-point fractional part of a pixel that Y advances each time X advances 1 pixel, truncating the result to avoid overrunning the endpoint along the X axis */ ErrorAdj = ((unsigned long) DeltaY << 16) / (unsigned long) DeltaX; /* Draw all pixels other than the first and last */ while (--DeltaX) { ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */ ErrorAcc += ErrorAdj; /* calculate error for next pixel */ if (ErrorAcc <= ErrorAccTemp) { /* The error accumulator turned over, so advance the Y coord */ Y0++; } X0 += XDir; /* X-major, so always advance X */ /* The IntensityBits most significant bits of ErrorAcc give us the intensity weighting for this pixel, and the complement of the weighting for the paired pixel */ Weighting = ErrorAcc >> 8; ASSERT( Weighting < 256 ); ASSERT( ( Weighting ^ 255 ) < 256 ); //get the color screen.LockHeap(); TUint32 * tmp = screen.DataAddress(); TUint32 clrBackground = tmp[X0+Y0*240]; screen.UnlockHeap(); TInt rb = (clrBackground & 0xff0000) >> 16; TInt gb = (clrBackground & 0x00ff00) >> 8; TInt bb = (clrBackground & 0xff); double grayb = rb * 0.299 + gb * 0.587 + bb * 0.114; double rr = ( rb > rl ? ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting: (Weighting ^ 255)) ) / 255.0 * ( rb - rl ) + rl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting:(Weighting ^ 255)) ) / 255.0 * ( rl - rb ) + rb ) ) ); double gr = ( gb > gl ? ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting: (Weighting ^ 255)) ) / 255.0 * ( gb - gl ) + gl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting:(Weighting ^ 255)) ) / 255.0 * ( gl - gb ) + gb ) ) ); double br = ( bb > bl ? ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting: (Weighting ^ 255)) ) / 255.0 * ( bb - bl ) + bl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?Weighting:(Weighting ^ 255)) ) / 255.0 * ( bl - bb ) + bb ) ) ); DrawPixel(screen, X0, Y0, TRgb(rr, gr, br)); for(int w = 1;w < penSize-1; w++) { DrawPixel(screen, X0, Y0+w, clrLine); } screen.LockHeap(); tmp = screen.DataAddress(); //clrBackground = tmp[X0+(Y0+1)*240]; clrBackground = tmp[(X0)+(Y0+penSize)*240]; screen.UnlockHeap(); rb = (clrBackground & 0xff0000) >> 16; gb = (clrBackground & 0x00ff00) >> 8; bb = (clrBackground & 0xff); grayb = rb * 0.299 + gb * 0.587 + bb * 0.114; rr = ( rb > rl ? ( /*( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255): Weighting) ) / 255.0 * ( rb - rl ) + rl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255):Weighting) ) / 255.0 * ( rl - rb ) + rb ) ) ); gr = ( gb > gl ? ( /*( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255): Weighting) ) / 255.0 * ( gb - gl ) + gl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255):Weighting) ) / 255.0 * ( gl - gb ) + gb ) ) ); br = ( bb > bl ? ( /*( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255): Weighting) ) / 255.0 * ( bb - bl ) + bl ) ) : ( /*( TInt )*/( ( ( double )( grayl<grayb?(Weighting ^ 255):Weighting) ) / 255.0 * ( bl - bb ) + bb ) ) ); //DrawPixel(screen, X0, Y0 + 1, TRgb(rr, gr, br)); DrawPixel(screen, X0, Y0 + (penSize), TRgb(rr, gr, br)); for(int w = 1;w < penSize-1; w++) { DrawPixel(screen, X0, Y0+w, TRgb(0,0,0)); } } /* Draw the final pixel, which is always exactly intersected by the line and so needs no weighting */ DrawPixel(screen, X1, Y1, clrLine); }

EDIT: originalkoden jag stulit det ifrån: http://www.suchit-tiwari.org/download/aawu.c