unit quaddraw;
//Kristian Whittick, September 2000
//as a much-appreciated favour for Richard Ebbs, EMIS
//Fill Random Quadrilateral Shape With Colour Gradient
//This is less of a simple task than it might first appear to be
//the QuadrilateralGradFill routine needs to take account of
//quadrilateral shapes that possibly 'cross-over' (so that they
//look like two end-to-end triangles) and the 'colour gradient'
//code needs to take account of possible rounding errors, etc
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Buttons, ExtCtrls;
type
TMainForm = class(TForm)
Image: TImage;
NewShapeButton: TBitBtn;
ExitButton: TButton;
procedure NewShapeButtonClick(Sender: TObject);
procedure ExitButtonClick(Sender: TObject);
private
{private declarations}
public
{public declarations}
procedure QuadrilateralGradFill(thisCanvas : TCanvas;
StartColor,
EndColor : TColor;
pts : array of Tpoint);
end;
var
MainForm: TMainForm;
implementation
{$R *.DFM}
procedure TMainForm.NewShapeButtonClick(Sender: TObject);
var
p1 : Tpoint;
p2 : Tpoint;
p3 : Tpoint;
p4 : Tpoint;
begin
p1.x := Random(400);
p2.x := Random(400);
p3.x := Random(400);
p4.x := Random(400);
p1.y := Random(400);
p2.y := Random(400);
p3.y := Random(400);
p4.y := Random(400);
QuadrilateralGradFill(self.Canvas, clRed, clBlue, [p1, p2, p3, p4]);
end;
//////////////////////////////////////////////////////////////
procedure TMainForm.QuadrilateralGradFill(thisCanvas : TCanvas;
StartColor,
EndColor : TColor;
pts : array of Tpoint);
type
Edge = record
X : Integer;
s : Boolean;
end;
var
Ct : Integer;
cty: Integer;
Miny : Integer;
Maxy : Integer;
Minyidx : Integer;
Maxyidx : Integer;
leftX : Edge;
rightX : Edge;
FourX : array[0..3] of Edge;
Colchange : single;
NewRed, NewGreen, NewBlue: Byte;
StartRed, StartGreen, StartBlue: Byte;
DiffRed, DiffGreen, DiffBlue : Integer;
function FindXintersect(Pt1, pt2 : Tpoint; height : Integer) : Edge;
begin
result.s := FALSE;
if pt1.y = pt2.y then
exit;
if (height > pt1.y) and (height > pt2.y) then
exit;
if (height < pt1.y) and (height < pt2.y) then
exit;
result.x := round((pt2.x - pt1.x) * (height - pt1.y) / (pt2.y - pt1.y) + pt1.x);
result.s := True;
end;
begin
//if less than three sides exit...
//find Min and Max in 'y' direction
for Ct := 0 to 3 do
begin
if Ct = 0 then
begin
Miny := pts[ct].Y;
Maxy := pts[ct].Y;
end
else
begin
if pts[ct].y > Maxy then
Maxy := pts[ct].Y
else
if pts[ct].y < Miny then
Miny := pts[ct].Y
end;
end;
//there is nothing to do if the top and bottom are the same...
if miny >= maxy then exit;
DiffRed := GetRValue(EndColor) - GetRValue(StartColor);
DiffGreen := GetGValue(EndColor) - GetGValue(StartColor);
DiffBlue := GetBValue(EndColor) - GetBValue(StartColor);
for cty := miny to maxy do
begin
FourX[0] := FindXintersect(pts[0], pts[1], Cty);
FourX[1] := FindXintersect(pts[1], pts[2], Cty);
FourX[2] := FindXintersect(pts[2], pts[3], Cty);
FourX[3] := FindXintersect(pts[3], pts[0], Cty);
leftX.s := FALSE;
rightX.s := FALSE;
for Ct := 0 to 3 do
if FourX[ct].s then
begin
if not leftX.s then
begin
leftX.x := FourX[ct].x;
leftX.s := TRUE;
end
else
if FourX[ct].x < leftX.x then
begin
leftX.x := FourX[ct].x;
leftX.s := TRUE;
end;
if not rightX.s then
begin
rightX.x := FourX[ct].x;
rightX.s := TRUE;
end
else
if FourX[ct].x > rightX.x then
begin
rightX.x := FourX[ct].x;
rightX.s := TRUE;
end;
end;
if leftX.s and rightX.s then
begin
Colchange := (cty - miny) / (maxy - miny);
NewRed := Round(DiffRed * Colchange) + GetRValue(StartColor);
NewGreen := Round(DiffGreen * Colchange) + GetGValue(StartColor);
NewBlue := Round(DiffBlue * Colchange) + GetBValue(StartColor);
ThisCanvas.Pen.Color := RGB(NewRed, NewGreen, NewBlue);
ThisCanvas.MoveTo(leftX.x, cty);
ThisCanvas.LineTo(rightX.x, cty);
end;
end;
end;
/////////////////////////////////////////////////////
procedure TMainForm.ExitButtonClick(Sender: TObject);
begin
Close;
end;
//////
end.