Graphics32 用阴影线填充多边形
Graphics32 fill polygon with hatched pattern
我正在尝试将 delphi XE4 应用程序转换为使用 Graphics32 库进行绘图,而不是使用标准 delphi 绘图方法。
我做的一件事是绘制一个图标,其中包含一个带有对角交叉影线图案的小椭圆。该图标应如下所示:
以下是我使用标准 TCanvas
绘图方法的方法:
ACanvas.Brush.Color := shape.pcolor;
ACanvas.Brush.Style := bsdiagCross;
ACanvas.Ellipse(-13, -9, 13, 9);
我可以使用 Graphics32 绘制一个椭圆,执行以下操作:
var
Polygon : TArrayOfFloatPoint;
begin
Polygon := Ellipse(0, 0, 13, 9);
PolylineFS(Bitmap, Polygon, pcolor, True, UAVPenWidth);
但是有没有一种简单的方法可以复制对角线交叉影线图案?我假设我可以使用 TBitmapPolygonFiller
class 但这是使用位图填充。请注意,如果相关的话,这张图是 TPositionedLayer
在它的 OnPaint
事件处理程序中。
到目前为止,Graphics32 中没有直接的模式支持,但是有许多方法可以创建您想要使用的模式。
这是一个使用多边形填充示例的解决方案:
首先你需要为阴影图案编写一个采样器class。有几种方法可以构建这样的采样器。下面你可以找到一个非常简单的:
type
THatchedPatternSampler = class(TCustomSampler)
public
function GetSampleInt(X, Y: Integer): TColor32; override;
end;
function THatchedPatternSampler.GetSampleInt(X, Y: Integer): TColor32;
begin
Result := 0;
if ((X - Y) mod 8 = 0) or ((X + Y) mod 8 = 0) then
Result := clRed32
end;
这里只需要重写一个方法(GetSampleInt),其他方法都可以使用祖先class.
现在有点复杂了。为了使用示例,您必须像这样在 TSamplerFiller 之上使用它:
Sampler := THatchedPatternSampler.Create;
Filler := TSamplerFiller.Create(Sampler);
一旦你有了这个填充器,你就可以在 PolygonFS 甚至 PolylineFS 中使用它。
最终代码可能如下所示:
var
Polygon: TArrayOfFloatPoint;
Sampler: THatchedPatternSampler;
Filler: TSamplerFiller;
begin
Polygon := Ellipse(128, 128, 120, 100);
Sampler := THatchedPatternSampler.Create;
try
Filler := TSamplerFiller.Create(Sampler);
try
PolygonFS(PaintBox32.Buffer, Polygon, Filler);
finally
Filler.Free;
end;
finally
Sampler.Free;
end;
PolylineFS(PaintBox32.Buffer, Polygon, clRed32, True, 1);
end;
这将在位图的中心(这里是 TPaintBox32 实例的缓冲区)绘制一个相当大的椭圆,并用阴影采样器代码填充它。最后使用PolylineFS函数画出实线轮廓。
从性能的角度来看,这不是最快的方法,因为每个像素都会调用 GetSampleInt。然而,它是最容易理解发生了什么的。
为了更快的替代方法,您应该直接使用填充剂。您可以像这样直接从 TCustomPolygonFiller 派生:
type
THatchedPatternFiller = class(TCustomPolygonFiller)
private
procedure FillLine(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32);
protected
function GetFillLine: TFillLineEvent; override;
end;
GetFillLine 方法变得如此简单:
function THatchedPatternFiller.GetFillLine: TFillLineEvent;
begin
Result := FillLine;
end;
但是,FillLine 方法会像这样有点复杂:
procedure THatchedPatternFiller.FillLine(Dst: PColor32; DstX, DstY,
Length: Integer; AlphaValues: PColor32);
var
X: Integer;
begin
for X := DstX to DstX + Length do
begin
if ((X - DstY) mod 8 = 0) or ((X + DstY) mod 8 = 0) then
Dst^ :=clRed32
else
Dst^ := 0;
Inc(Dst);
end;
end;
由于 DstY 保持不变,您还可以重构代码以提高性能。或者您可以使用汇编器 (SSE) 加速代码,但我想这对于这样一个简单的函数来说太过分了。
我尝试了上面描述的自定义填充,但是结果出乎意料。 U 形多边形两条腿之间的区域被填充。任何关于我正在做的错误的意见都将不胜感激。
procedure TForm1.Button1Click(Sender: TObject);
var Filler2: THatchedPatternFiller;
Polygon: TArrayOfFloatPoint;
begin
polygon := [floatpoint(100, 10), floatpoint(200, 10), floatpoint(200, 400), floatpoint(300, 400), floatpoint(300, 10), floatpoint(400, 10), floatpoint(400, 500), floatpoint( 100, 500), floatpoint( 100, 10)]; // U shaped polygon
filler2 := THatchedPatternFiller.Create;
PolygonFS(PreviewImage.Bitmap, polygon, filler2); // Wrong, red fill inside U share
PolygonFS(PreviewImage.Bitmap, polygon, clGreen32); // Works fine, green fill
Filler2.Free;
end;
Image with wrong fill, the red part should not be visible in the centre and on the right side
我正在尝试将 delphi XE4 应用程序转换为使用 Graphics32 库进行绘图,而不是使用标准 delphi 绘图方法。
我做的一件事是绘制一个图标,其中包含一个带有对角交叉影线图案的小椭圆。该图标应如下所示:
以下是我使用标准 TCanvas
绘图方法的方法:
ACanvas.Brush.Color := shape.pcolor;
ACanvas.Brush.Style := bsdiagCross;
ACanvas.Ellipse(-13, -9, 13, 9);
我可以使用 Graphics32 绘制一个椭圆,执行以下操作:
var
Polygon : TArrayOfFloatPoint;
begin
Polygon := Ellipse(0, 0, 13, 9);
PolylineFS(Bitmap, Polygon, pcolor, True, UAVPenWidth);
但是有没有一种简单的方法可以复制对角线交叉影线图案?我假设我可以使用 TBitmapPolygonFiller
class 但这是使用位图填充。请注意,如果相关的话,这张图是 TPositionedLayer
在它的 OnPaint
事件处理程序中。
到目前为止,Graphics32 中没有直接的模式支持,但是有许多方法可以创建您想要使用的模式。
这是一个使用多边形填充示例的解决方案:
首先你需要为阴影图案编写一个采样器class。有几种方法可以构建这样的采样器。下面你可以找到一个非常简单的:
type
THatchedPatternSampler = class(TCustomSampler)
public
function GetSampleInt(X, Y: Integer): TColor32; override;
end;
function THatchedPatternSampler.GetSampleInt(X, Y: Integer): TColor32;
begin
Result := 0;
if ((X - Y) mod 8 = 0) or ((X + Y) mod 8 = 0) then
Result := clRed32
end;
这里只需要重写一个方法(GetSampleInt),其他方法都可以使用祖先class.
现在有点复杂了。为了使用示例,您必须像这样在 TSamplerFiller 之上使用它:
Sampler := THatchedPatternSampler.Create;
Filler := TSamplerFiller.Create(Sampler);
一旦你有了这个填充器,你就可以在 PolygonFS 甚至 PolylineFS 中使用它。
最终代码可能如下所示:
var
Polygon: TArrayOfFloatPoint;
Sampler: THatchedPatternSampler;
Filler: TSamplerFiller;
begin
Polygon := Ellipse(128, 128, 120, 100);
Sampler := THatchedPatternSampler.Create;
try
Filler := TSamplerFiller.Create(Sampler);
try
PolygonFS(PaintBox32.Buffer, Polygon, Filler);
finally
Filler.Free;
end;
finally
Sampler.Free;
end;
PolylineFS(PaintBox32.Buffer, Polygon, clRed32, True, 1);
end;
这将在位图的中心(这里是 TPaintBox32 实例的缓冲区)绘制一个相当大的椭圆,并用阴影采样器代码填充它。最后使用PolylineFS函数画出实线轮廓。
从性能的角度来看,这不是最快的方法,因为每个像素都会调用 GetSampleInt。然而,它是最容易理解发生了什么的。
为了更快的替代方法,您应该直接使用填充剂。您可以像这样直接从 TCustomPolygonFiller 派生:
type
THatchedPatternFiller = class(TCustomPolygonFiller)
private
procedure FillLine(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32);
protected
function GetFillLine: TFillLineEvent; override;
end;
GetFillLine 方法变得如此简单:
function THatchedPatternFiller.GetFillLine: TFillLineEvent;
begin
Result := FillLine;
end;
但是,FillLine 方法会像这样有点复杂:
procedure THatchedPatternFiller.FillLine(Dst: PColor32; DstX, DstY,
Length: Integer; AlphaValues: PColor32);
var
X: Integer;
begin
for X := DstX to DstX + Length do
begin
if ((X - DstY) mod 8 = 0) or ((X + DstY) mod 8 = 0) then
Dst^ :=clRed32
else
Dst^ := 0;
Inc(Dst);
end;
end;
由于 DstY 保持不变,您还可以重构代码以提高性能。或者您可以使用汇编器 (SSE) 加速代码,但我想这对于这样一个简单的函数来说太过分了。
我尝试了上面描述的自定义填充,但是结果出乎意料。 U 形多边形两条腿之间的区域被填充。任何关于我正在做的错误的意见都将不胜感激。
procedure TForm1.Button1Click(Sender: TObject);
var Filler2: THatchedPatternFiller;
Polygon: TArrayOfFloatPoint;
begin
polygon := [floatpoint(100, 10), floatpoint(200, 10), floatpoint(200, 400), floatpoint(300, 400), floatpoint(300, 10), floatpoint(400, 10), floatpoint(400, 500), floatpoint( 100, 500), floatpoint( 100, 10)]; // U shaped polygon
filler2 := THatchedPatternFiller.Create;
PolygonFS(PreviewImage.Bitmap, polygon, filler2); // Wrong, red fill inside U share
PolygonFS(PreviewImage.Bitmap, polygon, clGreen32); // Works fine, green fill
Filler2.Free;
end;
Image with wrong fill, the red part should not be visible in the centre and on the right side