source: other-projects/playing-in-the-street/summer-2013/trunk/Playing-in-the-Street-WPF/Content/Web/mrdoob-three.js-4862f5f/src/math/Ray.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: 9.3 KB
Line 
1/**
2 * @author bhouston / http://exocortex.com
3 */
4
5THREE.Ray = function ( origin, direction ) {
6
7 this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3();
8 this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3();
9
10};
11
12THREE.Ray.prototype = {
13
14 constructor: THREE.Ray,
15
16 set: function ( origin, direction ) {
17
18 this.origin.copy( origin );
19 this.direction.copy( direction );
20
21 return this;
22
23 },
24
25 copy: function ( ray ) {
26
27 this.origin.copy( ray.origin );
28 this.direction.copy( ray.direction );
29
30 return this;
31
32 },
33
34 at: function ( t, optionalTarget ) {
35
36 var result = optionalTarget || new THREE.Vector3();
37
38 return result.copy( this.direction ).multiplyScalar( t ).add( this.origin );
39
40 },
41
42 recast: function () {
43
44 var v1 = new THREE.Vector3();
45
46 return function ( t ) {
47
48 this.origin.copy( this.at( t, v1 ) );
49
50 return this;
51
52 };
53
54 }(),
55
56 closestPointToPoint: function ( point, optionalTarget ) {
57
58 var result = optionalTarget || new THREE.Vector3();
59 result.subVectors( point, this.origin );
60 var directionDistance = result.dot( this.direction );
61
62 if ( directionDistance < 0 ) {
63
64 return result.copy( this.origin );
65
66 }
67
68 return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
69
70 },
71
72 distanceToPoint: function () {
73
74 var v1 = new THREE.Vector3();
75
76 return function ( point ) {
77
78 var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
79
80 // point behind the ray
81
82 if ( directionDistance < 0 ) {
83
84 return this.origin.distanceTo( point );
85
86 }
87
88 v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
89
90 return v1.distanceTo( point );
91
92 };
93
94 }(),
95
96 distanceSqToSegment: function( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
97
98 // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp
99 // It returns the min distance between the ray and the segment
100 // defined by v0 and v1
101 // It can also set two optional targets :
102 // - The closest point on the ray
103 // - The closest point on the segment
104
105 var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 );
106 var segDir = v1.clone().sub( v0 ).normalize();
107 var segExtent = v0.distanceTo( v1 ) * 0.5;
108 var diff = this.origin.clone().sub( segCenter );
109 var a01 = - this.direction.dot( segDir );
110 var b0 = diff.dot( this.direction );
111 var b1 = - diff.dot( segDir );
112 var c = diff.lengthSq();
113 var det = Math.abs( 1 - a01 * a01 );
114 var s0, s1, sqrDist, extDet;
115
116 if ( det >= 0 ) {
117
118 // The ray and segment are not parallel.
119
120 s0 = a01 * b1 - b0;
121 s1 = a01 * b0 - b1;
122 extDet = segExtent * det;
123
124 if ( s0 >= 0 ) {
125
126 if ( s1 >= - extDet ) {
127
128 if ( s1 <= extDet ) {
129
130 // region 0
131 // Minimum at interior points of ray and segment.
132
133 var invDet = 1 / det;
134 s0 *= invDet;
135 s1 *= invDet;
136 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
137
138 } else {
139
140 // region 1
141
142 s1 = segExtent;
143 s0 = Math.max( 0, - ( a01 * s1 + b0) );
144 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
145
146 }
147
148 } else {
149
150 // region 5
151
152 s1 = - segExtent;
153 s0 = Math.max( 0, - ( a01 * s1 + b0) );
154 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
155
156 }
157
158 } else {
159
160 if ( s1 <= - extDet) {
161
162 // region 4
163
164 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
165 s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
166 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
167
168 } else if ( s1 <= extDet ) {
169
170 // region 3
171
172 s0 = 0;
173 s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
174 sqrDist = s1 * ( s1 + 2 * b1 ) + c;
175
176 } else {
177
178 // region 2
179
180 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
181 s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
182 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
183
184 }
185
186 }
187
188 } else {
189
190 // Ray and segment are parallel.
191
192 s1 = ( a01 > 0 ) ? - segExtent : segExtent;
193 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
194 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
195
196 }
197
198 if ( optionalPointOnRay ) {
199
200 optionalPointOnRay.copy( this.direction.clone().multiplyScalar( s0 ).add( this.origin ) );
201
202 }
203
204 if ( optionalPointOnSegment ) {
205
206 optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) );
207
208 }
209
210 return sqrDist;
211
212 },
213
214 isIntersectionSphere: function ( sphere ) {
215
216 return this.distanceToPoint( sphere.center ) <= sphere.radius;
217
218 },
219
220 isIntersectionPlane: function ( plane ) {
221
222 // check if the ray lies on the plane first
223
224 var distToPoint = plane.distanceToPoint( this.origin );
225
226 if ( distToPoint === 0 ) {
227
228 return true;
229
230 }
231
232 var denominator = plane.normal.dot( this.direction );
233
234 if ( denominator * distToPoint < 0 ) {
235
236 return true
237
238 }
239
240 // ray origin is behind the plane (and is pointing behind it)
241
242 return false;
243
244 },
245
246 distanceToPlane: function ( plane ) {
247
248 var denominator = plane.normal.dot( this.direction );
249 if ( denominator == 0 ) {
250
251 // line is coplanar, return origin
252 if( plane.distanceToPoint( this.origin ) == 0 ) {
253
254 return 0;
255
256 }
257
258 // Null is preferable to undefined since undefined means.... it is undefined
259
260 return null;
261
262 }
263
264 var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
265
266 // Return if the ray never intersects the plane
267
268 return t >= 0 ? t : null;
269
270 },
271
272 intersectPlane: function ( plane, optionalTarget ) {
273
274 var t = this.distanceToPlane( plane );
275
276 if ( t === null ) {
277
278 return null;
279 }
280
281 return this.at( t, optionalTarget );
282
283 },
284
285 isIntersectionBox: function () {
286
287 var v = new THREE.Vector3();
288
289 return function ( box ) {
290
291 return this.intersectBox( box, v ) !== null;
292
293 }
294
295 }(),
296
297 intersectBox: function ( box , optionalTarget ) {
298
299 // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/
300
301 var tmin,tmax,tymin,tymax,tzmin,tzmax;
302
303 var invdirx = 1/this.direction.x,
304 invdiry = 1/this.direction.y,
305 invdirz = 1/this.direction.z;
306
307 var origin = this.origin;
308
309 if (invdirx >= 0) {
310
311 tmin = (box.min.x - origin.x) * invdirx;
312 tmax = (box.max.x - origin.x) * invdirx;
313
314 } else {
315
316 tmin = (box.max.x - origin.x) * invdirx;
317 tmax = (box.min.x - origin.x) * invdirx;
318 }
319
320 if (invdiry >= 0) {
321
322 tymin = (box.min.y - origin.y) * invdiry;
323 tymax = (box.max.y - origin.y) * invdiry;
324
325 } else {
326
327 tymin = (box.max.y - origin.y) * invdiry;
328 tymax = (box.min.y - origin.y) * invdiry;
329 }
330
331 if ((tmin > tymax) || (tymin > tmax)) return null;
332
333 // These lines also handle the case where tmin or tmax is NaN
334 // (result of 0 * Infinity). x !== x returns true if x is NaN
335
336 if (tymin > tmin || tmin !== tmin ) tmin = tymin;
337
338 if (tymax < tmax || tmax !== tmax ) tmax = tymax;
339
340 if (invdirz >= 0) {
341
342 tzmin = (box.min.z - origin.z) * invdirz;
343 tzmax = (box.max.z - origin.z) * invdirz;
344
345 } else {
346
347 tzmin = (box.max.z - origin.z) * invdirz;
348 tzmax = (box.min.z - origin.z) * invdirz;
349 }
350
351 if ((tmin > tzmax) || (tzmin > tmax)) return null;
352
353 if (tzmin > tmin || tmin !== tmin ) tmin = tzmin;
354
355 if (tzmax < tmax || tmax !== tmax ) tmax = tzmax;
356
357 //return point closest to the ray (positive side)
358
359 if ( tmax < 0 ) return null;
360
361 return this.at( tmin >= 0 ? tmin : tmax, optionalTarget );
362
363 },
364
365 intersectTriangle: function() {
366
367 // Compute the offset origin, edges, and normal.
368 var diff = new THREE.Vector3();
369 var edge1 = new THREE.Vector3();
370 var edge2 = new THREE.Vector3();
371 var normal = new THREE.Vector3();
372
373 return function ( a, b, c, backfaceCulling, optionalTarget ) {
374
375 // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp
376
377 edge1.subVectors( b, a );
378 edge2.subVectors( c, a );
379 normal.crossVectors( edge1, edge2 );
380
381 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
382 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
383 // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
384 // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
385 // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
386 var DdN = this.direction.dot( normal );
387 var sign;
388
389 if ( DdN > 0 ) {
390
391 if ( backfaceCulling ) return null;
392 sign = 1;
393
394 } else if ( DdN < 0 ) {
395
396 sign = - 1;
397 DdN = - DdN;
398
399 } else {
400
401 return null;
402
403 }
404
405 diff.subVectors( this.origin, a );
406 var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );
407
408 // b1 < 0, no intersection
409 if ( DdQxE2 < 0 ) {
410
411 return null;
412
413 }
414
415 var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );
416
417 // b2 < 0, no intersection
418 if ( DdE1xQ < 0 ) {
419
420 return null;
421
422 }
423
424 // b1+b2 > 1, no intersection
425 if ( DdQxE2 + DdE1xQ > DdN ) {
426
427 return null;
428
429 }
430
431 // Line intersects triangle, check if ray does.
432 var QdN = - sign * diff.dot( normal );
433
434 // t < 0, no intersection
435 if ( QdN < 0 ) {
436
437 return null;
438
439 }
440
441 // Ray intersects triangle.
442 return this.at( QdN / DdN, optionalTarget );
443
444 }
445
446 }(),
447
448 applyMatrix4: function ( matrix4 ) {
449
450 this.direction.add( this.origin ).applyMatrix4( matrix4 );
451 this.origin.applyMatrix4( matrix4 );
452 this.direction.sub( this.origin );
453 this.direction.normalize();
454
455 return this;
456 },
457
458 equals: function ( ray ) {
459
460 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
461
462 },
463
464 clone: function () {
465
466 return new THREE.Ray().copy( this );
467
468 }
469
470};
Note: See TracBrowser for help on using the repository browser.