29 from maya.api 
import OpenMaya, OpenMayaUI, OpenMayaRender
 
   30 from maya 
import OpenMayaRender 
as OpenMayaRenderV1
 
   32 logger = logging.getLogger(
'SquareScaleManipContext')
 
   42     This utility class represents a mathematical plane and performs intersection 
   47         Initialze the member variables of the class. 
   54     def set_plane( self, point_on_plane, normal_to_plane ):
 
   56         Define the plane by supplying a point on the plane and the plane's normal. 
   59         _normal_to_plane.normalize()
 
   62         self.a = _normal_to_plane.x
 
   63         self.b = _normal_to_plane.y
 
   64         self.c = _normal_to_plane.z
 
   65         self.d = -(self.a*point_on_plane.x + self.b*point_on_plane.y + self.c*point_on_plane.z)
 
   67     def intersect( self, line ):
 
   69         Intersect the plane with the given line.  Return the intersection point if an intersection 
   70         occurs.  Otherwise, raise an exception. 
   72         denominator = self.a*line[1].x + self.b*line[1].y + self.c*line[1].z
 
   75         if (denominator < .00001):
 
   78         t = -(self.d + self.a*line[0].x + self.b*line[0].y + self.c*line[0].z) / denominator
 
   81         return line[0] + t * line[1]
 
   85     This utility class represents a mathematical line and returns the closest point 
   86     on the line to a given point. 
   90         Initialze the member variables of the class. 
   95     def set_line( self, line_point, line_direction ):
 
   97         Define the line by supplying a point on the line and the line's direction. 
  101         self.direction.normalize()
 
  103     def closest_point( self, to_point ):
 
  105         Determine and return the point on the line which is closest to the given point. 
  107         t = self.direction * ( to_point - self.point )
 
  108         return self.point + ( self.direction * t )
 
  110 class SquareGeometry:
 
  112     This utility class defines methods for returning the four corner points of a unit square 
  118         Return the top left corner of the square. 
  124         Return the top right corner of the square. 
  130         Return the bottom left corner of the square. 
  136         Return the bottom right corner of the square. 
  146     This is the subclassed manipulator node.  It scales the selected objects 
  147     in the X direction based on dragging movements by the user. 
  149     kNodeName = 
