UNPKG

@awayfl/awayfl-player

Version:

Flash Player emulator for executing SWF files (published for FP versions 6 and up) in javascript

170 lines (169 loc) 6.62 kB
import { b2SimplexCache } from './b2SimplexCache'; import { b2DistanceInput } from './b2DistanceInput'; import { b2Transform, b2Math } from '../Common/Math'; import { b2DistanceOutput } from './b2DistanceOutput'; import { b2Settings } from '../Common/b2Settings'; import { b2Distance } from './b2Distance'; import { b2SeparationFunction } from './b2SeparationFunction'; /** * @private */ var b2TimeOfImpact = /** @class */ (function () { function b2TimeOfImpact() { } b2TimeOfImpact.TimeOfImpact = function (input) { ++this.b2_toiCalls; var proxyA = input.proxyA; var proxyB = input.proxyB; var sweepA = input.sweepA; var sweepB = input.sweepB; b2Settings.b2Assert(sweepA.t0 == sweepB.t0); b2Settings.b2Assert(1.0 - sweepA.t0 > Number.MIN_VALUE); var radius = proxyA.m_radius + proxyB.m_radius; var tolerance = input.tolerance; var alpha = 0.0; var k_maxIterations /** int */ = 1000; //TODO_ERIN b2Settings var iter /** int */ = 0; var target = 0.0; // Prepare input for distance query. this.s_cache.count = 0; this.s_distanceInput.useRadii = false; for (;;) { sweepA.GetTransform(this.s_xfA, alpha); sweepB.GetTransform(this.s_xfB, alpha); // Get the distance between shapes this.s_distanceInput.proxyA = proxyA; this.s_distanceInput.proxyB = proxyB; this.s_distanceInput.transformA = this.s_xfA; this.s_distanceInput.transformB = this.s_xfB; b2Distance.Distance(this.s_distanceOutput, this.s_cache, this.s_distanceInput); if (this.s_distanceOutput.distance <= 0.0) { alpha = 1.0; break; } this.s_fcn.Initialize(this.s_cache, proxyA, this.s_xfA, proxyB, this.s_xfB); var separation = this.s_fcn.Evaluate(this.s_xfA, this.s_xfB); if (separation <= 0.0) { alpha = 1.0; break; } if (iter == 0) { // Compute a reasonable target distance to give some breathing room // for conservative advancement. We take advantage of the shape radii // to create additional clearance if (separation > radius) { target = b2Math.Max(radius - tolerance, 0.75 * radius); } else { target = b2Math.Max(separation - tolerance, 0.02 * radius); } } if (separation - target < 0.5 * tolerance) { if (iter == 0) { alpha = 1.0; break; } break; } //#if 0 // Dump the curve seen by the root finder //{ //const N:number /** int */ = 100; //var dx:number = 1.0 / N; //var xs:Vector.<Number> = new Array(N + 1); //var fs:Vector.<Number> = new Array(N + 1); // //var x:number = 0.0; //for (var i:number /** int */ = 0; i <= N; i++) //{ //sweepA.GetTransform(xfA, x); //sweepB.GetTransform(xfB, x); //var f:number = fcn.Evaluate(xfA, xfB) - target; // //trace(x, f); //xs[i] = x; //fx[i] = f' // //x += dx; //} //} //#endif // Compute 1D root of f(x) - target = 0 var newAlpha = alpha; { var x1 = alpha; var x2 = 1.0; var f1 = separation; sweepA.GetTransform(this.s_xfA, x2); sweepB.GetTransform(this.s_xfB, x2); var f2 = this.s_fcn.Evaluate(this.s_xfA, this.s_xfB); // If intervals don't overlap at t2, then we are done if (f2 >= target) { alpha = 1.0; break; } // Determine when intervals intersect var rootIterCount /** int */ = 0; for (;;) { // Use a mis of the secand rule and bisection var x; if (rootIterCount & 1) { // Secant rule to improve convergence x = x1 + (target - f1) * (x2 - x1) / (f2 - f1); } else { // Bisection to guarantee progress x = 0.5 * (x1 + x2); } sweepA.GetTransform(this.s_xfA, x); sweepB.GetTransform(this.s_xfB, x); var f = this.s_fcn.Evaluate(this.s_xfA, this.s_xfB); if (b2Math.Abs(f - target) < 0.025 * tolerance) { newAlpha = x; break; } // Ensure we continue to bracket the root if (f > target) { x1 = x; f1 = f; } else { x2 = x; f2 = f; } ++rootIterCount; ++this.b2_toiRootIters; if (rootIterCount == 50) { break; } } this.b2_toiMaxRootIters = b2Math.Max(this.b2_toiMaxRootIters, rootIterCount); } // Ensure significant advancement if (newAlpha < (1.0 + 100.0 * Number.MIN_VALUE) * alpha) { break; } alpha = newAlpha; iter++; ++this.b2_toiIters; if (iter == k_maxIterations) { break; } } this.b2_toiMaxIters = b2Math.Max(this.b2_toiMaxIters, iter); return alpha; }; b2TimeOfImpact.b2_toiCalls = 0; b2TimeOfImpact.b2_toiIters = 0; b2TimeOfImpact.b2_toiMaxIters = 0; b2TimeOfImpact.b2_toiRootIters = 0; b2TimeOfImpact.b2_toiMaxRootIters = 0; b2TimeOfImpact.s_cache = new b2SimplexCache(); b2TimeOfImpact.s_distanceInput = new b2DistanceInput(); b2TimeOfImpact.s_xfA = new b2Transform(); b2TimeOfImpact.s_xfB = new b2Transform(); b2TimeOfImpact.s_fcn = new b2SeparationFunction(); b2TimeOfImpact.s_distanceOutput = new b2DistanceOutput(); return b2TimeOfImpact; }()); export { b2TimeOfImpact };