matterviz 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/dist/MillerIndexInput.svelte +5 -5
  2. package/dist/api/optimade.js +3 -3
  3. package/dist/brillouin/BrillouinZone.svelte +5 -2
  4. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  5. package/dist/brillouin/BrillouinZoneExportPane.svelte +1 -3
  6. package/dist/brillouin/BrillouinZoneInfoPane.svelte +1 -1
  7. package/dist/brillouin/BrillouinZoneScene.svelte +5 -5
  8. package/dist/brillouin/compute.js +21 -21
  9. package/dist/brillouin/index.d.ts +1 -1
  10. package/dist/brillouin/index.js +0 -1
  11. package/dist/brillouin/types.d.ts +8 -13
  12. package/dist/chempot-diagram/ChemPotDiagram.svelte +3 -3
  13. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +3 -4
  14. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +33 -34
  15. package/dist/chempot-diagram/compute.js +1 -7
  16. package/dist/chempot-diagram/temperature.d.ts +1 -1
  17. package/dist/chempot-diagram/temperature.js +1 -3
  18. package/dist/chempot-diagram/types.d.ts +4 -9
  19. package/dist/colors/index.js +5 -5
  20. package/dist/composition/Composition.svelte +2 -1
  21. package/dist/composition/Formula.svelte +7 -4
  22. package/dist/composition/FormulaFilter.svelte +1 -3
  23. package/dist/composition/format.js +4 -4
  24. package/dist/composition/parse.d.ts +2 -1
  25. package/dist/composition/parse.js +61 -46
  26. package/dist/convex-hull/ConvexHull2D.svelte +62 -51
  27. package/dist/convex-hull/ConvexHull3D.svelte +101 -90
  28. package/dist/convex-hull/ConvexHull4D.svelte +70 -58
  29. package/dist/convex-hull/ConvexHullControls.svelte +24 -35
  30. package/dist/convex-hull/ConvexHullInfoPane.svelte +8 -5
  31. package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +2 -0
  32. package/dist/convex-hull/ConvexHullStats.svelte +9 -2
  33. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +2 -0
  34. package/dist/convex-hull/GasPressureControls.svelte +7 -7
  35. package/dist/convex-hull/StructurePopup.svelte +65 -30
  36. package/dist/convex-hull/StructurePopup.svelte.d.ts +6 -6
  37. package/dist/convex-hull/TemperatureSlider.svelte +8 -5
  38. package/dist/convex-hull/barycentric-coords.d.ts +2 -2
  39. package/dist/convex-hull/barycentric-coords.js +2 -2
  40. package/dist/convex-hull/gas-thermodynamics.js +2 -4
  41. package/dist/convex-hull/helpers.d.ts +13 -2
  42. package/dist/convex-hull/helpers.js +37 -16
  43. package/dist/convex-hull/index.d.ts +1 -0
  44. package/dist/convex-hull/index.js +1 -0
  45. package/dist/convex-hull/thermodynamics.d.ts +2 -1
  46. package/dist/convex-hull/thermodynamics.js +7 -7
  47. package/dist/convex-hull/types.d.ts +15 -15
  48. package/dist/effects.svelte.d.ts +12 -0
  49. package/dist/effects.svelte.js +37 -0
  50. package/dist/element/BohrAtom.svelte +4 -4
  51. package/dist/element/data.json.gz.d.ts +3 -1
  52. package/dist/element/index.d.ts +1 -1
  53. package/dist/element/index.js +0 -1
  54. package/dist/fermi-surface/FermiSurface.svelte +4 -4
  55. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  56. package/dist/fermi-surface/FermiSurfaceControls.svelte +15 -19
  57. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  58. package/dist/fermi-surface/FermiSurfaceScene.svelte +8 -6
  59. package/dist/fermi-surface/compute.js +2 -2
  60. package/dist/fermi-surface/export.js +13 -26
  61. package/dist/fermi-surface/parse.js +8 -12
  62. package/dist/fermi-surface/types.d.ts +2 -5
  63. package/dist/heatmap-matrix/HeatmapMatrix.svelte +21 -3
  64. package/dist/heatmap-matrix/index.js +6 -6
  65. package/dist/io/decompress.d.ts +2 -1
  66. package/dist/io/decompress.js +1 -1
  67. package/dist/io/export.js +1 -1
  68. package/dist/io/index.d.ts +1 -1
  69. package/dist/io/index.js +0 -1
  70. package/dist/io/url-drop.js +7 -1
  71. package/dist/isosurface/IsosurfaceControls.svelte +11 -25
  72. package/dist/isosurface/slice.js +1 -1
  73. package/dist/isosurface/types.js +12 -12
  74. package/dist/labels.d.ts +1 -1
  75. package/dist/labels.js +14 -11
  76. package/dist/layout/InfoTag.svelte +6 -4
  77. package/dist/layout/PropertyFilter.svelte +4 -2
  78. package/dist/layout/json-tree/JsonTree.svelte +22 -14
  79. package/dist/layout/json-tree/JsonValue.svelte +2 -2
  80. package/dist/layout/json-tree/types.d.ts +3 -2
  81. package/dist/layout/json-tree/types.js +0 -1
  82. package/dist/layout/json-tree/utils.d.ts +4 -4
  83. package/dist/layout/json-tree/utils.js +12 -20
  84. package/dist/marching-cubes.js +13 -15
  85. package/dist/math.d.ts +11 -1
  86. package/dist/math.js +15 -6
  87. package/dist/overlays/DragControlTab.svelte +98 -0
  88. package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
  89. package/dist/overlays/DraggablePane.svelte +7 -84
  90. package/dist/overlays/index.d.ts +1 -0
  91. package/dist/overlays/index.js +1 -0
  92. package/dist/periodic-table/PeriodicTable.svelte +11 -11
  93. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +4 -2
  94. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  95. package/dist/phase-diagram/PhaseDiagramControls.svelte +4 -9
  96. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  97. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +2 -10
  98. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +2 -3
  99. package/dist/phase-diagram/TdbInfoPanel.svelte +3 -3
  100. package/dist/phase-diagram/build-diagram.js +11 -18
  101. package/dist/phase-diagram/diagram-input.d.ts +5 -9
  102. package/dist/phase-diagram/index.d.ts +2 -2
  103. package/dist/phase-diagram/index.js +0 -2
  104. package/dist/phase-diagram/parse.d.ts +2 -2
  105. package/dist/phase-diagram/parse.js +6 -10
  106. package/dist/phase-diagram/svg-to-diagram.js +15 -15
  107. package/dist/phase-diagram/types.d.ts +5 -11
  108. package/dist/phase-diagram/utils.d.ts +2 -2
  109. package/dist/phase-diagram/utils.js +9 -11
  110. package/dist/plot/BarPlot.svelte +162 -314
  111. package/dist/plot/BarPlot.svelte.d.ts +5 -4
  112. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  113. package/dist/plot/BinnedScatterPlot.svelte +1114 -0
  114. package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
  115. package/dist/plot/ColorBar.svelte +19 -17
  116. package/dist/plot/ColorBar.svelte.d.ts +1 -1
  117. package/dist/plot/FillArea.svelte +2 -4
  118. package/dist/plot/FillArea.svelte.d.ts +1 -1
  119. package/dist/plot/Histogram.svelte +167 -281
  120. package/dist/plot/Histogram.svelte.d.ts +1 -1
  121. package/dist/plot/HistogramControls.svelte.d.ts +1 -1
  122. package/dist/plot/InteractiveAxisLabel.svelte +5 -3
  123. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
  124. package/dist/plot/PlotAxis.svelte +169 -0
  125. package/dist/plot/PlotAxis.svelte.d.ts +24 -0
  126. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  127. package/dist/plot/ReferenceLine3D.svelte +53 -51
  128. package/dist/plot/ReferencePlane.svelte +39 -42
  129. package/dist/plot/ScatterPlot.svelte +300 -367
  130. package/dist/plot/ScatterPlot.svelte.d.ts +8 -5
  131. package/dist/plot/ScatterPlot3D.svelte +33 -6
  132. package/dist/plot/ScatterPlot3D.svelte.d.ts +3 -2
  133. package/dist/plot/ScatterPlot3DControls.svelte +9 -9
  134. package/dist/plot/ScatterPlotControls.svelte +3 -4
  135. package/dist/plot/ScatterPoint.svelte +18 -27
  136. package/dist/plot/ScatterPoint.svelte.d.ts +4 -3
  137. package/dist/plot/Surface3D.svelte +4 -7
  138. package/dist/plot/ZeroLines.svelte +2 -1
  139. package/dist/plot/ZeroLines.svelte.d.ts +2 -1
  140. package/dist/plot/ZoomRect.svelte +2 -2
  141. package/dist/plot/ZoomRect.svelte.d.ts +3 -3
  142. package/dist/plot/adaptive-density.d.ts +69 -0
  143. package/dist/plot/adaptive-density.js +191 -0
  144. package/dist/plot/auto-place.d.ts +43 -0
  145. package/dist/plot/auto-place.js +122 -0
  146. package/dist/plot/axis-utils.js +3 -5
  147. package/dist/plot/binned-scatter-types.d.ts +59 -0
  148. package/dist/plot/binned-scatter-types.js +1 -0
  149. package/dist/plot/data-cleaning.js +1 -1
  150. package/dist/plot/data-transform.js +1 -1
  151. package/dist/plot/fill-utils.d.ts +4 -9
  152. package/dist/plot/fill-utils.js +29 -44
  153. package/dist/plot/index.d.ts +4 -0
  154. package/dist/plot/index.js +2 -0
  155. package/dist/plot/interactions.d.ts +4 -4
  156. package/dist/plot/interactions.js +4 -3
  157. package/dist/plot/layout.d.ts +20 -2
  158. package/dist/plot/layout.js +59 -16
  159. package/dist/plot/reference-line.d.ts +1 -1
  160. package/dist/plot/reference-line.js +9 -11
  161. package/dist/plot/scales.d.ts +1 -1
  162. package/dist/plot/scales.js +20 -23
  163. package/dist/plot/types.d.ts +30 -58
  164. package/dist/plot/types.js +2 -6
  165. package/dist/plot/utils/label-placement.d.ts +24 -3
  166. package/dist/plot/utils/label-placement.js +82 -12
  167. package/dist/plot/utils/series-visibility.d.ts +8 -2
  168. package/dist/plot/utils/series-visibility.js +23 -5
  169. package/dist/rdf/RdfPlot.svelte +5 -5
  170. package/dist/rdf/calc-rdf.js +3 -3
  171. package/dist/sanitize.d.ts +2 -0
  172. package/dist/sanitize.js +2 -0
  173. package/dist/spectral/Bands.svelte +1 -1
  174. package/dist/spectral/BandsAndDos.svelte +22 -16
  175. package/dist/spectral/BrillouinBandsDos.svelte +20 -16
  176. package/dist/spectral/Dos.svelte +1 -1
  177. package/dist/spectral/helpers.d.ts +4 -2
  178. package/dist/spectral/helpers.js +44 -35
  179. package/dist/spectral/index.d.ts +1 -1
  180. package/dist/spectral/index.js +0 -1
  181. package/dist/structure/AtomLegend.svelte +23 -6
  182. package/dist/structure/AtomLegend.svelte.d.ts +1 -0
  183. package/dist/structure/CanvasTooltip.svelte +9 -9
  184. package/dist/structure/CanvasTooltip.svelte.d.ts +1 -1
  185. package/dist/structure/CellSelect.svelte +14 -16
  186. package/dist/structure/Structure.svelte +317 -68
  187. package/dist/structure/Structure.svelte.d.ts +4 -2
  188. package/dist/structure/StructureControls.svelte +20 -45
  189. package/dist/structure/StructureExportPane.svelte +2 -1
  190. package/dist/structure/StructureInfoPane.svelte +10 -8
  191. package/dist/structure/StructureScene.svelte +527 -177
  192. package/dist/structure/StructureScene.svelte.d.ts +5 -2
  193. package/dist/structure/atom-properties.js +4 -4
  194. package/dist/structure/bond-order-perception.js +115 -98
  195. package/dist/structure/bonding.d.ts +27 -1
  196. package/dist/structure/bonding.js +187 -16
  197. package/dist/structure/export.js +1 -1
  198. package/dist/structure/index.d.ts +3 -2
  199. package/dist/structure/index.js +0 -2
  200. package/dist/structure/parse.js +88 -59
  201. package/dist/symmetry/WyckoffTable.svelte +7 -0
  202. package/dist/symmetry/index.js +13 -14
  203. package/dist/table/HeatmapTable.svelte +45 -66
  204. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  205. package/dist/table/ToggleMenu.svelte +19 -10
  206. package/dist/theme/themes.mjs +12 -0
  207. package/dist/tooltip/index.d.ts +1 -1
  208. package/dist/tooltip/index.js +0 -1
  209. package/dist/trajectory/Trajectory.svelte +43 -15
  210. package/dist/trajectory/TrajectoryInfoPane.svelte +2 -2
  211. package/dist/trajectory/extract.js +1 -1
  212. package/dist/trajectory/frame-reader.js +4 -4
  213. package/dist/trajectory/helpers.d.ts +5 -4
  214. package/dist/trajectory/helpers.js +9 -17
  215. package/dist/trajectory/index.d.ts +2 -2
  216. package/dist/trajectory/index.js +2 -2
  217. package/dist/trajectory/parse/ase.js +4 -4
  218. package/dist/trajectory/parse/hdf5.js +1 -1
  219. package/dist/trajectory/parse/index.js +2 -3
  220. package/dist/trajectory/parse/lammps.js +1 -1
  221. package/dist/trajectory/parse/vasp.js +1 -1
  222. package/dist/trajectory/plotting.d.ts +1 -1
  223. package/dist/trajectory/plotting.js +38 -38
  224. package/dist/trajectory/types.d.ts +1 -1
  225. package/dist/utils.d.ts +1 -0
  226. package/dist/utils.js +9 -0
  227. package/dist/xrd/calc-xrd.js +3 -4
  228. package/dist/xrd/parse.js +1 -1
  229. package/package.json +42 -22
