eyeling 1.16.3 → 1.16.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +0 -1
  2. package/package.json +2 -3
  3. package/arctifacts/README.md +0 -59
  4. package/arctifacts/ackermann.html +0 -678
  5. package/arctifacts/auroracare.html +0 -1297
  6. package/arctifacts/bike-trip.html +0 -752
  7. package/arctifacts/binomial-theorem.html +0 -631
  8. package/arctifacts/bmi.html +0 -511
  9. package/arctifacts/building-performance.html +0 -750
  10. package/arctifacts/clinical-care.html +0 -726
  11. package/arctifacts/collatz.html +0 -403
  12. package/arctifacts/complex.html +0 -321
  13. package/arctifacts/control-system.html +0 -482
  14. package/arctifacts/delfour.html +0 -849
  15. package/arctifacts/earthquake-epicenter.html +0 -982
  16. package/arctifacts/eco-route.html +0 -662
  17. package/arctifacts/euclid-infinitude.html +0 -564
  18. package/arctifacts/euler-identity.html +0 -667
  19. package/arctifacts/exoplanet-transit.html +0 -1000
  20. package/arctifacts/faltings-theorem.html +0 -1046
  21. package/arctifacts/fibonacci.html +0 -299
  22. package/arctifacts/fundamental-theorem-arithmetic.html +0 -398
  23. package/arctifacts/godel-numbering.html +0 -743
  24. package/arctifacts/gps-bike.html +0 -759
  25. package/arctifacts/gps-clinical-bench.html +0 -792
  26. package/arctifacts/graph-french.html +0 -449
  27. package/arctifacts/grass-molecular.html +0 -592
  28. package/arctifacts/group-theory.html +0 -740
  29. package/arctifacts/health-info.html +0 -833
  30. package/arctifacts/kaprekar-constant.html +0 -576
  31. package/arctifacts/lee.html +0 -805
  32. package/arctifacts/linked-lists.html +0 -502
  33. package/arctifacts/lldm.html +0 -612
  34. package/arctifacts/matrix-multiplication.html +0 -502
  35. package/arctifacts/matrix.html +0 -651
  36. package/arctifacts/newton-raphson.html +0 -944
  37. package/arctifacts/peano-factorial.html +0 -456
  38. package/arctifacts/pi.html +0 -363
  39. package/arctifacts/polynomial.html +0 -646
  40. package/arctifacts/prime.html +0 -366
  41. package/arctifacts/pythagorean-theorem.html +0 -468
  42. package/arctifacts/rest-path.html +0 -469
  43. package/arctifacts/roots-of-unity.html +0 -363
  44. package/arctifacts/turing.html +0 -409
  45. package/arctifacts/wind-turbines.html +0 -726
