こちらの続きです。
3D曲線のパイプの中心線を求める3 - C#ATIA
マニアの為の解説です。
# surface evaluator取得
surfEva: adsk.core.SurfaceEvaluator = face.evaluator
"Surface Evaluatorって何" と聞かれても答えにくいのですが・・・。
https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-GUID-31dad9b2-ee1d-4216-8100-09ea44f9967a
サーフェスの詳細な情報を取得する際に利用します。
今回は曲率や法線等が必要なのですが、実際に選択した面のBRepFace
オブジェクトでは取得出来ない為、こちらを利用します。
# 面上の点からパラメータ取得 refPrm: adsk.core.Point2D = None _, refPrm = surfEva.getParameterAtPoint( face.pointOnFace )
"face.pointOnFace" は、何処かは分かりませんがサーフェス上に
ある事が保証された点です。
大体重心付近になりますが、何処になるかは分かりません。
"getParameterAtPoint" メソッドは3Dの点がサーフェス上のどの位置
に存在するかをパラメータとして取得します。
Fusion 360 Help
パラメータ・・・便利過ぎる言葉で悩んでしまいますよね。
僕たちはGPS等を利用する事で、今どの位置に居るかを確認する事が出来ます。
緯度・経度による位置ですよね。
一方、僕たちは間違いなく三次元の世界を生きています。(もっと多くの次元の
世界かも知れないと言う説もありますが・・・)
つまり、三次元の位置情報(XYZ)を、高さを無視し地球の表面上の二次元の
位置情報(緯度・経度)として変換している事になります。
この部分のパラメータと言うのはサーフェス上の緯度・経度(正しくはUとV)
を表しており、Fusion360APIではPoint2DオブジェクトのXとYを利用して
表現しています。
パラメータは "どうしても必要" と言うわけでは無いのですが、後に利用する
メソッドで利用する機会が有る為、取得しています。
# アイソメトリック曲線のV方向取得 isoCrvLst = surfEva.getIsoCurve(refPrm.y, False) isoCrv: adsk.core.NurbsCurve3D = isoCrvLst[0]
"getIsoCurve" メソッドでアイソメトリック曲線を取得します。
Fusion 360 Help
アイソメトリック曲線は先程の緯度・経度の線のようなものです。
"アイソカーブ解析" コマンドで表示させると見ることが出来ます。
赤矢印がUで、青矢印がVの方向です。
"Fusion360の場合、必ず径方向がUなのか?" と言う疑問は残るのですが、
幾つか試した所そのようになっていました。
今回はアイソメトリックV曲線を取得しています。
# アイソメトリックV曲線 evaluator取得
crvEva: adsk.core.CurveEvaluator3D = isoCrv.evaluator
続いて曲線のEvaluatorを取得します。
Fusion 360 Help
# 曲線のパラメータ範囲取得
_, sPrm, ePrm = crvEva.getParameterExtents()
曲線の始点と終点のパラメータを取得します。
Fusion 360 Help
曲線のパラメータはfloatです。
# トレランス以内で曲線上の点群を取得 _, points = crvEva.getStrokes(sPrm, ePrm, 0.01)
"getStrokes" メソッドで、曲線上にトレランス以内で大量の点を作成します。
Fusion 360 Help
この部分での処理はこの様なイメージを想定しています。
赤色曲線に対し、始点終点を結ぶ黄色直線を作成します。
この時の最大距離がトレランス以上の距離だった場合はNGです。
その為、中間地点に点を作成し、始点-中間、中間-終点
の2本の直線を作成し、同様に最大距離がトレランス以内に
収まっているかどうかを評価し点を作って行きます。
これらで得られた点(始点・終点を含む)を取得しています。
最終的なゴールでは曲線を作るのですが、こちらのトレランスは
折れ線化した際のトレランスとなる為、意図的に甘いトレランスに
しています。
(トレランスを厳しくすると点の数が多くなる = 処理遅くなる)
# 点群の面上のパラメータ群を取得
_, prms = surfEva.getParametersAtPoints(points)
先程取得した曲線上の点群から、サーフェス上のパラメータ群を
取得します。
Fusion 360 Help
リストでまとめて処理出来るので便利です。
引数と戻り値のお互いのインデックスは一致しています。
# パラメータ群の曲率を取得 _, _, crvTures, _ = surfEva.getCurvatures(prms) # パラメータ群の法線ベクトルを取得 これは単位ベクトル _, normals = surfEva.getNormalsAtParameters(prms) # 曲率からRサイズを取得 Rサイズは曲率の逆数 radius = [1/c for c in crvTures] # 法線ベクトルをRサイズ分考慮する 中心方向・サイズのベクトル [n.scaleBy(r) for n, r in zip(normals, radius)]
"getCurvatures" メソッドはパラメータから曲率を取得しています。
Fusion 360 Help
2方向の曲率が得られるのですが、今回は最大側(U方向)です。
Rサイズ(曲率半径)は曲率の逆数です。
曲率と曲率半径 [物理のかぎしっぽ]
数式は吹っ飛ばして構わないです。まぁそういうものだと思っておけば・・・。
"getNormalsAtParameters" メソッドでは法線ベクトルを取得しています。
Fusion 360 Help
こちらは単位ベクトルとなっていました。
サーフェスの表裏の関係もありますが、Fusion360の場合は中心方向でした。
最後は、これらを組み合わせて中心に向かってのベクトルを取得します。
断面で描くとこんな感じです。
ベクトルのサイズをRサイズにしてあげれば、中心点が求まります。
# 面上の点群を中心方向に移動 この時点で点群は中心を示す [p.translateBy(v) for p, v in zip(points, normals)]
曲線上の点群を、先程求めたベクトルを利用して移動させます。
Fusion 360 Help
これで中心点の点群が求まりました。
# Point3Dの座標値をリスト化 p: adsk.core.Point3D = None aryList = [p.asArray() for p in points] # 点群を通過するNurbs曲線を取得 crv: 'curve' = fitting.interpolate_curve(aryList, 3)
この部分は、外部モジュールの "NURBS-Python(geomdl)" を利用しています。
Curve and Surface Fitting — NURBS-Python 5.3.1 documentation
"interpolate_curve" メソッドが通過点でBSplineを作成してくれました。
Fusion360のPoint3DではNGで(X,Y,Z)のリスト等のリストを取得しています。
# NURBS-PythonのコントロールポイントをPoint3D化 pnt3D: adsk.core.Point3D = adsk.core.Point3D controlPoints = [pnt3D.create(c[0], c[1], c[2]) for c in crv.ctrlpts] # 他の要素はそのまま流用可 degree = crv.degree knots = crv.knotvector isPeriodic = crv.rational
"NURBS-Python" で得たBSplineから必要な情報を取得しています。
先程と逆に、コントロールポイントはリストからPoint3Dに変換しています。
# Fusion360用のNurbs曲線作成
nurbs: adsk.core.NurbsCurve3D = adsk.core.NurbsCurve3D.createNonRational(
controlPoints,
degree,
knots,
isPeriodic
)
ここで目的の中心線となるスプラインを作り出し、無事終了です。
Fusion 360 Help
非常に手間なのは確かなのですが、Fusion360のAPIは結構低レベルな
処理を提供してくれている為、何でも自動的に行ってしまうソフトより
込み入った処理が可能なんですよ。