__all__ = ["IdNavigationCustom", "instantiate"]
import math
from ActionRegistry import theActionRegistry
from awSupportApi import AffineMatrix, Line, Normal, Point, Vector
from MessageInterpreter import MessageInterpreter
from MessageRegistry import theMessageRegistry
from Modes import SelectionMode
from RTFapi import Event
from UserCustomization import UserCustomBase, CustomInfo
from SceneGraphUtilities import GetNodesFromIds
import ModelIO
CUSTOM_ID_NAVIGATION_ENABLE_Doc = \
[(
"""
Enable or disable custom id navigation feature. When enabled, left mouse
button will tumble the scene or selected objects. When disabled the items
being tumbled are returned to their original transform.
"""
),
[[("state"),("True to enable and False to disable")],
]
]
theMessageRegistry.register("CUSTOM_ID_NAVIGATION_ENABLE",
(bool,), 0, CUSTOM_ID_NAVIGATION_ENABLE_Doc)
class IdNavigationCustom(UserCustomBase):
__kMenuId = u"Edit"
def __init__(self):
self.__myMenu = None
self.__myMenuItemId = None
self.__myInterpreter = IdNavigationInterpreter()
def getInterpreter(self, isInteractive):
if isInteractive:
return self.__myInterpreter
return None
def appendMenuItems(self, id, menu):
if IdNavigationCustom.__kMenuId == id:
self.__myMenu = menu
menu.appendSeparator()
self.__myMenuItemId = menu.appendCheckItem(
_("Custom ID Navigation"), self.OnIdNavigation)
def enableMenuStates(self, id, enableStates):
if IdNavigationCustom.__kMenuId == id:
enableStates[self.__myMenuItemId] = True
def resetMenuStates(self, id):
if IdNavigationCustom.__kMenuId == id:
menuItemStates = {}
menuItemStates[self.__myMenuItemId] = False
self.__myMenu.checkMenuItems(menuItemStates)
def OnIdNavigation(self, event):
isOn = bool(self.__myMenu.IsChecked(self.__myMenuItemId))
self.sendMessage("CUSTOM_ID_NAVIGATION_ENABLE", (isOn,))
class IdNavigationInterpreter(MessageInterpreter):
__kRotateStartKeyMappingId = "RotateStart"
__kRotateKeyMappingId = "Rotate"
class NodeData:
def __init__(self, node):
self.node = node
self.undoMatrix = None
self.startMatrix = None
def __init__(self):
MessageInterpreter.__init__(self)
self.__myDisplay = None
self.__myLastPosition = (0.0, 0.0)
self.__targets = None
self.__myAzimuth = 0.0
self.__myElevation = 0.0
keyMappings = (
(Event.BUTTON_LMB, (), True, Event.BUTTONDOWN, "MyRotateStart"),
)
theActionRegistry.registerList(IdNavigationInterpreter.__kRotateStartKeyMappingId, keyMappings)
keyMappings = (
(Event.BUTTON_LMB, (), False, Event.BUTTONUP, "MyRotateStop")
, (Event.BUTTON_None, (), False, Event.MOVE, "MyRotate")
)
theActionRegistry.registerList(IdNavigationInterpreter.__kRotateKeyMappingId, keyMappings)
def getPosition(self, event):
x = event.getValue(Event.kNormalizedWinX)
y = event.getValue(Event.kNormalizedWinY)
return x, y
def MyRotateStart(self, event):
if self.__myDisplay is None or \
self.__myTargets is None:
return False
self.__myLastPosition = self.getPosition(event)
theActionRegistry.addSetToStack(IdNavigationInterpreter.__kRotateKeyMappingId)
theActionRegistry.activateSet(IdNavigationInterpreter.__kRotateKeyMappingId, True)
for target in self.__myTargets:
target.startMatrix = AffineMatrix(1.0)
target.node.getMatrix( target.startMatrix )
self.__myAzimuth = 0.0
self.__myElevation = 0.0
return True
def MyRotate(self, event):
x, y = self.getPosition(event)
lastX, lastY = self.__myLastPosition
dx = x - lastX
dy = y - lastY
self.__myLastPosition = self.getPosition(event)
rotationMatrix = self.__computeMatrix(dx, dy)
for target in self.__myTargets:
matrix = AffineMatrix(rotationMatrix)
matrix.preMult(target.startMatrix)
target.node.setMatrix(matrix)
return True
def __computeMatrix(self, dx, dy):
matrix = AffineMatrix(1.0)
if self.__myDisplay is None:
return matrix
azimuthDegrees = dx * 180.0
azimuthRadians = math.radians(azimuthDegrees)
elevationDegrees = dy * 90.0
elevationRadians = math.radians(elevationDegrees)
self.__myAzimuth += azimuthRadians
self.__myElevation += elevationRadians
halfpi = math.pi * 0.5
if self.__myElevation < -halfpi:
self.__myElevation = -halfpi + 0.0001
if self.__myElevation > halfpi:
self.__myElevation = halfpi - 0.0001
camera = self.__myDisplay.getCamera()
assert(camera)
pos = Point()
coi = Point()
up = Vector()
camera.getView(pos, coi, up)
view = Vector(coi[0] - pos[0], coi[1] - pos[1], coi[2] - pos[2])
side = up.cross(view)
azimuthAxis = Normal( 0.0, 0.0, 1.0 )
elevationAxis = Normal(side[0], side[1], side[2])
elevationAxis = Line(coi, elevationAxis)
azimuthAxis = Line(coi, azimuthAxis)
matrix.rotate(self.__myElevation, elevationAxis)
matrix.rotate(self.__myAzimuth, azimuthAxis)
return matrix
def MyRotateStop(self, event):
self.__myLastPosition = self.getPosition(event)
theActionRegistry.removeSetFromStack(IdNavigationInterpreter.__kRotateKeyMappingId)
theActionRegistry.activateSet(IdNavigationInterpreter.__kRotateKeyMappingId, False)
return True
def APPLICATION_CLOSE_SCENE(self, message):
self.__myTargets = None
self.__myLastPosition = (0.0, 0.0)
theActionRegistry.removeSetFromStack(IdNavigationInterpreter.__kRotateKeyMappingId)
theActionRegistry.removeSetFromStack(IdNavigationInterpreter.__kRotateStartKeyMappingId)
def CUSTOM_ID_NAVIGATION_ENABLE(self, message):
(isOn,) = message.data
if self.__myDocument is None:
return
models = self.__myDocument.get(ModelIO.id)
if models is None:
return
if isOn:
if models.selected.empty():
self.__myTargets = ( IdNavigationInterpreter.NodeData(models.root), )
else:
self.__myTargets = tuple( IdNavigationInterpreter.NodeData(node)
for node in GetNodesFromIds( models.selected.asTuple() ) )
for target in self.__myTargets:
target.undoMatrix = AffineMatrix(1.0)
target.node.getMatrix( target.undoMatrix )
self.sendMessage("SELECT", ((), SelectionMode.kReplace), requestUndo=False)
theActionRegistry.addSetToStack(IdNavigationInterpreter.__kRotateStartKeyMappingId)
else:
theActionRegistry.removeSetFromStack(IdNavigationInterpreter.__kRotateStartKeyMappingId)
for target in self.__myTargets:
target.node.setMatrix( target.undoMatrix )
target.undoMatrix = None
self.__myTargets = None
theActionRegistry.activateSet(IdNavigationInterpreter.__kRotateStartKeyMappingId, isOn)
def SET_DISPLAY(self, message):
(self.__myDisplay,) = message.data
def SET_DOCUMENT(self, message):
(document,) = message.data
self.__myDocument = document
def instantiate():
return IdNavigationCustom()
def info():
customInfo = CustomInfo()
customInfo.vendor = 'Autodesk'
customInfo.version = '1.0'
customInfo.api = '2013'
customInfo.shortInfo = "Enable or disable custom id navigation feature."
customInfo.longInfo = \
"""When enabled, left mouse button will tumble the scene or selected objects. \
When disabled the items being tumbled are returned to their original transform.
"""
return customInfo