/** * 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); }
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; }
void animate() { dim = getSize(); size = (int) (Math.min(dim.height, dim.width) / 2.2); timer.tell_time(); if (timer.time_diff == 0) return; // not enought time has passed, dont animate-crach fix dragged_speed = dragged_vec.sub(last_dragged_vec).div(timer.time_diff); last_dragged_vec = dragged_vec; if (dragged_ball != -1) { balls.get2(dragged_ball).pos = dragged_vec.add(find_offset).trim(-1, 1); balls.get2(dragged_ball).speed = dragged_speed; } balls = new WorldAnimate().calc_new_frame(balls, springs, RADIUS, timer); }
private void floodFillSimilarClusters( int unitpos, int[] clusterassoc, double[][] lkvalues, int[][] neighbors, int startunitpos) { // check if already associated to other cluster (end of recursion) if (clusterassoc[unitpos] != unitpos && clusterassoc[unitpos] != startunitpos) return; Vector<Integer> joinedunits = new Vector<Integer>(); // check neighbors (starts with index 1) for join candidates for (int i = 1; i < neighbors[unitpos].length; i++) { if (neighbors[unitpos][i] != -1 && // on the som clusterassoc[neighbors[unitpos][i]] != startunitpos && // not already in cluster clusterassoc[neighbors[unitpos][i]] == neighbors[unitpos][i]) { // not part of any other cluster // join two units iff summed up vector differs below threshold from both original vectors double[] cosNormA = Vec.cosineNormalize(Vec.cloneVector(lkvalues[unitpos])); double[] cosNormB = Vec.cosineNormalize(Vec.cloneVector(lkvalues[neighbors[unitpos][i]])); double[] sumAB = Vec.add(lkvalues[unitpos], lkvalues[neighbors[unitpos][i]]); double[] cosNormAB = Vec.cosineNormalize(Vec.cloneVector(sumAB)); if (Vec.euclDist(cosNormA, cosNormAB) < 0.6 && Vec.euclDist(cosNormB, cosNormAB) < 0.6) { // similar units -> join clusterassoc[neighbors[unitpos][i]] = startunitpos; // write new vector to all associated for (int k = 0; k < clusterassoc.length; k++) { if (clusterassoc[k] == startunitpos) { lkvalues[k] = sumAB; } } // Vec.copyTo(lkvalues[unitpos], sumAB); // Vec.copyTo(lkvalues[neighbors[unitpos][i]], sumAB); // add to list for recursion joinedunits.addElement(new Integer(neighbors[unitpos][i])); } } } // recursion over joined units Iterator<Integer> iit = joinedunits.iterator(); while (iit.hasNext()) { floodFillSimilarClusters( iit.next().intValue(), clusterassoc, lkvalues, neighbors, startunitpos); } }
public static Vec sub(Vec v1, Vec v2) { return Vec.add(v1, v2.scale(-1.0f)); }
/** Intenal use. Call {@link #checkValidity()} and if path is not valid recomputes it. */ protected void updatePath() { checkValidity(); if (!pathIsValid) { path.clear(); int nbSteps = 30; if (keyFrameList.isEmpty()) return; if (!valuesAreValid) updateModifiedFrameValues(); if (keyFrameList.get(0) == keyFrameList.get(keyFrameList.size() - 1)) // TODO experimenting really path.add( new Frame( keyFrameList.get(0).position(), keyFrameList.get(0).orientation(), keyFrameList.get(0).magnitude())); else { KeyFrame[] kf = new KeyFrame[4]; kf[0] = keyFrameList.get(0); kf[1] = kf[0]; int index = 1; kf[2] = (index < keyFrameList.size()) ? keyFrameList.get(index) : null; index++; kf[3] = (index < keyFrameList.size()) ? keyFrameList.get(index) : null; while (kf[2] != null) { Vec pdiff = Vec.subtract(kf[2].position(), kf[1].position()); Vec pvec1 = Vec.add(Vec.multiply(pdiff, 3.0f), Vec.multiply(kf[1].tgP(), (-2.0f))); pvec1 = Vec.subtract(pvec1, kf[2].tgP()); Vec pvec2 = Vec.add(Vec.multiply(pdiff, (-2.0f)), kf[1].tgP()); pvec2 = Vec.add(pvec2, kf[2].tgP()); for (int step = 0; step < nbSteps; ++step) { Frame frame = new Frame(); float alpha = step / (float) nbSteps; frame.setPosition( Vec.add( kf[1].position(), Vec.multiply( Vec.add( kf[1].tgP(), Vec.multiply(Vec.add(pvec1, Vec.multiply(pvec2, alpha)), alpha)), alpha))); if (gScene.is3D()) { frame.setOrientation( Quat.squad( (Quat) kf[1].orientation(), ((KeyFrame3D) kf[1]).tgQ(), ((KeyFrame3D) kf[2]).tgQ(), (Quat) kf[2].orientation(), alpha)); } else { // linear interpolation float start = kf[1].orientation().angle(); float stop = kf[2].orientation().angle(); frame.setOrientation(new Rot(start + (stop - start) * alpha)); } frame.setMagnitude(Util.lerp(kf[1].magnitude(), kf[2].magnitude(), alpha)); path.add(frame.get()); } // Shift kf[0] = kf[1]; kf[1] = kf[2]; kf[2] = kf[3]; index++; kf[3] = (index < keyFrameList.size()) ? keyFrameList.get(index) : null; } // Add last KeyFrame path.add(new Frame(kf[1].position(), kf[1].orientation(), kf[1].magnitude())); } pathIsValid = true; } }