protected void updateSplineCache() { Vec deltaP = Vec.subtract( keyFrameList.get(currentFrame2.nextIndex()).position(), keyFrameList.get(currentFrame1.nextIndex()).position()); pv1 = Vec.add( Vec.multiply(deltaP, 3.0f), Vec.multiply(keyFrameList.get(currentFrame1.nextIndex()).tgP(), (-2.0f))); pv1 = Vec.subtract(pv1, keyFrameList.get(currentFrame2.nextIndex()).tgP()); pv2 = Vec.add(Vec.multiply(deltaP, (-2.0f)), keyFrameList.get(currentFrame1.nextIndex()).tgP()); pv2 = Vec.add(pv2, keyFrameList.get(currentFrame2.nextIndex()).tgP()); splineCacheIsValid = true; }
protected void updateCurrentKeyFrameForTime(float time) { // Assertion: times are sorted in monotone order. // Assertion: keyFrame_ is not empty // TODO: Special case for loops when closed path is implemented !! if (!currentFrmValid) // Recompute everything from scratch currentFrame1 = keyFrameList.listIterator(); // currentFrame_[1]->peekNext() <---> keyFr.get(currentFrame1.nextIndex()); while (keyFrameList.get(currentFrame1.nextIndex()).time() > time) { currentFrmValid = false; if (!currentFrame1.hasPrevious()) break; currentFrame1.previous(); } if (!currentFrmValid) currentFrame2 = keyFrameList.listIterator(currentFrame1.nextIndex()); while (keyFrameList.get(currentFrame2.nextIndex()).time() < time) { currentFrmValid = false; if (!currentFrame2.hasNext()) break; currentFrame2.next(); } if (!currentFrmValid) { currentFrame1 = keyFrameList.listIterator(currentFrame2.nextIndex()); if ((currentFrame1.hasPrevious()) && (time < keyFrameList.get(currentFrame2.nextIndex()).time())) currentFrame1.previous(); currentFrame0 = keyFrameList.listIterator(currentFrame1.nextIndex()); if (currentFrame0.hasPrevious()) currentFrame0.previous(); currentFrame3 = keyFrameList.listIterator(currentFrame2.nextIndex()); if (currentFrame3.hasNext()) currentFrame3.next(); currentFrmValid = true; splineCacheIsValid = false; } }
/** * Interpolate {@link #frame()} at time {@code time} (expressed in seconds). {@link * #interpolationTime()} is set to {@code time} and {@link #frame()} is set accordingly. * * <p>If you simply want to change {@link #interpolationTime()} but not the {@link #frame()} * state, use {@link #setInterpolationTime(float)} instead. */ public void interpolateAtTime(float time) { this.checkValidity(); setInterpolationTime(time); if ((keyFrameList.isEmpty()) || (frame() == null)) return; if (!valuesAreValid) updateModifiedFrameValues(); updateCurrentKeyFrameForTime(time); if (!splineCacheIsValid) updateSplineCache(); float alpha; float dt = keyFrameList.get(currentFrame2.nextIndex()).time() - keyFrameList.get(currentFrame1.nextIndex()).time(); if (Util.zero(dt)) alpha = 0.0f; else alpha = (time - keyFrameList.get(currentFrame1.nextIndex()).time()) / dt; Vec pos = Vec.add( keyFrameList.get(currentFrame1.nextIndex()).position(), Vec.multiply( Vec.add( keyFrameList.get(currentFrame1.nextIndex()).tgP(), Vec.multiply(Vec.add(pv1, Vec.multiply(pv2, alpha)), alpha)), alpha)); float mag = Util.lerp( keyFrameList.get(currentFrame1.nextIndex()).magnitude(), keyFrameList.get(currentFrame2.nextIndex()).magnitude(), alpha); Rotation q; if (gScene.is3D()) { q = Quat.squad( (Quat) keyFrameList.get(currentFrame1.nextIndex()).orientation(), ((KeyFrame3D) keyFrameList.get(currentFrame1.nextIndex())).tgQ(), ((KeyFrame3D) keyFrameList.get(currentFrame2.nextIndex())).tgQ(), (Quat) keyFrameList.get(currentFrame2.nextIndex()).orientation(), alpha); } else { q = new Rot( Util.lerp( keyFrameList.get(currentFrame1.nextIndex()).orientation().angle(), keyFrameList.get(currentFrame2.nextIndex()).orientation().angle(), (alpha))); } frame().setPositionWithConstraint(pos); frame().setRotationWithConstraint(q); frame().setMagnitude(mag); }