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)