import copy import math #ツイストツール #選択している頂点だけを指定の位置を中心にねじります #上位パートに変換がかかっていると使用できないように変更(2010.03.03) #動作条件 #選択形状がポリゴンメッシュ #編集モードに入っている #頂点選択モード #頂点が二つ以上選択されている(x、y、z座標の値が異なる) #ローカル座標モードや、上位パートに変換がかかっていると結果が不正になります #設定項目 #回転の中心 「カーソルのクリック位置(最後にクリックした位置)」「選択頂点の平均座標」 #  「選択頂点を囲むバウンディングボックスの中心」「指定位置」 #指定位置の場合の座標(vec3) #回転軸 「x軸」「y軸」「z軸」 #「順周り」か「逆周り」 #回転速度 「数値で指定」「回転数で指定」 #数値で指定の場合の回転速度 #回転数で指定の場合の回転数 #「下端から上をねじる」「上端から下をねじる」 #「先っぽも一緒にねじる」 def return_henkan_pos(pos,mat): #posをmatで変換した座標(タプル)を返す tempx=pos[0] tempy=pos[1] tempz=pos[2] x1=mat[0][0]*tempx+mat[1][0]*tempy+mat[2][0]*tempz+mat[3][0]*1 y1=mat[0][1]*tempx+mat[1][1]*tempy+mat[2][1]*tempz+mat[3][1]*1 z1=mat[0][2]*tempx+mat[1][2]*tempy+mat[2][2]*tempz+mat[3][2]*1 return [x1,y1,z1] def return_kaiten(pos,cpos,kakudo2,ziku): #posをcposを中心にziku(0x軸、1y軸、2z軸)まわりにkakudoだけ回転させて返す kakudo=(2*math.pi*kakudo2)/360 tempos5=[pos[0]-cpos[0],pos[1]-cpos[1],pos[2]-cpos[2]] newpos=[tempos5[0],tempos5[1],tempos5[2]] if ziku==0: newpos[1]=tempos5[1]*math.cos(kakudo)-tempos5[2]*math.sin(kakudo) newpos[2]=tempos5[1]*math.sin(kakudo)+tempos5[2]*math.cos(kakudo) if ziku==1: newpos[2]=tempos5[2]*math.cos(kakudo)-tempos5[0]*math.sin(kakudo) newpos[0]=tempos5[2]*math.sin(kakudo)+tempos5[0]*math.cos(kakudo) if ziku==2: newpos[0]=tempos5[0]*math.cos(kakudo)-tempos5[1]*math.sin(kakudo) newpos[1]=tempos5[0]*math.sin(kakudo)+tempos5[1]*math.cos(kakudo) newpos=[newpos[0]+cpos[0],newpos[1]+cpos[1],newpos[2]+cpos[2]] return newpos dousasuru=0 xscene=xshade.scene() ashape=xshade.scene().active_shape() if ashape.type==7 and xscene.is_modify_mode==True: if xscene.selection_mode==2: aplist=[]#選択頂点リスト for i in range(ashape.total_number_of_control_points): if ashape.vertex(i).active==True: aplist.append(i) if len(aplist)>1:dousasuru=1 if dousasuru>0: #上位パートに変換がかかっているなら動作しない if xshade.scene().active_shape().local_to_world_matrix!=((1.0, 0.0, 0.0, 0.0), (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, 0.0, 0.0, 1.0)): dousasuru=0 dialog=xshade.create_dialog() dialog.append_push_button('上位パートに変換がかかっているため') dialog.append_push_button('スクリプトが実行できません') dialog.ask('エラー') if dousasuru==1: #ここに初期値 renzoku=1 ctype=0 #回転の中心タイプ spos=[0,0,0]#回転の中心が「指定位置」の場合の中心座標 ziku=0#回転軸 0がx軸、1がy軸、2がz軸 muki=0#回転の向き 右回りか左まわりか vtype=0 #回転速度のタイプ 0で「数値で指定」 1で「回転数で指定」 rval=90 #数値で指定の場合の回転速度 kaiten=1 #回転数で指定の場合の回転数 nezip=0 #0の場合は「下端より上をねじる」1なら「上端より下をねじる」 issyo=0 #1の場合は選択頂点より先の頂点も一緒に回転 dfctype=ctype dfspos=spos dfziku=ziku dfmuki=muki dfvtype=vtype dfrval=rval dfkaiten=kaiten dfnezip=nezip dfissyo=issyo while(renzoku==1): #ダイアログ表示 dialog=xshade.create_dialog_with_uuid('0x51900012') dialog.append_default_button() dialog.begin_group('回転の中心') idx1=dialog.append_radio_button('/カーソルのクリック位置/選択頂点の平均座標/選択頂点を囲むバウンディングボックスの中心/指定位置') dialog.end_group() dialog.begin_group('指定位置の場合') idx2=dialog.append_vec3() dialog.end_group() dialog.begin_group('回転軸(直行軸)') idx3=dialog.append_radio_button('/x軸/y軸/z軸') dialog.end_group() dialog.begin_group('回転の向き') idx4=dialog.append_radio_button('/順周り/逆周り') dialog.end_group() dialog.begin_group('回転速度') idx5=dialog.append_radio_button('/回転数で指定/数値で指定') dialog.end_group() dialog.begin_group('「回転数で指定」の場合') idx7=dialog.append_float() dialog.end_group() dialog.begin_group('「数値で指定」の場合') idx6=dialog.append_float() dialog.end_group() dialog.begin_group('開始点') idx8=dialog.append_radio_button('/最小値が開始点/最大値が開始点') dialog.end_group() idx9=dialog.append_bool('先っぽも一緒にねじる') dialog.set_default_value(idx1,dfctype) dialog.set_default_value(idx2,dfspos) dialog.set_default_value(idx3,dfziku) dialog.set_default_value(idx4,dfmuki) dialog.set_default_value(idx5,dfvtype) dialog.set_default_value(idx6,dfrval) dialog.set_default_value(idx7,dfkaiten) dialog.set_default_value(idx8,dfnezip) dialog.set_default_value(idx9,dfissyo) # dialog.set_value(idx1,ctype) # dialog.set_value(idx2,spos) # dialog.set_value(idx3,ziku) # dialog.set_value(idx4,muki) # dialog.set_value(idx5,vtype) # dialog.set_value(idx6,rval) # dialog.set_value(idx7,kaiten) # dialog.set_value(idx8,nezip) # dialog.set_value(idx9,issyo) xshade.idle(10) kekka=dialog.ask('ツイストツール') if kekka==False:renzoku=0 else: ctype=dialog.get_value(idx1) spos=dialog.get_value(idx2) ziku=dialog.get_value(idx3) muki=dialog.get_value(idx4) vtype=dialog.get_value(idx5) rval=dialog.get_value(idx6) kaiten=dialog.get_value(idx7) nezip=dialog.get_value(idx8) issyo=dialog.get_value(idx9) #元の形状をクリップボードにコピー ashape.copy() xscene.enter_modify_mode() #中心点の割り出し if ctype==0: cpos=xscene.cursor_position mat4=ashape.world_to_local_matrix cpos=return_henkan_pos(cpos,mat4) if ctype==1: sumpos=[0,0,0] for i in aplist: tempos=ashape.vertex(i).position sumpos[0]+=tempos[0] sumpos[1]+=tempos[1] sumpos[2]+=tempos[2] cpos=[sumpos[0]/len(aplist),sumpos[1]/len(aplist),sumpos[2]/len(aplist)] minx=ashape.vertex(aplist[0]).position[0] maxx=ashape.vertex(aplist[0]).position[0] miny=ashape.vertex(aplist[0]).position[1] maxy=ashape.vertex(aplist[0]).position[1] minz=ashape.vertex(aplist[0]).position[2] maxz=ashape.vertex(aplist[0]).position[2] minxp=aplist[0] minyp=aplist[0] minzp=aplist[0] maxxp=aplist[0] maxyp=aplist[0] maxzp=aplist[0] for i in aplist: tpos=ashape.vertex(i).position if tpos[0]maxx: maxxp=i maxx=tpos[0] if tpos[1]>maxy: maxyp=i maxy=tpos[1] if tpos[2]>maxz: maxzp=i maxz=tpos[2] if ctype==2: cpos=[(minx+maxx)/2,(miny+maxy)/2,(minz+maxz)/2] if ctype==3:cpos=spos #向きの変換 if muki==0:muki2=1 else:muki2=-1 #回転速度の割り出し if vtype==1:rval2=rval*0.01 if vtype==0: if ziku==0: if maxx==minx:rval2=0 else:rval2=kaiten*360/(maxx-minx) if ziku==1: if maxy==miny:rval2=0 else:rval2=kaiten*360/(maxy-miny) if ziku==2: if maxz==minz:rval2=0 else:rval2=kaiten*360/(maxz-minz) # print rval2 #開始位置 if nezip==0: if ziku==0:stpos=minx if ziku==1:stpos=miny if ziku==2:stpos=minz if nezip==1: if ziku==0:stpos=maxx if ziku==1:stpos=maxy if ziku==2:stpos=maxz #選択を全て解除 for i in aplist: ashape.vertex(i).active=False # xscene.inhibit_update() #個々の頂点を回転 for i in aplist: # ashape.vertex(i).active=True tpos=ashape.vertex(i).position if ziku==0: tempr=muki2*rval2*(tpos[0]-stpos) if i==minxp:minxval=tempr if i==maxxp:maxxval=tempr if ziku==1: tempr=muki2*rval2*(tpos[1]-stpos) if i==minyp:minyval=tempr if i==maxyp:maxyval=tempr if ziku==2: tempr=muki2*rval2*(tpos[2]-stpos) if i==minzp:minzval=tempr if i==maxzp:maxzval=tempr # while(tempr>=360): # tempr-=360.0 # while(tempr<0): # tempr+=360.0 # if tempr<0:mai=-1 # else:mai=1 # tempr=((tempr*mai)%360)*mai # print tempr if ziku==0:rrr=[tempr,0,0] if ziku==1:rrr=[0,tempr,0] if ziku==2:rrr=[0,0,tempr] tepos2=ashape.vertex(i).position tepos2=return_kaiten(tepos2,cpos,tempr,ziku) ashape.vertex(i).position=tepos2 # xscene.move_object(cpos,None,rrr,None) # ashape.vertex(i).active=False #先っぽもねじるか? if issyo==1: for i in range(ashape.total_number_of_control_points): tempos2=ashape.vertex(i).position if nezip==0: if ziku==0: if tempos2[0]>maxx:ashape.vertex(i).active=True if ziku==1: if tempos2[1]>maxy:ashape.vertex(i).active=True if ziku==2: if tempos2[2]>maxz:ashape.vertex(i).active=True if nezip==1: if ziku==0: if tempos2[0]