/ simulated_instruments / triangle
Sign in
simulated_instruments / triangle
triangle / webapp / src / lib / outline.ts
60 lines · 1.9 KBCodeBlameHistory
96aec9cTriangle strike simulator: MATLAB model and interactive web appJeremy Magland 1// Mirror of ../matlab/triangle_geometry.m: the open-triangle centerline as a
2// polyline in the x-y plane, apex up, gap at the bottom-left corner, running
3// counterclockwise from the free end on the base (arclength fraction 0) to
4// the free end on the left leg (fraction 1). Used by the 3D scene and the
5// mode-shape plot; the physics reads the same geometry from the MATLAB side.
7export interface OutlinePoint {
8 x: number;
9 y: number;
10 tx: number; // unit tangent along increasing arclength
11 ty: number;
14export interface Outline {
15 pts: { x: number; y: number }[]; // A, V3, V1, B
16 segLens: number[];
17 totalLen: number;
18 at(frac: number): OutlinePoint;
21export function triangleOutline(sideLength: number, gapM: number): Outline {
22 const L = sideLength;
23 const g = Math.min(gapM, 0.8 * L);
24 const V1 = { x: 0, y: (L * Math.sqrt(3)) / 2 };
25 const V2 = { x: -L / 2, y: 0 };
26 const V3 = { x: L / 2, y: 0 };
27 const e1 = { x: 1, y: 0 };
28 const e3 = { x: (V2.x - V1.x) / L, y: (V2.y - V1.y) / L };
29 const A = { x: V2.x + (e1.x * g) / 2, y: V2.y + (e1.y * g) / 2 };
30 const B = { x: V2.x - (e3.x * g) / 2, y: V2.y - (e3.y * g) / 2 };
31 const pts = [A, V3, V1, B];
32 const segLens = [L - g / 2, L, L - g / 2];
33 const totalLen = segLens[0] + segLens[1] + segLens[2];
34 return {
35 pts,
36 segLens,
37 totalLen,
38 at(frac: number): OutlinePoint {
39 let s = Math.min(0.999, Math.max(0.001, frac)) * totalLen;
40 for (let k = 0; k < 3; k++) {
41 if (s <= segLens[k] || k === 2) {
42 const a = pts[k];
43 const b = pts[k + 1];
44 const t = Math.min(1, s / segLens[k]);
45 const dx = b.x - a.x;
46 const dy = b.y - a.y;
47 const dl = Math.hypot(dx, dy);
48 return {
49 x: a.x + t * dx,
50 y: a.y + t * dy,
51 tx: dx / dl,
52 ty: dy / dl,
53 };
54 }
55 s -= segLens[k];
56 }
57 throw new Error('unreachable');
58 },
59 };
↑↓ move↵openescclose