iso.js

1.5 kB · javascript · 47 lines

1// PROJECTION23const RATIO = 0.8660254037844386;45export function project(x, y, z) {6  return [(x - y) * RATIO, (x + y) * 0.5 - z];7}89function fit(faces, frame) {10  let [lx, ly, hx, hy] = [Number.MAX_VALUE, Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE];11  for (const face of faces) {12    for (const p of face.quad) {13      if (p[0] < lx) lx = p[0];14      if (p[1] < ly) ly = p[1];15      if (p[0] > hx) hx = p[0];16      if (p[1] > hy) hy = p[1];17    }18  }19  const sx = Math.max(hx - lx, 1e-9);20  const sy = Math.max(hy - ly, 1e-9);21  const scale = Math.min(frame.w / sx, frame.h / sy);22  const ox = frame.x + (frame.w - sx * scale) / 2;23  const oy = frame.y + (frame.h - sy * scale) / 2;24  return (p) => [ox + (p[0] - lx) * scale, oy + (p[1] - ly) * scale];25}2627// DRAWING2829export function draw(pen, frame, quads, shade, edge) {30  const faces = [];31  for (const { normal, verts } of quads) {32    if (normal.x + normal.y + normal.z <= 0) continue;33    const tone = normal.z > 0 ? 0 : normal.y > 0 ? 1 : 2;34    let depth = 0;35    for (const v of verts) depth += Math.fround(Math.fround(v.x + v.y) + v.z);36    faces.push({ quad: verts.map((v) => project(v.x, v.y, v.z)), tone, depth: depth / 4 });37  }38  if (faces.length === 0) return;39  faces.sort((a, b) => a.depth - b.depth);40  const place = fit(faces, frame);41  const thick = Math.max(Math.min(frame.w, frame.h) / 400, 0.6);42  for (const { quad, tone } of faces) {43    const pts = quad.map(place);44    pen.polygon(pts, shade[tone]);45    if (edge) pen.polyline([...pts, pts[0]], thick, edge);46  }47}