API Docs for: 1.0.0
Show:

File: src\fork\box2d\collision\shapes\b2PolyShape.js

/*
* Copyright (c) 2006-2007 Erin Catto http:
*
* 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, and must not be
* misrepresented the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/

/**
 * A convex polygon
 *
 * The position of the polygon (m_position) is the
 * position of the centroid. The vertices of the incoming polygon are pre-rotated
 * according to the local rotation. The vertices are also shifted to be centered
 * on the centroid. Since the local rotation is absorbed into the vertex
 * coordinates, the polygon rotation is equal to the body rotation. However,
 * the polygon position is centered on the polygon centroid. This simplifies
 * some collision algorithms.
 * 
 * @class b2PolyShape
 * @constructor
 */
var b2PolyShape = function (def, body, newOrigin) {
    // initialize instance variables for references
	this.m_R = new b2Mat22();
	this.m_position = new b2Vec2();
	//

	// The constructor for b2Shape
	this.m_userData = def.userData;

	this.m_friction = def.friction;
	this.m_restitution = def.restitution;
	this.m_body = body;

	this.m_proxyId = b2Pair.b2_nullProxy;

	this.m_maxRadius = 0.0;

	this.m_categoryBits = def.categoryBits;
	this.m_maskBits = def.maskBits;
	this.m_groupIndex = def.groupIndex;
	//

	// initialize instance variables for references
	this.syncAABB = new b2AABB();
	this.syncMat = new b2Mat22();
	this.m_localCentroid = new b2Vec2();
	this.m_localOBB = new b2OBB();
	//


	//super(def, body);

	var i = 0;


	var hX;
	var hY;

	var tVec;

	var aabb = new b2AABB();

	// Vertices
	this.m_vertices = new Array(b2Settings.b2_maxPolyVertices);
	this.m_coreVertices = new Array(b2Settings.b2_maxPolyVertices);
	//for (i = 0; i < b2Settings.b2_maxPolyVertices; i++)
	//	this.m_vertices[i] = new b2Vec2();

	// Normals
	this.m_normals = new Array(b2Settings.b2_maxPolyVertices);
	//for (i = 0; i < b2Settings.b2_maxPolyVertices; i++)
	//	this.m_normals[i] = new b2Vec2();

	//b2Settings.b2Assert(def.type == b2Shape.e_boxShape || def.type == b2Shape.e_polyShape);
	this.m_type = b2Shape.e_polyShape;

	var localR = new b2Mat22(def.localRotation);

	// Get the vertices transformed into the body frame.
	if (def.type == b2Shape.e_boxShape)
	{
		//this.m_localCentroid = def.localPosition - newOrigin;
		this.m_localCentroid.x = def.localPosition.x - newOrigin.x;
		this.m_localCentroid.y = def.localPosition.y - newOrigin.y;

		var box = def;
		this.m_vertexCount = 4;
		hX = box.extents.x;
		hY = box.extents.y;

		//hc.x = b2Max(0.0f, h.x - 2.0f * b2_linearSlop);
		var hcX = Math.max(0.0, hX - 2.0 * b2Settings.b2_linearSlop);
		//hc.y = b2Max(0.0f, h.y - 2.0f * b2_linearSlop);
		var hcY = Math.max(0.0, hY - 2.0 * b2Settings.b2_linearSlop);

		//this.m_vertices[0] = b2Mul(localR, b2Vec2(h.x, h.y));
		tVec = this.m_vertices[0] = new b2Vec2();
		tVec.x = localR.col1.x * hX + localR.col2.x * hY;
		tVec.y = localR.col1.y * hX + localR.col2.y * hY;
		//this.m_vertices[1] = b2Mul(localR, b2Vec2(-h.x, h.y));
		tVec = this.m_vertices[1] = new b2Vec2();
		tVec.x = localR.col1.x * -hX + localR.col2.x * hY;
		tVec.y = localR.col1.y * -hX + localR.col2.y * hY;
		//this.m_vertices[2] = b2Mul(localR, b2Vec2(-h.x, -h.y));
		tVec = this.m_vertices[2] = new b2Vec2();
		tVec.x = localR.col1.x * -hX + localR.col2.x * -hY;
		tVec.y = localR.col1.y * -hX + localR.col2.y * -hY;
		//this.m_vertices[3] = b2Mul(localR, b2Vec2(h.x, -h.y));
		tVec = this.m_vertices[3] = new b2Vec2();
		tVec.x = localR.col1.x * hX + localR.col2.x * -hY;
		tVec.y = localR.col1.y * hX + localR.col2.y * -hY;

		//this.m_coreVertices[0] = b2Mul(localR, b2Vec2(hc.x, hc.y));
		tVec = this.m_coreVertices[0] = new b2Vec2();
		tVec.x = localR.col1.x * hcX + localR.col2.x * hcY;
		tVec.y = localR.col1.y * hcX + localR.col2.y * hcY;
		//this.m_coreVertices[1] = b2Mul(localR, b2Vec2(-hc.x, hc.y));
		tVec = this.m_coreVertices[1] = new b2Vec2();
		tVec.x = localR.col1.x * -hcX + localR.col2.x * hcY;
		tVec.y = localR.col1.y * -hcX + localR.col2.y * hcY;
		//this.m_coreVertices[2] = b2Mul(localR, b2Vec2(-hc.x, -hc.y));
		tVec = this.m_coreVertices[2] = new b2Vec2();
		tVec.x = localR.col1.x * -hcX + localR.col2.x * -hcY;
		tVec.y = localR.col1.y * -hcX + localR.col2.y * -hcY;
		//this.m_coreVertices[3] = b2Mul(localR, b2Vec2(hc.x, -hc.y));
		tVec = this.m_coreVertices[3] = new b2Vec2();
		tVec.x = localR.col1.x * hcX + localR.col2.x * -hcY;
		tVec.y = localR.col1.y * hcX + localR.col2.y * -hcY;
	}
	else
	{
		var poly = def;

		this.m_vertexCount = poly.vertexCount;
		//b2Settings.b2Assert(3 <= this.m_vertexCount && this.m_vertexCount <= b2Settings.b2_maxPolyVertices);
		//b2Vec2 centroid = b2Shape.PolyCentroid(poly->vertices, poly->vertexCount);
		b2Shape.PolyCentroid(poly.vertices, poly.vertexCount, b2PolyShape.tempVec);
		var centroidX = b2PolyShape.tempVec.x;
		var centroidY = b2PolyShape.tempVec.y;
		//this.m_localCentroid = def->localPosition + b2Mul(localR, centroid) - newOrigin;
		this.m_localCentroid.x = def.localPosition.x + (localR.col1.x * centroidX + localR.col2.x * centroidY) - newOrigin.x;
		this.m_localCentroid.y = def.localPosition.y + (localR.col1.y * centroidX + localR.col2.y * centroidY) - newOrigin.y;

		for (i = 0; i < this.m_vertexCount; ++i)
		{
			this.m_vertices[i] = new b2Vec2();
			this.m_coreVertices[i] = new b2Vec2();

			//this.m_vertices[i] = b2Mul(localR, poly->vertices[i] - centroid);
			hX = poly.vertices[i].x - centroidX;
			hY = poly.vertices[i].y - centroidY;
			this.m_vertices[i].x = localR.col1.x * hX + localR.col2.x * hY;
			this.m_vertices[i].y = localR.col1.y * hX + localR.col2.y * hY;

			//b2Vec2 u = this.m_vertices[i];
			var uX = this.m_vertices[i].x;
			var uY = this.m_vertices[i].y;
			//float32 length = u.Length();
			var length = Math.sqrt(uX*uX + uY*uY);
			if (length > Number.MIN_VALUE)
			{
				uX *= 1.0 / length;
				uY *= 1.0 / length;
			}

			//this.m_coreVertices[i] = this.m_vertices[i] - 2.0f * b2_linearSlop * u;
			this.m_coreVertices[i].x = this.m_vertices[i].x - 2.0 * b2Settings.b2_linearSlop * uX;
			this.m_coreVertices[i].y = this.m_vertices[i].y - 2.0 * b2Settings.b2_linearSlop * uY;
		}

	}

	// Compute bounding box. TODO_ERIN optimize OBB
	//var minVertex = new b2Vec2(Number.MAX_VALUE, Number.MAX_VALUE);
	var minVertexX = Number.MAX_VALUE;
	var minVertexY = Number.MAX_VALUE;
	var maxVertexX = -Number.MAX_VALUE;
	var maxVertexY = -Number.MAX_VALUE;
	this.m_maxRadius = 0.0;
	for (i = 0; i < this.m_vertexCount; ++i)
	{
		var v = this.m_vertices[i];
		//minVertex = b2Math.b2MinV(minVertex, this.m_vertices[i]);
		minVertexX = Math.min(minVertexX, v.x);
		minVertexY = Math.min(minVertexY, v.y);
		//maxVertex = b2Math.b2MaxV(maxVertex, this.m_vertices[i]);
		maxVertexX = Math.max(maxVertexX, v.x);
		maxVertexY = Math.max(maxVertexY, v.y);
		//this.m_maxRadius = b2Max(this.m_maxRadius, v.Length());
		this.m_maxRadius = Math.max(this.m_maxRadius, v.Length());
	}

	this.m_localOBB.R.SetIdentity();
	//this.m_localOBB.center = 0.5 * (minVertex + maxVertex);
	this.m_localOBB.center.Set((minVertexX + maxVertexX) * 0.5, (minVertexY + maxVertexY) * 0.5);
	//this.m_localOBB.extents = 0.5 * (maxVertex - minVertex);
	this.m_localOBB.extents.Set((maxVertexX - minVertexX) * 0.5, (maxVertexY - minVertexY) * 0.5);

	// Compute the edge normals and next index map.
	var i1 = 0;
	var i2 = 0;
	for (i = 0; i < this.m_vertexCount; ++i)
	{
		this.m_normals[i] =  new b2Vec2();
		i1 = i;
		i2 = i + 1 < this.m_vertexCount ? i + 1 : 0;
		//b2Vec2 edge = this.m_vertices[i2] - this.m_vertices[i1];
		//var edgeX = this.m_vertices[i2].x - this.m_vertices[i1].x;
		//var edgeY = this.m_vertices[i2].y - this.m_vertices[i1].y;
		//this.m_normals[i] = b2Cross(edge, 1.0f);
		this.m_normals[i].x = this.m_vertices[i2].y - this.m_vertices[i1].y;
		this.m_normals[i].y = -(this.m_vertices[i2].x - this.m_vertices[i1].x);
		this.m_normals[i].Normalize();
	}

	// Ensure the polygon in convex. TODO_ERIN compute convex hull.
	for (i = 0; i < this.m_vertexCount; ++i)
	{
		i1 = i;
		i2 = i + 1 < this.m_vertexCount ? i + 1 : 0;

		//b2Settings.b2Assert(b2Math.b2CrossVV(this.m_normals[i1], this.m_normals[i2]) > Number.MIN_VALUE);
	}

	this.m_R.SetM(this.m_body.m_R);
	//this.m_position.SetV( this.m_body.m_position  + b2Mul(this.m_body->this.m_R, this.m_localCentroid) );
	this.m_position.x = this.m_body.m_position.x + (this.m_R.col1.x * this.m_localCentroid.x + this.m_R.col2.x * this.m_localCentroid.y);
	this.m_position.y = this.m_body.m_position.y + (this.m_R.col1.y * this.m_localCentroid.x + this.m_R.col2.y * this.m_localCentroid.y);

	//var R = b2Math.b2MulMM(this.m_R, this.m_localOBB.R);
		//R.col1 = b2MulMV(this.m_R, this.m_localOBB.R.col1);
		b2PolyShape.tAbsR.col1.x = this.m_R.col1.x * this.m_localOBB.R.col1.x + this.m_R.col2.x * this.m_localOBB.R.col1.y;
		b2PolyShape.tAbsR.col1.y = this.m_R.col1.y * this.m_localOBB.R.col1.x + this.m_R.col2.y * this.m_localOBB.R.col1.y;
		//R.col2 = b2MulMV(this.m_R, this.m_localOBB.R.col2)
		b2PolyShape.tAbsR.col2.x = this.m_R.col1.x * this.m_localOBB.R.col2.x + this.m_R.col2.x * this.m_localOBB.R.col2.y;
		b2PolyShape.tAbsR.col2.y = this.m_R.col1.y * this.m_localOBB.R.col2.x + this.m_R.col2.y * this.m_localOBB.R.col2.y;
	//var absR = b2Math.b2AbsM(R);
	b2PolyShape.tAbsR.Abs()

	//h = b2Math.b2MulMV(b2PolyShape.tAbsR, this.m_localOBB.extents);
	hX = b2PolyShape.tAbsR.col1.x * this.m_localOBB.extents.x + b2PolyShape.tAbsR.col2.x * this.m_localOBB.extents.y;
	hY = b2PolyShape.tAbsR.col1.y * this.m_localOBB.extents.x + b2PolyShape.tAbsR.col2.y * this.m_localOBB.extents.y;

	//var position = this.m_position + b2Mul(this.m_R, this.m_localOBB.center);
	var positionX = this.m_position.x + (this.m_R.col1.x * this.m_localOBB.center.x + this.m_R.col2.x * this.m_localOBB.center.y);
	var positionY = this.m_position.y + (this.m_R.col1.y * this.m_localOBB.center.x + this.m_R.col2.y * this.m_localOBB.center.y);

	//aabb.minVertex = b2Math.SubtractVV(this.m_position, h);
	aabb.minVertex.x = positionX - hX;
	aabb.minVertex.y = positionY - hY;
	//aabb.maxVertex = b2Math.AddVV(this.m_position, h);
	aabb.maxVertex.x = positionX + hX;
	aabb.maxVertex.y = positionY + hY;

	var broadPhase = this.m_body.m_world.m_broadPhase;
	if (broadPhase.InRange(aabb))
	{
		this.m_proxyId = broadPhase.CreateProxy(aabb, this);
	}
	else
	{
		this.m_proxyId = b2Pair.b2_nullProxy;
	}

	if (this.m_proxyId == b2Pair.b2_nullProxy)
	{
		this.m_body.Freeze();
	}
};
Object.extend(b2PolyShape.prototype, b2Shape.prototype);
Object.extend(b2PolyShape.prototype, 
{
	TestPoint: function(p){

		//var pLocal = b2Math.b2MulTMV(this.m_R, b2Math.SubtractVV(p, this.m_position));
		var pLocal = new b2Vec2();
		pLocal.SetV(p);
		pLocal.Subtract(this.m_position);
		pLocal.MulTM(this.m_R);

		for (var i = 0; i < this.m_vertexCount; ++i)
		{
			//var dot = b2Math.b2Dot(this.m_normals[i], b2Math.SubtractVV(pLocal, this.m_vertices[i]));
			var tVec = new b2Vec2();
			tVec.SetV(pLocal);
			tVec.Subtract(this.m_vertices[i]);

			var dot = b2Math.b2Dot(this.m_normals[i], tVec);
			if (dot > 0.0)
			{
				return false;
			}
		}

		return true;
	},

	//--------------- Internals Below -------------------
	// Temp vec for b2Shape.PolyCentroid

	// Temp AABB for Synch function
	syncAABB: new b2AABB(),
	syncMat: new b2Mat22(),
	Synchronize: function(position1, R1, position2, R2){
		// The body transform is copied for convenience.
		this.m_R.SetM(R2);
		//this.m_position = this.m_body->this.m_position + b2Mul(this.m_body->this.m_R, this.m_localCentroid)
		this.m_position.x = this.m_body.m_position.x + (R2.col1.x * this.m_localCentroid.x + R2.col2.x * this.m_localCentroid.y);
		this.m_position.y = this.m_body.m_position.y + (R2.col1.y * this.m_localCentroid.x + R2.col2.y * this.m_localCentroid.y);

		if (this.m_proxyId == b2Pair.b2_nullProxy)
		{
			return;
		}

		//b2AABB aabb1, aabb2;
		var hX;
		var hY;

		//b2Mat22 obbR = b2Mul(R1, this.m_localOBB.R);
			var v1 = R1.col1;
			var v2 = R1.col2;
			var v3 = this.m_localOBB.R.col1;
			var v4 = this.m_localOBB.R.col2;
			//this.syncMat.col1 = b2MulMV(R1, this.m_localOBB.R.col1);
			this.syncMat.col1.x = v1.x * v3.x + v2.x * v3.y;
			this.syncMat.col1.y = v1.y * v3.x + v2.y * v3.y;
			//this.syncMat.col2 = b2MulMV(R1, this.m_localOBB.R.col2);
			this.syncMat.col2.x = v1.x * v4.x + v2.x * v4.y;
			this.syncMat.col2.y = v1.y * v4.x + v2.y * v4.y;
		//b2Mat22 absR = b2Abs(obbR);
		this.syncMat.Abs();
		//b2Vec2 center = position1 + b2Mul(R1, this.m_localCentroid + this.m_localOBB.center);
		hX = this.m_localCentroid.x + this.m_localOBB.center.x;
		hY = this.m_localCentroid.y + this.m_localOBB.center.y;
		var centerX = position1.x + (R1.col1.x * hX + R1.col2.x * hY);
		var centerY = position1.y + (R1.col1.y * hX + R1.col2.y * hY);
		//b2Vec2 h = b2Mul(this.syncMat, this.m_localOBB.extents);
		hX = this.syncMat.col1.x * this.m_localOBB.extents.x + this.syncMat.col2.x * this.m_localOBB.extents.y;
		hY = this.syncMat.col1.y * this.m_localOBB.extents.x + this.syncMat.col2.y * this.m_localOBB.extents.y;
		//aabb1.minVertex = center - h;
		this.syncAABB.minVertex.x = centerX - hX;
		this.syncAABB.minVertex.y = centerY - hY;
		//aabb1.maxVertex = center + h;
		this.syncAABB.maxVertex.x = centerX + hX;
		this.syncAABB.maxVertex.y = centerY + hY;

		//b2Mat22 obbR = b2Mul(R2, this.m_localOBB.R);
			v1 = R2.col1;
			v2 = R2.col2;
			v3 = this.m_localOBB.R.col1;
			v4 = this.m_localOBB.R.col2;
			//this.syncMat.col1 = b2MulMV(R1, this.m_localOBB.R.col1);
			this.syncMat.col1.x = v1.x * v3.x + v2.x * v3.y;
			this.syncMat.col1.y = v1.y * v3.x + v2.y * v3.y;
			//this.syncMat.col2 = b2MulMV(R1, this.m_localOBB.R.col2);
			this.syncMat.col2.x = v1.x * v4.x + v2.x * v4.y;
			this.syncMat.col2.y = v1.y * v4.x + v2.y * v4.y;
		//b2Mat22 absR = b2Abs(obbR);
		this.syncMat.Abs();
		//b2Vec2 center = position2 + b2Mul(R2, this.m_localCentroid + this.m_localOBB.center);
		hX = this.m_localCentroid.x + this.m_localOBB.center.x;
		hY = this.m_localCentroid.y + this.m_localOBB.center.y;
		centerX = position2.x + (R2.col1.x * hX + R2.col2.x * hY);
		centerY = position2.y + (R2.col1.y * hX + R2.col2.y * hY);
		//b2Vec2 h = b2Mul(absR, this.m_localOBB.extents);
		hX = this.syncMat.col1.x * this.m_localOBB.extents.x + this.syncMat.col2.x * this.m_localOBB.extents.y;
		hY = this.syncMat.col1.y * this.m_localOBB.extents.x + this.syncMat.col2.y * this.m_localOBB.extents.y;
		//aabb2.minVertex = center - h;
		//aabb2.maxVertex = center + h;

		//aabb.minVertex = b2Min(aabb1.minVertex, aabb2.minVertex);
		this.syncAABB.minVertex.x = Math.min(this.syncAABB.minVertex.x, centerX - hX);
		this.syncAABB.minVertex.y = Math.min(this.syncAABB.minVertex.y, centerY - hY);
		//aabb.maxVertex = b2Max(aabb1.maxVertex, aabb2.maxVertex);
		this.syncAABB.maxVertex.x = Math.max(this.syncAABB.maxVertex.x, centerX + hX);
		this.syncAABB.maxVertex.y = Math.max(this.syncAABB.maxVertex.y, centerY + hY);

		var broadPhase = this.m_body.m_world.m_broadPhase;
		if (broadPhase.InRange(this.syncAABB))
		{
			broadPhase.MoveProxy(this.m_proxyId, this.syncAABB);
		}
		else
		{
			this.m_body.Freeze();
		}
	},

	QuickSync: function(position, R){
		//this.m_R = R;
		this.m_R.SetM(R);
		//this.m_position = position + b2Mul(R, this.m_localCentroid);
		this.m_position.x = position.x + (R.col1.x * this.m_localCentroid.x + R.col2.x * this.m_localCentroid.y);
		this.m_position.y = position.y + (R.col1.y * this.m_localCentroid.x + R.col2.y * this.m_localCentroid.y);
	},

	ResetProxy: function(broadPhase){

		if (this.m_proxyId == b2Pair.b2_nullProxy)
		{
			return;
		}

		var proxy = broadPhase.GetProxy(this.m_proxyId);

		broadPhase.DestroyProxy(this.m_proxyId);
		proxy = null;

		var R = b2Math.b2MulMM(this.m_R, this.m_localOBB.R);
		var absR = b2Math.b2AbsM(R);
		var h = b2Math.b2MulMV(absR, this.m_localOBB.extents);
		//var position = this.m_position + b2Mul(this.m_R, this.m_localOBB.center);
		var position = b2Math.b2MulMV(this.m_R, this.m_localOBB.center);
		position.Add(this.m_position);

		var aabb = new b2AABB();
		//aabb.minVertex = position - h;
		aabb.minVertex.SetV(position);
		aabb.minVertex.Subtract(h);
		//aabb.maxVertex = position + h;
		aabb.maxVertex.SetV(position);
		aabb.maxVertex.Add(h);

		if (broadPhase.InRange(aabb))
		{
			this.m_proxyId = broadPhase.CreateProxy(aabb, this);
		}
		else
		{
			this.m_proxyId = b2Pair.b2_nullProxy;
		}

		if (this.m_proxyId == b2Pair.b2_nullProxy)
		{
			this.m_body.Freeze();
		}
	},


	Support: function(dX, dY, out)
	{
		//b2Vec2 dLocal = b2MulT(this.m_R, d);
		var dLocalX = (dX*this.m_R.col1.x + dY*this.m_R.col1.y);
		var dLocalY = (dX*this.m_R.col2.x + dY*this.m_R.col2.y);

		var bestIndex = 0;
		//float32 bestValue = b2Dot(this.m_vertices[0], dLocal);
		var bestValue = (this.m_coreVertices[0].x * dLocalX + this.m_coreVertices[0].y * dLocalY);
		for (var i = 1; i < this.m_vertexCount; ++i)
		{
			//float32 value = b2Dot(this.m_vertices[i], dLocal);
			var value = (this.m_coreVertices[i].x * dLocalX + this.m_coreVertices[i].y * dLocalY);
			if (value > bestValue)
			{
				bestIndex = i;
				bestValue = value;
			}
		}

		//return this.m_position + b2Mul(this.m_R, this.m_vertices[bestIndex]);
		out.Set(	this.m_position.x + (this.m_R.col1.x * this.m_coreVertices[bestIndex].x + this.m_R.col2.x * this.m_coreVertices[bestIndex].y),
					this.m_position.y + (this.m_R.col1.y * this.m_coreVertices[bestIndex].x + this.m_R.col2.y * this.m_coreVertices[bestIndex].y));

	},


	// Local position of the shape centroid in parent body frame.
	m_localCentroid: new b2Vec2(),

	// Local position oriented bounding box. The OBB center is relative to
	// shape centroid.
	m_localOBB: new b2OBB(),
	m_vertices: null,
	m_coreVertices: null,
	m_vertexCount: 0,
	m_normals: null});

b2PolyShape.tempVec = new b2Vec2();
b2PolyShape.tAbsR = new b2Mat22();