matterviz 0.3.0 → 0.3.2
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.
- package/dist/FilePicker.svelte +37 -20
- package/dist/Icon.svelte +2 -2
- package/dist/MillerIndexInput.svelte +60 -0
- package/dist/MillerIndexInput.svelte.d.ts +7 -0
- package/dist/app.css +38 -2
- package/dist/brillouin/BrillouinZone.svelte +20 -62
- package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneExportPane.svelte +12 -20
- package/dist/brillouin/BrillouinZoneScene.svelte +2 -2
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram.svelte +192 -0
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +677 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2688 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
- package/dist/chempot-diagram/color.d.ts +10 -0
- package/dist/chempot-diagram/color.js +33 -0
- package/dist/chempot-diagram/compute.d.ts +38 -0
- package/dist/chempot-diagram/compute.js +650 -0
- package/dist/chempot-diagram/index.d.ts +5 -0
- package/dist/chempot-diagram/index.js +5 -0
- package/dist/chempot-diagram/pointer.d.ts +16 -0
- package/dist/chempot-diagram/pointer.js +40 -0
- package/dist/chempot-diagram/temperature.d.ts +15 -0
- package/dist/chempot-diagram/temperature.js +37 -0
- package/dist/chempot-diagram/types.d.ts +83 -0
- package/dist/chempot-diagram/types.js +27 -0
- package/dist/colors/index.d.ts +3 -1
- package/dist/colors/index.js +4 -0
- package/dist/composition/BarChart.svelte +13 -22
- package/dist/composition/BubbleChart.svelte +5 -3
- package/dist/composition/FormulaFilter.svelte +770 -90
- package/dist/composition/FormulaFilter.svelte.d.ts +37 -1
- package/dist/composition/PieChart.svelte +43 -18
- package/dist/composition/PieChart.svelte.d.ts +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -0
- package/dist/convex-hull/ConvexHull.svelte +14 -1
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull2D.svelte +14 -45
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +396 -134
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +93 -42
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullControls.svelte +94 -31
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +4 -2
- package/dist/convex-hull/ConvexHullStats.svelte +697 -128
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +1 -0
- package/dist/convex-hull/GasPressureControls.svelte +72 -38
- package/dist/convex-hull/GasPressureControls.svelte.d.ts +2 -1
- package/dist/convex-hull/TemperatureSlider.svelte +46 -19
- package/dist/convex-hull/TemperatureSlider.svelte.d.ts +2 -1
- package/dist/convex-hull/demo-temperature.d.ts +6 -0
- package/dist/convex-hull/demo-temperature.js +36 -0
- package/dist/convex-hull/gas-thermodynamics.js +16 -5
- package/dist/convex-hull/helpers.d.ts +7 -1
- package/dist/convex-hull/helpers.js +45 -15
- package/dist/convex-hull/index.d.ts +15 -1
- package/dist/convex-hull/index.js +1 -0
- package/dist/convex-hull/thermodynamics.d.ts +8 -21
- package/dist/convex-hull/thermodynamics.js +106 -17
- package/dist/convex-hull/types.d.ts +7 -0
- package/dist/convex-hull/types.js +11 -0
- package/dist/coordination/CoordinationBarPlot.svelte +29 -46
- package/dist/element/BohrAtom.svelte +1 -1
- package/dist/element/data.js +2 -14
- package/dist/element/data.json.gz +0 -0
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +1 -0
- package/dist/element/types.d.ts +1 -0
- package/dist/fermi-surface/FermiSurface.svelte +21 -65
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
- package/dist/fermi-surface/compute.js +1 -21
- package/dist/fermi-surface/marching-cubes.d.ts +2 -13
- package/dist/fermi-surface/marching-cubes.js +2 -519
- package/dist/fermi-surface/parse.js +17 -23
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +1273 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +171 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +31 -0
- package/dist/heatmap-matrix/index.d.ts +53 -0
- package/dist/heatmap-matrix/index.js +100 -0
- package/dist/heatmap-matrix/shared.d.ts +2 -0
- package/dist/heatmap-matrix/shared.js +4 -0
- package/dist/icons.d.ts +119 -0
- package/dist/icons.js +119 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/io/export.js +15 -3
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +43 -0
- package/dist/io/index.d.ts +2 -2
- package/dist/io/index.js +2 -112
- package/dist/io/types.d.ts +1 -0
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +118 -0
- package/dist/isosurface/Isosurface.svelte +231 -0
- package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
- package/dist/isosurface/IsosurfaceControls.svelte +273 -0
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
- package/dist/isosurface/index.d.ts +5 -0
- package/dist/isosurface/index.js +6 -0
- package/dist/isosurface/parse.d.ts +6 -0
- package/dist/isosurface/parse.js +548 -0
- package/dist/isosurface/slice.d.ts +11 -0
- package/dist/isosurface/slice.js +145 -0
- package/dist/isosurface/types.d.ts +55 -0
- package/dist/isosurface/types.js +178 -0
- package/dist/labels.d.ts +2 -1
- package/dist/labels.js +1 -0
- package/dist/layout/InfoTag.svelte +62 -62
- package/dist/layout/SubpageGrid.svelte +74 -0
- package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
- package/dist/layout/index.d.ts +1 -0
- package/dist/layout/index.js +1 -0
- package/dist/layout/json-tree/JsonNode.svelte +226 -53
- package/dist/layout/json-tree/JsonTree.svelte +425 -51
- package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
- package/dist/layout/json-tree/JsonValue.svelte +218 -97
- package/dist/layout/json-tree/types.d.ts +27 -2
- package/dist/layout/json-tree/utils.d.ts +14 -1
- package/dist/layout/json-tree/utils.js +254 -0
- package/dist/marching-cubes.d.ts +14 -0
- package/dist/marching-cubes.js +519 -0
- package/dist/math.d.ts +8 -0
- package/dist/math.js +374 -7
- package/dist/overlays/ContextMenu.svelte +3 -2
- package/dist/overlays/DraggablePane.svelte +163 -58
- package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +232 -77
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
- package/dist/phase-diagram/PhaseDiagramControls.svelte +32 -11
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +103 -0
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +102 -95
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +7 -0
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +100 -26
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
- package/dist/phase-diagram/index.d.ts +2 -0
- package/dist/phase-diagram/index.js +2 -0
- package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
- package/dist/phase-diagram/svg-to-diagram.js +865 -0
- package/dist/phase-diagram/types.d.ts +10 -0
- package/dist/phase-diagram/utils.d.ts +7 -4
- package/dist/phase-diagram/utils.js +149 -59
- package/dist/plot/AxisLabel.svelte +26 -0
- package/dist/plot/AxisLabel.svelte.d.ts +16 -0
- package/dist/plot/BarPlot.svelte +473 -228
- package/dist/plot/BarPlot.svelte.d.ts +3 -3
- package/dist/plot/BarPlotControls.svelte +3 -2
- package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ColorBar.svelte +54 -54
- package/dist/plot/ColorBar.svelte.d.ts +1 -1
- package/dist/plot/ElementScatter.svelte +4 -3
- package/dist/plot/FillArea.svelte +4 -1
- package/dist/plot/Histogram.svelte +320 -230
- package/dist/plot/Histogram.svelte.d.ts +2 -2
- package/dist/plot/HistogramControls.svelte +29 -10
- package/dist/plot/HistogramControls.svelte.d.ts +6 -2
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +2 -2
- package/dist/plot/PlotControls.svelte +109 -27
- package/dist/plot/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/PlotLegend.svelte +1 -1
- package/dist/plot/PortalSelect.svelte +2 -1
- package/dist/plot/ReferenceLine.svelte +2 -1
- package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
- package/dist/plot/ReferencePlane.svelte +1 -3
- package/dist/plot/ScatterPlot.svelte +343 -209
- package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
- package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlot3DControls.svelte +203 -250
- package/dist/plot/ScatterPlot3DScene.svelte +4 -7
- package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlotControls.svelte +95 -55
- package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ZeroLines.svelte +44 -0
- package/dist/plot/ZeroLines.svelte.d.ts +32 -0
- package/dist/plot/ZoomRect.svelte +21 -0
- package/dist/plot/ZoomRect.svelte.d.ts +8 -0
- package/dist/plot/axis-utils.d.ts +1 -1
- package/dist/plot/data-cleaning.js +1 -5
- package/dist/plot/index.d.ts +6 -2
- package/dist/plot/index.js +6 -2
- package/dist/plot/interactions.d.ts +8 -10
- package/dist/plot/interactions.js +10 -19
- package/dist/plot/layout.d.ts +7 -1
- package/dist/plot/layout.js +12 -4
- package/dist/plot/reference-line.d.ts +4 -21
- package/dist/plot/reference-line.js +7 -81
- package/dist/plot/types.d.ts +42 -17
- package/dist/plot/types.js +10 -0
- package/dist/plot/utils/label-placement.js +14 -11
- package/dist/plot/utils.d.ts +1 -0
- package/dist/plot/utils.js +14 -0
- package/dist/rdf/RdfPlot.svelte +55 -66
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/rdf/index.d.ts +1 -1
- package/dist/rdf/index.js +1 -1
- package/dist/settings.d.ts +5 -0
- package/dist/settings.js +37 -3
- package/dist/spectral/Bands.svelte +515 -143
- package/dist/spectral/Bands.svelte.d.ts +22 -2
- package/dist/spectral/helpers.d.ts +23 -1
- package/dist/spectral/helpers.js +65 -9
- package/dist/spectral/types.d.ts +2 -0
- package/dist/structure/AtomLegend.svelte +31 -10
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/CellSelect.svelte +92 -22
- package/dist/structure/Lattice.svelte +2 -0
- package/dist/structure/Structure.svelte +716 -173
- package/dist/structure/Structure.svelte.d.ts +7 -2
- package/dist/structure/StructureControls.svelte +26 -14
- package/dist/structure/StructureControls.svelte.d.ts +5 -1
- package/dist/structure/StructureInfoPane.svelte +7 -1
- package/dist/structure/StructureScene.svelte +386 -95
- package/dist/structure/StructureScene.svelte.d.ts +15 -4
- package/dist/structure/atom-properties.d.ts +6 -2
- package/dist/structure/atom-properties.js +38 -25
- package/dist/structure/export.js +10 -7
- package/dist/structure/ferrox-wasm-types.d.ts +3 -2
- package/dist/structure/ferrox-wasm-types.js +0 -3
- package/dist/structure/ferrox-wasm.d.ts +3 -2
- package/dist/structure/ferrox-wasm.js +1 -2
- package/dist/structure/index.d.ts +7 -0
- package/dist/structure/index.js +22 -0
- package/dist/structure/parse.js +19 -16
- package/dist/structure/partial-occupancy.d.ts +25 -0
- package/dist/structure/partial-occupancy.js +102 -0
- package/dist/structure/validation.js +6 -3
- package/dist/symmetry/SymmetryStats.svelte +18 -4
- package/dist/symmetry/WyckoffTable.svelte +18 -10
- package/dist/symmetry/index.d.ts +7 -4
- package/dist/symmetry/index.js +83 -18
- package/dist/table/HeatmapTable.svelte +468 -69
- package/dist/table/HeatmapTable.svelte.d.ts +13 -1
- package/dist/table/ToggleMenu.svelte +291 -44
- package/dist/table/ToggleMenu.svelte.d.ts +4 -1
- package/dist/table/index.d.ts +3 -0
- package/dist/tooltip/index.d.ts +1 -1
- package/dist/tooltip/index.js +1 -0
- package/dist/trajectory/Trajectory.svelte +147 -145
- package/dist/trajectory/TrajectoryExportPane.svelte +13 -9
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
- package/dist/trajectory/constants.d.ts +6 -0
- package/dist/trajectory/constants.js +7 -0
- package/dist/trajectory/extract.js +3 -5
- package/dist/trajectory/format-detect.d.ts +9 -0
- package/dist/trajectory/format-detect.js +76 -0
- package/dist/trajectory/frame-reader.d.ts +17 -0
- package/dist/trajectory/frame-reader.js +339 -0
- package/dist/trajectory/helpers.d.ts +15 -0
- package/dist/trajectory/helpers.js +187 -0
- package/dist/trajectory/index.d.ts +1 -0
- package/dist/trajectory/index.js +11 -4
- package/dist/trajectory/parse/ase.d.ts +2 -0
- package/dist/trajectory/parse/ase.js +76 -0
- package/dist/trajectory/parse/hdf5.d.ts +2 -0
- package/dist/trajectory/parse/hdf5.js +121 -0
- package/dist/trajectory/parse/index.d.ts +12 -0
- package/dist/trajectory/parse/index.js +304 -0
- package/dist/trajectory/parse/lammps.d.ts +5 -0
- package/dist/trajectory/parse/lammps.js +169 -0
- package/dist/trajectory/parse/vasp.d.ts +2 -0
- package/dist/trajectory/parse/vasp.js +65 -0
- package/dist/trajectory/parse/xyz.d.ts +2 -0
- package/dist/trajectory/parse/xyz.js +109 -0
- package/dist/trajectory/types.d.ts +11 -0
- package/dist/trajectory/types.js +1 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +4 -0
- package/dist/xrd/XrdPlot.svelte +6 -4
- package/dist/xrd/calc-xrd.js +0 -1
- package/package.json +33 -23
- package/readme.md +4 -4
- package/dist/trajectory/parse.d.ts +0 -42
- package/dist/trajectory/parse.js +0 -1267
- /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
<script lang="ts">// Threlte component that renders isosurface meshes from volumetric data using marching cubes.
|
|
2
|
+
// Supports multiple layers at different isovalues with independent colors,
|
|
3
|
+
// plus positive/negative lobes and two-pass transparency.
|
|
4
|
+
import { marching_cubes } from '../marching-cubes';
|
|
5
|
+
import { T } from '@threlte/core';
|
|
6
|
+
import { BackSide, BufferAttribute, BufferGeometry, DoubleSide, FrontSide, Uint32BufferAttribute, } from 'three';
|
|
7
|
+
import { DEFAULT_ISOSURFACE_SETTINGS, downsample_grid, pad_periodic_grid, } from './types';
|
|
8
|
+
let { volume, settings = DEFAULT_ISOSURFACE_SETTINGS, } = $props();
|
|
9
|
+
// Resolve layers: use explicit layers array if provided, else build from single-isovalue settings
|
|
10
|
+
let resolved_layers = $derived.by(() => {
|
|
11
|
+
if (settings.layers?.length)
|
|
12
|
+
return settings.layers;
|
|
13
|
+
return [{
|
|
14
|
+
isovalue: settings.isovalue,
|
|
15
|
+
color: settings.positive_color,
|
|
16
|
+
opacity: settings.opacity,
|
|
17
|
+
visible: true,
|
|
18
|
+
show_negative: settings.show_negative,
|
|
19
|
+
negative_color: settings.negative_color,
|
|
20
|
+
}];
|
|
21
|
+
});
|
|
22
|
+
// Build indexed BufferGeometry from marching cubes output.
|
|
23
|
+
// Uses Three.js index buffer to avoid tripling vertex data, and
|
|
24
|
+
// computeVertexNormals() for fast GPU-friendly normals.
|
|
25
|
+
function build_geometry(vertices, faces) {
|
|
26
|
+
if (vertices.length === 0 || faces.length === 0)
|
|
27
|
+
return null;
|
|
28
|
+
// Flatten vertices: Vec3[] → Float32Array
|
|
29
|
+
const positions = new Float32Array(vertices.length * 3);
|
|
30
|
+
for (let idx = 0; idx < vertices.length; idx++) {
|
|
31
|
+
const vert = vertices[idx];
|
|
32
|
+
positions[idx * 3] = vert[0];
|
|
33
|
+
positions[idx * 3 + 1] = vert[1];
|
|
34
|
+
positions[idx * 3 + 2] = vert[2];
|
|
35
|
+
}
|
|
36
|
+
// Flatten face indices: number[][] → Uint32Array
|
|
37
|
+
const indices = new Uint32Array(faces.length * 3);
|
|
38
|
+
for (let idx = 0; idx < faces.length; idx++) {
|
|
39
|
+
const face = faces[idx];
|
|
40
|
+
indices[idx * 3] = face[0];
|
|
41
|
+
indices[idx * 3 + 1] = face[1];
|
|
42
|
+
indices[idx * 3 + 2] = face[2];
|
|
43
|
+
}
|
|
44
|
+
const geometry = new BufferGeometry();
|
|
45
|
+
geometry.setAttribute(`position`, new BufferAttribute(positions, 3));
|
|
46
|
+
geometry.setIndex(new Uint32BufferAttribute(indices, 1));
|
|
47
|
+
geometry.computeVertexNormals();
|
|
48
|
+
geometry.computeBoundingSphere();
|
|
49
|
+
return geometry;
|
|
50
|
+
}
|
|
51
|
+
// Downsample large grids once when volume changes to keep marching cubes interactive
|
|
52
|
+
let ds_result = $derived.by(() => {
|
|
53
|
+
if (!volume)
|
|
54
|
+
return undefined;
|
|
55
|
+
return downsample_grid(volume.grid, volume.grid_dims);
|
|
56
|
+
});
|
|
57
|
+
// Run marching cubes at the given isovalue with pre-prepared grid/lattice/shift.
|
|
58
|
+
function extract_surface(isovalue, mc_grid, mc_lattice, origin_shift) {
|
|
59
|
+
if (isovalue === 0)
|
|
60
|
+
return null;
|
|
61
|
+
const result = marching_cubes(mc_grid, isovalue, mc_lattice, {
|
|
62
|
+
periodic: false,
|
|
63
|
+
interpolate: true,
|
|
64
|
+
centered: false,
|
|
65
|
+
normals: false,
|
|
66
|
+
});
|
|
67
|
+
if (origin_shift) {
|
|
68
|
+
for (const vert of result.vertices) {
|
|
69
|
+
vert[0] += origin_shift[0];
|
|
70
|
+
vert[1] += origin_shift[1];
|
|
71
|
+
vert[2] += origin_shift[2];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return build_geometry(result.vertices, result.faces);
|
|
75
|
+
}
|
|
76
|
+
let active_geometries = $state([]);
|
|
77
|
+
let raf_id = 0;
|
|
78
|
+
let debounce_id = 0;
|
|
79
|
+
// Dispose all current geometries
|
|
80
|
+
function dispose_all() {
|
|
81
|
+
for (const entry of active_geometries)
|
|
82
|
+
entry.geometry.dispose();
|
|
83
|
+
active_geometries = [];
|
|
84
|
+
}
|
|
85
|
+
// Dispose on unmount
|
|
86
|
+
$effect(() => () => dispose_all());
|
|
87
|
+
function rebuild_geometries(layers) {
|
|
88
|
+
if (!volume || !ds_result)
|
|
89
|
+
return;
|
|
90
|
+
const old = active_geometries;
|
|
91
|
+
const entries = [];
|
|
92
|
+
// Prepare grid/lattice/shift once for all layers.
|
|
93
|
+
// When halo > 0 for periodic volumes, the downsampled grid is padded with
|
|
94
|
+
// halo cells from the opposite face so isosurfaces extend beyond the unit
|
|
95
|
+
// cell and close into complete enclosed shapes around boundary atoms.
|
|
96
|
+
let mc_grid = ds_result.grid;
|
|
97
|
+
let mc_lattice = volume.lattice;
|
|
98
|
+
let origin_shift = null;
|
|
99
|
+
if (settings.halo > 0 && volume.periodic) {
|
|
100
|
+
const padded = pad_periodic_grid(ds_result.grid, ds_result.dims, settings.halo);
|
|
101
|
+
mc_grid = padded.grid;
|
|
102
|
+
// marching_cubes maps [0,1] fractional -> Cartesian via lattice.
|
|
103
|
+
// The padded grid covers a wider fractional range, so scale the lattice
|
|
104
|
+
// to match. Then shift all vertices by the fractional offset.
|
|
105
|
+
const [la, lb, lc] = volume.lattice;
|
|
106
|
+
const sx = padded.dims[0] / ds_result.dims[0];
|
|
107
|
+
const sy = padded.dims[1] / ds_result.dims[1];
|
|
108
|
+
const sz = padded.dims[2] / ds_result.dims[2];
|
|
109
|
+
mc_lattice = [
|
|
110
|
+
[la[0] * sx, la[1] * sx, la[2] * sx],
|
|
111
|
+
[lb[0] * sy, lb[1] * sy, lb[2] * sy],
|
|
112
|
+
[lc[0] * sz, lc[1] * sz, lc[2] * sz],
|
|
113
|
+
];
|
|
114
|
+
const [ox, oy, oz] = padded.offset;
|
|
115
|
+
origin_shift = [
|
|
116
|
+
ox * la[0] + oy * lb[0] + oz * lc[0],
|
|
117
|
+
ox * la[1] + oy * lb[1] + oz * lc[1],
|
|
118
|
+
ox * la[2] + oy * lb[2] + oz * lc[2],
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
const surface_at = (isovalue) => extract_surface(isovalue, mc_grid, mc_lattice, origin_shift);
|
|
122
|
+
// Render lower-isovalue (outer) shells earlier so per-layer back/front passes
|
|
123
|
+
// interleave back-to-front across shells and reduce transparency artefacts.
|
|
124
|
+
const layer_render_rank = new Map(layers
|
|
125
|
+
.map((layer, layer_idx) => ({ layer_idx, isovalue: layer.isovalue }))
|
|
126
|
+
.sort((layer_a, layer_b) => layer_a.isovalue - layer_b.isovalue)
|
|
127
|
+
.map(({ layer_idx }, rank) => [layer_idx, rank]));
|
|
128
|
+
for (let layer_idx = 0; layer_idx < layers.length; layer_idx++) {
|
|
129
|
+
const layer = layers[layer_idx];
|
|
130
|
+
if (!layer.visible || layer.isovalue <= 0)
|
|
131
|
+
continue;
|
|
132
|
+
// Each layer gets 4 slots (positive back/front + negative back/front).
|
|
133
|
+
const base_order = (layer_render_rank.get(layer_idx) ?? layer_idx) * 4;
|
|
134
|
+
const pos_geo = surface_at(layer.isovalue);
|
|
135
|
+
if (pos_geo) {
|
|
136
|
+
entries.push({
|
|
137
|
+
geometry: pos_geo,
|
|
138
|
+
color: layer.color,
|
|
139
|
+
opacity: layer.opacity,
|
|
140
|
+
render_order: base_order,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (layer.show_negative) {
|
|
144
|
+
const neg_geo = surface_at(-layer.isovalue);
|
|
145
|
+
if (neg_geo) {
|
|
146
|
+
entries.push({
|
|
147
|
+
geometry: neg_geo,
|
|
148
|
+
color: layer.negative_color,
|
|
149
|
+
opacity: layer.opacity,
|
|
150
|
+
render_order: base_order + 2,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
active_geometries = entries;
|
|
156
|
+
for (const entry of old)
|
|
157
|
+
entry.geometry.dispose();
|
|
158
|
+
}
|
|
159
|
+
// Rebuild all layer geometries when layers or volume change.
|
|
160
|
+
// Debounces rapid changes (e.g. slider drags) to avoid repeated expensive marching cubes.
|
|
161
|
+
$effect(() => {
|
|
162
|
+
const layers = resolved_layers;
|
|
163
|
+
void settings.halo;
|
|
164
|
+
if (!ds_result) {
|
|
165
|
+
dispose_all();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
debounce_id = window.setTimeout(() => {
|
|
169
|
+
raf_id = requestAnimationFrame(() => rebuild_geometries(layers));
|
|
170
|
+
}, 50);
|
|
171
|
+
return () => {
|
|
172
|
+
clearTimeout(debounce_id);
|
|
173
|
+
cancelAnimationFrame(raf_id);
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
</script>
|
|
177
|
+
|
|
178
|
+
<!-- Render each geometry entry with appropriate material -->
|
|
179
|
+
{#each active_geometries as entry (entry)}
|
|
180
|
+
{#if settings.wireframe}
|
|
181
|
+
<T.Mesh geometry={entry.geometry} frustumCulled={false}>
|
|
182
|
+
<T.MeshBasicMaterial
|
|
183
|
+
color={entry.color}
|
|
184
|
+
wireframe
|
|
185
|
+
transparent={entry.opacity < 1}
|
|
186
|
+
opacity={entry.opacity}
|
|
187
|
+
/>
|
|
188
|
+
</T.Mesh>
|
|
189
|
+
{:else if entry.opacity < 1}
|
|
190
|
+
<!-- Two-pass rendering for correct transparency -->
|
|
191
|
+
<T.Mesh
|
|
192
|
+
geometry={entry.geometry}
|
|
193
|
+
renderOrder={entry.render_order}
|
|
194
|
+
frustumCulled={false}
|
|
195
|
+
>
|
|
196
|
+
<T.MeshStandardMaterial
|
|
197
|
+
color={entry.color}
|
|
198
|
+
transparent
|
|
199
|
+
opacity={entry.opacity}
|
|
200
|
+
side={BackSide}
|
|
201
|
+
depthWrite={false}
|
|
202
|
+
metalness={0.1}
|
|
203
|
+
roughness={0.6}
|
|
204
|
+
/>
|
|
205
|
+
</T.Mesh>
|
|
206
|
+
<T.Mesh
|
|
207
|
+
geometry={entry.geometry}
|
|
208
|
+
renderOrder={entry.render_order + 1}
|
|
209
|
+
frustumCulled={false}
|
|
210
|
+
>
|
|
211
|
+
<T.MeshStandardMaterial
|
|
212
|
+
color={entry.color}
|
|
213
|
+
transparent
|
|
214
|
+
opacity={entry.opacity}
|
|
215
|
+
side={FrontSide}
|
|
216
|
+
depthWrite={false}
|
|
217
|
+
metalness={0.1}
|
|
218
|
+
roughness={0.6}
|
|
219
|
+
/>
|
|
220
|
+
</T.Mesh>
|
|
221
|
+
{:else}
|
|
222
|
+
<T.Mesh geometry={entry.geometry} frustumCulled={false}>
|
|
223
|
+
<T.MeshStandardMaterial
|
|
224
|
+
color={entry.color}
|
|
225
|
+
side={DoubleSide}
|
|
226
|
+
metalness={0.1}
|
|
227
|
+
roughness={0.6}
|
|
228
|
+
/>
|
|
229
|
+
</T.Mesh>
|
|
230
|
+
{/if}
|
|
231
|
+
{/each}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { IsosurfaceSettings, VolumetricData } from './types';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
volume: VolumetricData;
|
|
4
|
+
settings?: IsosurfaceSettings;
|
|
5
|
+
};
|
|
6
|
+
declare const Isosurface: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type Isosurface = ReturnType<typeof Isosurface>;
|
|
8
|
+
export default Isosurface;
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
<script lang="ts">// Controls panel for isosurface visualization settings (isovalue, opacity, colors, etc.)
|
|
2
|
+
// Supports both single-isovalue mode and multi-layer mode.
|
|
3
|
+
import { format_num } from '../labels';
|
|
4
|
+
import { SettingsSection } from '../layout';
|
|
5
|
+
import { tooltip } from 'svelte-multiselect/attachments';
|
|
6
|
+
import { DEFAULT_ISOSURFACE_SETTINGS, generate_layers } from './types';
|
|
7
|
+
let { settings = $bindable({ ...DEFAULT_ISOSURFACE_SETTINGS }), volumes = [], active_volume_idx = $bindable(0), } = $props();
|
|
8
|
+
// Clamp active_volume_idx when volumes list changes (e.g. dataset swap)
|
|
9
|
+
$effect(() => {
|
|
10
|
+
if (volumes.length > 0 && active_volume_idx >= volumes.length) {
|
|
11
|
+
active_volume_idx = 0;
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
// Use precomputed data_range from the active volume
|
|
15
|
+
let data_range = $derived(volumes[active_volume_idx]?.data_range ?? { min: 0, max: 1, abs_max: 1, mean: 0 });
|
|
16
|
+
let slider_max = $derived(Math.max(data_range.abs_max, 0.001));
|
|
17
|
+
let step = $derived(slider_max / 200);
|
|
18
|
+
let is_multi_layer = $derived((settings.layers?.length ?? 0) > 0);
|
|
19
|
+
let n_layers = $derived(settings.layers?.length ?? 1);
|
|
20
|
+
function set_layer_count(count) {
|
|
21
|
+
if (count <= 1) {
|
|
22
|
+
settings.layers = undefined;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
settings.layers = generate_layers(data_range, count);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function update_layer(idx, updates) {
|
|
29
|
+
if (!settings.layers)
|
|
30
|
+
return;
|
|
31
|
+
settings.layers = settings.layers.map((layer, layer_idx) => layer_idx === idx ? { ...layer, ...updates } : layer);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<SettingsSection
|
|
36
|
+
title="Isosurface"
|
|
37
|
+
current_values={{
|
|
38
|
+
isovalue: settings.isovalue,
|
|
39
|
+
opacity: settings.opacity,
|
|
40
|
+
show_negative: settings.show_negative,
|
|
41
|
+
wireframe: settings.wireframe,
|
|
42
|
+
halo: settings.halo,
|
|
43
|
+
layers: n_layers,
|
|
44
|
+
}}
|
|
45
|
+
on_reset={() => {
|
|
46
|
+
settings = { ...DEFAULT_ISOSURFACE_SETTINGS }
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
<!-- Top row: volume selector (if multi-volume) + layer count + toggles -->
|
|
50
|
+
<div class="pane-row compact-row">
|
|
51
|
+
{#if volumes.length > 1}
|
|
52
|
+
<label
|
|
53
|
+
{@attach tooltip({
|
|
54
|
+
content: `Select which volume to display (e.g. charge vs magnetization)`,
|
|
55
|
+
})}
|
|
56
|
+
>
|
|
57
|
+
<span>Volume:</span>
|
|
58
|
+
<select bind:value={active_volume_idx}>
|
|
59
|
+
{#each volumes as vol, idx (idx)}
|
|
60
|
+
<option value={idx}>{vol.label ?? `Volume ${idx + 1}`}</option>
|
|
61
|
+
{/each}
|
|
62
|
+
</select>
|
|
63
|
+
</label>
|
|
64
|
+
{/if}
|
|
65
|
+
<label
|
|
66
|
+
{@attach tooltip({
|
|
67
|
+
content: `Number of isosurface shells at different density thresholds`,
|
|
68
|
+
})}
|
|
69
|
+
>
|
|
70
|
+
<span>Layers:</span>
|
|
71
|
+
<select
|
|
72
|
+
value={n_layers}
|
|
73
|
+
onchange={(event) =>
|
|
74
|
+
set_layer_count(Number((event.target as HTMLSelectElement).value))}
|
|
75
|
+
>
|
|
76
|
+
{#each [1, 2, 3, 4, 5] as count (count)}
|
|
77
|
+
<option value={count}>{count}</option>
|
|
78
|
+
{/each}
|
|
79
|
+
</select>
|
|
80
|
+
</label>
|
|
81
|
+
<!-- Sync both settings.show_negative (single-layer fallback) and all layer entries
|
|
82
|
+
so the toggle works consistently regardless of which mode is active -->
|
|
83
|
+
<label
|
|
84
|
+
{@attach tooltip({
|
|
85
|
+
content:
|
|
86
|
+
`Show negative lobe at −isovalue (for orbitals, ESP, magnetization)`,
|
|
87
|
+
})}
|
|
88
|
+
>
|
|
89
|
+
<span>Neg. lobe</span>
|
|
90
|
+
<input
|
|
91
|
+
type="checkbox"
|
|
92
|
+
checked={is_multi_layer
|
|
93
|
+
? settings.layers?.some((layer) => layer.show_negative) ?? false
|
|
94
|
+
: settings.show_negative}
|
|
95
|
+
onchange={(event) => {
|
|
96
|
+
const checked = (event.target as HTMLInputElement).checked
|
|
97
|
+
settings.show_negative = checked
|
|
98
|
+
if (settings.layers) {
|
|
99
|
+
settings.layers = settings.layers.map((layer) => ({
|
|
100
|
+
...layer,
|
|
101
|
+
show_negative: checked,
|
|
102
|
+
}))
|
|
103
|
+
}
|
|
104
|
+
}}
|
|
105
|
+
/>
|
|
106
|
+
</label>
|
|
107
|
+
<label
|
|
108
|
+
{@attach tooltip({ content: `Render as wireframe mesh instead of solid surface` })}
|
|
109
|
+
>
|
|
110
|
+
<span>Wireframe</span>
|
|
111
|
+
<input type="checkbox" bind:checked={settings.wireframe} />
|
|
112
|
+
</label>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
{#if is_multi_layer && settings.layers}
|
|
116
|
+
<!-- Multi-layer controls: each row has visibility, color, isovalue slider, opacity -->
|
|
117
|
+
{#each settings.layers as layer, idx (idx)}
|
|
118
|
+
<div class="layer-row">
|
|
119
|
+
<input
|
|
120
|
+
type="checkbox"
|
|
121
|
+
checked={layer.visible}
|
|
122
|
+
onchange={() => update_layer(idx, { visible: !layer.visible })}
|
|
123
|
+
/>
|
|
124
|
+
<input
|
|
125
|
+
type="color"
|
|
126
|
+
value={layer.color}
|
|
127
|
+
onchange={(event) =>
|
|
128
|
+
update_layer(idx, { color: (event.target as HTMLInputElement).value })}
|
|
129
|
+
/>
|
|
130
|
+
<input
|
|
131
|
+
type="range"
|
|
132
|
+
min={step}
|
|
133
|
+
max={slider_max}
|
|
134
|
+
{step}
|
|
135
|
+
value={layer.isovalue}
|
|
136
|
+
oninput={(event) =>
|
|
137
|
+
update_layer(idx, {
|
|
138
|
+
isovalue: Number((event.target as HTMLInputElement).value),
|
|
139
|
+
})}
|
|
140
|
+
style="flex: 1; min-width: 60px"
|
|
141
|
+
/>
|
|
142
|
+
<span class="layer-value">{format_num(layer.isovalue, `.3~g`)}</span>
|
|
143
|
+
<input
|
|
144
|
+
type="range"
|
|
145
|
+
min={0.1}
|
|
146
|
+
max={1}
|
|
147
|
+
step={0.05}
|
|
148
|
+
value={layer.opacity}
|
|
149
|
+
oninput={(event) =>
|
|
150
|
+
update_layer(idx, {
|
|
151
|
+
opacity: Number((event.target as HTMLInputElement).value),
|
|
152
|
+
})}
|
|
153
|
+
style="width: 50px"
|
|
154
|
+
title="Opacity: {format_num(layer.opacity, `.2f`)}"
|
|
155
|
+
/>
|
|
156
|
+
</div>
|
|
157
|
+
{/each}
|
|
158
|
+
{:else}
|
|
159
|
+
<!-- Single-layer: isovalue slider full width -->
|
|
160
|
+
<label
|
|
161
|
+
{@attach tooltip({
|
|
162
|
+
content: `Density threshold — surface is drawn where grid values equal this`,
|
|
163
|
+
})}
|
|
164
|
+
>
|
|
165
|
+
<span>Isovalue:</span>
|
|
166
|
+
<input
|
|
167
|
+
type="range"
|
|
168
|
+
min={step}
|
|
169
|
+
max={slider_max}
|
|
170
|
+
{step}
|
|
171
|
+
bind:value={settings.isovalue}
|
|
172
|
+
/>
|
|
173
|
+
<span class="value">{format_num(settings.isovalue, `.4~g`)}</span>
|
|
174
|
+
</label>
|
|
175
|
+
|
|
176
|
+
<!-- Opacity + colors on one row -->
|
|
177
|
+
<div class="pane-row compact-row">
|
|
178
|
+
<label
|
|
179
|
+
{@attach tooltip({
|
|
180
|
+
content: `Surface transparency — lower values reveal inner structure`,
|
|
181
|
+
})}
|
|
182
|
+
>
|
|
183
|
+
<span>Opacity:</span>
|
|
184
|
+
<input
|
|
185
|
+
type="range"
|
|
186
|
+
min={0.1}
|
|
187
|
+
max={1}
|
|
188
|
+
step={0.05}
|
|
189
|
+
bind:value={settings.opacity}
|
|
190
|
+
style="width: 60px"
|
|
191
|
+
/>
|
|
192
|
+
<span class="value">{format_num(settings.opacity, `.2f`)}</span>
|
|
193
|
+
</label>
|
|
194
|
+
<label {@attach tooltip({ content: `Color for the positive isovalue surface` })}>
|
|
195
|
+
<span>+ Color</span>
|
|
196
|
+
<input type="color" bind:value={settings.positive_color} />
|
|
197
|
+
</label>
|
|
198
|
+
{#if settings.show_negative}
|
|
199
|
+
<label
|
|
200
|
+
{@attach tooltip({ content: `Color for the negative (−isovalue) surface` })}
|
|
201
|
+
>
|
|
202
|
+
<span>− Color</span>
|
|
203
|
+
<input type="color" bind:value={settings.negative_color} />
|
|
204
|
+
</label>
|
|
205
|
+
{/if}
|
|
206
|
+
</div>
|
|
207
|
+
{/if}
|
|
208
|
+
|
|
209
|
+
{#if volumes?.[active_volume_idx]?.periodic}
|
|
210
|
+
<label
|
|
211
|
+
{@attach tooltip({
|
|
212
|
+
content:
|
|
213
|
+
`Extend isosurface beyond cell boundaries to close partial spheres (fraction of cell)`,
|
|
214
|
+
})}
|
|
215
|
+
>
|
|
216
|
+
Halo: {format_num(settings.halo, `.2f`)}
|
|
217
|
+
<input
|
|
218
|
+
type="range"
|
|
219
|
+
min={0}
|
|
220
|
+
max={0.5}
|
|
221
|
+
step={0.01}
|
|
222
|
+
bind:value={settings.halo}
|
|
223
|
+
/>
|
|
224
|
+
</label>
|
|
225
|
+
{/if}
|
|
226
|
+
|
|
227
|
+
{#if volumes[active_volume_idx]}
|
|
228
|
+
<div class="grid-info">
|
|
229
|
+
{volumes[active_volume_idx].grid_dims.join(` × `)} grid | [{
|
|
230
|
+
format_num(data_range.min, `.3~g`)
|
|
231
|
+
}, {format_num(data_range.max, `.3~g`)}]
|
|
232
|
+
</div>
|
|
233
|
+
{/if}
|
|
234
|
+
</SettingsSection>
|
|
235
|
+
|
|
236
|
+
<style>
|
|
237
|
+
.compact-row {
|
|
238
|
+
flex-wrap: wrap;
|
|
239
|
+
gap: 4pt 14pt;
|
|
240
|
+
}
|
|
241
|
+
label {
|
|
242
|
+
gap: 6pt;
|
|
243
|
+
}
|
|
244
|
+
.grid-info {
|
|
245
|
+
font-size: 0.75em;
|
|
246
|
+
opacity: 0.7;
|
|
247
|
+
padding: 2px 0;
|
|
248
|
+
}
|
|
249
|
+
.layer-row {
|
|
250
|
+
display: flex;
|
|
251
|
+
align-items: center;
|
|
252
|
+
gap: 0.3em;
|
|
253
|
+
font-size: 0.85em;
|
|
254
|
+
input[type='color'] {
|
|
255
|
+
width: 24px;
|
|
256
|
+
height: 20px;
|
|
257
|
+
padding: 0;
|
|
258
|
+
border: 1px solid var(--border-color, #ccc);
|
|
259
|
+
border-radius: 3px;
|
|
260
|
+
box-sizing: border-box;
|
|
261
|
+
cursor: pointer;
|
|
262
|
+
}
|
|
263
|
+
input[type='checkbox'] {
|
|
264
|
+
margin: 0;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
.layer-value {
|
|
268
|
+
font-family: monospace;
|
|
269
|
+
font-size: 0.85em;
|
|
270
|
+
min-width: 3.5em;
|
|
271
|
+
text-align: right;
|
|
272
|
+
}
|
|
273
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { IsosurfaceSettings, VolumetricData } from './types';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
settings?: IsosurfaceSettings;
|
|
4
|
+
volumes?: VolumetricData[];
|
|
5
|
+
active_volume_idx?: number;
|
|
6
|
+
};
|
|
7
|
+
declare const IsosurfaceControls: import("svelte").Component<$$ComponentProps, {}, "settings" | "active_volume_idx">;
|
|
8
|
+
type IsosurfaceControls = ReturnType<typeof IsosurfaceControls>;
|
|
9
|
+
export default IsosurfaceControls;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Isosurface visualization module for volumetric data (CHGCAR, .cube files)
|
|
2
|
+
export { default as Isosurface } from './Isosurface.svelte';
|
|
3
|
+
export { default as IsosurfaceControls } from './IsosurfaceControls.svelte';
|
|
4
|
+
export * from './parse';
|
|
5
|
+
export * from './slice';
|
|
6
|
+
export * from './types';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { VolumetricFileData } from './types';
|
|
2
|
+
export declare function parse_chgcar(content: string): VolumetricFileData | null;
|
|
3
|
+
export declare function parse_cube(content: string, options?: {
|
|
4
|
+
periodic?: boolean;
|
|
5
|
+
}): VolumetricFileData | null;
|
|
6
|
+
export declare function parse_volumetric_file(content: string, filename?: string): VolumetricFileData | null;
|