Project

General

Profile

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

library / src / main / java / org / distorted / library / type / Dynamic2D.java @ 649544b8

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.Vector;
23

    
24
///////////////////////////////////////////////////////////////////////////////////////////////////
25
/** 
26
* A 2-dimensional implementation of the Dynamic class to interpolate between a list
27
* of Static2Ds.
28
*/
29

    
30
public class Dynamic2D extends Dynamic implements Data2D
31
  {
32
  private Vector<Static2D> vv;
33
  private Static2D prev, curr, next;
34

    
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36
// no array bounds checking!
37
  
38
  private void vec(int c)
39
    {
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
    tmp1 = vc.elementAt(c);
48
    
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
        tmp1.tangent[0] = nx+px/q;
63
        tmp1.tangent[1] = ny+py/q;
64
        }
65
      else
66
        {
67
        tmp1.tangent[0] = px+nx*q;
68
        tmp1.tangent[1] = py+ny*q;
69
        }
70
      }
71
    else
72
      {
73
      tmp1.tangent[0] = 0.0f;
74
      tmp1.tangent[1] = 0.0f;
75
      }
76
    }
77
   
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79
  
80
  private void recomputeCache()
81
    {  
82
    if( numPoints==1 )
83
      {
84
      tmp1= vc.elementAt(0);
85
      curr= vv.elementAt(0);
86
              
87
      tmp1.a[0] = tmp1.a[1] = 0.0f;
88
      tmp1.b[0] = tmp1.b[1] = 0.0f;
89
      tmp1.c[0] = curr.x;
90
      tmp1.c[1] = curr.y;
91
      tmp1.d[0] = tmp1.d[1] = 0.0f;
92
      }
93
    else if( numPoints==2 )
94
      {
95
      tmp1= vc.elementAt(0);
96
      tmp2= vc.elementAt(1);
97
      curr= vv.elementAt(0);
98
      next= vv.elementAt(1);
99
          
100
      tmp1.a[0] = tmp1.a[1] = 0.0f;
101
      tmp1.b[0] = tmp1.b[1] = 0.0f;
102
      tmp1.c[0] = next.x - curr.x;
103
      tmp1.c[1] = next.y - curr.y;
104
      tmp1.d[0] = curr.x;
105
      tmp1.d[1] = curr.y;
106
      
107
      tmp2.a[0] = tmp2.a[1] = 0.0f;
108
      tmp2.b[0] = tmp2.b[1] = 0.0f;
109
      tmp2.c[0] = curr.x - next.x;
110
      tmp2.c[1] = curr.y - next.y;
111
      tmp2.d[0] = next.x;
112
      tmp2.d[1] = next.y;
113
      }
114
    else
115
      {
116
      int i, n;  
117
         
118
      for(i=0; i<numPoints; i++) vec(i);
119
   
120
      for(i=0; i<numPoints; i++)
121
        {
122
        n = i<numPoints-1 ? i+1:0;  
123
      
124
        tmp1= vc.elementAt(i);
125
        tmp2= vc.elementAt(n);
126
        curr= vv.elementAt(i);
127
        next= vv.elementAt(n);
128
      
129
        tmp1.cached[0] = curr.x;
130
        tmp1.cached[1] = curr.y;
131

    
132
        tmp1.a[0] =  2*curr.x +   tmp1.tangent[0] - 2*next.x + tmp2.tangent[0];
133
        tmp1.b[0] = -3*curr.x - 2*tmp1.tangent[0] + 3*next.x - tmp2.tangent[0];
134
        tmp1.c[0] = tmp1.tangent[0];
135
        tmp1.d[0] = curr.x;
136

    
137
        tmp1.a[1] =  2*curr.y +   tmp1.tangent[1] - 2*next.y + tmp2.tangent[1];
138
        tmp1.b[1] = -3*curr.y - 2*tmp1.tangent[1] + 3*next.y - tmp2.tangent[1];
139
        tmp1.c[1] = tmp1.tangent[1];
140
        tmp1.d[1] = curr.y;
141
        }
142
      }
143
    
144
    cacheDirty = false;
145
    }
146

    
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148
// PUBLIC API 
149
///////////////////////////////////////////////////////////////////////////////////////////////////
150
/**
151
 * Default constructor.
152
 */
153
  public Dynamic2D()
154
    {
155
    super(0,0.5f,2);
156
    vv = new Vector<>();
157
    }
158

    
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160

    
161
/**
162
 * Default constructor.
163
 *
164
 * @param duration number of milliseconds it takes to do a full loop/path from first vector to the
165
 *                 last and back to the first
166
 * @param count    number of loops/paths we will do; mCount = 1.5 means we go from the first vector
167
 *                 to the last, back to first, and to the last again.
168
 */
