# hprInterval

I would have thought that the hpr interval takes the shortest distance to the destination angle…I can adjust for this in code, but is this really the desired output?

``````import direct.directbase.DirectStart
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import *

s.reparentTo(render)
s.setH(-90)

s.hprInterval(10,Vec3(180,0,0)).start()

run()``````

the smiley turns 270 degrees instead of 90 the other way…The way around this is to either turn the -90 into 270 or the 180 to -180, and I can do this with some smart algorithms, but when the values are dynamic it gets a little more complex.

(Also, lerping from 0 to 360 or -180 to 180 results in a full 360 degree turn instead of a zero turn…)

Is this the desired result?
(the easy fix is simply to make sure that everything on the input side is in the range [0,360).

That’s the limitation of euler rotations, along with others.

The simple solution is to use a quatInterval, and to convert your rotations into quaternions.

``````import direct.directbase.DirectStart
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import *

s.reparentTo(render)
s.setH(-90)

q = Quat()
q.setHpr(Vec3(180, 0, 0))
s.quatInterval(10,q).start()

run() ``````

Note that quatInterval can automatically convert your hprs to quaternions:

``s.quatInterval(10, hpr = Vec3(180, 0, 0)).start()``

Note that this isn’t in fact a fix at all. If the hprInterval constrained all its inputs into [0, 360), it would change the 20-degree lerp from 10 to -10 into a 340-degree lerp from 10 to 350. If you insist on working with Euler angles, the real solution is to use PythonUtil.fitDestAngleToSrc() to match the destination angle to within +/- 180 degrees of the source angle. The hprInterval doesn’t do this automatically, though, because maybe you wanted it to go the long way around. (In fact you can construct a hprInterval that spins several times around before it stops, and this is sometimes useful.)

David

Actually I looked again and I am doing quite a bit more things than just that, but that is step number one…sorry for the partial answer.

I had a solution, basically copied straight from gpwiki.net, but it seems much more complicated than the solutions above:

``````def turnUnit(self, task):
H = self.model.getH() #self.model is the actor class
T = self.destinationAngle
if T < 0: T = 360.0+T
if H < 0: H = 360.0+H

maxTurn = self.turnSpeed*dt
targetVec.normalize()
curVec.normalize()
xProduct = targetVec.cross(curVec)
if abs(T-H) < maxTurn:
self.model.setH(T)
return
if xProduct > 0:
if H-maxTurn < 0:
self.model.setH(360+(H-maxTurn))
else:
self.model.setH(H-maxTurn)
else:
if H+maxTurn > 360:
self.model.setH(H+maxTurn-360)
else:
self.model.setH(H+maxTurn)