#get a null to follow a specific particle's position and orientation
#Version 1.03
#Author: Julian Johnson (julian@exch.demon.co.uk)
#Date: 13/03/2009
#multiple points can be tagged in multiple clouds. The positions are worked out
#in global space and nulls are dumped at the scene root.


import win32com.client
from win32com.client import constants as c

code = """
oTrans = XSIMath.CreateTransform()
oTempP = XSIMath.CreateVector3()
oTempR = XSIMath.CreateRotation()

def TrackParticle_Update(ctx,Out,Inpointcloud,Intransform):
	oPos = Inpointcloud.Value.Geometry.GetICEAttributeFromName('PointPosition')
	oRot = Inpointcloud.Value.Geometry.GetICEAttributeFromName('orientation')
	ind = ctx.Operator.Parameters("Index").Value
	
	if oPos.IsConstant:
		p = oPos.DataArray[0]
	else:
		try:
			p = oPos.DataArray[ind]
		except IndexError:
			p = oTempP
	if oRot.IsConstant:
		r = oRot.DataArray[0]
	else:
		try:
			r = oRot.DataArray[ind]
		except IndexError:
			r = oTempR
			
	oTrans.Translation = p
	oTrans.Rotation = r
	oTrans2 = XSIMath.MapObjectPoseToWorldSpace(Intransform.Value.Transform,oTrans)
	Out.Value.Transform = oTrans2
	return
"""
	
def main():
	oRoot = Application.ActiveSceneRoot
	oSel = Application.Selection
	if oSel.Count <= 0:
		s = 'You must directly tag some points on the cloud'
		oMessage = XSIUIToolkit.Msgbox(s, c.siMsgOkOnly)
		return
	
	for x in oSel:
		if x.Type != 'pntSubComponent':
			s = 'You must directly tag some points on the cloud'
			oMessage = XSIUIToolkit.Msgbox(s, c.siMsgOkOnly)
			return
		if x.SubComponent.Parent3DObject.Type != 'pointcloud':
			s = 'You have tagged some regular geometry'
			oMessage = XSIUIToolkit.Msgbox(s, c.siMsgOkOnly)
			return
	
	oColl = XSIFactory.CreateObject('XSI.Collection')
	oColl.AddItems(oSel.GetAsText())
	
	for x in oColl:
		for y in x.SubComponent.ElementArray:
			oPC = x.SubComponent.Parent3DObject
			oNull = oRoot.AddNull('Track_ID_%s' % y)
			oOp = XSIFactory.CreateScriptedOp("TrackParticle", code, "Python")
			oOp.AddOutputPort(oNull.Kinematics.Local, "Out")
			oOp.AddInputPort(oPC.ActivePrimitive, "Inpointcloud")
			oOp.AddInputPort(oPC.Kinematics.Local, "Intransform")
			oOp.AddParameter(XSIFactory.CreateParamDef2("Index", 3,y))
			oOp.debug = 0
			oOp.alwaysevaluate = 1
			
			oOp.Connect()

main()






