美好的一天,
我目前正面临着工作中的挑战,这一挑战正变得非常痛苦。
挑战:
我需要为穿孔环形板创建一个孔图案的CAD图,该板将被激光切割。这些孔需要尽可能接近等距,以便均匀地分配气流。孔的总面积需要等于总环形面积的40%。根据我的计算,我需要10,190个6.35mm的孔来完成这个......
解决方案:
编写一个小程序来计算点集的XY坐标,我可以将其导入到我的CAD软件中。
问题:
为此,我想使用 Fermat's Spiral 方法计算点坐标。作为起点,我使用了来自 Marmakoide's Blog 的信息。到目前为止,我已经均匀地完成了点分布并且看起来大致等距间隔。我的问题是我需要以某种方式指定环的内半径和外半径,其中N点的点集必须下降。请注意,我不是在数学上倾向于所有,所以请尽量保持答案清晰。
这是我的代码:
procedure TForm1.btnCalcClick(Sender: TObject);
var golden_angle, radI, radO, rad, theta, x, y : Double;
i, k, holeQTY, index : integer;
xCoords, yCoords : Array of Double;
begin
holeQTY := StrToInt(edtNumHoles.Text);
golden_angle := Pi * (3 - Sqrt(5));
radI := StrToFloat(edtRadInner.Text);
radO := StrToFloat(edtRadOuter.Text);
SetLength(xCoords, holeQTY);
SetLength(yCoords, holeQTY);
for i := 0 to holeQTY - 1 do
begin
theta := i * golden_angle;
rad := Sqrt(i) / Sqrt(holeQTY);
x := rad * Cos(theta);
y := rad * Sin(theta);
xCoords[i] := x;
yCoords[i] := y;
StatusBar1.Panels[1].Text := IntToStr(i+1) + ' of ' + IntToStr(holeQTY);
StatusBar1.Update;
Application.ProcessMessages;
end;
for k := 0 to holeQTY - 1 do
begin
Chart1.Series[0].AddXY(xCoords[k], yCoords[k], '', clBlack);
end;
end;
提前致谢,
马丁
答案 0 :(得分:1)
修改:将规范化考虑在内
Spreading points
页面中的方法用于填充单元圈。
你必须添加乘法系数A
rad := A * Sqrt(i) / Sqrt(N);
索引为N的最后一个洞应该在radO:
之内A * Sqrt(N) / Sqrt(N) < radO - HoleRadius
so
A = radO - HoleRadius;
现在是第一洞:
A * Sqrt(N - holeQTY + 1) / Sqrt(N) > (radI + HoleRadius)
N - holeQTY + 1 > N * Sqr((radI + HoleRadius) / A)
N * (1 - Sqr((radI + HoleRadius) / A)) > holeQTY - 1
N = Ceil((holeQTY - 1) / (1 - Sqr((radI + HoleRadius) / A))
结果:
您必须使用系数A绘制索引holeQTY
的{{1}}个点。示例代码:
(N - holeQTY + 1)..N
(MinGap介绍前的图片)
带双值的代码
var
A, golden_angle, radI, radO, rad, theta, MinGap: Double;
N, x, y, i, holeQTY, holeRadius: Integer;
begin
holeQTY := 120;
radI := 50;
radO := 200;
holeRadius := 4;
MinGap := 3;
golden_angle := Pi * (3 - Sqrt(5));
A := Floor(radO - (holeRadius + MinGap));
N := Ceil((holeQTY - 1) / (1 - Sqr((radI + holeRadius + MinGap) / A)));
Canvas.Ellipse(300 - 200, 300 - 200, 300 + 201, 300 + 201);
Canvas.Ellipse(300 - 50, 300 - 50, 300 + 51, 300 + 51);
for i := (N - holeQTY + 1) to N do begin
theta := i * golden_angle;
rad := A * Sqrt(i) / Sqrt(N);
x := 300 + Round(rad * Cos(theta));
y := 300 + Round(rad * Sin(theta));
Canvas.Ellipse(x - holeRadius, y - holeRadius, x + holeRadius + 1, y + holeRadius + 1);
end;
产生输出
holeQTY := 17;
radI := 0.1234;
radO := 0.23456;
holeRadius := 0.00635;
MinGap := 0.0000635;
golden_angle := Pi * (3 - Sqrt(5));
A := radO - (holeRadius + MinGap);
N := Ceil((holeQTY - 1) / (1 - Sqr((radI + holeRadius + MinGap) / A)));
for i := (N - holeQTY + 1) to N do begin
theta := i * golden_angle;
rad := A * Sqrt(i) / Sqrt(N);
x := rad * Cos(theta);
y := rad * Sin(theta);
Memo1.Lines.Add(Format('r:%5.4f x:%f y:%f', [rad, x, y]));
end;
最后可能的功能与GUI分离
r:0.1317 x:0.12 y:0.05
r:0.1397 x:-0.13 y:0.05
r:0.1473 x:0.06 y:-0.13
r:0.1545 x:0.05 y:0.15
r:0.1613 x:-0.14 y:-0.08
r:0.1679 x:0.16 y:-0.04
r:0.1742 x:-0.10 y:0.14
r:0.1804 x:-0.02 y:-0.18
r:0.1863 x:0.14 y:0.12
r:0.1920 x:-0.19 y:0.01
r:0.1976 x:0.14 y:-0.14
r:0.2030 x:-0.01 y:0.20
r:0.2083 x:-0.13 y:-0.16
r:0.2134 x:0.21 y:0.03
r:0.2184 x:-0.18 y:0.12
r:0.2233 x:0.05 y:-0.22
r:0.2281 x:0.11 y:0.20
及其用法
type
TPointDouble = record
X, Y: Double;
end;
function CalcRingPoints(const
InnerRadius,
OuterRadius,
HoleRadius,
CoverageRatio //range 0..1
: Double)
: TArray<TPointDouble>;
//doesn't check input validity and possible hole overlaps!
var
ACoeff, golden_angle, rad, theta, MinGap, Area: Double;
N, i, j, holeQTY: Integer;
begin
holeQTY := Round(CoverageRatio * (Sqr(OuterRadius) - Sqr(InnerRadius)) /
Sqr(HoleRadius));
MinGap := 0.1 * HoleRadius;
golden_angle := Pi * (3 - Sqrt(5));
ACoeff := OuterRadius - (HoleRadius + MinGap);
N := Ceil((holeQTY - 1) / (1 - Sqr((InnerRadius + HoleRadius + MinGap) /
ACoeff)));
SetLength(Result, holeQTY);
for i := (N - holeQTY + 1) to N do begin
theta := i * golden_angle;
rad := ACoeff * Sqrt(i / N);
j := i - (N - holeQTY + 1);
Result[j].X := rad * Cos(theta);
Result[j].Y := rad * Sin(theta);
end;
end;
答案 1 :(得分:0)
让我们看看。
固体磁盘的公式很明显,对吧?
r[max] = r_coeff * sqrt(max)
给了我们r_coeff = r[max]/sqrt[max]
;
您的问题似乎是关于当我们的飞机不是固体磁盘时要做什么,而是从较大的磁盘减去较小的磁盘。
嗯,懒惰的方法是纠正漏洞的数量。由于圆盘的平方与半径的平方成正比,并且由于我们希望我们的孔大部分分散,我们可以希望因为我们有足够多的孔,所以孔的份额(百分比)与圆盘方块成正比,对吧?
所以我们有
N = 10 190 = N_outer_disk - N_inner_disk
N_outer_disk / N_inner_disk ≈ S_outer / S_inner = (R_outer / R_inner)^2
N_inner_disk / N_outer_disk ≈ S_inner / S_outer = (R_inner / R_outer)^2
我们必须运行循环I := N_inner_disk + 1 to N_outer_disk
计算
r[I] = r_coeff * SqRt(I)
angle[I] = I * 137.508 * degrees-to-radians-coefficient
或许我们最好从N_inner_disk - 10% to N_outer_disk + 10%
运行循环,只过滤(hole_radius + 10%) + r_hole[I] < R_outer
和r_hole[I] > R_inner + (hole_radius + 10%)
的所有超大输出 - 因为我们的计算是近似的,我们无论如何都必须使用过滤,然后我们就可以从初学者那里使用它。
我相信你还需要增加一个变量 - 孔边缘和内/外圆边缘之间的最小间隙,这样就不会让洞穴变得干净了#34;在边缘部分地离开平台。
回到我们的N-S ......
N = 10 190 ≈ N_outer_disk - N_outer_disk*(R_inner / R_outer)^2 = N_outer_disk * (1 - (R_inner / R_outer)^2)
和
N = 10 190 ≈ N_inner_disk*(R_outer / R_inner)^2 - N_inner_disk = N_inner_disk * ((R_outer / R_inner)^2 - 1)
因此对于给定的N,R_outer,R_inner
的值N_inner_disk ≈ N / ((R_outer / R_inner)^2 - 1)
N_outer_disk ≈ N / (1 - (R_inner / R_outer)^2)
现在运行从N_inner+1
到N_outer
的循环,检查通过上述几何过滤器的孔的总量及其累积的平方,如果需要,稍微调整系数以稍微好一些{ {1}}和N_inner
,直到你能够达到足够适合你的分配。
因此N_outer
会变成r_coeff = r[max]/sqrt[max]
检查用这两种方法计算的系数是否彼此非常接近将是另一项检查,即两个N-s本身的计算在内部是一致的。