2015年3月16日月曜日

Softimage Script : 円状に集める2 等間隔

SIを使う人はもうないだろうから、
付け焼き刃的なスクリプトのままメモ

とりあえず、円周上に等間隔に整列するようにしてみました。



ズレる時はローカルで回転させてあわせてます。


Sorce

#AligenCircle
#
# 02 28 2015 ver 0.1
#
# 選択がまだ甘いがポイント選択状態だと動く
#
# ベクトルは選択したポイントの平均
# 中心はBBOX ,半径は一番遠いポイントまでの距離の設定になっている



app = Application; log = app.LogMessage
oCmdLog = app.Dictionary.GetObject( "preferences.scripting" )
userPref = oCmdLog.cmdlog.value
oCmdLog.cmdlog.value = False

import math
from win32com.client import constants as c
DEBUG = True
CUSTOM_RAD = False
CUSTOM_CENTER = False
CUSTOM_NORMAL = False
NORMAL = [1,0,0]


#Select
#Application.SelectGeometryComponents("grid.pnt[30-32,39-41,48-50]")

CENTER = (3,0,-1)
def vLog(v):
 return str(str(v.X) + ", " + str(v.Y) + ", " + str(v.Z) + "")
 
def dLog( str ):
 if DEBUG == True:
  log(str)


#サークルデータのソート

#---------------------------------------------------
# circleSort
#---------------------------------------------------
def circleSort(Center,pnts):
 o = XSIMath.CreateVector3(CENTER[0],CENTER[1],CENTER[2])
 v = XSIMath.CreateVector3()
 
 idRad = []
 
 for pnt in pnts:
  p = pnt.Position
  
  #中心点からのベクトル
  v.Sub(p,o)
  #vlog(v)
  r = math.atan2(-v.Z,v.X)
  
  if DEBUG:#Debg時にはわかりやすいように度表記で
   r = int( r / 3.141519 * 180)
  idRad.append( [r, pnt.Index] ) 
 idRad.sort()
 
 sortedIDs = []
 for i in idRad:
  sortedIDs.append(i[1])
  dLog(str(i))
  
 dLog("circleSortIDs : " + str(sortedIDs))
 return sortedIDs



#---------------------------------------------------
# getWorldPos
#---------------------------------------------------
def getWorldPos( pts, m4 ):
 posArray = []
 for pnt in pts:
  p = pnt.Position
  p.MulByMatrix4InPlace(m4)
  posArray.append([p.X,p.Y,p.Z])
 
 return posArray

#---------------------------------------------------
# getAveNormal
#---------------------------------------------------
def getAveNormal(pts,m4):
 n = XSIMath.CreateVector3()
 x = 0
 y = 0
 z = 0
 
 for pnt in pts:
  n = pnt.Normal
  
  #ノーマル座標(逆行列の転地をつかう)
  #m4.InvertInPlace()
  m4.TransposeInverseInPlace()
  n.MulByMatrix4InPlace(m4)
  x = x + n.X
  y = y + n.Y
  z = z + n.Z
  
 
 num = pts.Count
 n.Set( x / num, y / num, z / num)
 n.NormalizeInPlace()
 return n


#---------------------------------------------------
# getCenter
#---------------------------------------------------
def getCenter():
 center = XSIMath.CreateVector3()
 bbox = Application.GetBBox()
 rad = 0.01

 xLength = bbox(3) - bbox(0)
 yLength = bbox(4) - bbox(1)
 zLength = bbox(5) - bbox(2)
 xMid = xLength / 2 + bbox(0)
 yMid = yLength / 2 + bbox(1)
 zMid = zLength / 2 + bbox(2)
 center.Set(xMid,yMid,zMid)

 return center
 
#---------------------------------------------------
# getBBOXRadius
#---------------------------------------------------
def getBBOXRadius():
 bbox = Application.GetBBox()
 tmp = 0.01

 xLength = bbox(3) - bbox(0)
 yLength = bbox(4) - bbox(1)
 zLength = bbox(5) - bbox(2)
 
 if xLength > tmp:
  tmp = xLength
 if yLength > tmp:
  tmp = yLength
 if zLength > tmp:
  tmp = zLength
 rad = tmp * 0.5
 return rad
 
 

#---------------------------------------------------
# createCircleMatrix
#---------------------------------------------------
def createCircleMatrix(aID,aPos,normal,center):
 circleMatrix = XSIMath.CreateMatrix4()
 p = XSIMath.CreateVector3()
 v = XSIMath.CreateVector3()
 farPos = XSIMath.CreateVector3()
 offsetCount = 0
 maxLength = 0
 
 for i in range(len(aID)):
  p.Set(aPos[i][0],aPos[i][1],aPos[i][2])
  v.Sub(p,center)
  if maxLength < v.Length():
   maxLength = v.Length()
   farPos = p
   offsetCount = i

 x = XSIMath.CreateVector3()
 y = XSIMath.CreateVector3()   
 x.Sub(p,center)
 x.NormalizeInPlace()
 y.Cross(normal,x)
 y.NormalizeInPlace()
 
 circleMatrix.Set(
 x.X, x.Y, x.Z, 0,
 y.X, y.Y, y.Z, 0,
 normal.X, normal.Y, normal.Z, 0,
 center.X, center.Y, center.Z, 1)
 
 return circleMatrix,offsetCount


