-
Не подскажет ли кто алгоритм градиентной линейной заливки, но не горизонтальной или вертикальной, он есть, а с произвольным углом Alfa?
-
школьные знания по геометрии должны пригодиться.
-
Аналогичным образом я мог бы отвечать абсолютно на все вопросы форума.
-
>Аналогичным образом я мог бы отвечать абсолютно на все вопросы форума. Попробуй
homm © прав градиентная заливка по горизонтали или по вертикали по сути есть зависимость цвета от одной координаты. В случае диагонали зависимость будет от двух координат. С Пифагором вместе не служили?
-
>Не подскажет ли кто алгоритм градиентной линейной заливки, но не горизонтальной или вертикальной, он есть, а с произвольным углом Alfa?
А где должен быть чисто первый цвет и чисто второй?
-
Есть алгоритм рисования линии по клеткам(как в школьной тетрадке) реализуй его, а цвет меняй сам что бы плавно изменялся от начала к концу
-
> [5] ha (14.09.07 13:59)
Что-бы потом тот, кто такой код увидит, руки оторвал тому, кто его напишет :)
-
Бабах! %)) procedure Draw_GradientAngle(canvas:Tcanvas; _Rect:Trect; const Color_start,Color_end:Tcolor;angle:double);
const
Pixels = MaxInt div SizeOf(TRGBTriple);
type
PRGBArray = ^TRGBArray;
TRGBArray = array[0..Pixels-1] of TRGBTriple;
var _F_shadow_Bitmap:Tbitmap; x, y: Integer; Row1: PRGBArray;
rc1, rc2, gc1, gc2, bc1, bc2:integer;
long:double;
_r,_b,_g:integer;
begin
_F_shadow_Bitmap:=Tbitmap.Create;
try
_F_shadow_Bitmap.PixelFormat:=pf24bit;
_F_shadow_Bitmap.Width:=_Rect.Right-_Rect.Left;
_F_shadow_Bitmap.Height:=_Rect.Bottom-_Rect.Top;
rc1 := GetRValue(Color_start); gc1 := GetGValue(Color_start); bc1 := GetBValue(Color_start);
rc2 := GetRValue(Color_end); gc2 := GetGValue(Color_end); bc2 := GetBValue(Color_end);
rc2:=rc2-rc1;
gc2:=gc2-gc1;
bc2:=bc2-bc1;
long:= (abs(GetTrace(0,0,(_Rect.Right-_Rect.Left)div 2,(_Rect.Bottom-_Rect.Top) div 2)*sin(angle)))/2;
messagedlg(floattostr(long),mterror,[mbOK],0);
for Y := 0 to _F_shadow_Bitmap.Height - 1 do begin
Row1:= _F_shadow_Bitmap.ScanLine[y];
for x := 0 to _F_shadow_Bitmap.Width -1 do begin
_r:=trunc(rc1+rc2*(((GetTrace(_F_shadow_Bitmap.Width div 2,_F_shadow_Bitmap.Height div 2,x,y)*cos(angle-(Getpos2Angle(_F_shadow_Bitmap.Width div 2,_F_shadow_Bitmap.Height div 2,x,y))))+1)/long));
if _r>255 then _r:=255 else if _r<0 then _r:=0;
_g:=trunc(gc1+gc2*(((GetTrace(_F_shadow_Bitmap.Width div 2,_F_shadow_Bitmap.Height div 2,x,y)*cos(angle-(Getpos2Angle(_F_shadow_Bitmap.Width div 2,_F_shadow_Bitmap.Height div 2,x,y))))+1)/long));
if _g>255 then _g:=255 else if _g<0 then _g:=0;
_b:=trunc(bc1+bc2*(((GetTrace(_F_shadow_Bitmap.Width div 2,_F_shadow_Bitmap.Height div 2,x,y)*cos(angle-(Getpos2Angle(_F_shadow_Bitmap.Width div 2,_F_shadow_Bitmap.Height div 2,x,y))))+1)/long));
if _b>255 then _b:=255 else if _b<0 then _b:=0;
Row1[x].rgbtRed:=_r;
Row1[x].rgbtGreen:=_g;
Row1[x].rgbtBlue:=_b;
end;
end;
canvas.CopyRect(_Rect,_F_shadow_Bitmap.Canvas,_F_shadow_Bitmap.Canvas.ClipRect);
finally
_F_shadow_Bitmap.Free;
end;
end; юзать: Draw_GradientAngle(paintbox1.Canvas,rect(0,0,paintbox1.Width,paintbox1.Height),c lwhite,clblack,-pi/2);
-
ой, я там забыл почистить %)))
-
+ [7]function Getpos2Angle(x1,y1,x2,y2:real):real;
begin
if x1=x2 then begin
if y1>y2 then
result:=pi/2 else result:=3*pi/2;
exit;
end;
result:=ArcTan((y1-Y2)/(X1-x2));
if (X1-x2)<0 then result:=result-pi;
end;
function GetTrace(x1,y1,x2,y2:real):real;
begin
result:=(sqrt(sqr(x1-x2)+sqr(y1-y2)));
end;
-
> antonn ©
ужос какой то
-
> ужос какой то
согласен, но все же лучше, чем размышления, что школьный курс геометрии может пригодиться :)
-
> [11] antonn © (14.09.07 17:33) > согласен, но все же лучше, чем размышления, что школьный > курс геометрии может пригодиться :)
Вот по этому я промолчал, когда увидел твой код :)
-
> [11] antonn © (14.09.07 17:33)
Хрень полную рисует, если честно :(
-
в натуре... ехе не перекомпилил и запостил, щас исправлю:)
-
-
>Jimmy (12.09.07 22:48)
procedure DrawAngleGradient(aCanvas: TCanvas; aRect: TRect; aColor1, aColor2: TColor; aAngle: Integer; aSteps: Integer = 256);
var
i, x1, y1, x2, y2, W, H: Integer;
Angle, Delta, SinA, CosA, TanA, C: Extended;
R, G, B, FromR, ToR, FromG, ToG, FromB, ToB: Byte;
begin
if (aAngle > 0) and (aAngle < 90) then begin
W := aRect.Right - aRect.Left;
H := aRect.Bottom - aRect.Top;
FromR := GetRValue(AColor1);
FromG := GetGValue(AColor1);
FromB := GetBValue(AColor1);
ToR := GetRValue(AColor2);
ToG := GetGValue(AColor2);
ToB := GetBValue(AColor2);
SinA := 0; CosA := 0; Delta := 1;
Angle := (aAngle * PI) / 180;
SinCos(Angle, SinA, CosA);
TanA := SinA / CosA;
C := (W + (H / TanA)) / CosA;
if C < aSteps then
aSteps := Round(C)
else
Delta := C / aSteps;
aCanvas.Pen.Style := psClear;
X1 := 0; Y1 := 0;
for i := 0 to aSteps - 1 do begin
X2 := aRect.Left + Round(Delta * CosA * (i + 1));
Y2 := aRect.Top + Round(X2 * TanA);
R := FromR + MulDiv(i, ToR - FromR, aSteps - 1);
G := FromG + MulDiv(i, ToG - FromG, aSteps - 1);
B := FromB + MulDiv(i, ToB - FromB, aSteps - 1);
aCanvas.Brush.Color := RGB(R, G, B);
aCanvas.Polygon([Point(X1, 0), Point(X2, 0), Point(0, Y2), Point(0, Y1)]);
X1 := X2; Y1 := Y2;
end
end
end;
-
procedure MyGradient(Can:TCanvas; ApplyRect:TRect; ColorFrom, ColorTo: TColor; Angle: Single);
type
ARGBQuad = array[0..0] of TRGBQuad;
var
Bmp: TBitmap;
Line: ^ARGBQuad;
i, j, i2: Integer;
Wi, He: DWORD;
s, c, t, t90, t_t90: Single;
L, R: Single;
dr, dg, db: Single;
Col: TColor;
inv: Boolean;
begin
Wi := ApplyRect.Right - ApplyRect.Left;
He := ApplyRect.Bottom - ApplyRect.Top;
Bmp := TBitmap.Create;
Bmp.HandleType := bmDIB;
Bmp.PixelFormat := pf32bit;
Bmp.Width := Wi;
Bmp.Height := He;
Angle := Angle*pi/180.0;
Angle := Angle - trunc(Angle/(pi*2))*(pi*2);
if Angle < 0 then
Angle := Angle + 2*pi;
inv := true;
if ((Angle > pi) and (Angle < pi*3/2)) or ((Angle > 0) and (Angle < pi/2)) then begin
inv := false;
Angle := pi - Angle;
end;
if (Angle > pi/2) and (Angle < pi) then begin
Col := ColorFrom;
ColorFrom := ColorTo;
ColorTo := Col;
end;
t := Tan(Angle);
t90 := Tan(Angle+pi/2.0);
t_t90 := t - t90;
L := (t*Wi-He);
L := L/(t_t90);
L := sqrt( sqr(L) + sqr(L*t90) );
dr := (TRGBQuad(ColorTo).rgbRed - TRGBQuad(ColorFrom).rgbRed)/L;
dg := (TRGBQuad(ColorTo).rgbGreen - TRGBQuad(ColorFrom).rgbGreen)/L;
db := (TRGBQuad(ColorTo).rgbBlue - TRGBQuad(ColorFrom).rgbBlue)/L;
for i := 0 to He-1 do begin
Line := Bmp.ScanLine[i];
if inv then i2 := i else i2 := He - i;
for j := 0 to Wi-1 do begin
R := (i2 - t90*j)/(t_t90);
R := sqrt( sqr(R-j) + sqr(R*t-i2) );
Line[j].rgbRed := TRGBQuad(ColorFrom).rgbRed + round(r*dr);
Line[j].rgbGreen := TRGBQuad(ColorFrom).rgbGreen + round(r*dg);
Line[j].rgbBlue := TRGBQuad(ColorFrom).rgbBlue + round(r*db);
end;
end;
BitBlt(Can.Handle, ApplyRect.Left, ApplyRect.Top, Wi, He, Bmp.Canvas.Handle, 0, 0, SRCCOPY);
Bmp.Free;
end;
-
Огромное спасибо to Lacmus! А также всем, кто пытается оказать реальную помощь!
-
Красный и синий канал были спутаны местами. procedure MyGradient(Can:TCanvas; ApplyRect:TRect; ColorFrom, ColorTo: TColor; Angle: Single);
type
ARGBQuad = array[0..0] of TRGBQuad;
var
Bmp: TBitmap;
Line: ^ARGBQuad;
i, j, i2: Integer;
Wi, He: DWORD;
s, c, t, t90, t_t90: Single;
L: Single;
dr, dg, db: Single;
r, g, b: byte;
Col: TColor;
inv: Boolean;
begin
Wi := ApplyRect.Right - ApplyRect.Left;
He := ApplyRect.Bottom - ApplyRect.Top;
Bmp := TBitmap.Create;
Bmp.HandleType := bmDIB;
Bmp.PixelFormat := pf32bit;
Bmp.Width := Wi;
Bmp.Height := He;
Angle := Angle*pi/180.0;
Angle := Angle - trunc(Angle/(pi*2))*(pi*2);
if Angle < 0 then
Angle := Angle + 2*pi;
inv := true;
if ((Angle > pi) and (Angle < pi*3/2)) or ((Angle > 0) and (Angle < pi/2)) then begin
inv := false;
Angle := pi - Angle;
end;
if (Angle > pi/2) and (Angle < pi) then begin
Col := ColorFrom;
ColorFrom := ColorTo;
ColorTo := Col;
end;
t := Tan(Angle);
t90 := Tan(Angle+pi/2.0);
t_t90 := t - t90;
L := (t*Wi-He);
L := L/(t_t90);
L := sqrt( sqr(L) + sqr(L*t90) );
ColorFrom := ColorToRGB(ColorFrom);
ColorTo := ColorToRGB(ColorTo);
r := GetRValue(ColorFrom);
g := GetGValue(ColorFrom);
b := GetbValue(ColorFrom);
dr := (GetRValue(ColorTo) - r)/L;
dg := (GetGValue(ColorTo) - g)/L;
db := (GetBValue(ColorTo) - b)/L;
for i := 0 to He-1 do begin
Line := Bmp.ScanLine[i];
if inv then i2 := i else i2 := He - i;
for j := 0 to Wi-1 do begin
L := (i2 - t90*j)/(t_t90);
L := sqrt( sqr(L-j) + sqr(L*t-i2) );
Line[j].rgbRed := r + round(L*dr);
Line[j].rgbGreen := g + round(L*dg);
Line[j].rgbBlue := b + round(L*db);
end;
end;
BitBlt(Can.Handle, ApplyRect.Left, ApplyRect.Top, Wi, He, Bmp.Canvas.Handle, 0, 0, SRCCOPY);
Bmp.Free;
end;
-
> [16] Lacmus © (14.09.07 23:58)
Работает только для углов до 90°?
-
>homm © (15.09.07 00:53) [19]
Классно, хотя почему вычисляется тангенс 90 градусов без ошибки остается загадкой
>homm © (15.09.07 00:54) [20]
Там и с ClipRect тоже есть проблемы - он не выставлен
-
На основе homm © (15.09.07 00:53) [19]
procedure DrawAngleGradient(aCanvas: TCanvas; aRect: TRect; aColor1, aColor2: TColor; aAngle: Integer);
type
RGBQuadArray = array[0..0] of TRGBQuad;
var
FromR, FromG, FromB: Byte;
bBottomToTop: Boolean;
Bitmap: TBitmap;
i, j, k, W, H: Integer;
CoeffR, CoeffG, CoeffB, SinA, CosA, C: Extended;
Line: ^RGBQuadArray;
begin
W := aRect.Right - aRect.Left;
H := aRect.Bottom - aRect.Top;
Bitmap := TBitmap.Create;
try
Bitmap.HandleType := bmDIB;
Bitmap.PixelFormat := pf32bit;
Bitmap.SetSize(W, H);
aAngle := aAngle mod 360;
if aAngle < 0 then
aAngle := aAngle + 360;
if (aAngle >= 180) then begin
i := aColor1;
aColor1 := aColor2;
aColor2 := i;
aAngle := aAngle - 180;
end;
bBottomToTop := (aAngle > 90) and (aAngle < 180);
if bBottomToTop then
aAngle := 180 - aAngle;
SinCos(aAngle * PI / 180, SinA, CosA);
C := W * SinA + H * CosA;
FromR := GetRValue(AColor1);
FromG := GetGValue(AColor1);
FromB := GetBValue(AColor1);
CoeffR := (GetRValue(aColor2) - FromR) / C;
CoeffG := (GetGValue(aColor2) - FromG) / C;
CoeffB := (GetBValue(aColor2) - FromB) / C;
for i := 0 to H - 1 do begin
Line := Bitmap.ScanLine[i];
if bBottomToTop then
k := H - i
else
k := i;
for j := 0 to W - 1 do begin
C := j * SinA + k * CosA;
Line[j].rgbRed := FromR + Round(C * CoeffR);
Line[j].rgbGreen := FromG + Round(C * CoeffG);
Line[j].rgbBlue := FromB + Round(C * CoeffB);
end
end;
BitBlt(aCanvas.Handle, aRect.Left, aRect.Top, W, H, Bitmap.Canvas.Handle, 0, 0, SRCCOPY)
finally
Bitmap.Free
end
end;
-
Спасибо :) все-же я сам видимо не так силен в геметрии (или в логике, раз не смог додуматься до более простого варианта). Но я пошел еще дальше ;) procedure DrawAngleGradient(aCanvas: TCanvas; aRect: TRect; aColor1, aColor2: TColor; aAngle: Integer);
type
RGBQuadArray = array[0..0] of TRGBQuad;
var
FromR, FromG, FromB: Byte;
bBottomToTop: Boolean;
Bitmap: TBitmap;
i, j, k, W, H: Integer;
CoeffR, CoeffG, CoeffB, SinA, CosA, C: Integer;
Line: ^RGBQuadArray;
begin
W := aRect.Right - aRect.Left;
H := aRect.Bottom - aRect.Top;
Bitmap := TBitmap.Create;
try
Bitmap.HandleType := bmDIB;
Bitmap.PixelFormat := pf32bit;
Bitmap.Width := W;
Bitmap.Height := H;
aAngle := aAngle mod 360;
if aAngle < 0 then
aAngle := aAngle + 360;
if (aAngle >= 180) then begin
i := aColor1;
aColor1 := aColor2;
aColor2 := i;
aAngle := aAngle - 180;
end;
bBottomToTop := (aAngle > 90) and (aAngle < 180);
if bBottomToTop then
aAngle := 180 - aAngle;
SinA := round(sin(aAngle * PI / 180)*256);
CosA := round(cos(aAngle * PI / 180)*256);
C := W * SinA + H * CosA;
FromR := GetRValue(AColor1);
FromG := GetGValue(AColor1);
FromB := GetBValue(AColor1);
CoeffR := (GetRValue(aColor2) - FromR)*256 div (C shr 8);
CoeffG := (GetGValue(aColor2) - FromG)*256 div (C shr 8);
CoeffB := (GetBValue(aColor2) - FromB)*256 div (C shr 8);
for i := 0 to H - 1 do begin
Line := Bitmap.ScanLine[i];
if bBottomToTop then
k := H - i
else
k := i;
for j := 0 to W - 1 do begin
C := j * SinA + k * CosA;
Line[j].rgbRed := FromR + ((C * CoeffR) shr 16);
Line[j].rgbGreen := FromG + ((C * CoeffG) shr 16);
Line[j].rgbBlue := FromB + ((C * CoeffB) shr 16);
end;
end;
BitBlt(aCanvas.Handle, aRect.Left, aRect.Top, W, H, Bitmap.Canvas.Handle, 0, 0, SRCCOPY)
finally
Bitmap.Free
end;
end; мой старый вариант на тестовой сцене — 2050мс, вариант из [22] — 1150мс, этот ваиант — 310мс.
-
homm © k * CosA; можно вынести в первый цикл, будет еще чуть быстрее:)
-
> [24] antonn © (15.09.07 22:43)
Даже нескольких процентов не получилось :) Тем не менее точность повысил точность. procedure DrawAngleGradient(aCanvas: TCanvas; aRect: TRect; aColor1, aColor2: TColor; aAngle: Integer);
type
RGBQuadArray = array[0..0] of TRGBQuad;
var
FromR, FromG, FromB: Byte;
bBottomToTop: Boolean;
Bitmap: TBitmap;
i, j, k, W, H: Integer;
CoeffR, CoeffG, CoeffB, SinA, CosA, C, C1: Integer;
Line: ^RGBQuadArray;
begin
W := aRect.Right - aRect.Left;
H := aRect.Bottom - aRect.Top;
Bitmap := TBitmap.Create;
try
Bitmap.HandleType := bmDIB;
Bitmap.PixelFormat := pf32bit;
Bitmap.Width := W;
Bitmap.Height := H;
aAngle := aAngle mod 360;
if aAngle < 0 then
aAngle := aAngle + 360;
if (aAngle >= 180) then begin
i := aColor1;
aColor1 := aColor2;
aColor2 := i;
aAngle := aAngle - 180;
end;
bBottomToTop := (aAngle > 90) and (aAngle < 180);
if bBottomToTop then
aAngle := 180 - aAngle;
SinA := round(sin(aAngle * PI / 180)*4096);
CosA := round(cos(aAngle * PI / 180)*4096);
C := (W * SinA + H * CosA) shr 12;
FromR := GetRValue(AColor1);
FromG := GetGValue(AColor1);
FromB := GetBValue(AColor1);
CoeffR := (GetRValue(aColor2) - FromR)*4096 div C;
CoeffG := (GetGValue(aColor2) - FromG)*4096 div C;
CoeffB := (GetBValue(aColor2) - FromB)*4096 div C;
for i := 0 to H - 1 do begin
Line := Bitmap.ScanLine[i];
if bBottomToTop then
k := (H - i) * CosA
else
k := i * CosA;
for j := 0 to W - 1 do begin
C := j * SinA + k;
Line[j].rgbRed := FromR + ((C * CoeffR) shr 24);
Line[j].rgbGreen := FromG + ((C * CoeffG) shr 24);
Line[j].rgbBlue := FromB + ((C * CoeffB) shr 24);
end;
end;
BitBlt(aCanvas.Handle, aRect.Left, aRect.Top, W, H, Bitmap.Canvas.Handle, 0, 0, SRCCOPY)
finally
Bitmap.Free
end;
end;
-
> homm © (15.09.07 22:55) [25]
Вот так побыстрее процентов на 20:
procedure DrawAngleGradient2(DC: HDC; ARect: TRect; AColor1, AColor2: TColor; AAngle: Integer);
type
RGBQuadArray = array[0..0] of TRGBQuad;
var
FromR, FromG, FromB: Byte;
bBottomToTop: Boolean;
i, j, k, W, H: Integer;
CoeffR, CoeffG, CoeffB, SinA, CosA, C: Integer;
Line: ^RGBQuadArray;
bmi: BITMAPINFO;
PBits: pointer;
MemDC: HDC;
MemBmp: HBITMAP;
LineBytes: integer;
nRow: integer;
function BytesPerScanline(PixelsPerScanline, BitsPerPixel, Alignment: Longint): Longint;
begin
Dec(Alignment);
Result := ((PixelsPerScanline * BitsPerPixel) + Alignment) and not Alignment;
Result := Result div 8;
end;
function GetScanLine(bmi: BITMAPINFO; Bits: pointer; Row: Integer): Pointer;
var
nRow: integer;
begin
if bmi.bmiHeader.biHeight > 0 then
nRow := bmi.bmiHeader.biHeight - Row - 1
else
nRow := Row;
Integer(Result) := Integer(Bits) + nRow * BytesPerScanline(bmi.bmiHeader.biWidth, bmi.bmiHeader.biBitCount, 32);
end;
begin
W := aRect.Right - aRect.Left;
H := aRect.Bottom - aRect.Top;
ZeroMemory(@bmi, sizeof(bmi));
bmi.bmiHeader.biSize := sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biCompression := BI_RGB;
bmi.bmiHeader.biBitCount := 32;
bmi.bmiHeader.biPlanes := 1;
bmi.bmiHeader.biWidth := w;
bmi.bmiHeader.biHeight := h;
bmi.bmiHeader.biSizeImage := 0;
bmi.bmiHeader.biClrUsed :=0;
bmi.bmiHeader.biClrImportant:=0;
MemDC := CreateCompatibleDC(DC);
MemBmp := CreateDIBSection(MemDC, bmi, DIB_RGB_COLORS, pBits, 0, 0);
SelectObject(MemDC, MemBmp);
aAngle := aAngle mod 360;
if aAngle < 0 then
aAngle := aAngle + 360;
if (aAngle >= 180) then begin
i := aColor1;
aColor1 := aColor2;
aColor2 := i;
aAngle := aAngle - 180;
end;
bBottomToTop := (aAngle > 90) and (aAngle < 180);
if bBottomToTop then
aAngle := 180 - aAngle;
SinA := round(sin(AAngle * PI / 180) * 4096);
CosA := round(cos(AAngle * PI / 180) * 4096);
C := (W * SinA + H * CosA) shr 12;
FromR := GetRValue(AColor1);
FromG := GetGValue(AColor1);
FromB := GetBValue(AColor1);
CoeffR := (GetRValue(aColor2) - FromR) * 4096 div C;
CoeffG := (GetGValue(aColor2) - FromG) * 4096 div C;
CoeffB := (GetBValue(aColor2) - FromB) * 4096 div C;
for i := 0 to H - 1 do begin
Line := GetScanLine(bmi, pBits, i);
if bBottomToTop then
k := (H - i) * CosA
else
k := i * CosA;
for j := 0 to W - 1 do begin
C := j * SinA + k;
Line[j].rgbRed := FromR + ((C * CoeffR) shr 24);
Line[j].rgbGreen := FromG + ((C * CoeffG) shr 24);
Line[j].rgbBlue := FromB + ((C * CoeffB) shr 24);
end;
end;
BitBlt(DC, ARect.Left, ARect.Top, W, H, MemDC, 0, 0, SRCCOPY);
DeleteObject(MemBmp);
DeleteObject(MemDC);
end;
А для углов кратных 90 надо вообще по другому действовать - можно в 10-20 раз быстрее залить.
|