package org.jbox2d.collision.shapes; import org.jbox2d.collision.AABB; import org.jbox2d.collision.MassData; import org.jbox2d.collision.Segment; import org.jbox2d.collision.SegmentCollide; import org.jbox2d.common.Mat22; import org.jbox2d.common.MathUtils; import org.jbox2d.common.RaycastResult; import org.jbox2d.common.Settings; import org.jbox2d.common.Vec2; import org.jbox2d.common.XForm; import org.jbox2d.pooling.TLVec2; /** * Point shape. Like a circle shape of zero radius, except * that it has a finite mass. * */ public class PointShape extends Shape { public final Vec2 m_localPosition; public float m_mass; public PointShape(final ShapeDef def) { super(def); assert(def.type == ShapeType.POINT_SHAPE); final PointDef pointDef = (PointDef)def; m_type = ShapeType.POINT_SHAPE; m_localPosition = pointDef.localPosition.clone(); m_mass = pointDef.mass; } // djm pooling private static final TLVec2 tlP = new TLVec2(); /** * @see Shape#computeAABB(AABB, XForm) */ @Override public void computeAABB(final AABB aabb, final XForm transform) { //Vec2 p = transform.position.add(Mat22.mul(transform.R, m_localPosition)); final Vec2 p = tlP.get(); Mat22.mulToOut(transform.R, m_localPosition, p); p.add(transform.position); aabb.lowerBound.set(p.x-Settings.EPSILON, p.y-Settings.EPSILON); aabb.upperBound.set(p.x+Settings.EPSILON, p.y+Settings.EPSILON); } /** * @see Shape#computeMass(MassData) */ @Override public void computeMass(final MassData massData) { massData.mass = m_mass; massData.center.set(m_localPosition); massData.I = 0.0f; } // djm pooling private static final TLVec2 tlSwept1 = new TLVec2(); private static final TLVec2 tlSwept2 = new TLVec2(); /** * @see Shape#computeSweptAABB(AABB, XForm, XForm) */ @Override public void computeSweptAABB(final AABB aabb, final XForm transform1, final XForm transform2) { final Vec2 sweptP1 = tlSwept1.get(); final Vec2 sweptP2 = tlSwept2.get(); //Vec2 p1 = transform1.position.add(Mat22.mul(transform1.R, m_localPosition)); //Vec2 p2 = transform2.position.add(Mat22.mul(transform2.R, m_localPosition)); Mat22.mulToOut( transform2.R, m_localPosition, sweptP1); Mat22.mulToOut( transform2.R, m_localPosition, sweptP2); Vec2.minToOut( sweptP1, sweptP2, aabb.lowerBound); Vec2.maxToOut( sweptP1, sweptP2, aabb.upperBound); aabb.lowerBound.x -= Settings.EPSILON; aabb.lowerBound.y -= Settings.EPSILON; aabb.upperBound.x += Settings.EPSILON; aabb.upperBound.y += Settings.EPSILON; } /** * @see Shape#testPoint(XForm, Vec2) */ @Override public boolean testPoint(final XForm xf, final Vec2 p) { // TODO djm: could use more optimization. // we could probably use bit shifting return false; } // Collision Detection in Interactive 3D Environments by Gino van den Bergen // From Section 3.1.2 // x = s + a * r // norm(x) = radius // djm pooled private static final TLVec2 tlS = new TLVec2(); private static final TLVec2 tlPosition = new TLVec2(); private static final TLVec2 tlR = new TLVec2(); /** * @see Shape#testSegment(XForm, RaycastResult, Segment, float) */ @Override public SegmentCollide testSegment(final XForm xf, final RaycastResult out, final Segment segment, final float maxLambda){ final Vec2 position = tlPosition.get(); final Vec2 s = tlS.get(); Mat22.mulToOut( xf.R, m_localPosition, position); position.addLocal(xf.position); s.set(segment.p1); s.subLocal(position); final float b = Vec2.dot(s, s); // Does the segment start inside the circle? if (b < 0.0f){ return SegmentCollide.STARTS_INSIDE_COLLIDE; } final Vec2 r = tlR.get(); // Solve quadratic equation. r.set(segment.p2).subLocal(segment.p1); final float c = Vec2.dot(s, r); final float rr = Vec2.dot(r, r); final float sigma = c * c - rr * b; // Check for negative discriminant and short segment. if (sigma < 0.0f || rr < Settings.EPSILON){ return SegmentCollide.MISS_COLLIDE; } // Find the point of intersection of the line with the circle. float a = -(c + MathUtils.sqrt(sigma)); // Is the intersection point on the segment? if (0.0f <= a && a <= maxLambda * rr){ a /= rr; out.lambda = a; out.normal.set(r).mulLocal(a).addLocal(s); out.normal.normalize(); return SegmentCollide.HIT_COLLIDE; } return SegmentCollide.MISS_COLLIDE; } /** * @see Shape#updateSweepRadius(Vec2) */ // djm optimized @Override public void updateSweepRadius(final Vec2 center) { //Vec2 d = m_localPosition.sub(center); final float dx = m_localPosition.x - center.x; final float dy = m_localPosition.y - center.y; m_sweepRadius = MathUtils.sqrt(dx*dx + dy*dy) - Settings.toiSlop; } /** * @return a copy of local position */ public Vec2 getLocalPosition() { return m_localPosition.clone(); } /** * This is the member variable for the local position. * Don't change this. * @return */ public Vec2 getMemberLocalPosition(){ return m_localPosition; } public float getMass() { return m_mass; } }