DirectGeometry.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. from PandaModules import *
  2. from PandaObject import *
  3. from DirectGlobals import *
  4. from DirectUtil import *
  5. import math
  6. class LineNodePath(NodePath):
  7. def __init__(self, parent = None, name = None,
  8. thickness = 1.0, colorVec = VBase4(1)):
  9. # Initialize the superclass
  10. NodePath.__init__(self)
  11. if parent is None:
  12. parent = hidden
  13. # Attach a geomNode to the parent and set self to be
  14. # the resulting node path
  15. self.lineNode = GeomNode("lineNode")
  16. self.assign(parent.attachNewNode( self.lineNode ))
  17. if name:
  18. self.setName(name)
  19. # Create a lineSegs object to hold the line
  20. ls = self.lineSegs = LineSegs()
  21. # Initialize the lineSegs parameters
  22. ls.setThickness(thickness)
  23. ls.setColor(colorVec)
  24. def moveTo( self, *_args ):
  25. apply( self.lineSegs.moveTo, _args )
  26. def drawTo( self, *_args ):
  27. apply( self.lineSegs.drawTo, _args )
  28. def create( self, frameAccurate = 0 ):
  29. self.lineSegs.create( self.lineNode, frameAccurate )
  30. def reset( self ):
  31. self.lineSegs.reset()
  32. self.lineNode.removeAllGeoms()
  33. def isEmpty( self ):
  34. return self.lineSegs.isEmpty()
  35. def setThickness( self, thickness ):
  36. self.lineSegs.setThickness( thickness )
  37. def setColor( self, *_args ):
  38. apply( self.lineSegs.setColor, _args )
  39. def setVertex( self, *_args):
  40. apply( self.lineSegs.setVertex, _args )
  41. def setVertexColor( self, vertex, *_args ):
  42. apply( self.lineSegs.setVertexColor, (vertex,) + _args )
  43. def getCurrentPosition( self ):
  44. return self.lineSegs.getCurrentPosition()
  45. def getNumVertices( self ):
  46. return self.lineSegs.getNumVertices()
  47. def getVertex( self, index ):
  48. return self.lineSegs.getVertex(index)
  49. def getVertexColor( self ):
  50. return self.lineSegs.getVertexColor()
  51. def drawArrow(self, sv, ev, arrowAngle, arrowLength):
  52. """
  53. Do the work of moving the cursor around to draw an arrow from
  54. sv to ev. Hack: the arrows take the z value of the end point
  55. """
  56. self.moveTo(sv)
  57. self.drawTo(ev)
  58. v = sv - ev
  59. # Find the angle of the line
  60. angle = math.atan2(v[1], v[0])
  61. # Get the arrow angles
  62. a1 = angle + deg2Rad(arrowAngle)
  63. a2 = angle - deg2Rad(arrowAngle)
  64. # Get the arrow points
  65. a1x = arrowLength * math.cos(a1)
  66. a1y = arrowLength * math.sin(a1)
  67. a2x = arrowLength * math.cos(a2)
  68. a2y = arrowLength * math.sin(a2)
  69. z = ev[2]
  70. self.moveTo(ev)
  71. self.drawTo(Point3(ev + Point3(a1x, a1y, z)))
  72. self.moveTo(ev)
  73. self.drawTo(Point3(ev + Point3(a2x, a2y, z)))
  74. def drawArrow2d(self, sv, ev, arrowAngle, arrowLength):
  75. """
  76. Do the work of moving the cursor around to draw an arrow from
  77. sv to ev. Hack: the arrows take the z value of the end point
  78. """
  79. self.moveTo(sv)
  80. self.drawTo(ev)
  81. v = sv - ev
  82. # Find the angle of the line
  83. angle = math.atan2(v[2], v[0])
  84. # Get the arrow angles
  85. a1 = angle + deg2Rad(arrowAngle)
  86. a2 = angle - deg2Rad(arrowAngle)
  87. # Get the arrow points
  88. a1x = arrowLength * math.cos(a1)
  89. a1y = arrowLength * math.sin(a1)
  90. a2x = arrowLength * math.cos(a2)
  91. a2y = arrowLength * math.sin(a2)
  92. self.moveTo(ev)
  93. self.drawTo(Point3(ev + Point3(a1x, 0.0, a1y)))
  94. self.moveTo(ev)
  95. self.drawTo(Point3(ev + Point3(a2x, 0.0, a2y)))
  96. def drawLines(self, lineList):
  97. """
  98. Given a list of lists of points, draw a separate line for each list
  99. """
  100. for pointList in lineList:
  101. apply(self.moveTo, pointList[0])
  102. for point in pointList[1:]:
  103. apply(self.drawTo, point)
  104. ##
  105. ## Given a point in space, and a direction, find the point of intersection
  106. ## of that ray with a plane at the specified origin, with the specified normal
  107. def planeIntersect (lineOrigin, lineDir, planeOrigin, normal):
  108. t = 0
  109. offset = planeOrigin - lineOrigin
  110. t = offset.dot(normal) / lineDir.dot(normal)
  111. hitPt = lineDir * t
  112. return hitPt + lineOrigin
  113. def getNearProjectionPoint(nodePath):
  114. # Find the position of the projection of the specified node path
  115. # on the near plane
  116. origin = nodePath.getPos(direct.camera)
  117. # project this onto near plane
  118. if origin[1] != 0.0:
  119. return origin * (direct.dr.near / origin[1])
  120. else:
  121. # Object is coplaner with camera, just return something reasonable
  122. return Point3(0, direct.dr.near, 0)
  123. def getScreenXY(nodePath):
  124. # Where does the node path's projection fall on the near plane
  125. nearVec = getNearProjectionPoint(nodePath)
  126. # Clamp these coordinates to visible screen
  127. nearX = CLAMP(nearVec[0], direct.dr.left, direct.dr.right)
  128. nearY = CLAMP(nearVec[2], direct.dr.bottom, direct.dr.top)
  129. # What percentage of the distance across the screen is this?
  130. percentX = (nearX - direct.dr.left)/direct.dr.nearWidth
  131. percentY = (nearY - direct.dr.bottom)/direct.dr.nearHeight
  132. # Map this percentage to the same -1 to 1 space as the mouse
  133. screenXY = Vec3((2 * percentX) - 1.0,nearVec[1],(2 * percentY) - 1.0)
  134. # Return the resulting value
  135. return screenXY
  136. def getCrankAngle(center):
  137. # Used to compute current angle of mouse (relative to the coa's
  138. # origin) in screen space
  139. x = direct.dr.mouseX - center[0]
  140. y = direct.dr.mouseY - center[2]
  141. return (180 + rad2Deg(math.atan2(y,x)))
  142. def relHpr(nodePath, base, h, p, r):
  143. # Compute nodePath2newNodePath relative to base coordinate system
  144. # nodePath2base
  145. mNodePath2Base = nodePath.getMat(base)
  146. # delta scale, orientation, and position matrix
  147. mBase2NewBase = Mat4()
  148. composeMatrix(mBase2NewBase, UNIT_VEC, VBase3(h,p,r), ZERO_VEC,
  149. CSDefault)
  150. # base2nodePath
  151. mBase2NodePath = base.getMat(nodePath)
  152. # nodePath2 Parent
  153. mNodePath2Parent = nodePath.getMat()
  154. # Compose the result
  155. resultMat = mNodePath2Base * mBase2NewBase
  156. resultMat = resultMat * mBase2NodePath
  157. resultMat = resultMat * mNodePath2Parent
  158. # Extract and apply the hpr
  159. hpr = Vec3(0)
  160. decomposeMatrix(resultMat, VBase3(), hpr, VBase3(),
  161. CSDefault)
  162. nodePath.setHpr(hpr)
  163. # Quaternion interpolation
  164. def qSlerp(startQuat, endQuat, t):
  165. startQ = Quat(startQuat)
  166. destQuat = Quat.identQuat()
  167. # Calc dot product
  168. cosOmega = (startQ.getI() * endQuat.getI() +
  169. startQ.getJ() * endQuat.getJ() +
  170. startQ.getK() * endQuat.getK() +
  171. startQ.getR() * endQuat.getR())
  172. # If the above dot product is negative, it would be better to
  173. # go between the negative of the initial and the final, so that
  174. # we take the shorter path.
  175. if ( cosOmega < 0.0 ):
  176. cosOmega *= -1
  177. startQ.setI(-1 * startQ.getI())
  178. startQ.setJ(-1 * startQ.getJ())
  179. startQ.setK(-1 * startQ.getK())
  180. startQ.setR(-1 * startQ.getR())
  181. if ((1.0 + cosOmega) > Q_EPSILON):
  182. # usual case
  183. if ((1.0 - cosOmega) > Q_EPSILON):
  184. # usual case
  185. omega = math.acos(cosOmega)
  186. sinOmega = math.sin(omega)
  187. startScale = math.sin((1.0 - t) * omega)/sinOmega
  188. endScale = math.sin(t * omega)/sinOmega
  189. else:
  190. # ends very close
  191. startScale = 1.0 - t
  192. endScale = t
  193. destQuat.setI(startScale * startQ.getI() +
  194. endScale * endQuat.getI())
  195. destQuat.setJ(startScale * startQ.getJ() +
  196. endScale * endQuat.getJ())
  197. destQuat.setK(startScale * startQ.getK() +
  198. endScale * endQuat.getK())
  199. destQuat.setR(startScale * startQ.getR() +
  200. endScale * endQuat.getR())
  201. else:
  202. # ends nearly opposite
  203. destQuat.setI(-startQ.getJ())
  204. destQuat.setJ(startQ.getI())
  205. destQuat.setK(-startQ.getR())
  206. destQuat.setR(startQ.getK())
  207. startScale = math.sin((0.5 - t) * math.pi)
  208. endScale = math.sin(t * math.pi)
  209. destQuat.setI(startScale * startQ.getI() +
  210. endScale * endQuat.getI())
  211. destQuat.setJ(startScale * startQ.getJ() +
  212. endScale * endQuat.getJ())
  213. destQuat.setK(startScale * startQ.getK() +
  214. endScale * endQuat.getK())
  215. return destQuat