'SquareScaleContextManipulator' 
  154         Initialize the manipulator member variables. 
  159         self.point_on_plane = SquareGeometry.top_left()
 
  163         self.right_index = -1
 
  164         self.bottom_index = -1
 
  168         self.bottom_name = -1
 
  175         self.translate_x = 0.0
 
  176         self.translate_y = 0.0
 
  177         self.translate_z = 0.0
 
  182         self.normal_to_plane = v1 ^ v2
 
  185         self.normal_to_plane.normalize()
 
  186         self.plane = PlaneMath()
 
  187         self.plane.set_plane( self.point_on_plane, self.normal_to_plane )
 
  199     def postConstructor(self):
 
  200         self.top_index = self.addDoubleValue( 
'topValue', 0 )
 
  201         self.right_index = self.addDoubleValue( 
'rightValue', 0 )
 
  202         self.bottom_index = self.addDoubleValue( 
'bottomValue', 0 )
 
  203         self.left_index = self.addDoubleValue( 
'leftValue', 0 )
 
  205         gl_pickable_item = self.glFirstHandle()
 
  206         self.top_name = gl_pickable_item
 
  207         self.bottom_name = gl_pickable_item + 1
 
  208         self.right_name = gl_pickable_item + 2
 
  209         self.left_name = gl_pickable_item + 3
 
  212     def connectToDependNode(self, depend_node):
 
  214         Connect the manipulator to the given dependency node. 
  223             scale_x_plug = nodeFn.findPlug(
'scaleX', 
True)
 
  225             logger.info(
"    Could not find scaleX plug!")
 
  230             plug_index = self.connectPlugToValue(scale_x_plug, self.right_index)
 
  232             logger.info(
"    Could not connectPlugToValue!")
 
  235         self.finishAddingManips()
 
  240         Update the region dragged by the mouse. 
  244         tl = SquareGeometry.top_left()
 
  245         tr = SquareGeometry.top_right()
 
  246         bl = SquareGeometry.bottom_left()
 
  247         br = SquareGeometry.bottom_right()
 
  251         active = self.glActiveName()
 
  253             if ( active == self.top_name ):
 
  254                 tl += self.mouse_point_gl_name
 
  255                 tr += self.mouse_point_gl_name
 
  256             if ( active == self.bottom_name ):
 
  257                 bl += self.mouse_point_gl_name
 
  258                 br += self.mouse_point_gl_name
 
  259             if ( active == self.right_name ):
 
  260                 tr += self.mouse_point_gl_name
 
  261                 br += self.mouse_point_gl_name
 
  262             if ( active == self.left_name ):
 
  263                 tl += self.mouse_point_gl_name
 
  264                 bl += self.mouse_point_gl_name
 
  266         return [tl, tr, bl, br]
 
  269     def draw(self, view, path, style, status):
 
  271         Draw the manupulator in a legacy viewport. 
  275         gl_renderer = OpenMayaRenderV1.MHardwareRenderer.theRenderer()
 
  276         gl_ft = gl_renderer.glFunctionTable()
 
  278         [tl, tr, bl, br] = self.pre_draw()
 
  285         gl_ft.glMatrixMode( OpenMayaRenderV1.MGL_MODELVIEW )
 
  287         gl_ft.glTranslatef( self.translate_x, self.translate_y, self.translate_z )
 
  288         gl_ft.glRotatef( math.degrees(self.rotate_z), 0.0, 0.0, 1.0 )
 
  289         gl_ft.glRotatef( math.degrees(self.rotate_y), 0.0, 1.0, 0.0 )
 
  290         gl_ft.glRotatef( math.degrees(self.rotate_x), 1.0, 0.0, 0.0 )
 
  294         self.colorAndName( view, self.top_name, 
False, self.mainColor() )
 
  295         gl_ft.glBegin( OpenMayaRenderV1.MGL_LINES )
 
  296         gl_ft.glVertex3f( tl.x, tl.y, tl.z )
 
  297         gl_ft.glVertex3f( tr.x, tr.y, tr.z )
 
  301         self.colorAndName( view, self.right_name, 
True, self.mainColor() )
 
  302         gl_ft.glBegin( OpenMayaRenderV1.MGL_LINES )
 
  303         gl_ft.glVertex3f( tr.x, tr.y, tr.z )
 
  304         gl_ft.glVertex3f( br.x, br.y, br.z )
 
  308         self.colorAndName( view, self.bottom_name, 
False, self.mainColor() )
 
  309         gl_ft.glBegin( OpenMayaRenderV1.MGL_LINES )
 
  310         gl_ft.glVertex3f( br.x, br.y, br.z )
 
  311         gl_ft.glVertex3f( bl.x, bl.y, bl.z )
 
  315         self.colorAndName( view, self.left_name, 
True, self.mainColor() )
 
  316         gl_ft.glBegin( OpenMayaRenderV1.MGL_LINES )
 
  317         gl_ft.glVertex3f( bl.x, bl.y, bl.z )
 
  318         gl_ft.glVertex3f( tl.x, tl.y, tl.z )
 
  328     def preDrawUI(self, view):
 
  330         Cache the viewport for use in VP 2.0 drawing. 
  335     def drawUI(self, draw_manager, frame_context):
 
  337         Draw the manupulator in a VP 2.0 viewport. 
  340         [tl, tr, bl, br] = self.pre_draw()
 
  343         xform.rotateByComponents([math.degrees(self.rotate_x), \
 
  344                                   math.degrees(self.rotate_y), \
 
  345                                   math.degrees(self.rotate_z), \
 
  346                                   OpenMaya.MTransformationMatrix.kZYX], \
 
  347                                   OpenMaya.MSpace.kWorld)
 
  349         mat = xform.asMatrix()
 
  356         draw_manager.beginDrawable(OpenMayaRender.MUIDrawManager.kNonSelectable, self.top_name)
 
  357         self.setHandleColor(draw_manager, self.top_name, self.dimmedColor())
 
  358         draw_manager.line(tl, tr)
 
  359         draw_manager.endDrawable()
 
  362         draw_manager.beginDrawable(OpenMayaRender.MUIDrawManager.kSelectable, self.right_name)
 
  363         self.setHandleColor(draw_manager, self.right_name, self.mainColor())
 
  364         draw_manager.line(tr, br)
 
  365         draw_manager.endDrawable()
 
  368         draw_manager.beginDrawable(OpenMayaRender.MUIDrawManager.kNonSelectable, self.bottom_name)
 
  369         self.setHandleColor(draw_manager, self.bottom_name, self.dimmedColor())
 
  370         draw_manager.line(br, bl)
 
  371         draw_manager.endDrawable()
 
  374         draw_manager.beginDrawable(OpenMayaRender.MUIDrawManager.kSelectable, self.left_name)
 
  375         self.setHandleColor(draw_manager, self.left_name, self.mainColor())
 
  376         draw_manager.line(bl, tl)
 
  377         draw_manager.endDrawable()
 
  380     def doPress( self, view ):
 
  382         Handle the mouse press event in a VP2.0 viewport. 
  385         self.mouse_point_gl_name = OpenMaya.MPoint.kOrigin
 
  386         self.update_drag_information()
 
  389     def doDrag( self, view ):
 
  391         Handle the mouse drag event in a VP2.0 viewport. 
  393         self.update_drag_information()
 
  396     def doRelease( self, view ):
 
  398         Handle the mouse release event in a VP2.0 viewport. 
  402     def set_draw_transform_info( self, rotation, translation ):
 
  404         Store the given rotation and translation. 
  406         self.rotate_x = rotation[0]
 
  407         self.rotate_y = rotation[1]
 
  408         self.rotate_z = rotation[2]
 
  409         self.translate_x = translation[0]
 
  410         self.translate_y = translation[1]
 
  411         self.translate_z = translation[2]
 
  413     def update_drag_information( self ):
 
  415         Update the mouse's intersection location with the manipulator 
  418         self.local_mouse = self.mouseRay()
 
  421         mouse_intersection_with_manip_plane = self.plane.intersect( self.local_mouse )
 
  423         self.mouse_point_gl_name = mouse_intersection_with_manip_plane
 
  425         active = self.glActiveName()
 
  429             if ( active == self.top_name ):
 
  432             if ( active == self.bottom_name ):
 
  435             if ( active == self.right_name ):
 
  438             if ( active == self.left_name ):
 
  450                 line.set_line( start, vab )
 
  454                 cpt = line.closest_point( self.mouse_point_gl_name )
 
  455                 self.mouse_point_gl_name -= cpt
 
  457                 min_change_value = min( self.mouse_point_gl_name.x, self.mouse_point_gl_name.y, self.mouse_point_gl_name.z )
 
  458                 max_change_value = max( self.mouse_point_gl_name.x, self.mouse_point_gl_name.y, self.mouse_point_gl_name.z )
 
  459                 if ( active == self.right_name ):
 
  460                     self.setDoubleValue( self.right_index, max_change_value )
 
  461                 if ( active == self.left_name ):
 
  462                     self.setDoubleValue( self.right_index, min_change_value )
 
  468     This command class is used to create instances of the SquareScaleManipContext class. 
  470     kPluginCmdName = 
