Project

General

Profile

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

library / src / main / java / org / distorted / library / type / Dynamic1D.java @ c0e4d5cf

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