def circleSort2(aID,aPos):

 xID = 0
 yID = 1
 zID = 2
 
 idRad = []
 for i in range(len(aID)):
  r = math.atan2(aPos[i][yID],aPos[i][xID]) #y,x
  r += 0.01
  
  if DEBUG:#Debg時にはわかりやすいように度表記で
   r = int( r / 3.141519 * 180)
  idRad.append( [r, aID[i],i] ) 
 idRad.sort()
 
 sortedIDs = []
 
 for i in idRad:
  sortedIDs.append(i[2])
  dLog(str(i))
  
 dLog("circleSortIDs : " + str(sortedIDs))
 return sortedIDs


#---------------------------------------------------
# getWorldCirclePointsPositionArray
#---------------------------------------------------
def getWorldCirclePointsPositionArray(aID,aPos,center,radius,circleMatrix,offset):
 m4 = XSIMath.CreateMatrix4()
 im = XSIMath.CreateMatrix4()
 p = XSIMath.CreateVector3()
 m4.Invert(circleMatrix)
 im.Invert(m4)
 
 circlePositionArray = []
 
 #world to circle
 for i in aPos:
  p.Set(i[0],i[1],i[2])
  p.MulByMatrix4InPlace(m4)
  circlePositionArray.append([p.X,p.Y,p.Z])

 sortedID = circleSort2(aID,circlePositionArray)
 
 #AligenToLocalCircle
 dLog(offset)
 segment = len(aID)
 for i in range(len(sortedID)):
  j = (i + len(sortedID) / 2 ) % len(sortedID)
  x = radius * math.cos( j * 1.0 / segment * 2 * math.pi) 
  y = radius * math.sin( j * 1.0 / segment * 2 * math.pi)
  z = 0.0
  circlePositionArray[sortedID[i]] = [x,y,z]

 #Circle to World 
 newCirclePositionArray = []
 for i in circlePositionArray:
  p.Set(i[0],i[1],i[2])
  p.MulByMatrix4InPlace(im)
  newCirclePositionArray.append([p.X,p.Y,p.Z])
  
 return newCirclePositionArray 

#---------------------------------------------------
# main
#---------------------------------------------------
def main():

 #Defalt
 radius = 1.0
 center = XSIMath.CreateVector3(0,0,0)
 
 #if app.Selection().Count < 0:
 # return
 oSel = app.Selection(0)
 oSub = oSel.Subcomponent
 obj = oSub.Parent3DObject
 oColl = oSub.ComponentCollection
 
 #VertexCollectionから、IndexArrayを取得できないので一度ポイント選択にする
 if oSub.Type != "pntSubComponent":#point#
  Application.SelectFilter("Edge")
  Application.SelectAdjacent("", "Point", False)
  oSel = app.Selection(0)  
  oSub = oSel.Subcomponent
  obj = oSub.Parent3DObject
  pts = oSub.ComponentCollection
  
 else :
  pts = oColl

 if pts.Count < 3:
  log("selection error")
  return
  
 aID = pts.IndexArray
 pointNum = pts.Count
 
 normal = XSIMath.CreateVector3(NORMAL[0],NORMAL[1],NORMAL[2]) 
 circleMatrix = XSIMath.CreateMatrix4()
 m4 = XSIMath.CreateMatrix4()
 im4 = XSIMath.CreateMatrix4()
 tm4 = XSIMath.CreateMatrix4()
 objectMatrix = obj.Kinematics.Global.Transform.GetMatrix4(m4)
 im4.Invert(m4)
 offsetCount = 0
 
 
 #Center
 if CUSTOM_CENTER == False:
  center = getCenter()
 dLog("Center : " + vLog(center))
 
 #Radius
 if CUSTOM_RAD == False:
  radius = getBBOXRadius()
  
 #Local to Global
 aPos = getWorldPos(pts,m4)
 
 #Normal)
 if CUSTOM_NORMAL == False:
  normal = getAveNormal(pts,m4)
 
 #CircleMatrix,offdetCount(IndexArray)
 circleMatrix,offsetCount = createCircleMatrix(aID,aPos,normal,center)
 dLog("offsetCount : " + str(offsetCount))
 
 #getNewWorldPos newPositionArray[[x,y,z],[x,y,z]///]
 newPosA = getWorldCirclePointsPositionArray(aID,aPos,center,radius,circleMatrix,offsetCount)
 
 #setNewPosition
 for i in range(pointNum):
  app.Translate(oSel.Name + ".pnt[" + str(aID[i]) + "]", newPosA[i][0], newPosA[i][1], newPosA[i][2], 0, "siView", "siObj", "siXYZ", "", "", "", "", "", "", "", "", "", 0, "")

  
 #dLog(str(aPos))
 #dLog("Normal : " + vLog(normal))

 
 return
main()

近況

仕事
・リダクション作業が半分終わり
・キャラクター遅延気味

スクリプト挫折中
・屋根の処理
・電線の処理(カテナリー曲線)

心うきうき成分が足りない :p

0 件のコメント:

コメントを投稿