Rotation of one object relative to another


#1

Hello . I’m trying to rotate one object relative to another. But it’s not like it doesn’t work so that when the slider changes, it’s smooth.

In 1 case, I managed to make it rotate, but there it constantly adds value when the slider changes.
In 2 cases, I managed to make a smooth rotation, but for some reason it rotates relative to 0 coordinates.

Help solve the problem.

try (destroydialog Transformer) catch()
 
rollout Transformer "Transformer" width:200
(
	local nodeRoot
	local originTM = #()
	local nodeArray = #()
 
	group "Position: "
	(
		dotNetControl pos_x "System.Windows.Forms.TrackBar"  pos:[6,26] width:188 height:25
		dotNetControl pos_y "System.Windows.Forms.TrackBar"  pos:[6,53] width:188 height:25
		dotNetControl pos_z "System.Windows.Forms.TrackBar"  pos:[6,80] width:188 height:25
	)
	group "Position: "
	(
		dotNetControl rot_x "System.Windows.Forms.TrackBar"  pos:[6,138] width:188 height:25
		dotNetControl rot_y "System.Windows.Forms.TrackBar"  pos:[6,165] width:188 height:25
		dotNetControl rot_z "System.Windows.Forms.TrackBar"  pos:[6,192] width:188 height:25
	)
 
	button hold_tm_bt "Hold Transform" width:190 
	button reset_tm_bt "Zero Offset" width:190 
 
	fn transform_Relatively nodeArray node_root rot_x:0 rot_y:0 rot_z:0 = 
	(
		local obj_Trans = #()
 
		if nodeArr.count > 0 do
		(
			for i = 1 to nodeArr.count do
			(
				offset_rot = (eulerangles rot_x rot_y rot_z)
				node_trans = nodeArray[i].transform
				in coordsys (transmatrix node_root.transform.pos) nodeArray[i].rotation *= offset_rot
			)
		)
	)
 
	on rot_z MouseUp do
	(
		print "UP"
	)
 
	on  rot_z  ValueChanged val do
	( 
        nodeArray = selection as array
		Transform_Relatively nodeArray nodeRoot rot_x:rot_x.value rot_y:rot_y.value rot_z:rot_z.value
	) 
 
	on hold_tm_bt pressed do if isvalidnode (node = selection[1]) do
	(
		nodeArray = selection as array
		Transform_Relatively nodeArray nodeRoot rot_x:rot_x.value rot_y:rot_y.value rot_z:rot_y.value
	)
	on reset_tm_bt pressed do
	(
		nodeRoot = selection[1]
	)
 
)
createdialog Transformer
 
 
try (destroydialog Transformer) catch()
 
struct ANIM_DATA (bone_name, bone_transform)

rollout Transformer "Transformer" width:200
(
	local nodeRoot
	local originTM = #()
	local nodeArray = #()
 
	group "Position: "
	(
		 dotNetControl pos_x "System.Windows.Forms.TrackBar"  pos:[6,26] width:188 height:25
		dotNetControl pos_y "System.Windows.Forms.TrackBar"  pos:[6,53] width:188 height:25
		dotNetControl pos_z "System.Windows.Forms.TrackBar"  pos:[6,80] width:188 height:25
	)
	group "Position: "
	(
		dotNetControl rot_x "System.Windows.Forms.TrackBar"  pos:[6,138] width:188 height:25
		dotNetControl rot_y "System.Windows.Forms.TrackBar"  pos:[6,165] width:188 height:25
		dotNetControl rot_z "System.Windows.Forms.TrackBar"  pos:[6,192] width:188 height:25
	)
 
	button hold_tm_bt "Hold Transform" width:190 
	button reset_tm_bt "Zero Offset" width:190 
 
	fn transform_Relatively nodeArray originTM node_root rot_x:0 rot_y:0 rot_z:0 = 
	(
		local obj_Trans = #()
 
		if nodeArray.count > 0 do
		(
			for i = 1 to nodeArray.count do
			(
				offset_rot = (eulerangles rot_x rot_y rot_z) as matrix3
				node_trans = originTM[i]
 
				in coordsys (transmatrix node_root.transform.pos) node_trans *= offset_rot
				--in coordsys node_root ( node_trans *= offset_rot )
 
				append obj_Trans ( ANIM_DATA nodeArray[i].name node_trans )
			)
 
		)
			for data in obj_Trans do
			(
				obj = getNodeByName data.bone_name
				if obj == undefined do continue
				--add world transform
				obj.transform  = data.bone_transform
			)
 
	)
 
	on rot_z MouseDown do
	(
		originTM = #()
 
		if isvalidnode (node = selection[1]) do
		(
			nodeArray = mcBiped.sort_NodeByHeirarchy()
 
			for i = 1 to nodeArr.count do
			(
				append originTM nodeArray[i].transform
			)
		)
	)
 
	on rot_z MouseUp do
	(
		originTM = #()
		nodeArray = mcBiped.sort_NodeByHeirarchy()
 
		for i = 1 to nodeArr.count do
		(
			append originTM nodeArray[i].transform
		)
		rot_z.value = 0
	)
 
	on  rot_z  ValueChanged val do
	( 
		Transform_Relatively nodeArray originTM nodeRoot rot_x:rot_x.value rot_y:rot_y.value rot_z:rot_z.value
	) 
 
	on hold_tm_bt pressed do if isvalidnode (node = selection[1]) do
	(
		nodeArray = mcBiped.sort_NodeByHeirarchy()
 
		originTM = #()
		nodeArray = mcBiped.sort_NodeByHeirarchy()
 
		for i = 1 to nodeArr.count do
		(
			append originTM nodeArray[i].transform
		)
 
 		Transform_Relatively nodeArray originTM nodeRoot rot_x:rot_x.value rot_y:rot_y.value rot_z:45
	)
	on reset_tm_bt pressed do
	(
		nodeRoot = selection[1]
	)
 
 
)
createdialog Transformer

