UNPKG

@awayfl/awayfl-player

Version:

Flash Player emulator for executing SWF files (published for FP versions 6 and up) in javascript

195 lines (167 loc) 5.48 kB
import { b2Shape } from './b2Shape'; import { b2Transform, b2Vec2, b2Mat22, b2Math } from '../../Common/Math'; import { b2RayCastOutput } from '../b2RayCastOutput'; import { b2RayCastInput } from '../b2RayCastInput'; import { b2AABB } from '../b2AABB'; import { b2MassData } from './b2MassData'; import { b2Settings } from '../../Common/b2Settings'; /** * A circle shape. * @see b2CircleDef */ export class b2CircleShape extends b2Shape { __fast__: boolean = true; public Copy(): b2Shape { const s: b2Shape = new b2CircleShape(); s.Set(this); return s; } public Set(other: b2Shape): void { super.Set(other); if (other instanceof b2CircleShape) { const other2: b2CircleShape = other as b2CircleShape; this.m_p.SetV(other2.m_p); } } /** * @inheritDoc */ public TestPoint(transform: b2Transform, p: b2Vec2): boolean { //b2Vec2 center = transform.position + b2Mul(transform.R, m_p); const tMat: b2Mat22 = transform.R; let dX: number = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); let dY: number = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); //b2Vec2 d = p - center; dX = p.x - dX; dY = p.y - dY; //return b2Dot(d, d) <= m_radius * m_radius; return (dX * dX + dY * dY) <= this.m_radius * this.m_radius; } /** * @inheritDoc */ public RayCast(output: b2RayCastOutput, input: b2RayCastInput, transform: b2Transform): boolean { //b2Vec2 position = transform.position + b2Mul(transform.R, m_p); const tMat: b2Mat22 = transform.R; const positionX: number = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); const positionY: number = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); //b2Vec2 s = input.p1 - position; const sX: number = input.p1.x - positionX; const sY: number = input.p1.y - positionY; //float32 b = b2Dot(s, s) - m_radius * m_radius; const b: number = (sX * sX + sY * sY) - this.m_radius * this.m_radius; /*// Does the segment start inside the circle? if (b < 0.0) { output.fraction = 0; output.hit = e_startsInsideCollide; return; }*/ // Solve quadratic equation. //b2Vec2 r = input.p2 - input.p1; const rX: number = input.p2.x - input.p1.x; const rY: number = input.p2.y - input.p1.y; //float32 c = b2Dot(s, r); const c: number = (sX * rX + sY * rY); //float32 rr = b2Dot(r, r); const rr: number = (rX * rX + rY * rY); const sigma: number = c * c - rr * b; // Check for negative discriminant and short segment. if (sigma < 0.0 || rr < Number.MIN_VALUE) { return false; } // Find the point of intersection of the line with the circle. let a: number = -(c + Math.sqrt(sigma)); // Is the intersection point on the segment? if (0.0 <= a && a <= input.maxFraction * rr) { a /= rr; output.fraction = a; // manual inline of: output.normal = s + a * r; output.normal.x = sX + a * rX; output.normal.y = sY + a * rY; output.normal.Normalize(); return true; } return false; } /** * @inheritDoc */ public ComputeAABB(aabb: b2AABB, transform: b2Transform): void { //b2Vec2 p = transform.position + b2Mul(transform.R, m_p); const tMat: b2Mat22 = transform.R; const pX: number = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); const pY: number = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); aabb.lowerBound.Set(pX - this.m_radius, pY - this.m_radius); aabb.upperBound.Set(pX + this.m_radius, pY + this.m_radius); } /** * @inheritDoc */ public ComputeMass(massData: b2MassData, density: number): void { massData.mass = density * b2Settings.b2_pi * this.m_radius * this.m_radius; massData.center.SetV(this.m_p); // inertia about the local origin //massData.I = massData.mass * (0.5 * m_radius * m_radius + b2Dot(m_p, m_p)); massData.I = massData.mass * (0.5 * this.m_radius * this.m_radius + (this.m_p.x * this.m_p.x + this.m_p.y * this.m_p.y)); } /** * @inheritDoc */ public ComputeSubmergedArea( normal: b2Vec2, offset: number, xf: b2Transform, c: b2Vec2): number { const p: b2Vec2 = b2Math.MulX(xf, this.m_p); const l: number = -(b2Math.Dot(normal, p) - offset); if (l < -this.m_radius + Number.MIN_VALUE) { //Completely dry return 0; } if (l > this.m_radius) { //Completely wet c.SetV(p); return Math.PI * this.m_radius * this.m_radius; } //Magic const r2: number = this.m_radius * this.m_radius; const l2: number = l * l; const area: number = r2 * (Math.asin(l / this.m_radius) + Math.PI / 2) + l * Math.sqrt(r2 - l2); const com: number = -2 / 3 * Math.pow(r2 - l2, 1.5) / area; c.x = p.x + normal.x * com; c.y = p.y + normal.y * com; return area; } /** * Get the local position of this circle in its parent body. */ public GetLocalPosition(): b2Vec2 { return this.m_p; } /** * Set the local position of this circle in its parent body. */ public SetLocalPosition(position: b2Vec2): void { this.m_p.SetV(position); } /** * Get the radius of the circle */ public GetRadius(): number { return this.m_radius; } /** * Set the radius of the circle */ public SetRadius(radius: number): void { this.m_radius = radius; } constructor(radius: number = 0) { super(); this.m_type = b2Shape.e_circleShape; this.m_radius = radius; } // Local position in parent body public m_p: b2Vec2 = new b2Vec2(); }