// Placement via unfolding: each neighbor face is placed adjacent to its BFS // parent by a similarity transform, then shrunk toward its centroid by // DEPTH_SHRINK^depth so depth rings visually separate. // // Returns Map import { regular_polygon_2d, centroid_2d, similarity_transform_2d, apply_transform_2d, } from './geometry.mjs'; const DEPTH_SHRINK = 0.82; export function place_unfold(poly, neighborhood, root_face_index, cx, cy, face_size) { const placements = new Map(); for (const entry of neighborhood) { const fi = entry.face.index; const face = entry.face; const n = face.size; if (entry.parent_index === null) { // Root face: regular polygon centred on canvas. const pts = regular_polygon_2d(n, face_size).map(([x, y]) => [x + cx, y + cy]); placements.set(fi, { vertices_2d: pts, centroid_2d: [cx, cy], depth: 0 }); } else { const parent_pl = placements.get(entry.parent_index); if (!parent_pl) { continue; } const parent_face = poly.faces[entry.parent_index]; const pei = entry.parent_edge_index; const pa = parent_pl.vertices_2d[pei]; const pb = parent_pl.vertices_2d[(pei + 1) % parent_face.size]; // Find which edge of this face leads back to the parent. let nei = -1; for (let j = 0; j < face.edge_neighbors.length; j++) { if (face.edge_neighbors[j] === entry.parent_index) { nei = j; break; } } if (nei === -1) { console.warn(`place_unfold: face ${fi} has no reverse edge to parent ${entry.parent_index}`); continue; } // Winding is opposite: parent (a→b) ≡ neighbor (b→a). const local_pts = regular_polygon_2d(n, 1); const local_a = local_pts[nei]; const local_b = local_pts[(nei + 1) % n]; const transform = similarity_transform_2d(local_a, local_b, pb, pa); let vertices_2d = local_pts.map(pt => apply_transform_2d(transform, pt)); const c = centroid_2d(vertices_2d); // Shrink toward centroid after transform (before would be cancelled by scaling). const shrink = Math.pow(DEPTH_SHRINK, entry.depth); vertices_2d = vertices_2d.map(([x, y]) => [ c[0] + (x - c[0]) * shrink, c[1] + (y - c[1]) * shrink, ]); placements.set(fi, { vertices_2d, centroid_2d: c, depth: entry.depth }); } } return placements; }