Project

General

Profile

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

library / src / main / java / org / distorted / library / type / Dynamic1D.java @ 8c57d77b

1 2c8310b1 Leszek Koltunski
////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
3 d333eb6b Leszek Koltunski
//                                                                                               //
4 46b572b5 Leszek Koltunski
// This file is part of Distorted.                                                               //
5 d333eb6b Leszek Koltunski
//                                                                                               //
6 2c8310b1 Leszek Koltunski
// This library is free software; you can redistribute it and/or                                 //
7
// modify it under the terms of the GNU Lesser General Public                                    //
8
// License as published by the Free Software Foundation; either                                  //
9
// version 2.1 of the License, or (at your option) any later version.                            //
10 d333eb6b Leszek Koltunski
//                                                                                               //
11 2c8310b1 Leszek Koltunski
// This library is distributed in the hope that it will be useful,                               //
12 d333eb6b Leszek Koltunski
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13 2c8310b1 Leszek Koltunski
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                             //
14
// Lesser General Public License for more details.                                               //
15 d333eb6b Leszek Koltunski
//                                                                                               //
16 2c8310b1 Leszek Koltunski
// You should have received a copy of the GNU Lesser General Public                              //
17
// License along with this library; if not, write to the Free Software                           //
18
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
19 d333eb6b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
20
21 a4835695 Leszek Koltunski
package org.distorted.library.type;
22 6a06a912 Leszek Koltunski
23
import java.util.Vector;
24
25
///////////////////////////////////////////////////////////////////////////////////////////////////
26
/** 
27 568b29d8 Leszek Koltunski
* A 1-dimensional implementation of the Dynamic class to interpolate between a list
28 350cc2f5 Leszek Koltunski
* of Static1Ds.
29 6a06a912 Leszek Koltunski
*/
30
31 568b29d8 Leszek Koltunski
public class Dynamic1D extends Dynamic implements Data1D
32 6a06a912 Leszek Koltunski
  {
33 568b29d8 Leszek Koltunski
  private Vector<Static1D> vv;
34
  private Static1D prev, curr, next;
35 6a06a912 Leszek Koltunski
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37
// no array bounds checking!
38
  
39 f871c455 Leszek Koltunski
  private void computeVelocity(int c)
40 6a06a912 Leszek Koltunski
    {
41
    int p = c>0 ? c-1: numPoints-1;
42
    int n = c<numPoints-1 ? c+1: 0;
43
    
44
    prev = vv.elementAt(p);
45
    curr = vv.elementAt(c);
46
    next = vv.elementAt(n);
47
48 9aabc9eb Leszek Koltunski
    tmpCache1 = vc.elementAt(c);
49 6a06a912 Leszek Koltunski
    
50
    float px = curr.x - prev.x;
51
    float nx = next.x - curr.x;
52
     
53
    float d = nx*nx;
54
    
55
    if( d>0 )
56
      {
57
      float q = (float)Math.sqrt((px*px)/d);
58
      
59
      if( q>1 )
60
        {
61 9aabc9eb Leszek Koltunski
        tmpCache1.velocity[0] = nx+px/q;
62 6a06a912 Leszek Koltunski
        }
63
      else
64
        {
65 9aabc9eb Leszek Koltunski
        tmpCache1.velocity[0] = px+nx*q;
66 6a06a912 Leszek Koltunski
        }
67
      }
68
    else
69
      {
70 9aabc9eb Leszek Koltunski
      tmpCache1.velocity[0] = 0.0f;
71 6a06a912 Leszek Koltunski
      }
72
    }
73
      
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75
  
76
  private void recomputeCache()
77
    {  
78
    if( numPoints==1 )
79
      {
80 9aabc9eb Leszek Koltunski
      tmpCache1 = vc.elementAt(0);
81 6a06a912 Leszek Koltunski
      curr= vv.elementAt(0);
82
        
83 9aabc9eb Leszek Koltunski
      tmpCache1.a[0] = 0.0f;
84
      tmpCache1.b[0] = 0.0f;
85
      tmpCache1.c[0] = curr.x;
86
      tmpCache1.d[0] = 0.0f;
87 6a06a912 Leszek Koltunski
      }
88
    else if( numPoints==2 )
89
      {
90 9aabc9eb Leszek Koltunski
      tmpCache1 = vc.elementAt(0);
91
      tmpCache2 = vc.elementAt(1);
92 6a06a912 Leszek Koltunski
      curr= vv.elementAt(0);
93
      next= vv.elementAt(1);
94
          
95 9aabc9eb Leszek Koltunski
      tmpCache1.a[0] = 0.0f;
96
      tmpCache1.b[0] = 0.0f;
97
      tmpCache1.c[0] = next.x - curr.x;
98
      tmpCache1.d[0] = curr.x;
99 6a06a912 Leszek Koltunski
      
100 9aabc9eb Leszek Koltunski
      tmpCache2.a[0] = 0.0f;
101
      tmpCache2.b[0] = 0.0f;
102
      tmpCache2.c[0] = curr.x - next.x;
103
      tmpCache2.d[0] = next.x;
104 6a06a912 Leszek Koltunski
      }
105
    else
106
      {
107
      int i, n;  
108
         
109 f871c455 Leszek Koltunski
      for(i=0; i<numPoints; i++) computeVelocity(i);
110 6a06a912 Leszek Koltunski
   
111
      for(i=0; i<numPoints; i++)
112
        {
113
        n = i<numPoints-1 ? i+1:0;  
114
      
115 9aabc9eb Leszek Koltunski
        tmpCache1 = vc.elementAt(i);
116
        tmpCache2 = vc.elementAt(n);
117 6a06a912 Leszek Koltunski
        curr= vv.elementAt(i);
118
        next= vv.elementAt(n);
119
    
120 9aabc9eb Leszek Koltunski
        tmpCache1.cached[0] = curr.x;
121 6a06a912 Leszek Koltunski
        
122 9aabc9eb Leszek Koltunski
        tmpCache1.a[0] = mConvexity*( 2*curr.x +   tmpCache1.velocity[0] - 2*next.x + tmpCache2.velocity[0]);
123
        tmpCache1.b[0] = mConvexity*(-3*curr.x - 2* tmpCache1.velocity[0] + 3*next.x - tmpCache2.velocity[0]);
124
        tmpCache1.c[0] = mConvexity*(tmpCache1.velocity[0]) + (1.0f-mConvexity)*(next.x-curr.x);
125
        tmpCache1.d[0] = curr.x;
126
127
        if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) smoothOutSegment(tmpCache1);
128 6a06a912 Leszek Koltunski
        }
129
      }
130
   
131
    cacheDirty = false;
132
    }