@@ -1,612 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>Leg Length Discrepancy Measurement</title>
7
- <style>
8
- :root {
9
- --bg: #f8fafc;
10
- --fg: #0f172a;
11
- --muted: #475569;
12
- --soft: #e2e8f0;
13
- --card: #ffffff;
14
- --accent: #0ea5e9;
15
- --accent2: #ef4444;
16
- --accent3: #22c55e;
17
- --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;
18
- --sans:
19
- ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans',
20
- 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
21
- }
22
- html,
23
- body {
24
- height: 100%;
25
- }
26
- body {
27
- margin: 0;
28
- background: var(--bg);
29
- color: var(--fg);
30
- font: 16px/1.5 var(--sans);
31
- }
32
- .wrap {
33
- max-width: 960px;
34
- margin: 28px auto;
35
- padding: 0 16px;
36
- }
37
- header {
38
- margin-bottom: 16px;
39
- }
40
- h1 {
41
- font-size: 22px;
42
- font-weight: 700;
43
- margin: 0 0 4px;
44
- }
45
- .sub {
46
- color: var(--muted);
47
- font-size: 14px;
48
- }
49
- .card {
50
- background: var(--card);
51
- border: 1px solid var(--soft);
52
- border-radius: 14px;
53
- padding: 16px;
54
- margin: 14px 0;
55
- box-shadow: 0 6px 16px rgba(15, 23, 42, 0.06);
56
- }
57
- .inputs {
58
- display: grid;
59
- grid-template-columns: repeat(4, minmax(0, 1fr));
60
- gap: 10px;
61
- }
62
- label {
63
- font-size: 12px;
64
- color: var(--muted);
65
- display: block;
66
- margin-bottom: 6px;
67
- }
68
- input[type='number'] {
69
- width: 100%;
70
- box-sizing: border-box;
71
- background: #fff;
72
- color: var(--fg);
73
- border: 1px solid var(--soft);
74
- border-radius: 10px;
75
- padding: 8px 10px;
76
- font: 14px var(--mono);
77
- }
78
- button {
79
- appearance: none;
80
- border: 0;
81
- background: var(--accent);
82
- color: #fff;
83
- font-weight: 700;
84
- padding: 10px 14px;
85
- border-radius: 12px;
86
- cursor: pointer;
87
- }
88
- .btn-row {
89
- display: flex;
90
- gap: 10px;
91
- align-items: center;
92
- flex-wrap: wrap;
93
- margin-top: 12px;
94
- }
95
- .hint {
96
- color: var(--muted);
97
- font-size: 12px;
98
- }
99
-
100
- h2 {
101
- font-size: 18px;
102
- margin: 6px 0 10px;
103
- }
104
- pre {
105
- font: 14px/1.5 var(--mono);
106
- background: #fff;
107
- border: 1px solid var(--soft);
108
- border-radius: 12px;
109
- padding: 12px;
110
- overflow: auto;
111
- }
112
- code {
113
- font-family: var(--mono);
114
- background: #fff;
115
- border: 1px solid var(--soft);
116
- padding: 2px 6px;
117
- border-radius: 8px;
118
- }
119
- .answer {
120
- padding: 12px;
121
- border: 1px solid var(--soft);
122
- border-radius: 12px;
123
- background: #fff;
124
- }
125
- .answer pre {
126
- margin: 0;
127
- border: 0;
128
- }
129
-
130
- /* Archived image panel (no internal scrollbars) */
131
- .img-panel {
132
- position: relative;
133
- border: 1px solid var(--soft);
134
- border-radius: 12px;
135
- overflow: hidden;
136
- background: #fff;
137
- }
138
- .img-panel img {
139
- display: block;
140
- width: 100%;
141
- height: auto;
142
- }
143
- .annos {
144
- position: absolute;
145
- inset: 0;
146
- pointer-events: none;
147
- }
148
- .callout {
149
- position: absolute;
150
- background: #ffffffcc;
151
- border: 1px solid var(--soft);
152
- border-radius: 10px;
153
- padding: 8px 10px;
154
- font: 13px var(--mono);
155
- color: var(--fg);
156
- pointer-events: auto;
157
- }
158
- .callout .hd {
159
- font-weight: 700;
160
- margin-bottom: 4px;
161
- }
162
-
163
- table {
164
- width: 100%;
165
- border-collapse: collapse;
166
- font: 14px var(--mono);
167
- background: #fff;
168
- border: 1px solid var(--soft);
169
- border-radius: 12px;
170
- overflow: hidden;
171
- }
172
- th,
173
- td {
174
- padding: 8px 10px;
175
- border-bottom: 1px solid var(--soft);
176
- text-align: left;
177
- }
178
- tr:last-child td {
179
- border-bottom: 0;
180
- }
181
- .ok {
182
- color: #16a34a;
183
- font-weight: 700;
184
- }
185
- .bad {
186
- color: #dc2626;
187
- font-weight: 700;
188
- }
189
- </style>
190
- </head>
191
- <body>
192
- <div class="wrap">
193
- <header>
194
- <h1>Leg Length Discrepancy Measurement</h1>
195
- <div class="sub">
196
- Leg-Length Discrepancy Measurement (LLDM) by orthogonal projection onto pelvic baseline L1.
197
- </div>
198
- </header>
199
-
200
- <section class="card">
201
- <h2>Landmarks (cm)</h2>
202
- <div class="inputs">
203
- <div><label for="p1x">p1x</label><input id="p1x" type="number" step="0.1" value="10.1" /></div>
204
- <div><label for="p1y">p1y</label><input id="p1y" type="number" step="0.1" value="7.8" /></div>
205
- <div><label for="p2x">p2x</label><input id="p2x" type="number" step="0.1" value="45.1" /></div>
206
- <div><label for="p2y">p2y</label><input id="p2y" type="number" step="0.1" value="5.6" /></div>
207
- <div><label for="p3x">p3x</label><input id="p3x" type="number" step="0.1" value="3.6" /></div>
208
- <div><label for="p3y">p3y</label><input id="p3y" type="number" step="0.1" value="29.8" /></div>
209
- <div><label for="p4x">p4x</label><input id="p4x" type="number" step="0.1" value="54.7" /></div>
210
- <div><label for="p4y">p4y</label><input id="p4y" type="number" step="0.1" value="28.5" /></div>
211
- </div>
212
- <div class="btn-row">
213
- <button id="run">Compute</button>
214
- <span class="hint"
215
- >Rounding to 4 decimals; internal math in full precision. Slope convention:
216
- <span class="mono">cL3 = -(-1/cL1)</span>.</span
217
- >
218
- </div>
219
- </section>
220
-
221
- <section class="card">
222
- <h2>Answer</h2>
223
- <div class="answer"><pre id="answerTxt"></pre></div>
224
- </section>
225
-
226
- <section class="card">
227
- <h2>Reason why</h2>
228
- <pre id="trace"></pre>
229
- </section>
230
-
231
- <section class="card">
232
- <h2>Figure (photo with annotations)</h2>
233
- <div class="img-panel">
234
- <img
235
- src="https://web.archive.org/web/20110103134005im_/http://www.agfa.com/w3c/2002/10/medicad/op/lldmD.jpg"
236
- alt="LLDM illustration (archived Agfa page)" />
237
- <div class="annos">
238
- <div class="callout" style="top: 14px; left: 14px; max-width: 320px">
239
- <div class="hd">Computed results</div>
240
- <div class="mono" id="callNumbers">d53=?, d64=?, dCm=?</div>
241
- <div class="mono" id="callAlarm">LLDAlarm: ?</div>
242
- </div>
243
- <div class="callout" style="bottom: 14px; right: 14px; max-width: 360px">
244
- <div class="hd">Notes</div>
245
- <div>Values overlay the image. Landmarks drive the math.</div>
246
- </div>
247
- </div>
248
- </div>
249
- </section>
250
-
251
- <section class="card">
252
- <h2>Check (harness)</h2>
253
- <p class="hint">
254
- Each line: <code>p1x,p1y,p2x,p2y,p3x,p3y,p4x,p4y[,expected_dCm[,expected_alarm]]</code>. Expected columns are
255
- optional; when present they’re validated (|Δ| &lt; 0.001 cm).
256
- </p>
257
- <pre id="cases" contenteditable="true"></pre>
258
- <div style="display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 8px">
259
- <button id="runChecks">Run checks</button>
260
- <button id="addRow">Add current landmarks</button>
261
- <button id="clearRows" style="background: #64748b">Clear</button>
262
- </div>
263
- <div id="checkTableWrap" style="margin-top: 10px"></div>
264
- </section>
265
- </div>
266
-
267
- <script>
268
- (function () {
269
- const EN_DASH = '–';
270
- const fmt = (num, dec = 4, width = 7) => {
271
- const sgn = num >= 0 ? '+' : EN_DASH;
272
- const mag = Math.abs(num).toFixed(dec);
273
- return (sgn + mag).padStart(width + dec + 2, ' ');
274
- };
275
- const line1 = (buf, step, lhs, rhs) => buf.push(`Step ${String(step).padStart(2, '0')} ${lhs} = ${rhs}`);
276
- const cont = (buf, expr) => buf.push(` = ${expr}`);
277
- const sep = (buf) => buf.push('─'.repeat(76));
278
-
279
- function compute(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) {
280
- let step = 1,
281
- out = [];
282
- // Deltas
283
- const dx12 = p1x - p2x;
284
- const dy12 = p1y - p2y;
285
- const dy13 = p1y - p3y;
286
- const dy24 = p2y - p4y;
287
- line1(out, step, 'dx12Cm', 'p1x − p2x');
288
- cont(out, `${p1x} − ${p2x}`);
289
- cont(out, `${fmt(dx12)} cm`);
290
- step++;
291
- line1(out, step, 'dy12Cm', 'p1y − p2y');
292
- cont(out, `${p1y} − ${p2y}`);
293
- cont(out, `${fmt(dy12)} cm`);
294
- step++;
295
- line1(out, step, 'dy13Cm', 'p1y − p3y');
296
- cont(out, `${p1y} − ${p3y}`);
297
- cont(out, `${fmt(dy13)} cm`);
298
- step++;
299
- line1(out, step, 'dy24Cm', 'p2y − p4y');
300
- cont(out, `${p2y} − ${p4y}`);
301
- cont(out, `${fmt(dy24)} cm`);
302
- step++;
303
- sep(out);
304
-
305
- // Slopes
306
- const cL1 = dy12 / dx12;
307
- const dL3m = -1 / cL1;
308
- const cL3 = -dL3m;
309
- line1(out, step, 'cL1 ', 'dy12 / dx12');
310
- cont(out, `${fmt(dy12)} / ${fmt(dx12)}`);
311
- cont(out, `${fmt(cL1, 6)}`);
312
- step++;
313
- line1(out, step, 'dL3m', EN_DASH + '1 / cL1');
314
- cont(out, `${EN_DASH}1 / ${fmt(cL1, 6)}`);
315
- cont(out, `${fmt(dL3m, 4)}`);
316
- step++;
317
- line1(out, step, 'cL3 ', EN_DASH + 'dL3m');
318
- cont(out, `${EN_DASH}(${fmt(dL3m, 4)})`);
319
- cont(out, `${fmt(cL3, 4)}`);
320
- step++;
321
- sep(out);
322
-
323
- // m·x items
324
- const pL1x1 = cL1 * p1x,
325
- pL1x2 = cL1 * p2x;
326
- const pL3x3 = cL3 * p3x,
327
- pL3x4 = cL3 * p4x;
328
- line1(out, step, 'pL1x1', 'cL1 · p1x');
329
- cont(out, `${fmt(cL1, 6)} · ${p1x}`);
330
- cont(out, `${fmt(pL1x1)} cm`);
331
- step++;
332
- line1(out, step, 'pL1x2', 'cL1 · p2x');
333
- cont(out, `${fmt(cL1, 6)} · ${p2x}`);
334
- cont(out, `${fmt(pL1x2)} cm`);
335
- step++;
336
- line1(out, step, 'pL3x3', 'cL3 · p3x');
337
- cont(out, `${fmt(cL3, 4)} · ${p3x}`);
338
- cont(out, `${fmt(pL3x3)} cm`);
339
- step++;
340
- line1(out, step, 'pL3x4', 'cL3 · p4x');
341
- cont(out, `${fmt(cL3, 4)} · ${p4x}`);
342
- cont(out, `${fmt(pL3x4)} cm`);
343
- step++;
344
- sep(out);
345
-
346
- // Diagonal helpers
347
- const dd13 = pL1x1 - pL3x3,
348
- ddy13 = dd13 - dy13;
349
- const dd24 = pL1x2 - pL3x4,
350
- ddy24 = dd24 - dy24;
351
- const ddL13 = cL1 - cL3;
352
- line1(out, step, 'dd13Cm', 'pL1x1 − pL3x3');
353
- cont(out, `${fmt(pL1x1)} − ${fmt(pL3x3)}`);
354
- cont(out, `${fmt(dd13)} cm`);
355
- step++;
356
- line1(out, step, 'ddy13Cm', 'dd13Cm − dy13Cm');
357
- cont(out, `${fmt(dd13)} − (${fmt(dy13)})`);
358
- cont(out, `${fmt(ddy13)} cm`);
359
- step++;
360
- line1(out, step, 'dd24Cm', 'pL1x2 − pL3x4');
361
- cont(out, `${fmt(pL1x2)} − ${fmt(pL3x4)}`);
362
- cont(out, `${fmt(dd24)} cm`);
363
- step++;
364
- line1(out, step, 'ddy24Cm', 'dd24Cm − dy24Cm');
365
- cont(out, `${fmt(dd24)} − (${fmt(dy24)})`);
366
- cont(out, `${fmt(ddy24)} cm`);
367
- step++;
368
- line1(out, step, 'ddL13', 'cL1 − cL3');
369
- cont(out, `${fmt(cL1, 6)} − ${fmt(cL3, 4)}`);
370
- cont(out, `${fmt(ddL13)}`);
371
- step++;
372
- sep(out);
373
-
374
- // Feet p5/p6 on L1
375
- const p5x = ddy13 / ddL13;
376
- const dx51 = p5x - p1x;
377
- const p5y = cL1 * dx51 + p1y;
378
- const p6x = ddy24 / ddL13;
379
- const dx62 = p6x - p2x;
380
- const p6y = cL1 * dx62 + p2y;
381
- line1(out, step, 'p5xCm', 'ddy13Cm / ddL13');
382
- cont(out, `${fmt(ddy13)} / ${fmt(ddL13)}`);
383
- cont(out, `${fmt(p5x)} cm`);
384
- step++;
385
- line1(out, step, 'p5yCm', 'cL1·(p5x−p1x)+p1y');
386
- cont(out, `(${fmt(cL1, 6)})(${fmt(dx51)}) + ${p1y}`);
387
- cont(out, `${fmt(p5y)} cm`);
388
- step++;
389
- line1(out, step, 'p6xCm', 'ddy24Cm / ddL13');
390
- cont(out, `${fmt(ddy24)} / ${fmt(ddL13)}`);
391
- cont(out, `${fmt(p6x)} cm`);
392
- step++;
393
- line1(out, step, 'p6yCm', 'cL1·(p6x−p2x)+p2y');
394
- cont(out, `(${fmt(cL1, 6)})(${fmt(dx62)}) + ${p2y}`);
395
- cont(out, `${fmt(p6y)} cm`);
396
- step++;
397
- sep(out);
398
-
399
- // Distances
400
- const dx53 = p5x - p3x,
401
- dy53 = p5y - p3y;
402
- const dx64 = p6x - p4x,
403
- dy64 = p6y - p4y;
404
- const d53 = Math.hypot(dx53, dy53);
405
- const d64 = Math.hypot(dx64, dy64);
406
- line1(out, step, 'd53Cm', '√(dx53² + dy53²)');
407
- cont(out, `√(${fmt(dx53)}² + ${fmt(dy53)}²)`);
408
- cont(out, `${fmt(d53)} cm`);
409
- step++;
410
- line1(out, step, 'd64Cm', '√(dx64² + dy64²)');
411
- cont(out, `√(${fmt(dx64)}² + ${fmt(dy64)}²)`);
412
- cont(out, `${fmt(d64)} cm`);
413
- step++;
414
-
415
- // Discrepancy & alarm
416
- const dCm = d53 - d64;
417
- const alarm = Math.abs(dCm) > 1.25;
418
- line1(out, step, 'dCm ', 'd53 − d64');
419
- cont(out, `${d53.toFixed(4)} − ${d64.toFixed(4)}`);
420
- cont(out, `${fmt(dCm)} cm`);
421
- step++;
422
- line1(out, step, 'LLDAlarm', '|dCm| > 1.25 ?');
423
- cont(out, `|${fmt(dCm)}| > 1.25 → ${alarm}`);
424
- cont(out, `${alarm ? ' 1.000000' : ' 0.000000'}`);
425
-
426
- return {
427
- out: out.join('\n'),
428
- d: { p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y, p5x, p5y, p6x, p6y, d53, d64, dCm, alarm },
429
- };
430
- }
431
-
432
- function renderAnswer(d) {
433
- const sgn = (x) => (x >= 0 ? '+' : EN_DASH) + Math.abs(x).toFixed(4);
434
- return [
435
- 'Answer',
436
- '======',
437
- 'LLDAlarm = |dCm| > 1.25 ?',
438
- ` = |${sgn(d.dCm).padStart(10)}| > 1.25 → ${d.alarm ? 'True' : 'False'}`,
439
- ` = ${(d.alarm ? 1.0 : 0.0).toFixed(6)} # ${d.alarm ? 'Alarm raised: discrepancy exceeds ±1.25 cm' : 'No alarm: within ±1.25 cm'}`,
440
- ].join('\n');
441
- }
442
-
443
- function updateCallouts(d) {
444
- const num = (x) => (x >= 0 ? '+' : EN_DASH) + Math.abs(x).toFixed(4);
445
- document.getElementById('callNumbers').textContent =
446
- `d53=${d.d53.toFixed(4)} cm, d64=${d.d64.toFixed(4)} cm, dCm=${num(d.dCm)} cm`;
447
- document.getElementById('callAlarm').textContent = `LLDAlarm: ${d.alarm ? 'True' : 'False'}`;
448
- }
449
-
450
- function run() {
451
- const val = (id) => parseFloat(document.getElementById(id).value);
452
- const res = compute(
453
- val('p1x'),
454
- val('p1y'),
455
- val('p2x'),
456
- val('p2y'),
457
- val('p3x'),
458
- val('p3y'),
459
- val('p4x'),
460
- val('p4y'),
461
- );
462
- document.getElementById('trace').textContent = res.out;
463
- document.getElementById('answerTxt').textContent = renderAnswer(res.d);
464
- updateCallouts(res.d);
465
- }
466
-
467
- document.getElementById('run').addEventListener('click', run);
468
- run();
469
-
470
- // ---- Harness ----------------------------------------------------
471
- function parseLine(line) {
472
- const parts = line.split(/\s*,\s*/).filter(Boolean);
473
- if (parts.length < 8) return null;
474
- const nums = parts.slice(0, 8).map(parseFloat);
475
- const expDCm = parts[8] !== undefined && parts[8] !== '' ? parseFloat(parts[8]) : null;
476
- const expAlarm = parts[9] !== undefined ? /true/i.test(String(parts[9])) : null;
477
- return { nums, expDCm, expAlarm };
478
- }
479
-
480
- function runChecks() {
481
- const lines = document
482
- .getElementById('cases')
483
- .textContent.split(/\n+/)
484
- .map((s) => s.trim())
485
- .filter(Boolean);
486
- const rows = [];
487
- for (const line of lines) {
488
- const rec = parseLine(line);
489
- if (!rec) continue;
490
- const [p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y] = rec.nums;
491
- const { d } = compute(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y);
492
- const diff = rec.expDCm == null ? null : d.dCm - rec.expDCm;
493
- const passDCm = rec.expDCm == null ? null : Math.abs(diff) < 1e-3; // within 0.001 cm
494
- const passAlarm = rec.expAlarm == null ? null : d.alarm === rec.expAlarm;
495
- rows.push({
496
- p1x,
497
- p1y,
498
- p2x,
499
- p2y,
500
- p3x,
501
- p3y,
502
- p4x,
503
- p4y,
504
- d53: d.d53,
505
- d64: d.d64,
506
- dCm: d.dCm,
507
- alarm: d.alarm,
508
- expDCm: rec.expDCm,
509
- expAlarm: rec.expAlarm,
510
- diff,
511
- passDCm,
512
- passAlarm,
513
- });
514
- }
515
- renderTable(rows);
516
- }
517
-
518
- function renderTable(rows) {
519
- const wrap = document.getElementById('checkTableWrap');
520
- if (!rows.length) {
521
- wrap.innerHTML = '<p class="hint">No rows.</p>';
522
- return;
523
- }
524
- let html =
525
- '<table style="width:100%; border-collapse:collapse; font:14px var(--mono); background:#fff; border:1px solid var(--soft)">' +
526
- '<thead><tr>' +
527
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">p1x</th>' +
528
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">p1y</th>' +
529
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">p2x</th>' +
530
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">p2y</th>' +
531
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">p3x</th>' +
532
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">p3y</th>' +
533
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">p4x</th>' +
534
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">p4y</th>' +
535
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">d53</th>' +
536
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">d64</th>' +
537
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">dCm</th>' +
538
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">|dCm|>1.25</th>' +
539
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">exp dCm</th>' +
540
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">Δ</th>' +
541
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">exp alarm</th>' +
542
- '<th style="text-align:left;padding:8px 10px;border-bottom:1px solid var(--soft)">pass?</th>' +
543
- '</tr></thead><tbody>';
544
- for (const r of rows) {
545
- const pass = (r.passDCm === null || r.passDCm) && (r.passAlarm === null || r.passAlarm);
546
- const cells = [
547
- r.p1x,
548
- r.p1y,
549
- r.p2x,
550
- r.p2y,
551
- r.p3x,
552
- r.p3y,
553
- r.p4x,
554
- r.p4y,
555
- r.d53.toFixed(4),
556
- r.d64.toFixed(4),
557
- r.dCm.toFixed(4),
558
- Math.abs(r.dCm) > 1.25,
559
- r.expDCm == null ? '' : r.expDCm,
560
- r.diff == null ? '' : r.diff.toFixed(4),
561
- r.expAlarm == null ? '' : r.expAlarm,
562
- pass
563
- ? '<span style="color:#16a34a;font-weight:700">OK</span>'
564
- : '<span style="color:#dc2626;font-weight:700">FAIL</span>',
565
- ];
566
- html +=
567
- '<tr>' +
568
- cells.map((x) => `<td style="padding:8px 10px;border-bottom:1px solid var(--soft)">${x}</td>`).join('') +
569
- '</tr>';
570
- }
571
- html += '</tbody></table>';
572
- wrap.innerHTML = html;
573
- }
574
-
575
- // Buttons
576
- document.getElementById('runChecks').addEventListener('click', runChecks);
577
- document.getElementById('addRow').addEventListener('click', () => {
578
- const id = (s) => document.getElementById(s).value;
579
- const line = [id('p1x'), id('p1y'), id('p2x'), id('p2y'), id('p3x'), id('p3y'), id('p4x'), id('p4y')].join(
580
- ',',
581
- );
582
- const pre = document.getElementById('cases');
583
- pre.textContent += (pre.textContent.endsWith('\n') ? '' : '\n') + line + '\n';
584
- });
585
- document.getElementById('clearRows').addEventListener('click', () => {
586
- document.getElementById('cases').textContent = '';
587
- document.getElementById('checkTableWrap').innerHTML = '';
588
- });
589
-
590
- // Seed a few checks and AUTO-RUN them on load
591
- (function seedAndAutoRun() {
592
- const tests = [
593
- [10.1, 7.8, 45.1, 5.6, 3.6, 29.8, 54.7, 28.5], // baseline (page)
594
- [10.1, 7.8, 45.1, 5.6, 3.6, 29.8, 54.7, 29.5], // p4y +1cm
595
- [10.1, 7.8, 45.1, 5.6, 3.6, 28.8, 54.7, 28.5], // p3y -1cm
596
- [10.1, 8.8, 45.1, 5.6, 3.6, 29.8, 54.7, 28.5], // p1y +1cm (tilt L1)
597
- [8.1, 7.8, 47.1, 5.6, 3.6, 29.8, 54.7, 28.5], // widen pelvis
598
- ];
599
- const lines =
600
- tests
601
- .map((t) => {
602
- const { d } = compute(...t);
603
- return t.join(',') + ',' + d.dCm.toFixed(4) + ',' + (Math.abs(d.dCm) > 1.25);
604
- })
605
- .join('\n') + '\n';
606
- document.getElementById('cases').textContent = lines;
607
- runChecks(); // <-- auto-run now
608
- })();
609
- })();
610
- </script>
611
- </body>
612
- </html>