Interactive/TerrainCollision.py

########################################################################################################################
## Shows how to navigate the camera in the X/Y/Z directions while checking if it goes through a navigation mesh (checks for terrain collision).
## Recommended to be used with sample scene: Simple_Scene5.a3s
########################################################################################################################
##
## (C) Copyright 2012 Autodesk, Inc.  All rights reserved.
##
## Use of this software is subject to the terms of the Autodesk license
## agreement provided at the time of installation or download, or which
## otherwise accompanies this software in either electronic or hard copy
## form.
##

__all__ = ['TerrainCollision', 'instantiate']

from ActionRegistry     import theActionRegistry
from awSupportApi       import ApplicationMode, Point, Vector
from MessageInterpreter import MessageInterpreter
from DialogInterpreter  import DialogFactory
from UserCustomization  import UserCustomBase, CustomInfo
from WarningWindow      import WarningWindow

from DisplayUtilities   import GetCameras
from RTFapi             import KynapseManager, \
                               Event
               
kMeshNavigation = 'MeshNavigationId'

keyMappings = (
  ( Event.BUTTON_Left, ( Event.BUTTON_Shift, ),  True, Event.BUTTONDOWN, 'OnNavigateCameraNegX' )
, ( Event.BUTTON_Right, ( Event.BUTTON_Shift, ), True, Event.BUTTONDOWN, 'OnNavigateCameraPlusX' )
, ( Event.BUTTON_Down, ( Event.BUTTON_Shift, ), True,  Event.BUTTONDOWN, 'OnNavigateCameraNegY' )
, ( Event.BUTTON_Up, ( Event.BUTTON_Shift, ), True, Event.BUTTONDOWN,   'OnNavigateCameraPlusY' )
, ( Event.BUTTON_Down, ( Event.BUTTON_Control, ), True,  Event.BUTTONDOWN, 'OnNavigateCameraNegZ' )
, ( Event.BUTTON_Up, ( Event.BUTTON_Control, ), True,  Event.BUTTONDOWN, 'OnNavigateCameraPlusZ' )
)
theActionRegistry.registerList( kMeshNavigation, keyMappings )

kNavigationUnit = 100
class TerrainCollision(UserCustomBase):
    
    def __init__(self):
        self.__myNavigationMenu = None
        self.__myNavigateMinusX = None
        self.__myNavigatePlusX = None
        self.__myNavigateMinusY = None
        self.__myNavigatePlusY = None
        self.__myInterpreter = LocalInterpreter()

    def getInterpreter(self,isInteractive):
        if isInteractive:
            return self.__myInterpreter
        return None
    
    def appendMenuItems(self,id,menu):
        if "View" == id:
            self.__myNavigationMenu = menu
            self.__myNavigateMinusX = menu.appendItem(_( 'Navigate Camera in negative X direction\tShift+Left Arrow' ),
                                                   self.__onNavigateCameraNegX )
                        
            self.__myNavigatePlusX = menu.appendItem(_( 'Navigate Camera in positive X direction\tShift+Right Arrow' ),
                                                   self.__onNavigateCameraPlusX )

            self.__myNavigateMinusY = menu.appendItem(_( 'Navigate Camera in negative Y direction\tShift+Down Arrow' ),
                                                   self.__onNavigateCameraNegY )

            self.__myNavigatePlusY = menu.appendItem(_( 'Navigate Camera in positive Y direction\tShift+Up Arrow' ),
                                                   self.__onNavigateCameraPlusY )
                                                   
            self.__myNavigateMinusZ = menu.appendItem(_( 'Navigate Camera in negative Z direction\tCtrl+Down Arrow' ),
                                                   self.__onNavigateCameraNegZ )

            self.__myNavigatePlusZ = menu.appendItem(_( 'Navigate Camera in positive Z direction\tCtrl+Up Arrow' ),
                                                   self.__onNavigateCameraPlusZ )
                           
                                   
    def enableMenuStates(self,id,enableStates):
        if "View" == id:
            enabled = (self.__myInterpreter.Enabled() if self.__myInterpreter else False)
            
            enableStates[self.__myNavigateMinusX] = enabled
            enableStates[self.__myNavigatePlusX] = enabled
            enableStates[self.__myNavigateMinusY] = enabled
            enableStates[self.__myNavigatePlusY] = enabled
            enableStates[self.__myNavigateMinusZ] = enabled
            enableStates[self.__myNavigatePlusZ] = enabled

    # ------------------------------------------------
    def __onNavigateCameraNegX( self, event ):
        self.__myInterpreter.NavigateCamera( Vector( -kNavigationUnit, 0.0, 0.0) )

    def __onNavigateCameraPlusX( self, event ):
        self.__myInterpreter.NavigateCamera( Vector( kNavigationUnit, 0.0, 0.0) )

    def __onNavigateCameraNegY( self, event ):
        self.__myInterpreter.NavigateCamera( Vector( 0.0, -kNavigationUnit, 0.0) )

    def __onNavigateCameraPlusY( self, event ):
        self.__myInterpreter.NavigateCamera( Vector( 0.0, kNavigationUnit, 0.0) )
        
    def __onNavigateCameraNegZ( self, event ):
        self.__myInterpreter.NavigateCamera( Vector( 0.0, 0.0, -kNavigationUnit) )

    def __onNavigateCameraPlusZ( self, event ):
        self.__myInterpreter.NavigateCamera( Vector( 0.0, 0.0, kNavigationUnit) )
        
