こちらの続きです。
凸包に挑んでみる3 - C#ATIA
面倒なため非公開ですが、前回のコードを視覚的に確認出来るように修正し
実際に四面体を見ると
そこそこ良さそうなのですが、何度試してみても点群に対して薄い形状に
なりやすいんです。気のせいかも知れないのですが・・・。
そこで、知恵が無いなりにもう少し良さそうな4点を選択できないものか?
考えてみました。(イラストはあくまでイメージです)
ピンクが点群です。この点群に対して重心を求めます。(白い点)
点群の中から、重心から一番遠い点を選ぶ(点1)
点群の中から、点1から一番遠い点を選ぶ(点2)
点群の中から、点1-点2ラインに対して一番角度のある点を選ぶ(点3)
結果的に線に対しては一番遠い・・・はず。
(線の色、変わらんで欲しいのに)
点1,点2,点3を通過する仮平面を考え、平面から一番遠い点を選ぶ(点4)
これであれば、極端に平べったい四面体にならないような
気がしたのですが、どうでしょうか?
#FusionAPI_python test2 #Author-kantoku #Description-新たなスケッチを作成し、ランダムに3Dな点を作成し、ユニークな4点を取得 import adsk.core, adsk.fusion, traceback import random import itertools def run(context): ui = None #作成するランダムな点の数 pointcount = 30 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) #4面体頂点取得 pnts = [p.geometry for p in skt.sketchPoints] uniq_pnts = GetUnique4Points(pnts) if uniq_pnts is None: return #パッチ skt = root.sketches.add(root.xYConstructionPlane) [CreateSketchLine(skt,p1,p2) for p1,p2 in itertools.combinations(uniq_pnts,2)] CreatePatchs(root,skt) except: if ui: ui.messageBox('エラー:\n{}'.format(traceback.format_exc())) #ユニークな4点取得 def GetUnique4Points(pnts): if len(pnts) < 4: return None #重心 cog = GetCog(pnts) #重心から一番遠い点 p1 = max(pnts,key=lambda p:p.distanceTo(cog)) #p1から一番遠い点 p2 = max(pnts,key=lambda p:p.distanceTo(p1)) #p1-p2ベクトル vec1_2 = p1.vectorTo(p2) #p1から一番角度の大きい点 p3 = max(pnts,key=lambda p:vec1_2.angleTo(p1.vectorTo(p))) #p1,p2,p3を仮平面した際の法線 normal = vec1_2.crossProduct(p1.vectorTo(p3)) normal.normalize() #平面から一番遠い点 p4 = max(pnts,key=lambda p:abs(normal.dotProduct(p1.vectorTo(p)))) return [p1,p2,p3,p4] #点群中心 def GetCog(points3D): bbox = adsk.core.BoundingBox3D.create(InitZeroPoint3D(),InitZeroPoint3D()) [bbox.expand(p) for p in points3D] return InitMidPoint3D(bbox.maxPoint,bbox.minPoint) #中間点 def InitMidPoint3D(p1,p2): ary1 = p1.asArray() ary2 = p2.asArray() pos = [(a1+a2)*0.5 for a1,a2 in zip(ary1,ary2)] return adsk.core.Point3D.create(pos[0],pos[1],pos[2]) #ゼロ点 def InitZeroPoint3D(): return adsk.core.Point3D.create(0,0,0) #ランダムな点の作成 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] #2点間線分 def CreateSketchLine(skt,p1,p2): lines = skt.sketchCurves.sketchLines lines.addByTwoPoints(p1,p2) #パッチ def CreatePatchs(root,skt): profs = lst2objCollection(skt.profiles) patches = root.features.patchFeatures newBodyFeatureOpe = adsk.fusion.FeatureOperations.NewBodyFeatureOperation patches.add(patches.createInput(profs,newBodyFeatureOpe)) #リスト→objCollection def lst2objCollection(lst): ents = adsk.core.ObjectCollection.create() [ents.add(ent) for ent in lst] return ents #開発用 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]
同じ点群に対して前回と今回のもので処理した結果です。
黄色と体積の左は前回、緑と右が今回です。
2倍弱ぐらいにはなりました。
よく考えたら、遠い点ばかり選択するから平べったくなるのかも知れない。