169
  public Dynamic2D(int duration, float count)
170
    {
171
    super(duration,count,2);
172
    vv = new Vector<>();
173
    }
174

    
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176
/**
177
 * Returns the location'th Static2D.
178
 *   
179
 * @param location the index of the Point we are interested in.
180
 * @return The Static2D, if 0<=location&lt;getNumPoints(), or null otherwise.
181
 */  
182
  public synchronized Static2D getPoint(int location)
183
    {
184
    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
185
    }
186
  
187
///////////////////////////////////////////////////////////////////////////////////////////////////
188
/**
189
 * Resets the location'th Point.
190
 * 
191
 * @param location the index of the Point we are setting.
192
 * @param x New value of its first float.
193
 */
194
  public synchronized void setPoint(int location, float x, float y)
195
    {
196
    if( location>=0 && location<numPoints )
197
      {
198
      curr = vv.elementAt(location);
199
   
200
      if( curr!=null )
201
        {
202
        curr.set(x,y);
203
        cacheDirty=true;
204
        }
205
      }
206
    }
207
    
208
///////////////////////////////////////////////////////////////////////////////////////////////////
209
/**
210
 * Adds a new Static2D to the end of our list of Points to interpolate through.
211
 * <p>   
212
 * Only a reference to the Point gets added to the List; this means that one can add a Point 
213
 * here, and later on {@link Static2D#set(float,float)} it to some new value and the change
214
 * will be seamlessly reflected in the interpolated path.  
215
 * <p>
216
 * A Point can be added multiple times.
217
 *   
218
 * @param v The Point to add.
219
 */  
220
  public synchronized void add(Static2D v)
221
    {
222
    if( v!=null )
223
      {
224
      vv.add(v);
225
     
226
      if( vn!=null ) vn.add(new VectorNoise(2));
227
       
228
      switch(numPoints)
229
        {
230
        case 0:
231
        case 1: break;
232
        case 2: vc.add(new VectorCache(2));
233
                vc.add(new VectorCache(2));
234
                vc.add(new VectorCache(2));
235
                break;
236
        default:vc.add(new VectorCache(2));
237
        }
238
     
239
      numPoints++;
240
      cacheDirty = true;
241
      }
242
    }
243

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245
/**
246
 * Adds a new Static2D to the location'th place in our List of Points to interpolate through.
247
 *   
248
 * @param location Index in our List to add the new Point at.
249
 * @param v The Point to add.
250
 */  
251
  public synchronized void add(int location, Static2D v)
252
    {
253
    if( v!=null )
254
      {
255
      vv.add(location, v);
256
      
257
      if( vn!=null ) vn.add(new VectorNoise(2));
258
      
259
      switch(numPoints)
260
        {
261
        case 0:
262
        case 1: break;
263
        case 2: vc.add(new VectorCache(2));
264
                vc.add(new VectorCache(2));
265
                vc.add(new VectorCache(2));
266
                break;
267
        default:vc.add(location,new VectorCache(2));
268
        }
269
      
270
      numPoints++;
271
      cacheDirty = true;
272
      }
273
    }
274
  
275
///////////////////////////////////////////////////////////////////////////////////////////////////
276
/**
277
 * Removes all occurrences of Point v from the List of Points to interpolate through.  
278
 * 
279
 * @param v The Point to remove.
280
 * @return <code>true</code> if we have removed at least one Point.
281
 */
282
  public synchronized boolean remove(Static2D v)
283
    {
284
    int n = vv.indexOf(v);
285
    boolean found = false;
286
   
287
    while( n>=0 ) 
288
      {
289
      vv.remove(n);
290
     
291
      if( vn!=null ) vn.remove(0);
292
     
293
      switch(numPoints)
294
        {
295
        case 0:
296
        case 1: 
297
        case 2: break;
298
        case 3: vc.removeAllElements();
299
                break;
300
        default:vc.remove(n);
301
        }
302
     
303
      numPoints--;
304
      found = true;
305
      n = vv.indexOf(v);
306
      }
307
   
308
    if( found ) 
309
      {
310
      cacheDirty=true;
311
      }
312
   
313
    return found;
314
    }
315

    
316
///////////////////////////////////////////////////////////////////////////////////////////////////
317
/**
318
 * Removes a location'th Point from the List of Points we interpolate through.
319
 * 
320
 * @param location index of the Point we want to remove. 
321
 * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
322
 */
323
  public synchronized boolean remove(int location)
