こちらの続きです。
凸包に挑んでみる6 - C#ATIA
先日のスピードテストを反映させて
・処理時間の短縮
・実行後、ソリッド化
を修正しました。
#FusionAPI_python test_ConvexHull3D ver0.0.2 #Author-kantoku #Description-新たなスケッチを作成し、ランダムに3Dな点を作成し、3Dな凸包を作成 # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. import adsk.core, adsk.fusion, traceback import random, os, sys this_dir = os.path.dirname(os.path.abspath(__file__)) sys.path.append(this_dir) #thx-varkenvarken #chttps://michelanders.blogspot.com/2012/02/3d-convex-hull-in-python.html #https://github.com/varkenvarken/blenderaddons/blob/master/chull.py import chull def run(context): #Create Point Count p_count = 100 ui = None try: #extension chull.Vertex.toPnt = ToPoint3d chull.Face.toSkt = ToSketch chull.Face.cog = InitCOGPoint adsk.core.Point3D.toVec = ToCHullVector adsk.fusion.Sketch.initSurf = InitSurface #preparation app = adsk.core.Application.get() ui = app.userInterface des = app.activeProduct root = des.rootComponent #RandomPoint skt = root.sketches.add(root.xYConstructionPlane) skt.name = 'points' CreateRandomPoint(skt, -10.0, 10.0, p_count) #time import time t = time.time() #coordinate array pnts = [p.geometry.asArray() for p in skt.sketchPoints] del pnts[0] #remove origin point #edges sketch skt = root.sketches.add(root.xYConstructionPlane) skt.name = 'edges' #ConvexHull face_count = InitConvexHull(pnts,skt) #finish ui.messageBox('Point Count:{}\nface Count:{}\ntime:{:.2f}s' .format(p_count,face_count,time.time()- t)) except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) #ConvexHull def InitConvexHull(point3d_list,target_sketch): if len(point3d_list) < 4: return #hull pnts = [chull.Vector(ary[0],ary[1],ary[2]) for ary in point3d_list] hull = chull.Hull(pnts) #edges QuickOn(target_sketch) [f.toSkt(target_sketch) for f in hull.faces] QuickOff(target_sketch) #profile profs = GetUseProfiles(target_sketch,hull.faces,0.001) #faces target_sketch.initSurf(profs) return len(hull.faces) #有効なプロファイルのみ選択 重心距離で検索 def GetUseProfiles(skt,faces,tol): profs = skt.profiles if len(profs) == len(faces): return list(profs) cogs = [face.cog() for face in faces] lst = [] for cog in cogs: hit = [prof for prof in profs if prof.areaProperties().centroid.distanceTo(cog) < tol] lst.extend((filter(lambda x:not x in lst, hit))) return lst def QuickOn(skt): skt.isComputeDeferred = True skt.areProfilesShown = False skt.areDimensionsShown = False def QuickOff(skt): skt.areDimensionsShown = True skt.areProfilesShown = True skt.isComputeDeferred = False #RandomPoint def CreateRandomPoint(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 QuickOn(skt) [skt_Pnts.add(pnt) for pnt in pnts] QuickOff(skt) # --- extension method --- #chull.Vertex def ToPoint3d(self): return adsk.core.Point3D.create( self.v.x,self.v.y,self.v.z) #chull.Face def ToSketch(self, skt): #Vertex pnts = skt.sketchPoints ps = [pnts.add(p.toPnt()) for p in self.vertex] #edge lins = skt.sketchCurves.sketchLines edges =[(ps[0],ps[1]),(ps[1],ps[2]),(ps[2],ps[0])] [lins.addByTwoPoints(p0,p1) for p0,p1 in edges] #chull.Face def InitCOGPoint(self): return adsk.core.Point3D.create( (self.vertex[0].v.x+self.vertex[1].v.x+self.vertex[2].v.x)/3, (self.vertex[0].v.y+self.vertex[1].v.y+self.vertex[2].v.y)/3, (self.vertex[0].v.z+self.vertex[1].v.z+self.vertex[2].v.z)/3) #adsk.core.Point3D def ToCHullVector(self): ary = self.asArray() return chull.Vector(ary[0],ary[1],ary[2]) #adsk.fusion.Sketch def InitSurface(self,profs,tolerance = 0.001): if len(profs) < 1: return newBodyOpe = adsk.fusion.FeatureOperations.NewBodyFeatureOperation comp = self.parentComponent feats = comp.features objs = adsk.core.ObjectCollection.create() [objs.add(v) for v in profs] patches = feats.patchFeatures pats = patches.add(patches.createInput(objs,newBodyOpe)) objs.clear() [objs.add(v) for v in pats.bodies] tol = adsk.core.ValueInput.createByReal(tolerance) stitches = feats.stitchFeatures stitches.add(stitches.createInput(objs, tol, newBodyOpe))
結局、全ての三角形は1つのスケッチに描く今までの方法にしました。
ライブラリから得られた三角形の重心と同じ位置にある
プロファイルのみを選択し、パッチを作成するようにしたところ
100%ソリッド化出来るようになりました。
こちらに点100個と1000個のサンプルをUpしました。
3D CAD Model Collection | GrabCAD Community Library
10000個も挑戦したのですが、時間がかかりすぎたため断念。
となると、ボディから凸包を作成するのはちょっと厳しそうです。