/* * Copyright (c) 2006-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 { b2CircleShape } from "../../Collision/Shapes/b2CircleShape"; import { b2Shape } from "../../Collision/Shapes/b2Shape"; import { b2StaticEdgeShape } from "../../Collision/Shapes/b2StaticEdgeShape"; import { b2ContactPoint } from "../../Collision/b2ContactPoint"; import { b2Manifold } from "../../Collision/b2Manifold"; import { b2ManifoldPoint } from "../../Collision/b2ManifoldPoint"; import { b2Mat22, b2Vec2, b2XForm } from "../../Common/Math"; import { b2Body } from "../b2Body"; import { b2ContactListener } from "../b2ContactListener"; import { b2Contact } from "./b2Contact"; export class b2StaticEdgeAndCircleContact extends b2Contact { public static Create(shape1:b2Shape, shape2:b2Shape, allocator:any):b2Contact{ return new b2StaticEdgeAndCircleContact(shape1, shape2); } public static Destroy(contact:b2Contact, allocator:any) : void{ } constructor(shape1:b2Shape, shape2:b2Shape){ super(shape1, shape2); this.m_manifold = this.m_manifolds[0]; //b2Settings.b2Assert(m_shape1.m_type == b2Shape.e_staticEdgeShape); //b2Settings.b2Assert(m_shape2.m_type == b2Shape.e_circleShape); this.m_manifold.pointCount = 0; var point:b2ManifoldPoint = this.m_manifold.points[0]; point.normalImpulse = 0.0; point.tangentImpulse = 0.0; } //~b2StaticEdgeAndCircleContact() {} private static s_evalCP:b2ContactPoint = new b2ContactPoint(); public Evaluate(listener:b2ContactListener) : void{ var v1:b2Vec2; var v2:b2Vec2; var mp0:b2ManifoldPoint; var b1:b2Body = this.m_shape1.m_body; var b2:b2Body = this.m_shape2.m_body; //b2Manifold m0; //memcpy(&m0, &m_manifold, sizeof(b2Manifold)); // TODO: make sure this is completely necessary this.m0.Set(this.m_manifold); b2StaticEdgeAndCircleContact.b2CollideStaticEdgeAndCircle(this.m_manifold, this.m_shape1 as b2StaticEdgeShape, b1.m_xf, this.m_shape2 as b2CircleShape, b2.m_xf); var cp:b2ContactPoint = b2StaticEdgeAndCircleContact.s_evalCP; cp.shape1 = this.m_shape1; cp.shape2 = this.m_shape2; cp.friction = this.m_friction; cp.restitution = this.m_restitution; if (this.m_manifold.pointCount > 0) { this.m_manifoldCount = 1; var mp:b2ManifoldPoint = this.m_manifold.points[ 0 ]; if (this.m0.pointCount == 0) { mp.normalImpulse = 0.0; mp.tangentImpulse = 0.0; if (listener) { cp.position = b1.GetWorldPoint(mp.localPoint1); v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1); v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2); cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); cp.normal.SetV(this.m_manifold.normal); cp.separation = mp.separation; cp.id.key = mp.id._key; listener.Add(cp); } } else { mp0 = this.m0.points[ 0 ]; mp.normalImpulse = mp0.normalImpulse; mp.tangentImpulse = mp0.tangentImpulse; if (listener) { cp.position = b1.GetWorldPoint(mp.localPoint1); v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1); v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2); cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); cp.normal.SetV(this.m_manifold.normal); cp.separation = mp.separation; cp.id.key = mp.id._key; listener.Persist(cp); } } } else { this.m_manifoldCount = 0; if (this.m0.pointCount > 0 && listener) { mp0 = this.m0.points[ 0 ]; cp.position = b1.GetWorldPoint(mp0.localPoint1); v1 = b1.GetLinearVelocityFromLocalPoint(mp0.localPoint1); v2 = b2.GetLinearVelocityFromLocalPoint(mp0.localPoint2); cp.velocity.Set(v2.x - v1.x, v2.y - v1.y); cp.normal.SetV(this.m0.normal); cp.separation = mp0.separation; cp.id.key = mp0.id._key; listener.Remove(cp); } } } public GetManifolds():b2Manifold[] { return this.m_manifolds; } private m_manifolds:b2Manifold[] = [new b2Manifold()]; public m_manifold:b2Manifold; private m0:b2Manifold = new b2Manifold(); public static b2CollideStaticEdgeAndCircle( manifold:b2Manifold, edge:b2StaticEdgeShape, xf1:b2XForm, circle:b2CircleShape, xf2:b2XForm) : void { manifold.pointCount = 0; var dX:number; var dY:number; var separation:number; var tPoint:b2ManifoldPoint; var tMat:b2Mat22 = xf2.R; var tVec:b2Vec2 = circle.m_localPosition; var circleX:number = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); var circleY:number = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); var dirDist:number = (circleX - edge.m_v1.x) * edge.m_direction.x + (circleY - edge.m_v1.y) * edge.m_direction.y; if (dirDist <= 0) { dX = circleX - edge.m_v1.x; dY = circleY - edge.m_v1.y; if (dX * edge.m_cornerDir1.x + dY * edge.m_cornerDir1.y < 0) { return; } } else if (dirDist >= edge.m_length) { dX = circleX - edge.m_v2.x; dY = circleY - edge.m_v2.y; if (dX * edge.m_cornerDir2.x + dY * edge.m_cornerDir2.y > 0) { return; } } else { tVec = edge.m_normal; separation = (circleX - edge.m_v1.x) * tVec.x + (circleY - edge.m_v1.y) * tVec.y; if (separation > circle.m_radius || separation < -circle.m_radius) { return; } separation -= circle.m_radius; manifold.normal.x = tVec.x; manifold.normal.y = tVec.y; manifold.pointCount = 1; tPoint = manifold.points[0]; tPoint.id.key = 0; tPoint.separation = separation; circleX -= circle.m_radius * tVec.x; circleY -= circle.m_radius * tVec.y; tPoint.localPoint1.x = circleX; tPoint.localPoint1.y = circleY; dX = circleX - xf2.position.x; dY = circleY - xf2.position.y; tPoint.localPoint2.x = (dX * tMat.col1.x + dY * tMat.col1.y ); tPoint.localPoint2.y = (dX * tMat.col2.x + dY * tMat.col2.y ); return; } var distSqr:number = dX * dX + dY * dY; if (distSqr > circle.m_radius * circle.m_radius) { return; } if (distSqr < Number.MIN_VALUE) { separation = -circle.m_radius; manifold.normal.SetV(edge.m_normal); } else { var dist:number = Math.sqrt(distSqr); separation = dist - circle.m_radius; var a:number = 1.0 / dist; manifold.normal.x = a * dX; manifold.normal.y = a * dY; } manifold.pointCount = 1; tPoint = manifold.points[0]; tPoint.id.key = 0; tPoint.separation = separation; circleX -= circle.m_radius * manifold.normal.x; circleY -= circle.m_radius * manifold.normal.y; tPoint.localPoint1.x = circleX; tPoint.localPoint1.y = circleY; dX = circleX - xf2.position.x; dY = circleY - xf2.position.y; tPoint.localPoint2.x = (dX * tMat.col1.x + dY * tMat.col1.y ); tPoint.localPoint2.y = (dX * tMat.col2.x + dY * tMat.col2.y ); } }