Project

General

Profile

Download (23.9 KB) Statistics
| Branch: | Revision:

library / src / main / java / org / distorted / library / type / Dynamic.java @ 291705f6

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.library.type;
21

    
22
import java.util.Random;
23
import java.util.Vector;
24

    
25
///////////////////////////////////////////////////////////////////////////////////////////////////
26
/** A class to interpolate between a list of Statics.
27
* <p><ul>
28
* <li>if there is only one Point, just jump to it.
29
* <li>if there are two Points, linearly bounce between them
30
* <li>if there are more, interpolate a loop (or a path!) between them.
31
* </ul>
32
*/
33

    
34
// The way Interpolation between more than 2 Points is done:
35
// 
36
// Def: let w[i] = (w[i](x), w[i](y), w[i](z)) be the direction and speed we have to be flying at Point P[i]
37
//
38
// time it takes to fly though one segment v[i] --> v[i+1] : 0.0 --> 1.0
39
// w[i] should be parallel to v[i+1] - v[i-1]   (cyclic notation)
40
// |w[i]| proportional to | P[i]-P[i+1] |
41
//
42
// Given that the flight route (X(t), Y(t), Z(t)) from P(i) to P(i+1)  (0<=t<=1) has to satisfy
43
// X(0) = P[i  ](x), Y(0)=P[i  ](y), Z(0)=P[i  ](z), X'(0) = w[i  ](x), Y'(0) = w[i  ](y), Z'(0) = w[i  ](z)
44
// X(1) = P[i+1](x), Y(1)=P[i+1](y), Z(1)=P[i+1](z), X'(1) = w[i+1](x), Y'(1) = w[i+1](y), Z'(1) = w[i+1](z)
45
//
46
// we have the solution:  X(t) = at^3 + bt^2 + ct + d where
47
// a =  2*P[i](x) +   w[i](x) - 2*P[i+1](x) + w[i+1](x)
48
// b = -3*P[i](x) - 2*w[i](x) + 3*P[i+1](x) - w[i+1](x)
49
// c = w[i](x)
50
// d = P[i](x)
51
//
52
// and similarly Y(t) and Z(t).
53

    
54
public abstract class Dynamic
55
  {
56
  /**
57
   * One revolution takes us from the first vector to the last and back to first through the shortest path. 
58
   */
59
  public static final int MODE_LOOP = 0; 
60
  /**
61
   * We come back from the last to the first vector through the same way we got there.
62
   */
63
  public static final int MODE_PATH = 1; 
64
  /**
65
   * We just jump back from the last point to the first.
66
   */
67
  public static final int MODE_JUMP = 2; 
68

    
69
  protected int mDimension;
70
  protected int numPoints;
71
  protected int mSegment;       // between which pair of points are we currently? (in case of PATH this is a bit complicated!)
72
  protected boolean cacheDirty; // VectorCache not up to date
73
  protected int mMode;          // LOOP, PATH or JUMP
74
  protected long mDuration;     // number of milliseconds it takes to do a full loop/path from first vector to the last and back to the first
75
  protected float mCount;       // number of loops/paths we will do; mCount = 1.5 means we go from the first vector to the last, back to first, and to the last again. 
76

    
77
  protected class VectorNoise
78
    {
79
    float[][] n;
80

    
81
    VectorNoise()
82
      {
83
      n = new float[mDimension][NUM_NOISE];
84
      }
85

    
86
    void computeNoise()
87
      {
88
      n[0][0] = mRnd.nextFloat();
89
      for(int i=1; i<NUM_NOISE; i++) n[0][i] = n[0][i-1]+mRnd.nextFloat();
90

    
91
      float sum = n[0][NUM_NOISE-1] + mRnd.nextFloat();
92

    
93
      for(int i=0; i<NUM_NOISE; i++)
94
        {
95
        n[0][i] /=sum;
96
        for(int j=1; j<mDimension; j++) n[j][i] = mRnd.nextFloat()-0.5f;
97
        }
98
      }
99
    }
100

    
101
  protected Vector<VectorNoise> vn;
102
  protected float[] mFactor;
103
  protected float[] mNoise;
104
  protected float[][] baseV;
105

    
106
  ///////////////////////////////////////////////////////////////////////////////////////////////////
107
  // the coefficients of the X(t), Y(t) and Z(t) polynomials: X(t) = ax*T^3 + bx*T^2 + cx*t + dx  etc.
108
  // (tangent) is the vector tangent to the path.
109
  // (cached) is the original vector from vv (copied here so when interpolating we can see if it is
110
  // still valid and if not - rebuild the Cache
111

    
112
  protected class VectorCache
113
    {
114
    float[] a;
115
    float[] b;
116
    float[] c;
117
    float[] d;
118
    float[] tangent;
119
    float[] cached;
120

    
121
    VectorCache()
122
      {
123
      a = new float[mDimension];
124
      b = new float[mDimension];
125
      c = new float[mDimension];
126
      d = new float[mDimension];
127
      tangent = new float[mDimension];
128
      cached = new float[mDimension];
129
      }
130
    }
131

    
132
  protected Vector<VectorCache> vc;
133
  protected VectorCache tmp1, tmp2;
134

    
135
  private float[] buf;
136
  private float[] old;
137
  private static Random mRnd = new Random();
138
  private static final int NUM_NOISE = 5; // used iff mNoise>0.0. Number of intermediary points between each pair of adjacent vectors
139
                                          // where we randomize noise factors to make the way between the two vectors not so smooth.
140

    
141
//private int lastNon;
142

    
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144
// hide this from Javadoc
145
  
146
  protected Dynamic()
147
    {
148
    }
149

    
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151

    
152
  protected Dynamic(int duration, float count, int dimension)
153
    {
154
    vc         = new Vector<>();
155
    vn         = null;
156
    numPoints  = 0;
157
    cacheDirty = false;
158
    mMode      = MODE_LOOP;
159
    mDuration  = duration;
160
    mCount     = count;
161
    mDimension = dimension;
162
    mSegment   = -1;
163

    
164
    baseV      = new float[mDimension][mDimension];
165
    buf        = new float[mDimension];
166
    old        = new float[mDimension];
167
    }
168

    
169
///////////////////////////////////////////////////////////////////////////////////////////////////
170
  
171
  public void interpolateMain(float[] buffer, int offset, long currentDuration)
172
    {
173
    if( mDuration<=0.0f ) 
174
      {
175
      interpolate(buffer,offset,mCount-(int)mCount);  
176
      }
177
    else
178
      {
179
      double x = (double)currentDuration/mDuration;
180
           
181
      if( x<=mCount || mCount<=0.0f )
182
        {
183
        interpolate(buffer,offset, (float)(x-(int)x) );
184
        }
185
      }
186
    }
187
  
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189

    
190
  public boolean interpolateMain(float[] buffer, int offset, long currentDuration, long step)
191
    {
192
    if( mDuration<=0.0f ) 
193
      {
194
      interpolate(buffer,offset,mCount-(int)mCount);
195
      return false;
196
      }
197
     
198
    double x = (double)currentDuration/mDuration;
199
           
200
    if( x<=mCount || mCount<=0.0f )
201
      {
202
      interpolate(buffer,offset, (float)(x-(int)x) );
203
        
204
      if( currentDuration+step > mDuration*mCount && mCount>0.0f )
205
        {
206
        interpolate(buffer,offset,mCount-(int)mCount);
207
        return true;
208
        }
209
      }
210
    
211
    return false;
212
    }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215

    
216
  protected float noise(float time,int vecNum)
217
    {
218
    float lower, upper, len;
219
    float d = time*(NUM_NOISE+1);
220
    int index = (int)d;
221
    if( index>=NUM_NOISE+1 ) index=NUM_NOISE;
222
    VectorNoise tmpN = vn.elementAt(vecNum);
223

    
224
    float t = d-index;
225
    t = t*t*(3-2*t);
226

    
227
    switch(index)
228
      {
229
      case 0        : for(int i=0;i<mDimension-1;i++) mFactor[i] = mNoise[i+1]*tmpN.n[i+1][0]*t;
230
                      return time + mNoise[0]*(d*tmpN.n[0][0]-time);
231
      case NUM_NOISE: for(int i=0;i<mDimension-1;i++) mFactor[i] = mNoise[i+1]*tmpN.n[i+1][NUM_NOISE-1]*(1-t);
232
                      len = ((float)NUM_NOISE)/(NUM_NOISE+1);
233
                      lower = len + mNoise[0]*(tmpN.n[0][NUM_NOISE-1]-len);
234
                      return (1.0f-lower)*(d-NUM_NOISE) + lower;
235
      default       : float ya,yb;
236

    
237
                      for(int i=0;i<mDimension-1;i++)
238
                        {
239
                        yb = tmpN.n[i+1][index  ];
240
                        ya = tmpN.n[i+1][index-1];
241
                        mFactor[i] = mNoise[i+1]*((yb-ya)*t+ya);
242
                        }
243

    
244
                      len = ((float)index)/(NUM_NOISE+1);
245
                      lower = len + mNoise[0]*(tmpN.n[0][index-1]-len);
246
                      len = ((float)index+1)/(NUM_NOISE+1);
247
                      upper = len + mNoise[0]*(tmpN.n[0][index  ]-len);
248

    
249
                      return (upper-lower)*(d-index) + lower;
250
      }
251
    }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254
// debugging only
255

    
256
  private void printBase(String str)
257
    {
258
    String s;
259
    float t;
260

    
261
    for(int i=0; i<mDimension; i++)
262
      {
263
      s = "";
264

    
265
      for(int j=0; j<mDimension; j++)
266
        {
267
        t = ((int)(1000*baseV[i][j]))/(1000.0f);
268
        s+=(" "+t);
269
        }
270
      android.util.Log.e("dynamic", str+" base "+i+" : " + s);
271
      }
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275
// debugging only
276

    
277
  private void checkBase()
278
    {
279
    float tmp, cosA;
280
    float[] len= new float[mDimension];
281
    boolean error=false;
282

    
283
    for(int i=0; i<mDimension; i++)
284
      {
285
      len[i] = 0.0f;
286

    
287
      for(int k=0; k<mDimension; k++)
288
        {
289
        len[i] += baseV[i][k]*baseV[i][k];
290
        }
291

    
292
      if( len[i] == 0.0f || len[0]/len[i] < 0.95f || len[0]/len[i]>1.05f )
293
        {
294
        android.util.Log.e("dynamic", "length of vector "+i+" : "+Math.sqrt(len[i]));
295
        error = true;
296
        }
297
      }
298

    
299
    for(int i=0; i<mDimension; i++)
300
      for(int j=i+1; j<mDimension; j++)
301
        {
302
        tmp = 0.0f;
303

    
304
        for(int k=0; k<mDimension; k++)
305
          {
306
          tmp += baseV[i][k]*baseV[j][k];
307
          }
308

    
309
        cosA = ( (len[i]==0.0f || len[j]==0.0f) ? 0.0f : tmp/(float)Math.sqrt(len[i]*len[j]));
310

    
311
        if( cosA > 0.05f || cosA < -0.05f )
312
          {
313
          android.util.Log.e("dynamic", "cos angle between vectors "+i+" and "+j+" : "+cosA);
314
          error = true;
315
          }
316
        }
317

    
318
    if( error ) printBase("");
319
    }
320

    
321
///////////////////////////////////////////////////////////////////////////////////////////////////
322

    
323
  private void checkAngle(int index)
324
    {
325
    float cosA = 0.0f;
326

    
327
    for(int k=0;k<mDimension; k++)
328
      cosA += baseV[index][k]*old[k];
329

    
330
    if( cosA<0.0f )
331
      {
332
/*
333
      /// DEBUGGING ////
334
      String s = index+" (";
335
      float t;
336

    
337
      for(int j=0; j<mDimension; j++)
338
        {
339
        t = ((int)(100*baseV[index][j]))/(100.0f);
340
        s+=(" "+t);
341
        }
342
      s += ") (";
343

    
344
      for(int j=0; j<mDimension; j++)
345
        {
346
        t = ((int)(100*old[j]))/(100.0f);
347
        s+=(" "+t);
348
        }
349
      s+= ")";
350

    
351
      android.util.Log.e("dynamic", "kat: " + s);
352
      /// END DEBUGGING ///
353
*/
354
      for(int j=0; j<mDimension; j++)
355
        baseV[index][j] = -baseV[index][j];
356
      }
357
    }
358

    
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360
// helper function in case we are interpolating through exactly 2 points
361

    
362
  protected void computeOrthonormalBase2(Static1D curr, Static1D next)
363
    {
364
    switch(mDimension)
365
      {
366
      case 1: baseV[0][0] = (next.x-curr.x);
367
              break;
368
      case 2: Static2D curr2 = (Static2D)curr;
369
              Static2D next2 = (Static2D)next;
370
              baseV[0][0] = (next2.x-curr2.x);
371
              baseV[0][1] = (next2.y-curr2.y);
372
              break;
373
      case 3: Static3D curr3 = (Static3D)curr;
374
              Static3D next3 = (Static3D)next;
375
              baseV[0][0] = (next3.x-curr3.x);
376
              baseV[0][1] = (next3.y-curr3.y);
377
              baseV[0][2] = (next3.z-curr3.z);
378
              break;
379
      case 4: Static4D curr4 = (Static4D)curr;
380
              Static4D next4 = (Static4D)next;
381
              baseV[0][0] = (next4.x-curr4.x);
382
              baseV[0][1] = (next4.y-curr4.y);
383
              baseV[0][2] = (next4.z-curr4.z);
384
              baseV[0][3] = (next4.w-curr4.w);
385
              break;
386
      case 5: Static5D curr5 = (Static5D)curr;
387
              Static5D next5 = (Static5D)next;
388
              baseV[0][0] = (next5.x-curr5.x);
389
              baseV[0][1] = (next5.y-curr5.y);
390
              baseV[0][2] = (next5.z-curr5.z);
391
              baseV[0][3] = (next5.w-curr5.w);
392
              baseV[0][4] = (next5.v-curr5.v);
393
              break;
394
      default: throw new RuntimeException("Unsupported dimension");
395
      }
396

    
397
    if( baseV[0][0] == 0.0f )
398
      {
399
      baseV[1][0] = 1.0f;
400
      baseV[1][1] = 0.0f;
401
      }
402
    else
403
      {
404
      baseV[1][0] = 0.0f;
405
      baseV[1][1] = 1.0f;
406
      }
407

    
408
    for(int i=2; i<mDimension; i++)
409
      {
410
      baseV[1][i] = 0.0f;
411
      }
412

    
413
    computeOrthonormalBase();
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417
// debugging
418
/*
419
  protected void computeOrthonormalBaseMoreDebug(float time,VectorCache vc)
420
    {
421
    for(int i=0; i<mDimension; i++)
422
      {
423
      baseV[0][i] = (3*vc.a[i]*time+2*vc.b[i])*time+vc.c[i];   // first derivative, i.e. velocity vector
424
      baseV[1][i] =  6*vc.a[i]*time+2*vc.b[i];                 // second derivative,i.e. acceleration vector
425
      }
426

    
427
    float av=0.0f, vv=0.0f;
428

    
429
    android.util.Log.e("dyn3D", " ==>  velocity     ("+baseV[0][0]+","+baseV[0][1]+","+baseV[0][2]+")");
430
    android.util.Log.e("dyn3D", " ==>  acceleration ("+baseV[1][0]+","+baseV[1][1]+","+baseV[1][2]+")");
431

    
432
    for(int k=0; k<mDimension; k++)
433
      {
434
      vv += baseV[0][k]*baseV[0][k];
435
      av += baseV[1][k]*baseV[0][k];
436
      }
437

    
438
    android.util.Log.e("dyn3D", " ==>  av: "+av+" vv="+vv);
439

    
440
    av /= vv;
441

    
442
    for(int k=0;k<mDimension; k++)
443
      {
444
      baseV[1][k] -= av*baseV[0][k];
445
      }
446

    
447
    android.util.Log.e("dyn3D", " ==>  second base ("+baseV[1][0]+","+baseV[1][1]+","+baseV[1][2]+")");
448
    }
449
*/
450
///////////////////////////////////////////////////////////////////////////////////////////////////
451
// helper function in case we are interpolating through more than 2 points
452

    
453
  protected void computeOrthonormalBaseMore(float time,VectorCache vc)
454
    {
455
    for(int i=0; i<mDimension; i++)
456
      {
457
      baseV[0][i] = (3*vc.a[i]*time+2*vc.b[i])*time+vc.c[i];   // first derivative, i.e. velocity vector
458
      old[i]      = baseV[1][i];
459
      baseV[1][i] =  6*vc.a[i]*time+2*vc.b[i];                 // second derivative,i.e. acceleration vector
460
      }
461

    
462
    computeOrthonormalBase();
463
    }
464

    
465
///////////////////////////////////////////////////////////////////////////////////////////////////
466
// When this function gets called, baseV[0] and baseV[1] should have been filled with two mDimension-al
467
// vectors. This function then fills the rest of the baseV array with a mDimension-al Orthonormal base.
468
// (mDimension-2 vectors, pairwise orthogonal to each other and to the original 2). The function always
469
// leaves base[0] alone but generally speaking must adjust base[1] to make it orthogonal to base[0]!
470
// The whole baseV is then used to compute Noise.
471
//
472
// When computing noise of a point travelling along a N-dimensional path, there are three cases:
473
// a) we may be interpolating through 1 point, i.e. standing in place - nothing to do in this case
474
// b) we may be interpolating through 2 points, i.e. travelling along a straight line between them -
475
//    then pass the velocity vector in baseV[0] and anything linearly independent in base[1].
476
//    The output will then be discontinuous in dimensions>2 (sad corollary from the Hairy Ball Theorem)
477
//    but we don't care - we are travelling along a straight line, so velocity (aka baseV[0]!) does
478
//    not change.
479
// c) we may be interpolating through more than 2 points. Then interpolation formulas ensure the path
480
//    will never be a straight line, even locally -> we can pass in baseV[0] and baseV[1] the velocity
481
//    and the acceleration (first and second derivatives of the path) which are then guaranteed to be
482
//    linearly independent. Then we can ensure this is continuous in dimensions <=4. This leaves
483
//    dimension 5 (ATM WAVE is 5-dimensional) discontinuous -> WAVE will suffer from chaotic noise.
484
//
485
// Bear in mind here the 'normal' in 'orthonormal' means 'length equal to the length of the original
486
// velocity vector' (rather than the standard 1)
487

    
488
  protected void computeOrthonormalBase()
489
    {
490
    int last_non_zero=-1;
491
    float tmp;
492

    
493
    for(int i=0; i<mDimension; i++)
494
      if( baseV[0][i] != 0.0f )
495
        last_non_zero=i;
496
/*
497
if( last_non_zero != lastNon )
498
  android.util.Log.e("dynamic", "lastNon="+lastNon+" last_non_zero="+last_non_zero);
499
*/
500

    
501
    if( last_non_zero==-1 )                                               ///
502
      {                                                                   //  velocity is the 0 vector -> two
503
      for(int i=0; i<mDimension-1; i++)                                   //  consecutive points we are interpolating
504
        for(int j=0; j<mDimension; j++)                                   //  through are identical -> no noise,
505
          baseV[i+1][j]= 0.0f;                                            //  set the base to 0 vectors.
506
      }                                                                   ///
507
    else
508
      {
509
      for(int i=1; i<mDimension; i++)                                     /// One iteration computes baseV[i][*]
510
        {                                                                 //  (aka b[i]), the i-th orthonormal vector.
511
        buf[i-1]=0.0f;                                                    //
512
                                                                          //  We can use (modified!) Gram-Schmidt.
513
        for(int k=0; k<mDimension; k++)                                   //
514
          {                                                               //
515
          if( i>=2 )                                                      //  b[0] = b[0]
516
            {                                                             //  b[1] = b[1] - (<b[1],b[0]>/<b[0],b[0]>)*b[0]
517
            old[k] = baseV[i][k];                                         //  b[2] = b[2] - (<b[2],b[0]>/<b[0],b[0]>)*b[0] - (<b[2],b[1]>/<b[1],b[1]>)*b[1]
518
            baseV[i][k]= (k==i-(last_non_zero>=i?1:0)) ? 1.0f : 0.0f;     //  b[3] = b[3] - (<b[3],b[0]>/<b[0],b[0]>)*b[0] - (<b[3],b[1]>/<b[1],b[1]>)*b[1] - (<b[3],b[2]>/<b[2],b[2]>)*b[2]
519
            }                                                             //  (...)
520
                                                                          //  then b[i] = b[i] / |b[i]|  ( Here really b[i] = b[i] / (|b[0]|/|b[i]|)
521
          tmp = baseV[i-1][k];                                            //
522
          buf[i-1] += tmp*tmp;                                            //
523
          }                                                               //
524
                                                                          //
525
        for(int j=0; j<i; j++)                                            //
526
          {                                                               //
527
          tmp = 0.0f;                                                     //
528
          for(int k=0;k<mDimension; k++) tmp += baseV[i][k]*baseV[j][k];  //
529
          tmp /= buf[j];                                                  //
530
          for(int k=0;k<mDimension; k++) baseV[i][k] -= tmp*baseV[j][k];  //
531
          }                                                               //
532
                                                                          //
533
        checkAngle(i);                                                    //
534
        }                                                                 /// end compute baseV[i][*]
535

    
536
      buf[mDimension-1]=0.0f;                                             /// Normalize
537
      for(int k=0; k<mDimension; k++)                                     //
538
        {                                                                 //
539
        tmp = baseV[mDimension-1][k];                                     //
540
        buf[mDimension-1] += tmp*tmp;                                     //
541
        }                                                                 //
542
                                                                          //
543
      for(int i=1; i<mDimension; i++)                                     //
544
        {                                                                 //
545
        tmp = (float)Math.sqrt(buf[0]/buf[i]);                            //
546
        for(int k=0;k<mDimension; k++) baseV[i][k] *= tmp;                //
547
        }                                                                 /// End Normalize
548
      }
549

    
550
//lastNon = last_non_zero;
551

    
552
    //printBase("end");
553
    //checkBase();
554
    }
555

    
556
///////////////////////////////////////////////////////////////////////////////////////////////////
557
// internal debugging only!
558
  
559
  public String print()
560
    {
561
    return "duration="+mDuration+" count="+mCount+" Noise="+mNoise+" numVectors="+numPoints+" mMode="+mMode;
562
    }
563

    
564
///////////////////////////////////////////////////////////////////////////////////////////////////
565

    
566
  abstract void interpolate(float[] buffer, int offset, float time);
567

    
568
///////////////////////////////////////////////////////////////////////////////////////////////////
569
// PUBLIC API
570
///////////////////////////////////////////////////////////////////////////////////////////////////
571

    
572
/**
573
 * Sets the mode of the interpolation to Loop, Path or Jump.
574
 * <ul>
575
 * <li>Loop is when we go from the first point all the way to the last, and the back to the first through 
576
 * the shortest way.
577
 * <li>Path is when we come back from the last point back to the first the same way we got there.
578
 * <li>Jump is when we go from first to last and then jump back to the first.
579
 * </ul>
580
 * 
581
 * @param mode {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
582
 */
583

    
584
  public void setMode(int mode)
585
    {
586
    mMode = mode;  
587
    }
588

    
589
///////////////////////////////////////////////////////////////////////////////////////////////////
590
/**
591
 * Returns the number of Statics this Dynamic has been fed with.
592
 *   
593
 * @return the number of Statics we are currently interpolating through.
594
 */
595
  public synchronized int getNumPoints()
596
    {
597
    return numPoints;  
598
    }
599

    
600
///////////////////////////////////////////////////////////////////////////////////////////////////
601
/**
602
 * Controls how many times we want to interpolate.
603
 * <p>
604
 * Count equal to 1 means 'go from the first Static to the last and back'. Does not have to be an
605
 * integer - i.e. count=1.5 would mean 'start at the first Point, go to the last, come back to the first, 
606
 * go to the last again and stop'.
607
 * Count<=0 means 'go on interpolating indefinitely'.
608
 * 
609
 * @param count the number of times we want to interpolate between our collection of Statics.
610
 */
611
  public void setCount(float count)
612
    {
613
    mCount = count;  
614
    }
615

    
616
///////////////////////////////////////////////////////////////////////////////////////////////////
617
/**
618
 * Sets the time it takes to do one full interpolation.
619
 * 
620
 * @param duration Time, in milliseconds, it takes to do one full interpolation, i.e. go from the first 
621
 *                 Point to the last and back. 
622
 */
623
  
624
  public void setDuration(long duration)
625
    {
626
    mDuration = duration;
627
    }
628

    
629
///////////////////////////////////////////////////////////////////////////////////////////////////
630
// end of DistortedInterpolator
631
  }
(6-6/17)