@@ -0,0 +1,169 @@
1
+ <script lang="ts">
2
+ import { format_value } from '../labels'
3
+ import AxisLabel from './AxisLabel.svelte'
4
+ import type { Sides } from './layout'
5
+ import type { AxisConfig } from './types'
6
+ import { DEFAULT_GRID_STYLE } from './types'
7
+
8
+ type Side = `x` | `x2` | `y` | `y2`
9
+
10
+ // Reusable single-axis renderer: baseline, per-tick (grid + tick mark + label), and AxisLabel.
11
+ // One <g class="{side}-axis"> with per-tick <g class="tick">; mirror the structure across all
12
+ // four sides so consumers (ScatterPlot/BarPlot/Histogram/BinnedScatterPlot) share one template.
13
+ let {
14
+ side,
15
+ ticks,
16
+ place,
17
+ axis = {},
18
+ pad,
19
+ width,
20
+ height,
21
+ show_grid = false,
22
+ show_baseline = true,
23
+ tick_label,
24
+ domain,
25
+ unit_on_first_tick = false,
26
+ label_x,
27
+ label_y,
28
+ axis_loading = false,
29
+ on_axis_change,
30
+ }: {
31
+ side: Side
32
+ ticks: number[]
33
+ place: (value: number) => number // data value -> pixel for this axis
34
+ axis?: AxisConfig
35
+ pad: Required<Sides>
36
+ width: number
37
+ height: number
38
+ show_grid?: boolean
39
+ show_baseline?: boolean // axis spine line (ScatterPlot omits it)
40
+ tick_label?: (tick: number) => string | null | undefined // custom/categorical label
41
+ domain?: [number, number] // when set, cull off-plot ticks and hide out-of-domain labels
42
+ unit_on_first_tick?: boolean // append axis.unit after the first tick label (ScatterPlot)
43
+ label_x?: number
44
+ label_y?: number
45
+ axis_loading?: boolean
46
+ on_axis_change?: (key: string) => void
47
+ } = $props()
48
+
49
+ const is_x = $derived(side === `x` || side === `x2`)
50
+ const inside = $derived(axis.tick?.label?.inside ?? false)
51
+ const rotation = $derived(axis.tick?.label?.rotation ?? 0)
52
+ const shift_x = $derived(axis.tick?.label?.shift?.x ?? 0)
53
+ const shift_y = $derived(axis.tick?.label?.shift?.y ?? 0)
54
+ const stroke = $derived(axis.color || `var(--border-color, gray)`)
55
+ const text_fill = $derived(axis.color || `var(--text-color)`)
56
+ const plot_w = $derived(width - pad.l - pad.r)
57
+ const plot_h = $derived(height - pad.b - pad.t)
58
+ const axis_y = $derived(side === `x` ? height - pad.b : pad.t) // baseline y for x/x2
59
+ const axis_x = $derived(side === `y` ? pad.l : width - pad.r) // baseline x for y/y2
60
+
61
+ const show_label = $derived(
62
+ Boolean(axis.label || axis.options?.length) && label_x != null && label_y != null,
63
+ )
64
+
65
+ // Tick-invariant label geometry (depends only on side/inside/rotation/shift)
66
+ const text_x = $derived(
67
+ is_x ? shift_x : (side === `y` ? (inside ? 8 : -8) : (inside ? -8 : 8)) + shift_x,
68
+ )
69
+ const text_y = $derived(
70
+ is_x ? (side === `x` ? (inside ? -8 : 8) : (inside ? 8 : -8)) + shift_y : shift_y,
71
+ )
72
+ const text_anchor = $derived(
73
+ is_x
74
+ ? (rotation === 0
75
+ ? `middle`
76
+ : side === `x`
77
+ ? (inside ? `end` : `start`)
78
+ : (inside ? `start` : `end`)) // x2 rotates opposite to x
79
+ : (side === `y` ? (inside ? `start` : `end`) : (inside ? `end` : `start`)),
80
+ )
81
+ const text_baseline = $derived(
82
+ is_x
83
+ ? (side === `x` ? (inside ? `auto` : `hanging`) : (inside ? `hanging` : `auto`))
84
+ : `central`,
85
+ )
86
+ const text_transform = $derived(
87
+ rotation !== 0 ? `rotate(${rotation}, ${text_x}, ${text_y})` : undefined,
88
+ )
89
+
90
+ // Tick-invariant line geometry within the per-tick group (origin sits on the axis).
91
+ // Keep tick marks' y1="0"/x1="0" explicit: BarPlot's grid test selects `.tick line:not([y1='0'])`.
92
+ const grid_line = $derived(
93
+ is_x
94
+ ? (side === `x` ? { y1: -plot_h, y2: 0 } : { y1: 0, y2: plot_h })
95
+ : (side === `y` ? { x1: 0, x2: plot_w } : { x1: -plot_w, x2: 0 }),
96
+ )
97
+ const tick_mark = $derived(
98
+ is_x
99
+ ? (side === `x`
100
+ ? { y1: 0, y2: inside ? -5 : 5 }
101
+ : { y1: inside ? 0 : -5, y2: inside ? 5 : 0 })
102
+ : (side === `y`
103
+ ? { x1: inside ? 0 : -5, x2: inside ? 5 : 0 }
104
+ : { x1: inside ? -5 : 0, x2: inside ? 0 : 5 }),
105
+ )
106
+
107
+ // ScatterPlot mode: cull ticks whose pixel pos is off-plot and hide labels outside the data domain
108
+ const in_domain = (tick: number): boolean =>
109
+ !domain || (tick >= Math.min(...domain) && tick <= Math.max(...domain))
110
+ const in_plot = (pos: number): boolean =>
111
+ !domain ||
112
+ (is_x ? pos >= pad.l && pos <= width - pad.r : pos >= pad.t && pos <= height - pad.b)
113
+ const tick_text = (tick: number): string =>
114
+ tick_label?.(tick) ?? format_value(tick, axis.format ?? ``)
115
+ </script>
116
+
117
+ <g class="{side}-axis">
118
+ {#if show_baseline}
119
+ {#if is_x}
120
+ <line x1={pad.l} x2={width - pad.r} y1={axis_y} y2={axis_y} {stroke} stroke-width="1" />
121
+ {:else}
122
+ <line x1={axis_x} x2={axis_x} y1={pad.t} y2={height - pad.b} {stroke} stroke-width="1" />
123
+ {/if}
124
+ {/if}
125
+ {#each ticks as tick, idx (tick)}
126
+ {@const pos = place(tick)}
127
+ {#if isFinite(pos) && in_plot(pos)}
128
+ <g class="tick" transform="translate({is_x ? pos : axis_x}, {is_x ? axis_y : pos})">
129
+ {#if show_grid}
130
+ <line {...grid_line} {...DEFAULT_GRID_STYLE} {...axis.grid_style} />
131
+ {/if}
132
+ <line {...tick_mark} {stroke} stroke-width="1" />
133
+ {#if in_domain(tick)}
134
+ <text
135
+ x={text_x}
136
+ y={text_y}
137
+ text-anchor={text_anchor}
138
+ dominant-baseline={text_baseline}
139
+ fill={text_fill}
140
+ transform={text_transform}
141
+ >
142
+ {tick_text(tick)}{#if unit_on_first_tick && idx === 0 && axis.unit}&zwnj;&ensp;{axis
143
+ .unit}{/if}
144
+ </text>
145
+ {/if}
146
+ </g>
147
+ {/if}
148
+ {/each}
149
+ {#if show_label}
150
+ <AxisLabel
151
+ x={label_x ?? 0}
152
+ y={label_y ?? 0}
153
+ rotate={side === `y` || side === `y2`}
154
+ label={axis.label ?? ``}
155
+ options={axis.options}
156
+ selected_key={axis.selected_key}
157
+ loading={axis_loading}
158
+ axis_type={side}
159
+ color={axis.color}
160
+ on_select={(key) => on_axis_change?.(key)}
161
+ />
162
+ {/if}
163
+ </g>
164
+
165
+ <style>
166
+ .tick text {
167
+ font-size: var(--tick-font-size, 0.8em);
168
+ }
169
+ </style>
@@ -0,0 +1,24 @@
1
+ import type { Sides } from './layout';
2
+ import type { AxisConfig } from './types';
3
+ type Side = `x` | `x2` | `y` | `y2`;
4
+ type $$ComponentProps = {
5
+ side: Side;
6
+ ticks: number[];
7
+ place: (value: number) => number;
8
+ axis?: AxisConfig;
9
+ pad: Required<Sides>;
10
+ width: number;
11
+ height: number;
12
+ show_grid?: boolean;
13
+ show_baseline?: boolean;
14
+ tick_label?: (tick: number) => string | null | undefined;
15
+ domain?: [number, number];
16
+ unit_on_first_tick?: boolean;
17
+ label_x?: number;
18
+ label_y?: number;
19
+ axis_loading?: boolean;
20
+ on_axis_change?: (key: string) => void;
21
+ };
22
+ declare const PlotAxis: import("svelte").Component<$$ComponentProps, {}, "">;
23
+ type PlotAxis = ReturnType<typeof PlotAxis>;
24
+ export default PlotAxis;
@@ -1,4 +1,4 @@
1
1
  import type { PlotControlsProps } from './index';
2
- declare const PlotControls: import("svelte").Component<PlotControlsProps, {}, "display" | "show_controls" | "controls_open" | "x_axis" | "y_axis" | "x2_axis" | "y2_axis">;
2
+ declare const PlotControls: import("svelte").Component<PlotControlsProps, {}, "display" | "show_controls" | "x_axis" | "y_axis" | "controls_open" | "x2_axis" | "y2_axis">;
3
3
  type PlotControls = ReturnType<typeof PlotControls>;
4
4
  export default PlotControls;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  // ReferenceLine3D: 3D reference lines for axis-parallel, segments, and extended lines
3
3
  // Uses Line2 for proper variable-width lines (WebGL ignores linewidth on basic lines)
4
- import type { Vec3 } from '../math'
4
+ import type { Point3D, Vec3 } from '../math'
5
5
  import { T, useThrelte } from '@threlte/core'
6
6
  import * as THREE from 'three'
7
7
  import { Line2 } from 'three/examples/jsm/lines/Line2.js'
@@ -32,66 +32,68 @@
32
32
  })
33
33
  return (ux: number, uy: number, uz: number) => transform(ux, uy, uz)
34
34
  })
35
+ const endpoints_from = (point_a: Vec3, point_b: Vec3): [Point3D, Point3D] => [
36
+ to_coords(...point_a),
37
+ to_coords(...point_b),
38
+ ]
35
39
 
36
40
  // Compute line endpoints based on type
37
41
  let endpoints = $derived.by(
38
- ():
39
- | [{ x: number; y: number; z: number }, { x: number; y: number; z: number }]
40
- | null => {
42
+ (): [Point3D, Point3D] | null => {
41
43
  if (ref_line.visible === false) return null
42
44
  const [x_min, x_max] = span_or(ref_line.x_span, x_range)
43
45
  const [y_min, y_max] = span_or(ref_line.y_span, y_range)
44
46
  const [z_min, z_max] = span_or(ref_line.z_span, z_range)
45
47
 
46
- switch (ref_line.type) {
47
- case `x-axis`:
48
- return [
49
- to_coords(x_min, ref_line.y, ref_line.z),
50
- to_coords(x_max, ref_line.y, ref_line.z),
51
- ]
52
- case `y-axis`:
53
- return [
54
- to_coords(ref_line.x, y_min, ref_line.z),
55
- to_coords(ref_line.x, y_max, ref_line.z),
56
- ]
57
- case `z-axis`:
58
- return [
59
- to_coords(ref_line.x, ref_line.y, z_min),
60
- to_coords(ref_line.x, ref_line.y, z_max),
61
- ]
62
- case `segment`:
63
- return [to_coords(...ref_line.p1), to_coords(...ref_line.p2)]
64
- case `line`: {
65
- // Extend line through two points to bounding box
66
- const [p1x, p1y, p1z] = ref_line.p1
67
- const [dx, dy, dz] = [
68
- ref_line.p2[0] - p1x,
69
- ref_line.p2[1] - p1y,
70
- ref_line.p2[2] - p1z,
71
- ]
72
- // Find t values at each boundary plane
73
- const t_values = [
74
- ...(dx !== 0 ? [(x_min - p1x) / dx, (x_max - p1x) / dx] : []),
75
- ...(dy !== 0 ? [(y_min - p1y) / dy, (y_max - p1y) / dy] : []),
76
- ...(dz !== 0 ? [(z_min - p1z) / dz, (z_max - p1z) / dz] : []),
77
- ]
78
- // Keep only t values where the resulting point is inside bounds
79
- const eps = 1e-6
80
- const valid_t = t_values.filter((t) => {
81
- const [px, py, pz] = [p1x + t * dx, p1y + t * dy, p1z + t * dz]
82
- return px >= x_min - eps && px <= x_max + eps &&
83
- py >= y_min - eps && py <= y_max + eps && pz >= z_min - eps &&
84
- pz <= z_max + eps
85
- })
86
- if (valid_t.length < 2) return null
87
- const t_min = Math.min(...valid_t)
88
- const t_max = Math.max(...valid_t)
89
- return [
90
- to_coords(p1x + t_min * dx, p1y + t_min * dy, p1z + t_min * dz),
91
- to_coords(p1x + t_max * dx, p1y + t_max * dy, p1z + t_max * dz),
48
+ if (ref_line.type === `x-axis`) {
49
+ return endpoints_from([x_min, ref_line.y, ref_line.z], [x_max, ref_line.y, ref_line.z])
50
+ }
51
+ if (ref_line.type === `y-axis`) {
52
+ return endpoints_from([ref_line.x, y_min, ref_line.z], [ref_line.x, y_max, ref_line.z])
53
+ }
54
+ if (ref_line.type === `z-axis`) {
55
+ return endpoints_from([ref_line.x, ref_line.y, z_min], [ref_line.x, ref_line.y, z_max])
56
+ }
57
+ if (ref_line.type === `segment`) {
58
+ return endpoints_from(ref_line.p1, ref_line.p2)
59
+ }
60
+ if (ref_line.type === `line`) {
61
+ // Extend line through two points to bounding box
62
+ const [p1x, p1y, p1z] = ref_line.p1
63
+ const [dx, dy, dz] = [
64
+ ref_line.p2[0] - p1x,
65
+ ref_line.p2[1] - p1y,
66
+ ref_line.p2[2] - p1z,
67
+ ]
68
+ // Find t values at each boundary plane
69
+ const t_values = [
70
+ ...(dx !== 0 ? [(x_min - p1x) / dx, (x_max - p1x) / dx] : []),
71
+ ...(dy !== 0 ? [(y_min - p1y) / dy, (y_max - p1y) / dy] : []),
72
+ ...(dz !== 0 ? [(z_min - p1z) / dz, (z_max - p1z) / dz] : []),
73
+ ]
74
+ // Keep only t values where the resulting point is inside bounds
75
+ const eps = 1e-6
76
+ const valid_t = t_values.filter((t_value) => {
77
+ const [px, py, pz] = [
78
+ p1x + t_value * dx,
79
+ p1y + t_value * dy,
80
+ p1z + t_value * dz,
92
81
  ]
93
- }
82
+ return (
83
+ px >= x_min - eps && px <= x_max + eps &&
84
+ py >= y_min - eps && py <= y_max + eps &&
85
+ pz >= z_min - eps && pz <= z_max + eps
86
+ )
87
+ })
88
+ if (valid_t.length < 2) return null
89
+ const t_min = Math.min(...valid_t)
90
+ const t_max = Math.max(...valid_t)
91
+ return endpoints_from(
92
+ [p1x + t_min * dx, p1y + t_min * dy, p1z + t_min * dz],
93
+ [p1x + t_max * dx, p1y + t_max * dy, p1z + t_max * dz],
94
+ )
94
95
  }
96
+ return null
95
97
  },
96
98
  )
97
99
 
@@ -45,49 +45,46 @@
45
45
  function compute_geometry(): THREE.BufferGeometry | null {
46
46
  if (ref_plane.visible === false) return null
47
47
 
48
- switch (ref_plane.type) {
49
- case `xy`: {
50
- const zval = ref_plane.z
51
- return quad([
52
- [x_min, y_min, zval],
53
- [x_max, y_min, zval],
54
- [x_max, y_max, zval],
55
- [x_min, y_max, zval],
56
- ])
57
- }
58
- case `xz`: {
59
- const yval = ref_plane.y
60
- return quad([
61
- [x_min, yval, z_min],
62
- [x_max, yval, z_min],
63
- [x_max, yval, z_max],
64
- [x_min, yval, z_max],
65
- ])
66
- }
67
- case `yz`: {
68
- const xval = ref_plane.x
69
- return quad([
70
- [xval, y_min, z_min],
71
- [xval, y_max, z_min],
72
- [xval, y_max, z_max],
73
- [xval, y_min, z_max],
74
- ])
75
- }
76
- case `normal`: {
77
- if (Math.hypot(...ref_plane.normal) < 1e-9) return null // degenerate normal
78
- return create_plane_from_normal(ref_plane.normal, ref_plane.point)
79
- }
80
- case `points`: {
81
- const { p1, p2, p3 } = ref_plane
82
- const v1: Vec3 = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]]
83
- const v2: Vec3 = [p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2]]
84
- const cross = cross_3d(v1, v2)
85
- if (Math.hypot(...cross) < 1e-9) return null // collinear points
86
- return create_plane_from_normal(normalize_vec3(cross), p1)
87
- }
88
- default:
89
- return null
48
+ if (ref_plane.type === `xy`) {
49
+ const zval = ref_plane.z
50
+ return quad([
51
+ [x_min, y_min, zval],
52
+ [x_max, y_min, zval],
53
+ [x_max, y_max, zval],
54
+ [x_min, y_max, zval],
55
+ ])
90
56
  }
57
+ if (ref_plane.type === `xz`) {
58
+ const yval = ref_plane.y
59
+ return quad([
60
+ [x_min, yval, z_min],
61
+ [x_max, yval, z_min],
62
+ [x_max, yval, z_max],
63
+ [x_min, yval, z_max],
64
+ ])
65
+ }
66
+ if (ref_plane.type === `yz`) {
67
+ const xval = ref_plane.x
68
+ return quad([
69
+ [xval, y_min, z_min],
70
+ [xval, y_max, z_min],
71
+ [xval, y_max, z_max],
72
+ [xval, y_min, z_max],
73
+ ])
74
+ }
75
+ if (ref_plane.type === `normal`) {
76
+ if (Math.hypot(...ref_plane.normal) < 1e-9) return null // degenerate normal
77
+ return create_plane_from_normal(ref_plane.normal, ref_plane.point)
78
+ }
79
+ if (ref_plane.type === `points`) {
80
+ const { p1, p2, p3 } = ref_plane
81
+ const v1: Vec3 = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]]
82
+ const v2: Vec3 = [p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2]]
83
+ const cross = cross_3d(v1, v2)
84
+ if (Math.hypot(...cross) < 1e-9) return null // collinear points
85
+ return create_plane_from_normal(normalize_vec3(cross), p1)
86
+ }
87
+ return null
91
88
  }
92
89
 
93
90
  // Create geometry with proper disposal on dependency change