// Draws the problem geometry: boundary curve, evaluation points, and the // exact solution's sources. import { useEffect, useRef } from "react"; import type { Laplace2dInstance } from "../../problems/laplace2d/spec"; import { boundaryPoint, evalPoints, maxRadius, sources, } from "../../problems/laplace2d/exact"; function token(name: string): string { return getComputedStyle(document.documentElement).getPropertyValue(name).trim(); } export function DomainView({ inst }: { inst: Laplace2dInstance }) { const canvasRef = useRef(null); // The count varies by instance: 289 normally, and more where a // near-corner or near-boundary set is added. const nEval = evalPoints(inst).length; useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const draw = () => { const size = 360; const dpr = window.devicePixelRatio || 1; canvas.width = size * dpr; canvas.height = size * dpr; canvas.style.width = `${size}px`; canvas.style.height = `${size}px`; const ctx = canvas.getContext("2d"); if (!ctx) return; ctx.scale(dpr, dpr); ctx.clearRect(0, 0, size, size); const extent = maxRadius(inst) + inst.d + 0.25; const s = size / (2 * extent); const X = (x: number) => size / 2 + x * s; const Y = (y: number) => size / 2 - y * s; // domain fill + boundary ctx.beginPath(); const nOutline = 4096; for (let i = 0; i <= nOutline; i++) { const t = (2 * Math.PI * i) / nOutline; const p = boundaryPoint(inst, t); if (i === 0) ctx.moveTo(X(p.x), Y(p.y)); else ctx.lineTo(X(p.x), Y(p.y)); } ctx.closePath(); ctx.fillStyle = token("--surface-2"); ctx.fill(); ctx.strokeStyle = token("--text"); ctx.lineWidth = 2; ctx.stroke(); // evaluation points ctx.fillStyle = token("--text-2"); for (const p of evalPoints(inst)) { ctx.beginPath(); ctx.arc(X(p.x), Y(p.y), 1.4, 0, 2 * Math.PI); ctx.fill(); } // sources ctx.strokeStyle = token("--series-2"); ctx.lineWidth = 2; for (const src of sources(inst)) { const cx = X(src.x); const cy = Y(src.y); ctx.beginPath(); ctx.moveTo(cx - 5, cy - 5); ctx.lineTo(cx + 5, cy + 5); ctx.moveTo(cx - 5, cy + 5); ctx.lineTo(cx + 5, cy - 5); ctx.stroke(); } }; draw(); const mq = window.matchMedia("(prefers-color-scheme: dark)"); mq.addEventListener("change", draw); return () => mq.removeEventListener("change", draw); }, [inst]); return (
The domain, the {nEval} evaluation points where solutions are scored (dots), and the exact solution's sources a distance {inst.d}{" "} outside the boundary (crosses).
); }