DistributedSmoothNodeBase.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. """DistributedSmoothNodeBase module: contains the DistributedSmoothNodeBase class"""
  2. from ClockDelta import *
  3. from direct.task import Task
  4. from direct.showbase.PythonUtil import randFloat, Enum
  5. class DistributedSmoothNodeBase:
  6. """common base class for DistributedSmoothNode and DistributedSmoothNodeAI
  7. """
  8. BroadcastTypes = Enum('FULL, XYH')
  9. def __init__(self):
  10. pass
  11. def delete(self):
  12. # make sure our task is gone
  13. self.stopPosHprBroadcast()
  14. ### distributed set pos and hpr functions ###
  15. ### These functions send the distributed update to set the
  16. ### appropriate values on the remote side. These are
  17. ### composite fields, with all the likely combinations
  18. ### defined; each function maps (via the dc file) to one or
  19. ### more component operations on the remote client.
  20. def d_setSmStop(self):
  21. self.sendUpdate("setSmStop", [globalClockDelta.getFrameNetworkTime()])
  22. def d_setSmH(self, h):
  23. self.sendUpdate("setSmH", [h, globalClockDelta.getFrameNetworkTime()])
  24. def d_setSmXY(self, x, y):
  25. self.sendUpdate("setSmXY", [x, y,
  26. globalClockDelta.getFrameNetworkTime()])
  27. def d_setSmXZ(self, x, z):
  28. self.sendUpdate("setSmXZ", [x, z,
  29. globalClockDelta.getFrameNetworkTime()])
  30. def d_setSmPos(self, x, y, z):
  31. self.sendUpdate("setSmPos", [x, y, z,
  32. globalClockDelta.getFrameNetworkTime()])
  33. def d_setSmHpr(self, h, p, r):
  34. self.sendUpdate("setSmHpr", [h, p, r,
  35. globalClockDelta.getFrameNetworkTime()])
  36. def d_setSmXYH(self, x, y, h):
  37. self.sendUpdate("setSmXYH", [x, y, h,
  38. globalClockDelta.getFrameNetworkTime()])
  39. def d_setSmXYZH(self, x, y, z, h):
  40. self.sendUpdate("setSmXYZH", [x, y, z, h,
  41. globalClockDelta.getFrameNetworkTime()])
  42. def d_setSmPosHpr(self, x, y, z, h, p, r):
  43. self.sendUpdate("setSmPosHpr", [x, y, z, h, p, r,
  44. globalClockDelta.getFrameNetworkTime()])
  45. def b_clearSmoothing(self):
  46. self.d_clearSmoothing()
  47. self.clearSmoothing()
  48. def d_clearSmoothing(self):
  49. self.sendUpdate("clearSmoothing", [0])
  50. ### posHprBroadcast ###
  51. def getPosHprBroadcastTaskName(self):
  52. # presumably, we have a doId at this point
  53. return "sendPosHpr-%s" % self.doId
  54. def stopPosHprBroadcast(self):
  55. taskMgr.remove(self.getPosHprBroadcastTaskName())
  56. def startPosHprBroadcast(self, period=.2, stagger=0, type=None):
  57. BT = DistributedSmoothNodeBase.BroadcastTypes
  58. if type is None:
  59. type = BT.FULL
  60. # set the broadcast type
  61. self.broadcastType = type
  62. broadcastFuncs = {
  63. BT.FULL: self.d_broadcastPosHpr_FULL,
  64. BT.XYH: self.d_broadcastPosHpr_XYH,
  65. }
  66. self.d_broadcastPosHpr = broadcastFuncs[self.broadcastType]
  67. # Set stagger to non-zero to randomly delay the initial task execution
  68. # over 'period' seconds, to spread out task processing over time
  69. # when a large number of SmoothNodes are created simultaneously.
  70. taskName = self.getPosHprBroadcastTaskName()
  71. # Set up telemetry optimization variables
  72. xyz = self.getPos()
  73. hpr = self.getHpr()
  74. self.__storeX = xyz[0]
  75. self.__storeY = xyz[1]
  76. self.__storeZ = xyz[2]
  77. self.__storeH = hpr[0]
  78. self.__storeP = hpr[1]
  79. self.__storeR = hpr[2]
  80. self.__storeStop = 0
  81. self.__epsilon = 0.01
  82. self.__broadcastPeriod = period
  83. # Broadcast our initial position
  84. self.b_clearSmoothing()
  85. self.d_setSmPosHpr(self.__storeX, self.__storeY, self.__storeZ,
  86. self.__storeH, self.__storeP, self.__storeR)
  87. # remove any old tasks
  88. taskMgr.remove(taskName)
  89. # spawn the new task
  90. delay = 0.
  91. if stagger:
  92. delay = randFloat(period)
  93. taskMgr.doMethodLater(self.__broadcastPeriod + delay,
  94. self.posHprBroadcast, taskName)
  95. def posHprBroadcast(self, task):
  96. # TODO: we explicitly stagger the initial task timing in
  97. # startPosHprBroadcast; we should at least make an effort to keep
  98. # this task accurately aligned with its period and starting time.
  99. self.d_broadcastPosHpr()
  100. taskName = self.taskName("sendPosHpr")
  101. taskMgr.doMethodLater(self.__broadcastPeriod,
  102. self.posHprBroadcast, taskName)
  103. return Task.done
  104. def d_broadcastPosHpr_FULL(self):
  105. # send out the minimal bits to describe our new position
  106. xyz = self.getPos()
  107. hpr = self.getHpr()
  108. if abs(self.__storeX - xyz[0]) > self.__epsilon:
  109. self.__storeX = xyz[0]
  110. newX = 1
  111. else:
  112. newX = 0
  113. if abs(self.__storeY - xyz[1]) > self.__epsilon:
  114. self.__storeY = xyz[1]
  115. newY = 1
  116. else:
  117. newY = 0
  118. if abs(self.__storeZ - xyz[2]) > self.__epsilon:
  119. self.__storeZ = xyz[2]
  120. newZ = 1
  121. else:
  122. newZ = 0
  123. if abs(self.__storeH - hpr[0]) > self.__epsilon:
  124. self.__storeH = hpr[0]
  125. newH = 1
  126. else:
  127. newH = 0
  128. if abs(self.__storeP - hpr[1]) > self.__epsilon:
  129. self.__storeP = hpr[1]
  130. newP = 1
  131. else:
  132. newP = 0
  133. if abs(self.__storeR - hpr[2]) > self.__epsilon:
  134. self.__storeR = hpr[2]
  135. newR = 1
  136. else:
  137. newR = 0
  138. # Check for changes:
  139. if not(newX or newY or newZ or newH or newP or newR):
  140. # No change
  141. # Send one and only one "stop" message.
  142. if not self.__storeStop:
  143. self.__storeStop = 1
  144. self.d_setSmStop()
  145. # print 'no change'
  146. elif (newH) and not(newX or newY or newZ or newP or newR):
  147. # Only change in H
  148. self.__storeStop = 0
  149. self.d_setSmH(self.__storeH)
  150. # print ("H change")
  151. elif (newX or newY) and not(newZ or newH or newP or newR):
  152. # Only change in X, Y
  153. self.__storeStop = 0
  154. self.d_setSmXY(self.__storeX, self.__storeY)
  155. # print ("XY change")
  156. elif (newX or newY or newZ) and not(newH or newP or newR):
  157. # Only change in X, Y, Z
  158. self.__storeStop = 0
  159. self.d_setSmPos(self.__storeX, self.__storeY, self.__storeZ)
  160. # print ("XYZ change")
  161. elif (newX or newY or newH) and not(newZ or newP or newR):
  162. # Only change in X, Y, H
  163. self.__storeStop = 0
  164. self.d_setSmXYH(self.__storeX, self.__storeY, self.__storeH)
  165. # print ("XYH change")
  166. elif (newX or newY or newZ or newH) and not(newP or newR):
  167. # Only change in X, Y, Z, H
  168. self.__storeStop = 0
  169. self.d_setSmXYZH(self.__storeX, self.__storeY, self.__storeZ, self.__storeH)
  170. # print ("XYZH change")
  171. else:
  172. # Other changes
  173. self.__storeStop = 0
  174. self.d_setSmPosHpr(self.__storeX, self.__storeY, self.__storeZ,
  175. self.__storeH, self.__storeP, self.__storeR)
  176. # print ("XYZHPR change")
  177. def d_broadcastPosHpr_XYH(self):
  178. # send out the minimal bits to describe our new position
  179. assert not self.isEmpty(), 'DistributedSmoothNode %s has been removed from graph?' % self.doId
  180. xyz = self.getPos()
  181. h = self.getH()
  182. if abs(self.__storeX - xyz[0]) > self.__epsilon:
  183. self.__storeX = xyz[0]
  184. newX = 1
  185. else:
  186. newX = 0
  187. if abs(self.__storeY - xyz[1]) > self.__epsilon:
  188. self.__storeY = xyz[1]
  189. newY = 1
  190. else:
  191. newY = 0
  192. if abs(self.__storeH - h) > self.__epsilon:
  193. self.__storeH = h
  194. newH = 1
  195. else:
  196. newH = 0
  197. # Check for changes:
  198. if not(newX or newY or newH):
  199. # No change
  200. # Send one and only one "stop" message.
  201. if not self.__storeStop:
  202. self.__storeStop = 1
  203. self.d_setSmStop()
  204. # print 'no change'
  205. elif (newH) and not(newX or newY):
  206. # Only change in H
  207. self.__storeStop = 0
  208. self.d_setSmH(self.__storeH)
  209. # print ("H change")
  210. elif (newX or newY) and not(newH):
  211. # Only change in X, Y
  212. self.__storeStop = 0
  213. self.d_setSmXY(self.__storeX, self.__storeY)
  214. # print ("XY change")
  215. else:
  216. # Only change in X, Y, H
  217. self.__storeStop = 0
  218. self.d_setSmXYH(self.__storeX, self.__storeY, self.__storeH)
  219. # print ("XYH change")