/ tutorials / wave-acoustics
Sign in
tutorials / wave-acoustics
wave-acoustics / src / figures / rooms.tsx
132 lines · 5.6 KBBlameHistoryRaw
1// Figures for Part III: the causal reference of Chapter 7 and the image
2// lattice of Chapter 8.
3import type { ReactElement } from 'react'
4import { Arrowheads, Figure, Label, Node, arrow } from './svg.tsx'
5import { faded, ink, method } from '../plot/palette.ts'
7/** A larger grid, run for fewer steps than it is wide, is exact in the region. */
8export function Causality() {
9 const cx = 250
10 const cy = 132
11 const r = 44
12 const e = 96
13 return (
14 <Figure
15 width={716}
16 height={272}
17 caption="The reference of Chapter 7. The region of interest (solid) sits inside a grid that is larger by M + 2 nodes on every side. In M steps, anything that starts at the outer edge can travel at most M nodes inwards (the shaded band), so it never reaches the region: inside it, the larger grid computes the scheme's free-space solution exactly, whatever happens at its own edges."
18 >
19 <Arrowheads id="cau" colors={[ink.muted, method.boundary]} />
20 <rect x={cx - r - e} y={cy - r - e + 40} width={2 * (r + e)} height={2 * (r + e) - 80} fill="none" stroke={ink.secondary} strokeWidth={1.4} />
21 <rect
22 x={cx - r - e + 4}
23 y={cy - r - e + 44}
24 width={2 * (r + e) - 8}
25 height={2 * (r + e) - 88}
26 fill="none"
27 stroke={faded(method.boundary, 0.55)}
28 strokeWidth={30}
29 opacity={0.5}
30 />
31 <rect x={cx - r} y={cy - r} width={2 * r} height={2 * r} fill={faded(method.fd2, 0.82)} stroke={method.fd2} strokeWidth={2} />
32 <Node x={cx - 12} y={cy + 4} r={4} fill={method.waveguide} />
33 <Label x={cx} y={cy - r + 14} size={11} fill={ink.primary}>
34 region
35 </Label>
36 <line x1={cx + r + 2} y1={cy + 24} x2={cx + r + e - 2} y2={cy + 24} stroke={ink.muted} strokeWidth={1.2} markerStart={arrow('cau', 0)} markerEnd={arrow('cau', 0)} />
37 <Label x={cx + r + e / 2} y={cy + 38} size={11} fill={ink.muted}>
38 M + 2 nodes
39 </Label>
40 <line x1={cx + r + e - 4} y1={cy - 28} x2={cx + r + e - 30} y2={cy - 28} stroke={method.boundary} strokeWidth={1.6} markerEnd={arrow('cau', 1)} />
41 <Label x={470} y={96} size={11.5} fill={ink.secondary} anchor="start">
42 after M steps, the influence of the
43 </Label>
44 <Label x={470} y={112} size={11.5} fill={ink.secondary} anchor="start">
45 outer edge reaches at most M nodes in
46 </Label>
47 <Label x={470} y={148} size={11.5} fill={method.fd2} anchor="start">
48 the region never feels it: its
49 </Label>
50 <Label x={470} y={164} size={11.5} fill={method.fd2} anchor="start">
51 values are the free-space ones
52 </Label>
53 </Figure>
54 )
57/** The mirror rooms and image sources of a rectangular room, in plan. */
58export function Images() {
59 const W = 120
60 const H = 72
61 const ox = 358 - 1.5 * W
62 const oy = 20
63 const xs = 0.3
64 const ys = 0.62
65 const xr = 0.72
66 const yr = 0.3
67 const rooms: ReactElement[] = []
68 const imgs: ReactElement[] = []
69 let chosen: [number, number] = [0, 0]
70 for (let a = -1; a <= 1; a++) {
71 for (let b = -1; b <= 1; b++) {
72 const x = ox + (a + 1) * W
73 const y = oy + (b + 1) * H
74 rooms.push(
75 <rect
76 key={`r${a}${b}`}
77 x={x}
78 y={y}
79 width={W}
80 height={H}
81 fill={a === 0 && b === 0 ? faded(method.fd2, 0.85) : 'none'}
82 stroke={a === 0 && b === 0 ? ink.secondary : ink.axis}
83 strokeWidth={a === 0 && b === 0 ? 2 : 1}
84 />,
85 )
86 // the image in room (a, b) is mirrored once for every odd index
87 const fx = a % 2 === 0 ? xs : 1 - xs
88 const fy = b % 2 === 0 ? ys : 1 - ys
89 const px = x + fx * W
90 const py = y + fy * H
91 if (a === 1 && b === 0) chosen = [px, py]
92 imgs.push(
93 <Node
94 key={`i${a}${b}`}
95 x={px}
96 y={py}
97 r={a === 0 && b === 0 ? 5 : 4}
98 fill={a === 0 && b === 0 ? method.waveguide : faded(method.waveguide, 0.35)}
99 />,
100 )
101 }
102 }
103 const R: [number, number] = [ox + W + xr * W, oy + H + yr * H]
104 const S: [number, number] = [ox + W + xs * W, oy + H + ys * H]
105 // the path from the image in the right-hand room crosses the shared wall
106 const wx = ox + 2 * W
107 const t = (wx - chosen[0]) / (R[0] - chosen[0])
108 const hitY = chosen[1] + t * (R[1] - chosen[1])
109 return (
110 <Figure
111 width={716}
112 height={262}
113 caption="Image sources, in plan. The real room is in the middle, with its source (orange) and listener (white). Each neighbouring room is its mirror image in a wall, with a mirror-image source in it. The straight line from the image on the right to the listener (dashed) crosses the shared wall exactly where the real reflected path (solid) bounces off it, and has the same length; so the reflection arrives when, and as strongly as, sound from the image would, times the wall's reflection factor."
114 >
115 {rooms}
116 {imgs}
117 <line x1={chosen[0]} y1={chosen[1]} x2={R[0]} y2={R[1]} stroke={method.boundary} strokeWidth={1.4} strokeDasharray="5 4" />
118 <path d={`M${S[0]} ${S[1]}L${wx} ${hitY}L${R[0]} ${R[1]}`} fill="none" stroke={method.boundary} strokeWidth={2} />
119 <line x1={S[0]} y1={S[1]} x2={R[0]} y2={R[1]} stroke={faded(ink.node, 0.4)} strokeWidth={1.4} />
120 <Node x={R[0]} y={R[1]} r={5} fill={ink.node} />
121 <Label x={S[0] - 8} y={S[1] + 14} size={11} fill={method.waveguide} anchor="end">
122 source
123 </Label>
124 <Label x={R[0] - 4} y={R[1] - 12} size={11} fill={ink.secondary} anchor="middle">
125 listener
126 </Label>
127 <Label x={chosen[0] + 8} y={chosen[1] + 16} size={11} fill={faded(method.waveguide, 0.1)} anchor="start">
128 image
129 </Label>
130 </Figure>
131 )
↑↓ move↵openescclose