Import v2 base (unchanged files)
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
<!doctype html>
|
||||
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Print Crests — Newbury Exhibit</title>
|
||||
<style>
|
||||
body { font-family:system-ui,sans-serif; margin:0; }
|
||||
.sheet { display:flex; flex-wrap:wrap; gap:8mm; padding:10mm; }
|
||||
.crest { text-align:center; page-break-inside:avoid; }
|
||||
.crest canvas { image-rendering:pixelated; border:0.5mm solid #000; }
|
||||
.crest .cap { font-size:9pt; margin-top:2mm; }
|
||||
@media print { header { display:none } }
|
||||
</style></head>
|
||||
<body>
|
||||
<div id="hdr"></div>
|
||||
<div id="rose" style="padding:8mm 10mm 0"></div>
|
||||
<div class="sheet" id="sheet"></div>
|
||||
|
||||
<script src="/vendor/cv.js"></script>
|
||||
<script src="/vendor/svd.js"></script>
|
||||
<script src="/vendor/posit1.js"></script>
|
||||
<script src="/vendor/aruco.js"></script>
|
||||
<script src="/vendor/dictionaries/aruco_4x4_1000.js"></script>
|
||||
<script type="module">
|
||||
import { requireAuth, styles, nav } from './admin.js';
|
||||
document.getElementById('hdr').innerHTML = nav('print');
|
||||
document.head.insertAdjacentHTML('beforeend', `<style>@media screen {${styles}}</style>`);
|
||||
await requireAuth();
|
||||
|
||||
const scene = await (await fetch('/api/scene')).json();
|
||||
const dic = new AR.Dictionary('ARUCO_4X4_1000');
|
||||
const MM2PX = 96 / 25.4; // CSS px per mm
|
||||
|
||||
const sheet = document.getElementById('sheet');
|
||||
for (const a of scene.anchors) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'crest';
|
||||
const cv = document.createElement('canvas');
|
||||
const bits = 4 + 2; // 4x4 payload + 1-cell black border each side
|
||||
const px = Math.round(a.sizeMM * MM2PX);
|
||||
cv.width = cv.height = bits * 10;
|
||||
cv.style.width = cv.style.height = px + 'px';
|
||||
const ctx = cv.getContext('2d');
|
||||
ctx.fillStyle = '#000'; ctx.fillRect(0, 0, cv.width, cv.height);
|
||||
const code = dic.codeList[a.markerId]; // 16-char '0'/'1' string, row-major
|
||||
ctx.fillStyle = '#fff';
|
||||
for (let y = 0; y < 4; y++) for (let x = 0; x < 4; x++) {
|
||||
if (code[y * 4 + x] === '1') ctx.fillRect((x + 1) * 10, (y + 1) * 10, 10, 10);
|
||||
}
|
||||
div.appendChild(cv);
|
||||
|
||||
// Compass: bearing the print's TOP edge (flat) or FACE (wall) must point.
|
||||
// 0° = N = +Z (back of table), 90° = E = +X, 180° = S (front), 270° = W.
|
||||
const brg = a.mount === 'wall'
|
||||
? ((a.yawDeg % 360) + 360) % 360
|
||||
: (((180 + a.yawDeg) % 360) + 360) % 360;
|
||||
const dirName = ['N','NE','E','SE','S','SW','W','NW'][Math.round(brg / 45) % 8];
|
||||
const rose = document.createElement('canvas');
|
||||
rose.width = rose.height = 120;
|
||||
rose.style.width = rose.style.height = '18mm';
|
||||
const rc = rose.getContext('2d');
|
||||
rc.translate(60, 60);
|
||||
rc.strokeStyle = '#000'; rc.lineWidth = 2;
|
||||
rc.beginPath(); rc.arc(0, 0, 52, 0, 7); rc.stroke();
|
||||
rc.font = 'bold 16px system-ui'; rc.textAlign = 'center'; rc.textBaseline = 'middle'; rc.fillStyle = '#000';
|
||||
rc.fillText('N', 0, -40); rc.font = '12px system-ui';
|
||||
rc.fillText('E', 40, 0); rc.fillText('S', 0, 40); rc.fillText('W', -40, 0);
|
||||
rc.save(); rc.rotate(brg * Math.PI / 180); // needle at target bearing
|
||||
rc.beginPath(); rc.moveTo(0, 10); rc.lineTo(0, -46);
|
||||
rc.lineTo(-6, -34); rc.moveTo(0, -46); rc.lineTo(6, -34);
|
||||
rc.lineWidth = 3; rc.stroke(); rc.restore();
|
||||
rose.style.verticalAlign = 'middle'; rose.style.marginLeft = '3mm';
|
||||
div.appendChild(rose);
|
||||
|
||||
div.insertAdjacentHTML('beforeend',
|
||||
`<div class="cap"><b>Crest #${a.markerId}</b> · ${a.sizeMM} mm · ${a.mount}<br>` +
|
||||
(a.mount === 'wall'
|
||||
? `mount vertically, this way up · print <b>faces ${brg}° ${dirName}</b>`
|
||||
: `lay flat · <b>top edge of print → ${brg}° ${dirName}</b>`) +
|
||||
`<br>pos ${a.position.map(v => v.toFixed(1)).join(', ')} cm</div>`);
|
||||
sheet.appendChild(div);
|
||||
}
|
||||
document.getElementById('rose').innerHTML =
|
||||
`<b>Table compass:</b> N (0°) = +Z, the <u>back</u> of the table · E (90°) = +X, the right ·
|
||||
S (180°) = front · W (270°) = left. Each crest below shows the bearing its arrow must point —
|
||||
align the needle with the table compass and the AR maths will line up exactly.`;
|
||||
|
||||
if (!scene.anchors.length) sheet.innerHTML = '<p style="padding:20px">No anchors in the scene yet — add some in the Layout editor.</p>';
|
||||
</script>
|
||||
</body></html>
|
||||
Reference in New Issue
Block a user