UNPKG

the-world-engine

Version:

three.js based, unity like game engine for browser

444 lines (411 loc) 14.9 kB
import { b2_epsilon, b2_maxFloat, b2_linearSlop, b2_polygonRadius } from "../common/b2_settings.js"; import { b2Vec2, b2Rot, b2Transform } from "../common/b2_math.js"; import { b2MassData } from "./b2_shape.js"; import { b2Shape, b2ShapeType } from "./b2_shape.js"; export class b2PolygonShape extends b2Shape { constructor() { super(b2ShapeType.e_polygonShape, b2_polygonRadius); this.m_centroid = new b2Vec2(0, 0); this.m_vertices = []; this.m_normals = []; this.m_count = 0; } Clone() { return (new b2PolygonShape).Copy(this); } Copy(e) { super.Copy(e); this.m_centroid.Copy(e.m_centroid); this.m_count = e.m_count; this.m_vertices = b2Vec2.MakeArray(this.m_count); this.m_normals = b2Vec2.MakeArray(this.m_count); for (let t = 0; t < this.m_count; ++t) { this.m_vertices[t].Copy(e.m_vertices[t]); this.m_normals[t].Copy(e.m_normals[t]); } return this; } GetChildCount() { return 1; } Set(...e) { if (typeof e[0][0] === "number") { const t = e[0]; if (t.length % 2 !== 0) { throw new Error; } return this._Set((e => ({ x: t[e * 2], y: t[e * 2 + 1] })), t.length / 2); } else { const t = e[0]; const o = e[1] || t.length; return this._Set((e => t[e]), o); } } _Set(e, t) { if (t < 3) { return this.SetAsBox(1, 1); } let o = t; const s = []; for (let t = 0; t < o; ++t) { const o = e(t); let n = true; for (let e = 0; e < s.length; ++e) { if (b2Vec2.DistanceSquaredVV(o, s[e]) < .5 * b2_linearSlop * (.5 * b2_linearSlop)) { n = false; break; } } if (n) { s.push(o); } } o = s.length; if (o < 3) { return this.SetAsBox(1, 1); } let n = 0; let b = s[0].x; for (let e = 1; e < o; ++e) { const t = s[e].x; if (t > b || t === b && s[e].y < s[n].y) { n = e; b = t; } } const h = []; let c = 0; let i = n; for (;;) { h[c] = i; let e = 0; for (let t = 1; t < o; ++t) { if (e === i) { e = t; continue; } const o = b2Vec2.SubVV(s[e], s[h[c]], b2PolygonShape.Set_s_r); const n = b2Vec2.SubVV(s[t], s[h[c]], b2PolygonShape.Set_s_v); const b = b2Vec2.CrossVV(o, n); if (b < 0) { e = t; } if (b === 0 && n.LengthSquared() > o.LengthSquared()) { e = t; } } ++c; i = e; if (e === n) { break; } } this.m_count = c; this.m_vertices = b2Vec2.MakeArray(this.m_count); this.m_normals = b2Vec2.MakeArray(this.m_count); for (let e = 0; e < c; ++e) { this.m_vertices[e].Copy(s[h[e]]); } for (let e = 0; e < c; ++e) { const t = this.m_vertices[e]; const o = this.m_vertices[(e + 1) % c]; const s = b2Vec2.SubVV(o, t, b2Vec2.s_t0); b2Vec2.CrossVOne(s, this.m_normals[e]).SelfNormalize(); } b2PolygonShape.ComputeCentroid(this.m_vertices, c, this.m_centroid); return this; } SetAsBox(e, t, o, s = 0) { this.m_count = 4; this.m_vertices = b2Vec2.MakeArray(this.m_count); this.m_normals = b2Vec2.MakeArray(this.m_count); this.m_vertices[0].Set(-e, -t); this.m_vertices[1].Set(e, -t); this.m_vertices[2].Set(e, t); this.m_vertices[3].Set(-e, t); this.m_normals[0].Set(0, -1); this.m_normals[1].Set(1, 0); this.m_normals[2].Set(0, 1); this.m_normals[3].Set(-1, 0); this.m_centroid.SetZero(); if (o) { this.m_centroid.Copy(o); const e = new b2Transform; e.SetPosition(o); e.SetRotationAngle(s); for (let t = 0; t < this.m_count; ++t) { b2Transform.MulXV(e, this.m_vertices[t], this.m_vertices[t]); b2Rot.MulRV(e.q, this.m_normals[t], this.m_normals[t]); } } return this; } TestPoint(e, t) { const o = b2Transform.MulTXV(e, t, b2PolygonShape.TestPoint_s_pLocal); for (let e = 0; e < this.m_count; ++e) { const t = b2Vec2.DotVV(this.m_normals[e], b2Vec2.SubVV(o, this.m_vertices[e], b2Vec2.s_t0)); if (t > 0) { return false; } } return true; } ComputeDistance(e, t, o, s) { const n = b2Transform.MulTXV(e, t, b2PolygonShape.ComputeDistance_s_pLocal); let b = -b2_maxFloat; const h = b2PolygonShape.ComputeDistance_s_normalForMaxDistance.Copy(n); for (let e = 0; e < this.m_count; ++e) { const t = b2Vec2.DotVV(this.m_normals[e], b2Vec2.SubVV(n, this.m_vertices[e], b2Vec2.s_t0)); if (t > b) { b = t; h.Copy(this.m_normals[e]); } } if (b > 0) { const t = b2PolygonShape.ComputeDistance_s_minDistance.Copy(h); let s = b * b; for (let e = 0; e < this.m_count; ++e) { const o = b2Vec2.SubVV(n, this.m_vertices[e], b2PolygonShape.ComputeDistance_s_distance); const b = o.LengthSquared(); if (s > b) { t.Copy(o); s = b; } } b2Rot.MulRV(e.q, t, o); o.Normalize(); return Math.sqrt(s); } else { b2Rot.MulRV(e.q, h, o); return b; } } RayCast(e, t, o, s) { const n = b2Transform.MulTXV(o, t.p1, b2PolygonShape.RayCast_s_p1); const b = b2Transform.MulTXV(o, t.p2, b2PolygonShape.RayCast_s_p2); const h = b2Vec2.SubVV(b, n, b2PolygonShape.RayCast_s_d); let c = 0, i = t.maxFraction; let l = -1; for (let e = 0; e < this.m_count; ++e) { const t = b2Vec2.DotVV(this.m_normals[e], b2Vec2.SubVV(this.m_vertices[e], n, b2Vec2.s_t0)); const o = b2Vec2.DotVV(this.m_normals[e], h); if (o === 0) { if (t < 0) { return false; } } else { if (o < 0 && t < c * o) { c = t / o; l = e; } else if (o > 0 && t < i * o) { i = t / o; } } if (i < c) { return false; } } if (l >= 0) { e.fraction = c; b2Rot.MulRV(o.q, this.m_normals[l], e.normal); return true; } return false; } ComputeAABB(e, t, o) { const s = b2Transform.MulXV(t, this.m_vertices[0], e.lowerBound); const n = e.upperBound.Copy(s); for (let e = 0; e < this.m_count; ++e) { const o = b2Transform.MulXV(t, this.m_vertices[e], b2PolygonShape.ComputeAABB_s_v); b2Vec2.MinV(o, s, s); b2Vec2.MaxV(o, n, n); } const b = this.m_radius; s.SelfSubXY(b, b); n.SelfAddXY(b, b); } ComputeMass(e, t) { const o = b2PolygonShape.ComputeMass_s_center.SetZero(); let s = 0; let n = 0; const b = b2PolygonShape.ComputeMass_s_s.Copy(this.m_vertices[0]); const h = 1 / 3; for (let e = 0; e < this.m_count; ++e) { const t = b2Vec2.SubVV(this.m_vertices[e], b, b2PolygonShape.ComputeMass_s_e1); const c = b2Vec2.SubVV(this.m_vertices[(e + 1) % this.m_count], b, b2PolygonShape.ComputeMass_s_e2); const i = b2Vec2.CrossVV(t, c); const l = .5 * i; s += l; o.SelfAdd(b2Vec2.MulSV(l * h, b2Vec2.AddVV(t, c, b2Vec2.s_t0), b2Vec2.s_t1)); const r = t.x; const a = t.y; const p = c.x; const V = c.y; const f = r * r + p * r + p * p; const S = a * a + V * a + V * V; n += .25 * h * i * (f + S); } e.mass = t * s; o.SelfMul(1 / s); b2Vec2.AddVV(o, b, e.center); e.I = t * n; e.I += e.mass * (b2Vec2.DotVV(e.center, e.center) - b2Vec2.DotVV(o, o)); } Validate() { for (let e = 0; e < this.m_count; ++e) { const t = e; const o = (e + 1) % this.m_count; const s = this.m_vertices[t]; const n = b2Vec2.SubVV(this.m_vertices[o], s, b2PolygonShape.Validate_s_e); for (let e = 0; e < this.m_count; ++e) { if (e === t || e === o) { continue; } const b = b2Vec2.SubVV(this.m_vertices[e], s, b2PolygonShape.Validate_s_v); const h = b2Vec2.CrossVV(n, b); if (h < 0) { return false; } } } return true; } SetupDistanceProxy(e, t) { e.m_vertices = this.m_vertices; e.m_count = this.m_count; e.m_radius = this.m_radius; } ComputeSubmergedArea(e, t, o, s) { const n = b2Rot.MulTRV(o.q, e, b2PolygonShape.ComputeSubmergedArea_s_normalL); const b = t - b2Vec2.DotVV(e, o.p); const h = []; let c = 0; let i = -1; let l = -1; let r = false; for (let e = 0; e < this.m_count; ++e) { h[e] = b2Vec2.DotVV(n, this.m_vertices[e]) - b; const t = h[e] < -b2_epsilon; if (e > 0) { if (t) { if (!r) { i = e - 1; c++; } } else { if (r) { l = e - 1; c++; } } } r = t; } switch (c) { case 0: if (r) { const e = b2PolygonShape.ComputeSubmergedArea_s_md; this.ComputeMass(e, 1); b2Transform.MulXV(o, e.center, s); return e.mass; } else { return 0; } case 1: if (i === -1) { i = this.m_count - 1; } else { l = this.m_count - 1; } break; } const a = (i + 1) % this.m_count; const p = (l + 1) % this.m_count; const V = (0 - h[i]) / (h[a] - h[i]); const f = (0 - h[l]) / (h[p] - h[l]); const S = b2PolygonShape.ComputeSubmergedArea_s_intoVec.Set(this.m_vertices[i].x * (1 - V) + this.m_vertices[a].x * V, this.m_vertices[i].y * (1 - V) + this.m_vertices[a].y * V); const y = b2PolygonShape.ComputeSubmergedArea_s_outoVec.Set(this.m_vertices[l].x * (1 - f) + this.m_vertices[p].x * f, this.m_vertices[l].y * (1 - f) + this.m_vertices[p].y * f); let g = 0; const P = b2PolygonShape.ComputeSubmergedArea_s_center.SetZero(); let u = this.m_vertices[a]; let w; let m = a; while (m !== p) { m = (m + 1) % this.m_count; if (m === p) { w = y; } else { w = this.m_vertices[m]; } const e = .5 * ((u.x - S.x) * (w.y - S.y) - (u.y - S.y) * (w.x - S.x)); g += e; P.x += e * (S.x + u.x + w.x) / 3; P.y += e * (S.y + u.y + w.y) / 3; u = w; } P.SelfMul(1 / g); b2Transform.MulXV(o, P, s); return g; } Dump(e) { e(" const shape: b2PolygonShape = new b2PolygonShape();\n"); e(" const vs: b2Vec2[] = [];\n"); for (let t = 0; t < this.m_count; ++t) { e(" vs[%d] = new b2Vec2(%.15f, %.15f);\n", t, this.m_vertices[t].x, this.m_vertices[t].y); } e(" shape.Set(vs, %d);\n", this.m_count); } static ComputeCentroid(e, t, o) { const s = o; s.SetZero(); let n = 0; const b = b2PolygonShape.ComputeCentroid_s_s.Copy(e[0]); const h = 1 / 3; for (let o = 0; o < t; ++o) { const c = b2Vec2.SubVV(e[0], b, b2PolygonShape.ComputeCentroid_s_p1); const i = b2Vec2.SubVV(e[o], b, b2PolygonShape.ComputeCentroid_s_p2); const l = b2Vec2.SubVV(e[(o + 1) % t], b, b2PolygonShape.ComputeCentroid_s_p3); const r = b2Vec2.SubVV(i, c, b2PolygonShape.ComputeCentroid_s_e1); const a = b2Vec2.SubVV(l, c, b2PolygonShape.ComputeCentroid_s_e2); const p = b2Vec2.CrossVV(r, a); const V = .5 * p; n += V; s.x += V * h * (c.x + i.x + l.x); s.y += V * h * (c.y + i.y + l.y); } s.x = 1 / n * s.x + b.x; s.y = 1 / n * s.y + b.y; return s; } } b2PolygonShape.Set_s_r = new b2Vec2; b2PolygonShape.Set_s_v = new b2Vec2; b2PolygonShape.TestPoint_s_pLocal = new b2Vec2; b2PolygonShape.ComputeDistance_s_pLocal = new b2Vec2; b2PolygonShape.ComputeDistance_s_normalForMaxDistance = new b2Vec2; b2PolygonShape.ComputeDistance_s_minDistance = new b2Vec2; b2PolygonShape.ComputeDistance_s_distance = new b2Vec2; b2PolygonShape.RayCast_s_p1 = new b2Vec2; b2PolygonShape.RayCast_s_p2 = new b2Vec2; b2PolygonShape.RayCast_s_d = new b2Vec2; b2PolygonShape.ComputeAABB_s_v = new b2Vec2; b2PolygonShape.ComputeMass_s_center = new b2Vec2; b2PolygonShape.ComputeMass_s_s = new b2Vec2; b2PolygonShape.ComputeMass_s_e1 = new b2Vec2; b2PolygonShape.ComputeMass_s_e2 = new b2Vec2; b2PolygonShape.Validate_s_e = new b2Vec2; b2PolygonShape.Validate_s_v = new b2Vec2; b2PolygonShape.ComputeSubmergedArea_s_normalL = new b2Vec2; b2PolygonShape.ComputeSubmergedArea_s_md = new b2MassData; b2PolygonShape.ComputeSubmergedArea_s_intoVec = new b2Vec2; b2PolygonShape.ComputeSubmergedArea_s_outoVec = new b2Vec2; b2PolygonShape.ComputeSubmergedArea_s_center = new b2Vec2; b2PolygonShape.ComputeCentroid_s_s = new b2Vec2; b2PolygonShape.ComputeCentroid_s_p1 = new b2Vec2; b2PolygonShape.ComputeCentroid_s_p2 = new b2Vec2; b2PolygonShape.ComputeCentroid_s_p3 = new b2Vec2; b2PolygonShape.ComputeCentroid_s_e1 = new b2Vec2; b2PolygonShape.ComputeCentroid_s_e2 = new b2Vec2;