matterviz 0.3.7 → 0.4.1
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/Icon.svelte +7 -4
- package/dist/MillerIndexInput.svelte +1 -1
- package/dist/api/optimade.js +32 -26
- package/dist/app.css +0 -3
- package/dist/brillouin/BrillouinZone.svelte +76 -148
- package/dist/brillouin/BrillouinZone.svelte.d.ts +6 -14
- package/dist/brillouin/BrillouinZoneExportPane.svelte +43 -96
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +9 -32
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +2 -3
- package/dist/brillouin/BrillouinZoneScene.svelte +97 -205
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +4 -23
- package/dist/brillouin/BrillouinZoneTooltip.svelte +16 -25
- package/dist/brillouin/ReciprocalVectors.svelte +39 -0
- package/dist/brillouin/ReciprocalVectors.svelte.d.ts +9 -0
- package/dist/brillouin/compute.d.ts +2 -0
- package/dist/brillouin/compute.js +89 -90
- package/dist/brillouin/geometry.d.ts +8 -0
- package/dist/brillouin/geometry.js +57 -0
- package/dist/brillouin/index.d.ts +2 -0
- package/dist/brillouin/index.js +2 -0
- package/dist/brillouin/types.d.ts +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte +14 -13
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +109 -203
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +180 -470
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -1
- package/dist/chempot-diagram/async-compute.svelte.js +3 -1
- package/dist/chempot-diagram/chempot-worker.js +2 -1
- package/dist/chempot-diagram/color.d.ts +3 -6
- package/dist/chempot-diagram/color.js +5 -5
- package/dist/chempot-diagram/compute.d.ts +4 -4
- package/dist/chempot-diagram/compute.js +20 -20
- package/dist/chempot-diagram/controls-state.svelte.d.ts +10 -0
- package/dist/chempot-diagram/controls-state.svelte.js +42 -0
- package/dist/chempot-diagram/export.d.ts +47 -0
- package/dist/chempot-diagram/export.js +133 -0
- package/dist/chempot-diagram/index.d.ts +1 -0
- package/dist/chempot-diagram/index.js +1 -0
- package/dist/chempot-diagram/pointer.d.ts +0 -10
- package/dist/chempot-diagram/pointer.js +4 -4
- package/dist/chempot-diagram/types.d.ts +3 -3
- package/dist/colors/index.js +8 -7
- package/dist/composition/FormulaFilter.svelte +18 -11
- package/dist/composition/PieChart.svelte +11 -10
- package/dist/composition/chem-sys.d.ts +8 -0
- package/dist/composition/chem-sys.js +86 -0
- package/dist/composition/format.js +7 -4
- package/dist/composition/index.d.ts +1 -0
- package/dist/composition/index.js +1 -0
- package/dist/composition/parse.d.ts +0 -1
- package/dist/composition/parse.js +41 -31
- package/dist/controls.d.ts +1 -0
- package/dist/controls.js +0 -1
- package/dist/convex-hull/ConvexHull.svelte +8 -10
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -4
- package/dist/convex-hull/ConvexHull2D.svelte +106 -185
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +179 -683
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +183 -687
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullChrome.svelte +268 -0
- package/dist/convex-hull/ConvexHullChrome.svelte.d.ts +30 -0
- package/dist/convex-hull/ConvexHullControls.svelte +88 -7
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +7 -6
- package/dist/convex-hull/ConvexHullInfoPane.svelte +18 -5
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +6 -5
- package/dist/convex-hull/ConvexHullStats.svelte +36 -175
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +3 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +11 -2
- package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +2 -1
- package/dist/convex-hull/GasPressureControls.svelte +4 -4
- package/dist/convex-hull/TemperatureSlider.svelte +2 -2
- package/dist/convex-hull/barycentric-coords.d.ts +2 -4
- package/dist/convex-hull/barycentric-coords.js +6 -33
- package/dist/convex-hull/canvas-interactions.svelte.d.ts +79 -0
- package/dist/convex-hull/canvas-interactions.svelte.js +278 -0
- package/dist/convex-hull/demo-temperature.d.ts +1 -1
- package/dist/convex-hull/demo-temperature.js +20 -22
- package/dist/convex-hull/gas-thermodynamics.d.ts +2 -2
- package/dist/convex-hull/gas-thermodynamics.js +22 -30
- package/dist/convex-hull/helpers.d.ts +42 -7
- package/dist/convex-hull/helpers.js +171 -78
- package/dist/convex-hull/hull-state.svelte.d.ts +44 -0
- package/dist/convex-hull/hull-state.svelte.js +124 -0
- package/dist/convex-hull/index.d.ts +10 -8
- package/dist/convex-hull/index.js +7 -2
- package/dist/convex-hull/thermodynamics.js +136 -960
- package/dist/convex-hull/types.d.ts +13 -5
- package/dist/convex-hull/types.js +12 -0
- package/dist/coordination/CoordinationBarPlot.svelte +27 -34
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
- package/dist/element/BohrAtom.svelte +2 -1
- package/dist/element/index.d.ts +4 -0
- package/dist/element/index.js +18 -0
- package/dist/feedback/DragOverlay.svelte +3 -1
- package/dist/feedback/DragOverlay.svelte.d.ts +1 -0
- package/dist/feedback/StatusMessage.svelte +13 -3
- package/dist/fermi-surface/FermiSlice.svelte +13 -5
- package/dist/fermi-surface/FermiSurface.svelte +78 -151
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -14
- package/dist/fermi-surface/FermiSurfaceControls.svelte +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +72 -221
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +8 -34
- package/dist/fermi-surface/compute.js +67 -66
- package/dist/fermi-surface/export.js +6 -16
- package/dist/fermi-surface/index.d.ts +0 -1
- package/dist/fermi-surface/index.js +0 -1
- package/dist/fermi-surface/parse.d.ts +1 -1
- package/dist/fermi-surface/parse.js +71 -79
- package/dist/fermi-surface/types.d.ts +3 -2
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +69 -52
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +4 -3
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +3 -2
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +5 -5
- package/dist/heatmap-matrix/index.d.ts +3 -2
- package/dist/heatmap-matrix/index.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/io/ExportPane.svelte +166 -0
- package/dist/io/ExportPane.svelte.d.ts +17 -0
- package/dist/io/decompress.js +5 -4
- package/dist/io/export.d.ts +9 -5
- package/dist/io/export.js +77 -51
- package/dist/io/fetch.d.ts +2 -1
- package/dist/io/fetch.js +5 -1
- package/dist/io/file-drop.d.ts +8 -1
- package/dist/io/file-drop.js +48 -36
- package/dist/io/index.d.ts +2 -0
- package/dist/io/index.js +10 -0
- package/dist/io/types.d.ts +13 -0
- package/dist/io/url-drop.js +64 -33
- package/dist/isosurface/parse.js +52 -51
- package/dist/isosurface/slice.js +5 -4
- package/dist/isosurface/types.js +1 -1
- package/dist/keyboard.d.ts +3 -0
- package/dist/keyboard.js +23 -0
- package/dist/labels.d.ts +1 -1
- package/dist/labels.js +9 -8
- package/dist/layout/FullscreenButton.svelte +33 -0
- package/dist/layout/FullscreenButton.svelte.d.ts +10 -0
- package/dist/layout/FullscreenToggle.svelte +8 -14
- package/dist/layout/PropertyFilter.svelte +3 -2
- package/dist/layout/SettingsSection.svelte +1 -1
- package/dist/layout/ViewerChrome.svelte +116 -0
- package/dist/layout/ViewerChrome.svelte.d.ts +17 -0
- package/dist/layout/fullscreen.d.ts +4 -0
- package/dist/layout/fullscreen.svelte.d.ts +8 -0
- package/dist/layout/fullscreen.svelte.js +37 -0
- package/dist/layout/index.d.ts +3 -0
- package/dist/layout/index.js +3 -0
- package/dist/layout/json-tree/JsonNode.svelte +1 -1
- package/dist/layout/json-tree/JsonTree.svelte +2 -2
- package/dist/layout/json-tree/utils.js +5 -4
- package/dist/marching-cubes.js +8 -13
- package/dist/math.d.ts +12 -4
- package/dist/math.js +42 -30
- package/dist/overlays/DraggablePane.svelte +4 -4
- package/dist/overlays/index.d.ts +4 -0
- package/dist/periodic-table/PeriodicTable.svelte +27 -15
- package/dist/periodic-table/PropertySelect.svelte +1 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +9 -3
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte +3 -2
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +4 -3
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +4 -2
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +2 -3
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +47 -132
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +3 -4
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +1 -1
- package/dist/phase-diagram/build-diagram.js +2 -2
- package/dist/phase-diagram/colors.js +1 -1
- package/dist/phase-diagram/parse.d.ts +2 -1
- package/dist/phase-diagram/parse.js +6 -5
- package/dist/phase-diagram/types.d.ts +1 -1
- package/dist/phase-diagram/utils.d.ts +3 -3
- package/dist/phase-diagram/utils.js +8 -12
- package/dist/plot/{BarPlot.svelte → bar/BarPlot.svelte} +246 -841
- package/dist/plot/{BarPlot.svelte.d.ts → bar/BarPlot.svelte.d.ts} +8 -16
- package/dist/plot/{BarPlotControls.svelte → bar/BarPlotControls.svelte} +6 -5
- package/dist/plot/{BarPlotControls.svelte.d.ts → bar/BarPlotControls.svelte.d.ts} +3 -3
- package/dist/plot/{SpacegroupBarPlot.svelte → bar/SpacegroupBarPlot.svelte} +8 -7
- package/dist/plot/{SpacegroupBarPlot.svelte.d.ts → bar/SpacegroupBarPlot.svelte.d.ts} +1 -1
- package/dist/plot/bar/data.d.ts +40 -0
- package/dist/plot/bar/data.js +154 -0
- package/dist/plot/bar/geometry.d.ts +39 -0
- package/dist/plot/bar/geometry.js +60 -0
- package/dist/plot/bar/index.d.ts +3 -0
- package/dist/plot/bar/index.js +3 -0
- package/dist/plot/box/BoxPlot.svelte +1292 -0
- package/dist/plot/box/BoxPlot.svelte.d.ts +95 -0
- package/dist/plot/box/BoxPlotControls.svelte +109 -0
- package/dist/plot/box/BoxPlotControls.svelte.d.ts +19 -0
- package/dist/plot/box/Violin.svelte +14 -0
- package/dist/plot/box/Violin.svelte.d.ts +70 -0
- package/dist/plot/box/box-plot.d.ts +56 -0
- package/dist/plot/box/box-plot.js +129 -0
- package/dist/plot/box/index.d.ts +5 -0
- package/dist/plot/box/index.js +5 -0
- package/dist/plot/box/kde.d.ts +17 -0
- package/dist/plot/box/kde.js +160 -0
- package/dist/plot/box/quantile.d.ts +3 -0
- package/dist/plot/box/quantile.js +53 -0
- package/dist/plot/{auto-place.d.ts → core/auto-place.d.ts} +1 -1
- package/dist/plot/{auto-place.js → core/auto-place.js} +6 -3
- package/dist/plot/core/axis-utils.d.ts +46 -0
- package/dist/plot/core/axis-utils.js +110 -0
- package/dist/plot/{AxisLabel.svelte → core/components/AxisLabel.svelte} +2 -2
- package/dist/plot/{AxisLabel.svelte.d.ts → core/components/AxisLabel.svelte.d.ts} +1 -1
- package/dist/plot/{ColorBar.svelte → core/components/ColorBar.svelte} +41 -38
- package/dist/plot/{ColorBar.svelte.d.ts → core/components/ColorBar.svelte.d.ts} +7 -6
- package/dist/plot/{ColorScaleSelect.svelte → core/components/ColorScaleSelect.svelte} +4 -3
- package/dist/plot/{ColorScaleSelect.svelte.d.ts → core/components/ColorScaleSelect.svelte.d.ts} +2 -2
- package/dist/plot/core/components/ControlPane.svelte +46 -0
- package/dist/plot/core/components/ControlPane.svelte.d.ts +13 -0
- package/dist/plot/{FillArea.svelte → core/components/FillArea.svelte} +17 -6
- package/dist/plot/{FillArea.svelte.d.ts → core/components/FillArea.svelte.d.ts} +1 -1
- package/dist/plot/{InteractiveAxisLabel.svelte → core/components/InteractiveAxisLabel.svelte} +3 -3
- package/dist/plot/{InteractiveAxisLabel.svelte.d.ts → core/components/InteractiveAxisLabel.svelte.d.ts} +2 -2
- package/dist/plot/{Line.svelte → core/components/Line.svelte} +33 -15
- package/dist/plot/{Line.svelte.d.ts → core/components/Line.svelte.d.ts} +3 -2
- package/dist/plot/{PlotAxis.svelte → core/components/PlotAxis.svelte} +9 -6
- package/dist/plot/{PlotAxis.svelte.d.ts → core/components/PlotAxis.svelte.d.ts} +5 -3
- package/dist/plot/{PlotControls.svelte → core/components/PlotControls.svelte} +17 -29
- package/dist/plot/core/components/PlotControls.svelte.d.ts +4 -0
- package/dist/plot/{PlotLegend.svelte → core/components/PlotLegend.svelte} +21 -10
- package/dist/plot/{PlotLegend.svelte.d.ts → core/components/PlotLegend.svelte.d.ts} +3 -2
- package/dist/plot/{PlotTooltip.svelte → core/components/PlotTooltip.svelte} +17 -1
- package/dist/plot/{PlotTooltip.svelte.d.ts → core/components/PlotTooltip.svelte.d.ts} +8 -0
- package/dist/plot/{PortalSelect.svelte → core/components/PortalSelect.svelte} +11 -7
- package/dist/plot/{ReferenceLine.svelte → core/components/ReferenceLine.svelte} +3 -3
- package/dist/plot/{ReferenceLine.svelte.d.ts → core/components/ReferenceLine.svelte.d.ts} +1 -1
- package/dist/plot/{ReferenceLine3D.svelte → core/components/ReferenceLine3D.svelte} +5 -5
- package/dist/plot/{ReferenceLine3D.svelte.d.ts → core/components/ReferenceLine3D.svelte.d.ts} +5 -5
- package/dist/plot/{ReferencePlane.svelte → core/components/ReferencePlane.svelte} +8 -8
- package/dist/plot/{ReferencePlane.svelte.d.ts → core/components/ReferencePlane.svelte.d.ts} +5 -5
- package/dist/plot/{ZeroLines.svelte → core/components/ZeroLines.svelte} +3 -3
- package/dist/plot/{ZeroLines.svelte.d.ts → core/components/ZeroLines.svelte.d.ts} +3 -3
- package/dist/plot/{ZoomRect.svelte → core/components/ZoomRect.svelte} +1 -1
- package/dist/plot/{ZoomRect.svelte.d.ts → core/components/ZoomRect.svelte.d.ts} +1 -1
- package/dist/plot/core/components/index.d.ts +17 -0
- package/dist/plot/core/components/index.js +17 -0
- package/dist/plot/{data-cleaning.d.ts → core/data-cleaning.d.ts} +71 -1
- package/dist/plot/{data-cleaning.js → core/data-cleaning.js} +21 -23
- package/dist/plot/{data-transform.d.ts → core/data-transform.d.ts} +2 -2
- package/dist/plot/{data-transform.js → core/data-transform.js} +3 -3
- package/dist/plot/core/fill-utils.d.ts +34 -0
- package/dist/plot/core/fill-utils.js +391 -0
- package/dist/plot/core/index.d.ts +10 -0
- package/dist/plot/core/index.js +11 -0
- package/dist/plot/core/interactions.d.ts +39 -0
- package/dist/plot/core/interactions.js +209 -0
- package/dist/plot/{layout.d.ts → core/layout.d.ts} +1 -0
- package/dist/plot/{layout.js → core/layout.js} +16 -8
- package/dist/plot/core/pan-zoom.svelte.d.ts +35 -0
- package/dist/plot/core/pan-zoom.svelte.js +221 -0
- package/dist/plot/core/placed-tween.svelte.d.ts +21 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -0
- package/dist/plot/{reference-line.d.ts → core/reference-line.d.ts} +11 -11
- package/dist/plot/{reference-line.js → core/reference-line.js} +29 -42
- package/dist/plot/core/scales.d.ts +40 -0
- package/dist/plot/{scales.js → core/scales.js} +94 -93
- package/dist/plot/core/svg.d.ts +3 -0
- package/dist/plot/core/svg.js +41 -0
- package/dist/plot/{types.d.ts → core/types.d.ts} +36 -85
- package/dist/plot/{types.js → core/types.js} +1 -1
- package/dist/plot/{utils → core/utils}/label-placement.d.ts +3 -3
- package/dist/plot/{utils → core/utils}/label-placement.js +3 -3
- package/dist/plot/core/utils/series-visibility.d.ts +26 -0
- package/dist/plot/{utils → core/utils}/series-visibility.js +29 -2
- package/dist/plot/core/utils.d.ts +12 -0
- package/dist/plot/core/utils.js +27 -0
- package/dist/plot/{Histogram.svelte → histogram/Histogram.svelte} +174 -551
- package/dist/plot/{Histogram.svelte.d.ts → histogram/Histogram.svelte.d.ts} +2 -2
- package/dist/plot/{HistogramControls.svelte → histogram/HistogramControls.svelte} +6 -6
- package/dist/plot/{HistogramControls.svelte.d.ts → histogram/HistogramControls.svelte.d.ts} +4 -4
- package/dist/plot/histogram/index.d.ts +2 -0
- package/dist/plot/histogram/index.js +2 -0
- package/dist/plot/index.d.ts +8 -41
- package/dist/plot/index.js +10 -39
- package/dist/plot/sankey/Sankey.svelte +697 -0
- package/dist/plot/sankey/Sankey.svelte.d.ts +74 -0
- package/dist/plot/sankey/SankeyControls.svelte +98 -0
- package/dist/plot/sankey/SankeyControls.svelte.d.ts +19 -0
- package/dist/plot/sankey/index.d.ts +4 -0
- package/dist/plot/sankey/index.js +3 -0
- package/dist/plot/sankey/sankey-types.d.ts +42 -0
- package/dist/plot/sankey/sankey-types.js +4 -0
- package/dist/plot/sankey/sankey.d.ts +52 -0
- package/dist/plot/sankey/sankey.js +189 -0
- package/dist/plot/{BinnedScatterPlot.svelte → scatter/BinnedScatterPlot.svelte} +64 -64
- package/dist/plot/{BinnedScatterPlot.svelte.d.ts → scatter/BinnedScatterPlot.svelte.d.ts} +6 -6
- package/dist/plot/{ElementScatter.svelte → scatter/ElementScatter.svelte} +6 -6
- package/dist/plot/{ElementScatter.svelte.d.ts → scatter/ElementScatter.svelte.d.ts} +2 -2
- package/dist/plot/{ScatterPlot.svelte → scatter/ScatterPlot.svelte} +297 -1008
- package/dist/plot/{ScatterPlot.svelte.d.ts → scatter/ScatterPlot.svelte.d.ts} +10 -18
- package/dist/plot/{ScatterPlotControls.svelte → scatter/ScatterPlotControls.svelte} +6 -5
- package/dist/plot/{ScatterPlotControls.svelte.d.ts → scatter/ScatterPlotControls.svelte.d.ts} +2 -2
- package/dist/plot/{ScatterPoint.svelte → scatter/ScatterPoint.svelte} +7 -7
- package/dist/plot/{ScatterPoint.svelte.d.ts → scatter/ScatterPoint.svelte.d.ts} +3 -3
- package/dist/plot/{adaptive-density.d.ts → scatter/adaptive-density.d.ts} +14 -4
- package/dist/plot/{adaptive-density.js → scatter/adaptive-density.js} +46 -20
- package/dist/plot/{binned-scatter-types.d.ts → scatter/binned-scatter-types.d.ts} +5 -12
- package/dist/plot/scatter/index.d.ts +7 -0
- package/dist/plot/scatter/index.js +5 -0
- package/dist/plot/scatter/scatter-data.d.ts +19 -0
- package/dist/plot/scatter/scatter-data.js +212 -0
- package/dist/plot/{ScatterPlot3D.svelte → scatter-3d/ScatterPlot3D.svelte} +25 -34
- package/dist/plot/{ScatterPlot3D.svelte.d.ts → scatter-3d/ScatterPlot3D.svelte.d.ts} +9 -17
- package/dist/plot/{ScatterPlot3DControls.svelte → scatter-3d/ScatterPlot3DControls.svelte} +14 -14
- package/dist/plot/{ScatterPlot3DControls.svelte.d.ts → scatter-3d/ScatterPlot3DControls.svelte.d.ts} +6 -6
- package/dist/plot/{ScatterPlot3DScene.svelte → scatter-3d/ScatterPlot3DScene.svelte} +129 -128
- package/dist/plot/{ScatterPlot3DScene.svelte.d.ts → scatter-3d/ScatterPlot3DScene.svelte.d.ts} +6 -15
- package/dist/plot/{Surface3D.svelte → scatter-3d/Surface3D.svelte} +7 -6
- package/dist/plot/{Surface3D.svelte.d.ts → scatter-3d/Surface3D.svelte.d.ts} +5 -4
- package/dist/plot/scatter-3d/index.d.ts +4 -0
- package/dist/plot/scatter-3d/index.js +4 -0
- package/dist/plot/sunburst/Sunburst.svelte +1041 -0
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +97 -0
- package/dist/plot/sunburst/SunburstControls.svelte +200 -0
- package/dist/plot/sunburst/SunburstControls.svelte.d.ts +26 -0
- package/dist/plot/sunburst/index.d.ts +4 -0
- package/dist/plot/sunburst/index.js +4 -0
- package/dist/plot/sunburst/render.d.ts +34 -0
- package/dist/plot/sunburst/render.js +122 -0
- package/dist/plot/sunburst/sunburst.d.ts +62 -0
- package/dist/plot/sunburst/sunburst.js +269 -0
- package/dist/rdf/RdfPlot.svelte +2 -1
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/rdf/calc-rdf.js +11 -24
- package/dist/sanitize.js +14 -3
- package/dist/scene/SceneCamera.svelte +62 -0
- package/dist/scene/SceneCamera.svelte.d.ts +19 -0
- package/dist/scene/bind-renderer.svelte.d.ts +2 -0
- package/dist/scene/bind-renderer.svelte.js +14 -0
- package/dist/scene/index.d.ts +4 -0
- package/dist/scene/index.js +5 -0
- package/dist/scene/props.js +52 -0
- package/dist/scene/types.d.ts +26 -0
- package/dist/scene/types.js +1 -0
- package/dist/settings.d.ts +79 -3
- package/dist/settings.js +321 -1
- package/dist/spectral/Bands.svelte +47 -36
- package/dist/spectral/Bands.svelte.d.ts +6 -6
- package/dist/spectral/BandsAndDos.svelte +23 -25
- package/dist/spectral/BrillouinBandsDos.svelte +42 -30
- package/dist/spectral/Dos.svelte +15 -23
- package/dist/spectral/Dos.svelte.d.ts +4 -3
- package/dist/spectral/helpers.d.ts +8 -6
- package/dist/spectral/helpers.js +137 -65
- package/dist/state.svelte.d.ts +0 -7
- package/dist/state.svelte.js +0 -6
- package/dist/structure/Arrow.svelte +2 -4
- package/dist/structure/AtomLegend.svelte +8 -9
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/CanvasTooltip.svelte +1 -0
- package/dist/structure/CellSelect.svelte +12 -5
- package/dist/structure/CellSelect.svelte.d.ts +2 -1
- package/dist/structure/Cylinder.svelte +12 -8
- package/dist/structure/Cylinder.svelte.d.ts +4 -1
- package/dist/structure/Lattice.svelte +2 -2
- package/dist/structure/Structure.svelte +365 -423
- package/dist/structure/Structure.svelte.d.ts +5 -15
- package/dist/structure/StructureControls.svelte +217 -2
- package/dist/structure/StructureControls.svelte.d.ts +5 -3
- package/dist/structure/StructureExportPane.svelte +54 -156
- package/dist/structure/StructureExportPane.svelte.d.ts +4 -5
- package/dist/structure/StructureInfoPane.svelte +10 -9
- package/dist/structure/StructureInfoPane.svelte.d.ts +5 -5
- package/dist/structure/StructureScene.svelte +376 -208
- package/dist/structure/StructureScene.svelte.d.ts +22 -20
- package/dist/structure/{label-placement.d.ts → atom-label-placement.d.ts} +3 -3
- package/dist/structure/{label-placement.js → atom-label-placement.js} +15 -5
- package/dist/structure/atom-properties.d.ts +1 -1
- package/dist/structure/atom-properties.js +17 -22
- package/dist/structure/bond-order-perception.js +3 -5
- package/dist/structure/bonding.d.ts +4 -0
- package/dist/structure/bonding.js +134 -63
- package/dist/structure/export.d.ts +24 -4
- package/dist/structure/export.js +89 -143
- package/dist/structure/index.d.ts +4 -4
- package/dist/structure/index.js +3 -3
- package/dist/structure/measure.d.ts +3 -2
- package/dist/structure/measure.js +6 -5
- package/dist/structure/parse.d.ts +3 -2
- package/dist/structure/parse.js +419 -438
- package/dist/structure/partial-occupancy.d.ts +0 -1
- package/dist/structure/partial-occupancy.js +1 -1
- package/dist/structure/pbc.d.ts +1 -1
- package/dist/structure/pbc.js +190 -13
- package/dist/structure/polyhedra.d.ts +41 -0
- package/dist/structure/polyhedra.js +602 -0
- package/dist/structure/site.d.ts +4 -0
- package/dist/structure/site.js +1 -0
- package/dist/structure/supercell.js +3 -2
- package/dist/structure/validation.js +5 -6
- package/dist/symmetry/SymmetryElementControls.svelte +69 -0
- package/dist/symmetry/SymmetryElementControls.svelte.d.ts +9 -0
- package/dist/symmetry/SymmetryElements.svelte +354 -0
- package/dist/symmetry/SymmetryElements.svelte.d.ts +24 -0
- package/dist/symmetry/SymmetryStats.svelte +113 -8
- package/dist/symmetry/WyckoffTable.svelte +68 -7
- package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -0
- package/dist/symmetry/cell-transform.js +7 -14
- package/dist/symmetry/index.d.ts +14 -4
- package/dist/symmetry/index.js +291 -72
- package/dist/symmetry/spacegroups.d.ts +12 -1
- package/dist/symmetry/spacegroups.js +63 -14
- package/dist/symmetry/symmetry-elements.d.ts +33 -0
- package/dist/symmetry/symmetry-elements.js +521 -0
- package/dist/symmetry/wyckoff-db.d.ts +9 -0
- package/dist/symmetry/wyckoff-db.js +87 -0
- package/dist/table/HeatmapTable.svelte +66 -25
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/table/index.d.ts +1 -3
- package/dist/table/index.js +1 -1
- package/dist/theme/index.js +8 -8
- package/dist/tooltip/KCoords.svelte +45 -0
- package/dist/tooltip/KCoords.svelte.d.ts +8 -0
- package/dist/tooltip/index.d.ts +1 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/trajectory/Trajectory.svelte +123 -100
- package/dist/trajectory/Trajectory.svelte.d.ts +11 -22
- package/dist/trajectory/TrajectoryExportPane.svelte +17 -25
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
- package/dist/trajectory/TrajectoryInfoPane.svelte +5 -3
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -2
- package/dist/trajectory/constants.js +6 -2
- package/dist/trajectory/extract.js +17 -37
- package/dist/trajectory/format-detect.d.ts +1 -1
- package/dist/trajectory/format-detect.js +27 -19
- package/dist/trajectory/frame-reader.d.ts +0 -1
- package/dist/trajectory/frame-reader.js +63 -162
- package/dist/trajectory/helpers.d.ts +10 -2
- package/dist/trajectory/helpers.js +56 -36
- package/dist/trajectory/index.js +1 -1
- package/dist/trajectory/parse/ase.d.ts +9 -1
- package/dist/trajectory/parse/ase.js +47 -32
- package/dist/trajectory/parse/diagnostics.d.ts +3 -0
- package/dist/trajectory/parse/diagnostics.js +14 -0
- package/dist/trajectory/parse/hdf5.js +1 -1
- package/dist/trajectory/parse/index.d.ts +1 -1
- package/dist/trajectory/parse/index.js +65 -105
- package/dist/trajectory/parse/lammps.d.ts +0 -2
- package/dist/trajectory/parse/lammps.js +8 -6
- package/dist/trajectory/parse/pymatgen.d.ts +2 -0
- package/dist/trajectory/parse/pymatgen.js +74 -0
- package/dist/trajectory/parse/vasp.js +38 -18
- package/dist/trajectory/parse/xyz.d.ts +13 -1
- package/dist/trajectory/parse/xyz.js +102 -94
- package/dist/trajectory/plotting.d.ts +1 -2
- package/dist/trajectory/plotting.js +16 -113
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +7 -5
- package/dist/xrd/XrdPlot.svelte +16 -30
- package/dist/xrd/broadening.d.ts +2 -1
- package/dist/xrd/calc-xrd.js +18 -20
- package/dist/xrd/index.d.ts +2 -2
- package/dist/xrd/parse.js +2 -2
- package/package.json +43 -26
- package/dist/element/data.json +0 -11864
- package/dist/fermi-surface/marching-cubes.d.ts +0 -2
- package/dist/fermi-surface/marching-cubes.js +0 -2
- package/dist/plot/PlotControls.svelte.d.ts +0 -4
- package/dist/plot/axis-utils.d.ts +0 -19
- package/dist/plot/axis-utils.js +0 -78
- package/dist/plot/defaults.d.ts +0 -19
- package/dist/plot/defaults.js +0 -9
- package/dist/plot/fill-utils.d.ts +0 -46
- package/dist/plot/fill-utils.js +0 -322
- package/dist/plot/hover-lock.svelte.d.ts +0 -14
- package/dist/plot/hover-lock.svelte.js +0 -46
- package/dist/plot/interactions.d.ts +0 -12
- package/dist/plot/interactions.js +0 -101
- package/dist/plot/scales.d.ts +0 -48
- package/dist/plot/svg.d.ts +0 -1
- package/dist/plot/svg.js +0 -11
- package/dist/plot/utils/series-visibility.d.ts +0 -15
- package/dist/plot/utils.d.ts +0 -1
- package/dist/plot/utils.js +0 -14
- /package/dist/plot/{PortalSelect.svelte.d.ts → core/components/PortalSelect.svelte.d.ts} +0 -0
- /package/dist/plot/{binned-scatter-types.js → scatter/binned-scatter-types.js} +0 -0
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
// Coordination polyhedra detection and mesh generation.
|
|
2
|
+
// Self-contained: vertices come from the rendered bond graph, hulls from a custom
|
|
3
|
+
// quickhull tailored to small point sets (CN 4-12), output as merged typed arrays
|
|
4
|
+
// so the whole scene renders in 1-2 draw calls regardless of supercell size.
|
|
5
|
+
// Hot paths use scalar math and per-element caches to scale to large structures.
|
|
6
|
+
import { rgb as parse_rgb } from 'd3-color';
|
|
7
|
+
import { DEFAULTS } from '../settings';
|
|
8
|
+
import { get_orig_site_idx } from './atom-properties';
|
|
9
|
+
import { element_lookup, get_majority_element } from './bonding';
|
|
10
|
+
const face_of = (points, vert_a, vert_b, vert_c) => {
|
|
11
|
+
const [ax, ay, az] = points[vert_a];
|
|
12
|
+
const abx = points[vert_b][0] - ax;
|
|
13
|
+
const aby = points[vert_b][1] - ay;
|
|
14
|
+
const abz = points[vert_b][2] - az;
|
|
15
|
+
const acx = points[vert_c][0] - ax;
|
|
16
|
+
const acy = points[vert_c][1] - ay;
|
|
17
|
+
const acz = points[vert_c][2] - az;
|
|
18
|
+
let nx = aby * acz - abz * acy;
|
|
19
|
+
let ny = abz * acx - abx * acz;
|
|
20
|
+
let nz = abx * acy - aby * acx;
|
|
21
|
+
const len = Math.hypot(nx, ny, nz);
|
|
22
|
+
if (len > 0) {
|
|
23
|
+
nx /= len;
|
|
24
|
+
ny /= len;
|
|
25
|
+
nz /= len;
|
|
26
|
+
}
|
|
27
|
+
else
|
|
28
|
+
[nx, ny, nz] = [0, 0, 1];
|
|
29
|
+
return {
|
|
30
|
+
vert_a,
|
|
31
|
+
vert_b,
|
|
32
|
+
vert_c,
|
|
33
|
+
nx,
|
|
34
|
+
ny,
|
|
35
|
+
nz,
|
|
36
|
+
offset: nx * ax + ny * ay + nz * az,
|
|
37
|
+
outside: [],
|
|
38
|
+
deleted: false,
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
// Signed distance of point from face plane (positive = outside).
|
|
42
|
+
const dist_to_face = (face, point) => face.nx * point[0] + face.ny * point[1] + face.nz * point[2] - face.offset;
|
|
43
|
+
// Compute the 3D convex hull of a small point set via quickhull.
|
|
44
|
+
// Returns a degenerate result (faces=[], volume=0) for <4 unique points or
|
|
45
|
+
// collinear/coplanar sets (e.g. square-planar CN=4 coordination draws nothing,
|
|
46
|
+
// matching VESTA behavior). Supports up to 65535 input points (edge keys are
|
|
47
|
+
// packed into 32-bit integers) - far beyond any coordination shell.
|
|
48
|
+
export function convex_hull_3d(points, eps_scale = 1e-7) {
|
|
49
|
+
// Dedup points (coordination shells are tiny, O(n^2) is fine)
|
|
50
|
+
const unique = [];
|
|
51
|
+
const unique_input_idx = [];
|
|
52
|
+
for (let p_idx = 0; p_idx < points.length; p_idx++) {
|
|
53
|
+
const [px, py, pz] = points[p_idx];
|
|
54
|
+
let is_dup = false;
|
|
55
|
+
for (const other of unique) {
|
|
56
|
+
const dx = px - other[0];
|
|
57
|
+
const dy = py - other[1];
|
|
58
|
+
const dz = pz - other[2];
|
|
59
|
+
if (dx * dx + dy * dy + dz * dz < 1e-12) {
|
|
60
|
+
is_dup = true;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (!is_dup) {
|
|
65
|
+
unique.push(points[p_idx]);
|
|
66
|
+
unique_input_idx.push(p_idx);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const degenerate = {
|
|
70
|
+
vertices: unique,
|
|
71
|
+
input_idxs: unique_input_idx,
|
|
72
|
+
faces: [],
|
|
73
|
+
volume: 0,
|
|
74
|
+
};
|
|
75
|
+
if (unique.length < 4)
|
|
76
|
+
return degenerate;
|
|
77
|
+
// Bounding-box diagonal sets the numerical tolerance scale
|
|
78
|
+
let [min_x, min_y, min_z] = unique[0];
|
|
79
|
+
let [max_x, max_y, max_z] = unique[0];
|
|
80
|
+
for (const [px, py, pz] of unique) {
|
|
81
|
+
if (px < min_x)
|
|
82
|
+
min_x = px;
|
|
83
|
+
if (px > max_x)
|
|
84
|
+
max_x = px;
|
|
85
|
+
if (py < min_y)
|
|
86
|
+
min_y = py;
|
|
87
|
+
if (py > max_y)
|
|
88
|
+
max_y = py;
|
|
89
|
+
if (pz < min_z)
|
|
90
|
+
min_z = pz;
|
|
91
|
+
if (pz > max_z)
|
|
92
|
+
max_z = pz;
|
|
93
|
+
}
|
|
94
|
+
const diag = Math.hypot(max_x - min_x, max_y - min_y, max_z - min_z);
|
|
95
|
+
const eps = eps_scale * Math.max(1, diag);
|
|
96
|
+
// Initial simplex: farthest pair along principal axes -> farthest from line -> from plane
|
|
97
|
+
let [pt_0, pt_1] = [0, 1];
|
|
98
|
+
let max_dist = -1;
|
|
99
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
100
|
+
let [lo_idx, hi_idx] = [0, 0];
|
|
101
|
+
for (let idx = 1; idx < unique.length; idx++) {
|
|
102
|
+
if (unique[idx][axis] < unique[lo_idx][axis])
|
|
103
|
+
lo_idx = idx;
|
|
104
|
+
if (unique[idx][axis] > unique[hi_idx][axis])
|
|
105
|
+
hi_idx = idx;
|
|
106
|
+
}
|
|
107
|
+
const dx = unique[hi_idx][0] - unique[lo_idx][0];
|
|
108
|
+
const dy = unique[hi_idx][1] - unique[lo_idx][1];
|
|
109
|
+
const dz = unique[hi_idx][2] - unique[lo_idx][2];
|
|
110
|
+
const dist = Math.hypot(dx, dy, dz);
|
|
111
|
+
if (dist > max_dist)
|
|
112
|
+
[max_dist, pt_0, pt_1] = [dist, lo_idx, hi_idx];
|
|
113
|
+
}
|
|
114
|
+
if (max_dist < eps)
|
|
115
|
+
return degenerate; // all points coincide
|
|
116
|
+
const [ox, oy, oz] = unique[pt_0];
|
|
117
|
+
let dir_x = unique[pt_1][0] - ox;
|
|
118
|
+
let dir_y = unique[pt_1][1] - oy;
|
|
119
|
+
let dir_z = unique[pt_1][2] - oz;
|
|
120
|
+
const dir_len = Math.hypot(dir_x, dir_y, dir_z);
|
|
121
|
+
dir_x /= dir_len;
|
|
122
|
+
dir_y /= dir_len;
|
|
123
|
+
dir_z /= dir_len;
|
|
124
|
+
let pt_2 = -1;
|
|
125
|
+
max_dist = eps;
|
|
126
|
+
for (let idx = 0; idx < unique.length; idx++) {
|
|
127
|
+
const rx = unique[idx][0] - ox;
|
|
128
|
+
const ry = unique[idx][1] - oy;
|
|
129
|
+
const rz = unique[idx][2] - oz;
|
|
130
|
+
const proj = rx * dir_x + ry * dir_y + rz * dir_z;
|
|
131
|
+
const perp_sq = rx * rx + ry * ry + rz * rz - proj * proj;
|
|
132
|
+
if (perp_sq > max_dist * max_dist) {
|
|
133
|
+
max_dist = Math.sqrt(perp_sq);
|
|
134
|
+
pt_2 = idx;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (pt_2 === -1)
|
|
138
|
+
return degenerate; // collinear
|
|
139
|
+
const base = face_of(unique, pt_0, pt_1, pt_2);
|
|
140
|
+
let pt_3 = -1;
|
|
141
|
+
max_dist = eps;
|
|
142
|
+
for (let idx = 0; idx < unique.length; idx++) {
|
|
143
|
+
const dist = Math.abs(dist_to_face(base, unique[idx]));
|
|
144
|
+
if (dist > max_dist)
|
|
145
|
+
[max_dist, pt_3] = [dist, idx];
|
|
146
|
+
}
|
|
147
|
+
if (pt_3 === -1)
|
|
148
|
+
return degenerate; // coplanar
|
|
149
|
+
// Build initial tetrahedron with outward-facing windings
|
|
150
|
+
const centroid = [
|
|
151
|
+
(unique[pt_0][0] + unique[pt_1][0] + unique[pt_2][0] + unique[pt_3][0]) / 4,
|
|
152
|
+
(unique[pt_0][1] + unique[pt_1][1] + unique[pt_2][1] + unique[pt_3][1]) / 4,
|
|
153
|
+
(unique[pt_0][2] + unique[pt_1][2] + unique[pt_2][2] + unique[pt_3][2]) / 4,
|
|
154
|
+
];
|
|
155
|
+
const faces = [];
|
|
156
|
+
for (const [idx_a, idx_b, idx_c] of [
|
|
157
|
+
[pt_0, pt_1, pt_2],
|
|
158
|
+
[pt_0, pt_1, pt_3],
|
|
159
|
+
[pt_0, pt_2, pt_3],
|
|
160
|
+
[pt_1, pt_2, pt_3],
|
|
161
|
+
]) {
|
|
162
|
+
let face = face_of(unique, idx_a, idx_b, idx_c);
|
|
163
|
+
if (dist_to_face(face, centroid) > 0)
|
|
164
|
+
face = face_of(unique, idx_a, idx_c, idx_b);
|
|
165
|
+
faces.push(face);
|
|
166
|
+
}
|
|
167
|
+
// Assign each remaining point to the face it lies farthest outside of
|
|
168
|
+
const assign_point = (point_idx, candidates) => {
|
|
169
|
+
let [best_face, best_dist] = [null, eps];
|
|
170
|
+
for (const face of candidates) {
|
|
171
|
+
if (face.deleted)
|
|
172
|
+
continue;
|
|
173
|
+
const dist = dist_to_face(face, unique[point_idx]);
|
|
174
|
+
if (dist > best_dist)
|
|
175
|
+
[best_face, best_dist] = [face, dist];
|
|
176
|
+
}
|
|
177
|
+
best_face?.outside.push(point_idx);
|
|
178
|
+
};
|
|
179
|
+
for (let idx = 0; idx < unique.length; idx++) {
|
|
180
|
+
if (idx !== pt_0 && idx !== pt_1 && idx !== pt_2 && idx !== pt_3) {
|
|
181
|
+
assign_point(idx, faces);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Expand hull: repeatedly absorb the farthest outside point. Horizon edges are
|
|
185
|
+
// tracked as packed 32-bit integers (from * 2^16 + to) instead of strings.
|
|
186
|
+
const edge_set = new Set(); // packed directed edges
|
|
187
|
+
for (let guard = 0; guard < unique.length * 4; guard++) {
|
|
188
|
+
const active = faces.find((face) => !face.deleted && face.outside.length > 0);
|
|
189
|
+
if (!active)
|
|
190
|
+
break;
|
|
191
|
+
let [eye, eye_dist] = [-1, -Infinity];
|
|
192
|
+
for (const point_idx of active.outside) {
|
|
193
|
+
const dist = dist_to_face(active, unique[point_idx]);
|
|
194
|
+
if (dist > eye_dist)
|
|
195
|
+
[eye, eye_dist] = [point_idx, dist];
|
|
196
|
+
}
|
|
197
|
+
// Find all faces visible from the eye point and collect orphaned points
|
|
198
|
+
const orphans = [];
|
|
199
|
+
edge_set.clear();
|
|
200
|
+
for (const face of faces) {
|
|
201
|
+
if (face.deleted || dist_to_face(face, unique[eye]) <= eps)
|
|
202
|
+
continue;
|
|
203
|
+
face.deleted = true;
|
|
204
|
+
for (const point_idx of face.outside)
|
|
205
|
+
if (point_idx !== eye)
|
|
206
|
+
orphans.push(point_idx);
|
|
207
|
+
for (const [from, to] of [
|
|
208
|
+
[face.vert_a, face.vert_b],
|
|
209
|
+
[face.vert_b, face.vert_c],
|
|
210
|
+
[face.vert_c, face.vert_a],
|
|
211
|
+
]) {
|
|
212
|
+
const reverse_key = to * 65536 + from;
|
|
213
|
+
if (edge_set.has(reverse_key))
|
|
214
|
+
edge_set.delete(reverse_key); // internal edge
|
|
215
|
+
else
|
|
216
|
+
edge_set.add(from * 65536 + to);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Horizon edges (directed, so new faces inherit outward winding)
|
|
220
|
+
const new_faces = [];
|
|
221
|
+
for (const packed of edge_set) {
|
|
222
|
+
const from = Math.floor(packed / 65536);
|
|
223
|
+
const to = packed % 65536;
|
|
224
|
+
const face = face_of(unique, from, to, eye);
|
|
225
|
+
faces.push(face);
|
|
226
|
+
new_faces.push(face);
|
|
227
|
+
}
|
|
228
|
+
for (const point_idx of orphans)
|
|
229
|
+
assign_point(point_idx, new_faces);
|
|
230
|
+
}
|
|
231
|
+
// Compact vertices used by surviving faces and remap indices
|
|
232
|
+
const vert_remap = new Map();
|
|
233
|
+
const vertices = [];
|
|
234
|
+
const input_idxs = [];
|
|
235
|
+
const remap = (old_idx) => {
|
|
236
|
+
let new_idx = vert_remap.get(old_idx);
|
|
237
|
+
if (new_idx === undefined) {
|
|
238
|
+
new_idx = vertices.length;
|
|
239
|
+
vert_remap.set(old_idx, new_idx);
|
|
240
|
+
vertices.push(unique[old_idx]);
|
|
241
|
+
input_idxs.push(unique_input_idx[old_idx]);
|
|
242
|
+
}
|
|
243
|
+
return new_idx;
|
|
244
|
+
};
|
|
245
|
+
const remapped = [];
|
|
246
|
+
for (const face of faces) {
|
|
247
|
+
if (!face.deleted) {
|
|
248
|
+
remapped.push([remap(face.vert_a), remap(face.vert_b), remap(face.vert_c)]);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Volume via signed tetrahedra from the hull centroid (positive with outward winding)
|
|
252
|
+
let [cx, cy, cz] = [0, 0, 0];
|
|
253
|
+
for (const [vx, vy, vz] of vertices) {
|
|
254
|
+
cx += vx;
|
|
255
|
+
cy += vy;
|
|
256
|
+
cz += vz;
|
|
257
|
+
}
|
|
258
|
+
cx /= vertices.length;
|
|
259
|
+
cy /= vertices.length;
|
|
260
|
+
cz /= vertices.length;
|
|
261
|
+
let volume = 0;
|
|
262
|
+
for (const [idx_a, idx_b, idx_c] of remapped) {
|
|
263
|
+
const ax = vertices[idx_a][0] - cx;
|
|
264
|
+
const ay = vertices[idx_a][1] - cy;
|
|
265
|
+
const az = vertices[idx_a][2] - cz;
|
|
266
|
+
const bx = vertices[idx_b][0] - cx;
|
|
267
|
+
const by = vertices[idx_b][1] - cy;
|
|
268
|
+
const bz = vertices[idx_b][2] - cz;
|
|
269
|
+
const dx = vertices[idx_c][0] - cx;
|
|
270
|
+
const dy = vertices[idx_c][1] - cy;
|
|
271
|
+
const dz = vertices[idx_c][2] - cz;
|
|
272
|
+
volume +=
|
|
273
|
+
(ax * (by * dz - bz * dy) + ay * (bz * dx - bx * dz) + az * (bx * dy - by * dx)) / 6;
|
|
274
|
+
}
|
|
275
|
+
return { vertices, input_idxs, faces: remapped, volume: Math.abs(volume) };
|
|
276
|
+
}
|
|
277
|
+
// --- Bond graph adjacency ---
|
|
278
|
+
// Symmetric site_idx -> neighbor site_idx set from rendered bond pairs.
|
|
279
|
+
export function build_adjacency(bonds) {
|
|
280
|
+
const adjacency = new Map();
|
|
281
|
+
const link = (from, to) => {
|
|
282
|
+
const neighbors = adjacency.get(from);
|
|
283
|
+
if (neighbors)
|
|
284
|
+
neighbors.add(to);
|
|
285
|
+
else
|
|
286
|
+
adjacency.set(from, new Set([to]));
|
|
287
|
+
};
|
|
288
|
+
for (const { site_idx_1, site_idx_2 } of bonds) {
|
|
289
|
+
if (site_idx_1 === site_idx_2)
|
|
290
|
+
continue;
|
|
291
|
+
link(site_idx_1, site_idx_2);
|
|
292
|
+
link(site_idx_2, site_idx_1);
|
|
293
|
+
}
|
|
294
|
+
return adjacency;
|
|
295
|
+
}
|
|
296
|
+
// --- Center selection ---
|
|
297
|
+
// Large low-valent A-site cations whose coordination polyhedra (CN 8-12) tend to
|
|
298
|
+
// obscure the structural framework. VESTA-style figures draw the framework
|
|
299
|
+
// (e.g. TiO6 in BaTiO3, FeO6/PO4 in LiFePO4) and leave these as plain spheres.
|
|
300
|
+
// They still get polyhedra when they are the only qualifying cations (e.g. NaCl)
|
|
301
|
+
// or when force-included via `included_center_elements`.
|
|
302
|
+
const SPECTATOR_CATEGORIES = new Set([`alkali metal`]);
|
|
303
|
+
const HEAVY_ALKALINE_EARTHS = new Set([`Ca`, `Sr`, `Ba`, `Ra`]);
|
|
304
|
+
export const is_spectator_center = (element) => SPECTATOR_CATEGORIES.has(element_lookup.get(element)?.category ?? ``) ||
|
|
305
|
+
HEAVY_ALKALINE_EARTHS.has(element);
|
|
306
|
+
// A bonded neighbor counts as a polyhedron vertex only if it's an anion-former:
|
|
307
|
+
// a nonmetal or metalloid that is more electronegative than the center. This keeps
|
|
308
|
+
// spurious cation-cation bonds (e.g. Ti-Ba in perovskites, Li-P in thiophosphates)
|
|
309
|
+
// from contaminating coordination environments.
|
|
310
|
+
function is_anion_vertex(center_en, center_is_metal, neighbor_element, electronegativity_margin) {
|
|
311
|
+
if (!neighbor_element)
|
|
312
|
+
return false;
|
|
313
|
+
const n_data = element_lookup.get(neighbor_element);
|
|
314
|
+
if (n_data?.metal)
|
|
315
|
+
return false;
|
|
316
|
+
const n_en = n_data?.electronegativity ?? null;
|
|
317
|
+
if (center_en !== null && n_en !== null) {
|
|
318
|
+
return n_en > center_en + electronegativity_margin;
|
|
319
|
+
}
|
|
320
|
+
// EN data missing: only metal centers with nonmetal neighbors qualify
|
|
321
|
+
return center_is_metal && n_data?.nonmetal === true;
|
|
322
|
+
}
|
|
323
|
+
// --- Top-level polyhedra computation ---
|
|
324
|
+
// Detect coordination polyhedra from the rendered bond graph, VESTA-style:
|
|
325
|
+
// vertices are anion-former neighbors (nonmetals/metalloids more electronegative
|
|
326
|
+
// than the center) within `1 + distance_factor` of the shortest such bond, so
|
|
327
|
+
// over-long bond-graph noise doesn't inflate e.g. PO4 tetrahedra. Spectator A-site
|
|
328
|
+
// cations (alkali, heavy alkaline-earth) are skipped when framework cations exist,
|
|
329
|
+
// CN > max_neighbors hulls (e.g. CN-12 cuboctahedra) are skipped, and
|
|
330
|
+
// boundary-truncated copies only render when their vertex count matches the max
|
|
331
|
+
// among all copies of the same original site. Every polyhedron corner is a
|
|
332
|
+
// displayed atom (boundary shells are completed upstream by bond-completing image
|
|
333
|
+
// atoms - see find_image_atoms in pbc.ts).
|
|
334
|
+
export function compute_polyhedra(structure, bonds, options = {}) {
|
|
335
|
+
const {
|
|
336
|
+
// Neighbor-count fallbacks derive from DEFAULTS.structure so they can't drift
|
|
337
|
+
// from the polyhedra_min/max_neighbors settings defaults
|
|
338
|
+
min_neighbors = DEFAULTS.structure.polyhedra_min_neighbors, max_neighbors = DEFAULTS.structure.polyhedra_max_neighbors, excluded_center_elements = [], included_center_elements = [], electronegativity_margin = 0, distance_factor = 0.3, weak_bond_norm = 1.15, volume_eps = 1e-3, } = options;
|
|
339
|
+
const sites = structure?.sites;
|
|
340
|
+
if (!sites?.length || bonds.length === 0)
|
|
341
|
+
return [];
|
|
342
|
+
const adjacency = build_adjacency(bonds);
|
|
343
|
+
const excluded = new Set(excluded_center_elements);
|
|
344
|
+
const included = new Set(included_center_elements);
|
|
345
|
+
const site_elements = sites.map((site) => get_majority_element(site));
|
|
346
|
+
const unique_elements = [
|
|
347
|
+
...new Set(site_elements.filter((el) => el !== null)),
|
|
348
|
+
];
|
|
349
|
+
const center_info_cache = new Map();
|
|
350
|
+
const center_info = (element) => {
|
|
351
|
+
let info = center_info_cache.get(element);
|
|
352
|
+
if (!info) {
|
|
353
|
+
const data = element_lookup.get(element);
|
|
354
|
+
const center_en = data?.electronegativity ?? null;
|
|
355
|
+
const r_center = data?.covalent_radius ?? null;
|
|
356
|
+
const accepts = new Set(unique_elements.filter((n_elem) => is_anion_vertex(center_en, data?.metal === true, n_elem, electronegativity_margin)));
|
|
357
|
+
const radii_sums = new Map(unique_elements.map((n_elem) => {
|
|
358
|
+
const r_n = element_lookup.get(n_elem)?.covalent_radius ?? null;
|
|
359
|
+
return [n_elem, r_center !== null && r_n !== null ? r_center + r_n : null];
|
|
360
|
+
}));
|
|
361
|
+
info = { accepts, radii_sums };
|
|
362
|
+
center_info_cache.set(element, info);
|
|
363
|
+
}
|
|
364
|
+
return info;
|
|
365
|
+
};
|
|
366
|
+
const candidates = [];
|
|
367
|
+
for (const [site_idx, neighbors] of adjacency) {
|
|
368
|
+
if (neighbors.size < min_neighbors)
|
|
369
|
+
continue;
|
|
370
|
+
const element = site_elements[site_idx];
|
|
371
|
+
if (!element || excluded.has(element))
|
|
372
|
+
continue;
|
|
373
|
+
const { accepts, radii_sums } = center_info(element);
|
|
374
|
+
if (accepts.size === 0)
|
|
375
|
+
continue;
|
|
376
|
+
const [cx, cy, cz] = sites[site_idx].xyz;
|
|
377
|
+
// Bonded anion vertices (parallel arrays to avoid per-vertex object churn)
|
|
378
|
+
const vert_idxs = [];
|
|
379
|
+
const vert_dists = [];
|
|
380
|
+
let min_dist = Infinity;
|
|
381
|
+
for (const idx of neighbors) {
|
|
382
|
+
const n_elem = site_elements[idx];
|
|
383
|
+
if (!n_elem || !accepts.has(n_elem))
|
|
384
|
+
continue;
|
|
385
|
+
const [nx, ny, nz] = sites[idx].xyz;
|
|
386
|
+
const dist = Math.hypot(nx - cx, ny - cy, nz - cz);
|
|
387
|
+
vert_idxs.push(idx);
|
|
388
|
+
vert_dists.push(dist);
|
|
389
|
+
if (dist < min_dist)
|
|
390
|
+
min_dist = dist;
|
|
391
|
+
}
|
|
392
|
+
if (vert_idxs.length < min_neighbors)
|
|
393
|
+
continue;
|
|
394
|
+
// Trim over-long bonds relative to the shortest anion bond (VESTA-like local
|
|
395
|
+
// cutoff): keeps distorted/Jahn-Teller octahedra intact but rejects e.g. a 5th
|
|
396
|
+
// oxygen at 2.5 Å around P whose true tetrahedron has 1.5 Å bonds
|
|
397
|
+
const cutoff = min_dist * (1 + distance_factor);
|
|
398
|
+
const vertex_site_idxs = [];
|
|
399
|
+
let [norm_sum, norm_count] = [0, 0];
|
|
400
|
+
for (let pos = 0; pos < vert_idxs.length; pos++) {
|
|
401
|
+
if (vert_dists[pos] > cutoff)
|
|
402
|
+
continue;
|
|
403
|
+
const idx = vert_idxs[pos];
|
|
404
|
+
vertex_site_idxs.push(idx);
|
|
405
|
+
// Bond softness: how stretched the kept bonds are vs the covalent-radii sum
|
|
406
|
+
const n_elem = site_elements[idx];
|
|
407
|
+
const r_sum = n_elem ? (radii_sums.get(n_elem) ?? null) : null;
|
|
408
|
+
if (r_sum !== null) {
|
|
409
|
+
norm_sum += vert_dists[pos] / r_sum;
|
|
410
|
+
norm_count++;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (vertex_site_idxs.length < min_neighbors)
|
|
414
|
+
continue;
|
|
415
|
+
candidates.push({
|
|
416
|
+
site_idx,
|
|
417
|
+
orig_idx: get_orig_site_idx(sites[site_idx], site_idx),
|
|
418
|
+
element,
|
|
419
|
+
vertex_site_idxs,
|
|
420
|
+
mean_norm_dist: norm_count > 0 ? norm_sum / norm_count : null,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
// Pass 2: hide spectator A-site cations when the composition contains a
|
|
424
|
+
// potential framework cation (a non-spectator element less electronegative than
|
|
425
|
+
// the structure's most electronegative element, i.e. one that could coordinate
|
|
426
|
+
// the anions). Composition-based rather than candidate-based so boundary
|
|
427
|
+
// truncation of framework polyhedra doesn't promote Li/Na/Ba clutter; purely
|
|
428
|
+
// ionic binaries like NaCl or CaF2 still draw their spectator polyhedra.
|
|
429
|
+
const max_en = Math.max(...unique_elements.map((el) => element_lookup.get(el)?.electronegativity ?? -Infinity));
|
|
430
|
+
const has_framework_potential = unique_elements.some((el) => {
|
|
431
|
+
if (is_spectator_center(el))
|
|
432
|
+
return false;
|
|
433
|
+
const en = element_lookup.get(el)?.electronegativity;
|
|
434
|
+
return en !== null && en !== undefined && en < max_en;
|
|
435
|
+
});
|
|
436
|
+
// Weakly-bound center species (mean bond length well beyond the covalent-radii
|
|
437
|
+
// sum, e.g. lone-pair Bi3+ with 8 long Bi-O bonds) are hidden when a
|
|
438
|
+
// strongly-bound framework species exists - mirrors how pyrochlore-type figures
|
|
439
|
+
// show only the B-site octahedra
|
|
440
|
+
const norm_by_species = new Map();
|
|
441
|
+
for (const { element, mean_norm_dist } of candidates) {
|
|
442
|
+
if (mean_norm_dist === null)
|
|
443
|
+
continue;
|
|
444
|
+
const entry = norm_by_species.get(element) ?? { sum: 0, count: 0 };
|
|
445
|
+
entry.sum += mean_norm_dist;
|
|
446
|
+
entry.count++;
|
|
447
|
+
norm_by_species.set(element, entry);
|
|
448
|
+
}
|
|
449
|
+
const species_norm = (el) => {
|
|
450
|
+
const entry = norm_by_species.get(el);
|
|
451
|
+
return entry ? entry.sum / entry.count : null;
|
|
452
|
+
};
|
|
453
|
+
const has_strong_species = [...norm_by_species.keys()].some((el) => (species_norm(el) ?? Infinity) <= weak_bond_norm && !is_spectator_center(el));
|
|
454
|
+
const is_weak_species = (el) => has_strong_species && (species_norm(el) ?? 0) > weak_bond_norm;
|
|
455
|
+
const visible = candidates.filter(({ element }) => {
|
|
456
|
+
if (included.has(element))
|
|
457
|
+
return true;
|
|
458
|
+
if (is_spectator_center(element) && has_framework_potential)
|
|
459
|
+
return false;
|
|
460
|
+
return !is_weak_species(element);
|
|
461
|
+
});
|
|
462
|
+
// Pass 3: boundary completeness - copies of the same original site only render
|
|
463
|
+
// at the max observed vertex count, so any remaining truncated copies (bond
|
|
464
|
+
// completing image atoms handle most) are skipped
|
|
465
|
+
const max_cn_by_orig = new Map();
|
|
466
|
+
for (const { orig_idx, vertex_site_idxs } of visible) {
|
|
467
|
+
if (vertex_site_idxs.length > (max_cn_by_orig.get(orig_idx) ?? 0)) {
|
|
468
|
+
max_cn_by_orig.set(orig_idx, vertex_site_idxs.length);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
// Pass 4: CN cap (after completeness so capped interior copies don't let
|
|
472
|
+
// truncated boundary copies of the same site slip through; force-included
|
|
473
|
+
// elements bypass the cap - an explicit user request beats the clutter
|
|
474
|
+
// heuristic), then build hulls, deduping identical center positions (base
|
|
475
|
+
// atom vs PBC image)
|
|
476
|
+
const polyhedra = [];
|
|
477
|
+
const seen_positions = new Set();
|
|
478
|
+
for (const { site_idx, orig_idx, element, vertex_site_idxs } of visible) {
|
|
479
|
+
if (vertex_site_idxs.length !== max_cn_by_orig.get(orig_idx))
|
|
480
|
+
continue;
|
|
481
|
+
if (vertex_site_idxs.length > max_neighbors && !included.has(element))
|
|
482
|
+
continue;
|
|
483
|
+
const [px, py, pz] = sites[site_idx].xyz;
|
|
484
|
+
const pos_key = `${Math.round(px * 1e3)},${Math.round(py * 1e3)},${Math.round(pz * 1e3)}`;
|
|
485
|
+
if (seen_positions.has(pos_key))
|
|
486
|
+
continue;
|
|
487
|
+
seen_positions.add(pos_key);
|
|
488
|
+
const hull = convex_hull_3d(vertex_site_idxs.map((idx) => sites[idx].xyz));
|
|
489
|
+
if (hull.faces.length === 0 || hull.volume < volume_eps)
|
|
490
|
+
continue;
|
|
491
|
+
polyhedra.push({
|
|
492
|
+
center_site_idx: site_idx,
|
|
493
|
+
center_orig_idx: orig_idx,
|
|
494
|
+
center_element: element,
|
|
495
|
+
vertices: hull.vertices,
|
|
496
|
+
vertex_site_idxs: hull.input_idxs.map((input_idx) => vertex_site_idxs[input_idx]),
|
|
497
|
+
faces: hull.faces,
|
|
498
|
+
volume: hull.volume,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
return polyhedra;
|
|
502
|
+
}
|
|
503
|
+
// --- Merged render buffers ---
|
|
504
|
+
// Merge all polyhedra into single non-indexed position/color arrays (one draw call)
|
|
505
|
+
// plus crease-edge segments for outlines. Edges interior to coplanar face groups
|
|
506
|
+
// (e.g. quad diagonals on a cube) are omitted. `get_vertex_color` resolves the
|
|
507
|
+
// color of each hull vertex (e.g. the vertex atom's element color, the center
|
|
508
|
+
// atom's color, or a uniform custom color) - parsed colors are cached by string.
|
|
509
|
+
export function merge_polyhedra_buffers(polyhedra, get_vertex_color, coplanar_tol = 1e-3) {
|
|
510
|
+
let triangle_count = 0;
|
|
511
|
+
for (const poly of polyhedra)
|
|
512
|
+
triangle_count += poly.faces.length;
|
|
513
|
+
const positions = new Float32Array(triangle_count * 9);
|
|
514
|
+
const colors = new Float32Array(triangle_count * 9);
|
|
515
|
+
// A closed triangulated surface has at most 3F/2 unique edges
|
|
516
|
+
const edge_positions = new Float32Array(Math.ceil(triangle_count * 1.5) * 6);
|
|
517
|
+
const rgb_cache = new Map();
|
|
518
|
+
let offset = 0;
|
|
519
|
+
let edge_offset = 0;
|
|
520
|
+
// Per-polyhedron scratch: crease detection tracks the first face normal seen
|
|
521
|
+
// per undirected edge (packed vert_a * 2^16 + vert_b key)
|
|
522
|
+
const edge_normals = new Map();
|
|
523
|
+
for (const poly of polyhedra) {
|
|
524
|
+
const verts = poly.vertices;
|
|
525
|
+
// Resolve per-hull-vertex colors once
|
|
526
|
+
const vert_rgb = new Float32Array(verts.length * 3);
|
|
527
|
+
for (let v_idx = 0; v_idx < verts.length; v_idx++) {
|
|
528
|
+
const color = get_vertex_color(poly, v_idx);
|
|
529
|
+
let channels = rgb_cache.get(color);
|
|
530
|
+
if (!channels) {
|
|
531
|
+
// d3-color handles hex, rgb()/rgba() (d3 property-color scales) and named colors
|
|
532
|
+
const { r, g, b } = parse_rgb(color);
|
|
533
|
+
channels = Number.isFinite(r) ? [r / 255, g / 255, b / 255] : [0.5, 0.5, 0.5];
|
|
534
|
+
rgb_cache.set(color, channels);
|
|
535
|
+
}
|
|
536
|
+
vert_rgb[v_idx * 3] = channels[0];
|
|
537
|
+
vert_rgb[v_idx * 3 + 1] = channels[1];
|
|
538
|
+
vert_rgb[v_idx * 3 + 2] = channels[2];
|
|
539
|
+
}
|
|
540
|
+
edge_normals.clear();
|
|
541
|
+
for (const [idx_a, idx_b, idx_c] of poly.faces) {
|
|
542
|
+
const [ax, ay, az] = verts[idx_a];
|
|
543
|
+
const [bx, by, bz] = verts[idx_b];
|
|
544
|
+
const [px, py, pz] = verts[idx_c];
|
|
545
|
+
// Scalar face normal for crease detection
|
|
546
|
+
let nx = (by - ay) * (pz - az) - (bz - az) * (py - ay);
|
|
547
|
+
let ny = (bz - az) * (px - ax) - (bx - ax) * (pz - az);
|
|
548
|
+
let nz = (bx - ax) * (py - ay) - (by - ay) * (px - ax);
|
|
549
|
+
const len = Math.hypot(nx, ny, nz);
|
|
550
|
+
if (len > 0) {
|
|
551
|
+
nx /= len;
|
|
552
|
+
ny /= len;
|
|
553
|
+
nz /= len;
|
|
554
|
+
}
|
|
555
|
+
for (const v_idx of [idx_a, idx_b, idx_c]) {
|
|
556
|
+
const vert = verts[v_idx];
|
|
557
|
+
positions[offset] = vert[0];
|
|
558
|
+
positions[offset + 1] = vert[1];
|
|
559
|
+
positions[offset + 2] = vert[2];
|
|
560
|
+
colors[offset] = vert_rgb[v_idx * 3];
|
|
561
|
+
colors[offset + 1] = vert_rgb[v_idx * 3 + 1];
|
|
562
|
+
colors[offset + 2] = vert_rgb[v_idx * 3 + 2];
|
|
563
|
+
offset += 3;
|
|
564
|
+
}
|
|
565
|
+
for (const [from, to] of [
|
|
566
|
+
[idx_a, idx_b],
|
|
567
|
+
[idx_b, idx_c],
|
|
568
|
+
[idx_c, idx_a],
|
|
569
|
+
]) {
|
|
570
|
+
const key = from < to ? from * 65536 + to : to * 65536 + from;
|
|
571
|
+
const entry = edge_normals.get(key);
|
|
572
|
+
if (entry) {
|
|
573
|
+
entry.shared = true;
|
|
574
|
+
entry.crease = nx * entry.nx + ny * entry.ny + nz * entry.nz < 1 - coplanar_tol;
|
|
575
|
+
}
|
|
576
|
+
else
|
|
577
|
+
edge_normals.set(key, { nx, ny, nz, crease: false, shared: false });
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
// Draw an edge unless both adjacent faces are coplanar (quad diagonal)
|
|
581
|
+
for (const [key, entry] of edge_normals) {
|
|
582
|
+
if (entry.shared && !entry.crease)
|
|
583
|
+
continue;
|
|
584
|
+
const from = verts[Math.floor(key / 65536)];
|
|
585
|
+
const to = verts[key % 65536];
|
|
586
|
+
edge_positions[edge_offset] = from[0];
|
|
587
|
+
edge_positions[edge_offset + 1] = from[1];
|
|
588
|
+
edge_positions[edge_offset + 2] = from[2];
|
|
589
|
+
edge_positions[edge_offset + 3] = to[0];
|
|
590
|
+
edge_positions[edge_offset + 4] = to[1];
|
|
591
|
+
edge_positions[edge_offset + 5] = to[2];
|
|
592
|
+
edge_offset += 6;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return {
|
|
596
|
+
positions,
|
|
597
|
+
colors,
|
|
598
|
+
edge_positions: edge_positions.slice(0, edge_offset),
|
|
599
|
+
triangle_count,
|
|
600
|
+
edge_count: edge_offset / 6,
|
|
601
|
+
};
|
|
602
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ElementSymbol } from '../element';
|
|
2
|
+
import type { Vec3 } from '../math';
|
|
3
|
+
import type { Site } from './';
|
|
4
|
+
export declare const make_site: (element: ElementSymbol, abc: Vec3, xyz: Vec3, label: string, properties?: Record<string, unknown>, occu?: number) => Site;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const make_site = (element, abc, xyz, label, properties = {}, occu = 1) => ({ species: [{ element, occu, oxidation_state: 0 }], abc, xyz, label, properties });
|
|
@@ -115,7 +115,8 @@ export function make_supercell(structure, scaling, to_unit_cell = true) {
|
|
|
115
115
|
for (let kk = 0; kk < scale_z; kk++) {
|
|
116
116
|
for (let jj = 0; jj < scale_y; jj++) {
|
|
117
117
|
for (let ii = 0; ii < scale_x; ii++) {
|
|
118
|
-
|
|
118
|
+
// 1x1x1 short-circuits above, so every site gets a cell-index suffix
|
|
119
|
+
const label_suffix = `_${ii}${jj}${kk}`;
|
|
119
120
|
// Translation = ii * vec_a + jj * vec_b + kk * vec_c (inlined for performance)
|
|
120
121
|
const tx = ii * ax + jj * bx + kk * cx;
|
|
121
122
|
const ty = ii * ay + jj * by + kk * cy;
|
|
@@ -135,7 +136,7 @@ export function make_supercell(structure, scaling, to_unit_cell = true) {
|
|
|
135
136
|
species: site.species,
|
|
136
137
|
xyz: [site.xyz[0] + tx, site.xyz[1] + ty, site.xyz[2] + tz],
|
|
137
138
|
abc: [new_a, new_b, new_c],
|
|
138
|
-
label:
|
|
139
|
+
label: `${site.label}${label_suffix}`,
|
|
139
140
|
properties: { ...site.properties, orig_unit_cell_idx: site_idx },
|
|
140
141
|
};
|
|
141
142
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
import { is_plain_object } from '../utils';
|
|
1
2
|
export function is_crystal(obj) {
|
|
2
|
-
if (obj
|
|
3
|
+
if (!is_plain_object(obj))
|
|
3
4
|
return false;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const has_sites = Array.isArray(sites) && sites.length > 0;
|
|
8
|
-
const has_lattice = lattice !== undefined && lattice !== null && typeof lattice === `object`;
|
|
5
|
+
const has_sites = Array.isArray(obj.sites) && obj.sites.length > 0;
|
|
6
|
+
// lattice may be an object or (in some raw formats) a 3x3 array, so only reject nullish
|
|
7
|
+
const has_lattice = obj.lattice !== undefined && obj.lattice !== null && typeof obj.lattice === `object`;
|
|
9
8
|
return has_sites && has_lattice;
|
|
10
9
|
}
|