133
134
///////////////////////////////////////////////////////////////////////////////////////////////////
135
// PUBLIC API
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137
/**
138
 * Default constructor.
139
 */
140 568b29d8 Leszek Koltunski
  public Dynamic1D()
141 6a06a912 Leszek Koltunski
    {
142 649544b8 Leszek Koltunski
    super(0,0.5f,1);
143
    vv = new Vector<>();
144 6a06a912 Leszek Koltunski
    }
145 8c893ffc Leszek Koltunski
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147
/**
148 c45c2ab1 Leszek Koltunski
 * Constructor setting the speed of interpolation and the number of revolutions.
149
 *
150
 * What constitutes 'one revolution' depends on the MODE:
151
 * {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
152 8c893ffc Leszek Koltunski
 *
153 c45c2ab1 Leszek Koltunski
 * @param duration number of milliseconds it takes to do one revolution.
154
 * @param count    number of revolutions we will do. Count<=0 means 'infinite'.
155 8c893ffc Leszek Koltunski
 */
156
  public Dynamic1D(int duration, float count)
157
    {
158 649544b8 Leszek Koltunski
    super(duration,count,1);
159 8c893ffc Leszek Koltunski
    vv = new Vector<>();
160
    }
161
162 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
163
/**
164 568b29d8 Leszek Koltunski
 * Returns the location'th Static1D.
165 6a06a912 Leszek Koltunski
 *   
166
 * @param location the index of the Point we are interested in.
167 568b29d8 Leszek Koltunski
 * @return The Static1D, if 0<=location&lt;getNumPoints(), or null otherwise.
168 6a06a912 Leszek Koltunski
 */
169 568b29d8 Leszek Koltunski
  public synchronized Static1D getPoint(int location)
170 6a06a912 Leszek Koltunski
    {
171
    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
172
    }
173
  
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175
/**
176
 * Resets the location'th Point.
177
 * 
178
 * @param location the index of the Point we are setting.
179
 * @param x New value of its first float.
180
 */
181
  public synchronized void setPoint(int location, float x)
182
    {
183
    if( location>=0 && location<numPoints )
184
      {
185
      curr = vv.elementAt(location);
186
   
187
      if( curr!=null )
188
        {
189
        curr.set(x);
190
        cacheDirty=true;
191
        }
192
      }
193
    }
194
 
195
///////////////////////////////////////////////////////////////////////////////////////////////////
196
/**
197 568b29d8 Leszek Koltunski
 * Adds a new Static1D to the end of our list of Points to interpolate through.
198 6a06a912 Leszek Koltunski
 * <p>   
199
 * Only a reference to the Point gets added to the List; this means that one can add a Point 
200 568b29d8 Leszek Koltunski
 * here, and later on {@link Static1D#set(float)} it to some new value and the change will
201 6a06a912 Leszek Koltunski
 * be seamlessly reflected in the interpolated path.  
202
 * <p>
203
 * A Point can be added multiple times.
204
 *   
205
 * @param v The Point to add.
206
 */
