source: other-projects/playing-in-the-street/summer-2013/trunk/Playing-in-the-Street-WPF/Content/Web/mrdoob-three.js-4862f5f/src/extras/core/Curve.js@ 28897

Last change on this file since 28897 was 28897, checked in by davidb, 10 years ago

GUI front-end to server base plus web page content

File size: 6.6 KB
Line 
1/**
2 * @author zz85 / http://www.lab4games.net/zz85/blog
3 * Extensible curve object
4 *
5 * Some common of Curve methods
6 * .getPoint(t), getTangent(t)
7 * .getPointAt(u), getTagentAt(u)
8 * .getPoints(), .getSpacedPoints()
9 * .getLength()
10 * .updateArcLengths()
11 *
12 * This following classes subclasses THREE.Curve:
13 *
14 * -- 2d classes --
15 * THREE.LineCurve
16 * THREE.QuadraticBezierCurve
17 * THREE.CubicBezierCurve
18 * THREE.SplineCurve
19 * THREE.ArcCurve
20 * THREE.EllipseCurve
21 *
22 * -- 3d classes --
23 * THREE.LineCurve3
24 * THREE.QuadraticBezierCurve3
25 * THREE.CubicBezierCurve3
26 * THREE.SplineCurve3
27 * THREE.ClosedSplineCurve3
28 *
29 * A series of curves can be represented as a THREE.CurvePath
30 *
31 **/
32
33/**************************************************************
34 * Abstract Curve base class
35 **************************************************************/
36
37THREE.Curve = function () {
38
39};
40
41// Virtual base class method to overwrite and implement in subclasses
42// - t [0 .. 1]
43
44THREE.Curve.prototype.getPoint = function ( t ) {
45
46 console.log( "Warning, getPoint() not implemented!" );
47 return null;
48
49};
50
51// Get point at relative position in curve according to arc length
52// - u [0 .. 1]
53
54THREE.Curve.prototype.getPointAt = function ( u ) {
55
56 var t = this.getUtoTmapping( u );
57 return this.getPoint( t );
58
59};
60
61// Get sequence of points using getPoint( t )
62
63THREE.Curve.prototype.getPoints = function ( divisions ) {
64
65 if ( !divisions ) divisions = 5;
66
67 var d, pts = [];
68
69 for ( d = 0; d <= divisions; d ++ ) {
70
71 pts.push( this.getPoint( d / divisions ) );
72
73 }
74
75 return pts;
76
77};
78
79// Get sequence of points using getPointAt( u )
80
81THREE.Curve.prototype.getSpacedPoints = function ( divisions ) {
82
83 if ( !divisions ) divisions = 5;
84
85 var d, pts = [];
86
87 for ( d = 0; d <= divisions; d ++ ) {
88
89 pts.push( this.getPointAt( d / divisions ) );
90
91 }
92
93 return pts;
94
95};
96
97// Get total curve arc length
98
99THREE.Curve.prototype.getLength = function () {
100
101 var lengths = this.getLengths();
102 return lengths[ lengths.length - 1 ];
103
104};
105
106// Get list of cumulative segment lengths
107
108THREE.Curve.prototype.getLengths = function ( divisions ) {
109
110 if ( !divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200;
111
112 if ( this.cacheArcLengths
113 && ( this.cacheArcLengths.length == divisions + 1 )
114 && !this.needsUpdate) {
115
116 //console.log( "cached", this.cacheArcLengths );
117 return this.cacheArcLengths;
118
119 }
120
121 this.needsUpdate = false;
122
123 var cache = [];
124 var current, last = this.getPoint( 0 );
125 var p, sum = 0;
126
127 cache.push( 0 );
128
129 for ( p = 1; p <= divisions; p ++ ) {
130
131 current = this.getPoint ( p / divisions );
132 sum += current.distanceTo( last );
133 cache.push( sum );
134 last = current;
135
136 }
137
138 this.cacheArcLengths = cache;
139
140 return cache; // { sums: cache, sum:sum }; Sum is in the last element.
141
142};
143
144
145THREE.Curve.prototype.updateArcLengths = function() {
146 this.needsUpdate = true;
147 this.getLengths();
148};
149
150// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance
151
152THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) {
153
154 var arcLengths = this.getLengths();
155
156 var i = 0, il = arcLengths.length;
157
158 var targetArcLength; // The targeted u distance value to get
159
160 if ( distance ) {
161
162 targetArcLength = distance;
163
164 } else {
165
166 targetArcLength = u * arcLengths[ il - 1 ];
167
168 }
169
170 //var time = Date.now();
171
172 // binary search for the index with largest value smaller than target u distance
173
174 var low = 0, high = il - 1, comparison;
175
176 while ( low <= high ) {
177
178 i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
179
180 comparison = arcLengths[ i ] - targetArcLength;
181
182 if ( comparison < 0 ) {
183
184 low = i + 1;
185 continue;
186
187 } else if ( comparison > 0 ) {
188
189 high = i - 1;
190 continue;
191
192 } else {
193
194 high = i;
195 break;
196
197 // DONE
198
199 }
200
201 }
202
203 i = high;
204
205 //console.log('b' , i, low, high, Date.now()- time);
206
207 if ( arcLengths[ i ] == targetArcLength ) {
208
209 var t = i / ( il - 1 );
210 return t;
211
212 }
213
214 // we could get finer grain at lengths, or use simple interpolatation between two points
215
216 var lengthBefore = arcLengths[ i ];
217 var lengthAfter = arcLengths[ i + 1 ];
218
219 var segmentLength = lengthAfter - lengthBefore;
220
221 // determine where we are between the 'before' and 'after' points
222
223 var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
224
225 // add that fractional amount to t
226
227 var t = ( i + segmentFraction ) / ( il -1 );
228
229 return t;
230
231};
232
233// Returns a unit vector tangent at t
234// In case any sub curve does not implement its tangent derivation,
235// 2 points a small delta apart will be used to find its gradient
236// which seems to give a reasonable approximation
237
238THREE.Curve.prototype.getTangent = function( t ) {
239
240 var delta = 0.0001;
241 var t1 = t - delta;
242 var t2 = t + delta;
243
244 // Capping in case of danger
245
246 if ( t1 < 0 ) t1 = 0;
247 if ( t2 > 1 ) t2 = 1;
248
249 var pt1 = this.getPoint( t1 );
250 var pt2 = this.getPoint( t2 );
251
252 var vec = pt2.clone().sub(pt1);
253 return vec.normalize();
254
255};
256
257
258THREE.Curve.prototype.getTangentAt = function ( u ) {
259
260 var t = this.getUtoTmapping( u );
261 return this.getTangent( t );
262
263};
264
265
266
267
268
269/**************************************************************
270 * Utils
271 **************************************************************/
272
273THREE.Curve.Utils = {
274
275 tangentQuadraticBezier: function ( t, p0, p1, p2 ) {
276
277 return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 );
278
279 },
280
281 // Puay Bing, thanks for helping with this derivative!
282
283 tangentCubicBezier: function (t, p0, p1, p2, p3 ) {
284
285 return -3 * p0 * (1 - t) * (1 - t) +
286 3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) +
287 6 * t * p2 * (1-t) - 3 * t * t * p2 +
288 3 * t * t * p3;
289 },
290
291
292 tangentSpline: function ( t, p0, p1, p2, p3 ) {
293
294 // To check if my formulas are correct
295
296 var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1
297 var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t
298 var h01 = -6 * t * t + 6 * t; // − 2t3 + 3t2
299 var h11 = 3 * t * t - 2 * t; // t3 − t2
300
301 return h00 + h10 + h01 + h11;
302
303 },
304
305 // Catmull-Rom
306
307 interpolate: function( p0, p1, p2, p3, t ) {
308
309 var v0 = ( p2 - p0 ) * 0.5;
310 var v1 = ( p3 - p1 ) * 0.5;
311 var t2 = t * t;
312 var t3 = t * t2;
313 return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
314
315 }
316
317};
318
319
320// TODO: Transformation for Curves?
321
322/**************************************************************
323 * 3D Curves
324 **************************************************************/
325
326// A Factory method for creating new curve subclasses
327
328THREE.Curve.create = function ( constructor, getPointFunc ) {
329
330 constructor.prototype = Object.create( THREE.Curve.prototype );
331 constructor.prototype.getPoint = getPointFunc;
332
333 return constructor;
334
335};
Note: See TracBrowser for help on using the repository browser.