在 Processing 中创建锯齿形状

Create saw fin shape in Processing

我正在尝试使用 Processing 重新创建此图像。如何制作红锯鳍?

鉴于图像在几个轴上是对称的,我的思考过程是将其分解。我正在与 "red saw fins" 作斗争。看起来我必须使用贝塞尔曲线来创建线条,然后填充它们。如果我能够创建 1 个鳍,那么我可以在轴上旋转它的副本以将其旋转。 https://processing.org/reference/bezier_.html

只需使用贝塞尔曲线的控制点即可提供所需的形式。

这是 Delphi 中的快速示例。

点 P0-P3 给出齿的第一侧(凹面),点 P3-P6 给出齿的第二侧。

Rin 和ROut 是锯的内外半径,RM 是用于控制点计算的中间半径。

内环an是一个齿的底角,an1稍微移动以提供凹弧的曲率,an2是结束角(与下一个底角相同tooth),an3是凸弧控制点的中角。

var
  P: array[0..6] of TPoint;
  i, N, CX, CY, Rin, ROut, RM: integer;
  an, an1, an2, an3: Double;
begin
  Rin := 100;
  ROut := 170;
  RM := (RIn + ROut) div 2;
  N := 8;
  CX := 350;
  CY := 350;
  for i := 0 to 7 do begin
    an := i * 2 * Pi / N;
    an1 := an + 0.25 * Pi / N;
    an2 := an + 2 * Pi / N;
    an3 := an + Pi / N;
    P[0] := Point(Round(CX + Rin * Cos(an)), Round(CY + Rin * Sin(an)));
    P[1] := Point(Round(CX + RM * Cos(an1)), Round(CY + RM * Sin(an1)));
    P[2] := Point(Round(CX + RM * Cos(an1)), Round(CY + RM * Sin(an1)));
    P[3] := Point(Round(CX + ROut * Cos(an)), Round(CY + ROut * Sin(an)));
    P[4] := Point(Round(CX + RM * Cos(an3)), Round(CY + RM * Sin(an3)));
    P[5] := Point(Round(CX + RM * Cos(an3)), Round(CY + RM * Sin(an3)));
    P[6] := Point(Round(CX + RIn * Cos(an2)), Round(CY + RIn * Sin(an2)));
    Canvas.PolyBezier(P);
    Canvas.Ellipse(CX - 3 * RIn div 4, CY - 3 * RIn div 4,
                   CX + 3 * RIn div 4, CY + 3 * RIn div 4);

这是一张小图片。放大它,然后将其加载到用于绘制贝塞尔曲线的工具中。您知道三个固定坐标(圆上的两个坐标和尖端)并且您知道控制点需要沿着的总切线:

您还知道,控制点和曲线上的点需要形成一个包围实际曲线的框(例如,曲线不能超出该框)作为 属性 贝塞尔曲线。

所以现在:您可以尝试找到正确的点。您可以使用 Inkscape 或 Photoshop 或 Illustrator 之类的东西来查看哪条曲线看起来足够好,然后将坐标复制到您自己的程序中,或者您只需将其绘制在网格上并通过查看网格即可找到粗略的坐标然后尝试接近您认为的值。

然后当你有缺失的控制点时,你在处理中把它画成一个形状:

void draw() {
  // draw the inner circle with a "fat" stroke
  strokeWeight(20);
  // assuming center mode
  ellipse(width/2, height/2, 100, 100);

  // reset that stroke fatness
  strokeWeight(1);
  // make sure we'll be rotating about the center of the sketch
  translate(width/2, height/2);
  // and then start drawing eight 'teeth'
  for (int i=0; i<8; i++) {
    beginShape();
    // we know where p1, p2, and p3 are.
    vertex(p1.x, p1.y);
    // and we "guessed" at c1, c2, c3, and c4.
    bezierVertex(c1.x, c1.y, c2.y, c2.y, p2.x, p2.y);
    bezierVertex(c3.x, c3.y, c4.y, c4.y, p3.x, p3.y);
    // We leave the shape "open" in case you want both stroke and fill
    endShape();
    // we're drawing eight teeth, so we need to rotate by 2*PI/8 each time
    rotate(0.25 * PI);
  }
}