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
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// Bonding algorithms for structure visualization
|
|
2
|
-
import {
|
|
2
|
+
import element_data, { element_by_symbol } from '../element/data';
|
|
3
3
|
import * as math from '../math';
|
|
4
|
-
// Shared per-symbol element data lookup (also used by pbc.ts and polyhedra.ts)
|
|
5
|
-
export const element_lookup = new Map(element_data.map((el) => [el.symbol, el]));
|
|
6
4
|
const covalent_radii = new Map(element_data.flatMap((el) => el.covalent_radius === null ? [] : [[el.symbol, el.covalent_radius]]));
|
|
7
5
|
// Majority-occupancy element of a (possibly disordered) site
|
|
8
6
|
export const get_majority_element = (site) => {
|
|
@@ -10,12 +8,39 @@ export const get_majority_element = (site) => {
|
|
|
10
8
|
return null;
|
|
11
9
|
return site.species.reduce((max, spec) => (spec.occu > max.occu ? spec : max)).element;
|
|
12
10
|
};
|
|
11
|
+
// Large low-valent A-site cations whose coordination polyhedra (CN 8-12) tend to
|
|
12
|
+
// obscure the structural framework. VESTA-style figures draw the framework
|
|
13
|
+
// (e.g. TiO6 in BaTiO3, FeO6/PO4 in LiFePO4) and leave these as plain spheres.
|
|
14
|
+
// They still get polyhedra when they are the only qualifying cations (e.g. NaCl)
|
|
15
|
+
// or when force-included via `included_center_elements`. Shared by polyhedra.ts
|
|
16
|
+
// (vertex/center selection) and pbc.ts (phase-2 boundary completion) so the bond
|
|
17
|
+
// graph and the polyhedra it feeds stay consistent.
|
|
18
|
+
const HEAVY_ALKALINE_EARTHS = new Set([`Ca`, `Sr`, `Ba`, `Ra`]);
|
|
19
|
+
export const is_spectator_center = (element) => element_by_symbol.get(element)?.category === `alkali metal` ||
|
|
20
|
+
HEAVY_ALKALINE_EARTHS.has(element);
|
|
21
|
+
// True if the composition contains a framework cation: a non-spectator element
|
|
22
|
+
// strictly less electronegative than the most electronegative element present
|
|
23
|
+
// (i.e. one that can coordinate the anions). When true, spectator A-site cations
|
|
24
|
+
// are hidden from coordination polyhedra (compute_polyhedra) and skipped by phase-2
|
|
25
|
+
// boundary completion (find_image_atoms) - sharing this keeps the bond graph and
|
|
26
|
+
// the polyhedra it feeds consistent. Purely ionic binaries (NaCl, Li2O) return
|
|
27
|
+
// false, so the spectator IS the framework and keeps its polyhedra/completions.
|
|
28
|
+
export function has_framework_potential(elements) {
|
|
29
|
+
const els = [...new Set(elements)]; // dedupe so callers can pass per-site element lists
|
|
30
|
+
let max_en = -Infinity;
|
|
31
|
+
for (const el of els) {
|
|
32
|
+
const en = element_by_symbol.get(el)?.electronegativity;
|
|
33
|
+
if (en != null && en > max_en)
|
|
34
|
+
max_en = en;
|
|
35
|
+
}
|
|
36
|
+
return els.some((el) => {
|
|
37
|
+
if (is_spectator_center(el))
|
|
38
|
+
return false;
|
|
39
|
+
const en = element_by_symbol.get(el)?.electronegativity;
|
|
40
|
+
return en != null && en < max_en;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
13
43
|
const is_zero_cell_shift = (cell_shift) => cell_shift === undefined || cell_shift.every((val) => val === 0);
|
|
14
|
-
const format_cell_shift = (cell_shift) => {
|
|
15
|
-
if (cell_shift === undefined || is_zero_cell_shift(cell_shift))
|
|
16
|
-
return ``;
|
|
17
|
-
return `@${cell_shift.join(`,`)}`;
|
|
18
|
-
};
|
|
19
44
|
const negate_cell_shift = (cell_shift) => [
|
|
20
45
|
cell_shift[0] === 0 ? 0 : -cell_shift[0],
|
|
21
46
|
cell_shift[1] === 0 ? 0 : -cell_shift[1],
|
|
@@ -50,7 +75,10 @@ export const normalize_structure_bond = (site_idx_1, site_idx_2, order, cell_shi
|
|
|
50
75
|
};
|
|
51
76
|
export const get_bond_key = (idx_1, idx_2, cell_shift) => {
|
|
52
77
|
const normalized = normalize_bond_endpoints(idx_1, idx_2, cell_shift);
|
|
53
|
-
|
|
78
|
+
const shift_suffix = normalized.cell_shift === undefined || is_zero_cell_shift(normalized.cell_shift)
|
|
79
|
+
? ``
|
|
80
|
+
: `@${normalized.cell_shift.join(`,`)}`;
|
|
81
|
+
return `${normalized.site_idx_1}-${normalized.site_idx_2}${shift_suffix}`;
|
|
54
82
|
};
|
|
55
83
|
// Remap explicit bond metadata after site deletion: drop bonds touching deleted
|
|
56
84
|
// sites and shift each surviving index down by the number of deleted indices below it.
|
|
@@ -247,7 +275,6 @@ export const merge_bond_edits = (base_bonds, added, removed, overrides) => {
|
|
|
247
275
|
}
|
|
248
276
|
return [...merged.values()];
|
|
249
277
|
};
|
|
250
|
-
const is_record = (value) => typeof value === `object` && value !== null;
|
|
251
278
|
export function normalize_bond_order(order) {
|
|
252
279
|
if (order === `aromatic`)
|
|
253
280
|
return order;
|
|
@@ -305,13 +332,14 @@ export function get_explicit_bond_metadata(structure) {
|
|
|
305
332
|
}
|
|
306
333
|
const explicit_bonds = new Map();
|
|
307
334
|
for (const [entry_idx, raw_bond] of raw_bonds.entries()) {
|
|
308
|
-
if (
|
|
335
|
+
if (typeof raw_bond !== `object` || raw_bond === null) {
|
|
309
336
|
console.warn(`Ignoring invalid explicit bond at index ${entry_idx}: expected object`);
|
|
310
337
|
continue;
|
|
311
338
|
}
|
|
312
|
-
const
|
|
313
|
-
const
|
|
314
|
-
const
|
|
339
|
+
const bond_record = raw_bond;
|
|
340
|
+
const { order } = bond_record;
|
|
341
|
+
const site_idx_1 = bond_record.site_idx_1;
|
|
342
|
+
const site_idx_2 = bond_record.site_idx_2;
|
|
315
343
|
if (typeof site_idx_1 !== `number` ||
|
|
316
344
|
typeof site_idx_2 !== `number` ||
|
|
317
345
|
!Number.isInteger(site_idx_1) ||
|
|
@@ -331,7 +359,7 @@ export function get_explicit_bond_metadata(structure) {
|
|
|
331
359
|
console.warn(`Ignoring invalid explicit bond at index ${entry_idx}: unsupported order ${String(order)}`);
|
|
332
360
|
continue;
|
|
333
361
|
}
|
|
334
|
-
const cell_shift = normalize_cell_shift(
|
|
362
|
+
const cell_shift = normalize_cell_shift(bond_record.cell_shift);
|
|
335
363
|
if (cell_shift === null) {
|
|
336
364
|
console.warn(`Ignoring invalid explicit bond at index ${entry_idx}: cell_shift must be three integers`);
|
|
337
365
|
continue;
|
|
@@ -340,9 +368,7 @@ export function get_explicit_bond_metadata(structure) {
|
|
|
340
368
|
console.warn(`Ignoring invalid explicit bond at index ${entry_idx}: endpoints match`);
|
|
341
369
|
continue;
|
|
342
370
|
}
|
|
343
|
-
if (cell_shift
|
|
344
|
-
!is_zero_cell_shift(cell_shift) &&
|
|
345
|
-
!(`lattice` in structure)) {
|
|
371
|
+
if (!is_zero_cell_shift(cell_shift) && !(`lattice` in structure)) {
|
|
346
372
|
console.warn(`Ignoring invalid explicit bond at index ${entry_idx}: cell_shift requires a crystal lattice`);
|
|
347
373
|
continue;
|
|
348
374
|
}
|
|
@@ -501,11 +527,22 @@ export function compute_bond_transform(pos_1, pos_2) {
|
|
|
501
527
|
1,
|
|
502
528
|
]);
|
|
503
529
|
}
|
|
530
|
+
// Build a BondPair between two sites (shared by electroneg_ratio and solid_angle)
|
|
531
|
+
const make_bond = (sites, idx_1, idx_2, bond_length, strength) => ({
|
|
532
|
+
pos_1: sites[idx_1].xyz,
|
|
533
|
+
pos_2: sites[idx_2].xyz,
|
|
534
|
+
site_idx_1: idx_1,
|
|
535
|
+
site_idx_2: idx_2,
|
|
536
|
+
bond_length,
|
|
537
|
+
strength,
|
|
538
|
+
transform_matrix: compute_bond_transform(sites[idx_1].xyz, sites[idx_2].xyz),
|
|
539
|
+
});
|
|
504
540
|
// Pack quantized cell coordinates into one integer key (exact for cell coords in
|
|
505
541
|
// [-512, 511], i.e. structures up to ~1000 cells per axis - far beyond any real
|
|
506
542
|
// case). Integer Map keys avoid per-lookup string building in the hot pair loop.
|
|
543
|
+
// Also used by pbc.ts for its phase-2 boundary-completion grid.
|
|
507
544
|
const CELL_OFFSET = 512;
|
|
508
|
-
const pack_cell_key = (x, y, z) => (x + CELL_OFFSET) * 1048576 + (y + CELL_OFFSET) * 1024 + (z + CELL_OFFSET);
|
|
545
|
+
export const pack_cell_key = (x, y, z) => (x + CELL_OFFSET) * 1048576 + (y + CELL_OFFSET) * 1024 + (z + CELL_OFFSET);
|
|
509
546
|
// Build spatial grid by dividing 3D space into cubic cells.
|
|
510
547
|
function build_spatial_grid(sites, cell_size) {
|
|
511
548
|
const grid = new Map();
|
|
@@ -520,24 +557,28 @@ function build_spatial_grid(sites, cell_size) {
|
|
|
520
557
|
return grid;
|
|
521
558
|
}
|
|
522
559
|
// Get all site indices in 3x3x3 cube of cells around position.
|
|
560
|
+
// Fills and returns a REUSED module-level array (valid until the next call):
|
|
561
|
+
// this runs once per bond center, so per-call allocations would dominate GC
|
|
562
|
+
// pressure when computing bonds for large supercells.
|
|
563
|
+
const scratch_neighbors = [];
|
|
523
564
|
function get_neighbors_from_grid(pos, grid, cell_size) {
|
|
524
565
|
const [cx, cy, cz] = [
|
|
525
566
|
Math.floor(pos[0] / cell_size),
|
|
526
567
|
Math.floor(pos[1] / cell_size),
|
|
527
568
|
Math.floor(pos[2] / cell_size),
|
|
528
569
|
];
|
|
529
|
-
|
|
570
|
+
scratch_neighbors.length = 0;
|
|
530
571
|
for (let dx = -1; dx <= 1; dx++) {
|
|
531
572
|
for (let dy = -1; dy <= 1; dy++) {
|
|
532
573
|
for (let dz = -1; dz <= 1; dz++) {
|
|
533
574
|
const cell = grid.get(pack_cell_key(cx + dx, cy + dy, cz + dz));
|
|
534
575
|
if (cell)
|
|
535
|
-
for (const
|
|
536
|
-
|
|
576
|
+
for (const site_idx of cell)
|
|
577
|
+
scratch_neighbors.push(site_idx);
|
|
537
578
|
}
|
|
538
579
|
}
|
|
539
580
|
}
|
|
540
|
-
return
|
|
581
|
+
return scratch_neighbors;
|
|
541
582
|
}
|
|
542
583
|
// Setup spatial decomposition for structures with >50 atoms.
|
|
543
584
|
function setup_spatial_grid(sites, cutoff) {
|
|
@@ -549,6 +590,23 @@ const get_candidates = (pos, sites, spatial) => spatial
|
|
|
549
590
|
? get_neighbors_from_grid(pos, spatial.grid, spatial.cell_size)
|
|
550
591
|
: Array.from({ length: sites.length }, (_, idx) => idx);
|
|
551
592
|
export const BONDING_STRATEGIES = { electroneg_ratio, solid_angle };
|
|
593
|
+
// Memo for the costly neighbor search: WeakMap keyed by structure (GC'd with it), each holding a
|
|
594
|
+
// per-signature (strategy + JSON options) map of results. The multi-side view's 4 panes share one
|
|
595
|
+
// search (identical inputs, one flush); the per-signature map also lets alternating
|
|
596
|
+
// strategies/options on the same structure reuse earlier results instead of thrashing one slot.
|
|
597
|
+
const bond_memo = new WeakMap();
|
|
598
|
+
export function compute_bonds(structure, strategy, options = {}) {
|
|
599
|
+
const sig = `${strategy}:${JSON.stringify(options)}`;
|
|
600
|
+
let by_sig = bond_memo.get(structure);
|
|
601
|
+
const cached = by_sig?.get(sig);
|
|
602
|
+
if (cached)
|
|
603
|
+
return cached;
|
|
604
|
+
const bonds = BONDING_STRATEGIES[strategy](structure, options);
|
|
605
|
+
if (!by_sig)
|
|
606
|
+
bond_memo.set(structure, (by_sig = new Map()));
|
|
607
|
+
by_sig.set(sig, bonds);
|
|
608
|
+
return bonds;
|
|
609
|
+
}
|
|
552
610
|
// Electronegativity-based bonding with chemical preferences.
|
|
553
611
|
// This algorithm considers electronegativity differences between atoms, metal/nonmetal
|
|
554
612
|
// properties, and distance to determine bond strength. Bonds are only created if the
|
|
@@ -561,7 +619,11 @@ metal_nonmetal_bonus = 1.5, // Strength bonus for metal-nonmetal bonds
|
|
|
561
619
|
similar_electronegativity_bonus = 1.2, // Bonus for similar electronegativity
|
|
562
620
|
same_species_penalty = 0.5, // Penalty for bonds between same element
|
|
563
621
|
strength_threshold = 0.3, // Minimum bond strength to include in results
|
|
564
|
-
|
|
622
|
+
// Only iterate the first `center_count` sites as bond centers (default: all).
|
|
623
|
+
// Coordination coloring sets this to the original-atom count so appended PBC image
|
|
624
|
+
// atoms are used as neighbors but not iterated as centers — identical coordination
|
|
625
|
+
// for the originals (by translational symmetry), far cheaper when images dominate.
|
|
626
|
+
center_count = Infinity, } = {}) {
|
|
565
627
|
const { sites } = structure;
|
|
566
628
|
if (sites.length < 2)
|
|
567
629
|
return [];
|
|
@@ -571,6 +633,7 @@ strength_threshold = 0.3, // Minimum bond strength to include in results
|
|
|
571
633
|
// millions of candidate pairs in large supercells, so object property chains
|
|
572
634
|
// and Map lookups are replaced with indexed array reads.
|
|
573
635
|
const n_sites = sites.length;
|
|
636
|
+
const n_center = Math.min(center_count, n_sites - 1);
|
|
574
637
|
const electronegs = new Float64Array(n_sites);
|
|
575
638
|
const radii = new Float64Array(n_sites); // 0 = no covalent radius known
|
|
576
639
|
const metal_flags = new Uint8Array(n_sites);
|
|
@@ -580,7 +643,7 @@ strength_threshold = 0.3, // Minimum bond strength to include in results
|
|
|
580
643
|
const elem_id_lookup = new Map();
|
|
581
644
|
for (let idx = 0; idx < n_sites; idx++) {
|
|
582
645
|
const elem = get_majority_element(sites[idx]);
|
|
583
|
-
const data = elem ?
|
|
646
|
+
const data = elem ? element_by_symbol.get(elem) : undefined;
|
|
584
647
|
electronegs[idx] = data?.electronegativity ?? 2.0;
|
|
585
648
|
metal_flags[idx] = data?.metal ? 1 : 0;
|
|
586
649
|
nonmetal_flags[idx] = data?.nonmetal ? 1 : 0;
|
|
@@ -608,7 +671,7 @@ strength_threshold = 0.3, // Minimum bond strength to include in results
|
|
|
608
671
|
const max_cutoff = max_radius * 2 * max_distance_ratio;
|
|
609
672
|
const spatial = setup_spatial_grid(sites, max_cutoff);
|
|
610
673
|
const potential_bonds = [];
|
|
611
|
-
for (let idx_a = 0; idx_a <
|
|
674
|
+
for (let idx_a = 0; idx_a < n_center; idx_a++) {
|
|
612
675
|
const radius_a = radii[idx_a];
|
|
613
676
|
if (radius_a === 0)
|
|
614
677
|
continue; // no covalent radius -> no pairs (symmetric: idx_b skips too)
|
|
@@ -700,15 +763,7 @@ strength_threshold = 0.3, // Minimum bond strength to include in results
|
|
|
700
763
|
strength *= Math.exp(-(norm_dist / closest_dist_b - 1) / 0.5);
|
|
701
764
|
}
|
|
702
765
|
if (strength > strength_threshold) {
|
|
703
|
-
bonds.push(
|
|
704
|
-
pos_1: sites[site_idx_1].xyz,
|
|
705
|
-
pos_2: sites[site_idx_2].xyz,
|
|
706
|
-
site_idx_1,
|
|
707
|
-
site_idx_2,
|
|
708
|
-
bond_length: dist,
|
|
709
|
-
strength,
|
|
710
|
-
transform_matrix: compute_bond_transform(sites[site_idx_1].xyz, sites[site_idx_2].xyz),
|
|
711
|
-
});
|
|
766
|
+
bonds.push(make_bond(sites, site_idx_1, site_idx_2, dist, strength));
|
|
712
767
|
}
|
|
713
768
|
}
|
|
714
769
|
return apply_explicit_bond_metadata(structure, bonds);
|
|
@@ -718,7 +773,8 @@ strength_threshold = 0.3, // Minimum bond strength to include in results
|
|
|
718
773
|
// This algorithm computes bond strength based on the solid angle subtended by atoms
|
|
719
774
|
// and their distance penalty. Bonds are only created if the computed strength exceeds
|
|
720
775
|
// the strength_threshold parameter.
|
|
721
|
-
export function solid_angle(structure, { min_solid_angle = 0.01, min_face_area = 0.05, max_distance = 5.0, min_bond_dist = 0.4, strength_threshold = 0.05,
|
|
776
|
+
export function solid_angle(structure, { min_solid_angle = 0.01, min_face_area = 0.05, max_distance = 5.0, min_bond_dist = 0.4, strength_threshold = 0.05, center_count = Infinity, // see electroneg_ratio: limit bond centers to first N sites
|
|
777
|
+
} = {}) {
|
|
722
778
|
const { sites } = structure;
|
|
723
779
|
if (sites.length < 2)
|
|
724
780
|
return [];
|
|
@@ -726,7 +782,8 @@ export function solid_angle(structure, { min_solid_angle = 0.01, min_face_area =
|
|
|
726
782
|
const min_dist_sq = min_bond_dist ** 2;
|
|
727
783
|
const max_dist_sq = max_distance ** 2;
|
|
728
784
|
const spatial = setup_spatial_grid(sites, max_distance);
|
|
729
|
-
|
|
785
|
+
const n_center = Math.min(center_count, sites.length - 1);
|
|
786
|
+
for (let idx_a = 0; idx_a < n_center; idx_a++) {
|
|
730
787
|
const [x1, y1, z1] = sites[idx_a].xyz;
|
|
731
788
|
const elem_a = get_majority_element(sites[idx_a]);
|
|
732
789
|
const radius_a = elem_a ? covalent_radii.get(elem_a) : undefined;
|
|
@@ -751,15 +808,7 @@ export function solid_angle(structure, { min_solid_angle = 0.01, min_face_area =
|
|
|
751
808
|
const angle_strength = Math.min(bond_solid_angle / (4.0 * Math.PI), 1.0);
|
|
752
809
|
const strength = angle_strength * dist_penalty;
|
|
753
810
|
if (strength > strength_threshold) {
|
|
754
|
-
bonds.push(
|
|
755
|
-
pos_1: sites[idx_a].xyz,
|
|
756
|
-
pos_2: sites[idx_b].xyz,
|
|
757
|
-
site_idx_1: idx_a,
|
|
758
|
-
site_idx_2: idx_b,
|
|
759
|
-
bond_length: dist,
|
|
760
|
-
strength,
|
|
761
|
-
transform_matrix: compute_bond_transform(sites[idx_a].xyz, sites[idx_b].xyz),
|
|
762
|
-
});
|
|
811
|
+
bonds.push(make_bond(sites, idx_a, idx_b, dist, strength));
|
|
763
812
|
}
|
|
764
813
|
}
|
|
765
814
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type HistoryStacks<T> = [undo_stack: T[], redo_stack: T[]];
|
|
2
|
+
export declare function push_edit<T>([undo_stack]: HistoryStacks<T>, snapshot: T, max_history: number): HistoryStacks<T>;
|
|
3
|
+
export declare function step_history<T>([undo_stack, redo_stack]: HistoryStacks<T>, direction: `undo` | `redo`, current: T): {
|
|
4
|
+
stacks: HistoryStacks<T>;
|
|
5
|
+
restored: T;
|
|
6
|
+
} | null;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Pure undo/redo stack mechanics for Structure.svelte's edit-atoms history.
|
|
2
|
+
// Stacks are treated as immutable (updates return new arrays) so they work with
|
|
3
|
+
// $state.raw holders where only reassignment is reactive. Kept free of
|
|
4
|
+
// component state so the real logic (not a test-local mirror) is unit-testable.
|
|
5
|
+
// Record a new edit: push `snapshot` onto the undo stack (trimming to
|
|
6
|
+
// `max_history` entries) and invalidate the redo stack.
|
|
7
|
+
export function push_edit([undo_stack], snapshot, max_history) {
|
|
8
|
+
const trimmed = undo_stack.length >= max_history
|
|
9
|
+
? undo_stack.slice(undo_stack.length - max_history + 1)
|
|
10
|
+
: undo_stack;
|
|
11
|
+
return [[...trimmed, snapshot], []];
|
|
12
|
+
}
|
|
13
|
+
// Step the history in `direction`: pop that stack's top as the state to
|
|
14
|
+
// restore, pushing `current` onto the opposite stack. Returns null when there
|
|
15
|
+
// is nothing to step to (callers should snapshot `current` lazily by checking
|
|
16
|
+
// stack length first if snapshots are expensive).
|
|
17
|
+
export function step_history([undo_stack, redo_stack], direction, current) {
|
|
18
|
+
const source = direction === `undo` ? undo_stack : redo_stack;
|
|
19
|
+
const restored = source.at(-1);
|
|
20
|
+
if (restored === undefined)
|
|
21
|
+
return null;
|
|
22
|
+
const remaining = source.slice(0, -1);
|
|
23
|
+
const stacks = direction === `undo`
|
|
24
|
+
? [remaining, [...redo_stack, current]]
|
|
25
|
+
: [[...undo_stack, current], remaining];
|
|
26
|
+
return { stacks, restored };
|
|
27
|
+
}
|
|
@@ -7,6 +7,7 @@ export declare function has_color_property(mat: Material): mat is Material & {
|
|
|
7
7
|
export declare function extract_bond_color_for_instance(geometry: BufferGeometry, instance_idx: number): Color | null;
|
|
8
8
|
export declare function clean_geometry_for_export(geometry: BufferGeometry): void;
|
|
9
9
|
export declare function generate_mtl_content(scene: Scene): string;
|
|
10
|
+
export declare function convert_instanced_meshes_to_regular(scene: Scene): Scene;
|
|
10
11
|
export declare function create_structure_filename(structure: AnyStructure | undefined, extension: string): string;
|
|
11
12
|
export declare function structure_to_xyz_str(structure?: AnyStructure): string;
|
|
12
13
|
export declare function structure_to_cif_str(structure?: AnyStructure): string;
|
package/dist/structure/export.js
CHANGED
|
@@ -6,22 +6,15 @@ import { Color, Group, Matrix4, Mesh, MeshStandardMaterial, ShaderMaterial } fro
|
|
|
6
6
|
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
|
|
7
7
|
import { OBJExporter } from 'three/examples/jsm/exporters/OBJExporter.js';
|
|
8
8
|
// @internal exported only for tests - not part of the public API.
|
|
9
|
-
// Type guard to check if a material has a
|
|
10
|
-
//
|
|
9
|
+
// Type guard to check if a material has a Color-like property with numeric r/g/b
|
|
10
|
+
// channels (duck typing for bundler compatibility across different Three.js
|
|
11
|
+
// instances - Threlte vs vanilla Three.js).
|
|
11
12
|
export function has_color_property(mat) {
|
|
12
|
-
if (!(`color` in mat))
|
|
13
|
-
return false;
|
|
14
13
|
const color = mat.color;
|
|
15
14
|
if (!color || typeof color !== `object`)
|
|
16
15
|
return false;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const red_channel = color_obj.r;
|
|
20
|
-
const green_channel = color_obj.g;
|
|
21
|
-
const blue_channel = color_obj.b;
|
|
22
|
-
return (typeof red_channel === `number` &&
|
|
23
|
-
typeof green_channel === `number` &&
|
|
24
|
-
typeof blue_channel === `number`);
|
|
16
|
+
const { r: red, g: green, b: blue } = color;
|
|
17
|
+
return typeof red === `number` && typeof green === `number` && typeof blue === `number`;
|
|
25
18
|
}
|
|
26
19
|
// Extract color from a ShaderMaterial by checking common color uniform patterns
|
|
27
20
|
function extract_shader_color(shader_mat) {
|
|
@@ -34,8 +27,8 @@ function extract_shader_color(shader_mat) {
|
|
|
34
27
|
return uniforms[key].value.clone();
|
|
35
28
|
}
|
|
36
29
|
}
|
|
37
|
-
//
|
|
38
|
-
//
|
|
30
|
+
// Gradient bonds store colors as instanceColorStart/End geometry attributes,
|
|
31
|
+
// not uniforms — nothing to extract here (caller falls back to gray)
|
|
39
32
|
return null;
|
|
40
33
|
}
|
|
41
34
|
// Convert ShaderMaterial to MeshStandardMaterial for export compatibility
|
|
@@ -123,9 +116,10 @@ export function generate_mtl_content(scene) {
|
|
|
123
116
|
// Get diffuse color (main color)
|
|
124
117
|
if (has_color_property(mat)) {
|
|
125
118
|
const color = mat.color;
|
|
126
|
-
|
|
119
|
+
const fmt = (val) => val.toFixed(6);
|
|
120
|
+
lines.push(`Kd ${fmt(color.r)} ${fmt(color.g)} ${fmt(color.b)}`);
|
|
127
121
|
// Ambient is typically a fraction of diffuse
|
|
128
|
-
lines.push(`Ka ${(color.r * 0.2)
|
|
122
|
+
lines.push(`Ka ${fmt(color.r * 0.2)} ${fmt(color.g * 0.2)} ${fmt(color.b * 0.2)}`);
|
|
129
123
|
}
|
|
130
124
|
else {
|
|
131
125
|
// Default white if no color
|
|
@@ -145,19 +139,33 @@ export function generate_mtl_content(scene) {
|
|
|
145
139
|
});
|
|
146
140
|
return lines.join(`\n`);
|
|
147
141
|
}
|
|
148
|
-
// Extract color from material, returning RGB values or null if not found
|
|
149
|
-
function extract_material_color(mat) {
|
|
150
|
-
if (has_color_property(mat)) {
|
|
151
|
-
return { r: mat.color.r, g: mat.color.g, b: mat.color.b };
|
|
152
|
-
}
|
|
153
|
-
return null;
|
|
154
|
-
}
|
|
155
142
|
// Helper function to convert InstancedMesh to regular Mesh objects for export
|
|
156
143
|
// This is necessary because GLB/OBJ exporters don't handle InstancedMesh properly
|
|
157
144
|
// Note: Threlte's InstancedMesh sets isInstancedMesh=true but type remains "Mesh"
|
|
158
145
|
// Type guard for InstancedMesh (Three.js uses isInstancedMesh property, not exposed in Object3D type)
|
|
159
146
|
const is_instanced_mesh = (obj) => obj.isInstancedMesh || obj.type === `InstancedMesh`;
|
|
160
|
-
|
|
147
|
+
// Resolve the export color for one instance of an InstancedMesh. Precedence:
|
|
148
|
+
// gradient bond midpoints (shader bonds), then per-instance colors on meshes
|
|
149
|
+
// flagged userData.per_instance_color (atoms/arrows keep a white base material
|
|
150
|
+
// and store real colors in the instanceColor buffer), then the shared material
|
|
151
|
+
// color (legacy threlte-instanced meshes carry an all-white instanceColor that
|
|
152
|
+
// must NOT win), then instanceColor as a last resort. null = keep default.
|
|
153
|
+
function resolve_instance_material_color(instanced_mesh, instance_idx, bond_colors, stored_color) {
|
|
154
|
+
const bond_color = bond_colors?.get(instance_idx);
|
|
155
|
+
if (bond_color)
|
|
156
|
+
return bond_color;
|
|
157
|
+
const { instanceColor } = instanced_mesh;
|
|
158
|
+
const per_instance = instanceColor
|
|
159
|
+
? new Color(instanceColor.getX(instance_idx), instanceColor.getY(instance_idx), instanceColor.getZ(instance_idx))
|
|
160
|
+
: null;
|
|
161
|
+
if (instanced_mesh.userData.per_instance_color && per_instance)
|
|
162
|
+
return per_instance;
|
|
163
|
+
if (stored_color)
|
|
164
|
+
return new Color(stored_color.r, stored_color.g, stored_color.b);
|
|
165
|
+
return per_instance;
|
|
166
|
+
}
|
|
167
|
+
// @internal exported only for tests - not part of the public API.
|
|
168
|
+
export function convert_instanced_meshes_to_regular(scene) {
|
|
161
169
|
// STEP 1: Collect material colors from ORIGINAL scene BEFORE cloning
|
|
162
170
|
// This is crucial because scene.clone() may not properly preserve Threlte's material colors
|
|
163
171
|
const material_colors = new Map();
|
|
@@ -187,25 +195,29 @@ function convert_instanced_meshes_to_regular(scene) {
|
|
|
187
195
|
else {
|
|
188
196
|
// Extract shared material color for atoms
|
|
189
197
|
const single_mat = Array.isArray(mat) ? mat[0] : mat;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
if (has_color_property(single_mat)) {
|
|
199
|
+
material_colors.set(mesh_id, {
|
|
200
|
+
r: single_mat.color.r,
|
|
201
|
+
g: single_mat.color.g,
|
|
202
|
+
b: single_mat.color.b,
|
|
203
|
+
});
|
|
193
204
|
}
|
|
194
205
|
}
|
|
195
206
|
});
|
|
196
207
|
// STEP 2: Clone the scene
|
|
197
208
|
const cloned_scene = scene.clone();
|
|
198
|
-
// STEP 3: Find all InstancedMesh objects in
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
+
// STEP 3: Find all InstancedMesh objects in original + cloned scene (same traversal
|
|
210
|
+
// order) to map cloned meshes back to their original uuid
|
|
211
|
+
const collect_instanced = (root) => {
|
|
212
|
+
const meshes = [];
|
|
213
|
+
root.traverse((object) => {
|
|
214
|
+
if (is_instanced_mesh(object))
|
|
215
|
+
meshes.push(object);
|
|
216
|
+
});
|
|
217
|
+
return meshes;
|
|
218
|
+
};
|
|
219
|
+
const original_meshes = collect_instanced(scene);
|
|
220
|
+
const cloned_meshes = collect_instanced(cloned_scene);
|
|
209
221
|
// STEP 4: Convert each InstancedMesh to individual Mesh objects
|
|
210
222
|
for (let mesh_idx = 0; mesh_idx < cloned_meshes.length; mesh_idx++) {
|
|
211
223
|
const instanced_mesh = cloned_meshes[mesh_idx];
|
|
@@ -244,24 +256,10 @@ function convert_instanced_meshes_to_regular(scene) {
|
|
|
244
256
|
roughness: 0.5,
|
|
245
257
|
});
|
|
246
258
|
new_material.name = `material_${mesh_idx}_${idx}`;
|
|
247
|
-
// Apply the correct color
|
|
248
|
-
const
|
|
249
|
-
if (
|
|
250
|
-
|
|
251
|
-
new_material.color.copy(bond_color);
|
|
252
|
-
}
|
|
253
|
-
else if (stored_color) {
|
|
254
|
-
// Atom with shared material color
|
|
255
|
-
new_material.color.setRGB(stored_color.r, stored_color.g, stored_color.b);
|
|
256
|
-
}
|
|
257
|
-
else if (instanced_mesh.instanceColor) {
|
|
258
|
-
// Fallback: per-instance colors from instanceColor attribute
|
|
259
|
-
const color_r = instanced_mesh.instanceColor.getX(idx);
|
|
260
|
-
const color_g = instanced_mesh.instanceColor.getY(idx);
|
|
261
|
-
const color_b = instanced_mesh.instanceColor.getZ(idx);
|
|
262
|
-
new_material.color.setRGB(color_r, color_g, color_b);
|
|
263
|
-
}
|
|
264
|
-
// If no color found, material stays default white
|
|
259
|
+
// Apply the correct color (null = no color found, material stays default white)
|
|
260
|
+
const resolved_color = resolve_instance_material_color(instanced_mesh, idx, stored_bond_colors, stored_color);
|
|
261
|
+
if (resolved_color)
|
|
262
|
+
new_material.color.copy(resolved_color);
|
|
265
263
|
const mesh = new Mesh(cloned_geometry, new_material);
|
|
266
264
|
// Combine base transform with instance transform
|
|
267
265
|
const combined_matrix = new Matrix4();
|
|
@@ -321,26 +319,18 @@ export function create_structure_filename(structure, extension) {
|
|
|
321
319
|
if (formula && formula !== `Unknown`) {
|
|
322
320
|
safe_push(formula.replaceAll(` `, ``));
|
|
323
321
|
}
|
|
324
|
-
// Add space group if available
|
|
325
|
-
|
|
326
|
-
structure.symmetry
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
if (space_group && typeof space_group === `string`) {
|
|
331
|
-
safe_push(space_group.replaceAll(` `, ``));
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
// Add lattice system if available
|
|
335
|
-
if (`lattice` in structure &&
|
|
336
|
-
structure.lattice &&
|
|
337
|
-
typeof structure.lattice === `object` &&
|
|
338
|
-
`lattice_system` in structure.lattice) {
|
|
339
|
-
const lattice_system = structure.lattice.lattice_system;
|
|
340
|
-
if (lattice_system && typeof lattice_system === `string`) {
|
|
341
|
-
safe_push(lattice_system);
|
|
342
|
-
}
|
|
322
|
+
// Add space group and lattice system if available
|
|
323
|
+
const symmetry = `symmetry` in structure && is_plain_object(structure.symmetry)
|
|
324
|
+
? structure.symmetry
|
|
325
|
+
: undefined;
|
|
326
|
+
if (typeof symmetry?.space_group_symbol === `string`) {
|
|
327
|
+
safe_push(symmetry.space_group_symbol.replaceAll(` `, ``));
|
|
343
328
|
}
|
|
329
|
+
const lattice = `lattice` in structure && is_plain_object(structure.lattice)
|
|
330
|
+
? structure.lattice
|
|
331
|
+
: undefined;
|
|
332
|
+
if (lattice && `lattice_system` in lattice && typeof lattice.lattice_system === `string`)
|
|
333
|
+
safe_push(lattice.lattice_system);
|
|
344
334
|
// Add number of sites
|
|
345
335
|
if (structure.sites?.length)
|
|
346
336
|
parts.push(`${structure.sites.length}sites`);
|
|
@@ -372,9 +362,12 @@ export function structure_to_xyz_str(structure) {
|
|
|
372
362
|
const formula = get_electro_neg_formula(structure, true);
|
|
373
363
|
if (formula && formula !== `Unknown`)
|
|
374
364
|
comment_parts.push(formula);
|
|
365
|
+
const lattice_matrix = `lattice` in structure && structure.lattice?.matrix?.length === 3
|
|
366
|
+
? structure.lattice.matrix
|
|
367
|
+
: null;
|
|
375
368
|
// Include extended XYZ lattice information when available so round-trips preserve lattice
|
|
376
|
-
if (
|
|
377
|
-
const lattice_values =
|
|
369
|
+
if (lattice_matrix) {
|
|
370
|
+
const lattice_values = lattice_matrix
|
|
378
371
|
.flatMap((row) => row.map((value) => (Number.isFinite(value) ? value : 0).toFixed(8)))
|
|
379
372
|
.join(` `);
|
|
380
373
|
comment_parts.push(`Lattice="${lattice_values}"`);
|
|
@@ -382,9 +375,7 @@ export function structure_to_xyz_str(structure) {
|
|
|
382
375
|
const comment = comment_parts.length > 0 ? comment_parts.join(` `) : `Generated from structure`;
|
|
383
376
|
lines.push(comment);
|
|
384
377
|
// Cache converter for fractional→Cartesian (if lattice available)
|
|
385
|
-
const frac_to_cart =
|
|
386
|
-
? math.create_frac_to_cart(structure.lattice.matrix)
|
|
387
|
-
: null;
|
|
378
|
+
const frac_to_cart = lattice_matrix ? math.create_frac_to_cart(lattice_matrix) : null;
|
|
388
379
|
// Atom lines: element symbol followed by x, y, z coordinates
|
|
389
380
|
for (const site of structure.sites) {
|
|
390
381
|
const element_symbol = site_element(site);
|
|
@@ -456,21 +447,14 @@ export function structure_to_cif_str(structure) {
|
|
|
456
447
|
}
|
|
457
448
|
const lines = [];
|
|
458
449
|
// CIF header with data block (required by pymatgen and CIF spec)
|
|
459
|
-
lines.push(`# CIF file generated by MatterViz`);
|
|
460
|
-
const block_name = get_cif_block_name(structure);
|
|
461
|
-
lines.push(`data_${block_name}`);
|
|
462
|
-
lines.push(``);
|
|
450
|
+
lines.push(`# CIF file generated by MatterViz`, `data_${get_cif_block_name(structure)}`, ``);
|
|
463
451
|
// Cell parameters
|
|
464
452
|
const lattice = structure.lattice;
|
|
465
453
|
if (lattice.a && lattice.b && lattice.c) {
|
|
466
|
-
lines.push(`_cell_length_a ${lattice.a.toFixed(6)}`);
|
|
467
|
-
lines.push(`_cell_length_b ${lattice.b.toFixed(6)}`);
|
|
468
|
-
lines.push(`_cell_length_c ${lattice.c.toFixed(6)}`);
|
|
454
|
+
lines.push(`_cell_length_a ${lattice.a.toFixed(6)}`, `_cell_length_b ${lattice.b.toFixed(6)}`, `_cell_length_c ${lattice.c.toFixed(6)}`);
|
|
469
455
|
}
|
|
470
456
|
if (lattice.alpha && lattice.beta && lattice.gamma) {
|
|
471
|
-
lines.push(`_cell_angle_alpha ${lattice.alpha.toFixed(6)}`);
|
|
472
|
-
lines.push(`_cell_angle_beta ${lattice.beta.toFixed(6)}`);
|
|
473
|
-
lines.push(`_cell_angle_gamma ${lattice.gamma.toFixed(6)}`);
|
|
457
|
+
lines.push(`_cell_angle_alpha ${lattice.alpha.toFixed(6)}`, `_cell_angle_beta ${lattice.beta.toFixed(6)}`, `_cell_angle_gamma ${lattice.gamma.toFixed(6)}`);
|
|
474
458
|
}
|
|
475
459
|
// Space group information
|
|
476
460
|
if (`symmetry` in structure && is_plain_object(structure.symmetry)) {
|
|
@@ -489,13 +473,7 @@ export function structure_to_cif_str(structure) {
|
|
|
489
473
|
// full P1 list, so without it parsers would re-apply the H-M ops and multiply sites
|
|
490
474
|
lines.push(`loop_`, `_symmetry_equiv_pos_as_xyz`, ` 'x, y, z'`, ``);
|
|
491
475
|
// Atom site loop header
|
|
492
|
-
lines.push(`loop_`);
|
|
493
|
-
lines.push(`_atom_site_label`);
|
|
494
|
-
lines.push(`_atom_site_type_symbol`);
|
|
495
|
-
lines.push(`_atom_site_fract_x`);
|
|
496
|
-
lines.push(`_atom_site_fract_y`);
|
|
497
|
-
lines.push(`_atom_site_fract_z`);
|
|
498
|
-
lines.push(`_atom_site_occupancy`);
|
|
476
|
+
lines.push(`loop_`, `_atom_site_label`, `_atom_site_type_symbol`, `_atom_site_fract_x`, `_atom_site_fract_y`, `_atom_site_fract_z`, `_atom_site_occupancy`);
|
|
499
477
|
// Cache inverse transpose for Cartesian→fractional conversion (avoids recomputing per site)
|
|
500
478
|
const cart_to_frac = lattice.matrix?.length === 3 ? math.create_cart_to_frac(lattice.matrix) : null;
|
|
501
479
|
// Atom sites: one row per species entry so disordered (multi-species) sites
|
|
@@ -536,11 +514,10 @@ export function structure_to_poscar_str(structure) {
|
|
|
536
514
|
lines.push(`1.0`); // Scale factor (1.0 for direct coordinates)
|
|
537
515
|
const lattice = structure.lattice;
|
|
538
516
|
if (lattice.matrix && Array.isArray(lattice.matrix) && lattice.matrix.length >= 3) {
|
|
539
|
-
//
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
lines.push(`${matrix[2][0].toFixed(8)} ${matrix[2][1].toFixed(8)} ${matrix[2][2].toFixed(8)}`);
|
|
517
|
+
// One line per lattice vector, exactly 3 components at 8-decimal fixed precision
|
|
518
|
+
for (const vec of lattice.matrix.slice(0, 3)) {
|
|
519
|
+
lines.push([vec[0], vec[1], vec[2]].map((coord) => coord.toFixed(8)).join(` `));
|
|
520
|
+
}
|
|
544
521
|
}
|
|
545
522
|
else {
|
|
546
523
|
throw new Error(`No valid lattice matrix for POSCAR export`);
|
|
@@ -572,16 +549,23 @@ export function structure_to_poscar_str(structure) {
|
|
|
572
549
|
for (const group of sites_by_element.values()) {
|
|
573
550
|
for (const site of group) {
|
|
574
551
|
const frac_coords = get_frac_coords(site, cart_to_frac);
|
|
575
|
-
|
|
552
|
+
const coords_str = frac_coords
|
|
553
|
+
.slice(0, 3)
|
|
554
|
+
.map((coord) => coord.toFixed(8))
|
|
555
|
+
.join(` `);
|
|
556
|
+
let sel_dyn_str = ``;
|
|
576
557
|
if (has_selective_dynamics) {
|
|
577
558
|
const sel_dyn = (site.properties?.selective_dynamics ?? [
|
|
578
559
|
true,
|
|
579
560
|
true,
|
|
580
561
|
true,
|
|
581
562
|
]);
|
|
582
|
-
|
|
563
|
+
sel_dyn_str = ` ${sel_dyn
|
|
564
|
+
.slice(0, 3)
|
|
565
|
+
.map((flag) => (flag ? `T` : `F`))
|
|
566
|
+
.join(` `)}`;
|
|
583
567
|
}
|
|
584
|
-
lines.push(`${
|
|
568
|
+
lines.push(`${coords_str}${sel_dyn_str}`);
|
|
585
569
|
}
|
|
586
570
|
}
|
|
587
571
|
return lines.join(`\n`);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function is_structure_file(filename: string): boolean;
|