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

View File

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

View File

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

View File

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

View File

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