#-------------------------------------------------------------------------------------------------------

class LocalInterpreter( MessageInterpreter ):
    def __init__( self ):
        MessageInterpreter.__init__( self )
        self.__myDisplay = None
                            
        self.__myKynapseMeshExists = False
        self.__myKynapseEnabled = False
                    
    def __navigateCamera( self, axisChangeDistance ):
        if self.__myDisplay:
            for camera in GetCameras( self.__myDisplay ):
                position = camera.getPosition()
                fromPoint = camera.getPosition()
                coi = camera.getCOI()
                position += axisChangeDistance
                coi+= axisChangeDistance
                toPoint = position
                finalPoint = self.canNavigate(fromPoint, toPoint)
                camera.setPosition( finalPoint )
                camera.setCOI( coi )

#-------------------------------------------------------------------------------------------------------
    def OnNavigateCameraNegX( self, event ):
        self.NavigateCamera( Vector( -kNavigationUnit, 0.0, 0.0) )
        return True
        
    def OnNavigateCameraPlusX( self, event ):
        self.NavigateCamera( Vector( kNavigationUnit, 0.0, 0.0) )
        return True
        
    def OnNavigateCameraNegY( self, event ):
        self.NavigateCamera( Vector( 0.0, -kNavigationUnit, 0.0) )
        return True
        
    def OnNavigateCameraPlusY( self, event ):
        self.NavigateCamera( Vector( 0.0, kNavigationUnit, 0.0) )
        return True
        
    def OnNavigateCameraNegZ( self, event ):
        self.NavigateCamera( Vector( 0.0, 0.0, -kNavigationUnit) )
        return True
        
    def OnNavigateCameraPlusZ( self, event ):
        self.NavigateCamera( Vector( 0.0, 0.0, kNavigationUnit) )
        return True
        
    def NavigateCamera( self, axisChangeDistance ):
        if self.__myKynapseMeshExists and self.__myKynapseEnabled:
            self.__navigateCamera( axisChangeDistance )
                
        else:
            print "Please turn on walk zone"
            warning=_("This function requires walk zone to be enabled. \n\nTo enable walk zone, under menu, go to Edit -> Walk Zone.. then click the \"Make Walk Zone\" button.")
            if DialogFactory.ready():
                DialogFactory.instance().destroy(WarningWindow)
                DialogFactory.instance().show( WarningWindow,
                        title=_("Walk Zone Required"),
                        message=warning,
                        continueButtonLabel=_("OK"),
                        cancelButtonLabel=None )        
            
        return True
#-------------------------------------------------------------------------------------------------------        
        
    def canNavigate( self, fromPoint, toPoint ):
        kynapse = KynapseManager.instance()
        nearestPoint = Point( 0.0, 0.0, 0.0 )
        kynapse.canGo( fromPoint, toPoint, nearestPoint )
        return nearestPoint
        
    def SET_DISPLAY( self, message ):
        ( self.__myDisplay, ) = message.data
        
    def DOCUMENT_LOADED( self, message ):
        theActionRegistry.addSetToStack( kMeshNavigation )
        theActionRegistry.activateSet( kMeshNavigation, True )
            
    def Enabled( self ):
        return ApplicationMode.instance().isAuthoringMode() \
           and self.__myDisplay is not None 
            
    def DOCUMENT_CLOSED( self, message ):
        self.__myKynapseMeshExists = False
        theActionRegistry.activateSet( kMeshNavigation, False )
        theActionRegistry.removeSetFromStack( kMeshNavigation )

    def KYNAPSE_NAVIGATION_MESH_CHANGED ( self, message ):
        self.__myKynapseMeshExists = KynapseManager.instance().hasPathData()

    def KYNAPSE_ENABLED ( self, message):
        (self.__myKynapseEnabled, ) = message.data
        
#-------------------------------------------------------------------------------------------------------

def instantiate():
    return TerrainCollision()

def info():
    customInfo = CustomInfo()
    customInfo.vendor = 'Autodesk'
    customInfo.version = '2.0'
    customInfo.api = '2013'
    customInfo.shortInfo = "Navigates the camera in any direction and checks if it goes through any terrain."
    customInfo.longInfo = \
"""Add six menu items under "View" menu to navigate the camera in the positive and negative X/Y/Z axis.
"""
    return customInfo