Project

General

Profile

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

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

1
////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// 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
//                                                                                               //
11
// This library 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 GNU                             //
14
// Lesser General Public License for more details.                                               //
15
//                                                                                               //
16
// 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
///////////////////////////////////////////////////////////////////////////////////////////////////
20

    
21
package org.distorted.library.type;
22

    
23
import java.util.Vector;
24

    
25
///////////////////////////////////////////////////////////////////////////////////////////////////
26
/** 
27
* A 1-dimensional implementation of the Dynamic class to interpolate between a list
28
* of Static1Ds.
29
*/
30

    
31
public class Dynamic1D extends Dynamic implements Data1D
32
  {
33
  private Vector<Static1D> vv;
34
  private Static1D prev, curr, next;
35

    
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37
// no array bounds checking!
38
  
39
  private void computeVelocity(int c)
40
    {
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
    tmpCache1 = vc.elementAt(c);
49
    
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
        tmpCache1.velocity[0] = nx+px/q;
62
        }
63
      else
64
        {
65
        tmpCache1.velocity[0] = px+nx*q;
66
        }
67
      }
68
    else
69
      {
70
      tmpCache1.velocity[0] = 0.0f;
71
      }
72
    }
73
      
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75
  
76
  private void recomputeCache()
77
    {  
78
    if( numPoints==1 )
79
      {
80
      tmpCache1 = vc.elementAt(0);
81
      curr= vv.elementAt(0);
82
        
83
      tmpCache1.a[0] = 0.0f;
84
      tmpCache1.b[0] = 0.0f;
85
      tmpCache1.c[0] = curr.x;
86
      tmpCache1.d[0] = 0.0f;
87
      }
88
    else if( numPoints==2 )
89
      {
90
      tmpCache1 = vc.elementAt(0);
91
      tmpCache2 = vc.elementAt(1);
92
      curr= vv.elementAt(0);
93
      next= vv.elementAt(1);
94
          
95
      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
      
100
      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
      }
105
    else
106
      {
107
      int i, n;  
108
         
109
      for(i=0; i<numPoints; i++) computeVelocity(i);
110
   
111
      for(i=0; i<numPoints; i++)
112
        {
113
        n = i<numPoints-1 ? i+1:0;  
114
      
115
        tmpCache1 = vc.elementAt(i);
116
        tmpCache2 = vc.elementAt(n);
117
        curr= vv.elementAt(i);
118
        next= vv.elementAt(n);
119
    
120
        tmpCache1.cached[0] = curr.x;
121
        
122
        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
        }
129
      }
130
   
131
    cacheDirty = false;
132
    }
133

    
134
///////////////////////////////////////////////////////////////////////////////////////////////////
135
// PUBLIC API
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137
/**
138
 * Default constructor.
139
 */
140
  public Dynamic1D()
141
    {
142
    super(0,0.5f,1);
143
    vv = new Vector<>();
144
    }
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147
/**
148
 * 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
 *
153
 * @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
 */
156
  public Dynamic1D(int duration, float count)
157
    {
158
    super(duration,count,1);
159
    vv = new Vector<>();
160
    }
161

    
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163
/**
164
 * Returns the location'th Static1D.
165
 *   
166
 * @param location the index of the Point we are interested in.
167
 * @return The Static1D, if 0<=location&lt;getNumPoints(), or null otherwise.
168
 */
169
  public synchronized Static1D getPoint(int location)
170
    {
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
 * Adds a new Static1D to the end of our list of Points to interpolate through.
198
 * <p>   
199
 * Only a reference to the Point gets added to the List; this means that one can add a Point 
200
 * here, and later on {@link Static1D#set(float)} it to some new value and the change will
201
 * 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
  public synchronized void add(Static1D v)
208
    {
209
    if( v!=null )
210
      {
211
      vv.add(v);
212
     
213
      if( vn!=null ) vn.add(new VectorNoise());
214
       
215
      switch(numPoints)
216
        {
217
        case 0: 
218
        case 1: break;
219
        case 2: vc.add(new VectorCache());
220
                vc.add(new VectorCache());
221
                vc.add(new VectorCache());
222
                cacheDirty = true;
223
                break;
224
        default:vc.add(new VectorCache());
225
                cacheDirty = true;
226
        }
227
     
228
      numPoints++;
229
      }
230
    }
231

    
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233
/**
234
 * Adds a new Static1D to the location'th place in our List of Points to interpolate through.
235
 *   
236
 * @param location Index in our List to add the new Point at.
237
 * @param v The Point to add.
238
 */
239
  public synchronized void add(int location, Static1D v)
240
    {
241
    if( v!=null )
242
      {
243
      vv.add(location, v);
244
      
245
      if( vn!=null ) vn.add(new VectorNoise());
246
             
247
      switch(numPoints)
248
        {
249
        case 0:
250
        case 1: break;
251
        case 2: vc.add(new VectorCache());
252
                vc.add(new VectorCache());
253
                vc.add(new VectorCache());
254
                cacheDirty = true;
255
                break;
256
        default:vc.add(location,new VectorCache());
257
                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
  public synchronized boolean remove(Static1D v)
272
    {
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

    
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
      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
365

    
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
///////////////////////////////////////////////////////////////////////////////////////////////////
381

    
382
  synchronized void interpolate(float[] buffer, int offset, float time)
383
    {
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

    
394
              int segment= (int)(2*time);
395

    
396
              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
397

    
398
              if( vn!=null )
399
                {
400
                if( segment != mSegment )
401
                  {
402
                  if(mMode!=MODE_JUMP || mSegment==1) vn.elementAt(0).computeNoise();
403
                  mSegment = segment;
404
                  }
405

    
406
                time = noise(time,0);
407
                }
408
             
409
              buffer[offset] = (next.x-curr.x)*time + curr.x;
410
              break;
411
      default:computeSegmentAndTime(time);
412

    
413
              if( mTmpVec>=0 && mTmpVec<numPoints )
414
                {
415
                if( cacheDirty ) recomputeCache();  // recompute cache if we have added or remove vectors since last computation
416
                else if( mSegment!= mTmpSeg )       // ...or if we have just passed a vector and the vector we are currently flying to has changed
417
                  {
418
                  int vecNext = getNext(mTmpVec,time);
419
                  next = vv.elementAt(vecNext);
420
                  tmpCache2 = vc.elementAt(vecNext);
421

    
422
                  if( tmpCache2.cached[0]!=next.x ) recomputeCache();
423
                  }
424

    
425
                if( mSegment!= mTmpSeg && vn!=null ) vn.elementAt(mTmpVec).computeNoise();
426

    
427
                mSegment = mTmpSeg;
428
                time = mTmpTime-mTmpVec;
429
                tmpCache1 = vc.elementAt(mTmpVec);
430
                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
431

    
432
                if( vn!=null )
433
                  {
434
                  time = noise(time,mTmpVec);
435
                  }
436
            
437
                buffer[offset] = ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0];
438
                break;
439
                }
440
        }
441
     }  
442
  
443
  }
444
///////////////////////////////////////////////////////////////////////////////////////////////////
445
//
(7-7/18)