"squareScaleManipContext" 
  477         return SquareScaleManipContextCmd()
 
  481         Create and return an instance of the SquareScaleManipContext class. 
  483         return SquareScaleManipContext()
 
  487     This context handles all mouse interaction in the viewport when activated. 
  488     When activated, it creates and manages an instance of the SquareScaleManuplator 
  489     class on the selected objects. 
  492     kContextName = 
'SquareScaleManipContext' 
  500         Initialize the members of the SquareScaleManipContext class. 
  503         self.setTitleString(
'Plug-in manipulator: ' + SquareScaleManipContext.kContextName)
 
  504         self.manipulator_class_ptr = 
None 
  505         self.first_object_selected = 
None 
  506         self.active_list_modified_msg_id = -1
 
  509     def toolOnSetup(self, event):
 
  511         Set the help string and selection list callback. 
  513         self.setHelpString(
'Move the object using the manipulator')
 
  515         SquareScaleManipContext.update_manipulators_cb(self)
 
  518                                          OpenMaya.MModelMessage.kActiveListModified, \
 
  519                                          SquareScaleManipContext.update_manipulators_cb, self)
 
  525     def toolOffCleanup(self):
 
  527         Unregister the selection list callback. 
  531             self.active_list_modified_msg_id = -1
 
  538     def namesOfAttributes(self, attribute_names):
 
  540         Return the names of the attributes of the selected objects this context will be modifying. 
  542         attribute_names.append(
'scaleX')
 
  545     def setInitialState(self):
 
  547         Set the initial transform of the manipulator. 
  550         xformMatrix = xform.transformation()
 
  551         translation = xformMatrix.translation( OpenMaya.MSpace.kWorld )
 
  552         rotation = xformMatrix.rotation(
False)
 
  554         self.manipulator_class_ptr.set_draw_transform_info( rotation, translation )
 
  557     def valid_geometry_selected(self):
 
  559         Check to make sure the selected objects have transforms. 
  567             logger.info(
"    Could not get active selection")
 
  570         if (
not list) 
or (list.length() == 0):
 
  573         while not iter.isDone():
 
  574             depend_node = iter.getDependNode()
 
  575             if (depend_node.isNull() 
or (
not depend_node.hasFn(OpenMaya.MFn.kTransform))):
 
  581     def update_manipulators_cb(ctx):
 
  583         Callback that creates the manipulator if valid geometry is selected. Also removes 
  584         the manipulator if no geometry is selected. Handles connecting the manipulator to 
  585         multiply selected nodes. 
  588             ctx.deleteManipulators()
 
  590             logger.info(
"    No manipulators to delete")
 
  593             if not ctx.valid_geometry_selected():
 
  597             ctx.manipulator_class_ptr = 
