こちらの続きです。
凸包に挑んでみる2 - C#ATIA
2D凸包のスタートは1本の直線からなのですが、3Dは4面体からが正攻法のようです。
その為、出来る限りユニークで直線に並ばない4点が欲しいのですが、
具体的なアルゴリズムがわかりません。
色々と試した結果、こんな感じで良いものかな?と・・・
・XYZの最大・最小を持つ点を取得(最大6点)
・6点中同一の点を除外する
・4点の組み合わせを作り、4点間の合計距離が一番大きい組み合わせを取得
と考えました。 こちら
#FusionAPI_python test #Author-kantoku #Description-新たなスケッチを作成し、ランダムに3Dな点を作成し、ユニークな4点を取得 import adsk.core, adsk.fusion, traceback import random def run(context): ui = None #作成するランダムな点の数 pointcount = 100 try: #準備 app = adsk.core.Application.get() ui = app.userInterface des = app.activeProduct root = des.rootComponent #スケッチと点の作成 skt = root.sketches.add(root.xYConstructionPlane) InitRandomPoint(skt, -10.0, 10.0, pointcount) pnts = [adsk.core.Point3D.cast(p.geometry) for p in skt.sketchPoints] uniq_pnts = GetUnique4Points(pnts) dumpPoints(uniq_pnts) except: if ui: ui.messageBox('エラー:\n{}'.format(traceback.format_exc())) #ユニークな4点取得 def GetUnique4Points(pnts): lst = [ min(pnts,key=lambda p:p.x), max(pnts,key=lambda p:p.x), min(pnts,key=lambda p:p.y), max(pnts,key=lambda p:p.y), min(pnts,key=lambda p:p.z), max(pnts,key=lambda p:p.z)] lst2 = [] for p in lst: if not p in lst2: lst2.append(p) import itertools return max(itertools.combinations(lst2,4),key=lambda p:SumDist(p)) #点リストの合計距離 def SumDist(pnts): import itertools return sum(p1.distanceTo(p2) for p1,p2 in itertools.combinations(pnts,2)) #ランダムな点の作成 def InitRandomPoint(skt, low, upp, count): pnts = [adsk.core.Point3D.create( random.uniform(low,upp),random.uniform(low,upp),random.uniform(low,upp)) for dmy in range(count)] skt_Pnts = skt.sketchPoints [skt_Pnts.add(pnt) for pnt in pnts] return def dumpPoint(p): print("{:.3f},{:.3f},{:.3f}".format(p.x *10,p.y*10,p.z *10)) def dumpPoints(ps): [dumpPoint(p) for p in ps]
で、3点が直線になっていないか? のチェックを忘れている・・・。
重複点を除外する為にセットを利用したかったのですが、駄目なんですね。
どうやらハッシュメソッドを持っていないとNGらしいです。(まぁそうでしょう・・・)
重複点を削除した時点で4点以下の場合どうしよう・・・。