Enhancements to DirectSelection classes

This commit is contained in:
Mark Mine 2003-04-25 22:36:38 +00:00
parent 021108c0e1
commit d5b915eaad
5 changed files with 108 additions and 67 deletions

View File

@ -101,9 +101,7 @@ class DirectCameraControl(PandaObject):
skipFlags = SKIP_HIDDEN | SKIP_BACKFACE
# Skip camera (and its children), unless control key is pressed
skipFlags |= SKIP_CAMERA * (1 - base.getControl())
nodePath, hitPt, hitPtDist = direct.iRay.pickGeom(
skipFlags = skipFlags)
self.computeCOA(nodePath, hitPt, hitPtDist)
self.computeCOA(direct.iRay.pickGeom(skipFlags = skipFlags))
# Record reference point
self.coaMarkerRef.iPosHprScale(base.cam)
# Record entries
@ -307,7 +305,7 @@ class DirectCameraControl(PandaObject):
self.cqEntries = self.cqEntries[:-1]
self.pickNextCOA()
def computeCOA(self, nodePath, hitPt, hitPtDist):
def computeCOA(self, entry):
coa = Point3(0)
dr = direct.drList.getCurrentDr()
if self.fLockCOA:
@ -316,9 +314,11 @@ class DirectCameraControl(PandaObject):
coa.assign(self.coaMarker.getPos(direct.camera))
# Reset hit point count
self.nullHitPointCount = 0
elif nodePath:
elif entry:
# Got a hit point (hit point is in camera coordinates)
# Set center of action
hitPt = entry.getFromIntersectionPoint()
hitPtDist = Vec3(hitPt).length()
coa.assign(hitPt)
# Handle case of bad coa point (too close or too far)
if ((hitPtDist < (1.1 * dr.near)) or

View File

@ -40,14 +40,14 @@ class DirectManipulationControl(PandaObject):
# Start out in select mode
self.mode = 'select'
# Check for a widget hit point
nodePath, hitPt, hitPtDist = direct.iRay.pickWidget()
entry = direct.iRay.pickWidget()
# Did we hit a widget?
if nodePath:
if entry:
# Yes!
self.hitPt.assign(hitPt)
self.hitPtDist = hitPtDist
self.hitPt.assign(entry.getFromIntersectionPoint())
self.hitPtDist = Vec3(self.hitPt).length()
# Constraint determined by nodes name
self.constraint = nodePath.getName()
self.constraint = entry.getIntoNodePath().getName()
else:
# Nope, off the widget, no constraint
self.constraint = None
@ -90,14 +90,13 @@ class DirectManipulationControl(PandaObject):
skipFlags = SKIP_HIDDEN | SKIP_BACKFACE
# Skip camera (and its children), unless control key is pressed
skipFlags |= SKIP_CAMERA * (1 - base.getControl())
nodePath, hitPt, hitPtDist = direct.iRay.pickGeom(
skipFlags = skipFlags)
if nodePath:
entry = direct.iRay.pickGeom(skipFlags = skipFlags)
if entry:
# Record hit point information
self.hitPt.assign(hitPt)
self.hitPtDist = hitPtDist
self.hitPt.assign(entry.getFromIntersectionPoint())
self.hitPtDist = Vec3(self.hitPt).length()
# Select it
direct.select(nodePath, direct.fShift)
direct.select(entry.getIntoNodePath(), direct.fShift)
else:
direct.deselectAll()
else:
@ -484,16 +483,17 @@ class DirectManipulationControl(PandaObject):
def plantSelectedNodePath(self):
""" Move selected object to intersection point of cursor on scene """
# Check for intersection
nodePath, hitPt, hitPtDist = direct.iRay.pickGeom(
entry = direct.iRay.pickGeom(
skipFlags = SKIP_HIDDEN | SKIP_BACKFACE | SKIP_CAMERA)
# MRM: Need to handle moving COA
if (nodePath != None) and (direct.selected.last != None):
if (entry != None) and (direct.selected.last != None):
# Record undo point
direct.pushUndo(direct.selected)
# Record wrt matrix
direct.selected.getWrtAll()
# Move selected
direct.widget.setPos(direct.camera, hitPt)
direct.widget.setPos(
direct.camera,entry.getFromIntersectionPoint())
# Move all the selected objects with widget
# Move the objects with the widget
direct.selected.moveWrtWidgetAll()

View File

@ -379,13 +379,16 @@ class DirectBoundingBox:
class SelectionQueue(CollisionHandlerQueue):
def __init__(self, parent):
def __init__(self, fromNP = render):
# Initialize the superclass
CollisionHandlerQueue.__init__(self)
# Current entry in collision queue
# Current index and entry in collision queue
self.index = -1
# Create a collision node path attached to the given parent
self.collisionNodePath = parent.attachNewNode( CollisionNode("ray") )
self.entry = None
self.skipFlags = SKIP_NONE
# Create a collision node path attached to the given NP
self.collisionNodePath = NodePath(CollisionNode("collisionNP"))
self.setFromNP(fromNP)
# Don't pay the penalty of drawing this collision ray
self.collisionNodePath.hide()
self.collisionNode = self.collisionNodePath.node()
@ -399,6 +402,10 @@ class SelectionQueue(CollisionHandlerQueue):
self.unpickable = UNPICKABLE
# Derived class must add Collider to complete initialization
def setFromNP(self, fromNP):
# Update fromNP
self.collisionNodePath.reparentTo(fromNP)
def addCollider(self, collider):
# Inherited class must call this function to specify collider object
# Record collision object
@ -426,11 +433,17 @@ class SelectionQueue(CollisionHandlerQueue):
if item in self.unpickable:
self.unpickable.remove(item)
def getCurrentEntry(self):
if self.index < 0:
return None
def setCurrentIndex(self, index):
if (index < 0) or (index >= self.getNumEntries()):
self.index = -1
else:
return self.getEntry(self.index)
self.index = index
def setCurrentEntry(self, entry):
self.entry = entry
def getCurrentEntry(self):
return self.entry
def isEntryBackfacing(self, entry):
# If dot product of collision point surface normal and
@ -440,10 +453,39 @@ class SelectionQueue(CollisionHandlerQueue):
v.normalize()
return v.dot(entry.getFromSurfaceNormal()) >= 0
class NewSelectionRay(SelectionQueue):
def __init__(self,parent):
def findCollisionEntry(self, skipFlags = SKIP_NONE, startIndex = 0 ):
# Init self.index and self.entry
self.setCurrentIndex(-1)
self.setCurrentEntry(None)
# Pick out the closest object that isn't a widget
for i in range(startIndex,self.getNumEntries()):
entry = self.getEntry(i)
nodePath = entry.getIntoNodePath()
if (skipFlags & SKIP_HIDDEN) and nodePath.isHidden():
# Skip if hidden node
pass
elif (skipFlags & SKIP_BACKFACE) and self.isEntryBackfacing(entry):
# Skip, if backfacing poly
pass
elif ((skipFlags & SKIP_CAMERA) and
(camera in nodePath.getAncestry())):
# Skip if parented to a camera.
pass
# Can pick unpickable, use the first visible node
elif ((skipFlags & SKIP_UNPICKABLE) and
(nodePath.getName() in self.unpickable)):
# Skip if in unpickable list
pass
else:
self.setCurrentIndex(i)
self.setCurrentEntry(entry)
break
return self.getCurrentEntry()
class SelectionRay(SelectionQueue):
def __init__(self, fromNP = render):
# Initialize the superclass
SelectionQueue.__init__(self, parent)
SelectionQueue.__init__(self, fromNP)
self.addCollider(CollisionRay())
def pick(self, targetNodePath):
@ -485,37 +527,35 @@ class NewSelectionRay(SelectionQueue):
# Determine collision entry
return self.findCollisionEntry(skipFlags)
def findCollisionEntry(self, skipFlags = SKIP_NONE ):
# Init self.index
self.index = -1
# Pick out the closest object that isn't a widget
for i in range(0,self.getNumEntries()):
entry = self.getEntry(i)
nodePath = entry.getIntoNodePath()
if (skipFlags & SKIP_HIDDEN) and nodePath.isHidden():
# Skip if hidden node
pass
elif (skipFlags & SKIP_BACKFACE) and self.isEntryBackfacing(entry):
# Skip, if backfacing poly
pass
elif ((skipFlags & SKIP_CAMERA) and
(camera in nodePath.getAncestry())):
# Skip if parented to a camera.
pass
# Can pick unpickable, use the first visible node
elif ((skipFlags & SKIP_UNPICKABLE) and
(nodePath.getName() in self.unpickable)):
# Skip if in unpickable list
pass
else:
self.index = i
break
# Did we hit an object?
if(self.index >= 0):
# Yes! Find hit point in parent's space
hitPt = entry.getFromIntersectionPoint()
hitPtDist = Vec3(hitPt).length()
return (nodePath, hitPt, hitPtDist)
else:
return (None, ZERO_POINT, 0)
class SelectionSegment(SelectionQueue):
# Like a selection ray but with two endpoints instead of an endpoint
# and a direction
def __init__(self, fromNP = render, numSegments = 1):
# Initialize the superclass
SelectionQueue.__init__(self, fromNP)
self.colliders = []
self.numColliders = 0
for i in range(numSegments):
self.addCollider(CollisionSegment())
def addCollider(self, collider):
# Record new collision object
self.colliders.append(collider)
# Add the collider to the collision Node
self.collisionNode.addSolid( collider )
self.numColliders += 1
def pickGeom(self, targetNodePath = render, endPointList = [],
skipFlags = SKIP_HIDDEN | SKIP_CAMERA ):
self.collideWithGeom()
for i in range(min(len(endPointList), self.numColliders)):
pointA, pointB = endPointList[i]
collider = self.colliders[i]
collider.setPointA( pointA )
collider.setPointB( pointB )
self.ct.traverse( targetNodePath )
# self.sortEntries()
# Determine collision entry
return self.findCollisionEntry(skipFlags)

View File

@ -784,7 +784,7 @@ class DisplayRegionContext(PandaObject):
DisplayRegionContext.regionCount += 1
self.camLens.setChangeEvent(changeEvent)
self.accept(changeEvent, self.camUpdate)
self.iRay = NewSelectionRay(self.cam)
self.iRay = SelectionRay(self.cam)
self.nearVec = Vec3(0)
self.mouseX = 0.0
self.mouseY = 0.0

View File

@ -1675,8 +1675,9 @@ class MopathRecorder(AppShell, PandaObject):
def followTerrain(self, height = 1.0):
self.iRay.rayCollisionNodePath.reparentTo(self.nodePath)
nodePath, hitPt, hitPtDist = self.iRay.pickGeom3D()
if nodePath:
entry = self.iRay.pickGeom3D()
if entry:
hitPtDist = Vec3(entry.getFromIntersectionPoint()).length()
self.nodePath.setZ(self.nodePath, height - hitPtDist)
self.iRay.rayCollisionNodePath.reparentTo(self.recorderNodePath)