You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GDI+绘制多边形路径出现内部多余连线问题咨询

GDI+绘制八角星路径异常问题

我尝试绘制如下多边形:
目标绘制效果

实现代码如下:

procedure TForm1.Paint;
var
  g: TGPGraphics;
  pen: TGPPen;
  i: Integer;
  p: TGPGraphicsPath;
  m: TGPMatrix;
  br: TGpSolidBrush;
begin
  inherited;
  g := TGPGraphics.Create(Canvas.Handle);
  pen := TGPPen.Create(MakeColor(141, 63, 0), 3);
  p := TGPGraphicsPath.Create();
  m := TGPMatrix.Create;
  br := TGpSolidBrush.Create(MakeColor(244, 146, 32));
  try
    g.SetSmoothingMode(SmoothingModeHighQuality);
    g.Clear(MakeColor(255, 255, 255));
    g.TranslateTransform(ClientWidth div 2, ClientHeight div 2);
    m.Rotate(45);
    p.StartFigure;
    for i := 0 to 7 do begin
      p.AddLine(-14, -33, 0, -55); // 到右上
      p.AddLine(0, -55, 14, -33); // 到右下
      p.Transform(m); // 旋转45度
    end;
    p.CloseFigure;
    g.DrawPath(pen, p);
  finally
    br.Free;
    m.Free;
    p.Free;
    pen.Free;
    g.Free;
  end;
end;

但运行后GDI+会自动闭合每一条星射线的路径,生成了存在多余内部连线的错误效果,实际绘制结果如下:
实际绘制效果

现有三个咨询问题:

  • 上述代码存在什么问题?
  • 备注:我必须使用AddLine方法(每次调用传入两组坐标点)绘制射线的两条边,GDI+中是否存在类似LineTo的方法,仅需传入一组X、Y坐标,自动以上一个路径点作为线段起点?
  • 是否存在无需执行绘制操作,即可直接对TGPPointF围绕指定点做旋转变换的方法?

问题解答

1. 代码核心问题

两处逻辑错误直接导致绘制结果不符合预期:

  • 路径的Transform方法会对路径内所有已存储的点全部生效,不是仅对后续新增的点做变换。第一次循环后路径存了3个点(2条线段),旋转45度;第二次循环新增线段后再调用旋转,第一次存的3个点会累计旋转90度,循环执行8次后,最早存入的点累计旋转360度,所有点位置完全错位,根本不是均匀分布的八角结构。
  • 路径绘制时没有做子图分割:每画完一个星角的两条边,既没有回到中心起点,也没有调用StartFigure开启新的子路径,GDI+会自动把上一段的终点和下一段的起点连线,最后调用CloseFigure还会强制连接整个路径的首尾,自然会出现大量多余的内部连线。

2. 类LineTo效果的实现方式

GDI+没有提供只接收单个坐标点的LineTo同名方法,但完全可以基于AddLine实现同等效果,不需要使用其他接口:
TGPGraphicsPath提供了GetLastPoint方法,可以直接获取路径当前的最后一个端点坐标,封装一个简单的辅助逻辑即可:每次要追加线段到新坐标点时,先取出路径最后一个点作为线段起点,和新的目标点一起传入AddLine,效果和传统GDI的LineTo完全一致,也符合必须使用AddLine的要求。

不要依赖GDI+路径的隐式自动连线规则,显式传入线段起止点的写法更稳定,不会因为子图闭合、路径变换等操作出现意外连线。

3. 独立点旋转变换方法

不需要绑定任何绘制操作,直接用矩阵类的点变换能力即可实现:
TGPMatrix自带TransformPoints方法,先构造好符合旋转规则的矩阵,把要变换的TGPPointF指针传入,就能直接把点的坐标更新为变换后的值,全程不需要创建绘图路径、不需要调用任何绘制接口。
如果要围绕任意指定点旋转,构造矩阵时按「平移坐标系到旋转中心→旋转指定角度→平移回原坐标系」的顺序设置参数即可,参考实现:

// 围绕指定中心旋转单个TGPPointF点
function RotatePointF(const P: TGPPointF; const Center: TGPPointF; AngleDeg: Single): TGPPointF;
var
  mat: TGPMatrix;
begin
  mat := TGPMatrix.Create;
  try
    mat.Translate(-Center.X, -Center.Y);
    mat.Rotate(AngleDeg);
    mat.Translate(Center.X, Center.Y);
    Result := P;
    mat.TransformPoints(@Result, 1);
  finally
    mat.Free;
  end;
end;

可以提前用这个方法算好8个星角所有端点的坐标,再按顺序一次性加入路径,就能完全避免之前反复变换路径导致的点错位问题。


内容的提问来源于stack exchange,提问作者Paul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 22:15:46