Notifications
Clear all

[Closed] Calculate mouse direction

I’m creating a scripted manipulator with a circle gizmo that will rotate another box gizmo around a specific axis when the user clicks on it and moves the mouse. I’ve used the light roll angle manipulator example to get it up and running and it works fine up to a certain point, with the main problem being that the gizmo rotates in the opposite direction as the mouse depending on where you first click on the circle. So what I need is a general way to tell if the mouse is moving clockwise or counterclockwise in screen space around the center of the circle gizmo as the user is dragging the cursor around.

I’m going to continue working on what will probably be a really convoluted way of figuring this out, since I’m not much of a math guy. But I thought I’d check here to see if someone knows of a simple, elegant way of getting it.

2 Replies

Hi James,
here is a function to calculate rotation direction, relative to a point, in screenspace. It gets two subsequent mouse positions and calculates the cross product relative to the reference point in screen. Current version uses the center of viewport as reference. Then it tests result vector angle with a vector perpendicular to screen and sort the rotation direction. I hope this helps.

(
    local p2PosScreenPrev = [0,0]
    local p2PosScreenCurr = [0,0]

    function clockWork msg ir obj faceNum shift ctrl alt =
    (
        local nStep = #continue

        case msg of
        (
            #freeMove:
            (
                local p2ReferencePointScreen = getViewSize() / 2.0
                local p3ViewDir = (inverse(getViewTM())).row3

                p2PosScreenPrev = p2PosScreenCurr
                p2PosScreenCurr = mouse.pos

                local p2Vec_1 = p2PosScreenPrev - p2ReferencePointScreen
                local p2Vec_2 = p2PosScreenCurr - p2ReferencePointScreen

                local p3Cross = cross [p2Vec_1.x, p2Vec_1.y, 0] [p2Vec_2.x, p2Vec_2.y, 0]

                if ((dot p3Cross [0,0,1]) >= 0) then
                    format "Rotating Clockwise
"
                else
                    format "Rotating Counterclockwise
"

                nStep = #continue
            )
            #mouseAbort:
            (
                nStep = #stop
            )
        )
            
        return nStep
    )
    
    mouseTrack trackCallback:clockWork
)
  • Enrico

Yeah, that did the trick. Here’s a quick example of how I’m using it (sort of, I’m not actually creating and deleting boxes).

plugin simpleManipulator rotationTest
 	name:"Rotation Test"
 	invisible:true
 (
 	local unSelClr = colorMan.getColor #manipulatorsActive
 	local selClr = colorMan.getColor #manipulatorsSelected
 	local curRot
 	local lastM = [0,0]
 	local objP =[0,0]
 	local tempObj
 	
 	fn mapWorldToScreen pos =
 	(
 		width=gw.getWinSizeX()
 		height=gw.getWinSizeY()
 
 		thePos = pos * viewport.getTM()
 		screenOrigin = mapScreenToView [0,0] (thePos.z) [width,height]
 
 		worldSize = screenOrigin*2
 		xAspect = width/(abs worldSize.x)
 		yAspect = height/(abs worldSize.y)
 
 		screenPos=point2 (xAspect *(thePos.x-screenOrigin.x)) (-(yAspect*(thePos.y-screenOrigin.y)))
 		if (screenPos.x) < 0 then (screenPos.x=0)
 		if (screenPos.y) < 0 then (screenPos.y=0)
 		
 		screenPos.x = screenPos.x as integer
 		screenPos.y = screenPos.y as integer
 		
 		screenPos
 	)
 	
 	fn normalizeAngle a =
 	(
 		mod a 360
 	)
 	
 	on canManipulateNode target do
 	(
 		(superClassOf target == helper)
 	)
 
 	on updateGizmos do
 	(
 		local giz
 		this.clearGizmos()
 		-- gizmo circle
 		giz = manip.makeCircle [0,0,0] 10 28
 		giz.transform (matrix3 [0,0,1] [0,1,0] [1,0,0] [0,0,0])
 		this.addGizmoShape giz 16 unSelClr selClr
 		if isValidNode tempObj then
 		(
 			tempObj.name + " [X Rotation: " + (tempObj.rotation.controller[1].value as string) + "]"
 		)
 		else
 		(
 			""
 		)
 	)
 	
 	on mouseDown m which do
 	(
 		if not isValidNode tempOb then
 		(
 			tempObj = box name:"tempRotationObject" pos:node.pos wirecolor:red
 		)
 		
 		lastM = m
 		objP = mapWorldToScreen node.pos
 		if keyboard.shiftPressed then
 		(
 			curRot = 0
 		)
 		else
 		(
 			curRot = normalizeAngle tempObj.rotation.controller[1].value
 		)
 		tempObj.rotation.controller[1].value = curRot
 	)
 	
 	on mouseMove m which do
 	(
 		m = m
 		p2Vec_1 = lastM - objP
 		p2Vec_2 = m - objP
 		p3Vec_1 = [p2Vec_1.x, p2Vec_1.y, 0]
 		p3Vec_2 = [p2Vec_2.x, p2Vec_2.y, 0]
 		p3Cross = cross p3Vec_1 p3Vec_2
 		rotVal = distance p3Vec_1 p3Vec_2
 		if ((dot p3Cross [0,0,1]) >= 0) then
 		(
 			curRot += rotVal
 		)
 		else
 		(
 			curRot -= rotVal
 		)
 		tempObj.rotation.controller[1].value = curRot
 		lastM = m
 	)
 	
 	on mouseUp m which do
 	(
 		if isValidNode tempObj then
 		(
 			delete tempObj
 		)
 	)
 )
 
 select (point())
 manipulateMode = true