root/as3/MultiTouchSprite/trunk/demo/lib/Box2D/Collision/b2Distance.as

リビジョン 3986, 14.9 kB (コミッタ: alternadotin, コミット時期: 3 年 前)

ディレクトリの変更

Line 
1 /*
2 * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty.  In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 * Permission is granted to anyone to use this software for any purpose,
8 * including commercial applications, and to alter it and redistribute it
9 * freely, subject to the following restrictions:
10 * 1. The origin of this software must not be misrepresented; you must not
11 * claim that you wrote the original software. If you use this software
12 * in a product, an acknowledgment in the product documentation would be
13 * appreciated but is not required.
14 * 2. Altered source versions must be plainly marked as such, and must not be
15 * misrepresented as being the original software.
16 * 3. This notice may not be removed or altered from any source distribution.
17 */
18
19 package Box2D.Collision{
20        
21 import Box2D.Common.Math.*;
22 import Box2D.Common.*;
23 import Box2D.Collision.Shapes.*;
24 import Box2D.Collision.*;
25
26 public class b2Distance
27 {
28
29 // GJK using Voronoi regions (Christer Ericson) and region selection
30 // optimizations (Casey Muratori).
31
32 // The origin is either in the region of points[1] or in the edge region. The origin is
33 // not in region of points[0] because that is the old point.
34 static public function ProcessTwo(x1:b2Vec2, x2:b2Vec2, p1s:Array, p2s:Array, points:Array):int
35 {
36         var points_0:b2Vec2 = points[0];
37         var points_1:b2Vec2 = points[1];
38         var p1s_0:b2Vec2 = p1s[0];
39         var p1s_1:b2Vec2 = p1s[1];
40         var p2s_0:b2Vec2 = p2s[0];
41         var p2s_1:b2Vec2 = p2s[1];
42        
43         // If in point[1] region
44         //b2Vec2 r = -points[1];
45         var rX:Number = -points_1.x;
46         var rY:Number = -points_1.y;
47         //b2Vec2 d = points[1] - points[0];
48         var dX:Number = points_0.x - points_1.x;
49         var dY:Number = points_0.y - points_1.y;
50         //float32 length = d.Normalize();
51         var length:Number = Math.sqrt(dX*dX + dY*dY);
52         dX /= length;
53         dY /= length;
54        
55         //float32 lambda = b2Dot(r, d);
56         var lambda:Number = rX * dX + rY * dY;
57         if (lambda <= 0.0 || length < Number.MIN_VALUE)
58         {
59                 // The simplex is reduced to a point.
60                 //*p1Out = p1s[1];
61                 x1.SetV(p1s_1);
62                 //*p2Out = p2s[1];
63                 x2.SetV(p2s_1);
64                 //p1s[0] = p1s[1];
65                 p1s_0.SetV(p1s_1);
66                 //p2s[0] = p2s[1];
67                 p2s_0.SetV(p2s_1);
68                 points_0.SetV(points_1);
69                 return 1;
70         }
71
72         // Else in edge region
73         lambda /= length;
74         //*x1 = p1s[1] + lambda * (p1s[0] - p1s[1]);
75         x1.x = p1s_1.x + lambda * (p1s_0.x - p1s_1.x);
76         x1.y = p1s_1.y + lambda * (p1s_0.y - p1s_1.y);
77         //*x2 = p2s[1] + lambda * (p2s[0] - p2s[1]);
78         x2.x = p2s_1.x + lambda * (p2s_0.x - p2s_1.x);
79         x2.y = p2s_1.y + lambda * (p2s_0.y - p2s_1.y);
80         return 2;
81 }
82
83 // Possible regions:
84 // - points[2]
85 // - edge points[0]-points[2]
86 // - edge points[1]-points[2]
87 // - inside the triangle
88 static public function ProcessThree(x1:b2Vec2, x2:b2Vec2, p1s:Array, p2s:Array, points:Array):int
89 {
90         var points_0:b2Vec2 = points[0];
91         var points_1:b2Vec2 = points[1];
92         var points_2:b2Vec2 = points[2];
93         var p1s_0:b2Vec2 = p1s[0];
94         var p1s_1:b2Vec2 = p1s[1];
95         var p1s_2:b2Vec2 = p1s[2];
96         var p2s_0:b2Vec2 = p2s[0];
97         var p2s_1:b2Vec2 = p2s[1];
98         var p2s_2:b2Vec2 = p2s[2];
99        
100         //b2Vec2 a = points[0];
101         var aX:Number = points_0.x;
102         var aY:Number = points_0.y;
103         //b2Vec2 b = points[1];
104         var bX:Number = points_1.x;
105         var bY:Number = points_1.y;
106         //b2Vec2 c = points[2];
107         var cX:Number = points_2.x;
108         var cY:Number = points_2.y;
109
110         //b2Vec2 ab = b - a;
111         var abX:Number = bX - aX;
112         var abY:Number = bY - aY;
113         //b2Vec2 ac = c - a;
114         var acX:Number = cX - aX;
115         var acY:Number = cY - aY;
116         //b2Vec2 bc = c - b;
117         var bcX:Number = cX - bX;
118         var bcY:Number = cY - bY;
119
120         //float32 sn = -b2Dot(a, ab), sd = b2Dot(b, ab);
121         var sn:Number = -(aX * abX + aY * abY);
122         var sd:Number = (bX * abX + bY * abY);
123         //float32 tn = -b2Dot(a, ac), td = b2Dot(c, ac);
124         var tn:Number = -(aX * acX + aY * acY);
125         var td:Number = (cX * acX + cY * acY);
126         //float32 un = -b2Dot(b, bc), ud = b2Dot(c, bc);
127         var un:Number = -(bX * bcX + bY * bcY);
128         var ud:Number = (cX * bcX + cY * bcY);
129
130         // In vertex c region?
131         if (td <= 0.0 && ud <= 0.0)
132         {
133                 // Single point
134                 //*x1 = p1s[2];
135                 x1.SetV(p1s_2);
136                 //*x2 = p2s[2];
137                 x2.SetV(p2s_2);
138                 //p1s[0] = p1s[2];
139                 p1s_0.SetV(p1s_2);
140                 //p2s[0] = p2s[2];
141                 p2s_0.SetV(p2s_2);
142                 points_0.SetV(points_2);
143                 return 1;
144         }
145
146         // Should not be in vertex a or b region.
147         //b2Settings.b2Assert(sn > 0.0 || tn > 0.0);
148         //b2Settings.b2Assert(sd > 0.0 || un > 0.0);
149
150         //float32 n = b2Cross(ab, ac);
151         var n:Number = abX * acY - abY * acX;
152
153         // Should not be in edge ab region.
154         //float32 vc = n * b2Cross(a, b);
155         var vc:Number = n * (aX * bY - aY * bX);
156         //b2Settings.b2Assert(vc > 0.0 || sn > 0.0 || sd > 0.0);
157         var lambda:Number;
158        
159         // In edge bc region?
160         //float32 va = n * b2Cross(b, c);
161         var va:Number = n * (bX * cY - bY * cX);
162         if (va <= 0.0 && un >= 0.0 && ud >= 0.0 && (un+ud) > 0.0)
163         {
164                 //b2Settings.b2Assert(un + ud > 0.0);
165                
166                 //float32 lambda = un / (un + ud);
167                 lambda = un / (un + ud);
168                 //*x1 = p1s[1] + lambda * (p1s[2] - p1s[1]);
169                 x1.x = p1s_1.x + lambda * (p1s_2.x - p1s_1.x);
170                 x1.y = p1s_1.y + lambda * (p1s_2.y - p1s_1.y);
171                 //*x2 = p2s[1] + lambda * (p2s[2] - p2s[1]);
172                 x2.x = p2s_1.x + lambda * (p2s_2.x - p2s_1.x);
173                 x2.y = p2s_1.y + lambda * (p2s_2.y - p2s_1.y);
174                 //p1s[0] = p1s[2];
175                 p1s_0.SetV(p1s_2);
176                 //p2s[0] = p2s[2];
177                 p2s_0.SetV(p2s_2);
178                 //points[0] = points[2];
179                 points_0.SetV(points_2);
180                 return 2;
181         }
182
183         // In edge ac region?
184         //float32 vb = n * b2Cross(c, a);
185         var vb:Number = n * (cX * aY - cY * aX);
186         if (vb <= 0.0 && tn >= 0.0 && td >= 0.0 && (tn+td) > 0.0)
187         {
188                 //b2Settings.b2Assert(tn + td > 0.0);
189                
190                 //float32 lambda = tn / (tn + td);
191                 lambda = tn / (tn + td);
192                 //*x1 = p1s[0] + lambda * (p1s[2] - p1s[0]);
193                 x1.x = p1s_0.x + lambda * (p1s_2.x - p1s_0.x);
194                 x1.y = p1s_0.y + lambda * (p1s_2.y - p1s_0.y);
195                 //*x2 = p2s[0] + lambda * (p2s[2] - p2s[0]);
196                 x2.x = p2s_0.x + lambda * (p2s_2.x - p2s_0.x);
197                 x2.y = p2s_0.y + lambda * (p2s_2.y - p2s_0.y);
198                 //p1s[1] = p1s[2];
199                 p1s_1.SetV(p1s_2);
200                 //p2s[1] = p2s[2];
201                 p2s_1.SetV(p2s_2);
202                 //points[1] = points[2];
203                 points_1.SetV(points_2);
204                 return 2;
205         }
206
207         // Inside the triangle, compute barycentric coordinates
208         //float32 denom = va + vb + vc;
209         var denom:Number = va + vb + vc;
210         //b2Settings.b2Assert(denom > 0.0);
211         denom = 1.0 / denom;
212         //float32 u = va * denom;
213         var u:Number = va * denom;
214         //float32 v = vb * denom;
215         var v:Number = vb * denom;
216         //float32 w = 1.0f - u - v;
217         var w:Number = 1.0 - u - v;
218         //*x1 = u * p1s[0] + v * p1s[1] + w * p1s[2];
219         x1.x = u * p1s_0.x + v * p1s_1.x + w * p1s_2.x;
220         x1.y = u * p1s_0.y + v * p1s_1.y + w * p1s_2.y;
221         //*x2 = u * p2s[0] + v * p2s[1] + w * p2s[2];
222         x2.x = u * p2s_0.x + v * p2s_1.x + w * p2s_2.x;
223         x2.y = u * p2s_0.y + v * p2s_1.y + w * p2s_2.y;
224         return 3;
225 }
226
227 static public function InPoints(w:b2Vec2, points:Array, pointCount:int):Boolean
228 {
229         const k_tolerance:Number = 100.0 * Number.MIN_VALUE;
230         for (var i:int = 0; i < pointCount; ++i)
231         {
232                 var points_i:b2Vec2 = points[i];
233                 //b2Vec2 d = b2Abs(w - points[i]);
234                 var dX:Number = Math.abs(w.x - points_i.x);
235                 var dY:Number = Math.abs(w.y - points_i.y);
236                 //b2Vec2 m = b2Max(b2Abs(w), b2Abs(points[i]));
237                 var mX:Number = Math.max(Math.abs(w.x), Math.abs(points_i.x));
238                 var mY:Number = Math.max(Math.abs(w.y), Math.abs(points_i.y));
239                
240                 if (dX < k_tolerance * (mX + 1.0) &&
241                         dY < k_tolerance * (mY + 1.0)){
242                         return true;
243                 }
244         }
245
246         return false;
247 }
248
249 //
250 static private var s_p1s:Array = [new b2Vec2(), new b2Vec2(), new b2Vec2()];
251 static private var s_p2s:Array = [new b2Vec2(), new b2Vec2(), new b2Vec2()];
252 static private var s_points:Array = [new b2Vec2(), new b2Vec2(), new b2Vec2()];
253 //
254
255 static public function DistanceGeneric(x1:b2Vec2, x2:b2Vec2,
256                                                                                 shape1:*, xf1:b2XForm,
257                                                                                 shape2:*, xf2:b2XForm):Number
258 {
259         var tVec: b2Vec2;
260        
261         //b2Vec2 p1s[3], p2s[3];
262         var p1s:Array = s_p1s;
263         var p2s:Array = s_p2s;
264         //b2Vec2 points[3];
265         var points:Array = s_points;
266         //int32 pointCount = 0;
267         var pointCount:int = 0;
268
269         //*x1 = shape1->GetFirstVertex(xf1);
270         x1.SetV(shape1.GetFirstVertex(xf1));
271         //*x2 = shape2->GetFirstVertex(xf2);
272         x2.SetV(shape2.GetFirstVertex(xf2));
273
274         var vSqr:Number = 0.0;
275         const maxIterations:int = 20;
276         for (var iter:int = 0; iter < maxIterations; ++iter)
277         {
278                 //b2Vec2 v = *x2 - *x1;
279                 var vX:Number = x2.x - x1.x;
280                 var vY:Number = x2.y - x1.y;
281                 //b2Vec2 w1 = shape1->Support(xf1, v);
282                 var w1:b2Vec2 = shape1.Support(xf1, vX, vY);
283                 //b2Vec2 w2 = shape2->Support(xf2, -v);
284                 var w2:b2Vec2 = shape2.Support(xf2, -vX, -vY);
285                 //float32 vSqr = b2Dot(v, v);
286                 vSqr = (vX*vX + vY*vY);
287                 //b2Vec2 w = w2 - w1;
288                 var wX:Number = w2.x - w1.x;
289                 var wY:Number = w2.y - w1.y;
290                 //float32 vw = b2Dot(v, w);
291                 var vw:Number = (vX*wX + vY*wY);
292                 //if (vSqr - b2Dot(v, w) <= 0.01f * vSqr) // or w in points
293                 if (vSqr - vw <= 0.01 * vSqr) // or w in points
294                 {
295                         if (pointCount == 0)
296                         {
297                                 //*x1 = w1;
298                                 x1.SetV(w1);
299                                 //*x2 = w2;
300                                 x2.SetV(w2);
301                         }
302                         g_GJK_Iterations = iter;
303                         return Math.sqrt(vSqr);
304                 }
305                
306                 switch (pointCount)
307                 {
308                 case 0:
309                         //p1s[0] = w1;
310                         tVec = p1s[0];
311                         tVec.SetV(w1);
312                         //p2s[0] = w2;
313                         tVec = p2s[0];
314                         tVec.SetV(w2);
315                         //points[0] = w;
316                         tVec = points[0];
317                         tVec.x = wX;
318                         tVec.y = wY;
319                         //*x1 = p1s[0];
320                         x1.SetV(p1s[0]);
321                         //*x2 = p2s[0];
322                         x2.SetV(p2s[0]);
323                         ++pointCount;
324                         break;
325                        
326                 case 1:
327                         //p1s[1] = w1;
328                         tVec = p1s[1];
329                         tVec.SetV(w1);
330                         //p2s[1] = w2;
331                         tVec = p2s[1];
332                         tVec.SetV(w2);
333                         //points[1] = w;
334                         tVec = points[1];
335                         tVec.x = wX;
336                         tVec.y = wY;
337                         pointCount = ProcessTwo(x1, x2, p1s, p2s, points);
338                         break;
339                        
340                 case 2:
341                         //p1s[2] = w1;
342                         tVec = p1s[2];
343                         tVec.SetV(w1);
344                         //p2s[2] = w2;
345                         tVec = p2s[2];
346                         tVec.SetV(w2);
347                         //points[2] = w;
348                         tVec = points[2];
349                         tVec.x = wX;
350                         tVec.y = wY;
351                         pointCount = ProcessThree(x1, x2, p1s, p2s, points);
352                         break;
353                 }
354                
355                 // If we have three points, then the origin is in the corresponding triangle.
356                 if (pointCount == 3)
357                 {
358                         g_GJK_Iterations = iter;
359                         return 0.0;
360                 }
361                
362                 //float32 maxSqr = -FLT_MAX;
363                 var maxSqr:Number = -Number.MAX_VALUE;
364                 for (var i:int = 0; i < pointCount; ++i)
365                 {
366                         //maxSqr = b2Math.b2Max(maxSqr, b2Dot(points[i], points[i]));
367                         tVec = points[i];
368                         maxSqr = b2Math.b2Max(maxSqr, (tVec.x*tVec.x + tVec.y*tVec.y));
369                 }
370                
371                 if (pointCount == 3 || vSqr <= 100.0 * Number.MIN_VALUE * maxSqr)
372                 {
373                         g_GJK_Iterations = iter;
374                         //v = *x2 - *x1;
375                         vX = x2.x - x1.x;
376                         vY = x2.y - x1.y;
377                         //vSqr = b2Dot(v, v);
378                         vSqr = (vX*vX + vY*vY);
379                         return Math.sqrt(vSqr);
380                 }
381         }
382
383         g_GJK_Iterations = maxIterations;
384         return Math.sqrt(vSqr);
385 }
386
387
388 static public function DistanceCC(
389         x1:b2Vec2, x2:b2Vec2,
390         circle1:b2CircleShape, xf1:b2XForm,
391         circle2:b2CircleShape, xf2:b2XForm) : Number
392 {
393         var tMat:b2Mat22;
394         var tVec:b2Vec2;
395         //b2Vec2 p1 = b2Mul(xf1, circle1->m_localPosition);
396         tMat = xf1.R;
397         tVec = circle1.m_localPosition;
398         var p1X:Number = xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
399         var p1Y:Number = xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
400         //b2Vec2 p2 = b2Mul(xf2, circle2->m_localPosition);
401         tMat = xf2.R;
402         tVec = circle2.m_localPosition;
403         var p2X:Number = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
404         var p2Y:Number = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
405
406         //b2Vec2 d = p2 - p1;
407         var dX:Number = p2X - p1X;
408         var dY:Number = p2Y - p1Y;
409         var dSqr:Number = (dX*dX + dY*dY);
410         var r1:Number = circle1.m_radius - b2Settings.b2_toiSlop;
411         var r2:Number = circle2.m_radius - b2Settings.b2_toiSlop;
412         var r:Number = r1 + r2;
413         if (dSqr > r * r)
414         {
415                 //var dLen:Number = d.Normalize();
416                 var dLen:Number = Math.sqrt(dSqr);
417                 dX /= dLen;
418                 dY /= dLen;
419                 var distance:Number = dLen - r;
420                 //*x1 = p1 + r1 * d;
421                 x1.x = p1X + r1 * dX;
422                 x1.y = p1Y + r1 * dY;
423                 //*x2 = p2 - r2 * d;
424                 x2.x = p2X - r2 * dX;
425                 x2.y = p2Y - r2 * dY;
426                 return distance;
427         }
428         else if (dSqr > Number.MIN_VALUE * Number.MIN_VALUE)
429         {
430                 //d.Normalize();
431                 dLen = Math.sqrt(dSqr);
432                 dX /= dLen;
433                 dY /= dLen;
434                 //*x1 = p1 + r1 * d;
435                 x1.x = p1X + r1 * dX;
436                 x1.y = p1Y + r1 * dY;
437                 //*x2 = *x1;
438                 x2.x = x1.x;
439                 x2.y = x1.y;
440                 return 0.0;
441         }
442
443         //*x1 = p1;
444         x1.x = p1X;
445         x1.y = p1Y;
446         //*x2 = *x1;
447         x2.x = x1.x;
448         x2.y = x1.y;
449         return 0.0;
450 }
451
452
453
454 // GJK is more robust with polygon-vs-point than polygon-vs-circle.
455 // So we convert polygon-vs-circle to polygon-vs-point.
456 static private var gPoint:b2Point = new b2Point();
457 ///
458 static public function DistancePC(
459         x1:b2Vec2, x2:b2Vec2,
460         polygon:b2PolygonShape, xf1:b2XForm,
461         circle:b2CircleShape, xf2:b2XForm) : Number
462 {
463        
464         var tMat:b2Mat22;
465         var tVec:b2Vec2;
466        
467         var point:b2Point = gPoint;
468         //point.p = b2Mul(xf2, circle->m_localPosition);
469         tVec = circle.m_localPosition;
470         tMat = xf2.R;
471         point.p.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
472         point.p.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
473
474         // Create variation of function to replace template
475         var distance:Number = DistanceGeneric(x1, x2, polygon, xf1, point, b2Math.b2XForm_identity);
476
477         var r:Number = circle.m_radius - b2Settings.b2_toiSlop;
478
479         if (distance > r)
480         {
481                 distance -= r;
482                 //b2Vec2 d = *x2 - *x1;
483                 var dX:Number = x2.x - x1.x;
484                 var dY:Number = x2.y - x1.y;
485                 //d.Normalize();
486                 var dLen:Number = Math.sqrt(dX*dX + dY*dY);
487                 dX /= dLen;
488                 dY /= dLen;
489                 //*x2 -= r * d;
490                 x2.x -= r * dX;
491                 x2.y -= r * dY;
492         }
493         else
494         {
495                 distance = 0.0;
496                 //*x2 = *x1;
497                 x2.x = x1.x;
498                 x2.y = x1.y;
499         }
500        
501         return distance;
502 }
503
504
505 static public function Distance(x1:b2Vec2, x2:b2Vec2,
506                                    shape1:b2Shape, xf1:b2XForm,
507                                    shape2:b2Shape, xf2:b2XForm) : Number
508 {
509         //b2ShapeType type1 = shape1->GetType();
510         var type1:int = shape1.m_type;
511         //b2ShapeType type2 = shape2->GetType();
512         var type2:int = shape2.m_type;
513
514         if (type1 == b2Shape.e_circleShape && type2 == b2Shape.e_circleShape)
515         {
516                 //return DistanceCC(x1, x2, (b2CircleShape*)shape1, xf1, (b2CircleShape*)shape2, xf2);
517                 return DistanceCC(x1, x2, shape1 as b2CircleShape, xf1, shape2 as b2CircleShape, xf2);
518         }
519        
520         if (type1 == b2Shape.e_polygonShape && type2 == b2Shape.e_circleShape)
521         {
522                 //return DistancePC(x1, x2, (b2PolygonShape*)shape1, xf1, (b2CircleShape*)shape2, xf2);
523                 return DistancePC(x1, x2, shape1 as b2PolygonShape, xf1, shape2 as b2CircleShape, xf2);
524         }
525
526         if (type1 == b2Shape.e_circleShape && type2 == b2Shape.e_polygonShape)
527         {
528                 return DistancePC(x2, x1, shape2 as b2PolygonShape, xf2, shape1 as b2CircleShape, xf1);
529         }
530
531         if (type1 == b2Shape.e_polygonShape && type2 == b2Shape.e_polygonShape)
532         {
533                 return DistanceGeneric(x1, x2, shape1 as b2PolygonShape, xf1, shape2 as b2PolygonShape, xf2);
534         }
535        
536         return 0.0;
537 }
538
539
540
541 static public var g_GJK_Iterations:int = 0;
542
543
544
545 };
546
547
548 }
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。