Project

General

Profile

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

library / src / main / java / org / distorted / library / type / Dynamic.java @ 3002bef3

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.Random;
23
import java.util.Vector;
24

    
25
///////////////////////////////////////////////////////////////////////////////////////////////////
26
/** A class to interpolate between a List of Static{1,2,3,4}Ds.
27
* <p><ul>
28
* <li>if there is only one Point, just jump to it.
29
* <li>if there are two Points, linearly bounce between them
30
* <li>if there are more, interpolate a loop (or a path!) between them.
31
* </ul>
32
*/
33

    
34
// The way Interpolation between more than 2 Points is done:
35
// 
36
// Def: let w[i] = (w[i](x), w[i](y), w[i](z)) be the direction and speed we have to be flying at Point P[i]
37
//
38
// time it takes to fly though one segment v[i] --> v[i+1] : 0.0 --> 1.0
39
// w[i] should be parallel to v[i+1] - v[i-1]   (cyclic notation)
40
// |w[i]| proportional to | P[i]-P[i+1] |
41
//
42
// Given that the flight route (X(t), Y(t), Z(t)) from P(i) to P(i+1)  (0<=t<=1) has to satisfy
43
// X(0) = P[i  ](x), Y(0)=P[i  ](y), Z(0)=P[i  ](z), X'(0) = w[i  ](x), Y'(0) = w[i  ](y), Z'(0) = w[i  ](z)
44
// X(1) = P[i+1](x), Y(1)=P[i+1](y), Z(1)=P[i+1](z), X'(1) = w[i+1](x), Y'(1) = w[i+1](y), Z'(1) = w[i+1](z)
45
//
46
// we have the solution:  X(t) = at^3 + bt^2 + ct + d where
47
// a =  2*P[i](x) +   w[i](x) - 2*P[i+1](x) + w[i+1](x)
48
// b = -3*P[i](x) - 2*w[i](x) + 3*P[i+1](x) - w[i+1](x)
49
// c = w[i](x)<br>
50
// d = P[i](x)
51
//
52
// and similarly Y(t) and Z(t).
53

    
54
public abstract class Dynamic
55
  {
56
  /**
57
   * One revolution takes us from the first vector to the last and back to first through the shortest path. 
58
   */
59
  public static final int MODE_LOOP = 0; 
60
  /**
61
   * We come back from the last to the first vector through the same way we got there.
62
   */
63
  public static final int MODE_PATH = 1; 
64
  /**
65
   * We just jump back from the last point to the first.
66
   */
67
  public static final int MODE_JUMP = 2; 
68

    
69
  protected static Random mRnd = new Random();
70
  
71
  protected static final int NUM_NOISE = 5; // used iff mNoise>0.0. Number of intermediary points between each pair of adjacent vectors
72
                                            // where we randomize noise factors to make the way between the two vectors not so smooth.
73

    
74
  protected int mDimension;
75
  protected int numPoints;
76
  protected int mVecCurr;    
77
  protected boolean cacheDirty; // VectorCache not up to date
78
  protected int mMode;          // LOOP, PATH or JUMP
79
  protected long mDuration;     // number of milliseconds it takes to do a full loop/path from first vector to the last and back to the first
80
  protected float mCount;       // number of loops/paths we will do; mCount = 1.5 means we go from the first vector to the last, back to first, and to the last again. 
81
  protected float mNoise;       // how 'smooth' our path form each vector to the next is. mNoise = 0.0 (min) --> completely smooth; mNoise==1.0 (max) --> very uneven
82

    
83
  protected class VectorNoise
84
    {
85
    float[][] n;
86

    
87
    VectorNoise(int dim)
88
      {
89
      n = new float[dim][NUM_NOISE];
90

    
91
      n[0][0] = mRnd.nextFloat();
92
      for(int i=1; i<NUM_NOISE; i++) n[0][i] = n[0][i-1]+mRnd.nextFloat();
93
      float sum = n[0][NUM_NOISE-1] + mRnd.nextFloat();
94
      for(int i=0; i<NUM_NOISE; i++) n[0][i] /=sum;
95

    
96
      for(int j=1; j<dim; j++)
97
        {
98
        for(int i=0; i<NUM_NOISE; i++) n[j][i] = mRnd.nextFloat()-0.5f;
99
        }
100
      }
101
    }
102

    
103
  protected Vector<VectorNoise> vn;
104
  protected float[] mFactor;
105

    
106
///////////////////////////////////////////////////////////////////////////////////////////////////
107
// hide this from Javadoc
108
  
109
  Dynamic()
110
    {
111
    }
112

    
113
///////////////////////////////////////////////////////////////////////////////////////////////////
114
  
115
  public void interpolateMain(float[] buffer, int offset, long currentDuration)
116
    {
117
    if( mDuration<=0.0f ) 
118
      {
119
      interpolate(buffer,offset,mCount-(int)mCount);  
120
      }
121
    else
122
      {
123
      float x = (float)currentDuration/mDuration;
124
           
125
      if( x<=mCount || mCount<=0.0f )
126
        {
127
        interpolate(buffer,offset,x-(int)x);
128
        }
129
      }
130
    }
131
  
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133

    
134
  public boolean interpolateMain(float[] buffer, int offset, long currentDuration, long step)
135
    {
136
    if( mDuration<=0.0f ) 
137
      {
138
      interpolate(buffer,offset,mCount-(int)mCount);
139
      return false;
140
      }
141
     
142
    float x = (float)currentDuration/mDuration;
143
           
144
    if( x<=mCount || mCount<=0.0f )
145
      {
146
      interpolate(buffer,offset,x-(int)x);
147
        
148
      if( currentDuration+step > mDuration*mCount && mCount>0.0f )
149
        {
150
        interpolate(buffer,offset,mCount-(int)mCount);
151
        return true;
152
        }
153
      }
154
    
155
    return false;
156
    }
157

    
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159

    
160
  protected float noise(float time,int vecNum)
161
    {
162
    float lower, upper, len;
163
    float d = time*(NUM_NOISE+1);
164
    int index = (int)d;
165
    if( index>=NUM_NOISE+1 ) index=NUM_NOISE;
166
    VectorNoise tmpN = vn.elementAt(vecNum);
167

    
168
    float t = d-index;
169
    t = t*t*(3-2*t);
170

    
171
    switch(index)
172
      {
173
      case 0        : for(int i=0;i<mDimension-1;i++) mFactor[i] = mNoise*tmpN.n[i+1][0]*t;
174
                      return time + mNoise*(d*tmpN.n[0][0]-time);
175
      case NUM_NOISE: for(int i=0;i<mDimension-1;i++) mFactor[i] = mNoise*tmpN.n[i+1][NUM_NOISE-1]*(1-t);
176
                      len = ((float)NUM_NOISE)/(NUM_NOISE+1);
177
                      lower = len + mNoise*(tmpN.n[0][NUM_NOISE-1]-len);
178
                      return (1.0f-lower)*(d-NUM_NOISE) + lower;
179
      default       : float ya,yb;
180

    
181
                      for(int i=0;i<mDimension-1;i++)
182
                        {
183
                        yb = tmpN.n[i+1][index  ];
184
                        ya = tmpN.n[i+1][index-1];
185
                        mFactor[i] = mNoise*((yb-ya)*t+ya);
186
                        }
187

    
188
                      len = ((float)index)/(NUM_NOISE+1);
189
                      lower = len + mNoise*(tmpN.n[0][index-1]-len);
190
                      len = ((float)index+1)/(NUM_NOISE+1);
191
                      upper = len + mNoise*(tmpN.n[0][index  ]-len);
192

    
193
                      return (upper-lower)*(d-index) + lower;
194
      }
195
    }
196

    
197
///////////////////////////////////////////////////////////////////////////////////////////////////
198
// internal debugging only!
199
  
200
  public String print()
201
    {
202
    return "duration="+mDuration+" count="+mCount+" Noise="+mNoise+" numVectors="+numPoints+" mMode="+mMode;
203
    }
204

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206

    
207
  abstract void interpolate(float[] buffer, int offset, float time);
208

    
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210
// PUBLIC API
211
///////////////////////////////////////////////////////////////////////////////////////////////////
212

    
213
/**
214
 * Sets the mode of the interpolation to Loop, Path or Jump.
215
 * <ul>
216
 * <li>Loop is when we go from the first point all the way to the last, and the back to the first through 
217
 * the shortest way.
218
 * <li>Path is when we come back from the last point back to the first the same way we got there.
219
 * <li>Jump is when we go from first to last and then jump back to the first.
220
 * </ul>
221
 * 
222
 * @param mode {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
223
 */
224

    
225
  public void setMode(int mode)
226
    {
227
    mMode = mode;  
228
    }
229

    
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231
/**
232
 * Returns the number of Static{1,2,3,4}Ds this Dynamic has been fed with.
233
 *   
234
 * @return the number of Static{1,2,3,4}Ds we are currently interpolating through.
235
 */
236
  public synchronized int getNumPoints()
237
    {
238
    return numPoints;  
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242
/**
243
 * Controls how many times we want to interpolate.
244
 * <p>
245
 * Count equal to 1 means 'go from the first Static{1,2,3,4}D to the last and back'. Does not have to be an
246
 * integer - i.e. count=1.5 would mean 'start at the first Point, go to the last, come back to the first, 
247
 * go to the last again and stop'.
248
 * Count<=0 means 'go on interpolating indefinitely'.
249
 * 
250
 * @param count the number of times we want to interpolate between our collection of Static{1,2,3,4}Ds.
251
 */
252
  public void setCount(float count)
253
    {
254
    mCount = count;  
255
    }
256

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258
/**
259
 * Sets the time it takes to do one full interpolation.
260
 * 
261
 * @param duration Time, in milliseconds, it takes to do one full interpolation, i.e. go from the first 
262
 *                 Point to the last and back. 
263
 */
264
  
265
  public void setDuration(long duration)
266
    {
267
    mDuration = duration;
268
    }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271
/**
272
 * Sets the 'smoothness' of interpolation. 
273
 * <p>
274
 * When Noise=0 (the default), we interpolate between our Points through the most smooth path possible. 
275
 * Increasing noise makes the Dynamic increasingly deviate from this path, pseudo-randomly speeding
276
 * up and slowing down, etc.
277
 * 
278
 * @param noise The noise level. Permitted range: 0 <= noise <= 1.
279
 */
280
  
281
  public synchronized void setNoise(float noise)
282
    {
283
    if( mNoise==0.0f && noise != 0.0f && vn==null )
284
      {
285
      vn = new Vector<>();
286
      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise(mDimension));
287

    
288
      if( mDimension>=2 )
289
        {
290
        mFactor = new float[mDimension-1];
291
        }
292
      }
293
   
294
    if( mNoise<0.0f ) mNoise = 0.0f;
295
    if( mNoise>1.0f ) mNoise = 1.0f;
296
   
297
    mNoise = noise;
298
    }
299

    
300
///////////////////////////////////////////////////////////////////////////////////////////////////
301
// end of DistortedInterpolator
302
  }
(6-6/17)