| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- """DistributedSmoothNodeBase module: contains the DistributedSmoothNodeBase class"""
- from ClockDelta import *
- from direct.task import Task
- from direct.showbase.PythonUtil import randFloat, Enum
- class DistributedSmoothNodeBase:
- """common base class for DistributedSmoothNode and DistributedSmoothNodeAI
- """
- BroadcastTypes = Enum('FULL, XYH')
-
- def __init__(self):
- pass
- def delete(self):
- # make sure our task is gone
- self.stopPosHprBroadcast()
- ### distributed set pos and hpr functions ###
- ### These functions send the distributed update to set the
- ### appropriate values on the remote side. These are
- ### composite fields, with all the likely combinations
- ### defined; each function maps (via the dc file) to one or
- ### more component operations on the remote client.
- def d_setSmStop(self):
- self.sendUpdate("setSmStop", [globalClockDelta.getFrameNetworkTime()])
- def d_setSmH(self, h):
- self.sendUpdate("setSmH", [h, globalClockDelta.getFrameNetworkTime()])
- def d_setSmXY(self, x, y):
- self.sendUpdate("setSmXY", [x, y,
- globalClockDelta.getFrameNetworkTime()])
- def d_setSmXZ(self, x, z):
- self.sendUpdate("setSmXZ", [x, z,
- globalClockDelta.getFrameNetworkTime()])
- def d_setSmPos(self, x, y, z):
- self.sendUpdate("setSmPos", [x, y, z,
- globalClockDelta.getFrameNetworkTime()])
- def d_setSmHpr(self, h, p, r):
- self.sendUpdate("setSmHpr", [h, p, r,
- globalClockDelta.getFrameNetworkTime()])
- def d_setSmXYH(self, x, y, h):
- self.sendUpdate("setSmXYH", [x, y, h,
- globalClockDelta.getFrameNetworkTime()])
- def d_setSmXYZH(self, x, y, z, h):
- self.sendUpdate("setSmXYZH", [x, y, z, h,
- globalClockDelta.getFrameNetworkTime()])
- def d_setSmPosHpr(self, x, y, z, h, p, r):
- self.sendUpdate("setSmPosHpr", [x, y, z, h, p, r,
- globalClockDelta.getFrameNetworkTime()])
- def b_clearSmoothing(self):
- self.d_clearSmoothing()
- self.clearSmoothing()
- def d_clearSmoothing(self):
- self.sendUpdate("clearSmoothing", [0])
- ### posHprBroadcast ###
- def getPosHprBroadcastTaskName(self):
- # presumably, we have a doId at this point
- return "sendPosHpr-%s" % self.doId
- def stopPosHprBroadcast(self):
- taskMgr.remove(self.getPosHprBroadcastTaskName())
- def startPosHprBroadcast(self, period=.2, stagger=0, type=None):
- BT = DistributedSmoothNodeBase.BroadcastTypes
- if type is None:
- type = BT.FULL
- # set the broadcast type
- self.broadcastType = type
- broadcastFuncs = {
- BT.FULL: self.d_broadcastPosHpr_FULL,
- BT.XYH: self.d_broadcastPosHpr_XYH,
- }
- self.d_broadcastPosHpr = broadcastFuncs[self.broadcastType]
-
- # Set stagger to non-zero to randomly delay the initial task execution
- # over 'period' seconds, to spread out task processing over time
- # when a large number of SmoothNodes are created simultaneously.
- taskName = self.getPosHprBroadcastTaskName()
- # Set up telemetry optimization variables
- xyz = self.getPos()
- hpr = self.getHpr()
- self.__storeX = xyz[0]
- self.__storeY = xyz[1]
- self.__storeZ = xyz[2]
- self.__storeH = hpr[0]
- self.__storeP = hpr[1]
- self.__storeR = hpr[2]
- self.__storeStop = 0
- self.__epsilon = 0.01
- self.__broadcastPeriod = period
- # Broadcast our initial position
- self.b_clearSmoothing()
- self.d_setSmPosHpr(self.__storeX, self.__storeY, self.__storeZ,
- self.__storeH, self.__storeP, self.__storeR)
- # remove any old tasks
- taskMgr.remove(taskName)
- # spawn the new task
- delay = 0.
- if stagger:
- delay = randFloat(period)
- taskMgr.doMethodLater(self.__broadcastPeriod + delay,
- self.posHprBroadcast, taskName)
- def posHprBroadcast(self, task):
- # TODO: we explicitly stagger the initial task timing in
- # startPosHprBroadcast; we should at least make an effort to keep
- # this task accurately aligned with its period and starting time.
- self.d_broadcastPosHpr()
- taskName = self.taskName("sendPosHpr")
- taskMgr.doMethodLater(self.__broadcastPeriod,
- self.posHprBroadcast, taskName)
- return Task.done
- def d_broadcastPosHpr_FULL(self):
- # send out the minimal bits to describe our new position
- xyz = self.getPos()
- hpr = self.getHpr()
- if abs(self.__storeX - xyz[0]) > self.__epsilon:
- self.__storeX = xyz[0]
- newX = 1
- else:
- newX = 0
- if abs(self.__storeY - xyz[1]) > self.__epsilon:
- self.__storeY = xyz[1]
- newY = 1
- else:
- newY = 0
- if abs(self.__storeZ - xyz[2]) > self.__epsilon:
- self.__storeZ = xyz[2]
- newZ = 1
- else:
- newZ = 0
- if abs(self.__storeH - hpr[0]) > self.__epsilon:
- self.__storeH = hpr[0]
- newH = 1
- else:
- newH = 0
- if abs(self.__storeP - hpr[1]) > self.__epsilon:
- self.__storeP = hpr[1]
- newP = 1
- else:
- newP = 0
- if abs(self.__storeR - hpr[2]) > self.__epsilon:
- self.__storeR = hpr[2]
- newR = 1
- else:
- newR = 0
- # Check for changes:
- if not(newX or newY or newZ or newH or newP or newR):
- # No change
- # Send one and only one "stop" message.
- if not self.__storeStop:
- self.__storeStop = 1
- self.d_setSmStop()
- # print 'no change'
- elif (newH) and not(newX or newY or newZ or newP or newR):
- # Only change in H
- self.__storeStop = 0
- self.d_setSmH(self.__storeH)
- # print ("H change")
- elif (newX or newY) and not(newZ or newH or newP or newR):
- # Only change in X, Y
- self.__storeStop = 0
- self.d_setSmXY(self.__storeX, self.__storeY)
- # print ("XY change")
- elif (newX or newY or newZ) and not(newH or newP or newR):
- # Only change in X, Y, Z
- self.__storeStop = 0
- self.d_setSmPos(self.__storeX, self.__storeY, self.__storeZ)
- # print ("XYZ change")
- elif (newX or newY or newH) and not(newZ or newP or newR):
- # Only change in X, Y, H
- self.__storeStop = 0
- self.d_setSmXYH(self.__storeX, self.__storeY, self.__storeH)
- # print ("XYH change")
- elif (newX or newY or newZ or newH) and not(newP or newR):
- # Only change in X, Y, Z, H
- self.__storeStop = 0
- self.d_setSmXYZH(self.__storeX, self.__storeY, self.__storeZ, self.__storeH)
- # print ("XYZH change")
- else:
- # Other changes
- self.__storeStop = 0
- self.d_setSmPosHpr(self.__storeX, self.__storeY, self.__storeZ,
- self.__storeH, self.__storeP, self.__storeR)
- # print ("XYZHPR change")
- def d_broadcastPosHpr_XYH(self):
- # send out the minimal bits to describe our new position
- assert not self.isEmpty(), 'DistributedSmoothNode %s has been removed from graph?' % self.doId
- xyz = self.getPos()
- h = self.getH()
- if abs(self.__storeX - xyz[0]) > self.__epsilon:
- self.__storeX = xyz[0]
- newX = 1
- else:
- newX = 0
- if abs(self.__storeY - xyz[1]) > self.__epsilon:
- self.__storeY = xyz[1]
- newY = 1
- else:
- newY = 0
- if abs(self.__storeH - h) > self.__epsilon:
- self.__storeH = h
- newH = 1
- else:
- newH = 0
- # Check for changes:
- if not(newX or newY or newH):
- # No change
- # Send one and only one "stop" message.
- if not self.__storeStop:
- self.__storeStop = 1
- self.d_setSmStop()
- # print 'no change'
- elif (newH) and not(newX or newY):
- # Only change in H
- self.__storeStop = 0
- self.d_setSmH(self.__storeH)
- # print ("H change")
- elif (newX or newY) and not(newH):
- # Only change in X, Y
- self.__storeStop = 0
- self.d_setSmXY(self.__storeX, self.__storeY)
- # print ("XY change")
- else:
- # Only change in X, Y, H
- self.__storeStop = 0
- self.d_setSmXYH(self.__storeX, self.__storeY, self.__storeH)
- # print ("XYH change")
|