Distance class
class Distance { int calls; int iters; int maxIters; /** Pool variables for use in distance calculation. */ Simplex simplex; List<int> saveA; List<int> saveB; vec2 closestPoint; vec2 searchDirection; vec2 temp; vec2 normal; /** * Construct a new Distance object. For internal use only. Don't directly * invoke. */ Distance._construct() : simplex = new Simplex(), saveA = new List<int>(3), saveB = new List<int>(3), closestPoint = new vec2.zero(), searchDirection = new vec2.zero(), temp = new vec2.zero(), normal = new vec2.zero(), calls = 0, iters = 0, maxIters = 20 { } /** * Compute the closest points between two shapes. Supports any combination of: * CircleShape and PolygonShape. The simplex cache is input/output. * On the first call set SimplexCache.count to zero. */ void computeDistance(DistanceOutput output, SimplexCache cache, DistanceInput input) { calls++; final DistanceProxy proxyA = input.proxyA; final DistanceProxy proxyB = input.proxyB; Transform transformA = input.transformA; Transform transformB = input.transformB; // Initialize the simplex. simplex.readCache(cache, proxyA, transformA, proxyB, transformB); // Get simplex vertices as an array. List<SimplexVertex> vertices = simplex.vertices; // These store the vertices of the last simplex so that we // can check for duplicates and prevent cycling. // (pooled above) int saveCount = 0; simplex.getClosestPoint(closestPoint); num distanceSqr1 = closestPoint.length2; num distanceSqr2 = distanceSqr1; // Main iteration loop int iter = 0; while (iter < maxIters) { // Copy simplex so we can identify duplicates. saveCount = simplex.count; for (int i = 0; i < saveCount; i++) { saveA[i] = vertices[i].indexA; saveB[i] = vertices[i].indexB; } switch (simplex.count) { case 1 : break; case 2 : simplex.solve2(); break; case 3 : simplex.solve3(); break; default : assert (false); return; } // If we have 3 points, then the origin is in the corresponding triangle. if (simplex.count == 3) break; // Compute closest point. simplex.getClosestPoint(closestPoint); distanceSqr2 = closestPoint.length2; distanceSqr1 = distanceSqr2; // get search direction; simplex.getSearchDirection(searchDirection); // Ensure the search direction is numerically fit. if (searchDirection.length2 < Settings.EPSILON * Settings.EPSILON) { // The origin is probably contained by a line segment // or triangle. Thus the shapes are overlapped. // We can't return zero here even though there may be overlap. // In case the simplex is a point, segment, or triangle it is difficult // to determine if the origin is contained in the CSO or very close to // it. break; } // Compute a tentative new simplex vertex using support points. SimplexVertex vertex = vertices[simplex.count]; transformA.rotation.transposed().transformed(searchDirection.negate(), temp); vertex.indexA = proxyA.getSupport(temp); Transform.mulToOut(transformA, proxyA.vertices[vertex.indexA], vertex.wA); // Vec2 wBLocal; transformB.rotation.transposed().transformed(searchDirection.negate(), temp); vertex.indexB = proxyB.getSupport(temp); Transform.mulToOut(transformB, proxyB.vertices[vertex.indexB], vertex.wB); vertex.w.copyFrom(vertex.wB).sub(vertex.wA); // Iteration count is equated to the number of support point calls. ++iter; ++iters; // Check for duplicate support points. This is the main termination // criteria. bool duplicate = false; for (int i = 0; i < saveCount; ++i) { if (vertex.indexA == saveA[i] && vertex.indexB == saveB[i]) { duplicate = true; break; } } // If we found a duplicate support point we must exit to avoid cycling. if (duplicate) break; // New vertex is ok and needed. ++simplex.count; } maxIters = math.max(maxIters, iter); // Prepare output. simplex.getWitnessPoints(output.pointA, output.pointB); output._distance = distance(output.pointA, output.pointB); output.iterations = iter; // Cache the simplex. simplex.writeCache(cache); // Apply radii if requested. if (input.useRadii) { num rA = proxyA.radius; num rB = proxyB.radius; if (output._distance > rA + rB && output._distance > Settings.EPSILON) { // Shapes are still no overlapped. // Move the witness points to the outer surface. output._distance -= rA + rB; normal.copyFrom(output.pointB).sub(output.pointA); normal.normalize(); temp.copyFrom(normal).scale(rA); output.pointA.add(temp); temp.copyFrom(normal).scale(rB); output.pointB.sub(temp); } else { // Shapes are overlapped when radii are considered. // Move the witness points to the middle. output.pointA.add(output.pointB).scale(.5); output.pointB.copyFrom(output.pointA); output._distance = 0.0; } } } }
Properties
int calls #
calls
int iters #
iters
int maxIters #
maxIters
List<int> saveA #
saveA
List<int> saveB #
saveB
Methods
void computeDistance(DistanceOutput output, SimplexCache cache, DistanceInput input) #
Compute the closest points between two shapes. Supports any combination of: CircleShape and PolygonShape. The simplex cache is input/output. On the first call set SimplexCache.count to zero.
void computeDistance(DistanceOutput output, SimplexCache cache, DistanceInput input) { calls++; final DistanceProxy proxyA = input.proxyA; final DistanceProxy proxyB = input.proxyB; Transform transformA = input.transformA; Transform transformB = input.transformB; // Initialize the simplex. simplex.readCache(cache, proxyA, transformA, proxyB, transformB); // Get simplex vertices as an array. List<SimplexVertex> vertices = simplex.vertices; // These store the vertices of the last simplex so that we // can check for duplicates and prevent cycling. // (pooled above) int saveCount = 0; simplex.getClosestPoint(closestPoint); num distanceSqr1 = closestPoint.length2; num distanceSqr2 = distanceSqr1; // Main iteration loop int iter = 0; while (iter < maxIters) { // Copy simplex so we can identify duplicates. saveCount = simplex.count; for (int i = 0; i < saveCount; i++) { saveA[i] = vertices[i].indexA; saveB[i] = vertices[i].indexB; } switch (simplex.count) { case 1 : break; case 2 : simplex.solve2(); break; case 3 : simplex.solve3(); break; default : assert (false); return; } // If we have 3 points, then the origin is in the corresponding triangle. if (simplex.count == 3) break; // Compute closest point. simplex.getClosestPoint(closestPoint); distanceSqr2 = closestPoint.length2; distanceSqr1 = distanceSqr2; // get search direction; simplex.getSearchDirection(searchDirection); // Ensure the search direction is numerically fit. if (searchDirection.length2 < Settings.EPSILON * Settings.EPSILON) { // The origin is probably contained by a line segment // or triangle. Thus the shapes are overlapped. // We can't return zero here even though there may be overlap. // In case the simplex is a point, segment, or triangle it is difficult // to determine if the origin is contained in the CSO or very close to // it. break; } // Compute a tentative new simplex vertex using support points. SimplexVertex vertex = vertices[simplex.count]; transformA.rotation.transposed().transformed(searchDirection.negate(), temp); vertex.indexA = proxyA.getSupport(temp); Transform.mulToOut(transformA, proxyA.vertices[vertex.indexA], vertex.wA); // Vec2 wBLocal; transformB.rotation.transposed().transformed(searchDirection.negate(), temp); vertex.indexB = proxyB.getSupport(temp); Transform.mulToOut(transformB, proxyB.vertices[vertex.indexB], vertex.wB); vertex.w.copyFrom(vertex.wB).sub(vertex.wA); // Iteration count is equated to the number of support point calls. ++iter; ++iters; // Check for duplicate support points. This is the main termination // criteria. bool duplicate = false; for (int i = 0; i < saveCount; ++i) { if (vertex.indexA == saveA[i] && vertex.indexB == saveB[i]) { duplicate = true; break; } } // If we found a duplicate support point we must exit to avoid cycling. if (duplicate) break; // New vertex is ok and needed. ++simplex.count; } maxIters = math.max(maxIters, iter); // Prepare output. simplex.getWitnessPoints(output.pointA, output.pointB); output._distance = distance(output.pointA, output.pointB); output.iterations = iter; // Cache the simplex. simplex.writeCache(cache); // Apply radii if requested. if (input.useRadii) { num rA = proxyA.radius; num rB = proxyB.radius; if (output._distance > rA + rB && output._distance > Settings.EPSILON) { // Shapes are still no overlapped. // Move the witness points to the outer surface. output._distance -= rA + rB; normal.copyFrom(output.pointB).sub(output.pointA); normal.normalize(); temp.copyFrom(normal).scale(rA); output.pointA.add(temp); temp.copyFrom(normal).scale(rB); output.pointB.sub(temp); } else { // Shapes are overlapped when radii are considered. // Move the witness points to the middle. output.pointA.add(output.pointB).scale(.5); output.pointB.copyFrom(output.pointA); output._distance = 0.0; } } }