planck-js
Version:
2D physics engine for JavaScript/HTML5 game development
132 lines (120 loc) • 3.51 kB
JavaScript
/*
* Copyright (c) 2016 Ali Shakiba http://shakiba.me/planck.js
* Copyright (c) 2006-2011 Erin Catto 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.
*/
module.exports = Transform;
var Vec2 = require('./Vec2');
var Rot = require('./Rot');
// TODO merge with Rot
/**
* A transform contains translation and rotation. It is used to represent the
* position and orientation of rigid frames. Initialize using a position vector
* and a rotation.
*
* @prop {Vec2} position
* @prop {Rot} rotation
*/
function Transform(position, rotation) {
if (!(this instanceof Transform)) {
return new Vec2(position, rotation);
}
this.p = new Vec2();
this.q = new Rot();
if (typeof position !== 'undefined') {
this.p.Set(position);
}
if (typeof rotation !== 'undefined') {
this.q.Set(rotation);
}
};
/**
* Set this to the identity transform.
*/
Transform.prototype.SetIdentity = function() {
this.p.SetZero();
this.q.SetIdentity();
}
/**
* Set this based on the position and angle.
*/
Transform.prototype.Set = function(position, angle) {
this.p.Set(position);
this.q.Set(angle);
}
Transform.IsValid = function(o) {
return o && Vec2.IsValid(o.p) && Rot.IsValid(o.q);
}
Transform.Assert = function(o) {
if (!Transform.IsValid(o)) {
console.log(o);
throw new Error('Invalid Transform!');
}
}
/**
* @param {Transform} a
* @param {Vec2} b
* @returns {Vec2}
*
* @param {Transform} a
* @param {Transform} b
* @returns {Transform}
*/
Transform.Mul = function(a, b) {
Transform.Assert(a);
if ('x' in b && 'y' in b) {
Vec2.Assert(b)
var x = (a.q.c * b.x - a.q.s * b.y) + a.p.x;
var y = (a.q.s * b.x + a.q.c * b.y) + a.p.y;
return Vec2(x, y);
} else if ('p' in b && 'q' in b) {
Transform.Assert(b);
// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p
// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p
var xf = new Transform();
xf.q = Rot.Mul(a.q, b.q);
xf.p = Vec2.Add(Rot.Mul(a.q, b.p), a.p);
return xf;
}
}
/**
* @param {Transform} a
* @param {Vec2} b
* @returns {Vec2}
*
* @param {Transform} a
* @param {Transform} b
* @returns {Transform}
*/
Transform.MulT = function(a, b) {
Transform.Assert(a);
if ('x' in b && 'y' in b) {
Vec2.Assert(b)
var px = b.x - a.p.x;
var py = b.y - a.p.y;
var x = (a.q.c * px + a.q.s * py);
var y = (-a.q.s * px + a.q.c * py);
return Vec2(x, y);
} else if ('p' in b && 'q' in b) {
Transform.Assert(b);
// v2 = A.q' * (B.q * v1 + B.p - A.p)
// = A.q' * B.q * v1 + A.q' * (B.p - A.p)
var xf = new Transform();
xf.q.Set(Rot.MulT(a.q, b.q));
xf.p.Set(Rot.MulT(a.q, Vec2.Sub(b.p, a.p)));
return xf;
}
}