#厚みをつける #ウィジェットに収録する場合はutfでコーディング #高速化(2010.01.31) #方向に法線方向を追加(2010.02.06) #内包面が元からできないアルゴリズムに変更(2010.02.16) #押し出す方向によっては面の向きが内向きになるのに対処(2010.02.18)まささんにアドバイスいただきました。ありがとうございました。 #平面状のポリゴンメッシュに厚みをつけるスクリプトです #パラメーター #方向(X軸方向、Y軸方向、Z軸方向、法線方向) #厚み・・・厚み量 #向き(+方向、-方向)・・・ふくらます方向 #動作条件 #選択形状がポリゴンメッシュ #上位パートに変換マトリクスがかかっていたり、ローカル座標モードでは #結果が不正になります def return_henlist(face): #面番号から面を構成する辺の番号を返す #前後にsetup_winged_edgeとclean_winged_edgeが必要 tempvlist=xshade.scene().active_shape().face(face).vertex_indices henlist=[] for i in tempvlist: tempf=xshade.scene().active_shape().eccwfv(face,i,False) henlist.append(tempf) return henlist def return_setuzokuhen(point): #頂点番号を渡すと、その頂点と接続されている辺のリストを返す henlist=[] for i in range(xshade.scene().active_shape().number_of_edges): if xshade.scene().active_shape().edge(i).v0==point or xshade.scene().active_shape().edge(i).v1==point: henlist.append(i) return henlist def return_menlist(edgenumber): #その辺を共有する面の面番号をリストで返す(引数 辺番号) menlist=[] edgevertex=[xshade.scene().active_shape().edge(edgenumber).v0,xshade.scene().active_shape().edge(edgenumber).v1] totalmenmen=xshade.scene().active_shape().number_of_faces for i in range(totalmenmen): konomen=0 temppoint=list(xshade.scene().active_shape().face(i).vertex_indices) for j in temppoint: if edgevertex[0]==j: konomen+=1 if edgevertex[1]==j: konomen+=1 if konomen==2: menlist.append(i) return menlist def return_edgelist(mennumber): #その面を構成する辺の辺番号をリストで返す #def return_edge_numberが必要 #def erase_same_num が必要 returnlist=[] menpoints=list(xshade.scene().active_shape().face(mennumber).vertex_indices) kumiawase=[]#頂点を組みあわせたリスト(重複分は削除する) for i in range(len(menpoints)): if i!=(len(menpoints)-1): kumiawase.append([menpoints[i],menpoints[i+1]]) else: kumiawase.append([menpoints[i],menpoints[0]]) for i in kumiawase: modori=return_edge_number(i[0],i[1]) returnlist.append(modori) return returnlist def return_edge_number(pointnum1,pointnum2): #頂点二つの頂点番号を与えると、その頂点で構成される辺の辺番号を返す #エラー(辺の両端のポイントでは無い)の場合は-1を返す returnnum=-1 for i in range(xshade.scene().active_shape().number_of_edges): if xshade.scene().active_shape().edge(i).v0==pointnum1 and xshade.scene().active_shape().edge(i).v1==pointnum2: returnnum=i break if xshade.scene().active_shape().edge(i).v1==pointnum1 and xshade.scene().active_shape().edge(i).v0==pointnum2: returnnum=i break return returnnum def erase_same_num(list1): #リスト内に同じ値が重複する場合は一つに減らす関数 例[1,1,1,3,3,4]→[1,3,4] #呼び出す時はlist=erase_same_num(list)ではなく、erase_same_num(list)で良い list1.sort() nagasa=len(list1) if nagasa>1: kesu=[] for i in range(nagasa-1): if list1[i]==list1[i+1]: kesu.append(list1[i]) kesukaisuu=len(kesu) if kesukaisuu>0: for i in kesu: list1.remove(i) dousasuru=0 if xshade.scene().active_shape().type==7: dousasuru=1 if dousasuru==1: xscene=xshade.scene() #ここに初期値 renzoku=1 houkou=0#方向 0がx軸方向 1がy軸方向 2がz軸方向 atumi=100#厚み muki=0#向き  deln=1#内包面の自動削除のONかOFF(デフォルトでONの1) temphoukou=houkou tempatumi=atumi tempmuki=muki tempdeln=deln while(renzoku==1): ashape=xshade.scene().active_shape() #ダイアログ表示 dialog=xshade.create_dialog_with_uuid('0x51903F33') dialog.append_default_button() dialog.begin_group() idx1=dialog.append_radio_button('/X軸方向/Y軸方向/Z軸方向/法線方向') dialog.end_group() idx2=dialog.append_float('厚み') dialog.begin_group() idx3=dialog.append_radio_button('/+方向/-方向') dialog.end_group() # idx4=dialog.append_bool('内包面の自動削除') dialog.set_default_value(idx1,temphoukou) dialog.set_default_value(idx2,tempatumi) dialog.set_default_value(idx3,tempmuki) # dialog.set_default_value(idx4,tempdeln) # dialog.set_value(idx4,deln) kekka=dialog.ask('厚みをつける') if kekka==False: renzoku=0 if kekka==True: ashape.adjust_face_direction() houkou=dialog.get_value(idx1) atumi=dialog.get_value(idx2) muki=dialog.get_value(idx3) if muki==1: muki2=-1 else: muki2=1 # deln=dialog.get_value(idx4) #面の向きのサンプルを取る fvec=[0,0,0] if ashape.number_of_faces>0: templist55=ashape.face(0).vertex_indices tvec1=[0,0,0] for i in templist55: tvec=ashape.vertex(i).normal tvec1=[tvec1[0]+tvec[0],tvec1[1]+tvec[1],tvec1[2]+tvec[2]] fvec=[tvec1[0]/len(templist55),tvec1[1]/len(templist55),tvec1[2]/len(templist55)] #元の形状をクリップボードにコピーしておく if xshade.scene().is_modify_mode==True:ima=1 else:ima=0 xshade.scene().active_shape().copy() if ima==1:xshade.scene().enter_modify_mode() #頂点番号順に座標リストを作成 vposlist=[] for i in range(xshade.scene().active_shape().total_number_of_control_points): tempos=xshade.scene().active_shape().vertex(i).position vposlist.append([tempos[0],tempos[1],tempos[2]]) #辺の端点リストを作成 v0v1list=[] for i in range(xshade.scene().active_shape().number_of_edges): v0p=xshade.scene().active_shape().edge(i).v0 v1p=xshade.scene().active_shape().edge(i).v1 v0v1list.append([v0p,v1p]) #元の頂点数 pnum=xshade.scene().active_shape().total_number_of_control_points #面を構成する頂点群のリストを作成 facevlist=[] for i in range(xshade.scene().active_shape().number_of_faces): facevlist.append(xshade.scene().active_shape().face(i).vertex_indices) eflist=[]#辺の隣接面リスト 辺番号順に格納 velist=[]#頂点の接続辺リスト 頂点番号順に格納 for i in range(ashape.number_of_edges): eflist.append([]) for i in range(ashape.total_number_of_control_points): velist.append([]) for i in range(ashape.number_of_edges): vv0=ashape.edge(i).v0 vv1=ashape.edge(i).v1 templ=velist[vv0] templ.append(i) velist[vv0]=templ templ=velist[vv1] templ.append(i) velist[vv1]=templ ashape.adjust_face_direction() ashape.setup_winged_edge() for i in range(ashape.number_of_faces): henlist=return_henlist(i) for gg in henlist: tt=eflist[gg] tt.append(i) eflist[gg]=tt ashape.clean_winged_edge() #隣接面が1以下の辺の両端の頂点リストを作成 e01list=[] for i in range(ashape.number_of_edges): if len(eflist[i])<2: e01list.append([ashape.edge(i).v0,ashape.edge(i).v1]) tasu3=ashape.total_number_of_control_points #面の向きが内向きになるのを対処 gyaku=0 sposlist=[] kei=1 if ashape.number_of_faces==1:kei=-1 if houkou==0: if muki2*fvec[0]*kei>0: gyaku=1 #元の頂点を移動 for i in range(ashape.total_number_of_control_points): mpos=ashape.vertex(i).position sposlist.append(mpos) ashape.vertex(i).position=[mpos[0]+muki2*atumi,mpos[1],mpos[2]] if houkou==1: if muki2*fvec[1]*kei>0: gyaku=1 #元の頂点を移動 for i in range(ashape.total_number_of_control_points): mpos=ashape.vertex(i).position sposlist.append(mpos) ashape.vertex(i).position=[mpos[0],mpos[1]+muki2*atumi,mpos[2]] if houkou==2: if muki2*fvec[2]*kei>0: gyaku=1 #元の頂点を移動 for i in range(ashape.total_number_of_control_points): mpos=ashape.vertex(i).position sposlist.append(mpos) ashape.vertex(i).position=[mpos[0],mpos[1],mpos[2]+muki2*atumi] if houkou==3: if muki2>0 and kei==1: gyaku=1 #元の頂点を移動 for i in range(ashape.total_number_of_control_points): tempn2=ashape.vertex(i).normal mpos=ashape.vertex(i).position sposlist.append(mpos) ashape.vertex(i).position=[mpos[0]+atumi*tempn2[0],mpos[1]+atumi*tempn2[1],mpos[2]+atumi*tempn2[2]] if muki2<0 and kei==-1: gyaku=1 #元の頂点を移動 for i in range(ashape.total_number_of_control_points): tempn2=ashape.vertex(i).normal mpos=ashape.vertex(i).position sposlist.append(mpos) ashape.vertex(i).position=[mpos[0]-atumi*tempn2[0],mpos[1]-atumi*tempn2[1],mpos[2]-atumi*tempn2[2]] #新しい位置に頂点を追加 for i in range(pnum): motopos=vposlist[i] if houkou==0: if gyaku==0: newpos=[motopos[0]+muki2*atumi,motopos[1],motopos[2]] else: newpos=sposlist[i] if houkou==1: if gyaku==0: newpos=[motopos[0],motopos[1]+muki2*atumi,motopos[2]] else: newpos=sposlist[i] if houkou==2: if gyaku==0: newpos=[motopos[0],motopos[1],motopos[2]+muki2*atumi] else: newpos=sposlist[i] if houkou==3: if gyaku==0: tvec=ashape.vertex(i).normal newpos=[motopos[0]+muki2*atumi*tvec[0],motopos[1]+muki2*atumi*tvec[1],motopos[2]+muki2*atumi*tvec[2]] else: newpos=sposlist[i] xshade.scene().active_shape().append_point(newpos) #辺を追加 for i in v0v1list: xshade.scene().active_shape().make_edge(i[0]+pnum,i[1]+pnum) #面を追加 for i in facevlist: newlistv=[] for g in i: newlistv.append(g+pnum) xshade.scene().active_shape().append_face(newlistv) #元の頂点と追加した頂点の間にエッジを張る #ただし、元の頂点が面の内側にある場合はエッジを張らない #(元の頂点の接続辺の隣接面がすべて2以上) for i in range(pnum): temphenlist=velist[i] tunagu=0 for g in temphenlist: if len(eflist[g])<2: tunagu=1 break if tunagu==1: # xshade.scene().active_shape().append_edge(i,i+pnum) xshade.scene().active_shape().make_edge(i,i+pnum) #側面の面を張る for i in e01list: ashape.append_face((i[0],i[1],i[1]+tasu3,i[0]+tasu3)) #面の向きを統一 xshade.scene().active_shape().adjust_face_direction() #内包面の削除 # if deln==1: # nailist=[] # eflist=[] #辺の隣接面リスト  辺番号順に格納 # felist=[] #面を構成する辺のリスト 面番号順に格納 # for i in range(ashape.number_of_edges): # eflist.append([]) # ashape.setup_winged_edge() # for i in range(ashape.number_of_faces): # henlist=return_henlist(i) # felist.append(henlist) # for gg in henlist: # tt=eflist[gg] # tt.append(i) # eflist[gg]=tt # ashape.clean_winged_edge() #面を構成する全ての辺の隣接面の数が3以上の面をリストに加えていく # for i in range(xshade.scene().active_shape().number_of_faces): # edgelist=felist[i] # hantei=0 # for g in edgelist: # if len(eflist[g])>=3:hantei+=1 # if hantei==len(edgelist):nailist.append(i) #内包面の削除 # xshade.scene().active_shape().begin_removing_faces() # for i in nailist: # xshade.scene().active_shape().face(i).remove() # xshade.scene().active_shape().end_removing_faces() # #面の向きを統一 # xshade.scene().active_shape().adjust_face_direction() #元に戻すか聞く dialog=xshade.create_dialog() idx3=dialog.append_push_button('処理を確定する場合はokを') idx4=dialog.append_push_button('取り消す場合はcancelを押してください') kekka2=dialog.ask('厚みをつける') #キャンセルなら形状を削除してクリップボードの形状を元に戻す #さらに頂点の選択状態も元に戻す? if kekka2==False: idou1=0 if xshade.scene().active_shape().has_sis==True: idou1=1 xshade.scene().paste() xshade.scene().select_sister(1) xshade.scene().clear() if idou1==1: xshade.scene().select_brother() if ima==1: xshade.scene().enter_modify_mode() # for i in activepointlist: # xshade.scene().active_shape().vertex(i).active=True #選択番号が変更されているので、入れなおし # for i in range(len(activepointlist2)): # xshade.scene().active_shape().vertex(activepointlist2[i]).active_order=i+1 if kekka2==True: renzoku=0 #戻す終わり