@awayfl/awayfl-player
Version:
Flash Player emulator for executing SWF files (published for FP versions 6 and up) in javascript
283 lines (282 loc) • 9.96 kB
JavaScript
import { b2Vec2, b2Math } from '../Common/Math';
import { b2Settings } from '../Common/b2Settings';
import { b2SimplexVertex } from './b2SimplexVertex';
var b2Simplex = /** @class */ (function () {
function b2Simplex() {
this.__fast__ = true;
this.m_v1 = new b2SimplexVertex();
this.m_v2 = new b2SimplexVertex();
this.m_v3 = new b2SimplexVertex();
this.m_vertices = new Array(3);
this.m_vertices[0] = this.m_v1;
this.m_vertices[1] = this.m_v2;
this.m_vertices[2] = this.m_v3;
}
b2Simplex.prototype.ReadCache = function (cache, proxyA, transformA, proxyB, transformB) {
b2Settings.b2Assert(0 <= cache.count && cache.count <= 3);
var wALocal;
var wBLocal;
// Copy data from cache.
this.m_count = cache.count;
var vertices = this.m_vertices;
for (var i /** int */ = 0; i < this.m_count; i++) {
var v = vertices[i];
v.indexA = cache.indexA[i];
v.indexB = cache.indexB[i];
wALocal = proxyA.GetVertex(v.indexA);
wBLocal = proxyB.GetVertex(v.indexB);
v.wA = b2Math.MulX(transformA, wALocal);
v.wB = b2Math.MulX(transformB, wBLocal);
v.w = b2Math.SubtractVV(v.wB, v.wA);
v.a = 0;
}
// Compute the new simplex metric, if it substantially different than
// old metric then flush the simplex
if (this.m_count > 1) {
var metric1 = cache.metric;
var metric2 = this.GetMetric();
if (metric2 < .5 * metric1 || 2.0 * metric1 < metric2 || metric2 < Number.MIN_VALUE) {
// Reset the simplex
this.m_count = 0;
}
}
// If the cache is empty or invalid
if (this.m_count == 0) {
v = vertices[0];
v.indexA = 0;
v.indexB = 0;
wALocal = proxyA.GetVertex(0);
wBLocal = proxyB.GetVertex(0);
v.wA = b2Math.MulX(transformA, wALocal);
v.wB = b2Math.MulX(transformB, wBLocal);
v.w = b2Math.SubtractVV(v.wB, v.wA);
this.m_count = 1;
}
};
b2Simplex.prototype.WriteCache = function (cache) {
cache.metric = this.GetMetric();
cache.count = this.m_count >>> 0;
var vertices = this.m_vertices;
for (var i /** int */ = 0; i < this.m_count; i++) {
cache.indexA[i] = vertices[i].indexA;
cache.indexB[i] = vertices[i].indexB;
}
};
b2Simplex.prototype.GetSearchDirection = function () {
switch (this.m_count) {
case 1:
return this.m_v1.w.GetNegative();
case 2:
{
var e12 = b2Math.SubtractVV(this.m_v2.w, this.m_v1.w);
var sgn = b2Math.CrossVV(e12, this.m_v1.w.GetNegative());
if (sgn > 0.0) {
// Origin is left of e12.
return b2Math.CrossFV(1.0, e12);
}
else {
// Origin is right of e12.
return b2Math.CrossVF(e12, 1.0);
}
}
default:
b2Settings.b2Assert(false);
return new b2Vec2();
}
};
b2Simplex.prototype.GetClosestPoint = function () {
switch (this.m_count) {
case 0:
b2Settings.b2Assert(false);
return new b2Vec2();
case 1:
return this.m_v1.w;
case 2:
return new b2Vec2(this.m_v1.a * this.m_v1.w.x + this.m_v2.a * this.m_v2.w.x, this.m_v1.a * this.m_v1.w.y + this.m_v2.a * this.m_v2.w.y);
default:
b2Settings.b2Assert(false);
return new b2Vec2();
}
};
b2Simplex.prototype.GetWitnessPoints = function (pA, pB) {
switch (this.m_count) {
case 0:
b2Settings.b2Assert(false);
break;
case 1:
pA.SetV(this.m_v1.wA);
pB.SetV(this.m_v1.wB);
break;
case 2:
pA.x = this.m_v1.a * this.m_v1.wA.x + this.m_v2.a * this.m_v2.wA.x;
pA.y = this.m_v1.a * this.m_v1.wA.y + this.m_v2.a * this.m_v2.wA.y;
pB.x = this.m_v1.a * this.m_v1.wB.x + this.m_v2.a * this.m_v2.wB.x;
pB.y = this.m_v1.a * this.m_v1.wB.y + this.m_v2.a * this.m_v2.wB.y;
break;
case 3:
pB.x = pA.x = this.m_v1.a * this.m_v1.wA.x + this.m_v2.a * this.m_v2.wA.x + this.m_v3.a * this.m_v3.wA.x;
pB.y = pA.y = this.m_v1.a * this.m_v1.wA.y + this.m_v2.a * this.m_v2.wA.y + this.m_v3.a * this.m_v3.wA.y;
break;
default:
b2Settings.b2Assert(false);
break;
}
};
b2Simplex.prototype.GetMetric = function () {
switch (this.m_count) {
case 0:
b2Settings.b2Assert(false);
return 0.0;
case 1:
return 0.0;
case 2:
return b2Math.SubtractVV(this.m_v1.w, this.m_v2.w).Length();
case 3:
return b2Math.CrossVV(b2Math.SubtractVV(this.m_v2.w, this.m_v1.w), b2Math.SubtractVV(this.m_v3.w, this.m_v1.w));
default:
b2Settings.b2Assert(false);
return 0.0;
}
};
// Solve a line segment using barycentric coordinates.
//
// p = a1 * w1 + a2 * w2
// a1 + a2 = 1
//
// The vector from the origin to the closest point on the line is
// perpendicular to the line.
// e12 = w2 - w1
// dot(p, e) = 0
// a1 * dot(w1, e) + a2 * dot(w2, e) = 0
//
// 2-by-2 linear system
// [1 1 ][a1] = [1]
// [w1.e12 w2.e12][a2] = [0]
//
// Define
// d12_1 = dot(w2, e12)
// d12_2 = -dot(w1, e12)
// d12 = d12_1 + d12_2
//
// Solution
// a1 = d12_1 / d12
// a2 = d12_2 / d12
b2Simplex.prototype.Solve2 = function () {
var w1 = this.m_v1.w;
var w2 = this.m_v2.w;
var e12 = b2Math.SubtractVV(w2, w1);
// w1 region
var d12_2 = -(w1.x * e12.x + w1.y * e12.y);
if (d12_2 <= 0.0) {
// a2 <= 0, so we clamp it to 0
this.m_v1.a = 1.0;
this.m_count = 1;
return;
}
// w2 region
var d12_1 = (w2.x * e12.x + w2.y * e12.y);
if (d12_1 <= 0.0) {
// a1 <= 0, so we clamp it to 0
this.m_v2.a = 1.0;
this.m_count = 1;
this.m_v1.Set(this.m_v2);
return;
}
// Must be in e12 region.
var inv_d12 = 1.0 / (d12_1 + d12_2);
this.m_v1.a = d12_1 * inv_d12;
this.m_v2.a = d12_2 * inv_d12;
this.m_count = 2;
};
b2Simplex.prototype.Solve3 = function () {
var w1 = this.m_v1.w;
var w2 = this.m_v2.w;
var w3 = this.m_v3.w;
// Edge12
// [1 1 ][a1] = [1]
// [w1.e12 w2.e12][a2] = [0]
// a3 = 0
var e12 = b2Math.SubtractVV(w2, w1);
var w1e12 = b2Math.Dot(w1, e12);
var w2e12 = b2Math.Dot(w2, e12);
var d12_1 = w2e12;
var d12_2 = -w1e12;
// Edge13
// [1 1 ][a1] = [1]
// [w1.e13 w3.e13][a3] = [0]
// a2 = 0
var e13 = b2Math.SubtractVV(w3, w1);
var w1e13 = b2Math.Dot(w1, e13);
var w3e13 = b2Math.Dot(w3, e13);
var d13_1 = w3e13;
var d13_2 = -w1e13;
// Edge23
// [1 1 ][a2] = [1]
// [w2.e23 w3.e23][a3] = [0]
// a1 = 0
var e23 = b2Math.SubtractVV(w3, w2);
var w2e23 = b2Math.Dot(w2, e23);
var w3e23 = b2Math.Dot(w3, e23);
var d23_1 = w3e23;
var d23_2 = -w2e23;
// Triangle123
var n123 = b2Math.CrossVV(e12, e13);
var d123_1 = n123 * b2Math.CrossVV(w2, w3);
var d123_2 = n123 * b2Math.CrossVV(w3, w1);
var d123_3 = n123 * b2Math.CrossVV(w1, w2);
// w1 region
if (d12_2 <= 0.0 && d13_2 <= 0.0) {
this.m_v1.a = 1.0;
this.m_count = 1;
return;
}
// e12
if (d12_1 > 0.0 && d12_2 > 0.0 && d123_3 <= 0.0) {
var inv_d12 = 1.0 / (d12_1 + d12_2);
this.m_v1.a = d12_1 * inv_d12;
this.m_v2.a = d12_2 * inv_d12;
this.m_count = 2;
return;
}
// e13
if (d13_1 > 0.0 && d13_2 > 0.0 && d123_2 <= 0.0) {
var inv_d13 = 1.0 / (d13_1 + d13_2);
this.m_v1.a = d13_1 * inv_d13;
this.m_v3.a = d13_2 * inv_d13;
this.m_count = 2;
this.m_v2.Set(this.m_v3);
return;
}
// w2 region
if (d12_1 <= 0.0 && d23_2 <= 0.0) {
this.m_v2.a = 1.0;
this.m_count = 1;
this.m_v1.Set(this.m_v2);
return;
}
// w3 region
if (d13_1 <= 0.0 && d23_1 <= 0.0) {
this.m_v3.a = 1.0;
this.m_count = 1;
this.m_v1.Set(this.m_v3);
return;
}
// e23
if (d23_1 > 0.0 && d23_2 > 0.0 && d123_1 <= 0.0) {
var inv_d23 = 1.0 / (d23_1 + d23_2);
this.m_v2.a = d23_1 * inv_d23;
this.m_v3.a = d23_2 * inv_d23;
this.m_count = 2;
this.m_v1.Set(this.m_v3);
return;
}
// Must be in triangle123
var inv_d123 = 1.0 / (d123_1 + d123_2 + d123_3);
this.m_v1.a = d123_1 * inv_d123;
this.m_v2.a = d123_2 * inv_d123;
this.m_v3.a = d123_3 * inv_d123;
this.m_count = 3;
};
return b2Simplex;
}());
export { b2Simplex };