import copy #稜線のオフセットとコピー #ローカル座標モードでも使えるように修正(2010.03.03) #アルゴリズムc廃止(2010.03.03) #一時ローカル座標モードで使えますが、上位パートに変換がかかっていると使えません #shade1301対応 #辺をループ状に選択状態でこのスクリプトを実行すると #元の辺からの厚みが上面図(正面図、側面図)で見て一定になるように拡大縮小したり、コピーしたりできます。 #動作条件 #選択形状がポリゴンメッシュ #編集モードに入っている #辺編集モード #辺を一つ以上選択しており、ループ状に辺が選択されている #設定項目 #idouryou・・・移動量 #hanten・・・内側へ移動か外側へ移動か #pcopy・・・0のときは移動、1のときはコピー #ziku・・・直行軸。0はx軸、1はy軸、2はz軸 #al・・・アルゴリズム0と1と2 def henkan(pos,mode22): #mode22が0の場合ローカル座標からワールド座標へ変換 #mode22が1の場合ワールド座標から図形ウインドウ座標へ変換 #mode22が2の場合図形ウインドウ座標からワールド座標へ変換 #mode22が3の場合ワールド座標からローカル座標へ変換 if mode22==0:mat2=xshade.scene().active_shape().local_to_world_matrix if mode22==1:mat2=xshade.scene().world_to_user_matrix if mode22==2:mat2=xshade.scene().user_to_world_matrix if mode22==3:mat2=xshade.scene().active_shape().world_to_local_matrix tempx=pos[0] tempy=pos[1] tempz=pos[2] x1=mat2[0][0]*tempx+mat2[1][0]*tempy+mat2[2][0]*tempz+mat2[3][0]*1 y1=mat2[0][1]*tempx+mat2[1][1]*tempy+mat2[2][1]*tempz+mat2[3][1]*1 z1=mat2[0][2]*tempx+mat2[1][2]*tempy+mat2[2][2]*tempz+mat2[3][2]*1 return [x1,y1,z1] 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) 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_vec(avec): #単位ベクトルに変換して返す if (avec[0]**2+avec[1]**2)!=0: bun=pow(avec[0]**2+avec[1]**2,0.5) newvec=[avec[0]/bun,avec[1]/bun] else: newvec=[0,0] return newvec def erase_same_num_all(list1): #リスト内に同じ値が重複する場合はその値を全て消したリストを返す関数 例[1,1,1,3,3,4]→[4] #erase_same_numが必要 list1copy=[] for i in range(len(list1)): list1copy.append(list1[i]) list1copy.sort() nagasa=len(list1copy) if nagasa>1: kesu=[] for i in range(nagasa-1): if list1copy[i]==list1copy[i+1]: kesu.append(list1copy[i]) kesukaisuu=len(kesu) if kesukaisuu>0: for i in kesu: list1copy.remove(i) erase_same_num(kesu) if len(kesu)>0: for i in kesu: list1copy.remove(i) return list1copy def return_edge_number(pointnum1,pointnum2): #頂点二つの頂点番号を与えると、その頂点で構成される辺の辺番号を返す #エラー(辺の両端のポイントでは無い)の場合は-1を返す #velist(頂点の接続辺リストを頂点番号順に格納したもの)が必要 thenlist12=velist[point1] for i in thenlist12: if xshade.scene().active_shape().edge(i).v0==point1 and xshade.scene().active_shape().edge(i).v1==point2: return i if xshade.scene().active_shape().edge(i).v1==point1 and xshade.scene().active_shape().edge(i).v0==point2: return i return -1 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 dousasuru=0 if xshade.scene().is_modify_mode==True and xshade.scene().selection_mode==1 and xshade.scene().active_shape().type==7: activeedgelist=[] hantei=0 for i in range(xshade.scene().active_shape().number_of_edges): if xshade.scene().active_shape().edge(i).active_order>0: activeedgelist.append(i) for i in activeedgelist: if len(return_menlist(i))>=2:hantei+=1 if hantei==0: dousasuru=1 copyok=1 if hantei==len(activeedgelist): dousasuru=1 copyok=0 # print dousasuru if dousasuru==1: #上位パートに変換がかかっているなら動作しない 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: error=0 vvlist=[]#頂点に接続されている頂点リストを頂点番号順に格納したもの velist=[]#頂点に接続されている辺リストを頂点番号順に格納したもの for i in range(xshade.scene().active_shape().total_number_of_control_points): vvlist.append([]) velist.append([]) for i in range(xshade.scene().active_shape().number_of_edges): vv0=xshade.scene().active_shape().edge(i).v0 vv1=xshade.scene().active_shape().edge(i).v1 tempvv=vvlist[vv0] tempvv.append(vv1) vvlist[vv0]=tempvv tempvv=vvlist[vv1] tempvv.append(vv0) vvlist[vv1]=tempvv tempve=velist[vv1] tempve.append(i) velist[vv1]=tempve tempve=velist[vv0] tempve.append(i) velist[vv0]=tempve eflist=[]#辺に隣接されている面リストを辺番号順に格納したもの felist=[]#面を構成する辺リストを面番号順に格納したもの #return_henlist必要 for i in range(xshade.scene().active_shape().number_of_edges): eflist.append([]) xshade.scene().active_shape().setup_winged_edge() for i in range(xshade.scene().active_shape().number_of_faces): thenlist=return_henlist(i) felist.append(thenlist) for gg in thenlist: tempf=eflist[gg] tempf.append(i) eflist[gg]=tempf xshade.scene().active_shape().clean_winged_edge() #選択辺がループしてるか確認 mugen=0 pointlist=[] startedge=activeedgelist[0] loop=1 nokoriedge=copy.copy(activeedgelist) nokoriedge.remove(startedge) pointlist.append(xshade.scene().active_shape().edge(startedge).v0) imapoint=xshade.scene().active_shape().edge(startedge).v1 pointlist.append(imapoint) while(loop==1): mugen+=1 if mugen>9000:loop=0 kesu=-1 for i in nokoriedge: if xshade.scene().active_shape().edge(i).v0==imapoint: imapoint=xshade.scene().active_shape().edge(i).v1 if len(nokoriedge)>1: pointlist.append(imapoint) kesu=i break if xshade.scene().active_shape().edge(i).v1==imapoint: imapoint=xshade.scene().active_shape().edge(i).v0 if len(nokoriedge)>1: pointlist.append(imapoint) kesu=i break if kesu>=0:nokoriedge.remove(kesu) if len(nokoriedge)<1:loop=0 if mugen>9000:dousasuru=0 if dousasuru==1: templist=[] for i in activeedgelist: templist.append(xshade.scene().active_shape().edge(i).v0) templist.append(xshade.scene().active_shape().edge(i).v1) # print templist templist=erase_same_num_all(templist) if len(templist)>0:dousasuru=0 if dousasuru==1: #ここに初期値 idouryou=200#移動量 hanten=0#内へ移動か外へ移動かの反転 ziku=0#直行軸 x軸、y軸、z軸 pcopy=0#0で選択辺を移動、1では選択辺をコピーし、元の頂点と辺を結ぶ renzoku=1 al=0 while(renzoku==1): #ダイアログ表示 dialog=xshade.create_dialog() idx1=dialog.append_float('移動量') idx2=dialog.append_bool('方向の反転') idx3=dialog.append_radio_button('直行軸/X軸/Y軸/Z軸') dialog.begin_group() if copyok==1: idx4=dialog.append_radio_button('/移動/複製') if copyok==0: idx4=dialog.append_radio_button('/移動') dialog.end_group() dialog.begin_group() idx5=dialog.append_radio_button('/アルゴリズムA/アルゴリズムB') dialog.end_group() dialog.set_value(idx1,idouryou) dialog.set_value(idx2,hanten) dialog.set_value(idx3,ziku) dialog.set_value(idx4,pcopy) dialog.set_value(idx5,al) xshade.idle(120) kekka=dialog.ask('稜線のオフセットとコピー') if kekka==False:renzoku=0 if kekka==True: idouryou=dialog.get_value(idx1) hanten=dialog.get_value(idx2) ziku=dialog.get_value(idx3) pcopy=dialog.get_value(idx4) al=dialog.get_value(idx5) #元の形状をクリップボードにコピー xshade.scene().copy() xshade.scene().enter_modify_mode() #移動先(コピー先)のポイントを生成 if al==1 or al==2: newposlist=[] for i in range(len(pointlist)): motopos=xshade.scene().active_shape().vertex(pointlist[i]).position motopos=henkan(motopos,0) motopos=henkan(motopos,1) if i==0: maepoint=pointlist[len(pointlist)-1] else: maepoint=pointlist[i-1] if i==(len(pointlist)-1): atopoint=pointlist[0] else: atopoint=pointlist[i+1] maepos=xshade.scene().active_shape().vertex(maepoint).position atopos=xshade.scene().active_shape().vertex(atopoint).position maepos=henkan(maepos,0) maepos=henkan(maepos,1) atopos=henkan(atopos,0) atopos=henkan(atopos,1) if ziku==0: avec=[maepos[1]-motopos[1],maepos[2]-motopos[2]] bvec=[atopos[1]-motopos[1],atopos[2]-motopos[2]] if ziku==1: avec=[maepos[0]-motopos[0],maepos[2]-motopos[2]] bvec=[atopos[0]-motopos[0],atopos[2]-motopos[2]] if ziku==2: avec=[maepos[0]-motopos[0],maepos[1]-motopos[1]] bvec=[atopos[0]-motopos[0],atopos[1]-motopos[1]] #単位ベクトルに変換 avec=return_vec(avec) bvec=return_vec(bvec) #直行するベクトル avecv=[-1*(avec[1]),avec[0]] bvecv=[(bvec[1]),-1*(bvec[0])] #合成して単位ベクトルに変換 cvec=[avecv[0]+bvecv[0],avecv[1]+bvecv[1]] cvec=return_vec(cvec) muki=1 if hanten==1:muki=-1 tempvec=[muki*idouryou*cvec[0],muki*idouryou*cvec[1]] if ziku==0: idouvec=[0,tempvec[0],tempvec[1]] if ziku==1: idouvec=[tempvec[0],0,tempvec[1]] if ziku==2: idouvec=[tempvec[0],tempvec[1],0] newposlist.append([motopos[0]+idouvec[0],motopos[1]+idouvec[1],motopos[2]+idouvec[2]]) if al==0: error=0 newposlist=[] muki=-1 if hanten==1:muki=1 for i in range(len(pointlist)): motopos=xshade.scene().active_shape().vertex(pointlist[i]).position motopos=henkan(motopos,0) motopos=henkan(motopos,1) if i==0: maepoint=pointlist[len(pointlist)-1] else: maepoint=pointlist[i-1] if i==(len(pointlist)-1): atopoint=pointlist[0] else: atopoint=pointlist[i+1] maepos=xshade.scene().active_shape().vertex(maepoint).position atopos=xshade.scene().active_shape().vertex(atopoint).position maepos=henkan(maepos,0) maepos=henkan(maepos,1) atopos=henkan(atopos,0) atopos=henkan(atopos,1) if ziku==0: ix=motopos[1] iy=motopos[2] mx=maepos[1] my=maepos[2] ax=atopos[1] ay=atopos[2] if ziku==1: ix=motopos[0] iy=motopos[2] mx=maepos[0] my=maepos[2] ax=atopos[0] ay=atopos[2] if ziku==2: ix=motopos[0] iy=motopos[1] mx=maepos[0] my=maepos[1] ax=atopos[0] ay=atopos[1] waru=my*ax-my*ix-iy*ax-mx*ay+mx*iy+ix*ay # if waru==0: # error=1 # break ddd=1 if ((my-iy)**2+(ix-mx)**2)==0 or ((iy-ay)**2+(ax-ix)**2)==0: error=1 break else: # print ((my-iy)**2+(ix-mx)**2) l1=1/(pow((my-iy)**2+(ix-mx)**2,0.5)) l2=1/(pow((iy-ay)**2+(ax-ix)**2,0.5)) aa=idouryou*muki bunbo=(mx-ix)*( (ay-my)/2+l2*aa*(ax-ix)-l1*aa*(ix-mx))-(my-iy)*((ax-mx)/2+l2*aa*(iy-ay)-l1*aa*(my-iy)) # kk=bunbo/waru if waru==0: newx=ix+l2*aa*(iy-ay) newy=iy+l2*aa*(ax-ix) else: kk=bunbo/waru newx=kk*(ax-ix)+(ix+ax)/2+l2*aa*(iy-ay) newy=kk*(ay-iy)+(iy+ay)/2+l2*aa*(ax-ix) if ziku==0: temppos2=[motopos[0],newx,newy] if ziku==1: temppos2=[newx,motopos[1],newy] if ziku==2: temppos2=[newx,newy,motopos[2]] newposlist.append(temppos2) if al==2: #最初の選択頂点と生成された新しい頂点を結ぶ直線を稜線に沿って掃引 poslist=[] for i in pointlist: poslist.append(xshade.scene().active_shape().vertex(i).position) xshade.scene().begin_creating() xshade.scene().begin_part() xshade.scene().begin_line(None,False) xshade.scene().append_point(poslist[0],None,None,None,None) xshade.scene().append_point(newposlist[0],None,None,None,None) xshade.scene().end_line() xshade.scene().begin_line(None,True) for i in poslist: xshade.scene().append_point(i,None,None,None,None) xshade.scene().end_line() xshade.scene().end_part() xshade.scene().end_creating() xshade.scene().select_child(1) xshade.scene().select_brother(1) xshade.scene().memory() xshade.scene().select_sister(1) xshade.scene().exit_modify_mode() xshade.scene().sweep() xshade.scene().select_parent(1) xshade.scene().switch() xshade.scene().select_child(1) xshade.scene().clear() xshade.scene().place_parent(1) xshade.scene().place_sister(0) xshade.scene().active_shape().convert_to_polygon_mesh_with_subdivision_level(2) for i in range(xshade.scene().active_shape().total_number_of_control_points): tempnew=xshade.scene().active_shape().vertex(i).position newposlist[len(newposlist)-1-i]=[tempnew[0],tempnew[1],tempnew[2]] xshade.scene().select_parent(1) xshade.scene().clear() xshade.scene().enter_modify_mode() #移動の場合 if pcopy==0 and error==0: for i in range(len(pointlist)): tempos=newposlist[i] tempos=henkan(tempos,2) tempos=henkan(tempos,3) xshade.scene().active_shape().vertex(pointlist[i]).position=tempos #複製の場合 if pcopy==1 and error==0: cpointnum=xshade.scene().active_shape().total_number_of_control_points #新しい頂点を追加 for i in range(len(newposlist)): tempos=newposlist[i] tempos=henkan(tempos,2) tempos=henkan(tempos,3) xshade.scene().active_shape().append_point(tempos) # xshade.scene().active_shape().append_point(newposlist[i]) #新しい頂点同士にエッジを追加 for i in range(len(newposlist)): if i==(len(newposlist)-1): xshade.scene().active_shape().append_edge(cpointnum,cpointnum+i) else: xshade.scene().active_shape().append_edge(cpointnum+i,cpointnum+i+1) #元の頂点と新しい頂点にエッジを追加 for i in range(len(pointlist)): xshade.scene().active_shape().append_edge(pointlist[i],cpointnum+i) #面の方向を統一 xshade.scene().active_shape().adjust_face_direction() #新しい稜線を選択状態に xshade.scene().selection_mode=2 for i in range(xshade.scene().active_shape().total_number_of_control_points): xshade.scene().active_shape().vertex(i).active=False for i in range(cpointnum,cpointnum+len(newposlist)): xshade.scene().active_shape().vertex(i).active=True xshade.scene().selection_mode=1 #元に戻すかどうか dialog=xshade.create_dialog() idx3=dialog.append_push_button('結果を確定する場合はokを') idx4=dialog.append_push_button('取り消す場合はcancelを押してください') xshade.idle(120) if error==0:kekka2=dialog.ask('稜線のオフセット コピー') #キャンセルなら形状を削除してクリップボードの形状を元に戻す #さらに頂点の選択状態も元に戻す? if error==0: 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() xshade.scene().enter_modify_mode() for i in activeedgelist: xshade.scene().active_shape().edge(i).active=True if kekka2==True and error==0: renzoku=0 #戻す終わり if error==1: dialog=xshade.create_dialog() dialog.append_push_button('移動(コピー)に失敗しました。') dialog.append_push_button('軸の選択を間違っていませんか?') # dialog.append_push_button('ご利用できません') xshade.idle(120) dialog.ask('アラート') error=0