C#ATIA

↑タイトル詐欺 主にCATIA V5 の VBA(最近はPMillマクロとFusion360APIが多い)

凸包に挑んでみる3

こちらの続きです。
凸包に挑んでみる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点以下の場合どうしよう・・・。