None 
  598             ctx.first_object_selected = OpenMaya.MObject.kNullObj
 
  600             (manipulator, manip_object) = SquareScaleManipulator.newManipulator(
'SquareScaleContextManipulator')
 
  604                 ctx.manipulator_class_ptr = manipulator
 
  607                 ctx.addManipulator(manip_object)
 
  612                 while not iter.isDone():
 
  613                     depend_node = iter.getDependNode()
 
  617                     if (
not manipulator.connectToDependNode(depend_node)):
 
  622                     if ( ctx.first_object_selected == OpenMaya.MObject.kNullObj ):
 
  623                         ctx.first_object_selected = depend_node
 
  627                 ctx.setInitialState()
 
  633     update_manipulators_cb = staticmethod(update_manipulators_cb)
 
  637 def initializePlugin(plugin):
 
  641         pluginFn.registerContextCommand( SquareScaleManipContextCmd.kPluginCmdName, SquareScaleManipContextCmd.creator)
 
  643         sys.stderr.write(
"Failed to register context command: %s\n" % SquareScaleManipContextCmd.kPluginCmdName)
 
  647         pluginFn.registerNode( SquareScaleManipulator.kNodeName, SquareScaleManipulator.kTypeId, \
 
  648                                SquareScaleManipulator.creator, SquareScaleManipulator.initialize, \
 
  649                                OpenMaya.MPxNode.kManipulatorNode)
 
  651         sys.stderr.write(
"Failed to register node: %s\n" % SquareScaleManipulator.kNodeName)
 
  656 def uninitializePlugin(plugin):
 
  659         pluginFn.deregisterContextCommand(SquareScaleManipContextCmd.kPluginCmdName)
 
  662             "Failed to unregister command: %s\n" % SquareScaleManipContextCmd.kPluginCmdName)
 
  666         pluginFn.deregisterNode(SquareScaleManipulator.kTypeId)
 
  669             "Failed to unregister node: %s\n" % SquareScaleManipulator.kNodeName)