/*
* JBox2D - A Java Port of Erin Catto's Box2D
*
* JBox2D homepage: http://jbox2d.sourceforge.net/
* Box2D homepage: http://www.box2d.org
*
* 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.
*/
package org.jbox2d.collision;
/*
* Copyright (c) 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 org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.EdgeShape;
import org.jbox2d.collision.shapes.PointShape;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.collision.shapes.ShapeType;
import org.jbox2d.common.MathUtils;
import org.jbox2d.common.Settings;
import org.jbox2d.common.Vec2;
import org.jbox2d.common.XForm;
//updated to rev 108->139 of b2cpp
/** Implements the GJK algorithm for computing distance between shapes. */
public final class Distance {
public int g_GJK_Iterations = 0;
// These are used to avoid allocations on hot paths:
private final Vec2 p1s[] = new Vec2[3];
private final Vec2 p2s[] = new Vec2[3];
private final Vec2 points[] = new Vec2[3];
private final Vec2 v = new Vec2();
private final Vec2 vNeg = new Vec2();
private final Vec2 w = new Vec2();
private final Vec2 w1 = new Vec2();
private final Vec2 w2 = new Vec2();
public Distance() {
for (int i = 0; i < 3; ++i) {
p1s[i] = new Vec2();
p2s[i] = new Vec2();
points[i] = new Vec2();
}
}
// 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.
// djm pooled
private final Vec2 p2r = new Vec2();
private final Vec2 p2d = new Vec2();
protected final int ProcessTwo(final Vec2 x1, final Vec2 x2, final Vec2[] p1s,
final Vec2[] p2s, final Vec2[] points) {
// If in point[1] region
p2r.x = -points[1].x;
p2r.y = -points[1].y;
p2d.x = points[0].x - points[1].x;
p2d.y = points[0].y - points[1].y;
final float length = p2d.normalize();
float lambda = Vec2.dot(p2r, p2d);
if (lambda <= 0.0f || length < Settings.EPSILON) {
// The simplex is reduced to a point.
x1.set(p1s[1]);
x2.set(p2s[1]);
p1s[0].set(p1s[1]);
p2s[0].set(p2s[1]);
points[0].set(points[1]);
return 1;
}
// Else in edge region
lambda /= length;
x1
.set(p1s[1].x + lambda * (p1s[0].x - p1s[1].x), p1s[1].y + lambda
* (p1s[0].y - p1s[1].y));
x2
.set(p2s[1].x + lambda * (p2s[0].x - p2s[1].x), 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
protected final int ProcessThree(final Vec2 x1, final Vec2 x2, final Vec2[] p1s,
final Vec2[] p2s, final Vec2[] points) {
final Vec2 a = points[0];
final Vec2 b = points[1];
final Vec2 c = points[2];
final float abx = b.x - a.x;
final float aby = b.y - a.y;
final float acx = c.x - a.x;
final float acy = c.y - a.y;
final float bcx = c.x - b.x;
final float bcy = c.y - b.y;
final float sn = -(a.x * abx + a.y * aby), sd = b.x * abx + b.y * aby;
final float tn = -(a.x * acx + a.y * acy), td = c.x * acx + c.y * acy;
final float un = -(b.x * bcx + b.y * bcy), ud = c.x * bcx + c.y * bcy;
// In vertex c region?
if (td <= 0.0f && ud <= 0.0f) {
// Single point
x1.set(p1s[2]);
x2.set(p2s[2]);
p1s[0].set(p1s[2]);
p2s[0].set(p2s[2]);
points[0].set(points[2]);
return 1;
}
// Should not be in vertex a or b region.
// B2_NOT_USED(sd);
// B2_NOT_USED(sn);
assert sn > 0.0f || tn > 0.0f;
assert sd > 0.0f || un > 0.0f;
final float n = abx * acy - aby * acx;
// Should not be in edge ab region.
final float vc = n * Vec2.cross(a, b);
assert vc > 0.0f || sn > 0.0f || sd > 0.0f;
// In edge bc region?
final float va = n * Vec2.cross(b, c);
if (va <= 0.0f && un >= 0.0f && ud >= 0.0f && un + ud > 0.0f) {
assert un + ud > 0.0f;
final float lambda = un / (un + ud);
x1.set(p1s[1].x + lambda * (p1s[2].x - p1s[1].x), p1s[1].y + lambda
* (p1s[2].y - p1s[1].y));
x2.set(p2s[1].x + lambda * (p2s[2].x - p2s[1].x), p2s[1].y + lambda
* (p2s[2].y - p2s[1].y));
p1s[0].set(p1s[2]);
p2s[0].set(p2s[2]);
points[0].set(points[2]);
return 2;
}
// In edge ac region?
final float vb = n * Vec2.cross(c, a);
if (vb <= 0.0f && tn >= 0.0f && td >= 0.0f && tn + td > 0.0f) {
assert tn + td > 0.0f;
final float lambda = tn / (tn + td);
x1.set(p1s[0].x + lambda * (p1s[2].x - p1s[0].x), p1s[0].y + lambda
* (p1s[2].y - p1s[0].y));
x2.set(p2s[0].x + lambda * (p2s[2].x - p2s[0].x), p2s[0].y + lambda
* (p2s[2].y - p2s[0].y));
p1s[1].set(p1s[2]);
p2s[1].set(p2s[2]);
points[1].set(points[2]);
return 2;
}
// Inside the triangle, compute barycentric coordinates
float denom = va + vb + vc;
assert denom > 0.0f;
denom = 1.0f / denom;
final float u = va * denom;
final float v = vb * denom;
final float w = 1.0f - u - v;
x1.set(u * p1s[0].x + v * p1s[1].x + w * p1s[2].x, u * p1s[0].y + v * p1s[1].y + w
* p1s[2].y);
x2.set(u * p2s[0].x + v * p2s[1].x + w * p2s[2].x, u * p2s[0].y + v * p2s[1].y + w
* p2s[2].y);
return 3;
}
public final boolean InPoints(final Vec2 w, final Vec2[] points, final int pointCount) {
final float k_tolerance = 100.0f * Settings.EPSILON;
for (int i = 0; i < pointCount; ++i) {
final Vec2 v = points[i];
// INLINED
// Vec2 d =Vec2.abs(w.sub(points[i]));
// new Vec2( MathUtils.abs(w.x-points[i].x),
// MathUtils.abs(w.y-points[i].y));//Vec2.abs(w - points[i]);
// Vec2 m = Vec2.max(Vec2.abs(w), Vec2.abs(points[i]));
final float dx = MathUtils.abs(w.x - v.x);
final float dy = MathUtils.abs(w.y - v.y);
final float mx = MathUtils.max(MathUtils.abs(w.x), MathUtils.abs(points[i].x));
final float my = MathUtils.max(MathUtils.abs(w.y), MathUtils.abs(points[i].y));
if (dx < k_tolerance * (mx + 1.0f) && dy < k_tolerance * (my + 1.0f)) {
return true;
}
}
return false;
}
/**
* Distance between any two objects that implement SupportsGeneric Note that
* x1 and x2 are passed so that they may store results - they must be
* instantiated before being passed, and the contents will be lost.
*
* @param x1
* Set to closest point on shape1 (result parameter)
* @param x2
* Set to closest point on shape2 (result parameter)
* @param shape1
* Shape to test
* @param xf1
* Transform of shape1
* @param shape2
* Shape to test
* @param xf2
* Transform of shape2
* @return the distance
*/
// pooled from above
public final float DistanceGeneric(final Vec2 x1, final Vec2 x2,
final SupportsGenericDistance shape1, final XForm xf1,
final SupportsGenericDistance shape2, final XForm xf2) {
int pointCount = 0;
shape1.getFirstVertexToOut(xf1, x1);
shape2.getFirstVertexToOut(xf2, x2);
float vSqr = 0.0f;
final int maxIterations = 20;
for (int iter = 0; iter < maxIterations; ++iter) {
v.set(x2.x - x1.x, x2.y - x1.y);
shape1.support(w1, xf1, v);
vNeg.set(-v.x, -v.y);
shape2.support(w2, xf2, vNeg);
vSqr = Vec2.dot(v, v);
w.set(w2.x - w1.x, w2.y - w1.y);
final float vw = Vec2.dot(v, w);
if (vSqr - vw <= 0.01f * vSqr || InPoints(w, points, pointCount)) // or
// w
// in
// points
{
if (pointCount == 0) {
x1.set(w1);
x2.set(w2);
}
g_GJK_Iterations = iter;
return MathUtils.sqrt(vSqr);
}
switch (pointCount) {
case 0:
p1s[0].set(w1);
p2s[0].set(w2);
points[0].set(w);
x1.set(p1s[0]);
x2.set(p2s[0]);
++pointCount;
break;
case 1:
p1s[1].set(w1);
p2s[1].set(w2);
points[1].set(w);
pointCount = ProcessTwo(x1, x2, p1s, p2s, points);
break;
case 2:
p1s[2].set(w1);
p2s[2].set(w2);
points[2].set(w);
pointCount = ProcessThree(x1, x2, p1s, p2s, points);
break;
}
// If we have three points, then the origin is in the corresponding
// triangle.
if (pointCount == 3) {
g_GJK_Iterations = iter;
return 0.0f;
//
}
float maxSqr = -Float.MAX_VALUE;// -FLT_MAX;
for (int i = 0; i < pointCount; ++i) {
maxSqr = MathUtils.max(maxSqr, Vec2.dot(points[i], points[i]));
}
if (pointCount == 3 || vSqr <= 100.0f * Settings.EPSILON * maxSqr) {
g_GJK_Iterations = iter;
final float vx = x2.x - x1.x;
final float vy = x2.y - x1.y;
vSqr = vx * vx + vy * vy;
return MathUtils.sqrt(vSqr);
//
}
}
g_GJK_Iterations = maxIterations;
return MathUtils.sqrt(vSqr);
//
}
// djm pooled
private final Vec2 distCCp1 = new Vec2();
private final Vec2 distCCp2 = new Vec2();
private final Vec2 distCCd = new Vec2();
/**
* distance between two circle shapes
*
* @param x1
* Closest point on shape1 is put here (result parameter)
* @param x2
* Closest point on shape2 is put here (result parameter)
* @param circle1
* @param xf1
* Transform of first shape
* @param circle2
* @param xf2
* Transform of second shape
* @return the distance
*/
public final float DistanceCC(final Vec2 x1, final Vec2 x2, final CircleShape circle1,
final XForm xf1, final CircleShape circle2, final XForm xf2) {
XForm.mulToOut(xf1, circle1.getMemberLocalPosition(), distCCp1);
XForm.mulToOut(xf2, circle2.getMemberLocalPosition(), distCCp2);
distCCd.x = distCCp2.x - distCCp1.x;
distCCd.y = distCCp2.y - distCCp1.y;
final float dSqr = Vec2.dot(distCCd, distCCd);
final float r1 = circle1.getRadius() - Settings.toiSlop;
final float r2 = circle2.getRadius() - Settings.toiSlop;
final float r = r1 + r2;
if (dSqr > r * r) {
final float dLen = distCCd.normalize();
final float distance = dLen - r;
x1.set(distCCp1.x + r1 * distCCd.x, distCCp1.y + r1 * distCCd.y);
x2.set(distCCp2.x - r2 * distCCd.x, distCCp2.y - r2 * distCCd.y);
return distance;
}
else if (dSqr > Settings.EPSILON * Settings.EPSILON) {
distCCd.normalize();
x1.set(distCCp1.x + r1 * distCCd.x, distCCp1.y + r1 * distCCd.y);
x2.set(x1);
return 0.0f;
}
x1.set(distCCp1);
x2.set(x1);
return 0.0f;
}
// djm pooled
private final Vec2 cWorld = new Vec2(); // just like sea world but with less
// water and more chlorine
// private Vec2 shamoo = new Vec2();
private final Vec2 ECcLocal = new Vec2();
private final Vec2 ECvWorld = new Vec2();
private final Vec2 ECd = new Vec2();
private final Vec2 ECtemp = new Vec2();
/**
* Distance bewteen an edge and a circle
*
* @param x1
* Closest point on shape1 is put here (result parameter)
* @param x2
* Closest point on shape2 is put here (result parameter)
* @param edge
* @param xf1
* xform of edge
* @param circle
* @param xf2
* xform of circle
* @return the distance
*/
public final float DistanceEdgeCircle(final Vec2 x1, final Vec2 x2, final EdgeShape edge,
final XForm xf1, final CircleShape circle, final XForm xf2) {
float dSqr;
float dLen;
final float r = circle.getRadius() - Settings.toiSlop;
XForm.mulToOut(xf2, circle.getMemberLocalPosition(), cWorld);
XForm.mulTransToOut(xf1, cWorld, ECcLocal);
final float dirDist = Vec2.dot(ECcLocal.sub(edge.getCoreVertex1()), edge
.getDirectionVector());
if (dirDist <= 0.0f) {
XForm.mulToOut(xf1, edge.getCoreVertex1(), ECvWorld);
}
else if (dirDist >= edge.getLength()) {
XForm.mulToOut(xf1, edge.getCoreVertex2(), ECvWorld);
}
else {
x1.set(edge.getDirectionVector());
x1.mulLocal(dirDist).addLocal(edge.getCoreVertex1());
XForm.mulToOut(xf1, x1, x1);
// x1.set(XForm.mul(xf1,
// edge.getCoreVertex1().add(edge.getDirectionVector().mul(dirDist))));
ECtemp.set(ECcLocal);
ECtemp.subLocal(edge.getCoreVertex1());
dLen = Vec2.dot(ECtemp, edge.getNormalVector());
if (dLen < 0.0f) {
if (dLen < -r) {
x2.set(edge.getNormalVector());
x2.mulLocal(r).addLocal(ECcLocal);
XForm.mulToOut(xf1, x2, x2);
// x2.set(XForm.mul(xf1,
// ECcLocal.add(edge.getNormalVector().mul(r))));
return -dLen - r;
}
else {
x2.set(x1);
return 0.0f;
}
}
else {
if (dLen > r) {
x2.set(edge.getNormalVector());
x2.mulLocal(r).subLocal(ECcLocal).negateLocal();
XForm.mulToOut(xf1, x2, x2);
// x2.set(XForm.mul(xf1,
// ECcLocal.sub(edge.getNormalVector().mul(r))));
// System.out.println("dlen - r: "+(dLen - r));
return dLen - r;
}
else {
x2.set(x1);
return 0.0f;
}
}
}
x1.set(ECvWorld);
ECd.set(cWorld);
ECd.subLocal(ECvWorld);
dSqr = Vec2.dot(ECd, ECd);
if (dSqr > r * r) {
dLen = ECd.normalize();
x2.set(ECd);
x2.mulLocal(r).subLocal(cWorld).negateLocal();
// x2.set(ECcWorld.sub(ECd.mul(r)));
return dLen - r;
}
else {
x2.set(ECvWorld);
return 0.0f;
}
}
// GJK is more robust with polygon-vs-point than polygon-vs-circle.
// So we convert polygon-vs-circle to polygon-vs-point.
// djm pooled
private final Point point = new Point();
/**
* Distance between a polygon and a circle
*
* @param x1
* Closest point on shape1 is put here (result parameter)
* @param x2
* Closest point on shape2 is put here (result parameter)
* @param polygon
* @param xf1
* xform of polygon
* @param circle
* @param xf2
* xform of circle
* @return the distance
*/
public final float DistancePC(final Vec2 x1, final Vec2 x2, final PolygonShape polygon,
final XForm xf1, final CircleShape circle, final XForm xf2) {
// v is just used as a dummy Vec2 since it gets overwritten in a moment
// Point point = new Point(v); djm we don't need this
// INLINED
// point.p = XForm.mul(xf2, circle.getLocalPosition());
point.p.set(xf2.position.x + xf2.R.col1.x * circle.m_localPosition.x + xf2.R.col2.x
* circle.m_localPosition.y, xf2.position.y + xf2.R.col1.y
* circle.m_localPosition.x + xf2.R.col2.y
* circle.m_localPosition.y);
float distance = DistanceGeneric(x1, x2, polygon, xf1, point, XForm.identity);
final float r = circle.getRadius() - Settings.toiSlop;
if (distance > r) {
distance -= r;
float dx = x2.x - x1.x;
float dy = x2.y - x1.y;
final float length = MathUtils.sqrt(dx * dx + dy * dy);
if (length >= Settings.EPSILON) {
final float invLength = 1.0f / length;
dx *= invLength;
dy *= invLength;
}
x2.x -= r * dx;
x2.y -= r * dy;
}
else {
distance = 0.0f;
x2.set(x1);
}
return distance;
}
/**
* Distance between a polygon and a point
*
* @param x1
* Closest point on shape1 is put here (result parameter)
* @param x2
* Closest point on shape2 is put here (result parameter)
* @param polygon
* @param xf1
* xform of polygon
* @param pt
* @param xf2
* xform of point
* @return the distance
*/
// djm pooled from above
public final float DistancePolygonPoint(final Vec2 x1, final Vec2 x2,
final PolygonShape polygon, final XForm xf1, final PointShape pt, final XForm xf2) {
// v is just used as a dummy Vec2 since it gets overwritten in a moment
// Point point = new Point(v);
// INLINED
// point.p = XForm.mul(xf2, pt.m_localPosition);
point.p.set(xf2.position.x + xf2.R.col1.x * pt.m_localPosition.x + xf2.R.col2.x
* pt.m_localPosition.y, xf2.position.y + xf2.R.col1.y * pt.m_localPosition.x
+ xf2.R.col2.y * pt.m_localPosition.y);
// TODO: check if we need to subtract toi slop from this...
float distance = DistanceGeneric(x1, x2, polygon, xf1, point, XForm.identity);
// ...or if it's better to do it here
final float r = -Settings.toiSlop;
if (distance > r) {
distance -= r;
float dx = x2.x - x1.x;
float dy = x2.y - x1.y;
final float length = MathUtils.sqrt(dx * dx + dy * dy);
if (length >= Settings.EPSILON) {
final float invLength = 1.0f / length;
dx *= invLength;
dy *= invLength;
}
x2.x -= r * dx;
x2.y -= r * dy;
}
else {
distance = 0.0f;
x2.set(x1);
}
return distance;
}
// djm pooled
private final Vec2 CPp1 = new Vec2();
private final Vec2 CPp2 = new Vec2();
private final Vec2 CPd = new Vec2();
/**
* Distance between a circle and a point
*
* @param x1
* Closest point on shape1 is put here (result parameter)
* @param x2
* Closest point on shape2 is put here (result parameter)
* @param circle1
* @param xf1
* xform of circle
* @param pt2
* @param xf2
* xform of point
* @return the distance
*/
public final float DistanceCirclePoint(final Vec2 x1, final Vec2 x2, final CircleShape circle1,
final XForm xf1, final PointShape pt2, final XForm xf2) {
XForm.mulToOut(xf1, circle1.getMemberLocalPosition(), CPp1);
XForm.mulToOut(xf2, pt2.getMemberLocalPosition(), CPp2);
CPd.x = CPp2.x - CPp1.x;
CPd.y = CPp2.y - CPp1.y;
final float dSqr = Vec2.dot(CPd, CPd);
final float r1 = circle1.getRadius() - Settings.toiSlop;
final float r2 = -Settings.toiSlop; // this is necessary, otherwise the
// toi steps aren't taken
// correctly...
final float r = r1 + r2;
if (dSqr > r * r) {
final float dLen = CPd.normalize();
final float distance = dLen - r;
x1.set(CPp1.x + r1 * CPd.x, CPp1.y + r1 * CPd.y);
x2.set(CPp2.x - r2 * CPd.x, CPp2.y - r2 * CPd.y);
return distance;
}
else if (dSqr > Settings.EPSILON * Settings.EPSILON) {
CPd.normalize();
x1.set(CPp1.x + r1 * CPd.x, CPp1.y + r1 * CPd.y);
x2.set(x1);
return 0.0f;
}
x1.set(CPp1);
x2.set(x1);
return 0.0f;
}
/**
* Find the closest distance between shapes shape1 and shape2, and load the
* closest points into x1 and x2. Note that x1 and x2 are passed so that
* they may store results - they must be instantiated before being passed,
* and the contents will be lost.
*
* @param x1
* Closest point on shape1 is put here (result parameter)
* @param x2
* Closest point on shape2 is put here (result parameter)
* @param shape1
* First shape to test
* @param xf1
* Transform of first shape
* @param shape2
* Second shape to test
* @param xf2
* Transform of second shape
* @return the distance
*/
public final float distance(final Vec2 x1, final Vec2 x2, final Shape shape1, final XForm xf1,
final Shape shape2, final XForm xf2) {
final ShapeType type1 = shape1.getType();
final ShapeType type2 = shape2.getType();
if (type1 == ShapeType.CIRCLE_SHAPE && type2 == ShapeType.CIRCLE_SHAPE) {
return DistanceCC(x1, x2, (CircleShape) shape1, xf1, (CircleShape) shape2, xf2);
}
else if (type1 == ShapeType.POLYGON_SHAPE && type2 == ShapeType.CIRCLE_SHAPE) {
return DistancePC(x1, x2, (PolygonShape) shape1, xf1, (CircleShape) shape2, xf2);
}
else if (type1 == ShapeType.CIRCLE_SHAPE && type2 == ShapeType.POLYGON_SHAPE) {
return DistancePC(x2, x1, (PolygonShape) shape2, xf2, (CircleShape) shape1, xf1);
}
else if (type1 == ShapeType.POLYGON_SHAPE && type2 == ShapeType.POLYGON_SHAPE) {
return DistanceGeneric(x1, x2, (PolygonShape) shape1, xf1, (PolygonShape) shape2, xf2);
}
else if (type1 == ShapeType.EDGE_SHAPE && type2 == ShapeType.CIRCLE_SHAPE) {
return DistanceEdgeCircle(x1, x2, (EdgeShape) shape1, xf1, (CircleShape) shape2, xf2);
}
else if (type1 == ShapeType.CIRCLE_SHAPE && type2 == ShapeType.EDGE_SHAPE) {
return DistanceEdgeCircle(x2, x1, (EdgeShape) shape2, xf2, (CircleShape) shape1, xf1);
}
else if (type1 == ShapeType.POLYGON_SHAPE && type2 == ShapeType.EDGE_SHAPE) {
return DistanceGeneric(x2, x1, (EdgeShape) shape2, xf2, (PolygonShape) shape1, xf1);
}
else if (type1 == ShapeType.EDGE_SHAPE && type2 == ShapeType.POLYGON_SHAPE) {
return DistanceGeneric(x1, x2, (EdgeShape) shape1, xf1, (PolygonShape) shape2, xf2);
}
else if (type1 == ShapeType.POINT_SHAPE && type2 == ShapeType.POINT_SHAPE) {
return Float.MAX_VALUE;
}
else if (type1 == ShapeType.POINT_SHAPE && type2 == ShapeType.CIRCLE_SHAPE) {
return DistanceCirclePoint(x2, x1, (CircleShape) shape2, xf2, (PointShape) shape1, xf1);
}
else if (type1 == ShapeType.CIRCLE_SHAPE && type2 == ShapeType.POINT_SHAPE) {
return DistanceCirclePoint(x1, x2, (CircleShape) shape1, xf1, (PointShape) shape2, xf2);
}
else if (type1 == ShapeType.POINT_SHAPE && type2 == ShapeType.POLYGON_SHAPE) {
return DistancePolygonPoint(x2, x1, (PolygonShape) shape2, xf2, (PointShape) shape1,
xf1);
}
else if (type1 == ShapeType.POLYGON_SHAPE && type2 == ShapeType.POINT_SHAPE) {
return DistancePolygonPoint(x1, x2, (PolygonShape) shape1, xf1, (PointShape) shape2,
xf2);
}
return 0.0f;
}
}
// This is used for polygon-vs-circle distance.
class Point implements SupportsGenericDistance {
public Vec2 p;
public Point(final Vec2 _p) {
p = _p.clone();
}
public Point() {
p = new Vec2();
}
public void support(final Vec2 dest, final XForm xf, final Vec2 v) {
dest.set(p);
}
public void getFirstVertexToOut(final XForm xf, final Vec2 out) {
out.set(p);
}
}