@awayfl/awayfl-player
Version:
Flash Player emulator for executing SWF files (published for FP versions 6 and up) in javascript
837 lines (753 loc) • 25.7 kB
text/typescript
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
import { b2Vec2, b2XForm, b2Math, b2Mat22 } from '../Common/Math';
import { b2Settings } from '../Common/b2Settings';
import { b2Shape } from './Shapes/b2Shape';
import { b2Point } from './b2Point';
import { b2PolygonShape } from './Shapes/b2PolygonShape';
import { b2CircleShape } from './Shapes/b2CircleShape';
import { b2DistanceRegister } from './b2DistanceRegister';
import { b2ManifoldPoint } from './b2ManifoldPoint';
import { b2ConcaveArcShape } from './Shapes/b2ConcaveArcShape';
import { b2StaticEdgeShape } from './Shapes/b2StaticEdgeShape';
export class b2Distance {
public static AddType(fcn:Function, type1:number /** int */, type2:number /** int */) : void
{
//b2Settings.b2Assert(b2Shape.e_unknownShape < type1 && type1 < b2Shape.e_shapeTypeCount);
//b2Settings.b2Assert(b2Shape.e_unknownShape < type2 && type2 < b2Shape.e_shapeTypeCount);
this.s_registers[type1 + type2 * b2Shape.e_shapeTypeCount] = new b2DistanceRegister(fcn, true);
if (type1 != type2)
{
this.s_registers[type2 + type1 * b2Shape.e_shapeTypeCount] = new b2DistanceRegister(fcn, false);
}
}
public static InitializeRegisters() : void {
if (this.s_initialized == true) {
return;
}
this.s_initialized = true;
this.s_registers = new Array(b2Shape.e_shapeTypeCount * b2Shape.e_shapeTypeCount);
//Flash only: Function closures
this.AddType(this.DistanceCC, b2Shape.e_circleShape, b2Shape.e_circleShape);
this.AddType(this.DistancePC, b2Shape.e_polygonShape, b2Shape.e_circleShape);
this.AddType(this.DistanceGeneric, b2Shape.e_polygonShape, b2Shape.e_polygonShape);
this.AddType(this.DistanceCcaC, b2Shape.e_concaveArcShape, b2Shape.e_circleShape);
this.AddType(this.DistancePCca, b2Shape.e_polygonShape, b2Shape.e_concaveArcShape);
this.AddType(this.DistanceSeC, b2Shape.e_staticEdgeShape, b2Shape.e_circleShape);
this.AddType(this.DistanceGeneric, b2Shape.e_polygonShape, b2Shape.e_staticEdgeShape);
}
// GJK using Voronoi regions (Christer Ericson) and region selection
// optimizations (Casey Muratori).
// The origin is either in the region of points[1] or in the edge region. The origin is
// not in region of points[0] because that is the old point.
public static ProcessTwo(x1: b2Vec2, x2: b2Vec2, p1s: b2Vec2[], p2s: b2Vec2[], points: b2Vec2[]): number /** int */
{
const points_0: b2Vec2 = points[0];
const points_1: b2Vec2 = points[1];
const p1s_0: b2Vec2 = p1s[0];
const p1s_1: b2Vec2 = p1s[1];
const p2s_0: b2Vec2 = p2s[0];
const p2s_1: b2Vec2 = p2s[1];
// If in point[1] region
//b2Vec2 r = -points[1];
const rX: number = -points_1.x;
const rY: number = -points_1.y;
//b2Vec2 d = points[1] - points[0];
let dX: number = points_0.x - points_1.x;
let dY: number = points_0.y - points_1.y;
//float32 length = d.Normalize();
const length: number = Math.sqrt(dX * dX + dY * dY);
dX /= length;
dY /= length;
//float32 lambda = b2Dot(r, d);
let lambda: number = rX * dX + rY * dY;
if (lambda <= 0.0 || length < Number.MIN_VALUE) {
// The simplex is reduced to a point.
//*p1Out = p1s[1];
x1.SetV(p1s_1);
//*p2Out = p2s[1];
x2.SetV(p2s_1);
//p1s[0] = p1s[1];
p1s_0.SetV(p1s_1);
//p2s[0] = p2s[1];
p2s_0.SetV(p2s_1);
points_0.SetV(points_1);
return 1;
}
// Else in edge region
lambda /= length;
//*x1 = p1s[1] + lambda * (p1s[0] - p1s[1]);
x1.x = p1s_1.x + lambda * (p1s_0.x - p1s_1.x);
x1.y = p1s_1.y + lambda * (p1s_0.y - p1s_1.y);
//*x2 = p2s[1] + lambda * (p2s[0] - p2s[1]);
x2.x = p2s_1.x + lambda * (p2s_0.x - p2s_1.x);
x2.y = p2s_1.y + lambda * (p2s_0.y - p2s_1.y);
return 2;
}
// Possible regions:
// - points[2]
// - edge points[0]-points[2]
// - edge points[1]-points[2]
// - inside the triangle
public static ProcessThree(x1: b2Vec2, x2: b2Vec2, p1s: b2Vec2[], p2s: b2Vec2[], points: b2Vec2[]): number /** int */
{
const points_0: b2Vec2 = points[0];
const points_1: b2Vec2 = points[1];
const points_2: b2Vec2 = points[2];
const p1s_0: b2Vec2 = p1s[0];
const p1s_1: b2Vec2 = p1s[1];
const p1s_2: b2Vec2 = p1s[2];
const p2s_0: b2Vec2 = p2s[0];
const p2s_1: b2Vec2 = p2s[1];
const p2s_2: b2Vec2 = p2s[2];
//b2Vec2 a = points[0];
const aX: number = points_0.x;
const aY: number = points_0.y;
//b2Vec2 b = points[1];
const bX: number = points_1.x;
const bY: number = points_1.y;
//b2Vec2 c = points[2];
const cX: number = points_2.x;
const cY: number = points_2.y;
//b2Vec2 ab = b - a;
const abX: number = bX - aX;
const abY: number = bY - aY;
//b2Vec2 ac = c - a;
const acX: number = cX - aX;
const acY: number = cY - aY;
//b2Vec2 bc = c - b;
const bcX: number = cX - bX;
const bcY: number = cY - bY;
//float32 sn = -b2Dot(a, ab), sd = b2Dot(b, ab);
const sn: number = -(aX * abX + aY * abY);
const sd: number = (bX * abX + bY * abY);
//float32 tn = -b2Dot(a, ac), td = b2Dot(c, ac);
const tn: number = -(aX * acX + aY * acY);
const td: number = (cX * acX + cY * acY);
//float32 un = -b2Dot(b, bc), ud = b2Dot(c, bc);
const un: number = -(bX * bcX + bY * bcY);
const ud: number = (cX * bcX + cY * bcY);
// In vertex c region?
if (td <= 0.0 && ud <= 0.0) {
// Single point
//*x1 = p1s[2];
x1.SetV(p1s_2);
//*x2 = p2s[2];
x2.SetV(p2s_2);
//p1s[0] = p1s[2];
p1s_0.SetV(p1s_2);
//p2s[0] = p2s[2];
p2s_0.SetV(p2s_2);
points_0.SetV(points_2);
return 1;
}
// Should not be in vertex a or b region.
//b2Settings.b2Assert(sn > 0.0 || tn > 0.0);
//b2Settings.b2Assert(sd > 0.0 || un > 0.0);
//float32 n = b2Cross(ab, ac);
const n: number = abX * acY - abY * acX;
// Should not be in edge ab region.
//float32 vc = n * b2Cross(a, b);
const vc: number = n * (aX * bY - aY * bX);
//b2Settings.b2Assert(vc > 0.0 || sn > 0.0 || sd > 0.0);
let lambda: number;
// In edge bc region?
//float32 va = n * b2Cross(b, c);
const va: number = n * (bX * cY - bY * cX);
if (va <= 0.0 && un >= 0.0 && ud >= 0.0 && (un + ud) > 0.0) {
//b2Settings.b2Assert(un + ud > 0.0);
//float32 lambda = un / (un + ud);
lambda = un / (un + ud);
//*x1 = p1s[1] + lambda * (p1s[2] - p1s[1]);
x1.x = p1s_1.x + lambda * (p1s_2.x - p1s_1.x);
x1.y = p1s_1.y + lambda * (p1s_2.y - p1s_1.y);
//*x2 = p2s[1] + lambda * (p2s[2] - p2s[1]);
x2.x = p2s_1.x + lambda * (p2s_2.x - p2s_1.x);
x2.y = p2s_1.y + lambda * (p2s_2.y - p2s_1.y);
//p1s[0] = p1s[2];
p1s_0.SetV(p1s_2);
//p2s[0] = p2s[2];
p2s_0.SetV(p2s_2);
//points[0] = points[2];
points_0.SetV(points_2);
return 2;
}
// In edge ac region?
//float32 vb = n * b2Cross(c, a);
const vb: number = n * (cX * aY - cY * aX);
if (vb <= 0.0 && tn >= 0.0 && td >= 0.0 && (tn + td) > 0.0) {
//b2Settings.b2Assert(tn + td > 0.0);
//float32 lambda = tn / (tn + td);
lambda = tn / (tn + td);
//*x1 = p1s[0] + lambda * (p1s[2] - p1s[0]);
x1.x = p1s_0.x + lambda * (p1s_2.x - p1s_0.x);
x1.y = p1s_0.y + lambda * (p1s_2.y - p1s_0.y);
//*x2 = p2s[0] + lambda * (p2s[2] - p2s[0]);
x2.x = p2s_0.x + lambda * (p2s_2.x - p2s_0.x);
x2.y = p2s_0.y + lambda * (p2s_2.y - p2s_0.y);
//p1s[1] = p1s[2];
p1s_1.SetV(p1s_2);
//p2s[1] = p2s[2];
p2s_1.SetV(p2s_2);
//points[1] = points[2];
points_1.SetV(points_2);
return 2;
}
// Inside the triangle, compute barycentric coordinates
//float32 denom = va + vb + vc;
let denom: number = va + vb + vc;
//b2Settings.b2Assert(denom > 0.0);
denom = 1.0 / denom;
//float32 u = va * denom;
const u: number = va * denom;
//float32 v = vb * denom;
const v: number = vb * denom;
//float32 w = 1.0f - u - v;
const w: number = 1.0 - u - v;
//*x1 = u * p1s[0] + v * p1s[1] + w * p1s[2];
x1.x = u * p1s_0.x + v * p1s_1.x + w * p1s_2.x;
x1.y = u * p1s_0.y + v * p1s_1.y + w * p1s_2.y;
//*x2 = u * p2s[0] + v * p2s[1] + w * p2s[2];
x2.x = u * p2s_0.x + v * p2s_1.x + w * p2s_2.x;
x2.y = u * p2s_0.y + v * p2s_1.y + w * p2s_2.y;
return 3;
}
public static InPoints(w: b2Vec2, points: b2Vec2[], pointCount: number /** int */): boolean {
const k_tolerance: number = 100.0 * Number.MIN_VALUE;
for (let i: number /** int */ = 0; i < pointCount; ++i) {
const points_i: b2Vec2 = points[i];
//b2Vec2 d = b2Abs(w - points[i]);
const dX: number = Math.abs(w.x - points_i.x);
const dY: number = Math.abs(w.y - points_i.y);
//b2Vec2 m = b2Max(b2Abs(w), b2Abs(points[i]));
const mX: number = Math.max(Math.abs(w.x), Math.abs(points_i.x));
const mY: number = Math.max(Math.abs(w.y), Math.abs(points_i.y));
if (dX < k_tolerance * (mX + 1.0) &&
dY < k_tolerance * (mY + 1.0)) {
return true;
}
}
return false;
}
//
private static s_p1s: b2Vec2[] = [new b2Vec2(), new b2Vec2(), new b2Vec2()];
private static s_p2s: b2Vec2[] = [new b2Vec2(), new b2Vec2(), new b2Vec2()];
private static s_points: b2Vec2[] = [new b2Vec2(), new b2Vec2(), new b2Vec2()];
//
public static DistanceGeneric(x1: b2Vec2, x2: b2Vec2,
shape1: any, xf1: b2XForm,
shape2: any, xf2: b2XForm): number {
let tVec: b2Vec2;
//b2Vec2 p1s[3], p2s[3];
const p1s: b2Vec2[] = b2Distance.s_p1s;
const p2s: b2Vec2[] = b2Distance.s_p2s;
//b2Vec2 points[3];
const points: b2Vec2[] = b2Distance.s_points;
//int32 pointCount = 0;
let pointCount: number /** int */ = 0;
//*x1 = shape1->GetFirstVertex(xf1);
x1.SetV(shape1.GetFirstVertex(xf1));
//*x2 = shape2->GetFirstVertex(xf2);
x2.SetV(shape2.GetFirstVertex(xf2));
let vSqr: number = 0.0;
const maxIterations: number /** int */ = 20;
for (let iter: number /** int */ = 0; iter < maxIterations; ++iter) {
//b2Vec2 v = *x2 - *x1;
let vX: number = x2.x - x1.x;
let vY: number = x2.y - x1.y;
//b2Vec2 w1 = shape1->Support(xf1, v);
const w1: b2Vec2 = shape1.Support(xf1, vX, vY);
//b2Vec2 w2 = shape2->Support(xf2, -v);
const w2: b2Vec2 = shape2.Support(xf2, -vX, -vY);
//float32 vSqr = b2Dot(v, v);
vSqr = (vX * vX + vY * vY);
//b2Vec2 w = w2 - w1;
const wX: number = w2.x - w1.x;
const wY: number = w2.y - w1.y;
//float32 vw = b2Dot(v, w);
const vw: number = (vX * wX + vY * wY);
//if (vSqr - b2Dot(v, w) <= 0.01f * vSqr) // or w in points
if (vSqr - (vX * wX + vY * wY) <= 0.01 * vSqr) // or w in points
{
if (pointCount == 0) {
//*x1 = w1;
x1.SetV(w1);
//*x2 = w2;
x2.SetV(w2);
}
b2Distance.g_GJK_Iterations = iter;
return Math.sqrt(vSqr);
}
switch (pointCount) {
case 0:
//p1s[0] = w1;
tVec = p1s[0];
tVec.SetV(w1);
//p2s[0] = w2;
tVec = p2s[0];
tVec.SetV(w2);
//points[0] = w;
tVec = points[0];
tVec.x = wX;
tVec.y = wY;
//*x1 = p1s[0];
x1.SetV(p1s[0]);
//*x2 = p2s[0];
x2.SetV(p2s[0]);
++pointCount;
break;
case 1:
//p1s[1] = w1;
tVec = p1s[1];
tVec.SetV(w1);
//p2s[1] = w2;
tVec = p2s[1];
tVec.SetV(w2);
//points[1] = w;
tVec = points[1];
tVec.x = wX;
tVec.y = wY;
pointCount = b2Distance.ProcessTwo(x1, x2, p1s, p2s, points);
break;
case 2:
//p1s[2] = w1;
tVec = p1s[2];
tVec.SetV(w1);
//p2s[2] = w2;
tVec = p2s[2];
tVec.SetV(w2);
//points[2] = w;
tVec = points[2];
tVec.x = wX;
tVec.y = wY;
pointCount = b2Distance.ProcessThree(x1, x2, p1s, p2s, points);
break;
}
// If we have three points, then the origin is in the corresponding triangle.
if (pointCount == 3) {
b2Distance.g_GJK_Iterations = iter;
return 0.0;
}
//float32 maxSqr = -FLT_MAX;
let maxSqr: number = -Number.MAX_VALUE;
for (let i: number /** int */ = 0; i < pointCount; ++i) {
//maxSqr = b2Math.b2Max(maxSqr, b2Dot(points[i], points[i]));
tVec = points[i];
maxSqr = b2Math.b2Max(maxSqr, (tVec.x * tVec.x + tVec.y * tVec.y));
}
if (pointCount == 3 || vSqr <= 100.0 * Number.MIN_VALUE * maxSqr) {
b2Distance.g_GJK_Iterations = iter;
//v = *x2 - *x1;
vX = x2.x - x1.x;
vY = x2.y - x1.y;
//vSqr = b2Dot(v, v);
vSqr = (vX * vX + vY * vY);
return Math.sqrt(vSqr);
}
}
b2Distance.g_GJK_Iterations = maxIterations;
return Math.sqrt(vSqr);
}
public static DistanceCC(
x1: b2Vec2, x2: b2Vec2,
circle1: b2CircleShape, xf1: b2XForm,
circle2: b2CircleShape, xf2: b2XForm): number {
let tMat: b2Mat22;
let tVec: b2Vec2;
//b2Vec2 p1 = b2Mul(xf1, circle1->m_localPosition);
tMat = xf1.R;
tVec = circle1.m_localPosition;
const p1X: number = xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
const p1Y: number = xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
//b2Vec2 p2 = b2Mul(xf2, circle2->m_localPosition);
tMat = xf2.R;
tVec = circle2.m_localPosition;
const p2X: number = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
const p2Y: number = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
//b2Vec2 d = p2 - p1;
let dX: number = p2X - p1X;
let dY: number = p2Y - p1Y;
const dSqr: number = (dX * dX + dY * dY);
const r1: number = circle1.m_radius - b2Settings.b2_toiSlop;
const r2: number = circle2.m_radius - b2Settings.b2_toiSlop;
const r: number = r1 + r2;
if (dSqr > r * r) {
//var dLen:number = d.Normalize();
var dLen: number = Math.sqrt(dX * dX + dY * dY);
dX /= dLen;
dY /= dLen;
const distance: number = dLen - r;
//*x1 = p1 + r1 * d;
x1.x = p1X + r1 * dX;
x1.y = p1Y + r1 * dY;
//*x2 = p2 - r2 * d;
x2.x = p2X - r2 * dX;
x2.y = p2Y - r2 * dY;
return distance;
} else if (dSqr > Number.MIN_VALUE * Number.MIN_VALUE) {
//d.Normalize();
dLen = Math.sqrt(dX * dX + dY * dY);
dX /= dLen;
dY /= dLen;
//*x1 = p1 + r1 * d;
x1.x = p1X + r1 * dX;
x1.y = p1Y + r1 * dY;
//*x2 = *x1;
x2.x = x1.x;
x2.y = x1.y;
return 0.0;
}
//*x1 = p1;
x1.x = p1X;
x1.y = p1Y;
//*x2 = *x1;
x2.x = x1.x;
x2.y = x1.y;
return 0.0;
}
public static DistanceSeC(
x1: b2Vec2, x2:b2Vec2,
edge:b2StaticEdgeShape, xf1:b2XForm,
circle:b2CircleShape, xf2:b2XForm) : number
{
var dX:number;
var dY:number;
var dSqr:number;
var dLen: number;
var r:number = circle.m_radius - b2Settings.b2_toiSlop;
var tPoint:b2ManifoldPoint;
var tMat:b2Mat22 = xf2.R;
var tVec:b2Vec2 = circle.m_localPosition;
var circleX:number = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
var circleY:number = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
tVec = edge.m_direction;
var dirDist: number = (circleX - edge.m_coreV1.x) * tVec.x + (circleY - edge.m_coreV1.y) * tVec.y;
if (dirDist <= 0) {
x1.SetV(edge.m_coreV1);
dX = circleX - edge.m_coreV1.x;
dY = circleY - edge.m_coreV1.y;
dSqr = dX*dX + dY*dY;
if (dSqr > r*r) {
dLen = Math.sqrt(dSqr);
dX /= dLen;
dY /= dLen;
x2.x = circleX - dX * r;
x2.y = circleY - dY * r;
return dLen - r;
} else {
x2.SetV(edge.m_coreV1);
return 0.0;
}
} else if (dirDist >= edge.m_length) {
x1.SetV(edge.m_coreV2);
dX = circleX - edge.m_coreV2.x;
dY = circleY - edge.m_coreV2.y;
dSqr = dX*dX + dY*dY;
if (dSqr > r*r) {
dLen = Math.sqrt(dSqr);
dX /= dLen;
dY /= dLen;
x2.x = circleX - dX * r;
x2.y = circleY - dY * r;
return dLen - r;
} else {
x2.SetV(edge.m_coreV2);
return 0.0;
}
} else {
x1.x = edge.m_coreV1.x + tVec.x * dirDist;
x1.y = edge.m_coreV1.y + tVec.y * dirDist;
tVec = edge.m_normal;
dLen = (circleX - edge.m_coreV1.x) * tVec.x +
(circleY - edge.m_coreV1.y) * tVec.y;
if (dLen < 0.0) {
if (dLen < -r) {
x2.x = circleX + r * tVec.x;
x2.y = circleY + r * tVec.y;
return -dLen - r;
} else {
x2.SetV(x1);
return 0.0;
}
} else {
if (dLen > r) {
x2.x = circleX - r * tVec.x;
x2.y = circleY - r * tVec.y;
return dLen - r;
} else {
x2.SetV(x1);
return 0.0;
}
}
}
}
// GJK is more robust with polygon-vs-point than polygon-vs-circle.
// So we convert polygon-vs-circle to polygon-vs-point.
private static gPoint: b2Point = new b2Point();
///
public static DistancePC(
x1: b2Vec2, x2: b2Vec2,
polygon: b2PolygonShape, xf1: b2XForm,
circle: b2CircleShape, xf2: b2XForm): number {
let tMat: b2Mat22;
let tVec: b2Vec2;
const point: b2Point = b2Distance.gPoint;
//point.p = b2Mul(xf2, circle->m_localPosition);
tVec = circle.m_localPosition;
tMat = xf2.R;
point.p.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
point.p.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
// Create variation of function to replace template
let distance: number = b2Distance.DistanceGeneric(x1, x2, polygon, xf1, point, b2Math.b2XForm_identity);
const r: number = circle.m_radius - b2Settings.b2_toiSlop;
if (distance > r) {
distance -= r;
//b2Vec2 d = *x2 - *x1;
let dX: number = x2.x - x1.x;
let dY: number = x2.y - x1.y;
//d.Normalize();
const dLen: number = Math.sqrt(dX * dX + dY * dY);
dX /= dLen;
dY /= dLen;
//*x2 -= r * d;
x2.x -= r * dX;
x2.y -= r * dY;
} else {
distance = 0.0;
//*x2 = *x1;
x2.x = x1.x;
x2.y = x1.y;
}
return distance;
}
public static DistanceCcaC(
x1:b2Vec2, x2:b2Vec2,
polygon:b2ConcaveArcShape, xf1:b2XForm,
circle:b2CircleShape, xf2:b2XForm) : number
{
var tMat:b2Mat22;
var tVec:b2Vec2;
var point:b2Point = b2Distance.gPoint;
//point.p = b2Mul(xf2, circle->m_localPosition);
tVec = circle.m_localPosition;
tMat = xf2.R;
point.p.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
point.p.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
// Create variation of function to replace template
var distance:number = b2Distance.DistanceGeneric(x1, x2, polygon, xf1, point, b2Math.b2XForm_identity);
var r:number = circle.m_radius - b2Settings.b2_toiSlop;
//Check if x1 is along the first edge of the arc, in which case DistanceGeneric will be wrong
/*
//Alternate calculation of n
var x1l:b2Vec2 = b2Math.b2MulXT(xf1,x1);
x1l.x -= polygon.m_coreVertices[0].x;
x1l.y -= polygon.m_coreVertices[0].y;
tVec = polygon.m_normals[0];
var n:number = x1l.x * tVec.x + x1l.y * tVec.y;*/
var vx0:b2Vec2 = b2Math.b2MulX(xf1,polygon.m_coreVertices[0]);
var normal:b2Vec2 = b2Math.b2MulMV(xf1.R,polygon.m_normals[0]);
var n:number = (x1.x-vx0.x) * normal.x + (x1.y-vx0.y) * normal.y;
if(n >= 0){
//The center is closest to the arc of all the edges, so do appropriate distance calcs
var arcCenter:b2Vec2 = b2Math.b2MulX(xf1,polygon.m_arcCenter);
//See similar code in b2ConcaveArcAndCircleContact
var c2X: number = point.p.x - arcCenter.x;
var c2Y: number = point.p.y - arcCenter.y;
var norm:number = -normal.y*c2X+normal.x*c2Y;
if (c2X*normal.x+c2Y*normal.y>0)
{
if(norm < 0){
//Vertex 0
tVec = vx0;
}else{
//Vertex 1
tVec = b2Math.b2MulX(xf1,polygon.m_coreVertices[1]);
}
}else{
if (norm <= -polygon.m_norm){
//Vertex 0
tVec = vx0;
}else if (norm >= polygon.m_norm){
//Vertex 1
tVec = b2Math.b2MulX(xf1,polygon.m_coreVertices[1]);
}else{
//Nearest point on arc
var c: number = Math.sqrt(c2X*c2X+c2Y*c2Y);
//trace([c2X,c2Y]);
//trace([polygon.m_radius+b2Settings.b2_toiSlop,r,c]);
distance = (polygon.m_radius+b2Settings.b2_toiSlop*2)-r-c;
c2X /= c;
c2Y /= c;
if(distance<0) distance = 0;
x1.x = arcCenter.x + c2X * (polygon.m_radius+b2Settings.b2_toiSlop);
x1.y = arcCenter.y + c2Y * (polygon.m_radius+b2Settings.b2_toiSlop);
x2.x += c2X * r;
x2.y += c2Y * r;
//trace(distance);
return distance;
}
}
x1.SetV(tVec);
tVec.x -= point.p.x;
tVec.y -= point.p.y;
distance = tVec.Normalize() - r;
if(distance > 0){
x2.x += r * tVec.x;
x2.y += r * tVec.y;
return distance;
}else{
x2.SetV(x1);
return 0;
}
}
if (distance > r)
{
distance -= r;
//b2Vec2 d = *x2 - *x1;
var dX:number = x2.x - x1.x;
var dY:number = x2.y - x1.y;
//d.Normalize();
var dLen:number = Math.sqrt(dX*dX + dY*dY);
dX /= dLen;
dY /= dLen;
//*x2 -= r * d
x2.x -= r * dX;
x2.y -= r * dY;
}
else
{
distance = 0.0;
//*x2 = *x1;
x2.x = x1.x;
x2.y = x1.y;
}
return distance;
}
public static t:number=-1;
public static DistancePCca(
x1:b2Vec2, x2:b2Vec2,
polygon:b2PolygonShape, xf1:b2XForm,
arc:b2ConcaveArcShape, xf2:b2XForm) : number
{
let t=-1;
var gd:number = b2Distance.DistanceGeneric(x1,x2,polygon,xf1,arc,xf2);
var vx0:b2Vec2 = b2Math.b2MulX(xf2,arc.m_coreVertices[0]);
var normal:b2Vec2 = b2Math.b2MulMV(xf2.R,arc.m_normals[0]);
var n:number = (x2.x-vx0.x) * normal.x + (x2.y-vx0.y) * normal.y;
//n should be compared to zero, but apprently the rounding errors are pretty bad
if(n < -b2Settings.b2_linearSlop/4 && gd>0){
//The closest point on the bounding poly of the arc shape is not on the first edge
//So it is correct
t=0;
return gd;
}
var vx1:b2Vec2 = b2Math.b2MulX(xf2,arc.m_coreVertices[1]);
//Check if x2==vx0 or x2==vx1. This would be a lot easier if there was some results caching going on
var tVec:b2Vec2 = new b2Vec2();
var tolerance: number = b2Settings.b2_linearSlop * b2Settings.b2_linearSlop;
tVec.x = vx0.x - x2.x;
tVec.y = vx0.y - x2.y;
if(tVec.x*tVec.x+tVec.y*tVec.y< tolerance){
t=1;
return gd;
}
tVec.x = vx1.x - x2.x;
tVec.y = vx1.y - x2.y;
if(tVec.x*tVec.x+tVec.y*tVec.y< tolerance){
t=2;
return gd;
}
//Otherwise, calculate the nearest point on the arc to the poly
//AFAIK, there is little you can do more than brute force
//Perhaps start with a sensible vertex, so that others are more likely to get discarded earlier
var localCenter:b2Vec2 = b2Math.b2MulXT(xf1, b2Math.b2MulX(xf2, arc.m_arcCenter));
var localNorm:b2Vec2 = b2Math.b2MulTMV(xf1.R, normal)
var maxDist2:number = -1;//Square of the distance of the furthest (valid) vertex (so far) from localCenter; or equivalent
var bestVx:number = -1;
var separation: number = Number.MAX_VALUE;
var dist2:number;
var dist:number;
for(var i:number = 0;i<polygon.m_vertexCount;i++){
tVec.x = polygon.m_coreVertices[i].x - localCenter.x;
tVec.y = polygon.m_coreVertices[i].y - localCenter.y;
var norm: number = tVec.x*localNorm.y-tVec.y*localNorm.x;
dist2 = tVec.x*tVec.x+tVec.y*tVec.y;
if( norm*norm<arc.m_norm*arc.m_norm*dist2
&& tVec.x*localNorm.x+tVec.y*localNorm.y<0 ){
//Near the curve of the arc
if(dist2>maxDist2){
maxDist2 = dist2;
bestVx = i;
dist = Math.sqrt(dist2);
separation = arc.m_radius+b2Settings.b2_toiSlop-dist;
if(separation<0) separation=0;
x1.SetV(b2Math.b2MulX(xf1,polygon.m_coreVertices[i]))
tVec.x *= (arc.m_radius+b2Settings.b2_toiSlop)/dist;
tVec.y *= (arc.m_radius+b2Settings.b2_toiSlop)/dist;
tVec.x += localCenter.x;
tVec.y += localCenter.y;
x2.SetV(b2Math.b2MulX(xf1,tVec));
t=3;
}
}
}
var sx1:b2Vec2 = new b2Vec2();
var sx2:b2Vec2 = new b2Vec2();
var point:b2Point = b2Distance.gPoint;
point.p.SetV(vx0);
var anotherDistance:number = b2Distance.DistanceGeneric(sx1, sx2, polygon, xf1, point, b2Math.b2XForm_identity);
if(anotherDistance<separation){
t=4;
separation=anotherDistance;
x1.SetV(sx1);
x2.SetV(sx2);
}
point.p.SetV(vx1);
anotherDistance = b2Distance.DistanceGeneric(sx1, sx2, polygon, xf1, point, b2Math.b2XForm_identity);
if(anotherDistance<separation){
t=5;
separation=anotherDistance;
x1.SetV(sx1);
x2.SetV(sx2);
}
//As we have shrank the arc from it's bounding poly,
//It should never be closer to the polygon than it's bounding poly
//b2Settings.b2Assert(separation>gd);
return separation;
}
public static Distance(x1: b2Vec2, x2: b2Vec2,
shape1: b2Shape, xf1: b2XForm,
shape2: b2Shape, xf2: b2XForm): number {
//b2ShapeType type1 = shape1->GetType();
const type1: number /** int */ = shape1.m_type;
//b2ShapeType type2 = shape2->GetType();
const type2: number /** int */ = shape2.m_type;
var register: b2DistanceRegister = b2Distance.s_registers[type1 + type2 * b2Shape.e_shapeTypeCount];
if (register != null) {
if (register.primary) {
return register.fcn(x1, x2, shape1, xf1, shape2, xf2);
} else {
return register.fcn(x2, x1, shape2, xf2, shape1, xf1);
}
}
return 0.0;
}
public static g_GJK_Iterations: number /** int */ = 0;
public static s_registers: any[];
public static s_initialized: boolean = false;
}