以前のものは選択したポリゴン面の法泉を基準(これは少し怪しい)に平面化してましたが
今回はスクリプトを実行するとポイントをピックさせられます。
3点ピックするとそれを元に平面化します。
相変わらず4つ以上の面に接したポイントがあるとダメです。
いやぁ使えない使えない。。。
from win32com.client import *
xsi = Application
def GetReferencePoints():
''' リファレンスポイントを取得(最低3点) '''
xsi.ActivateVertexSelTool()
lPnts = []
while len(lPnts) < 3:
rtn = xsi.PickElement(constants.siPointFilter)
oPick = rtn[2]
if not oPick: #ピックが足りない場合処理中止
return
for oCmp in oPick.SubComponent.ComponentCollection:
lPnts.append(oCmp)
return lPnts
def GetReferenceTransform(lPnts):
''' リファレンストランスフォームを取得 '''
#外積を取得
v1 = XSIMath.CreateVector3()
v2 = XSIMath.CreateVector3()
vCrs = XSIMath.CreateVector3()
v1.Sub(lPnts[1].Position, lPnts[0].Position)
v2.Sub(lPnts[2].Position, lPnts[0].Position)
vCrs.Cross(v1, v2)
#トランスフォームに変換(後でレイキャストさせるために位置をどのポイントとも違う位置(ポイントの中点)に)
vPos = XSIMath.CreateVector3()
for i in range(3):
vPos.AddInPlace(lPnts[i].Position)
vPos.ScaleInPlace(1.0/len(lPnts))
vYAxis = XSIMath.CreateVector3(0,1,0)
oTrans = XSIMath.CreateTransform()
oTrans.Translation = vPos
nAgl = vYAxis.Angle(vCrs)
vCrs.Cross(vCrs, vYAxis)
vCrs.NegateInPlace()
oTrans.SetRotationFromAxisAngle(vCrs, nAgl)
return oTrans
def MovePointToReferenceTransform(oFace, oItemTrans, oRefTrans, oAllPnts):
''' ポイントをリファレンストランスフォーム上のY=0に移動 '''
lPosArr = [list(t) for t in oAllPnts.PositionArray]
for oPnt in oFace.Points:
vPosOnRef = XSIMath.MapObjectPositionToObjectSpace(oItemTrans, oRefTrans, oPnt.Position)
vPosOnRef.Y = 0
vPosOnRef.ScaleInPlace(10)
vPos = XSIMath.MapObjectPositionToObjectSpace(oRefTrans, oItemTrans, vPosOnRef)
lPosArr[0][oPnt.Index] = vPos.X
lPosArr[1][oPnt.Index] = vPos.Y
lPosArr[2][oPnt.Index] = vPos.Z
oAllPnts.PositionArray = lPosArr
def GetEdgeInfo(oFace):
''' エッジ情報を取得 '''
def GetInfo(oEdge, lPntIndxsOnFace):
oPnts = oEdge.Points
if oPnts[0].Index in lPntIndxsOnFace:
oStartPnt = oPnts[1]
oEndPnt = oPnts[0]
else:
oStartPnt = oPnts[0]
oEndPnt = oPnts[1]
vStart = oStartPnt.Position
vEnd = oEndPnt.Position
vEnd.SubInPlace(vStart)
vStart.SubInPlace(vEnd)
return vStart, vEnd, oEndPnt.Index
oNgbrEdges = oFace.Edges.NeighborEdges()
lPntIndxsOnFace = [oPnt.Index for oPnt in oFace.Points]
lPos = [] #開始位置リスト
lAxis = [] #方向リスト
lPntIdx = [] #対象ポイントインデックスリスト
for oEdge in oNgbrEdges:
lInfo = GetInfo(oEdge, lPntIndxsOnFace)
lPos.extend(lInfo[0].Get2())
lAxis.extend(lInfo[1].Get2())
lPntIdx.append(lInfo[2])
return lPos, lAxis, lPntIdx
def MovePointToRaycastPosition(oGeom, oFace, lEdgeInfo):
''' ポイントをレイキャストした先に移動 '''
oGeom.SetupPointLocatorQueries(3, None, [oFace.Index], -1)
oPntLocations = oGeom.GetRaycastIntersections(lEdgeInfo[0], lEdgeInfo[1], 0)
lPos = oGeom.EvaluatePositions(oPntLocations)
oPnts = oGeom.Points
lPosArr = [list(t) for t in oPnts.PositionArray]
for idx, allidx in enumerate(lEdgeInfo[2]):
lPosArr[0][allidx] = lPos[0][idx]
lPosArr[1][allidx] = lPos[1][idx]
lPosArr[2][allidx] = lPos[2][idx]
oPnts.PositionArray = lPosArr
def main():
oSel = xsi.Selection(0)
if oSel.Type != 'polySubComponent': #ポリゴンが選択されてない場合処理中止
return
#選択ポリゴンのサブコンポーネントからいろいろ取得
oSubCmp = oSel.SubComponent
oFace = oSubCmp.ComponentCollection[0]
oPoly = oFace.Nodes[0]
oItem = oSubCmp.Parent3DObject
xsi.FreezeModeling(oItem) #フリーズしとかないとポイントの移動ができない
oItemTrans = oItem.Kinematics.Global.Transform
oGeom = oItem.ActivePrimitive.Geometry
oAllPnts = oGeom.Points
lPosArr = [list(t) for t in oAllPnts.PositionArray]
oAllPnts.PositionArray = lPosArr #一旦ポイントをいじっとくことで初回実行からちゃんと動く(なぞ)
lEdgeInfo = GetEdgeInfo(oFace) #エッジ情報を保存
lPnts = GetReferencePoints() #参照トランスフォーム作成用ポイントをピックさせる(最低3点)
if not lPnts:
return
oRefTrans = GetReferenceTransform(lPnts) #参照トランスフォームを作成
MovePointToReferenceTransform(oFace, oItemTrans, oRefTrans, oAllPnts) #とりあえず平面化
MovePointToRaycastPosition(oGeom, oFace, lEdgeInfo) #できた面と保存しておいてエッジをレイキャストして補正
xsi.ActivateRaycastPolySelTool()
main()