324
    {
325
    if( location>=0 && location<numPoints ) 
326
      {
327
      vv.removeElementAt(location);
328
      
329
      if( vn!=null ) vn.remove(0);
330
      
331
      switch(numPoints)
332
        {
333
        case 0:
334
        case 1: 
335
        case 2: break;
336
        case 3: vc.removeAllElements();
337
                break;
338
        default:vc.removeElementAt(location);
339
        }
340

    
341
      numPoints--;
342
      cacheDirty = true; 
343
      return true;
344
      }
345

    
346
   return false;
347
   }
348
  
349
///////////////////////////////////////////////////////////////////////////////////////////////////
350
/**
351
 * Removes all Points.
352
 */
353
  public synchronized void removeAll()
354
    {
355
    numPoints = 0;
356
    vv.removeAllElements();
357
    vc.removeAllElements();
358
    cacheDirty = false;
359
   
360
    if( vn!=null ) vn.removeAllElements();
361
    }
362

    
363
///////////////////////////////////////////////////////////////////////////////////////////////////
364
/**
365
 * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
366
 * <p>
367
 * Since this is a 2-dimensional Dynamic, the resulting interpolated Static2D gets written
368
 * to two locations in the buffer: buffer[offset] and buffer[offset+1]. 
369
 * 
370
 * @param buffer Float buffer we will write the resulting Static2D to.
371
 * @param offset Offset in the buffer where to write the result.
372
 * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
373
 *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
374
 */  
375
  public synchronized void interpolate(float[] buffer, int offset, float time)
376
    {
377
    switch(numPoints)
378
      {
379
      case 0: buffer[offset  ] = 0.0f;
380
              buffer[offset+1] = 0.0f;
381
              break;
382
      case 1: curr = vv.elementAt(0);
383
              buffer[offset  ] = curr.x;
384
              buffer[offset+1] = curr.y;
385
              break;
386
      case 2: curr = vv.elementAt(0);
387
              next = vv.elementAt(1);
388
               
389
              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
390
             
391
              if( vn!=null )
392
                {
393
                time = noise(time,0);
394
              
395
                baseV[0][0] = next.x-curr.x;
396
                baseV[0][1] = next.y-curr.y;
397
   
398
                buffer[offset  ] = baseV[0][0]*time + curr.x +baseV[0][0]*mFactor[0];
399
                buffer[offset+1] = baseV[0][1]*time + curr.y -baseV[0][1]*mFactor[0];
400
                }
401
              else
402
                {
403
                buffer[offset  ] = (next.x-curr.x)*time + curr.x;
404
                buffer[offset+1] = (next.y-curr.y)*time + curr.y;
405
                }
406
              
407
              break;
408
      default:float t = time;
409
        
410
              switch(mMode)
411
                {
412
                case MODE_LOOP: time = time*numPoints;
413
                                break;
414
                case MODE_PATH: time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
415
                                break;
416
                case MODE_JUMP: time = time*(numPoints-1);
417
                                break;
418
                }
419
            
420
              int vecCurr = (int)time;
421
              time = time-vecCurr;
422
      
423
              if( vecCurr>=0 && vecCurr<numPoints )
424
                { 
425
                if( cacheDirty ) recomputeCache();    // recompute cache if we have added or remove vectors since last computation
426
                else if( mVecCurr!= vecCurr )         // ...or if we have just passed a vector and the vector we are currently flying to has changed
427
                  {
428
                  int vecNext;   
429
                  mVecCurr = vecCurr;
430
                                
431
                  switch(mMode)
432
                    {
433
                    case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
434
                                    break;
435
                    case MODE_PATH: if( t<0.5f ) vecNext = vecCurr==numPoints-1 ? numPoints-2: vecCurr+1;  
436
                                    else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
437
                                    break;
438
                    case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
439
                                    break;
440
                    default       : vecNext = 0;                
441
                    }
442
              
443
                  next = vv.elementAt(vecNext);
444
                  tmp2 = vc.elementAt(vecNext);
445
              
446
                  if( tmp2.cached[0]!=next.x || tmp2.cached[1]!=next.y ) recomputeCache();
447
                  }
448

    
449
                tmp1 = vc.elementAt(vecCurr);
450

    
451
                if( vn!=null )
452
                  {
453
                  time = noise(time,vecCurr);
454

    
455
                  baseV[0][0] = (3*tmp1.a[0]*time+2*tmp1.b[0])*time + tmp1.c[0];
456
                  baseV[0][1] = (3*tmp1.a[1]*time+2*tmp1.b[1])*time + tmp1.c[1];
457
                 
458
                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0] +baseV[0][0]*mFactor[0];
459
                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1] -baseV[0][1]*mFactor[0];
460
                  } 
461
                else
462
                  {
463
                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0];
464
                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1];
465
                  }
466
                
467
                break;
468
                }
469
      }
470
    }  
471
  }
472
///////////////////////////////////////////////////////////////////////////////////////////////////
473
//
(8-8/17)