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

如何优化带360度刻度椭圆的绘制代码?避免重复调用MoveTo和LineTo

优化椭圆刻度绘制的重复代码问题

我在窗体的PaintBox上绘制了带360度刻度的椭圆,但目前需要多次重复调用MoveTo和LineTo来绘制刻度,同时手动定位每个数字的位置,代码冗余严重。以下是当前的PaintBox1Paint事件处理代码:

procedure PaintBox1Paint(Sender: TObject);
begin
 paintbox1.canvas.Pen.Color := clblue;
 paintbox1.canvas.Pen.Width := 1;
 paintbox1.canvas.Ellipse(98,51,520,473);
 paintbox1.canvas.MoveTo(515,263);
 paintbox1.canvas.LineTo(526,263);
 paintbox1.canvas.MoveTo(310,45);
 paintbox1.canvas.LineTo(310,52);              
 paintbox1.canvas.MoveTo(90,263);
 paintbox1.canvas.LineTo(99,263);
 paintbox1.canvas.MoveTo(310,472);
 paintbox1.canvas.LineTo(310,479);
 paintbox1.canvas.MoveTo(512,207);              
 paintbox1.canvas.LineTo(518,206);
 paintbox1.canvas.MoveTo(491,158);
 paintbox1.canvas.LineTo(496,155);
 paintbox1.canvas.MoveTo(458,114);
 paintbox1.canvas.LineTo(462,110); 
 paintbox1.canvas.MoveTo(414,81);
 paintbox1.canvas.LineTo(417,76);                                    
 paintbox1.canvas.MoveTo(364,59);
 paintbox1.canvas.LineTo(365,52);
 paintbox1.canvas.MoveTo(255,59);               
 paintbox1.canvas.LineTo(254,52);
 paintbox1.canvas.MoveTo(203,78);
 paintbox1.canvas.LineTo(201,73);
 paintbox1.canvas.MoveTo(161,110);
 paintbox1.canvas.LineTo(155,105);
 paintbox1.canvas.MoveTo(127,158);
 paintbox1.canvas.LineTo(119,154);
 paintbox1.canvas.MoveTo(106,209);
 paintbox1.canvas.LineTo(97,207);
 paintbox1.canvas.MoveTo(106,317);
 paintbox1.canvas.LineTo(97,319);
 paintbox1.canvas.MoveTo(126,368);
 paintbox1.canvas.LineTo(120,371);
 paintbox1.canvas.MoveTo(160,411);
 paintbox1.canvas.LineTo(153,418);
 paintbox1.canvas.MoveTo(414,445);
 paintbox1.canvas.LineTo(417,450);
 paintbox1.canvas.MoveTo(458,411);
 paintbox1.canvas.LineTo(462,415);
 //========================= Outer Ring Number 0,1,2,3,4,5 ....23 =============== 
 paintbox1.canvas.Font.Color := clblue;
 paintbox1.canvas.Font.Size := 10;
 paintbox1.canvas.TextOut(530,255,' 0');
 paintbox1.canvas.TextOut(524,196,' 1');
 paintbox1.canvas.TextOut(501,144,' 2');
 paintbox1.canvas.TextOut(465,97,' 3'); 
 paintbox1.canvas.TextOut(417,60,' 4');                                         
 paintbox1.canvas.TextOut(361,33,' 5');
 paintbox1.canvas.TextOut(303,26,' 6 ');
 paintbox1.canvas.TextOut(242,37,'7 ');
 paintbox1.canvas.TextOut(187,55,'8 '); 
 paintbox1.canvas.TextOut(139,91,'9 ');
 paintbox1.canvas.TextOut(95,140,'10 ');
 paintbox1.canvas.TextOut(75,195,'11 ');
 paintbox1.canvas.TextOut(68,255,' 12 ');
 paintbox1.canvas.TextOut(80,312,'13 ');                                   
 paintbox1.canvas.TextOut(101,365,'14 ');
 paintbox1.canvas.TextOut(135,417,'15 '); 
 paintbox1.canvas.TextOut(186,456,'16 ');
 paintbox1.canvas.TextOut(244,476,'17 ');
 paintbox1.canvas.TextOut(298,480,' 18 '); 
 paintbox1.canvas.TextOut(360,474,' 19');
 paintbox1.canvas.TextOut(415,453,' 20');
 paintbox1.canvas.TextOut(464,415,' 21');
 paintbox1.canvas.TextOut(497,368,' 22');
 paintbox1.canvas.TextOut(520,315,' 23'); 
