【问题标题】:Graphics32 fill polygon with hatched patternGraphics32 用阴影图案填充多边形
【发布时间】:2018-01-01 06:33:51
【问题描述】:

我正在尝试将 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 类,但这是使用位图填充。请注意,如果相关,此绘图是针对 TPositionedLayerOnPaint 事件处理程序。

【问题讨论】:

    标签: delphi vcl delphi-xe4 graphics32


    【解决方案1】:

    到目前为止,Graphics32 中还没有直接的模式支持,但是有很多方法可以创建您想要使用的模式。

    这是使用示例多边形填充的一种解决方案:

    首先,您需要为阴影图案编写一个采样器类。有几种方法可以构建这样的采样器。下面你可以找到一个非常简单的:

    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),所有其他方法都可以从祖先类中使用。

    现在它有点复杂了。为了使用示例,您必须在 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) 加快代码速度,但我想这对于这样一个简单的功能来说可能有点过头了。

    【讨论】:

      【解决方案2】:

      我尝试了上述自定义填充,但结果出乎意料。 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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-22
        • 1970-01-01
        • 2023-03-20
        • 1970-01-01
        • 1970-01-01
        • 2020-07-26
        • 2019-02-15
        • 1970-01-01
        相关资源
        最近更新 更多