207 568b29d8 Leszek Koltunski
  public synchronized void add(Static1D v)
208 6a06a912 Leszek Koltunski
    {
209
    if( v!=null )
210
      {
211
      vv.add(v);
212
     
213 291705f6 Leszek Koltunski
      if( vn!=null ) vn.add(new VectorNoise());
214 6a06a912 Leszek Koltunski
       
215
      switch(numPoints)
216
        {
217
        case 0: 
218
        case 1: break;
219 291705f6 Leszek Koltunski
        case 2: vc.add(new VectorCache());
220
                vc.add(new VectorCache());
221
                vc.add(new VectorCache());
222 6a06a912 Leszek Koltunski
                cacheDirty = true;
223
                break;
224 291705f6 Leszek Koltunski
        default:vc.add(new VectorCache());
225 6a06a912 Leszek Koltunski
                cacheDirty = true;
226
        }
227
     
228
      numPoints++;
229
      }
230
    }
231
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233
/**
234 568b29d8 Leszek Koltunski
 * Adds a new Static1D to the location'th place in our List of Points to interpolate through.
235 6a06a912 Leszek Koltunski
 *   
236
 * @param location Index in our List to add the new Point at.
237
 * @param v The Point to add.
238
 */
239 568b29d8 Leszek Koltunski
  public synchronized void add(int location, Static1D v)
240 6a06a912 Leszek Koltunski
    {
241
    if( v!=null )
242
      {
243
      vv.add(location, v);
244
      
245 291705f6 Leszek Koltunski
      if( vn!=null ) vn.add(new VectorNoise());
246 6a06a912 Leszek Koltunski
             
247
      switch(numPoints)
248
        {
249
        case 0:
250
        case 1: break;
251 291705f6 Leszek Koltunski
        case 2: vc.add(new VectorCache());
252
                vc.add(new VectorCache());
253
                vc.add(new VectorCache());
254 6a06a912 Leszek Koltunski
                cacheDirty = true;
255
                break;
256 291705f6 Leszek Koltunski
        default:vc.add(location,new VectorCache());
257 6a06a912 Leszek Koltunski
                cacheDirty = true;
258
        }
259
      
260
      numPoints++;
261
      }
262
    }
263
  
264
///////////////////////////////////////////////////////////////////////////////////////////////////
265
/**
266
 * Removes all occurrences of Point v from the List of Points to interpolate through.  
267
 * 
268
 * @param v The Point to remove.
269
 * @return <code>true</code> if we have removed at least one Point.
270
 */
271 568b29d8 Leszek Koltunski
  public synchronized boolean remove(Static1D v)
272 6a06a912 Leszek Koltunski
    {
273
    int n = vv.indexOf(v);
274
    boolean found = false;
275
   
276
    while( n>=0 ) 
277
      {
278
      vv.remove(n);
279
     
280
      if( vn!=null ) vn.remove(0);
281
     
282
      switch(numPoints)
283
        {
284
        case 0:
285
        case 1:
286
        case 2: break;
287
        case 3: vc.removeAllElements();
288
                break;
289
        default:vc.remove(n);
290
                cacheDirty=true;
291
        }
292
293
      numPoints--;
294
      found = true;
295
      n = vv.indexOf(v);
296
      }
297
   
298
    return found;
299
    }
300
301
///////////////////////////////////////////////////////////////////////////////////////////////////
302
/**
303
 * Removes a location'th Point from the List of Points we interpolate through.
304
 * 
305
 * @param location index of the Point we want to remove. 
306
 * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
307
 */
308
  public synchronized boolean remove(int location)
309
    {
310
    if( location>=0 && location<numPoints ) 
311
      {
312
      vv.removeElementAt(location);
313
      
314
      if( vn!=null ) vn.remove(0);
315
     
316
      switch(numPoints)
317
        {
318
        case 0:
319
        case 1: 
320
        case 2: break;
321
        case 3: vc.removeAllElements();
322
                break;
323
        default:vc.removeElementAt(location);
324
        }
325
326
      numPoints--;
327
      cacheDirty = true; 
328
      return true;
329
      }
330
331
   return false;
332
   }
333
  
334
///////////////////////////////////////////////////////////////////////////////////////////////////
335
/**
336
 * Removes all Points.
337
 */
338
  public synchronized void removeAll()
339
    {
340
    numPoints = 0;
341
    vv.removeAllElements();
342
    vc.removeAllElements();
343
    cacheDirty = false;
344
   
345
    if( vn!=null ) vn.removeAllElements();
346
    }
