FreeCADで翼型を読み込んで3次元翼を作成するPythonスクリプト(マクロ)を作成した
FreeCADのバージョンは0.19
概要
最終的にはこんな感じのものを作成する
↓FreeCADの公式ドキュメントはこちら
インストールとチュートリアル
↓参考サイトと公式サイト
使い方は下のサイトの「形状作成チュートリアル」を一通りやれば完全に理解できる
使用するデータの形式
FreeCADにはデフォルトで2次元翼型読み込みの機能が入っている
FreeCAD can import airfoil data such as that found on the UIUC Airfoil Coordinates Database or files produced by airfoil creation and annalizing software like XFLR5.
https://wiki.freecadweb.org/Common_Airfoil_Data_Import
公式が2次元翼型の読み込みにXFLR5の形式を採用しているので,この記事でも3次元翼型の読み込みにXFLR5の形式を使うことにする
↓XFLR5についてはこちら
SamplePlane
今回の記事で使うのはXFLR5で適当に作ったこの機体
これをXFLR5で出力すると次のような.xwimpファイルができる
Main Wing
0 1.5 -0.473 0.128 7.499 10 1 1 0 NACA4412 NACA4412
0.2 1.5 -0.473 0.384 7.498 10 1 1 0 NACA4412 NACA4412
0.4 1.5 -0.473 0.644 7.496 10 1 1 0 NACA4412 NACA4412
0.6 1.5 -0.473 0.908 7.495 10 1 1 0 NACA4412 NACA4412
0.8 1.5 -0.473 1.173 7.494 10 1 1 0 NACA4412 NACA4412
1 1.5 -0.473 1.433 7.492 10 1 1 0 NACA4412 NACA4412
1.2 1.5 -0.473 1.684 7.491 10 1 1 0 NACA4412 NACA4412
1.4 1.5 -0.473 1.923 7.489 10 1 1 0 NACA4412 NACA4412
1.6 1.5 -0.473 2.15 7.488 10 1 1 0 NACA4412 NACA4412
1.8 1.5 -0.473 2.366 7.487 10 1 1 0 NACA4412 NACA4412
1.999 1.5 -0.473 2.572 7.485 10 1 1 0 NACA4412 NACA4412
2.199 1.5 -0.473 2.731 7.484 10 1 1 0 NACA4412 NACA4412
2.399 1.5 -0.473 2.832 7.484 10 1 1 0 NACA4412 NACA4412
2.599 1.5 -0.473 2.934 7.483 10 1 1 0 NACA4412 NACA4412
2.798 1.5 -0.473 3.105 7.481 10 1 1 0 NACA4412 NACA4412
2.998 1.5 -0.473 3.324 7.478 10 1 1 0 NACA4412 NACA4412
3.198 1.5 -0.473 3.541 7.476 10 1 1 0 NACA4412 NACA4412
3.397 1.5 -0.473 3.755 7.473 10 1 1 0 NACA4412 NACA4412
3.597 1.5 -0.473 3.965 7.47 10 1 1 0 NACA4412 NACA4412
3.796 1.5 -0.473 4.172 7.467 10 1 1 0 NACA4412 NACA4412
3.996 1.5 -0.473 4.376 7.464 10 1 1 0 NACA4412 NACA4412
4.195 1.5 -0.473 4.576 7.461 10 1 1 0 NACA4412 NACA4412
4.395 1.5 -0.473 4.772 7.458 10 1 1 0 NACA4412 NACA4412
4.594 1.5 -0.473 4.964 7.455 10 1 1 0 NACA4412 NACA4412
4.793 1.5 -0.473 5.152 7.451 10 1 1 0 NACA4412 NACA4412
4.992 1.5 -0.473 5.335 7.448 10 1 1 0 NACA4412 NACA4412
5.192 1.5 -0.473 5.514 7.445 10 1 1 0 NACA4412 NACA4412
5.391 1.5 -0.473 5.688 7.441 10 1 1 0 NACA4412 NACA4412
5.59 1.5 -0.473 5.858 7.438 10 1 1 0 NACA4412 NACA4412
5.789 1.5 -0.473 6.022 7.434 10 1 1 0 NACA4412 NACA4412
5.988 1.5 -0.473 6.182 7.431 10 1 1 0 NACA4412 NACA4412
6.186 1.5 -0.473 6.337 7.427 10 1 1 0 NACA4412 NACA4412
6.385 1.5 -0.473 6.487 7.424 10 1 1 0 NACA4412 NACA4412
6.584 1.481 -0.467 6.631 7.421 10 1 1 0 NACA4412 NACA4412
6.783 1.463 -0.461 6.771 7.418 10 1 1 0 NACA4412 NACA4412
6.981 1.444 -0.455 6.906 7.415 10 1 1 0 NACA4412 NACA4412
7.18 1.425 -0.449 7.036 7.412 10 1 1 0 NACA4412 NACA4412
7.378 1.406 -0.443 7.143 7.41 10 1 1 0 NACA4412 NACA4412
7.577 1.388 -0.437 7.217 7.408 10 1 1 0 NACA4412 NACA4412
7.775 1.369 -0.431 7.293 7.407 10 1 1 0 NACA4412 NACA4412
7.973 1.35 -0.425 7.425 7.405 10 1 1 0 NACA4412 NACA4412
8.172 1.331 -0.419 7.601 7.402 10 1 1 0 NACA4412 NACA4412
8.37 1.313 -0.413 7.775 7.399 10 1 1 0 NACA4412 NACA4412
8.568 1.294 -0.408 7.951 7.396 10 1 1 0 NACA4412 NACA4412
8.766 1.275 -0.402 8.131 7.393 10 1 1 0 NACA4412 NACA4412
8.964 1.256 -0.396 8.319 7.389 10 1 1 0 NACA4412 NACA4412
9.162 1.238 -0.39 8.52 7.384 10 1 1 0 NACA4412 NACA4412
9.36 1.219 -0.384 8.739 7.38 10 1 1 0 NACA4412 NACA4412
9.558 1.2 -0.378 8.984 7.374 10 1 1 0 NACA4412 NACA4412
9.755 1.181 -0.372 9.263 7.368 10 1 1 0 NACA4412 NACA4412
9.953 1.163 -0.366 9.588 7.361 10 1 1 0 NACA4412 NACA4412
10.15 1.144 -0.36 9.948 7.352 10 1 1 0 NACA4412 NACA4412
10.347 1.125 -0.354 10.305 7.342 10 1 1 0 NACA4412 NACA4412
10.544 1.106 -0.348 10.633 7.331 10 1 1 0 NACA4412 NACA4412
10.74 1.088 -0.343 10.933 7.318 10 1 1 0 NACA4412 NACA4412
10.936 1.069 -0.337 11.202 7.302 10 1 1 0 NACA4412 NACA4412
11.133 1.05 -0.331 11.438 7.284 10 1 1 0 NACA4412 NACA4412
11.329 1.031 -0.325 11.64 7.264 10 1 1 0 NACA4412 NACA4412
11.525 1.013 -0.319 11.807 7.241 10 1 1 0 NACA4412 NACA4412
11.72 0.994 -0.313 11.907 7.222 10 1 1 0 NACA4412 NACA4412
11.916 0.975 -0.307 11.944 7.212 10 1 1 0 NACA4412 NACA4412
12.112 0.956 -0.301 11.968 7.2 10 1 1 0 NACA4412 NACA4412
12.307 0.938 -0.295 12.016 7.165 10 1 1 0 NACA4412 NACA4412
12.503 0.919 -0.289 12.06 7.123 10 1 1 0 NACA4412 NACA4412
12.699 0.9 -0.284 6.14 7.301 10 1 1 0 NACA4412 NACA4412
12.897 0.6 -0.189 6.14 7.301 10 1 1 0 NACA4412 NACA4412
Elevator
0 1 -0.283 0 0 10 1 1 0 NACA0012 NACA0012
0.2 1 -0.283 0 0 10 1 1 0 NACA0012 NACA0012
0.4 1 -0.283 0 0 10 1 1 0 NACA0012 NACA0012
0.6 1 -0.283 0 0 10 1 1 0 NACA0012 NACA0012
0.8 1 -0.283 0 0 10 1 1 0 NACA0012 NACA0012
1 1 -0.283 0 0 10 1 1 0 NACA0012 NACA0012
1.2 1 -0.283 0 0 10 1 1 0 NACA0012 NACA0012
1.4 1 -0.283 0 0 10 1 1 0 NACA0012 NACA0012
1.6 1 -0.283 0 0 10 1 1 0 NACA0012 NACA0012
1.8 1 -0.283 0 0 10 1 1 0 NACA0012 NACA0012
2 1 -0.283 0 0 10 1 1 0 NACA0012 NACA0012
Fin
0 0.6 -0.15 0 0 10 1 1 0 NACA0009 NACA0009
0.2 0.75 -0.188 0 0 10 1 1 0 NACA0009 NACA0009
0.4 0.9 -0.225 0 0 10 1 1 0 NACA0009 NACA0009
0.6 0.85 -0.213 0 0 10 1 1 0 NACA0009 NACA0009
0.8 0.8 -0.2 0 0 10 1 1 0 NACA0009 NACA0009
1 0.75 -0.188 0 0 10 1 1 0 NACA0009 NACA0009
1.2 0.7 -0.175 0 0 10 1 1 0 NACA0009 NACA0009
1.4 0.65 -0.163 0 0 10 1 1 0 NACA0009 NACA0009
1.6 0.6 -0.15 0 0 10 1 1 0 NACA0009 NACA0009
データの出力は以下の手順で行う
①「Wing and Plane Design」の「Plane>Current Plane>Edit」をクリック
②ウィンドウが開くので,それぞれの翼で「Define」をクリック
③「Other>Export Wing (depricated, use XML)」をクリック
④好きな名前で保存
以上
各断面ごとに11個のデータで構成されている
各データは左から順に以下の通り
名称 | 単位 |
翼断面の位置(y座標) | m |
コード長 | m |
前縁のx座標(機体後方を正) | m |
上反角 | deg |
取り付け角(頭上げを正) | deg |
パネル分割数(コード方向) | - |
パネル分割数(スパン方向) | - |
パネル分割手法(コード方向) | - |
パネル分割手法(スパン方向) | - |
翼型(パネルの翼根側) | - |
翼型(パネルの翼端側) | - |
今回のプログラムではパネル分割数/分割手法は使わないので気にしなくていい
翼型も1種類しか使わないので深く考える必要はない(考えたくない)
2次元翼のデータはこんな感じ
NACA4412
1.0000000 0.0012600
0.9928006 0.0032198
0.9798895 0.0066835
0.9635184 0.0109823
0.9445469 0.0158354
0.9234998 0.0210604
0.9007495 0.0265227
0.8765830 0.0321168
0.8512328 0.0377572
0.8248944 0.0433730
0.7977362 0.0489045
0.7699063 0.0543008
0.7415373 0.0595184
0.7127487 0.0645195
0.6836500 0.0692712
0.6543419 0.0737448
0.6249182 0.0779148
0.5954661 0.0817592
0.5660677 0.0852584
0.5368005 0.0883955
0.5077378 0.0911557
0.4789491 0.0935267
0.4505011 0.0954983
0.4224571 0.0970626
0.3948782 0.0982103
0.3678229 0.0988053
0.3413476 0.0987893
0.3155065 0.0981781
0.2903524 0.0969911
0.2659361 0.0952510
0.2423068 0.0929845
0.2195125 0.0902210
0.1975998 0.0869933
0.1766138 0.0833369
0.1565988 0.0792897
0.1375977 0.0748918
0.1196525 0.0701852
0.1028043 0.0652129
0.0870931 0.0600189
0.0725582 0.0546478
0.0592379 0.0491435
0.0471700 0.0435495
0.0398384 0.0397909
0.0363913 0.0379076
0.0330915 0.0360235
0.0299394 0.0341394
0.0269381 0.0322577
0.0240880 0.0303793
0.0213896 0.0285049
0.0188458 0.0266369
0.0164571 0.0247759
0.0142241 0.0229225
0.0121494 0.0210790
0.0102336 0.0192459
0.0084774 0.0174236
0.0068832 0.0156139
0.0054516 0.0138171
0.0041835 0.0120339
0.0030809 0.0102667
0.0021446 0.0085156
0.0013756 0.0067792
0.0007756 0.0050573
0.0003455 0.0033493
0.0000866 0.0016607
0.0000000 0.0000000
0.0000866 -0.0016261
0.0003455 -0.0032112
0.0007756 -0.0047474
0.0013756 -0.0062299
0.0021446 -0.0076600
0.0030809 -0.0090391
0.0041835 -0.0103693
0.0054516 -0.0116513
0.0068832 -0.0128843
0.0084774 -0.0140686
0.0102336 -0.0152049
0.0121494 -0.0162931
0.0142241 -0.0173340
0.0164571 -0.0183285
0.0188458 -0.0192762
0.0213896 -0.0201778
0.0240880 -0.0210342
0.0269381 -0.0218453
0.0299394 -0.0226118
0.0330915 -0.0233344
0.0363913 -0.0240133
0.0398384 -0.0246491
0.0471700 -0.0257940
0.0592379 -0.0272029
0.0725582 -0.0282569
0.0870931 -0.0289743
0.1028043 -0.0293755
0.1196525 -0.0294825
0.1375977 -0.0293193
0.1565988 -0.0289118
0.1766138 -0.0282876
0.1975998 -0.0274762
0.2195125 -0.0265089
0.2423068 -0.0254180
0.2659361 -0.0242376
0.2903524 -0.0230023
0.3155065 -0.0217477
0.3413476 -0.0205094
0.3678229 -0.0193230
0.3948782 -0.0182234
0.4224571 -0.0171746
0.4505011 -0.0160650
0.4789491 -0.0149118
0.5077378 -0.0137351
0.5368005 -0.0125542
0.5660677 -0.0113870
0.5954661 -0.0102497
0.6249182 -0.0091567
0.6543419 -0.0081203
0.6836500 -0.0071506
0.7127487 -0.0062555
0.7415373 -0.0054401
0.7699063 -0.0047076
0.7977362 -0.0040587
0.8248944 -0.0034919
0.8512328 -0.0030041
0.8765830 -0.0025904
0.9007495 -0.0022449
0.9234998 -0.0019608
0.9445469 -0.0017313
0.9635184 -0.0015496
0.9798895 -0.0014106
0.9928006 -0.0013115
1.0000000 -0.0012600
NACA0012
1.0000000 0.0012600
0.9928006 0.0022657
0.9798895 0.0040471
0.9635184 0.0062660
0.9445469 0.0087833
0.9234998 0.0115106
0.9007495 0.0143838
0.8765830 0.0173536
0.8512328 0.0203807
0.8248944 0.0234325
0.7977362 0.0264816
0.7699063 0.0295042
0.7415373 0.0324793
0.7127487 0.0353875
0.6836500 0.0382109
0.6543419 0.0409325
0.6249182 0.0435357
0.5954661 0.0460044
0.5660677 0.0483227
0.5368005 0.0504749
0.5077378 0.0524454
0.4789491 0.0542192
0.4505011 0.0557817
0.4224571 0.0571186
0.3948782 0.0582169
0.3678229 0.0590641
0.3413476 0.0596494
0.3155065 0.0599629
0.2903524 0.0599967
0.2659361 0.0597443
0.2423068 0.0592012
0.2195125 0.0583649
0.1975998 0.0572348
0.1766138 0.0558122
0.1565988 0.0541007
0.1375977 0.0521056
0.1196525 0.0498338
0.1028043 0.0472942
0.0870931 0.0444966
0.0725582 0.0414523
0.0592379 0.0381732
0.0471700 0.0346718
0.0363913 0.0309604
0.0299394 0.0283756
0.0269381 0.0270515
0.0240880 0.0257068
0.0213896 0.0243414
0.0188458 0.0229565
0.0164571 0.0215522
0.0142241 0.0201283
0.0121494 0.0186860
0.0102336 0.0172254
0.0084774 0.0157461
0.0068832 0.0142491
0.0054516 0.0127342
0.0041835 0.0112016
0.0030809 0.0096529
0.0021446 0.0080878
0.0013756 0.0065046
0.0007756 0.0049023
0.0003455 0.0032802
0.0000866 0.0016434
0.0000000 0.0000000
0.0000866 -0.0016434
0.0003455 -0.0032802
0.0007756 -0.0049023
0.0013756 -0.0065046
0.0021446 -0.0080878
0.0030809 -0.0096529
0.0041835 -0.0112016
0.0054516 -0.0127342
0.0068832 -0.0142491
0.0084774 -0.0157461
0.0102336 -0.0172254
0.0121494 -0.0186860
0.0142241 -0.0201283
0.0164571 -0.0215522
0.0188458 -0.0229565
0.0213896 -0.0243414
0.0240880 -0.0257068
0.0269381 -0.0270515
0.0299394 -0.0283756
0.0363913 -0.0309604
0.0471700 -0.0346718
0.0592379 -0.0381732
0.0725582 -0.0414523
0.0870931 -0.0444966
0.1028043 -0.0472942
0.1196525 -0.0498338
0.1375977 -0.0521056
0.1565988 -0.0541007
0.1766138 -0.0558122
0.1975998 -0.0572348
0.2195125 -0.0583649
0.2423068 -0.0592012
0.2659361 -0.0597443
0.2903524 -0.0599967
0.3155065 -0.0599629
0.3413476 -0.0596494
0.3678229 -0.0590641
0.3948782 -0.0582169
0.4224571 -0.0571186
0.4505011 -0.0557817
0.4789491 -0.0542192
0.5077378 -0.0524454
0.5368005 -0.0504749
0.5660677 -0.0483227
0.5954661 -0.0460044
0.6249182 -0.0435357
0.6543419 -0.0409325
0.6836500 -0.0382109
0.7127487 -0.0353875
0.7415373 -0.0324793
0.7699063 -0.0295042
0.7977362 -0.0264816
0.8248944 -0.0234325
0.8512328 -0.0203807
0.8765830 -0.0173536
0.9007495 -0.0143838
0.9234998 -0.0115106
0.9445469 -0.0087833
0.9635184 -0.0062660
0.9798895 -0.0040471
0.9928006 -0.0022657
1.0000000 -0.0012600
NACA0009
1.0000000 0.0009450
0.9901282 0.0019773
0.9701682 0.0040276
0.9469539 0.0063503
0.9229830 0.0086826
0.8988830 0.0109621
0.8747544 0.0131812
0.8506129 0.0153402
0.8264621 0.0174401
0.8023039 0.0194817
0.7781400 0.0214655
0.7539718 0.0233914
0.7298010 0.0252589
0.7056291 0.0270669
0.6814577 0.0288141
0.6572885 0.0304984
0.6331231 0.0321174
0.6089632 0.0336680
0.5848106 0.0351466
0.5606672 0.0365489
0.5365351 0.0378702
0.5124163 0.0391050
0.4883132 0.0402470
0.4642285 0.0412893
0.4401651 0.0422242
0.4161262 0.0430429
0.3921157 0.0437356
0.3681380 0.0442917
0.3441984 0.0446990
0.3203032 0.0449439
0.2964603 0.0450110
0.2726795 0.0448829
0.2489733 0.0445397
0.2253582 0.0439580
0.2018562 0.0431109
0.1784983 0.0419661
0.1553293 0.0404845
0.1324180 0.0386185
0.1098794 0.0363101
0.0879308 0.0334933
0.0670466 0.0301197
0.0482645 0.0262609
0.0330984 0.0222613
0.0253681 0.0197423
0.0221517 0.0185528
0.0193096 0.0174133
0.0167968 0.0163198
0.0145701 0.0152677
0.0125870 0.0142513
0.0108176 0.0132648
0.0092361 0.0123031
0.0078178 0.0113606
0.0065463 0.0104322
0.0054085 0.0095141
0.0043917 0.0086017
0.0034888 0.0076918
0.0026950 0.0067823
0.0020056 0.0058707
0.0014197 0.0049561
0.0009380 0.0040392
0.0005596 0.0031211
0.0002811 0.0022089
0.0000981 0.0013119
0.0000069 0.0004347
0.0000069 -0.0004347
0.0000981 -0.0013119
0.0002811 -0.0022089
0.0005596 -0.0031211
0.0009380 -0.0040392
0.0014197 -0.0049561
0.0020056 -0.0058707
0.0026950 -0.0067823
0.0034888 -0.0076918
0.0043917 -0.0086017
0.0054085 -0.0095141
0.0065463 -0.0104322
0.0078178 -0.0113606
0.0092361 -0.0123031
0.0108176 -0.0132648
0.0125870 -0.0142513
0.0145701 -0.0152677
0.0167968 -0.0163198
0.0193096 -0.0174133
0.0221517 -0.0185528
0.0253681 -0.0197423
0.0330984 -0.0222613
0.0482645 -0.0262609
0.0670466 -0.0301197
0.0879308 -0.0334933
0.1098794 -0.0363101
0.1324180 -0.0386185
0.1553293 -0.0404845
0.1784983 -0.0419661
0.2018562 -0.0431109
0.2253582 -0.0439580
0.2489733 -0.0445397
0.2726795 -0.0448829
0.2964603 -0.0450110
0.3203032 -0.0449439
0.3441984 -0.0446990
0.3681380 -0.0442917
0.3921157 -0.0437356
0.4161262 -0.0430429
0.4401651 -0.0422242
0.4642285 -0.0412893
0.4883132 -0.0402470
0.5124163 -0.0391050
0.5365351 -0.0378702
0.5606672 -0.0365489
0.5848106 -0.0351466
0.6089632 -0.0336680
0.6331231 -0.0321174
0.6572885 -0.0304984
0.6814577 -0.0288141
0.7056291 -0.0270669
0.7298010 -0.0252589
0.7539718 -0.0233914
0.7781400 -0.0214655
0.8023039 -0.0194817
0.8264621 -0.0174401
0.8506129 -0.0153402
0.8747544 -0.0131812
0.8988830 -0.0109621
0.9229830 -0.0086826
0.9469539 -0.0063503
0.9701682 -0.0040276
0.9901282 -0.0019773
1.0000000 -0.0009450
これら2つのテキストファイル(.xwimpと.dat)から冒頭に示したようなCADデータを作成する
フローチャートとソースコード全文
今回のプログラムのフローチャートはこんな感じ
ソースコードはこちら
import os
import math
import PySide2
import FreeCAD as App
import FreeCADGui as Gui
import importAirfoilDAT
import Draft
### Read .xwimp
# Open dialog box
DirPath = os.path.dirname(App.ActiveDocument.FileName)
ReadName, Filter = PySide2.QtWidgets.QFileDialog.getOpenFileName(None, "Read a file", DirPath, "All files (*.*);;")
# Open .xwimp
with open(ReadName) as f:
xwimp = f.readlines()
xwimp = xwimp[1:]
xwimp = [line.split() for line in xwimp]
### Import airfoil sections
y0 = 0
z = 0
for i, sta in enumerate(xwimp):
# Import airfoil.dat at the beginning of the loop
if i==0:
# Get the airfoil Name (FoilName.dat)
FoilName = sta[9]
# Import .dat file
importAirfoilDAT.insert(DirPath+"/"+FoilName+".dat",App.activeDocument().Name)
# Get the imported airfoil object
airfoilObject = App.ActiveDocument.getObject(FoilName).Group[0]
# Set label for the object
airfoilObject.Label = airfoilObject.Name+"_"+FoilName
# Read dimensions from .xwimp
y = float(sta[0])*1000
chord = float(sta[1])*1000
sweep = float(sta[2])*1000
dihedral = float(sta[3])
twist = float(sta[4])
# Calcurate z dimensions
z = z+math.tan(math.radians(dihedral))*(y-y0)
y0 = y
# Create clones for each aifoil sections
cloneObject = Draft.clone(airfoilObject)
# Move and Scale the cloned object
cloneObject.Scale = (chord,chord,chord)
cloneObject.Placement = App.Placement(App.Vector(sweep,z,y),App.Rotation(-twist,0,0))
### Lofting the airfoil sections
App.ActiveDocument.addObject('Part::Loft','Loft_'+FoilName)
LoftObject = App.ActiveDocument.ActiveObject
LoftObject.Sections = [obj for obj in App.ActiveDocument.Objects if FoilName+' (2D)' in obj.Label]
LoftObject.Solid = True
LoftObject.Ruled = True
LoftObject.Closed = False
### Mirror the left wing to create the right wing
Gui.runCommand('Part_Mirror',0)
App.ActiveDocument.addObject("Part::Mirroring",'Mirror_'+FoilName)
MirrorObject = App.ActiveDocument.ActiveObject
MirrorObject.Source = LoftObject
MirrorObject.Label = 'Mirror_'+FoilName
MirrorObject.Normal = (0,0,1)
MirrorObject.Base = (0,0,0)
### Run a boolean operation with the loft and the mirrored one
Gui.runCommand('Part_Boolean',0)
App.activeDocument().addObject("Part::Fuse","Fusion_"+FoilName)
FusionObject = App.ActiveDocument.getObject('Fusion_'+FoilName)
FusionObject.Base = LoftObject
FusionObject.Tool = MirrorObject
Gui.activeDocument().hide(LoftObject.Name)
Gui.activeDocument().hide(MirrorObject.Name)
FusionObject.ViewObject.ShapeColor = getattr(LoftObject.getLinkedObject(True).ViewObject,'ShapeColor',FusionObject.ViewObject.ShapeColor)
FusionObject.ViewObject.DisplayMode = getattr(LoftObject.getLinkedObject(True).ViewObject,'DisplayMode',FusionObject.ViewObject.DisplayMode)
Gui.activeDocument().getObject(FusionObject.Name).DisplayMode = "Shaded"
# Hide airfoil section objects
objectLabelList = [obj.Label for obj in App.ActiveDocument.Objects if FoilName+' (2D)' in obj.Label]
Gui.Selection.clearSelection()
for objectLabel in objectLabelList:
App.ActiveDocument.getObjectsByLabel(objectLabel)[0].Visibility = False
FusionObject.Placement = App.Placement(App.Vector(0,0,0),App.Rotation(180,0,-90))
これだけ見てもなんのこっちゃ分からないので,1つずつ解説していく
ソースコードの解説
FreeCADにおけるプログラムの作成方法
FreeCADで行うすべての操作はPythonのスクリプトに変換されて実行される
Python Consoleを開けば自分が行った操作がPythonでどのように記述されるかをリアルタイムで知ることができる
自分で何かしらのマクロを作成したい場合は
- マクロにしたい操作を自分で実行する
- Python Consoleに出てくるスクリプトをコピペする
- 上記のスクリプトをもとに汎化性を持たせたコードを作成する
といった手順をとることで,比較的簡単に欲しいマクロを作成することができる
作成したプログラムのデバッグを行う際はReport Viewを使うといい
print()
の出力やエラー文などが表示される
以上のことを踏まえて,フローチャートに沿って説明していく
モジュールのインポート
今回のプログラムでは以下のモジュールを使用する
import os
import math
import PySide2
import FreeCAD as App
import FreeCADGui as Gui
import importAirfoilDAT
import Draft
PySide2
は「ファイルを開く」ダイアログボックスを使うのに使用する
FreeCAD
とFreeCADGui
はPython Consoleに合わせてそれぞれApp
,Gui
としてインポートしている
.xwimpの読み込み
.xwimpファイルを読み込む
### Read .xwimp
# Open dialog box
DirPath = os.path.dirname(App.ActiveDocument.FileName)
ReadName, Filter = PySide2.QtWidgets.QFileDialog.getOpenFileName(None, "Read a file", DirPath, "All files (*.*);;")
# Open .xwimp
with open(ReadName) as f:
xwimp = f.readlines()
xwimp = xwimp[1:]
xwimp = [line.split() for line in xwimp]
App.ActiveDocument.FileName
で現在編集しているFreeCADのファイル名を取得し,os.path.dirname()
でFreeCADのファイルが保存されているディレクトリのPathを取得する
PySide2.QtWidgets.QFileDialog.getOpenFileName()
で,「ファイルを開く」のダイアログボックスを開くことができる
最初に開くのは上で取得したFreeCADのファイルが保存されているディレクトリである
選択したファイルはwith open()
以降で読み込まれている
.xwimpファイルはスペース区切りのテキストファイルなので,split()
を使って空白を削除してリストに変換している
参考
≫FreeCAD API - FreeCAD Documentation
≫Pythonで実行中のファイルの場所(パス)を取得する
≫QFileDialog — Qt for Python
≫Pythonでファイルの読み込み、書き込み(作成・追記)
≫Python, splitでカンマ区切り文字列を分割、空白を削除しリスト化
.datのインポート,翼断面のループ
.datファイルをインポートし,翼断面の数だけループを回して必要な断面を作成する
### Import airfoil sections
y0 = 0
z = 0
for i, sta in enumerate(xwimp):
# Import airfoil.dat at the beginning of the loop
if i==0:
# Get the airfoil Name (FoilName.dat)
FoilName = sta[9]
# Import .dat file
importAirfoilDAT.insert(DirPath+"/"+FoilName+".dat",App.activeDocument().Name)
# Get the imported airfoil object
airfoilObject = App.ActiveDocument.getObject(FoilName).Group[0]
# Set label for the object
airfoilObject.Label = airfoilObject.Name+"_"+FoilName
# Read dimensions from .xwimp
y = float(sta[0])*1000
chord = float(sta[1])*1000
sweep = float(sta[2])*1000
dihedral = math.radians(float(sta[3]))
twist = float(sta[4])
# Calcurate z dimensions
z = z+math.tan(dihedral)*(y-y0)
y0 = y
# Create clones for each aifoil sections
cloneObject = Draft.clone(airfoilObject)
# Move and Scale the cloned object
cloneObject.Scale = (chord,chord,chord)
cloneObject.Placement = App.Placement(App.Vector(sweep,z,y),App.Rotation(0,0,-twist))
FreeCADのObjectにはややこしいことにNameとLabelという2つの概念が存在する
In summary, the
https://wiki.freecadweb.org/Object_nameName
essentially acts like a unique identifier (UID) for an object. Since a uniqueName
is very restrictive, all objects also have aLabel
property which allows "renaming" the object to something more descriptive. The internalName
actually remains fixed, but the user editableLabel
can be used in most situations where theName
would be used. In common usage in the program and the documentation, "renaming" means changing theLabel
and not the actualName
of the object.
NameはObjectが生成されたとき与えられるIDのようなもので変更できない
LabelはデフォルトではNameと同じだが,ユーザーが分かりやすいように変更することができる
FreeCADのTree Viewなどから変更できる名前はLabelの方である
今回のプログラムでは,わかりやすさの観点からできる限りLabelを使用することにする
ループの初めにimportAirfoilDAT.insert()
を使って翼型の.datファイルをインポートしている
インポートされた翼型は「翼型名のGroupオブジェクト>Wireオブジェクト」という入れ子構造になっている
これから使うのはWireオブジェクトの方なので,App.ActiveDocument.getObject(FoilName).Group[0]
でGroupオブジェクトに入っているWireオブジェクトを取得している
このWireオブジェクトに対して拡大縮小・移動回転を行って各翼断面を作成する
Draft.clone()
でWireオブジェクトのCloneを作成し,Scaleで拡大縮小,Placementで移動および回転を行う
Placementにおける回転角は「Z軸回り→Y軸回り→X軸回り」の順番で指定する
Placement = [Position, Yaw-Pitch-Roll]
https://wiki.freecadweb.org/Placement
The second form of Placement fixes an object's location in space with a Position (as in the first form), but describes its orientation using Yaw, Pitch and Roll angles. ... Yaw-Pitch-Roll = (y,p,r) is a tuple that specifies the attitude of the object. Values for y,p,r specify degrees of rotation about each of the z,y,x axis (see note).
俗にいう航空機のヨー・ピッチ・ロールである
ここまで実行すると次のようになる
参考
≫FreeCAD 翼形状の作成 - XSim
≫Object name - FreeCAD Documentation
≫Tree view - FreeCAD Documentation
≫FreeCAD Scripting Basics - FreeCAD Documentation
≫Std Group - FreeCAD Documentation
≫Draft Wire - FreeCAD Documentation
≫オブジェクトのコピー、移動、回転
≫FreeCAD 3次元オブジェクトの拡大縮小 - XSim
≫Draft Clone - FreeCAD Documentation
≫Draft Scale - FreeCAD Documentation
≫Placement - FreeCAD Documentation
翼断面をロフトでつなぐ
上で作成した翼断面をロフトでつなぐ
### Lofting the airfoil sections
App.ActiveDocument.addObject('Part::Loft','Loft_'+FoilName)
LoftObject = App.ActiveDocument.ActiveObject
LoftObject.Sections = [obj for obj in App.ActiveDocument.Objects if FoilName+' (2D)' in obj.Label]
LoftObject.Solid = True
LoftObject.Ruled = True
LoftObject.Closed = False
SectionsではロフトでつなぐObjectのリストを指定する
App.ActiveDocument.Objects
でドキュメント内のすべてのObjectのリストを取得し,if
を使って上で作成したCloneオブジェクトのみを抽出している
それ以外の設定の意味は以下の通り
The Loft has three parameters, "Ruled surface","Create solid" and "Closed" each with a value of either "true" or "false".
https://wiki.freecadweb.org/Part_Loft
If "Create solid" is "true" FreeCAD creates a solid if the profiles are of closed geometry, if "false" FreeCAD creates a face or (if more than one face) a shell for either open or closed profiles.
If "Ruled surface" is "true" FreeCAD creates a face, faces or a solid from ruled surfaces. Ruled surface page on Wikipedia.
If "Closed" is "true" FreeCAD attempts to loft the last profile to the first profile to create a closed figure.
Ruled Surfaceとは線織面のことである
≫線織面とは - コトバンク
≫線織面と可展面 - 大人になってからの再学習
≫FreeCAD 線織面の作成 - XSim
意味は分からない
ここまで実行すると次のようになる
片翼分しかいらないならプログラムはここまででいい
参考
≫Pythonで文字列のリスト(配列)の条件を満たす要素を抽出、置換
≫断面形状をつないで複雑な形状を作成する(ロフト機能)
≫Part Loft - FreeCAD Documentation
LoftをMirrorで複製する
上で作成したロフトをMirrorで複製して反対側の翼を作成する
### Mirror the left wing to create the right wing
Gui.runCommand('Part_Mirror',0)
App.ActiveDocument.addObject("Part::Mirroring",'Mirror_'+FoilName)
MirrorObject = App.ActiveDocument.ActiveObject
MirrorObject.Source = LoftObject
MirrorObject.Label = 'Mirror_'+FoilName
MirrorObject.Normal = (0,0,1)
MirrorObject.Base = (0,0,0)
Sourceでミラー元のオブジェクト(上で作成したLoftオブジェクト)を指定する
NormalとBaseで「原点中心でXY平面に対するMirroring」を指定している
ここまで実行すると次のようになる
参考
≫Part Mirror - FreeCAD Documentation
LoftとMirrorを結合する
Loftで作成した左翼とMirrorで作成した右翼を結合する
### Run a boolean operation with the loft and the mirrored one
Gui.runCommand('Part_Boolean',0)
App.activeDocument().addObject("Part::Fuse","Fusion_"+FoilName)
FusionObject = App.ActiveDocument.getObject('Fusion_'+FoilName)
FusionObject.Base = LoftObject
FusionObject.Tool = MirrorObject
Gui.activeDocument().hide(LoftObject.Name)
Gui.activeDocument().hide(MirrorObject.Name)
FusionObject.ViewObject.ShapeColor = getattr(LoftObject.getLinkedObject(True).ViewObject,'ShapeColor',FusionObject.ViewObject.ShapeColor)
FusionObject.ViewObject.DisplayMode = getattr(LoftObject.getLinkedObject(True).ViewObject,'DisplayMode',FusionObject.ViewObject.DisplayMode)
Gui.activeDocument().getObject(FusionObject.Name).DisplayMode = "Shaded"
そろそろノリで理解できるのではないだろうか
DisplayMode = "Shaded"
で表示モードを変更している
ここまで実行すると次のようになる
左翼に見える翼断面の線はCloneオブジェクトである
参考
≫ソリッド間のブーリアン演算
≫Part Boolean - FreeCAD Documentation
≫Std DrawStyle - FreeCAD Documentation
不要なObjectを非表示・翼を回転させる
Loftの作成に使ったCloneオブジェクトを非表示にする
ついでに座標系を「機体前方にX軸,右翼側にY軸,機体下方にZ軸」となるように翼を回転させる
# Hide airfoil section objects
objectLabelList = [obj.Label for obj in App.ActiveDocument.Objects if FoilName+' (2D)' in obj.Label]
Gui.Selection.clearSelection()
for objectLabel in objectLabelList:
App.ActiveDocument.getObjectsByLabel(objectLabel)[0].Visibility = False
FusionObject.Placement = App.Placement(App.Vector(0,0,0),App.Rotation(180,0,-90))
これで3次元翼の読み込みは完了である
使い方
それではこのプログラムを使って実際に主翼,水平尾翼,垂直尾翼を作成してみる
ソースコードの置き場所
上で説明したソースコードを置くべきディレクトリを調べる
「Macro>Macros ...」をクリックする
「Execute macro」のウィンドウが開くので,下の「User macros location」のパスを調べる
筆者の場合は「C:/Users/XXX/AppData/Roaming/FreeCAD/Macro」だったので,ここに作成した.pyファイルを置けばいい
マクロの実行は右上の「Execute」を実行すればいい
主翼の読み込み
「Macro>macros ...」でウィンドウを開き,.pyを選択して「Execute」をクリックする
ダイアログボックスが開くので「SampleWing.xwimp」を選択して「開く」をクリックする
「Tasks>Cansel」で読み込みが完了する
水平尾翼の読み込み
主翼と同様の手順で「SampleTail.xwimp」を読み込む
Tree Viewから「Fusion_NACA0012」を選択し,Dataタブの「Base>Placement>Position」に「x=-4500mm,z=-450mm」を入力する
水平尾翼の位置がいい感じになる
垂直尾翼の読み込み
主翼・水平尾翼と同様の手順で「SampleFin.xwimp」を読み込む
垂直尾翼にMirrorは必要ないので削除する必要がある
「Fusion_NACA0009」を選択して「Delete」キーを押す
続けて「Mirror_NACA0009」を選択して「Delete」キーを押す
「Loft_NACA0009」を選択して,Dataタブの「Base>Placement」で「Angle=180°,Axis=(0,1,0)」を入力する
続けてDataタブの「Base>Placement>Position」に「x=-3500mm,z=-150mm」を入力する
最後にViewタブの「Display Options>Display Mode」のプルダウンから「Shaded」を選択する
これですべての操作は完了である
おわりに
FreeCADで3次元翼を作成するPythonスクリプトを作成した
FreeCADはオープンソースのソフトウェアなので無料で使える上に,一般的なサブスク形式のCADソフトのように突然の改悪におびえる必要もない
これからはしばらくはFreeCADをメインにして使っていこうと思う
↓関連記事
↓おすすめ記事
コメント