Summer 2010 CMU ETC PandaLE team: (1) fixed bug that made things move in wrong directions when manipulated from an orthographic viewport; (2) added capability to show the manipulation widget in world space rather than the local space of the selected object; (3) added an option to show a separate scale widget rather than using control key to scale

This commit is contained in:
Mike Christel 2010-08-20 19:33:15 +00:00
parent 22e80168cb
commit b66a795efb

View File

@ -5,6 +5,7 @@ from DirectGeometry import *
from DirectSelection import SelectionRay from DirectSelection import SelectionRay
from direct.task import Task from direct.task import Task
import types import types
from copy import deepcopy
class DirectManipulationControl(DirectObject): class DirectManipulationControl(DirectObject):
def __init__(self): def __init__(self):
@ -33,6 +34,9 @@ class DirectManipulationControl(DirectObject):
self.fScaling1D = 0 self.fScaling1D = 0
self.fMovable = 1 self.fMovable = 1
self.mode = None self.mode = None
self.worldSpaceManip = False
#turn this on to enable separate handles for scaling
self.useSeparateScaleHandles = False
self.actionEvents = [ self.actionEvents = [
['DIRECT-mouse1', self.manipulationStart], ['DIRECT-mouse1', self.manipulationStart],
['DIRECT-mouse1Up', self.manipulationStop], ['DIRECT-mouse1Up', self.manipulationStop],
@ -152,6 +156,12 @@ class DirectManipulationControl(DirectObject):
watchMarqueeTask.initY = base.direct.dr.mouseY watchMarqueeTask.initY = base.direct.dr.mouseY
taskMgr.add(watchMarqueeTask, 'manip-marquee-mouse') taskMgr.add(watchMarqueeTask, 'manip-marquee-mouse')
def switchToWorldSpaceMode(self):
self.worldSpaceManip = True
def switchToLocalSpaceMode(self):
self.worldSpaceManip = False
def switchToMoveMode(self, state): def switchToMoveMode(self, state):
taskMgr.remove('manip-watch-mouse') taskMgr.remove('manip-watch-mouse')
self.mode = 'move' self.mode = 'move'
@ -384,9 +394,17 @@ class DirectManipulationControl(DirectObject):
def followSelectedNodePathTask(self, state): def followSelectedNodePathTask(self, state):
if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView: if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView:
for widget in base.direct.manipulationControl.widgetList: for widget in base.direct.manipulationControl.widgetList:
widget.setPosHpr(state.base, state.pos, state.hpr) if self.worldSpaceManip:
widget.setPos(state.base, state.pos)
widget.setHpr(render, VBase3(0))
else:
widget.setPosHpr(state.base, state.pos, state.hpr)
else: else:
base.direct.widget.setPosHpr(state.base, state.pos, state.hpr) if self.worldSpaceManip:
widget.setPos(state.base, state.pos)
widget.setHpr(render, VBase3(0))
else:
base.direct.widget.setPosHpr(state.base, state.pos, state.hpr)
return Task.cont return Task.cont
def enableManipulation(self): def enableManipulation(self):
@ -549,24 +567,39 @@ class DirectManipulationControl(DirectObject):
# Widget takes precedence # Widget takes precedence
if self.constraint: if self.constraint:
type = self.constraint[2:] type = self.constraint[2:]
if base.direct.fControl and not self.currEditTypes & EDIT_TYPE_UNSCALABLE: if self.useSeparateScaleHandles:
if type == 'post':
# [gjeon] non-uniform scaling
self.fScaling1D = 1
self.scale1D(state)
else:
# [gjeon] uniform scaling
self.fScaling3D = 1
self.scale3D(state)
else:
if type == 'post' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE: if type == 'post' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
self.xlate1D(state) self.xlate1D(state)
elif type == 'disc' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE: elif type == 'disc' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
self.xlate2D(state) self.xlate2D(state)
elif type == 'ring' and not self.currEditTypes & EDIT_TYPE_UNROTATABLE: elif type == 'ring' and not self.currEditTypes & EDIT_TYPE_UNROTATABLE:
self.rotate1D(state) self.rotate1D(state)
elif type == 'scale' and not self.currEditTypes & EDIT_TYPE_UNSCALABLE:
if base.direct.fShift:
self.fScaling3D = 1
self.scale3D(state)
else:
self.fScaling1D = 1
self.scale1D(state)
else:
if base.direct.fControl and not self.currEditTypes & EDIT_TYPE_UNSCALABLE:
if type == 'post':
# [gjeon] non-uniform scaling
self.fScaling1D = 1
self.scale1D(state)
else:
# [gjeon] uniform scaling
self.fScaling3D = 1
self.scale3D(state)
else:
if type == 'post' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
self.xlate1D(state)
elif type == 'disc' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
self.xlate2D(state)
elif type == 'ring' and not self.currEditTypes & EDIT_TYPE_UNROTATABLE:
self.rotate1D(state)
# No widget interaction, determine free manip mode # No widget interaction, determine free manip mode
elif self.fFreeManip: elif self.fFreeManip and not self.useSeparateScaleHandles:
# If we've been scaling and changed modes, reset object handles # If we've been scaling and changed modes, reset object handles
if 0 and (self.fScaling1D or self.fScaling3D) and (not base.direct.fAlt): if 0 and (self.fScaling1D or self.fScaling3D) and (not base.direct.fAlt):
if hasattr(base.direct, 'widget'): if hasattr(base.direct, 'widget'):
@ -594,6 +627,8 @@ class DirectManipulationControl(DirectObject):
self.xlateCamXY(state) self.xlateCamXY(state)
else: else:
self.xlateCamXZ(state) self.xlateCamXZ(state)
else:
return Task.done
if self.fSetCoa: if self.fSetCoa:
# Update coa based on current widget position # Update coa based on current widget position
base.direct.selected.last.mCoa2Dnp.assign( base.direct.selected.last.mCoa2Dnp.assign(
@ -674,8 +709,8 @@ class DirectManipulationControl(DirectObject):
widget.setPos(self.gridSnapping(widget, offset)) widget.setPos(self.gridSnapping(widget, offset))
else: else:
widget.setPos(widget, offset) widget.setPos(widget, offset)
if base.direct.camera.getName() != 'persp': #if base.direct.camera.getName() != 'persp':
self.prevHit.assign(self.hitPt) #self.prevHit.assign(self.hitPt)
else: else:
if self.fGridSnap: if self.fGridSnap:
base.direct.widget.setPos(self.gridSnapping(base.direct.widget, offset)) base.direct.widget.setPos(self.gridSnapping(base.direct.widget, offset))
@ -881,36 +916,31 @@ class DirectManipulationControl(DirectObject):
relHpr(base.direct.widget, base.direct.camera, 0, 0, -deltaAngle) relHpr(base.direct.widget, base.direct.camera, 0, 0, -deltaAngle)
def scale1D(self, state): def scale1D(self, state):
print self.constraint
if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView: if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView:
self.hitPtScale.assign(self.objectHandles.getMouseIntersectPt()) self.hitPtScale.assign(self.objectHandles.getAxisIntersectPt(self.constraint[:1]))
self.hitPtScale = self.objectHandles.getMat().xformVec(self.hitPtScale)
if self.fScaleInit1: if self.fScaleInit1:
# First time through just record hit point # First time through just record hit point
self.fScaleInit1 = 0 self.fScaleInit1 = 0
self.prevHitScale.assign(self.hitPtScale) self.prevHitScale.assign(self.hitPtScale)
self.origScale = base.direct.widget.getScale()
else: else:
widgetPos = base.direct.widget.getPos() widgetPos = base.direct.widget.getPos()
d0 = (self.prevHitScale - widgetPos).length() d0 = (self.prevHitScale).length()
d1 = (self.hitPtScale - widgetPos).length() if d0 == 0: #make sure we don't divide by zero
offset = d1 - d0 d0 = 0.001
currScale = base.direct.widget.getScale() d1 = (self.hitPtScale).length()
if d1 == 0: #make sure we don't set scale to zero
d1 = 0.001
currScale = self.origScale
# Scale factor is ratio current mag with init mag # Scale factor is ratio current mag with init mag
if self.constraint[:1] == 'x': if self.constraint[:1] == 'x':
currScale = Vec3(currScale.getX() + offset, currScale.getY(), currScale.getZ()) currScale = Vec3(currScale.getX() * d1/d0, currScale.getY(), currScale.getZ())
if currScale.getX() < 0.0:
currScale.setX(0.01)
elif self.constraint[:1] == 'y': elif self.constraint[:1] == 'y':
currScale = Vec3(currScale.getX(), currScale.getY() + offset, currScale.getZ()) currScale = Vec3(currScale.getX(), currScale.getY() * d1/d0, currScale.getZ())
if currScale.getY() < 0.0:
currScale.setY(0.01)
elif self.constraint[:1] == 'z': elif self.constraint[:1] == 'z':
currScale = Vec3(currScale.getX(), currScale.getY(), currScale.getZ() + offset) currScale = Vec3(currScale.getX(), currScale.getY(), currScale.getZ() * d1/d0)
if currScale.getZ() < 0.0:
currScale.setZ(0.01)
base.direct.widget.setScale(currScale) base.direct.widget.setScale(currScale)
self.prevHitScale.assign(self.hitPtScale)
return return
# [gjeon] Constrained 1D scale of the selected node based upon up down mouse motion # [gjeon] Constrained 1D scale of the selected node based upon up down mouse motion
@ -943,26 +973,47 @@ class DirectManipulationControl(DirectObject):
def scale3D(self, state): def scale3D(self, state):
if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView: if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView:
self.hitPtScale.assign(self.objectHandles.getMouseIntersectPt()) if self.useSeparateScaleHandles:
self.hitPtScale.assign(self.objectHandles.getAxisIntersectPt(self.constraint[:1]))
if self.fScaleInit1: self.hitPtScale = self.objectHandles.getMat().xformVec(self.hitPtScale)
# First time through just record hit point if self.fScaleInit1:
self.fScaleInit1 = 0 # First time through just record hit point
self.prevHitScale.assign(self.hitPtScale) self.fScaleInit1 = 0
self.prevHitScale.assign(self.hitPtScale)
self.origScale = base.direct.widget.getScale()
else:
widgetPos = base.direct.widget.getPos()
d0 = (self.prevHitScale).length()
if d0 == 0: #make sure we don't divide by zero
d0 = 0.001
d1 = (self.hitPtScale).length()
if d1 == 0: #make sure we don't set scale to zero
d1 = 0.001
currScale = self.origScale
# Scale factor is ratio current mag with init mag
currScale = Vec3(currScale.getX() * d1/d0, currScale.getY() * d1/d0, currScale.getZ() * d1/d0)
base.direct.widget.setScale(currScale)
return
else: else:
widgetPos = base.direct.widget.getPos() self.hitPtScale.assign(self.objectHandles.getMouseIntersectPt())
d0 = (self.prevHitScale - widgetPos).length()
d1 = (self.hitPtScale - widgetPos).length() if self.fScaleInit1:
offset = d1 - d0 # First time through just record hit point
currScale = base.direct.widget.getScale() self.fScaleInit1 = 0
currScale += offset self.prevHitScale.assign(self.hitPtScale)
if currScale.getX() < 0.0 and\ self.origScale = base.direct.widget.getScale()
currScale.getY() < 0.0 and\ else:
currScale.getZ() < 0.0: widgetPos = base.direct.widget.getPos()
currScale = VBase3(0.01, 0.01, 0.01) d0 = (self.prevHitScale - widgetPos).length()
base.direct.widget.setScale(currScale) if d0 == 0: #make sure we don't divide by zero
self.prevHitScale.assign(self.hitPtScale) d0 = 0.001
return d1 = (self.hitPtScale - widgetPos).length()
if d1 == 0:
d1 = 0.001 #make sure we don't set scale to zero
currScale = self.origScale
currScale = currScale * d1/d0
base.direct.widget.setScale(currScale)
return
# Scale the selected node based upon up down mouse motion # Scale the selected node based upon up down mouse motion
# Mouse motion from edge to edge results in a factor of 4 scaling # Mouse motion from edge to edge results in a factor of 4 scaling
# From midpoint to edge doubles or halves objects scale # From midpoint to edge doubles or halves objects scale
@ -1032,6 +1083,10 @@ class ObjectHandles(NodePath, DirectObject):
self.xDiscGroup = self.xHandles.find('**/x-disc-group') self.xDiscGroup = self.xHandles.find('**/x-disc-group')
self.xDisc = self.xHandles.find('**/x-disc-visible') self.xDisc = self.xHandles.find('**/x-disc-visible')
self.xDiscCollision = self.xHandles.find('**/x-disc') self.xDiscCollision = self.xHandles.find('**/x-disc')
self.xScaleGroup = deepcopy(self.xPostGroup)
self.xScaleGroup.setName('x-scale-group')
self.xScaleCollision = self.xScaleGroup.find('**/x-post')
self.xScaleCollision.setName('x-scale')
self.yHandles = self.find('**/Y') self.yHandles = self.find('**/Y')
self.yPostGroup = self.yHandles.find('**/y-post-group') self.yPostGroup = self.yHandles.find('**/y-post-group')
@ -1041,6 +1096,10 @@ class ObjectHandles(NodePath, DirectObject):
self.yDiscGroup = self.yHandles.find('**/y-disc-group') self.yDiscGroup = self.yHandles.find('**/y-disc-group')
self.yDisc = self.yHandles.find('**/y-disc-visible') self.yDisc = self.yHandles.find('**/y-disc-visible')
self.yDiscCollision = self.yHandles.find('**/y-disc') self.yDiscCollision = self.yHandles.find('**/y-disc')
self.yScaleGroup = deepcopy(self.yPostGroup)
self.yScaleGroup.setName('y-scale-group')
self.yScaleCollision = self.yScaleGroup.find('**/y-post')
self.yScaleCollision.setName('y-scale')
self.zHandles = self.find('**/Z') self.zHandles = self.find('**/Z')
self.zPostGroup = self.zHandles.find('**/z-post-group') self.zPostGroup = self.zHandles.find('**/z-post-group')
@ -1050,16 +1109,23 @@ class ObjectHandles(NodePath, DirectObject):
self.zDiscGroup = self.zHandles.find('**/z-disc-group') self.zDiscGroup = self.zHandles.find('**/z-disc-group')
self.zDisc = self.zHandles.find('**/z-disc-visible') self.zDisc = self.zHandles.find('**/z-disc-visible')
self.zDiscCollision = self.zHandles.find('**/z-disc') self.zDiscCollision = self.zHandles.find('**/z-disc')
self.zScaleGroup = deepcopy(self.zPostGroup)
self.zScaleGroup.setName('z-scale-group')
self.zScaleCollision = self.zScaleGroup.find('**/z-post')
self.zScaleCollision.setName('z-scale')
# Adjust visiblity, colors, and transparency # Adjust visiblity, colors, and transparency
self.xPostCollision.hide() self.xPostCollision.hide()
self.xRingCollision.hide() self.xRingCollision.hide()
self.xScaleCollision.hide()
self.xDisc.setColor(1, 0, 0, .2) self.xDisc.setColor(1, 0, 0, .2)
self.yPostCollision.hide() self.yPostCollision.hide()
self.yRingCollision.hide() self.yRingCollision.hide()
self.yScaleCollision.hide()
self.yDisc.setColor(0, 1, 0, .2) self.yDisc.setColor(0, 1, 0, .2)
self.zPostCollision.hide() self.zPostCollision.hide()
self.zRingCollision.hide() self.zRingCollision.hide()
self.zScaleCollision.hide()
self.zDisc.setColor(0, 0, 1, .2) self.zDisc.setColor(0, 0, 1, .2)
# Augment geometry with lines # Augment geometry with lines
self.createObjectHandleLines() self.createObjectHandleLines()
@ -1080,11 +1146,18 @@ class ObjectHandles(NodePath, DirectObject):
self.yDiscCollision.setTag('WidgetName',name) self.yDiscCollision.setTag('WidgetName',name)
self.zDiscCollision.setTag('WidgetName',name) self.zDiscCollision.setTag('WidgetName',name)
self.xScaleCollision.setTag('WidgetName',name)
self.yScaleCollision.setTag('WidgetName',name)
self.zScaleCollision.setTag('WidgetName',name)
# name disc geoms so they can be added to unpickables # name disc geoms so they can be added to unpickables
self.xDisc.find("**/+GeomNode").setName('x-disc-geom') self.xDisc.find("**/+GeomNode").setName('x-disc-geom')
self.yDisc.find("**/+GeomNode").setName('y-disc-geom') self.yDisc.find("**/+GeomNode").setName('y-disc-geom')
self.zDisc.find("**/+GeomNode").setName('z-disc-geom') self.zDisc.find("**/+GeomNode").setName('z-disc-geom')
#turn scale off by default
self.disableHandles('scale')
# Start with widget handles hidden # Start with widget handles hidden
self.fActive = 1 self.fActive = 1
self.toggleWidget() self.toggleWidget()
@ -1139,21 +1212,23 @@ class ObjectHandles(NodePath, DirectObject):
for handle in handles: for handle in handles:
self.enableHandle(handle) self.enableHandle(handle)
elif handles == 'x': elif handles == 'x':
self.enableHandles(['x-post','x-ring','x-disc']) self.enableHandles(['x-post','x-ring','x-disc', 'x-scale'])
elif handles == 'y': elif handles == 'y':
self.enableHandles(['y-post','y-ring','y-disc']) self.enableHandles(['y-post','y-ring','y-disc', 'y-scale'])
elif handles == 'z': elif handles == 'z':
self.enableHandles(['z-post','z-ring','z-disc']) self.enableHandles(['z-post','z-ring','z-disc', 'z-scale'])
elif handles == 'post': elif handles == 'post':
self.enableHandles(['x-post','y-post','z-post']) self.enableHandles(['x-post','y-post','z-post'])
elif handles == 'ring': elif handles == 'ring':
self.enableHandles(['x-ring','y-ring','z-ring']) self.enableHandles(['x-ring','y-ring','z-ring'])
elif handles == 'disc': elif handles == 'disc':
self.enableHandles(['x-disc','y-disc','z-disc']) self.enableHandles(['x-disc','y-disc','z-disc'])
elif handles == 'scale':
self.enableHandles(['x-scale','y-scale','z-scale'])
elif handles == 'all': elif handles == 'all':
self.enableHandles(['x-post','x-ring','x-disc', self.enableHandles(['x-post','x-ring','x-disc','x-scale',
'y-post','y-ring','y-disc', 'y-post','y-ring','y-disc','y-scale',
'z-post','z-ring','z-disc']) 'z-post','z-ring','z-disc','z-scale'])
def enableHandle(self, handle): def enableHandle(self, handle):
if handle == 'x-post': if handle == 'x-post':
@ -1162,39 +1237,47 @@ class ObjectHandles(NodePath, DirectObject):
self.xRingGroup.reparentTo(self.xHandles) self.xRingGroup.reparentTo(self.xHandles)
elif handle == 'x-disc': elif handle == 'x-disc':
self.xDiscGroup.reparentTo(self.xHandles) self.xDiscGroup.reparentTo(self.xHandles)
if handle == 'y-post': elif handle == 'x-scale' and base.direct.manipulationControl.useSeparateScaleHandles:
self.xScaleGroup.reparentTo(self.xHandles)
elif handle == 'y-post':
self.yPostGroup.reparentTo(self.yHandles) self.yPostGroup.reparentTo(self.yHandles)
elif handle == 'y-ring': elif handle == 'y-ring':
self.yRingGroup.reparentTo(self.yHandles) self.yRingGroup.reparentTo(self.yHandles)
elif handle == 'y-disc': elif handle == 'y-disc':
self.yDiscGroup.reparentTo(self.yHandles) self.yDiscGroup.reparentTo(self.yHandles)
if handle == 'z-post': elif handle == 'y-scale' and base.direct.manipulationControl.useSeparateScaleHandles:
self.yScaleGroup.reparentTo(self.yHandles)
elif handle == 'z-post':
self.zPostGroup.reparentTo(self.zHandles) self.zPostGroup.reparentTo(self.zHandles)
elif handle == 'z-ring': elif handle == 'z-ring':
self.zRingGroup.reparentTo(self.zHandles) self.zRingGroup.reparentTo(self.zHandles)
elif handle == 'z-disc': elif handle == 'z-disc':
self.zDiscGroup.reparentTo(self.zHandles) self.zDiscGroup.reparentTo(self.zHandles)
elif handle == 'z-scale' and base.direct.manipulationControl.useSeparateScaleHandles:
self.zScaleGroup.reparentTo(self.zHandles)
def disableHandles(self, handles): def disableHandles(self, handles):
if type(handles) == types.ListType: if type(handles) == types.ListType:
for handle in handles: for handle in handles:
self.disableHandle(handle) self.disableHandle(handle)
elif handles == 'x': elif handles == 'x':
self.disableHandles(['x-post','x-ring','x-disc']) self.disableHandles(['x-post','x-ring','x-disc','x-scale'])
elif handles == 'y': elif handles == 'y':
self.disableHandles(['y-post','y-ring','y-disc']) self.disableHandles(['y-post','y-ring','y-disc','y-scale'])
elif handles == 'z': elif handles == 'z':
self.disableHandles(['z-post','z-ring','z-disc']) self.disableHandles(['z-post','z-ring','z-disc','z-scale'])
elif handles == 'post': elif handles == 'post':
self.disableHandles(['x-post','y-post','z-post']) self.disableHandles(['x-post','y-post','z-post'])
elif handles == 'ring': elif handles == 'ring':
self.disableHandles(['x-ring','y-ring','z-ring']) self.disableHandles(['x-ring','y-ring','z-ring'])
elif handles == 'disc': elif handles == 'disc':
self.disableHandles(['x-disc','y-disc','z-disc']) self.disableHandles(['x-disc','y-disc','z-disc'])
elif handles == 'scale':
self.disableHandles(['x-scale','y-scale','z-scale'])
elif handles == 'all': elif handles == 'all':
self.disableHandles(['x-post','x-ring','x-disc', self.disableHandles(['x-post','x-ring','x-disc','x-scale',
'y-post','y-ring','y-disc', 'y-post','y-ring','y-disc','y-scale',
'z-post','z-ring','z-disc']) 'z-post','z-ring','z-disc','z-scale'])
def disableHandle(self, handle): def disableHandle(self, handle):
if handle == 'x-post': if handle == 'x-post':
@ -1203,40 +1286,52 @@ class ObjectHandles(NodePath, DirectObject):
self.xRingGroup.reparentTo(hidden) self.xRingGroup.reparentTo(hidden)
elif handle == 'x-disc': elif handle == 'x-disc':
self.xDiscGroup.reparentTo(hidden) self.xDiscGroup.reparentTo(hidden)
elif handle == 'x-scale':
self.xScaleGroup.reparentTo(hidden)
if handle == 'y-post': if handle == 'y-post':
self.yPostGroup.reparentTo(hidden) self.yPostGroup.reparentTo(hidden)
elif handle == 'y-ring': elif handle == 'y-ring':
self.yRingGroup.reparentTo(hidden) self.yRingGroup.reparentTo(hidden)
elif handle == 'y-disc': elif handle == 'y-disc':
self.yDiscGroup.reparentTo(hidden) self.yDiscGroup.reparentTo(hidden)
elif handle == 'y-scale':
self.yScaleGroup.reparentTo(hidden)
if handle == 'z-post': if handle == 'z-post':
self.zPostGroup.reparentTo(hidden) self.zPostGroup.reparentTo(hidden)
elif handle == 'z-ring': elif handle == 'z-ring':
self.zRingGroup.reparentTo(hidden) self.zRingGroup.reparentTo(hidden)
elif handle == 'z-disc': elif handle == 'z-disc':
self.zDiscGroup.reparentTo(hidden) self.zDiscGroup.reparentTo(hidden)
elif handle == 'z-scale':
self.zScaleGroup.reparentTo(hidden)
def showAllHandles(self): def showAllHandles(self):
self.xPost.show() self.xPost.show()
self.xRing.show() self.xRing.show()
self.xDisc.show() self.xDisc.show()
self.xScale.show()
self.yPost.show() self.yPost.show()
self.yRing.show() self.yRing.show()
self.yDisc.show() self.yDisc.show()
self.yScale.show()
self.zPost.show() self.zPost.show()
self.zRing.show() self.zRing.show()
self.zDisc.show() self.zDisc.show()
self.zScale.show()
def hideAllHandles(self): def hideAllHandles(self):
self.xPost.hide() self.xPost.hide()
self.xRing.hide() self.xRing.hide()
self.xDisc.hide() self.xDisc.hide()
self.xScale.hide()
self.yPost.hide() self.yPost.hide()
self.yRing.hide() self.yRing.hide()
self.yDisc.hide() self.yDisc.hide()
self.yScale.hide()
self.zPost.hide() self.zPost.hide()
self.zRing.hide() self.zRing.hide()
self.zDisc.hide() self.zDisc.hide()
self.zScale.hide()
def showHandle(self, handle): def showHandle(self, handle):
if handle == 'x-post': if handle == 'x-post':
@ -1245,18 +1340,24 @@ class ObjectHandles(NodePath, DirectObject):
self.xRing.show() self.xRing.show()
elif handle == 'x-disc': elif handle == 'x-disc':
self.xDisc.show() self.xDisc.show()
elif handle == 'x-scale':
self.xScale.show()
elif handle == 'y-post': elif handle == 'y-post':
self.yPost.show() self.yPost.show()
elif handle == 'y-ring': elif handle == 'y-ring':
self.yRing.show() self.yRing.show()
elif handle == 'y-disc': elif handle == 'y-disc':
self.yDisc.show() self.yDisc.show()
elif handle == 'y-scale':
self.yScale.show()
elif handle == 'z-post': elif handle == 'z-post':
self.zPost.show() self.zPost.show()
elif handle == 'z-ring': elif handle == 'z-ring':
self.zRing.show() self.zRing.show()
elif handle == 'z-disc': elif handle == 'z-disc':
self.zDisc.show() self.zDisc.show()
elif handle == 'z-scale':
self.zScale.show()
def showGuides(self): def showGuides(self):
self.guideLines.show() self.guideLines.show()
@ -1337,6 +1438,19 @@ class ObjectHandles(NodePath, DirectObject):
lines.create() lines.create()
lines.setName('x-post-line') lines.setName('x-post-line')
#X scale
self.xScale = self.xScaleGroup.attachNewNode('x-scale-visible')
lines = LineNodePath(self.xScale)
lines.setColor(VBase4(1, 0, 0, 1))
lines.setThickness(5)
lines.moveTo(1.3, 0, 0)
lines.drawTo(-1.5, 0, 0)
drawBox(lines, (1.3, 0, 0), 0.2)
lines.create()
lines.setName('x-scale-line')
# X ring # X ring
self.xRing = self.xRingGroup.attachNewNode('x-ring-visible') self.xRing = self.xRingGroup.attachNewNode('x-ring-visible')
lines = LineNodePath(self.xRing) lines = LineNodePath(self.xRing)
@ -1377,6 +1491,19 @@ class ObjectHandles(NodePath, DirectObject):
lines.create() lines.create()
lines.setName('y-post-line') lines.setName('y-post-line')
#Y scale
self.yScale = self.yScaleGroup.attachNewNode('y-scale-visible')
lines = LineNodePath(self.yScale)
lines.setColor(VBase4(0, 1, 0, 1))
lines.setThickness(5)
lines.moveTo(0, 1.3, 0)
lines.drawTo(0, -1.5, 0)
drawBox(lines, (0, 1.4, 0), 0.2)
lines.create()
lines.setName('y-scale-line')
# Y ring # Y ring
self.yRing = self.yRingGroup.attachNewNode('y-ring-visible') self.yRing = self.yRingGroup.attachNewNode('y-ring-visible')
lines = LineNodePath(self.yRing) lines = LineNodePath(self.yRing)
@ -1418,6 +1545,19 @@ class ObjectHandles(NodePath, DirectObject):
lines.create() lines.create()
lines.setName('z-post-line') lines.setName('z-post-line')
#Z scale
self.zScale = self.zScaleGroup.attachNewNode('z-scale-visible')
lines = LineNodePath(self.zScale)
lines.setColor(VBase4(0, 0, 1, 1))
lines.setThickness(5)
lines.moveTo(0, 0, 1.3)
lines.drawTo(0, 0, -1.5)
drawBox(lines, (0, 0, 1.4), 0.2)
lines.create()
lines.setName('y-scale-line')
# Z ring # Z ring
self.zRing = self.zRingGroup.attachNewNode('z-ring-visible') self.zRing = self.zRingGroup.attachNewNode('z-ring-visible')
lines = LineNodePath(self.zRing) lines = LineNodePath(self.zRing)
@ -1475,13 +1615,7 @@ class ObjectHandles(NodePath, DirectObject):
return self.hitPt return self.hitPt
entry = iRay.getEntry(0) entry = iRay.getEntry(0)
hitPt = entry.getSurfacePoint(entry.getFromNodePath()) self.hitPt = entry.getSurfacePoint(self)
# create a temp nodePath to get the position
np = NodePath('temp')
np.setPos(base.direct.camera, hitPt)
self.hitPt.assign(np.getPos())
np.remove()
del iRay del iRay
if axis == 'x': if axis == 'x':
# We really only care about the nearest point on the axis # We really only care about the nearest point on the axis
@ -1598,4 +1732,41 @@ class ObjectHandles(NodePath, DirectObject):
return self.hitPt return self.hitPt
def drawBox(lines, center, sideLength):
l = sideLength * 0.5
lines.moveTo(center[0] + l, center[1] + l, center[2] + l)
lines.drawTo(center[0] + l, center[1] + l, center[2] - l)
lines.drawTo(center[0] + l, center[1] - l, center[2] - l)
lines.drawTo(center[0] + l, center[1] - l, center[2] + l)
lines.drawTo(center[0] + l, center[1] + l, center[2] + l)
lines.moveTo(center[0] - l, center[1] + l, center[2] + l)
lines.drawTo(center[0] - l, center[1] + l, center[2] - l)
lines.drawTo(center[0] - l, center[1] - l, center[2] - l)
lines.drawTo(center[0] - l, center[1] - l, center[2] + l)
lines.drawTo(center[0] - l, center[1] + l, center[2] + l)
lines.moveTo(center[0] + l, center[1] + l, center[2] + l)
lines.drawTo(center[0] + l, center[1] + l, center[2] - l)
lines.drawTo(center[0] - l, center[1] + l, center[2] - l)
lines.drawTo(center[0] - l, center[1] + l, center[2] + l)
lines.drawTo(center[0] + l, center[1] + l, center[2] + l)
lines.moveTo(center[0] + l, center[1] - l, center[2] + l)
lines.drawTo(center[0] + l, center[1] - l, center[2] - l)
lines.drawTo(center[0] - l, center[1] - l, center[2] - l)
lines.drawTo(center[0] - l, center[1] - l, center[2] + l)
lines.drawTo(center[0] + l, center[1] - l, center[2] + l)
lines.moveTo(center[0] + l, center[1] + l, center[2] + l)
lines.drawTo(center[0] - l, center[1] + l, center[2] + l)
lines.drawTo(center[0] - l, center[1] - l, center[2] + l)
lines.drawTo(center[0] + l, center[1] - l, center[2] + l)
lines.drawTo(center[0] + l, center[1] + l, center[2] + l)
lines.moveTo(center[0] + l, center[1] + l, center[2] - l)
lines.drawTo(center[0] - l, center[1] + l, center[2] - l)
lines.drawTo(center[0] - l, center[1] - l, center[2] - l)
lines.drawTo(center[0] + l, center[1] - l, center[2] - l)
lines.drawTo(center[0] + l, center[1] + l, center[2] - l)