347 1e22c248 Leszek Koltunski
348
///////////////////////////////////////////////////////////////////////////////////////////////////
349
/**
350
 * Sets the 'smoothness' of interpolation.
351
 * <p>
352
 * When Noise=0 (the default), we interpolate between our Points through the most smooth path possible.
353
 * Increasing noise makes the Dynamic increasingly deviate from this path, pseudo-randomly speeding
354
 * up and slowing down, etc.
355
 *
356
 * @param noise The noise level. Permitted range: 0 <= noise <= 1.
357
 */
358
359
  public synchronized void setNoise(Static1D noise)
360
    {
361
    if( vn==null )
362
      {
363
      vn = new Vector<>();
364 291705f6 Leszek Koltunski
      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
365 1e22c248 Leszek Koltunski
366
      if( mDimension>=2 )
367
        {
368
        mFactor = new float[mDimension-1];
369
        }
370
371
      mNoise = new float[mDimension];
372
      }
373
374
    if( noise.x<0.0f ) noise.x = 0.0f;
375
    if( noise.x>1.0f ) noise.x = 1.0f;
376
377
    mNoise[0] = noise.x;
378
    }
379
380 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
381 bdb341bc Leszek Koltunski
382 c6dec65b Leszek Koltunski
  synchronized void interpolate(float[] buffer, int offset, float time)
383 6a06a912 Leszek Koltunski
    {
384
    switch(numPoints)
385
      {
386
      case 0: buffer[offset] = 0.0f;
387
              break;
388
      case 1: curr = vv.elementAt(0);
389
              buffer[offset] = curr.x;
390
              break;
391
      case 2: curr = vv.elementAt(0);
392
              next = vv.elementAt(1);
393 291705f6 Leszek Koltunski
394 c0e4d5cf Leszek Koltunski
              int segment= (int)(2*time);
395 291705f6 Leszek Koltunski
396 6a06a912 Leszek Koltunski
              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
397 291705f6 Leszek Koltunski
398 6a06a912 Leszek Koltunski
              if( vn!=null )
399
                {
400 c0e4d5cf Leszek Koltunski
                if( segment != mSegment )
401 291705f6 Leszek Koltunski
                  {
402
                  if(mMode!=MODE_JUMP || mSegment==1) vn.elementAt(0).computeNoise();
403 c0e4d5cf Leszek Koltunski
                  mSegment = segment;
404 291705f6 Leszek Koltunski
                  }
405
406 6a06a912 Leszek Koltunski
                time = noise(time,0);
407
                }
408
             
409
              buffer[offset] = (next.x-curr.x)*time + curr.x;
410
              break;
411 d403b466 Leszek Koltunski
      default:computeSegmentAndTime(time);
412 291705f6 Leszek Koltunski
413 d403b466 Leszek Koltunski
              if( mTmpVec>=0 && mTmpVec<numPoints )
414 6a06a912 Leszek Koltunski
                {
415
                if( cacheDirty ) recomputeCache();  // recompute cache if we have added or remove vectors since last computation
416 d403b466 Leszek Koltunski
                else if( mSegment!= mTmpSeg )       // ...or if we have just passed a vector and the vector we are currently flying to has changed
417 6a06a912 Leszek Koltunski
                  {
418 d403b466 Leszek Koltunski
                  int vecNext = getNext(mTmpVec,time);
419 6a06a912 Leszek Koltunski
                  next = vv.elementAt(vecNext);
420 9aabc9eb Leszek Koltunski
                  tmpCache2 = vc.elementAt(vecNext);
421 d403b466 Leszek Koltunski
422 9aabc9eb Leszek Koltunski
                  if( tmpCache2.cached[0]!=next.x ) recomputeCache();
423 6a06a912 Leszek Koltunski
                  }
424 291705f6 Leszek Koltunski
425 d403b466 Leszek Koltunski
                if( mSegment!= mTmpSeg && vn!=null ) vn.elementAt(mTmpVec).computeNoise();
426 291705f6 Leszek Koltunski
427 d403b466 Leszek Koltunski
                mSegment = mTmpSeg;
428
                time = mTmpTime-mTmpVec;
429
                tmpCache1 = vc.elementAt(mTmpVec);
430 9aabc9eb Leszek Koltunski
                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
431 291705f6 Leszek Koltunski
432 6a06a912 Leszek Koltunski
                if( vn!=null )
433
                  {
434 d403b466 Leszek Koltunski
                  time = noise(time,mTmpVec);
435 6a06a912 Leszek Koltunski
                  }
436
            
437 9aabc9eb Leszek Koltunski
                buffer[offset] = ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0];
438 6a06a912 Leszek Koltunski
                break;
439
                }
440
        }
441
     }  
442
  
443
  }
444
///////////////////////////////////////////////////////////////////////////////////////////////////
445
//