Project

General

Profile

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

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