#2
try(destroydialog RelativeTransformRol) catch()
deleteAllChangeHandlers id:#my_relative_transform

rollout RelativeTransformRol "Relative Transform" width:261
(
	local coordsys_node = coordsys_node
	
	group "Coordsys Node: "
	(
		pickbutton pick_coordsys_bt "< Pick Coordsys Node >" width:242 autodisplay:on align:#left offset:[-4,2] filter:isvalidnode \
			tooltip:"Pick a node to be used as a coordsys"
	)
	label emp_00 height:4
	
	local xrot_control = bezier_float()
	local yrot_control = bezier_float()
	local zrot_control = bezier_float()
	
	local xpos_control = bezier_float()
	local ypos_control = bezier_float()
	local zpos_control = bezier_float()
	
	group "Rotation: "
	(
		slider x_rot_sl "" type:#float range:[-360,360,0] ticks:0 width:180 align:#left offset:[-4,2] across:2
		spinner x_rot_sp "" type:#float range:[-360,360,0] fieldwidth:60 align:#right offset:[4,4]
		
		slider y_rot_sl "" type:#float range:[-360,360,0] ticks:0 width:180 align:#left offset:[-4,2] across:2
		spinner y_rot_sp "" type:#float range:[-360,360,0] fieldwidth:60 align:#right offset:[4,4]
		
		slider z_rot_sl "" type:#float range:[-360,360,0] ticks:0 width:180 align:#left offset:[-4,2] across:2
		spinner z_rot_sp "" type:#float range:[-360,360,0] fieldwidth:60 align:#right offset:[4,4]
	)

	label emp_01 height:0

	group "Position: "
	(
		slider x_pos_sl "" type:#float range:[0,100,0] ticks:0 width:180 align:#left offset:[-4,2] across:2
		spinner x_pos_sp "" type:#float range:[0,100,0] fieldwidth:60 align:#right offset:[4,4]
		
		slider y_pos_sl "" type:#float range:[0,100,0] ticks:0 width:180 align:#left offset:[-4,2] across:2
		spinner y_pos_sp "" type:#float range:[0,100,0] fieldwidth:60 align:#right offset:[4,4]
		
		slider z_pos_sl "" type:#float range:[0,100,0] ticks:0 width:180 align:#left offset:[-4,2] across:2
		spinner z_pos_sp "" type:#float range:[0,100,0] fieldwidth:60 align:#right offset:[4,4]
	)
	
	button update_transform_bt "Update" width:119 align:#left offset:[-4,8] across:2 \
		tooltip:"Update Transform"
	button reset_zero_bt "Zero Transform" width:119 align:#right offset:[4,8] \
		tooltip:"Zero Transform"

	label info_lb "info..." width:172 align:#left offset:[-4,6]


	fn updateRelativeTransform = if isvalidnode coordsys_node do
	(
		tm = copy coordsys_node.transform
		
		prerotateX tm xrot_control.value
		prerotateY tm yrot_control.value
		prerotateZ tm zrot_control.value
		
		pretranslate tm [xpos_control.value, ypos_control.value, zpos_control.value]
		
		nodes = for node in selection where node != coordsys_node collect node
		if nodes.count do nodes.transform = tm
	)

	on pick_coordsys_bt picked obj do
	(
		if isvalidnode obj do 
		(
			coordsys_node = obj
			when transform coordsys_node change id:#my_relative_transform do updateRelativeTransform()
			updateRelativeTransform()
			redrawviews()
		)
	)
	on pick_coordsys_bt rightclick do 
	(
		if isvalidnode (node = selection[1]) do
		(
			pick_coordsys_bt.object = coordsys_node = node
			when transform coordsys_node change id:#my_relative_transform do updateRelativeTransform()
			updateRelativeTransform()
			redrawviews()
		)
	)

	on update_transform_bt pressed do 
	(
		updateRelativeTransform() 
		redrawviews()
	)
	on reset_zero_bt pressed do undo "Zero Transform" on 
	(
		xrot_control.value = yrot_control.value = zrot_control.value = 0
		xpos_control.value = ypos_control.value = zpos_control.value = 0
		
		updateRelativeTransform() 
		redrawviews()
	)
	
	local tm_controls = #(xrot_control, yrot_control, zrot_control, xpos_control, ypos_control, zpos_control)
		
	on RelativeTransformRol open do
	(
		deleteAllChangeHandlers id:#my_relative_transform
	)
	
	on RelativeTransformRol open do
	(
		x_rot_sl.controller = x_rot_sp.controller = xrot_control
		y_rot_sl.controller = y_rot_sp.controller = yrot_control
		z_rot_sl.controller = z_rot_sp.controller = zrot_control

		x_pos_sl.controller = x_pos_sp.controller = xpos_control
		y_pos_sl.controller = y_pos_sp.controller = ypos_control
		z_pos_sl.controller = z_pos_sp.controller = zpos_control
		
		when geometry tm_controls change id:#my_relative_transform do updateRelativeTransform()
		
		if isvalidnode coordsys_node do 
		(
			pick_coordsys_bt.object = coordsys_node
			when transform coordsys_node change id:#my_relative_transform do updateRelativeTransform()
		)
		updateRelativeTransform()
		redrawviews()
	)
)
createdialog RelativeTransformRol escapeEnable:true