end;

请问是否有避免大量重复代码的优化方法?


优化方案

当然可以通过三角函数计算位置+循环遍历的方式彻底消除重复代码,核心思路是利用椭圆的参数方程,计算每个刻度和数字的坐标,然后批量绘制。

步骤1:提取椭圆核心参数

先算出椭圆的中心坐标、长半轴和短半轴:

  • 原椭圆边界为Ellipse(98,51,520,473),因此:
    • 中心X:(98 + 520) / 2 = 309
    • 中心Y:(51 + 473) / 2 = 262
    • 长半轴(水平方向):(520 - 98) / 2 = 211
    • 短半轴(垂直方向):(473 - 51) / 2 = 211(注:你这里实际是正圆,不过代码兼容椭圆场景)

步骤2:循环绘制刻度与数字

利用Sin和Cos函数计算每个角度对应的坐标,循环处理24个刻度(对应15度间隔):

procedure PaintBox1Paint(Sender: TObject);
const
  // 椭圆参数
  CenterX = 309;
  CenterY = 262;
  RadiusX = 211;
  RadiusY = 211;
  // 刻度配置
  TickCount = 24;
  TickAngleStep = 360 / TickCount; // 每个刻度间隔15度
  TickLength = 7; // 刻度线长度
  // 数字偏移量(让数字在椭圆外侧)
  TextOffset = 15;
var
  I: Integer;
  Angle: Double;
  Radian: Double;
  X1, Y1, X2, Y2: Integer;
  TextX, TextY: Integer;
  TextStr: string;
begin
  PaintBox1.Canvas.Pen.Color := clBlue;
  PaintBox1.Canvas.Pen.Width := 1;
  // 绘制椭圆
  PaintBox1.Canvas.Ellipse(98, 51, 520, 473);

  // 设置字体
  PaintBox1.Canvas.Font.Color := clBlue;
  PaintBox1.Canvas.Font.Size := 10;

  // 循环绘制所有刻度和数字
  for I := 0 to TickCount - 1 do
  begin
    // 将角度转换为弧度(Delphi三角函数使用弧度)
    Angle := I * TickAngleStep;
    Radian := DegToRad(Angle);

    // 计算椭圆上的点(刻度内侧端点)
    X1 := Round(CenterX + RadiusX * Cos(Radian));
    Y1 := Round(CenterY + RadiusY * Sin(Radian));

    // 计算刻度外侧端点
    X2 := Round(CenterX + (RadiusX + TickLength) * Cos(Radian));
    Y2 := Round(CenterY + (RadiusY + TickLength) * Sin(Radian));

    // 绘制刻度线
    PaintBox1.Canvas.MoveTo(X1, Y1);
    PaintBox1.Canvas.LineTo(X2, Y2);

    // 计算数字位置(在刻度外侧更远处)
    TextX := Round(CenterX + (RadiusX + TextOffset) * Cos(Radian));
    TextY := Round(CenterY + (RadiusY + TextOffset) * Sin(Radian));
    TextStr := IntToStr(I);

    // 根据角度微调数字位置,避免偏移过多
    case I of
      0: PaintBox1.Canvas.TextOut(TextX + 5, TextY - 5, TextStr);
      6: PaintBox1.Canvas.TextOut(TextX - 5, TextY - 10, TextStr);
      12: PaintBox1.Canvas.TextOut(TextX - 10, TextY - 5, TextStr);
      18: PaintBox1.Canvas.TextOut(TextX - 5, TextY, TextStr);
    else
      PaintBox1.Canvas.TextOut(TextX, TextY, TextStr);
    end;
  end;
end;

优化后的优势

  • 代码量大幅减少,逻辑清晰易维护
  • 可通过修改常量快速调整刻度数量、间隔、长度
  • 自动适配椭圆参数,后续椭圆大小变化时只需更新核心参数
  • 避免手动计算坐标的繁琐与出错概率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 04:44:53