matterviz 0.4.1 → 0.4.3
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/EmptyState.svelte +10 -4
- package/dist/FilePicker.svelte +48 -60
- package/dist/Icon.svelte +7 -4
- package/dist/MillerIndexInput.svelte +2 -2
- package/dist/api/optimade.js +10 -7
- package/dist/app.css +68 -0
- package/dist/brillouin/BrillouinZone.svelte +90 -91
- package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -7
- package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
- package/dist/brillouin/BrillouinZoneExportPane.svelte +18 -14
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +6 -10
- package/dist/brillouin/BrillouinZoneScene.svelte +46 -68
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
- package/dist/brillouin/compute.js +10 -16
- package/dist/brillouin/geometry.js +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte +48 -50
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +61 -169
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +559 -755
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +1 -1
- package/dist/chempot-diagram/async-compute.svelte.js +13 -14
- package/dist/chempot-diagram/color.d.ts +21 -1
- package/dist/chempot-diagram/color.js +70 -1
- package/dist/chempot-diagram/compute.d.ts +7 -0
- package/dist/chempot-diagram/compute.js +85 -26
- package/dist/chempot-diagram/controls-state.svelte.js +1 -1
- package/dist/chempot-diagram/export.js +1 -6
- package/dist/chempot-diagram/temperature.js +9 -10
- package/dist/colors/index.d.ts +0 -4
- package/dist/colors/index.js +19 -20
- package/dist/composition/BarChart.svelte +30 -26
- package/dist/composition/BubbleChart.svelte +17 -17
- package/dist/composition/Composition.svelte +10 -19
- package/dist/composition/Formula.svelte +20 -27
- package/dist/composition/FormulaFilter.svelte +115 -184
- package/dist/composition/PieChart.svelte +55 -41
- package/dist/composition/format.js +7 -9
- package/dist/composition/index.d.ts +2 -0
- package/dist/composition/index.js +14 -0
- package/dist/composition/parse.d.ts +2 -2
- package/dist/composition/parse.js +61 -115
- package/dist/constants.d.ts +0 -1
- package/dist/constants.js +17 -26
- package/dist/convex-hull/ConvexHull.svelte +12 -15
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull2D.svelte +93 -94
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +127 -186
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +131 -180
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullChrome.svelte +36 -40
- package/dist/convex-hull/ConvexHullControls.svelte +46 -48
- package/dist/convex-hull/ConvexHullStats.svelte +193 -195
- package/dist/convex-hull/ConvexHullTooltip.svelte +5 -12
- package/dist/convex-hull/GasPressureControls.svelte +5 -12
- package/dist/convex-hull/StructurePopup.svelte +18 -22
- package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
- package/dist/convex-hull/TemperatureSlider.svelte +4 -10
- package/dist/convex-hull/canvas-interactions.svelte.js +2 -1
- package/dist/convex-hull/gas-thermodynamics.js +21 -53
- package/dist/convex-hull/helpers.d.ts +8 -10
- package/dist/convex-hull/helpers.js +37 -43
- package/dist/convex-hull/hull-state.svelte.d.ts +1 -1
- package/dist/convex-hull/thermodynamics.js +37 -44
- package/dist/coordination/CoordinationBarPlot.svelte +49 -53
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
- package/dist/coordination/calc-coordination.d.ts +1 -1
- package/dist/coordination/calc-coordination.js +28 -25
- package/dist/element/BohrAtom.svelte +5 -9
- package/dist/element/ElementHeading.svelte +4 -1
- package/dist/element/ElementPhoto.svelte +11 -9
- package/dist/element/ElementStats.svelte +12 -10
- package/dist/element/ElementTile.svelte +44 -67
- package/dist/element/Nucleus.svelte +4 -2
- package/dist/element/data.d.ts +3 -2
- package/dist/element/data.js +5 -1
- package/dist/element/helpers.d.ts +4 -0
- package/dist/element/helpers.js +18 -0
- package/dist/element/index.d.ts +2 -5
- package/dist/element/index.js +4 -19
- package/dist/feedback/DragOverlay.svelte +5 -5
- package/dist/feedback/DragOverlay.svelte.d.ts +2 -2
- package/dist/feedback/StatusMessage.svelte +7 -4
- package/dist/fermi-surface/FermiSlice.svelte +21 -18
- package/dist/fermi-surface/FermiSurface.svelte +35 -44
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +7 -13
- package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +64 -136
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
- package/dist/fermi-surface/compute.js +25 -58
- package/dist/fermi-surface/parse.js +54 -88
- package/dist/file-viewer/JsonBrowser.svelte +1043 -0
- package/dist/file-viewer/JsonBrowser.svelte.d.ts +9 -0
- package/dist/file-viewer/PlotPanel.svelte +350 -0
- package/dist/file-viewer/PlotPanel.svelte.d.ts +9 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte +30 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte.d.ts +10 -0
- package/dist/file-viewer/detect.d.ts +11 -0
- package/dist/file-viewer/detect.js +381 -0
- package/dist/file-viewer/eligibility.d.ts +4 -0
- package/dist/file-viewer/eligibility.js +53 -0
- package/dist/file-viewer/host-protocol.d.ts +50 -0
- package/dist/file-viewer/host-transfer.d.ts +25 -0
- package/dist/file-viewer/host-transfer.js +42 -0
- package/dist/file-viewer/index.d.ts +5 -0
- package/dist/file-viewer/index.js +5 -0
- package/dist/file-viewer/main.d.ts +44 -0
- package/dist/file-viewer/main.js +535 -0
- package/dist/file-viewer/parse.d.ts +9 -0
- package/dist/file-viewer/parse.js +170 -0
- package/dist/file-viewer/plot-utils.d.ts +24 -0
- package/dist/file-viewer/plot-utils.js +191 -0
- package/dist/file-viewer/types.d.ts +4 -0
- package/dist/file-viewer/types.js +5 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +153 -219
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +2 -2
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +9 -7
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
- package/dist/heatmap-matrix/index.d.ts +5 -0
- package/dist/icons.d.ts +4 -0
- package/dist/icons.js +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/io/ExportPane.svelte +11 -7
- package/dist/io/decompress.d.ts +4 -1
- package/dist/io/decompress.js +24 -36
- package/dist/io/export.d.ts +11 -4
- package/dist/io/export.js +75 -19
- package/dist/io/fetch.d.ts +0 -3
- package/dist/io/fetch.js +0 -11
- package/dist/io/file-drop.js +60 -35
- package/dist/io/index.d.ts +0 -1
- package/dist/io/index.js +2 -9
- package/dist/io/is-binary.d.ts +9 -0
- package/dist/io/is-binary.js +45 -1
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +40 -40
- package/dist/isosurface/Isosurface.svelte +700 -215
- package/dist/isosurface/Isosurface.svelte.d.ts +7 -1
- package/dist/isosurface/IsosurfaceControls.svelte +590 -116
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +1 -1
- package/dist/isosurface/VolumeSlice.svelte +224 -0
- package/dist/isosurface/VolumeSlice.svelte.d.ts +28 -0
- package/dist/isosurface/coloring.d.ts +20 -0
- package/dist/isosurface/coloring.js +118 -0
- package/dist/isosurface/geometry-worker-types.d.ts +38 -0
- package/dist/isosurface/geometry.worker.d.ts +1 -0
- package/dist/isosurface/geometry.worker.js +59 -0
- package/dist/isosurface/grid.d.ts +10 -0
- package/dist/isosurface/grid.js +31 -0
- package/dist/isosurface/index.d.ts +4 -0
- package/dist/isosurface/index.js +4 -0
- package/dist/isosurface/parse-vaspwave.d.ts +3 -0
- package/dist/isosurface/parse-vaspwave.js +138 -0
- package/dist/isosurface/parse.js +6 -6
- package/dist/isosurface/profile.d.ts +12 -0
- package/dist/isosurface/profile.js +19 -0
- package/dist/isosurface/sampling.d.ts +34 -0
- package/dist/isosurface/sampling.js +408 -0
- package/dist/isosurface/slice-rendering.d.ts +13 -0
- package/dist/isosurface/slice-rendering.js +79 -0
- package/dist/isosurface/slice.d.ts +22 -2
- package/dist/isosurface/slice.js +200 -116
- package/dist/isosurface/types.d.ts +24 -1
- package/dist/isosurface/types.js +120 -8
- package/dist/json-path.d.ts +4 -0
- package/dist/json-path.js +89 -0
- package/dist/labels.d.ts +6 -2
- package/dist/labels.js +44 -14
- package/dist/layout/FullscreenButton.svelte +2 -1
- package/dist/layout/FullscreenToggle.svelte +10 -4
- package/dist/layout/InfoCard.svelte +8 -21
- package/dist/layout/InfoTag.svelte +1 -3
- package/dist/layout/NumberRangeInput.svelte +46 -0
- package/dist/layout/NumberRangeInput.svelte.d.ts +12 -0
- package/dist/layout/PropertyFilter.svelte +2 -6
- package/dist/layout/SettingsSection.svelte +57 -62
- package/dist/layout/SettingsSection.svelte.d.ts +6 -7
- package/dist/layout/SubpageGrid.svelte +3 -1
- package/dist/layout/ViewerChrome.svelte +16 -11
- package/dist/layout/ViewerChrome.svelte.d.ts +2 -1
- package/dist/layout/fullscreen.js +3 -5
- package/dist/layout/fullscreen.svelte.js +1 -2
- package/dist/layout/index.d.ts +1 -0
- package/dist/layout/index.js +1 -0
- package/dist/layout/json-tree/JsonNode.svelte +22 -59
- package/dist/layout/json-tree/JsonTree.svelte +101 -172
- package/dist/layout/json-tree/JsonValue.svelte +9 -32
- package/dist/layout/json-tree/utils.d.ts +0 -3
- package/dist/layout/json-tree/utils.js +50 -188
- package/dist/marching-cubes.d.ts +8 -1
- package/dist/marching-cubes.js +115 -48
- package/dist/math.d.ts +5 -2
- package/dist/math.js +48 -38
- package/dist/overlays/ContextMenu.svelte +19 -34
- package/dist/overlays/CopyButton.svelte +11 -5
- package/dist/overlays/DragControlTab.svelte +6 -1
- package/dist/overlays/DraggablePane.svelte +110 -74
- package/dist/overlays/DraggablePane.svelte.d.ts +2 -1
- package/dist/overlays/GlassChip.svelte +32 -0
- package/dist/overlays/GlassChip.svelte.d.ts +8 -0
- package/dist/overlays/InfoPaneCards.svelte +11 -23
- package/dist/overlays/index.d.ts +7 -0
- package/dist/overlays/index.js +26 -0
- package/dist/overlays/portal.d.ts +2 -0
- package/dist/overlays/portal.js +14 -0
- package/dist/periodic-table/PeriodicTable.svelte +113 -145
- package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
- package/dist/periodic-table/PeriodicTableControls.svelte +37 -115
- package/dist/periodic-table/TableInset.svelte +9 -4
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +68 -105
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
- package/dist/phase-diagram/PhaseDiagramControls.svelte +70 -94
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +12 -12
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
- package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
- package/dist/phase-diagram/build-diagram.js +4 -9
- package/dist/phase-diagram/diagram-input.d.ts +1 -2
- package/dist/phase-diagram/parse.js +15 -15
- package/dist/phase-diagram/svg-to-diagram.js +28 -27
- package/dist/phase-diagram/utils.js +2 -3
- package/dist/plot/bar/BarPlot.svelte +461 -426
- package/dist/plot/bar/BarPlot.svelte.d.ts +2 -0
- package/dist/plot/bar/BarPlotControls.svelte +1 -3
- package/dist/plot/bar/BarPlotControls.svelte.d.ts +4 -6
- package/dist/plot/bar/SpacegroupBarPlot.svelte +46 -77
- package/dist/plot/bar/data.d.ts +5 -4
- package/dist/plot/bar/data.js +2 -1
- package/dist/plot/box/BoxPlot.svelte +322 -226
- package/dist/plot/box/BoxPlot.svelte.d.ts +2 -0
- package/dist/plot/box/Violin.svelte.d.ts +1 -0
- package/dist/plot/box/box-plot.js +1 -1
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +2 -2
- package/dist/plot/core/axis-utils.d.ts +12 -7
- package/dist/plot/core/axis-utils.js +48 -48
- package/dist/plot/core/components/AxisLabel.svelte +82 -20
- package/dist/plot/core/components/AxisLabel.svelte.d.ts +1 -0
- package/dist/plot/core/components/ColorBar.svelte +101 -106
- package/dist/plot/core/components/ColorScaleSelect.svelte +1 -1
- package/dist/plot/core/components/FillArea.svelte +10 -17
- package/dist/plot/core/components/HierarchyControls.svelte +249 -0
- package/dist/plot/{sunburst/SunburstControls.svelte.d.ts → core/components/HierarchyControls.svelte.d.ts} +12 -8
- package/dist/plot/core/components/InteractiveAxisLabel.svelte +1 -1
- package/dist/plot/core/components/InteractiveAxisLabel.svelte.d.ts +1 -1
- package/dist/plot/core/components/Line.svelte +18 -9
- package/dist/plot/core/components/Line.svelte.d.ts +2 -0
- package/dist/plot/core/components/PlotAxis.svelte +40 -17
- package/dist/plot/core/components/PlotControls.svelte +65 -41
- package/dist/plot/core/components/PlotLegend.svelte +31 -35
- package/dist/plot/core/components/PlotMarginals.svelte +616 -0
- package/dist/plot/core/components/PlotMarginals.svelte.d.ts +15 -0
- package/dist/plot/core/components/PlotTooltip.svelte +1 -1
- package/dist/plot/core/components/PortalSelect.svelte +4 -8
- package/dist/plot/core/components/ReferenceLine.svelte +27 -24
- package/dist/plot/core/components/ReferenceLine3D.svelte +54 -57
- package/dist/plot/core/components/ReferencePlane.svelte +7 -8
- package/dist/plot/core/components/ZeroLines.svelte +4 -8
- package/dist/plot/core/components/ZoomRect.svelte +1 -2
- package/dist/plot/core/components/index.d.ts +1 -0
- package/dist/plot/core/components/index.js +1 -0
- package/dist/plot/core/data-cleaning-signal.d.ts +46 -0
- package/dist/plot/core/data-cleaning-signal.js +467 -0
- package/dist/plot/core/data-cleaning.d.ts +2 -42
- package/dist/plot/core/data-cleaning.js +27 -474
- package/dist/plot/core/data-transform.d.ts +1 -2
- package/dist/plot/core/data-transform.js +9 -15
- package/dist/plot/core/fill-utils.d.ts +3 -1
- package/dist/plot/core/fill-utils.js +28 -6
- package/dist/plot/core/index.d.ts +1 -0
- package/dist/plot/core/index.js +1 -0
- package/dist/plot/core/interactions.js +0 -2
- package/dist/plot/core/layout.d.ts +15 -6
- package/dist/plot/core/layout.js +57 -38
- package/dist/plot/core/marginals.d.ts +170 -0
- package/dist/plot/core/marginals.js +436 -0
- package/dist/plot/core/pan-zoom.svelte.d.ts +2 -4
- package/dist/plot/core/pan-zoom.svelte.js +34 -17
- package/dist/plot/core/placed-tween.svelte.d.ts +3 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -21
- package/dist/plot/core/reference-line.js +1 -1
- package/dist/plot/core/scales.d.ts +23 -0
- package/dist/plot/core/scales.js +39 -13
- package/dist/plot/core/svg.js +0 -1
- package/dist/plot/core/types/fills.d.ts +101 -0
- package/dist/plot/core/types/fills.js +15 -0
- package/dist/plot/core/types/plot-3d.d.ts +87 -0
- package/dist/plot/core/types/plot-3d.js +4 -0
- package/dist/plot/core/types/reference-lines.d.ts +140 -0
- package/dist/plot/core/types/reference-lines.js +9 -0
- package/dist/plot/core/types.d.ts +29 -324
- package/dist/plot/core/types.js +23 -20
- package/dist/plot/core/utils/hierarchy-chart.d.ts +52 -0
- package/dist/plot/core/utils/hierarchy-chart.js +191 -0
- package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
- package/dist/plot/core/utils/hierarchy-labels.js +100 -0
- package/dist/plot/core/utils/label-placement.js +2 -2
- package/dist/plot/histogram/Histogram.svelte +314 -340
- package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
- package/dist/plot/histogram/HistogramControls.svelte +30 -28
- package/dist/plot/histogram/histogram.d.ts +31 -0
- package/dist/plot/histogram/histogram.js +70 -0
- package/dist/plot/histogram/index.d.ts +1 -0
- package/dist/plot/histogram/index.js +1 -0
- package/dist/plot/index.d.ts +1 -0
- package/dist/plot/index.js +1 -0
- package/dist/plot/sankey/Sankey.svelte +78 -69
- package/dist/plot/sankey/Sankey.svelte.d.ts +2 -2
- package/dist/plot/sankey/SankeyControls.svelte +22 -16
- package/dist/plot/sankey/sankey.js +13 -9
- package/dist/plot/scatter/BinnedScatterPlot.svelte +311 -141
- package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +7 -0
- package/dist/plot/scatter/ElementScatter.svelte +4 -1
- package/dist/plot/scatter/ScatterPlot.svelte +517 -410
- package/dist/plot/scatter/ScatterPlot.svelte.d.ts +2 -0
- package/dist/plot/scatter/ScatterPlotControls.svelte +18 -19
- package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/scatter/ScatterPoint.svelte +16 -9
- package/dist/plot/scatter/adaptive-density.d.ts +1 -1
- package/dist/plot/scatter/adaptive-density.js +36 -20
- package/dist/plot/scatter/binned-scatter-types.d.ts +3 -2
- package/dist/plot/scatter/binned-scatter-types.js +6 -1
- package/dist/plot/scatter/scatter-data.d.ts +1 -1
- package/dist/plot/scatter/scatter-data.js +8 -7
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte +25 -34
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +2 -2
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +8 -5
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +113 -116
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +2 -2
- package/dist/plot/scatter-3d/Surface3D.svelte +4 -13
- package/dist/plot/sunburst/Sunburst.svelte +269 -347
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +2 -2
- package/dist/plot/sunburst/index.d.ts +1 -1
- package/dist/plot/sunburst/index.js +2 -1
- package/dist/plot/sunburst/render.d.ts +2 -2
- package/dist/plot/sunburst/render.js +47 -22
- package/dist/plot/sunburst/sunburst.d.ts +5 -1
- package/dist/plot/sunburst/sunburst.js +10 -3
- package/dist/plot/treemap/Treemap.svelte +1022 -0
- package/dist/plot/treemap/Treemap.svelte.d.ts +90 -0
- package/dist/plot/treemap/index.d.ts +4 -0
- package/dist/plot/treemap/index.js +4 -0
- package/dist/plot/treemap/labels.d.ts +38 -0
- package/dist/plot/treemap/labels.js +80 -0
- package/dist/plot/treemap/treemap.d.ts +28 -0
- package/dist/plot/treemap/treemap.js +102 -0
- package/dist/rdf/RdfPlot.svelte +37 -59
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/rdf/calc-rdf.js +63 -52
- package/dist/rdf/index.d.ts +0 -1
- package/dist/sanitize.js +85 -27
- package/dist/scene/SceneCamera.svelte +1 -1
- package/dist/scene/SceneCamera.svelte.d.ts +1 -1
- package/dist/scene/bind-renderer.svelte.js +14 -6
- package/dist/scene/index.d.ts +1 -2
- package/dist/scene/index.js +1 -1
- package/dist/scene/{props.js → props.svelte.js} +15 -1
- package/dist/settings.d.ts +19 -9
- package/dist/settings.js +229 -525
- package/dist/spectral/Bands.svelte +207 -221
- package/dist/spectral/BandsAndDos.svelte +11 -9
- package/dist/spectral/BrillouinBandsDos.svelte +19 -42
- package/dist/spectral/Dos.svelte +92 -93
- package/dist/spectral/helpers.d.ts +3 -3
- package/dist/spectral/helpers.js +65 -140
- package/dist/state.svelte.js +5 -18
- package/dist/structure/Arrow.svelte +5 -18
- package/dist/structure/ArrowInstances.svelte +160 -0
- package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
- package/dist/structure/AtomLegend.svelte +120 -85
- package/dist/structure/AtomLegend.svelte.d.ts +2 -3
- package/dist/structure/Bond.svelte +31 -23
- package/dist/structure/CanvasTooltip.svelte +15 -3
- package/dist/structure/CellSelect.svelte +45 -35
- package/dist/structure/Cylinder.svelte +24 -40
- package/dist/structure/InstancedAtoms.svelte +114 -0
- package/dist/structure/InstancedAtoms.svelte.d.ts +15 -0
- package/dist/structure/Lattice.svelte +85 -149
- package/dist/structure/SiteLabels.svelte +122 -0
- package/dist/structure/SiteLabels.svelte.d.ts +18 -0
- package/dist/structure/Structure.svelte +636 -504
- package/dist/structure/Structure.svelte.d.ts +4 -2
- package/dist/structure/StructureCarousel.svelte +637 -0
- package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
- package/dist/structure/StructureControls.svelte +165 -425
- package/dist/structure/StructureControls.svelte.d.ts +1 -1
- package/dist/structure/StructureExportPane.svelte +17 -21
- package/dist/structure/StructureInfoPane.svelte +128 -133
- package/dist/structure/StructureInfoPane.svelte.d.ts +1 -1
- package/dist/structure/StructureScene.svelte +535 -578
- package/dist/structure/StructureScene.svelte.d.ts +6 -2
- package/dist/structure/StructureViewport.svelte +451 -0
- package/dist/structure/StructureViewport.svelte.d.ts +65 -0
- package/dist/structure/atom-label-placement.d.ts +16 -12
- package/dist/structure/atom-label-placement.js +70 -37
- package/dist/structure/atom-properties.d.ts +2 -0
- package/dist/structure/atom-properties.js +105 -38
- package/dist/structure/bond-order-perception.js +3 -8
- package/dist/structure/bonding.d.ts +9 -3
- package/dist/structure/bonding.js +95 -46
- package/dist/structure/edit-history.d.ts +6 -0
- package/dist/structure/edit-history.js +27 -0
- package/dist/structure/export.d.ts +1 -0
- package/dist/structure/export.js +89 -105
- package/dist/structure/format-detect.d.ts +1 -0
- package/dist/structure/format-detect.js +20 -0
- package/dist/structure/geometry.d.ts +9 -0
- package/dist/structure/geometry.js +27 -0
- package/dist/structure/index.d.ts +16 -1
- package/dist/structure/index.js +15 -10
- package/dist/structure/measure.d.ts +1 -1
- package/dist/structure/measure.js +6 -12
- package/dist/structure/parse.d.ts +2 -1
- package/dist/structure/parse.js +272 -313
- package/dist/structure/partial-occupancy.js +10 -5
- package/dist/structure/pbc.js +85 -107
- package/dist/structure/polyhedra.d.ts +0 -1
- package/dist/structure/polyhedra.js +7 -21
- package/dist/structure/prop-groups.d.ts +85 -0
- package/dist/structure/prop-groups.js +18 -0
- package/dist/structure/supercell.d.ts +1 -2
- package/dist/structure/supercell.js +7 -13
- package/dist/symmetry/SymmetryElements.svelte +11 -15
- package/dist/symmetry/SymmetryStats.svelte +55 -71
- package/dist/symmetry/WyckoffTable.svelte +10 -28
- package/dist/symmetry/cell-transform.js +6 -14
- package/dist/symmetry/index.d.ts +1 -0
- package/dist/symmetry/index.js +13 -10
- package/dist/symmetry/spacegroups.js +3 -2
- package/dist/table/HeatmapTable.svelte +1142 -447
- package/dist/table/HeatmapTable.svelte.d.ts +12 -2
- package/dist/table/ToggleMenu.svelte +168 -53
- package/dist/table/ToggleMenu.svelte.d.ts +1 -1
- package/dist/table/index.d.ts +21 -6
- package/dist/table/index.js +34 -21
- package/dist/theme/ThemeControl.svelte +16 -8
- package/dist/theme/embedded.d.ts +18 -0
- package/dist/theme/embedded.js +206 -0
- package/dist/theme/index.d.ts +5 -5
- package/dist/theme/index.js +5 -12
- package/dist/theme/themes.mjs +44 -66
- package/dist/tooltip/KCoords.svelte +4 -1
- package/dist/tooltip/TooltipContent.svelte +3 -6
- package/dist/tooltip/TooltipContent.svelte.d.ts +1 -1
- package/dist/tooltip/index.d.ts +8 -1
- package/dist/trajectory/Trajectory.svelte +613 -386
- package/dist/trajectory/Trajectory.svelte.d.ts +1 -1
- package/dist/trajectory/TrajectoryError.svelte +12 -74
- package/dist/trajectory/TrajectoryExportPane.svelte +14 -32
- package/dist/trajectory/TrajectoryInfoPane.svelte +127 -164
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +2 -1
- package/dist/trajectory/extract.js +61 -49
- package/dist/trajectory/format-detect.d.ts +2 -0
- package/dist/trajectory/format-detect.js +17 -13
- package/dist/trajectory/frame-reader.d.ts +2 -0
- package/dist/trajectory/frame-reader.js +35 -32
- package/dist/trajectory/helpers.d.ts +2 -0
- package/dist/trajectory/helpers.js +34 -56
- package/dist/trajectory/index.d.ts +1 -0
- package/dist/trajectory/index.js +5 -8
- package/dist/trajectory/parse/ase.js +1 -1
- package/dist/trajectory/parse/h5-utils.d.ts +13 -0
- package/dist/trajectory/parse/h5-utils.js +109 -0
- package/dist/trajectory/parse/hdf5.d.ts +1 -1
- package/dist/trajectory/parse/hdf5.js +116 -106
- package/dist/trajectory/parse/index.d.ts +6 -6
- package/dist/trajectory/parse/index.js +25 -33
- package/dist/trajectory/parse/lammps.js +8 -12
- package/dist/trajectory/parse/vasp.js +10 -7
- package/dist/trajectory/parse/vaspout-electronic.d.ts +13 -0
- package/dist/trajectory/parse/vaspout-electronic.js +207 -0
- package/dist/trajectory/parse/vaspout-h5.d.ts +4 -0
- package/dist/trajectory/parse/vaspout-h5.js +281 -0
- package/dist/trajectory/parse/xyz.js +59 -9
- package/dist/trajectory/plotting.d.ts +8 -9
- package/dist/trajectory/plotting.js +113 -64
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +7 -0
- package/dist/xrd/XrdPlot.svelte +79 -118
- package/dist/xrd/broadening.js +2 -1
- package/dist/xrd/calc-xrd.js +24 -62
- package/dist/xrd/parse.d.ts +0 -1
- package/dist/xrd/parse.js +69 -95
- package/package.json +94 -34
- package/readme.md +6 -5
- package/dist/api/mp.d.ts +0 -6
- package/dist/api/mp.js +0 -22
- package/dist/plot/sunburst/SunburstControls.svelte +0 -200
- package/dist/scene/types.d.ts +0 -26
- package/dist/tooltip/types.d.ts +0 -8
- package/dist/trajectory/constants.d.ts +0 -6
- package/dist/trajectory/constants.js +0 -11
- /package/dist/{scene/types.js → file-viewer/host-protocol.js} +0 -0
- /package/dist/{tooltip/types.js → isosurface/geometry-worker-types.js} +0 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Parser for VASP vaspwave.h5 charge density: charge/charge on charge/grid
|
|
2
|
+
// plus the embedded structure under structure/positions (dataset paths follow
|
|
3
|
+
// ferrox's VASPWAVE_* constants / py4vasp's VASP 6.x schema). Full files are
|
|
4
|
+
// hundreds of MB, so embedding hosts are expected to prune them server-side
|
|
5
|
+
// first; this parser sees only charge/{charge,grid} + structure/positions.
|
|
6
|
+
//
|
|
7
|
+
// Prototype scope: charge (+ magnetization) isosurfaces only — wavefunctions
|
|
8
|
+
// are out of scope. The "charge density RMS per SCF step" convergence signal
|
|
9
|
+
// is already covered by OSZICAR's rms(c) column in the vaspout.h5 parser
|
|
10
|
+
// (scf_charge_rms frame metadata); diffing charge grids between live reloads
|
|
11
|
+
// is explicitly out of scope here.
|
|
12
|
+
import { calc_lattice_params, create_frac_to_cart } from '../math';
|
|
13
|
+
import { wrap_to_unit_cell } from '../structure/pbc';
|
|
14
|
+
import { make_site } from '../structure/site';
|
|
15
|
+
import { validate_3x3_matrix } from '../trajectory/helpers';
|
|
16
|
+
import { expand_ion_types, is_hdf5_dataset, read_dataset, scale_matrix, to_number_array, to_scalar_number, to_string_array, with_h5_file, } from '../trajectory/parse/h5-utils';
|
|
17
|
+
import { grid_data_range } from './types';
|
|
18
|
+
const CHARGE_PATH = `charge/charge`;
|
|
19
|
+
const CHARGE_GRID_PATH = `charge/grid`;
|
|
20
|
+
const STRUCTURE_PREFIX = `structure/positions`;
|
|
21
|
+
// vaspwave carries charge density/wavefunctions, never a trajectory — used by
|
|
22
|
+
// file-open routing to divert from the HDF5 trajectory dispatcher.
|
|
23
|
+
export const is_vaspwave_filename = (filename) => {
|
|
24
|
+
const basename = filename.split(`/`).pop() ?? filename;
|
|
25
|
+
return /vaspwave.*\.(?:h5|hdf5)$/i.test(basename);
|
|
26
|
+
};
|
|
27
|
+
const dataset_shape = (h5_file, path) => {
|
|
28
|
+
const entity = h5_file.get(path);
|
|
29
|
+
return is_hdf5_dataset(entity) ? (entity.shape ?? null) : null;
|
|
30
|
+
};
|
|
31
|
+
const read_embedded_structure = (h5_file) => {
|
|
32
|
+
const lattice_data = read_dataset(h5_file, `${STRUCTURE_PREFIX}/lattice_vectors`);
|
|
33
|
+
if (!lattice_data) {
|
|
34
|
+
throw new Error(`vaspwave.h5 has no embedded structure (${STRUCTURE_PREFIX}/lattice_vectors) — ` +
|
|
35
|
+
`cannot place the charge grid in a lattice`);
|
|
36
|
+
}
|
|
37
|
+
const scale = to_scalar_number(read_dataset(h5_file, `${STRUCTURE_PREFIX}/scale`)) ?? 1;
|
|
38
|
+
const lattice = scale_matrix(validate_3x3_matrix(lattice_data), scale);
|
|
39
|
+
// Sites are optional for rendering (the isosurface needs only the lattice),
|
|
40
|
+
// so a pruned/torn file missing ion data still opens with an empty cell.
|
|
41
|
+
const sites = [];
|
|
42
|
+
const ion_types = to_string_array(read_dataset(h5_file, `${STRUCTURE_PREFIX}/ion_types`));
|
|
43
|
+
const ion_counts = to_number_array(read_dataset(h5_file, `${STRUCTURE_PREFIX}/number_ion_types`));
|
|
44
|
+
const frac_positions = read_dataset(h5_file, `${STRUCTURE_PREFIX}/position_ions`);
|
|
45
|
+
if (ion_types && ion_counts && frac_positions && ion_types.length === ion_counts.length) {
|
|
46
|
+
const elements = expand_ion_types(ion_types, ion_counts);
|
|
47
|
+
const frac_to_cart = create_frac_to_cart(lattice);
|
|
48
|
+
for (const [site_idx, element] of elements.entries()) {
|
|
49
|
+
const frac = frac_positions[site_idx];
|
|
50
|
+
if (!Array.isArray(frac) || frac.length < 3)
|
|
51
|
+
break; // torn positions: keep what parsed
|
|
52
|
+
const abc = wrap_to_unit_cell(frac.slice(0, 3));
|
|
53
|
+
sites.push(make_site(element, abc, frac_to_cart(abc), `${element}${site_idx + 1}`));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
sites,
|
|
58
|
+
lattice: { matrix: lattice, pbc: [true, true, true], ...calc_lattice_params(lattice) },
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
// VASP writes volumetric data C-order [components, nz, ny, nx]; the grid
|
|
62
|
+
// dataset [nx, ny, nz] disambiguates (same logic as ferrox's
|
|
63
|
+
// volumetric_grid_shape_and_order — when nx == nz both layouts match, so
|
|
64
|
+
// default to the canonical zyx order).
|
|
65
|
+
const charge_axis_order = (spatial_shape, grid_dims) => {
|
|
66
|
+
const [nx, ny, nz] = grid_dims;
|
|
67
|
+
const matches = (dims) => dims.every((dim, idx) => dim === spatial_shape[idx]);
|
|
68
|
+
if (matches([nz, ny, nx]))
|
|
69
|
+
return `zyx`;
|
|
70
|
+
if (matches([nx, ny, nz]))
|
|
71
|
+
return `xyz`;
|
|
72
|
+
throw new Error(`vaspwave.h5 ${CHARGE_GRID_PATH} [${grid_dims}] is incompatible with ` +
|
|
73
|
+
`${CHARGE_PATH} spatial shape [${spatial_shape}]`);
|
|
74
|
+
};
|
|
75
|
+
function parse_vaspwave_charge_file(h5_file) {
|
|
76
|
+
const shape = dataset_shape(h5_file, CHARGE_PATH);
|
|
77
|
+
if (!shape) {
|
|
78
|
+
throw new Error(`vaspwave.h5 file has no charge density (missing ${CHARGE_PATH})`);
|
|
79
|
+
}
|
|
80
|
+
// Only the dimension count is checked here — the spatial axis order (zyx vs
|
|
81
|
+
// xyz) is disambiguated later by charge_axis_order against CHARGE_GRID_PATH.
|
|
82
|
+
if (shape.length !== 4) {
|
|
83
|
+
throw new Error(`${CHARGE_PATH} must have 4 dimensions, got [${shape}]`);
|
|
84
|
+
}
|
|
85
|
+
const n_components = shape[0];
|
|
86
|
+
if (n_components < 1 || n_components > 2) {
|
|
87
|
+
throw new Error(`${CHARGE_PATH} has unsupported component count ${n_components}; expected 1 ` +
|
|
88
|
+
`(non-spin-polarized) or 2 (total + magnetization)`);
|
|
89
|
+
}
|
|
90
|
+
const grid_dims = to_number_array(read_dataset(h5_file, CHARGE_GRID_PATH));
|
|
91
|
+
if (grid_dims?.length !== 3) {
|
|
92
|
+
throw new Error(`vaspwave.h5 is missing ${CHARGE_GRID_PATH}; cannot determine the axis order of ${CHARGE_PATH}`);
|
|
93
|
+
}
|
|
94
|
+
const axis_order = charge_axis_order(shape.slice(1), grid_dims);
|
|
95
|
+
const [nx, ny, nz] = grid_dims;
|
|
96
|
+
const structure = read_embedded_structure(h5_file);
|
|
97
|
+
const lattice = structure.lattice.matrix;
|
|
98
|
+
const charge_data = read_dataset(h5_file, CHARGE_PATH);
|
|
99
|
+
if (!charge_data)
|
|
100
|
+
throw new Error(`Failed to read ${CHARGE_PATH} data`);
|
|
101
|
+
// Metadata shape and decoded data can disagree in torn/corrupt files — fail
|
|
102
|
+
// loudly instead of silently rendering fewer components than the file claims
|
|
103
|
+
if (charge_data.length !== n_components) {
|
|
104
|
+
throw new Error(`${CHARGE_PATH} decoded ${charge_data.length} components but its shape claims ${n_components}`);
|
|
105
|
+
}
|
|
106
|
+
const component_labels = [`charge density`, `magnetization density`];
|
|
107
|
+
const volumes = charge_data.map((component, component_idx) => {
|
|
108
|
+
const grid = Array(nx);
|
|
109
|
+
for (let x_idx = 0; x_idx < nx; x_idx++) {
|
|
110
|
+
const plane = Array(ny);
|
|
111
|
+
for (let y_idx = 0; y_idx < ny; y_idx++) {
|
|
112
|
+
const row = Array(nz);
|
|
113
|
+
for (let z_idx = 0; z_idx < nz; z_idx++) {
|
|
114
|
+
row[z_idx] =
|
|
115
|
+
axis_order === `zyx`
|
|
116
|
+
? component[z_idx][y_idx][x_idx]
|
|
117
|
+
: component[x_idx][y_idx][z_idx];
|
|
118
|
+
}
|
|
119
|
+
plane[y_idx] = row;
|
|
120
|
+
}
|
|
121
|
+
grid[x_idx] = plane;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
grid,
|
|
125
|
+
grid_dims: [nx, ny, nz],
|
|
126
|
+
lattice,
|
|
127
|
+
origin: [0, 0, 0],
|
|
128
|
+
data_range: grid_data_range(grid),
|
|
129
|
+
data_order: `x_fastest`,
|
|
130
|
+
periodic: true,
|
|
131
|
+
label: component_labels[component_idx],
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
return { structure, volumes };
|
|
135
|
+
}
|
|
136
|
+
export async function parse_vaspwave_charge(buffer, filename) {
|
|
137
|
+
return with_h5_file(buffer, filename, parse_vaspwave_charge_file);
|
|
138
|
+
}
|
package/dist/isosurface/parse.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// Parsers for volumetric data file formats (VASP CHGCAR, Gaussian .cube)
|
|
2
2
|
import { ATOMIC_NUMBER_TO_SYMBOL } from '../composition/parse';
|
|
3
3
|
import { VASP_VOLUMETRIC_REGEX } from '../constants';
|
|
4
|
-
import { coerce_elem_symbol, FALLBACK_ELEMENTS } from '../element';
|
|
5
|
-
import { strip_compression_extensions } from '../io';
|
|
4
|
+
import { coerce_elem_symbol, FALLBACK_ELEMENTS } from '../element/helpers';
|
|
5
|
+
import { strip_compression_extensions } from '../io/decompress';
|
|
6
6
|
import * as math from '../math';
|
|
7
7
|
import { wrap_to_unit_cell } from '../structure/pbc';
|
|
8
8
|
import { make_site } from '../structure/site';
|
|
9
|
+
import { parse_leading_num } from '../utils';
|
|
9
10
|
// Bohr radius in Angstroms (for Gaussian .cube unit conversion)
|
|
10
11
|
const BOHR_TO_ANGSTROM = 0.529177249;
|
|
11
12
|
// === Parse error contract ===
|
|
@@ -188,7 +189,7 @@ export function parse_chgcar(content) {
|
|
|
188
189
|
pos = cur.next;
|
|
189
190
|
// Line 1: scale factor
|
|
190
191
|
cur = read_line(content, pos);
|
|
191
|
-
const scale_factor =
|
|
192
|
+
const scale_factor = parse_leading_num(cur.line);
|
|
192
193
|
if (isNaN(scale_factor)) {
|
|
193
194
|
vol_error(`Invalid scaling factor in CHGCAR`);
|
|
194
195
|
return null;
|
|
@@ -212,8 +213,7 @@ export function parse_chgcar(content) {
|
|
|
212
213
|
return null;
|
|
213
214
|
}
|
|
214
215
|
// Detect VASP 5+ format (has element symbols before counts)
|
|
215
|
-
const
|
|
216
|
-
const has_element_symbols = isNaN(parseInt(first_token, 10));
|
|
216
|
+
const has_element_symbols = isNaN(parse_leading_num(cur.line));
|
|
217
217
|
if (has_element_symbols) {
|
|
218
218
|
element_symbols = cur.line.trim().split(/\s+/);
|
|
219
219
|
pos = cur.next;
|
|
@@ -536,7 +536,7 @@ export function parse_volumetric_file(content, filename) {
|
|
|
536
536
|
// CHGCAR detection: requires POSCAR-like header (scale factor on line 2) AND
|
|
537
537
|
// a grid dimensions line (3 integers) somewhere after the header. This distinguishes
|
|
538
538
|
// CHGCAR from plain POSCAR/CONTCAR files which share the same header format.
|
|
539
|
-
if (lines.length > 2 && !isNaN(
|
|
539
|
+
if (lines.length > 2 && !isNaN(parse_leading_num(lines[1]))) {
|
|
540
540
|
// Scan for grid dimensions line (3 integers) starting from ~line 7
|
|
541
541
|
let scan_pos = find_line_offset(content, 7);
|
|
542
542
|
// Only scan a limited window, not the entire file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type IsosurfaceProfileStage = `prepare_geometry` | `marching_cubes` | `build_geometry` | `sample_scalars` | `scalar_range` | `apply_colormap` | `rebuild_total` | `recolor_total`;
|
|
2
|
+
export type IsosurfaceProfileMeta = Record<string, boolean | number | string>;
|
|
3
|
+
export interface IsosurfaceProfileEvent {
|
|
4
|
+
stage: IsosurfaceProfileStage;
|
|
5
|
+
duration_ms: number;
|
|
6
|
+
meta: IsosurfaceProfileMeta;
|
|
7
|
+
}
|
|
8
|
+
export type IsosurfaceProfiler = (event: IsosurfaceProfileEvent) => void;
|
|
9
|
+
/** Record a stage whose duration was measured elsewhere. */
|
|
10
|
+
export declare function record_profile(profiler: IsosurfaceProfiler | undefined, stage: IsosurfaceProfileStage, duration_ms: number, meta?: IsosurfaceProfileMeta): void;
|
|
11
|
+
/** Time a synchronous pipeline stage only when an internal profiler is attached. */
|
|
12
|
+
export declare function profile_stage<Result>(profiler: IsosurfaceProfiler | undefined, stage: IsosurfaceProfileStage, operation: () => Result, meta?: IsosurfaceProfileMeta | ((result: Result) => IsosurfaceProfileMeta)): Result;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Internal, opt-in profiling primitives for the isosurface benchmark route.
|
|
2
|
+
// This module is intentionally not re-exported from the public package barrels.
|
|
3
|
+
/** Record a stage whose duration was measured elsewhere. */
|
|
4
|
+
export function record_profile(profiler, stage, duration_ms, meta = {}) {
|
|
5
|
+
profiler?.({ stage, duration_ms, meta });
|
|
6
|
+
}
|
|
7
|
+
/** Time a synchronous pipeline stage only when an internal profiler is attached. */
|
|
8
|
+
export function profile_stage(profiler, stage, operation, meta = {}) {
|
|
9
|
+
if (!profiler)
|
|
10
|
+
return operation();
|
|
11
|
+
const start_time = performance.now();
|
|
12
|
+
const result = operation();
|
|
13
|
+
profiler({
|
|
14
|
+
stage,
|
|
15
|
+
duration_ms: performance.now() - start_time,
|
|
16
|
+
meta: typeof meta === `function` ? meta(result) : meta,
|
|
17
|
+
});
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Matrix3x3, Vec2, Vec3 } from '../math';
|
|
2
|
+
import { type VolumetricData } from './types';
|
|
3
|
+
export declare function trilinear_interpolate(grid: number[][][], fx: number, fy: number, fz: number, periodic: boolean): number;
|
|
4
|
+
export type OutOfBoundsPolicy = `clamp` | `fallback`;
|
|
5
|
+
export interface VolumeSamplerOptions {
|
|
6
|
+
out_of_bounds?: OutOfBoundsPolicy;
|
|
7
|
+
}
|
|
8
|
+
export interface BulkVolumeSamplerOptions extends VolumeSamplerOptions {
|
|
9
|
+
position_offset?: Vec3;
|
|
10
|
+
out?: Float32Array;
|
|
11
|
+
}
|
|
12
|
+
export declare function create_volume_sampler(volume: VolumetricData, options?: VolumeSamplerOptions): (position: Vec3) => number;
|
|
13
|
+
export declare function sample_volume_at_positions(volume: VolumetricData, positions: Float32Array | Float64Array, options?: BulkVolumeSamplerOptions): Float32Array;
|
|
14
|
+
export interface GridCompatibility {
|
|
15
|
+
ok: boolean;
|
|
16
|
+
reason?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function compare_volume_grids(vol_a: VolumetricData, vol_b: VolumetricData, { tolerance }?: {
|
|
19
|
+
tolerance?: number;
|
|
20
|
+
}): GridCompatibility;
|
|
21
|
+
export type DisplayRange = [Vec2, Vec2, Vec2];
|
|
22
|
+
export declare function sanitize_display_range(range: DisplayRange, periodic: boolean): DisplayRange;
|
|
23
|
+
export interface VolumeDisplayRangeOptions {
|
|
24
|
+
display_range?: DisplayRange;
|
|
25
|
+
tiling?: Vec3;
|
|
26
|
+
halo?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function resolve_volume_display_range(volume: VolumetricData, { display_range, tiling, halo }?: VolumeDisplayRangeOptions): DisplayRange | null;
|
|
29
|
+
export declare function extract_volume_range(volume: VolumetricData, range: DisplayRange, max_points?: number): VolumetricData;
|
|
30
|
+
export declare function prepare_geometry_grid(volume: VolumetricData, range: DisplayRange | null): {
|
|
31
|
+
grid: number[][][];
|
|
32
|
+
lattice: Matrix3x3;
|
|
33
|
+
origin: Vec3;
|
|
34
|
+
};
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { create_cart_to_frac_matrix, scale_lattice_matrix } from '../math';
|
|
2
|
+
import { grid_dimensions } from './grid';
|
|
3
|
+
import { downsample_grid, MAX_GRID_POINTS } from './types';
|
|
4
|
+
const safe_mod = (val, dim) => ((val % dim) + dim) % dim;
|
|
5
|
+
// Lower/upper voxel indices for one axis of a trilinear sample. Singleton axes
|
|
6
|
+
// (n===1) pin both corners to 0 so nx-2 clamping never goes negative.
|
|
7
|
+
const voxel_corners = (n, floor_g, periodic) => {
|
|
8
|
+
if (n === 1)
|
|
9
|
+
return [0, 0];
|
|
10
|
+
const lower = periodic ? safe_mod(floor_g, n) : Math.max(0, Math.min(floor_g, n - 2));
|
|
11
|
+
return [lower, periodic ? (lower + 1) % n : Math.min(lower + 1, n - 1)];
|
|
12
|
+
};
|
|
13
|
+
// Trilinear interpolation of a scalar 3D grid at fractional coordinates.
|
|
14
|
+
// Periodic grids wrap with modulo; non-periodic return 0 for out-of-bounds.
|
|
15
|
+
export function trilinear_interpolate(grid, fx, fy, fz, periodic) {
|
|
16
|
+
const nx = grid.length;
|
|
17
|
+
const ny = grid[0]?.length ?? 0;
|
|
18
|
+
const nz = grid[0]?.[0]?.length ?? 0;
|
|
19
|
+
if (nx === 0 || ny === 0 || nz === 0)
|
|
20
|
+
return 0;
|
|
21
|
+
// Convert fractional to grid coordinates
|
|
22
|
+
const gx = periodic ? fx * nx : fx * (nx - 1);
|
|
23
|
+
const gy = periodic ? fy * ny : fy * (ny - 1);
|
|
24
|
+
const gz = periodic ? fz * nz : fz * (nz - 1);
|
|
25
|
+
if (!periodic) {
|
|
26
|
+
// Out-of-bounds check for non-periodic grids
|
|
27
|
+
if (fx < 0 || fx > 1 || fy < 0 || fy > 1 || fz < 0 || fz > 1)
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
const [x0, x1] = voxel_corners(nx, Math.floor(gx), periodic);
|
|
31
|
+
const [y0, y1] = voxel_corners(ny, Math.floor(gy), periodic);
|
|
32
|
+
const [z0, z1] = voxel_corners(nz, Math.floor(gz), periodic);
|
|
33
|
+
// deltas from clamped lower index (non-periodic x0 clamps to nx-2 so floor(gx) may != x0)
|
|
34
|
+
const xd = periodic ? gx - Math.floor(gx) : gx - x0;
|
|
35
|
+
const yd = periodic ? gy - Math.floor(gy) : gy - y0;
|
|
36
|
+
const zd = periodic ? gz - Math.floor(gz) : gz - z0;
|
|
37
|
+
// 8-point interpolation
|
|
38
|
+
const c000 = grid[x0][y0][z0];
|
|
39
|
+
const c001 = grid[x0][y0][z1];
|
|
40
|
+
const c010 = grid[x0][y1][z0];
|
|
41
|
+
const c011 = grid[x0][y1][z1];
|
|
42
|
+
const c100 = grid[x1][y0][z0];
|
|
43
|
+
const c101 = grid[x1][y0][z1];
|
|
44
|
+
const c110 = grid[x1][y1][z0];
|
|
45
|
+
const c111 = grid[x1][y1][z1];
|
|
46
|
+
const c00 = c000 + (c100 - c000) * xd;
|
|
47
|
+
const c01 = c001 + (c101 - c001) * xd;
|
|
48
|
+
const c10 = c010 + (c110 - c010) * xd;
|
|
49
|
+
const c11 = c011 + (c111 - c011) * xd;
|
|
50
|
+
const c0 = c00 + (c10 - c00) * yd;
|
|
51
|
+
const c1 = c01 + (c11 - c01) * yd;
|
|
52
|
+
return c0 + (c1 - c0) * zd;
|
|
53
|
+
}
|
|
54
|
+
// Small tolerance so vertices numerically on the boundary of a finite grid
|
|
55
|
+
// (e.g. marching-cubes output at fractional coordinate 1.0 + 1e-16) still sample.
|
|
56
|
+
const OOB_TOL = 1e-6;
|
|
57
|
+
const prepared_sampler_cache = new WeakMap();
|
|
58
|
+
const prepare_volume_sampler = (volume) => {
|
|
59
|
+
const grid_dims = grid_dimensions(volume.grid);
|
|
60
|
+
const signature = [
|
|
61
|
+
...volume.lattice.flat(),
|
|
62
|
+
...volume.origin,
|
|
63
|
+
...grid_dims,
|
|
64
|
+
Number(volume.periodic),
|
|
65
|
+
].join(`,`);
|
|
66
|
+
const cached = prepared_sampler_cache.get(volume);
|
|
67
|
+
if (cached?.grid === volume.grid && cached.signature === signature)
|
|
68
|
+
return cached;
|
|
69
|
+
const prepared = {
|
|
70
|
+
grid: volume.grid,
|
|
71
|
+
inv: create_cart_to_frac_matrix(volume.lattice),
|
|
72
|
+
origin: volume.origin,
|
|
73
|
+
periodic: volume.periodic,
|
|
74
|
+
grid_dims,
|
|
75
|
+
signature,
|
|
76
|
+
};
|
|
77
|
+
prepared_sampler_cache.set(volume, prepared);
|
|
78
|
+
return prepared;
|
|
79
|
+
};
|
|
80
|
+
// Create a sampler that maps absolute Cartesian positions (in the same physical
|
|
81
|
+
// frame as the volume's `origin`) to trilinearly-interpolated scalar values.
|
|
82
|
+
// Handles non-orthogonal lattices, origin offsets, and periodic wrapping, so it
|
|
83
|
+
// works both for strictly matching grids and for general resampling between
|
|
84
|
+
// volumes that share a Cartesian coordinate system.
|
|
85
|
+
// The hot callback uses scalar arithmetic only (no per-call array allocations)
|
|
86
|
+
// since it runs once per isosurface vertex.
|
|
87
|
+
export function create_volume_sampler(volume, options = {}) {
|
|
88
|
+
const { out_of_bounds = `clamp` } = options;
|
|
89
|
+
const { grid, inv, origin, periodic } = prepare_volume_sampler(volume);
|
|
90
|
+
const [ox, oy, oz] = origin;
|
|
91
|
+
return (position) => {
|
|
92
|
+
const cx = position[0] - ox;
|
|
93
|
+
const cy = position[1] - oy;
|
|
94
|
+
const cz = position[2] - oz;
|
|
95
|
+
let fx = inv[0][0] * cx + inv[0][1] * cy + inv[0][2] * cz;
|
|
96
|
+
let fy = inv[1][0] * cx + inv[1][1] * cy + inv[1][2] * cz;
|
|
97
|
+
let fz = inv[2][0] * cx + inv[2][1] * cy + inv[2][2] * cz;
|
|
98
|
+
if (periodic) {
|
|
99
|
+
fx = safe_mod(fx, 1);
|
|
100
|
+
fy = safe_mod(fy, 1);
|
|
101
|
+
fz = safe_mod(fz, 1);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
if (out_of_bounds === `fallback` &&
|
|
105
|
+
(fx < -OOB_TOL ||
|
|
106
|
+
fx > 1 + OOB_TOL ||
|
|
107
|
+
fy < -OOB_TOL ||
|
|
108
|
+
fy > 1 + OOB_TOL ||
|
|
109
|
+
fz < -OOB_TOL ||
|
|
110
|
+
fz > 1 + OOB_TOL))
|
|
111
|
+
return NaN;
|
|
112
|
+
// Clamp both genuine out-of-bounds ('clamp' policy = nearest edge value)
|
|
113
|
+
// and tiny numerical overshoot at the boundary
|
|
114
|
+
fx = Math.min(1, Math.max(0, fx));
|
|
115
|
+
fy = Math.min(1, Math.max(0, fy));
|
|
116
|
+
fz = Math.min(1, Math.max(0, fz));
|
|
117
|
+
}
|
|
118
|
+
return trilinear_interpolate(grid, fx, fy, fz, periodic);
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// Sample a volume at many Cartesian positions (flat xyz triplets).
|
|
122
|
+
// Returns one scalar per position; NaN marks out-of-bounds under 'fallback' policy.
|
|
123
|
+
export function sample_volume_at_positions(volume, positions, options = {}) {
|
|
124
|
+
const { out_of_bounds = `clamp`, position_offset = [0, 0, 0] } = options;
|
|
125
|
+
const { grid, inv, origin, periodic, grid_dims } = prepare_volume_sampler(volume);
|
|
126
|
+
const [nx, ny, nz] = grid_dims;
|
|
127
|
+
const [offset_x, offset_y, offset_z] = position_offset;
|
|
128
|
+
const [origin_x, origin_y, origin_z] = origin;
|
|
129
|
+
const n_points = Math.floor(positions.length / 3);
|
|
130
|
+
const out = options.out?.length === n_points ? options.out : new Float32Array(n_points);
|
|
131
|
+
if (nx === 0 || ny === 0 || nz === 0) {
|
|
132
|
+
out.fill(0);
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
for (let idx = 0; idx < n_points; idx++) {
|
|
136
|
+
const position_idx = idx * 3;
|
|
137
|
+
const cart_x = positions[position_idx] + offset_x - origin_x;
|
|
138
|
+
const cart_y = positions[position_idx + 1] + offset_y - origin_y;
|
|
139
|
+
const cart_z = positions[position_idx + 2] + offset_z - origin_z;
|
|
140
|
+
let frac_x = inv[0][0] * cart_x + inv[0][1] * cart_y + inv[0][2] * cart_z;
|
|
141
|
+
let frac_y = inv[1][0] * cart_x + inv[1][1] * cart_y + inv[1][2] * cart_z;
|
|
142
|
+
let frac_z = inv[2][0] * cart_x + inv[2][1] * cart_y + inv[2][2] * cart_z;
|
|
143
|
+
if (periodic) {
|
|
144
|
+
frac_x = safe_mod(frac_x, 1);
|
|
145
|
+
frac_y = safe_mod(frac_y, 1);
|
|
146
|
+
frac_z = safe_mod(frac_z, 1);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
if (out_of_bounds === `fallback` &&
|
|
150
|
+
(frac_x < -OOB_TOL ||
|
|
151
|
+
frac_x > 1 + OOB_TOL ||
|
|
152
|
+
frac_y < -OOB_TOL ||
|
|
153
|
+
frac_y > 1 + OOB_TOL ||
|
|
154
|
+
frac_z < -OOB_TOL ||
|
|
155
|
+
frac_z > 1 + OOB_TOL)) {
|
|
156
|
+
out[idx] = Number.NaN;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
frac_x = Math.min(1, Math.max(0, frac_x));
|
|
160
|
+
frac_y = Math.min(1, Math.max(0, frac_y));
|
|
161
|
+
frac_z = Math.min(1, Math.max(0, frac_z));
|
|
162
|
+
}
|
|
163
|
+
const grid_x = frac_x * (periodic ? nx : nx - 1);
|
|
164
|
+
const grid_y = frac_y * (periodic ? ny : ny - 1);
|
|
165
|
+
const grid_z = frac_z * (periodic ? nz : nz - 1);
|
|
166
|
+
const floor_x = Math.floor(grid_x);
|
|
167
|
+
const floor_y = Math.floor(grid_y);
|
|
168
|
+
const floor_z = Math.floor(grid_z);
|
|
169
|
+
const [x_lower, x_upper] = voxel_corners(nx, floor_x, periodic);
|
|
170
|
+
const [y_lower, y_upper] = voxel_corners(ny, floor_y, periodic);
|
|
171
|
+
const [z_lower, z_upper] = voxel_corners(nz, floor_z, periodic);
|
|
172
|
+
const x_weight = grid_x - x_lower;
|
|
173
|
+
const y_weight = grid_y - y_lower;
|
|
174
|
+
const z_weight = grid_z - z_lower;
|
|
175
|
+
const row_00 = grid[x_lower][y_lower];
|
|
176
|
+
const row_01 = grid[x_lower][y_upper];
|
|
177
|
+
const row_10 = grid[x_upper][y_lower];
|
|
178
|
+
const row_11 = grid[x_upper][y_upper];
|
|
179
|
+
const value_00 = row_00[z_lower] + (row_10[z_lower] - row_00[z_lower]) * x_weight;
|
|
180
|
+
const value_01 = row_00[z_upper] + (row_10[z_upper] - row_00[z_upper]) * x_weight;
|
|
181
|
+
const value_10 = row_01[z_lower] + (row_11[z_lower] - row_01[z_lower]) * x_weight;
|
|
182
|
+
const value_11 = row_01[z_upper] + (row_11[z_upper] - row_01[z_upper]) * x_weight;
|
|
183
|
+
const value_0 = value_00 + (value_10 - value_00) * y_weight;
|
|
184
|
+
const value_1 = value_01 + (value_11 - value_01) * y_weight;
|
|
185
|
+
out[idx] = value_0 + (value_1 - value_0) * z_weight;
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
189
|
+
const incompatible_grids = (reason) => ({ ok: false, reason });
|
|
190
|
+
const fmt_vec = (vec) => `[${vec.map((val) => Number(val.toPrecision(6))).join(`, `)}]`;
|
|
191
|
+
// Strictly compare two volumetric grids: identical dimensions, origins equal
|
|
192
|
+
// within tolerance, all voxel vectors equal within tolerance, and matching
|
|
193
|
+
// periodic/finite boundary modes. Cross-volume coloring via create_volume_sampler
|
|
194
|
+
// works for any two volumes sharing a Cartesian frame, but strictly matching
|
|
195
|
+
// grids guarantee the sampled field is exact (no cross-grid resampling).
|
|
196
|
+
export function compare_volume_grids(vol_a, vol_b, { tolerance = 1e-4 } = {}) {
|
|
197
|
+
const [nx_a, ny_a, nz_a] = vol_a.grid_dims;
|
|
198
|
+
const [nx_b, ny_b, nz_b] = vol_b.grid_dims;
|
|
199
|
+
if (nx_a !== nx_b || ny_a !== ny_b || nz_a !== nz_b) {
|
|
200
|
+
return incompatible_grids(`grid dimensions differ: ${nx_a}×${ny_a}×${nz_a} vs ${nx_b}×${ny_b}×${nz_b}`);
|
|
201
|
+
}
|
|
202
|
+
if (vol_a.periodic !== vol_b.periodic) {
|
|
203
|
+
return incompatible_grids(`boundary modes differ: ${vol_a.periodic ? `periodic` : `finite`} vs ${vol_b.periodic ? `periodic` : `finite`}`);
|
|
204
|
+
}
|
|
205
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
206
|
+
const delta = Math.abs(vol_a.origin[axis] - vol_b.origin[axis]);
|
|
207
|
+
if (delta > tolerance) {
|
|
208
|
+
return incompatible_grids(`origins differ by ${delta.toPrecision(3)} Å along axis ${axis}: ${fmt_vec(vol_a.origin)} vs ${fmt_vec(vol_b.origin)}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Compare voxel vectors: lattice_row / n for periodic grids (spacing 1/n),
|
|
212
|
+
// lattice_row / (n-1) for finite grids (spacing 1/(n-1), endpoints included).
|
|
213
|
+
// Dims and boundary modes already match at this point, so one divisor per
|
|
214
|
+
// axis suffices for both volumes.
|
|
215
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
216
|
+
const divisor = Math.max(vol_a.periodic ? vol_a.grid_dims[axis] : vol_a.grid_dims[axis] - 1, 1);
|
|
217
|
+
for (let comp = 0; comp < 3; comp++) {
|
|
218
|
+
const voxel_delta = Math.abs(vol_a.lattice[axis][comp] - vol_b.lattice[axis][comp]) / divisor;
|
|
219
|
+
if (voxel_delta > tolerance) {
|
|
220
|
+
return incompatible_grids(`voxel vectors differ along axis ${axis}: ${fmt_vec(vol_a.lattice[axis])} vs ${fmt_vec(vol_b.lattice[axis])} (lattice rows)`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return { ok: true };
|
|
225
|
+
}
|
|
226
|
+
// Replace invalid axes (non-finite bounds or non-positive width) with [0, 1].
|
|
227
|
+
// Non-periodic volumes additionally clamp to [0, 1] — a finite volume must not
|
|
228
|
+
// be repeated implicitly.
|
|
229
|
+
export function sanitize_display_range(range, periodic) {
|
|
230
|
+
return range.map(([lo, hi]) => {
|
|
231
|
+
if (!Number.isFinite(lo) || !Number.isFinite(hi) || hi - lo <= 1e-6)
|
|
232
|
+
return [0, 1];
|
|
233
|
+
if (periodic)
|
|
234
|
+
return [lo, hi];
|
|
235
|
+
const clamped = [Math.max(lo, 0), Math.min(hi, 1)];
|
|
236
|
+
return clamped[1] - clamped[0] > 1e-6 ? clamped : [0, 1];
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
// Resolve the finite window used for marching cubes. Periodic volumes always
|
|
240
|
+
// need an endpoint-inclusive window, including for an integer structure
|
|
241
|
+
// supercell: a periodic N-point grid spans [0, 1), while finite marching cubes
|
|
242
|
+
// interprets N points as spanning [0, 1]. Resampling [0, S] to N*S + 1 points
|
|
243
|
+
// preserves the original voxel spacing and closes the final periodic interval.
|
|
244
|
+
// Finite volumes only get a window when one is explicitly requested and are
|
|
245
|
+
// never repeated to follow the structure supercell.
|
|
246
|
+
export function resolve_volume_display_range(volume, { display_range, tiling = [1, 1, 1], halo = 0 } = {}) {
|
|
247
|
+
if (!display_range && !volume.periodic)
|
|
248
|
+
return null;
|
|
249
|
+
const range = display_range
|
|
250
|
+
? sanitize_display_range(display_range, volume.periodic)
|
|
251
|
+
: tiling.map((factor) => [0, factor]);
|
|
252
|
+
if (!volume.periodic)
|
|
253
|
+
return range;
|
|
254
|
+
const padding = Math.max(0, halo);
|
|
255
|
+
return range.map(([lo, hi]) => [lo - padding, hi + padding]);
|
|
256
|
+
}
|
|
257
|
+
const precompute_axis_interpolation = (range, count, source_dim, periodic) => {
|
|
258
|
+
const intervals = periodic ? source_dim : Math.max(source_dim - 1, 1);
|
|
259
|
+
const fractional_step = (range[1] - range[0]) / (count - 1);
|
|
260
|
+
const grid_step = fractional_step * intervals;
|
|
261
|
+
const grid_start = range[0] * intervals;
|
|
262
|
+
const direct = Math.abs(grid_step - 1) < 1e-10 && Math.abs(grid_start - Math.round(grid_start)) < 1e-10;
|
|
263
|
+
const lower = new Int32Array(count);
|
|
264
|
+
const upper = new Int32Array(count);
|
|
265
|
+
const weight = new Float64Array(count);
|
|
266
|
+
for (let sample_idx = 0; sample_idx < count; sample_idx++) {
|
|
267
|
+
const grid_coord = grid_start + sample_idx * grid_step;
|
|
268
|
+
const grid_floor = Math.floor(grid_coord);
|
|
269
|
+
if (periodic) {
|
|
270
|
+
lower[sample_idx] = safe_mod(grid_floor, source_dim);
|
|
271
|
+
upper[sample_idx] = (lower[sample_idx] + 1) % source_dim;
|
|
272
|
+
weight[sample_idx] = grid_coord - grid_floor;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
lower[sample_idx] = Math.max(0, Math.min(grid_floor, source_dim - 2));
|
|
276
|
+
upper[sample_idx] = Math.min(lower[sample_idx] + 1, source_dim - 1);
|
|
277
|
+
weight[sample_idx] = grid_coord - lower[sample_idx];
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return { lower, upper, weight, direct };
|
|
281
|
+
};
|
|
282
|
+
// Resample a volume over a fractional display range (VESTA-style non-integer
|
|
283
|
+
// supercell) into a finite grid whose bounds land exactly on the requested
|
|
284
|
+
// fractional coordinates, so marching cubes clips repeated surfaces precisely
|
|
285
|
+
// at the range instead of at integer cell boundaries. Periodic volumes wrap;
|
|
286
|
+
// the sample resolution follows the source voxel density, capped at max_points
|
|
287
|
+
// (matching the downsampling budget applied to integer-tiled grids).
|
|
288
|
+
// The returned volume's lattice spans the range and its origin shifts by
|
|
289
|
+
// range_min·lattice, keeping vertices in the same Cartesian frame as the source.
|
|
290
|
+
export function extract_volume_range(volume, range, max_points = MAX_GRID_POINTS) {
|
|
291
|
+
const [rx, ry, rz] = sanitize_display_range(range, volume.periodic);
|
|
292
|
+
const widths = [rx[1] - rx[0], ry[1] - ry[0], rz[1] - rz[0]];
|
|
293
|
+
// Sample counts follow the source voxel density (inclusive endpoints), capped
|
|
294
|
+
// to the point budget. The reduction loop guards against cbrt undershoot when
|
|
295
|
+
// the min-2 floor prevents an axis from shrinking.
|
|
296
|
+
let counts = widths.map((width, axis) => {
|
|
297
|
+
const source_intervals = volume.periodic
|
|
298
|
+
? volume.grid_dims[axis]
|
|
299
|
+
: Math.max(volume.grid_dims[axis] - 1, 1);
|
|
300
|
+
return Math.max(2, Math.round(width * source_intervals) + 1);
|
|
301
|
+
});
|
|
302
|
+
const total = counts[0] * counts[1] * counts[2];
|
|
303
|
+
if (total > max_points) {
|
|
304
|
+
const shrink = Math.cbrt(max_points / total);
|
|
305
|
+
counts = counts.map((count) => Math.max(2, Math.floor(count * shrink)));
|
|
306
|
+
while (counts[0] * counts[1] * counts[2] > Math.max(max_points, 8)) {
|
|
307
|
+
const largest = counts.indexOf(Math.max(...counts));
|
|
308
|
+
counts[largest] = Math.max(2, Math.floor(counts[largest] * 0.9));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
const [nx, ny, nz] = counts;
|
|
312
|
+
const grid = Array(nx);
|
|
313
|
+
const x_samples = precompute_axis_interpolation(rx, nx, volume.grid_dims[0], volume.periodic);
|
|
314
|
+
const y_samples = precompute_axis_interpolation(ry, ny, volume.grid_dims[1], volume.periodic);
|
|
315
|
+
const z_samples = precompute_axis_interpolation(rz, nz, volume.grid_dims[2], volume.periodic);
|
|
316
|
+
let [min_val, max_val, sum] = [Infinity, -Infinity, 0];
|
|
317
|
+
const direct_copy = x_samples.direct && y_samples.direct && z_samples.direct;
|
|
318
|
+
if (direct_copy) {
|
|
319
|
+
for (let x_idx = 0; x_idx < nx; x_idx++) {
|
|
320
|
+
const source_x = x_samples.weight[x_idx] > 0.5 ? x_samples.upper[x_idx] : x_samples.lower[x_idx];
|
|
321
|
+
const source_plane = volume.grid[source_x];
|
|
322
|
+
const plane = Array(ny);
|
|
323
|
+
for (let y_idx = 0; y_idx < ny; y_idx++) {
|
|
324
|
+
const source_y = y_samples.weight[y_idx] > 0.5 ? y_samples.upper[y_idx] : y_samples.lower[y_idx];
|
|
325
|
+
const source_row = source_plane[source_y];
|
|
326
|
+
const row = Array(nz);
|
|
327
|
+
for (let z_idx = 0; z_idx < nz; z_idx++) {
|
|
328
|
+
const source_z = z_samples.weight[z_idx] > 0.5 ? z_samples.upper[z_idx] : z_samples.lower[z_idx];
|
|
329
|
+
const value = source_row[source_z];
|
|
330
|
+
row[z_idx] = value;
|
|
331
|
+
if (value < min_val)
|
|
332
|
+
min_val = value;
|
|
333
|
+
if (value > max_val)
|
|
334
|
+
max_val = value;
|
|
335
|
+
sum += value;
|
|
336
|
+
}
|
|
337
|
+
plane[y_idx] = row;
|
|
338
|
+
}
|
|
339
|
+
grid[x_idx] = plane;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
for (let x_idx = 0; x_idx < nx; x_idx++) {
|
|
344
|
+
const x_lower_plane = volume.grid[x_samples.lower[x_idx]];
|
|
345
|
+
const x_upper_plane = volume.grid[x_samples.upper[x_idx]];
|
|
346
|
+
const x_weight = x_samples.weight[x_idx];
|
|
347
|
+
const plane = Array(ny);
|
|
348
|
+
for (let y_idx = 0; y_idx < ny; y_idx++) {
|
|
349
|
+
const y_lower = y_samples.lower[y_idx];
|
|
350
|
+
const y_upper = y_samples.upper[y_idx];
|
|
351
|
+
const y_weight = y_samples.weight[y_idx];
|
|
352
|
+
const row_00 = x_lower_plane[y_lower];
|
|
353
|
+
const row_01 = x_lower_plane[y_upper];
|
|
354
|
+
const row_10 = x_upper_plane[y_lower];
|
|
355
|
+
const row_11 = x_upper_plane[y_upper];
|
|
356
|
+
const row = Array(nz);
|
|
357
|
+
for (let z_idx = 0; z_idx < nz; z_idx++) {
|
|
358
|
+
const z_lower = z_samples.lower[z_idx];
|
|
359
|
+
const z_upper = z_samples.upper[z_idx];
|
|
360
|
+
const z_weight = z_samples.weight[z_idx];
|
|
361
|
+
const value_00 = row_00[z_lower] + (row_10[z_lower] - row_00[z_lower]) * x_weight;
|
|
362
|
+
const value_01 = row_00[z_upper] + (row_10[z_upper] - row_00[z_upper]) * x_weight;
|
|
363
|
+
const value_10 = row_01[z_lower] + (row_11[z_lower] - row_01[z_lower]) * x_weight;
|
|
364
|
+
const value_11 = row_01[z_upper] + (row_11[z_upper] - row_01[z_upper]) * x_weight;
|
|
365
|
+
const value_0 = value_00 + (value_10 - value_00) * y_weight;
|
|
366
|
+
const value_1 = value_01 + (value_11 - value_01) * y_weight;
|
|
367
|
+
const value = value_0 + (value_1 - value_0) * z_weight;
|
|
368
|
+
row[z_idx] = value;
|
|
369
|
+
if (value < min_val)
|
|
370
|
+
min_val = value;
|
|
371
|
+
if (value > max_val)
|
|
372
|
+
max_val = value;
|
|
373
|
+
sum += value;
|
|
374
|
+
}
|
|
375
|
+
plane[y_idx] = row;
|
|
376
|
+
}
|
|
377
|
+
grid[x_idx] = plane;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
const [row_a, row_b, row_c] = volume.lattice;
|
|
381
|
+
return {
|
|
382
|
+
...volume,
|
|
383
|
+
grid,
|
|
384
|
+
grid_dims: counts,
|
|
385
|
+
lattice: scale_lattice_matrix(volume.lattice, widths),
|
|
386
|
+
origin: [
|
|
387
|
+
volume.origin[0] + rx[0] * row_a[0] + ry[0] * row_b[0] + rz[0] * row_c[0],
|
|
388
|
+
volume.origin[1] + rx[0] * row_a[1] + ry[0] * row_b[1] + rz[0] * row_c[1],
|
|
389
|
+
volume.origin[2] + rx[0] * row_a[2] + ry[0] * row_b[2] + rz[0] * row_c[2],
|
|
390
|
+
],
|
|
391
|
+
data_range: {
|
|
392
|
+
min: min_val,
|
|
393
|
+
max: max_val,
|
|
394
|
+
abs_max: Math.max(Math.abs(min_val), Math.abs(max_val)),
|
|
395
|
+
mean: sum / (nx * ny * nz),
|
|
396
|
+
},
|
|
397
|
+
periodic: false, // the extracted block is a finite window; endpoints included
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
export function prepare_geometry_grid(volume, range) {
|
|
401
|
+
if (range)
|
|
402
|
+
return extract_volume_range(volume, range);
|
|
403
|
+
return {
|
|
404
|
+
grid: downsample_grid(volume.grid, volume.grid_dims).grid,
|
|
405
|
+
lattice: volume.lattice,
|
|
406
|
+
origin: volume.origin,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type D3InterpolateName } from '../colors';
|
|
2
|
+
import type { Vec2 } from '../math';
|
|
3
|
+
import type { SliceResult } from './slice';
|
|
4
|
+
export type VolumeSliceMode = `both` | `contours` | `filled`;
|
|
5
|
+
/** Resolve an explicit or automatic slice color range. */
|
|
6
|
+
export declare function resolve_slice_color_range(slice: Pick<SliceResult, `min` | `max`>, color_range?: Vec2, symmetric?: boolean | `auto`): Vec2;
|
|
7
|
+
/** Convert a sampled slice to browser-sRGB RGBA pixels, preserving its exact mask. */
|
|
8
|
+
export declare function slice_to_rgba(slice: Pick<SliceResult, `data` | `mask` | `width` | `height`>, colormap: D3InterpolateName, color_range: Vec2, { flip_y, out }?: {
|
|
9
|
+
flip_y?: boolean;
|
|
10
|
+
out?: Uint8ClampedArray;
|
|
11
|
+
}): Uint8ClampedArray;
|
|
12
|
+
/** Resolve a contour count or explicit threshold list against a color range. */
|
|
13
|
+
export declare function resolve_contour_thresholds(color_range: Vec2, contour_levels: number | number[]): number[];
|