the most complicated part is to organize the right UI and parameter notifications. I would probably do it using a CustAttribute(s).


#3

denisT thanks for the hint. I completely forgot about - prerotateX.

I modified it a little here, as I needed the selected objects to retain their original transform relative to the pivot point. And after changing the slider, it returned back to 0 and the offset transformation was saved.
If you can optimize it a little, I’ll be glad to see it. Thanks in advance.

try (destroydialog Transformer) catch()

rollout Transformer "Transformer by denisT" width:200
(
	local nodeRoot
	local originTM = #()
	local rootTM = #()
	local offsetTM = #()
	local nodeArray = #()
	
	group "Rotation Offset "
	(
		dotNetControl rot_x "System.Windows.Forms.TrackBar"  pos:[6,26] width:188 height:25
		dotNetControl rot_y "System.Windows.Forms.TrackBar"  pos:[6,53] width:188 height:25
		dotNetControl rot_z "System.Windows.Forms.TrackBar"  pos:[6,80] width:188 height:25
	)
	
	button hold_tm_bt "Hold Transform" width:190 
	button reset_tm_bt "Zero Offset" width:190 
	
	fn get_Origin_pos =
	(
		originTM = #()
		
		if isvalidnode (node = selection[1]) do
		(
			nodeArray = selection as array
			
			for i = 1 to nodeArray.count do
			(
				offsetTM	= in coordsys nodeRoot nodeArray[i].pos
				rootTM		= in coordsys nodeRoot nodeArray[i].rotation
					
				append originTM #(offsetTM, rootTM)
			)
		)
	)
	
	fn transform_Relatively nodeArray originTM node_root rot_x:0 rot_y:0 rot_z:0 = 
	(
		for i = 1 to nodeArray.count  where nodeArray[i] != node_root do
		(
			tm = copy node_root.transform
			
			prerotateX tm rot_x
			prerotateY tm rot_y
			prerotateZ tm rot_z
			
			pretranslate tm originTM[i][1]
					
			nodeArray[i].transform = tm
			nodeArray[i].rotation *= originTM[i][2]
			nodeArray[i].position = tm.position
		)
	)
	
	
	on rot_z MouseDown do
	(
		print "Down"
		get_Origin_pos()
 		
	)
	
	on rot_z MouseUp do
	(
		print "UP"
		get_Origin_pos()
		rot_z.value = 0
	)
	
	on  rot_z ValueChanged val do if isvalidnode (node = selection[1]) do
	( 
        nodeArray = selection as array
		transform_Relatively nodeArray originTM nodeRoot rot_x:rot_x.value rot_y:rot_y.value rot_z:rot_z.value
	) 
		
	on hold_tm_bt pressed do if isvalidnode (node = selection[1]) do
	(
		rot_z.value = 0
	)
	on reset_tm_bt pressed do
	(
		with redraw off
		(
			--delete objects
			--Rot  = dummy name:#target pos:(random -[10,10,10] [10,10,10]) dir:(random -[1,1,1] [1,1,1]) isselected:on
			nodeRoot = selection[1]
		)
		
		--rot_x.value = rot_y.value = rot_z.value = pos_x.value = pos_y.value = pos_z.value = 0
		--transformNode()
	)
	
	on Transformer open do
	(
		rot_z.Maximum = 360
		rot_z.Minimum = -360
		rot_z.Value = 0
		
		
	)
	
)
createdialog Transformer

#4

True, this does not work with biprd objects.