UNPKG

@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
/* * 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 }