@awayfl/awayfl-player
Version:
Flash Player emulator for executing SWF files (published for FP versions 6 and up) in javascript
217 lines (181 loc) • 8.05 kB
text/typescript
/*
* 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 { b2Mat22, b2Vec2, b2XForm } from "../../Common/Math";
import { b2Settings } from "../../Common/b2Settings";
import { b2Segment } from "../b2Segment";
import { b2ConcaveArcDef } from "./b2ConcaveArcDef";
import { b2MassData } from "./b2MassData";
import { b2PolygonShape } from "./b2PolygonShape";
import { b2Shape } from "./b2Shape";
import { b2ShapeDef } from "./b2ShapeDef";
///A polygon with a circle subtracted from it.
///It works exactly the same as b2PolyShape, except the edge from vertex 0 to vertex 1 is a concave arc,
///with radius given by the radius property. The diameter should be longer than the distance between the
///vertices, and the rest of the polygonal shape should be large enough to enclose the resulting curve (this is not checked).
export class b2ConcaveArcShape extends b2PolygonShape
{
/// @see b2Shape::TestPoint
public TestPoint(xf:b2XForm, p:b2Vec2) : boolean{
//b2Vec2 pLocal = b2MulT(xf.R, p - xf.position);
var tMat:b2Mat22 = xf.R;
var tX:number = p.x - xf.position.x;
var tY:number = p.y - xf.position.y;
var pLocalX:number = (tX*tMat.col1.x + tY*tMat.col1.y);
var pLocalY:number = (tX*tMat.col2.x + tY*tMat.col2.y);
for (var i:number /** uint */ = 0; i < this.m_vertexCount; ++i)
{
//float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);
var tVec:b2Vec2 = this.m_vertices[i];
tX = pLocalX - tVec.x;
tY = pLocalY - tVec.y;
var dot:number = (tVec.x * tX + tVec.y * tY);
if (dot > 0.0)
{
return false;
}
}
tX = pLocalX - this.m_arcCenter.x;
tY = pLocalY - this.m_arcCenter.y;
return (tX*tX+tY*tY)>this.m_radius2;
}
/// @see b2Shape::TestSegment
public TestSegment( xf:b2XForm,
lambda:number[], // float ptr
normal:b2Vec2, // ptr
segment:b2Segment,
maxLambda:number) : boolean
{
b2Settings.b2Assert(false);
return false;
}
/// @see b2Shape::ComputeMass
public ComputeMass(massData:b2MassData) : void{
/*var polyMass:b2MassData = new b2MassData();
var triMass:b2MassData = new b2MassData();
var segMass:b2MassData = new b2MassData();
super.ComputeMass(polyMass);
if(m_dot > Number.MIN_VALUE)
TriangleMass(triMass, m_vertices[0], m_arcCenter, m_vertices[1], m_density);
SegmentMass(segMass, m_arcCenter, m_radius, m_normals[0].Negative(), m_norm*m_radius*2, -m_density);
//massData=polyMass+triMass+segMass
massData.Set(b2MassData.Add(polyMass,triMass,segMass));*/
super.ComputeMass(massData);
}
//--------------- Internals Below -------------------
constructor(def:b2ShapeDef){
super(def);
var arcDef:b2ConcaveArcDef = def as b2ConcaveArcDef;
this.m_radius = arcDef.radius;
this.m_radius2 = this.m_radius*this.m_radius;
var p1:b2Vec2 = this.m_vertices[0];
var p2:b2Vec2 = this.m_vertices[1];
//Find the point at m_radius from p1 and p2;
var dx:number = p1.x-p2.x;
var dy:number = p1.y-p2.y;
var d2:number = dx*dx+dy*dy;
var d:number=Math.sqrt(d2);
if(d2/4 > this.m_radius2){
//Increase radius to fit the edge it is replacing
this.m_radius2 = d2/4;
this.m_radius = d/2;
}
var dot:number = Math.sqrt(this.m_radius2-d2*.25);//The perp distance from p1p2 to m_arcCenter
this.m_arcCenter = new b2Vec2( (p1.x+p2.x)/2+dot*this.m_normals[0].x, (p1.y+p2.y)/2+dot*this.m_normals[0].y );
this.m_dot=dot/this.m_radius;
this.m_norm=d/2/this.m_radius;
//Adjust core vertices so that the core curved edge is of radius m_radius+b2Settings.b2_toiSlop, from core vertex 0 to core vertex 1, and with the same center
var coreRadius2: number = (this.m_radius+b2Settings.b2_toiSlop)*(this.m_radius+b2Settings.b2_toiSlop);
var nx:number,ny:number;
//Vertex 0
nx=this.m_normals[this.m_vertexCount-1].x;
ny=this.m_normals[this.m_vertexCount-1].y;
dx=this.m_coreVertices[0].x-this.m_arcCenter.x;
dy=this.m_coreVertices[0].y-this.m_arcCenter.y;
d=dx*nx+dy*ny;
d2=Math.sqrt(coreRadius2-d*d);
this.m_coreVertices[0].x=this.m_arcCenter.x+d*nx+d2*ny;
this.m_coreVertices[0].y=this.m_arcCenter.y+d*ny-d2*nx;
//Vertex 1
nx=this.m_normals[1].x;
ny=this.m_normals[1].y;
dx=this.m_coreVertices[1].x-this.m_arcCenter.x;
dy=this.m_coreVertices[1].y-this.m_arcCenter.y;
d=dx*nx+dy*ny;
d2=Math.sqrt(coreRadius2-d*d);
this.m_coreVertices[1].x=this.m_arcCenter.x+d*nx-d2*ny;
this.m_coreVertices[1].y=this.m_arcCenter.y+d*ny+d2*nx;
this.m_type = b2Shape.e_concaveArcShape;
}
//Calculate the mass of a segment of a circle
//arcCenter, radius defines the circle
//norm defines the reverse direction of the segment
//d is the distance between the two vertices on the perimeter
//See the code for the relationship between d and theta, the angle of the segment.
public static SegmentMass(massData:b2MassData, arcCenter:b2Vec2, radius:number, norm:b2Vec2, d:number, density:number): void
{
//var theta:number = Math.acos(dot / radius) * 2;
var theta:number = Math.asin(d / radius / 2) * 2;
massData.mass = 0.5 * radius * radius * theta * density;
var v:number = 2/3 * d / theta;
if(theta < Number.MIN_VALUE) v=2/3*radius;
massData.center = new b2Vec2(arcCenter.x - norm.x*v, arcCenter.y - norm.y*v);
massData.I = 0.5 * massData.mass * radius * radius - massData.mass * v * v;
}
public static TriangleMass(massData:b2MassData, p1:b2Vec2, p2:b2Vec2, p3:b2Vec2, density:number): void
{
var k_inv3:number = 1.0 / 3.0;
//b2Vec2 e1 = p2 - p1;
var e1X:number = p2.x - p1.x;
var e1Y:number = p2.y - p1.y;
//b2Vec2 e2 = p3 - p1;
var e2X:number = p3.x - p1.x;
var e2Y:number = p3.y - p1.y;
//float32 D = b2Cross(e1, e2);
var D: number = e1X * e2Y - e1Y * e2X;
//float32 triangleArea = 0.5f * D;
var triangleArea:number = 0.5 * D;
//area += triangleArea;
massData.mass = triangleArea * density;
// Area weighted centroid
//center += triangleArea * k_inv3 * (p1 + p2 + p3);
//centerX += triangleArea * k_inv3 * (p1X + p2.x + p3.x);
//centerY += triangleArea * k_inv3 * (p1Y + p2.y + p3.y);
massData.center.x = k_inv3 * (p1.x + p2.x + p3.x);
massData.center.y = k_inv3 * (p1.y + p2.y + p3.y);
//float32 px = p1.x, py = p1.y;
var px:number = p1.x;
var py:number = p1.y;
//float32 ex1 = e1.x, ey1 = e1.y;
var ex1:number = e1X;
var ey1:number = e1Y;
//float32 ex2 = e2.x, ey2 = e2.y;
var ex2:number = e2X;
var ey2:number = e2Y;
//float32 intx2 = k_inv3 * (0.25f * (ex1*ex1 + ex2*ex1 + ex2*ex2) + (px*ex1 + px*ex2)) + 0.5f*px*px;
var intx2:number = k_inv3 * (0.25 * (ex1*ex1 + ex2*ex1 + ex2*ex2) + (px*ex1 + px*ex2)) + 0.5*px*px;
//float32 inty2 = k_inv3 * (0.25f * (ey1*ey1 + ey2*ey1 + ey2*ey2) + (py*ey1 + py*ey2)) + 0.5f*py*py;
var inty2:number = k_inv3 * (0.25 * (ey1*ey1 + ey2*ey1 + ey2*ey2) + (py*ey1 + py*ey2)) + 0.5*py*py;
//I += D * (intx2 + inty2);
massData.I = D * (intx2 + inty2) * density;
}
public m_arcCenter:b2Vec2;
public m_norm:number;//=sin(theta/2) for theta the angle of the arc
public m_dot:number;//=cos(theta/2) for theta the angle of the arc
public m_radius:number;
public m_radius2:number;//=m_radius*m_radius. Flash Only: In C++ we should calculate this each time
}