matterviz 0.4.2 → 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/FilePicker.svelte +40 -50
- package/dist/api/optimade.js +10 -7
- package/dist/app.css +15 -0
- package/dist/brillouin/BrillouinZone.svelte +18 -9
- package/dist/brillouin/BrillouinZoneScene.svelte +20 -29
- package/dist/brillouin/compute.js +10 -16
- package/dist/brillouin/geometry.js +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte +18 -15
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +17 -113
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +104 -264
- package/dist/chempot-diagram/async-compute.svelte.js +12 -13
- 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/export.js +1 -6
- package/dist/chempot-diagram/temperature.js +9 -10
- package/dist/composition/BarChart.svelte +7 -9
- package/dist/composition/Composition.svelte +3 -8
- package/dist/composition/Formula.svelte +2 -2
- package/dist/composition/FormulaFilter.svelte +27 -93
- package/dist/composition/format.js +6 -8
- package/dist/composition/parse.js +50 -105
- package/dist/constants.d.ts +0 -1
- package/dist/constants.js +6 -17
- package/dist/convex-hull/ConvexHull2D.svelte +0 -2
- package/dist/convex-hull/ConvexHull3D.svelte +19 -47
- package/dist/convex-hull/ConvexHull4D.svelte +65 -95
- package/dist/convex-hull/StructurePopup.svelte +1 -1
- package/dist/convex-hull/gas-thermodynamics.js +21 -53
- package/dist/convex-hull/helpers.js +1 -7
- package/dist/convex-hull/thermodynamics.js +19 -27
- package/dist/coordination/CoordinationBarPlot.svelte +12 -21
- package/dist/element/BohrAtom.svelte +0 -1
- package/dist/element/ElementTile.svelte +26 -44
- package/dist/element/data.d.ts +2 -0
- package/dist/element/data.js +5 -1
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +1 -1
- package/dist/fermi-surface/FermiSurface.svelte +22 -23
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +2 -6
- package/dist/fermi-surface/FermiSurfaceScene.svelte +32 -77
- package/dist/fermi-surface/compute.js +22 -55
- package/dist/fermi-surface/parse.js +38 -70
- 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 +57 -84
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/io/ExportPane.svelte +1 -1
- package/dist/io/decompress.d.ts +2 -0
- package/dist/io/decompress.js +3 -2
- package/dist/io/export.d.ts +7 -4
- package/dist/io/export.js +70 -18
- package/dist/io/file-drop.js +60 -35
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +28 -16
- package/dist/isosurface/Isosurface.svelte +687 -196
- package/dist/isosurface/Isosurface.svelte.d.ts +7 -1
- package/dist/isosurface/IsosurfaceControls.svelte +564 -85
- 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/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.js +1 -1
- package/dist/layout/InfoCard.svelte +1 -3
- package/dist/layout/SettingsSection.svelte +52 -61
- package/dist/layout/SettingsSection.svelte.d.ts +6 -7
- package/dist/layout/ViewerChrome.svelte +7 -1
- package/dist/layout/json-tree/JsonNode.svelte +14 -48
- package/dist/layout/json-tree/JsonTree.svelte +48 -95
- package/dist/layout/json-tree/JsonValue.svelte +3 -18
- package/dist/layout/json-tree/utils.d.ts +0 -3
- package/dist/layout/json-tree/utils.js +50 -179
- package/dist/marching-cubes.d.ts +8 -1
- package/dist/marching-cubes.js +115 -48
- package/dist/math.d.ts +3 -2
- package/dist/math.js +29 -38
- package/dist/overlays/ContextMenu.svelte +15 -32
- package/dist/overlays/DraggablePane.svelte +39 -58
- package/dist/overlays/DraggablePane.svelte.d.ts +1 -1
- package/dist/overlays/GlassChip.svelte +3 -1
- package/dist/periodic-table/PeriodicTableControls.svelte +26 -52
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +18 -34
- package/dist/phase-diagram/build-diagram.js +1 -6
- package/dist/phase-diagram/svg-to-diagram.js +9 -14
- package/dist/plot/bar/BarPlot.svelte +38 -42
- package/dist/plot/bar/SpacegroupBarPlot.svelte +18 -42
- package/dist/plot/box/BoxPlot.svelte +27 -23
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +1 -1
- package/dist/plot/core/data-transform.d.ts +1 -2
- package/dist/plot/core/data-transform.js +0 -10
- package/dist/plot/core/layout.d.ts +12 -5
- package/dist/plot/core/layout.js +37 -27
- 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/svg.js +0 -1
- package/dist/plot/core/utils/hierarchy-chart.d.ts +1 -0
- package/dist/plot/core/utils/hierarchy-chart.js +12 -0
- package/dist/plot/core/utils/hierarchy-labels.js +3 -2
- package/dist/plot/histogram/Histogram.svelte +21 -26
- package/dist/plot/sankey/sankey.js +13 -9
- package/dist/plot/scatter/BinnedScatterPlot.svelte +59 -43
- package/dist/plot/scatter/ScatterPlot.svelte +67 -52
- package/dist/plot/scatter/adaptive-density.d.ts +1 -1
- package/dist/plot/scatter/adaptive-density.js +36 -20
- package/dist/plot/sunburst/Sunburst.svelte +20 -20
- package/dist/plot/treemap/Treemap.svelte +175 -60
- package/dist/plot/treemap/Treemap.svelte.d.ts +6 -0
- package/dist/plot/treemap/index.d.ts +1 -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 +4 -2
- package/dist/plot/treemap/treemap.js +5 -2
- package/dist/rdf/RdfPlot.svelte +17 -35
- package/dist/rdf/calc-rdf.js +59 -44
- package/dist/rdf/index.d.ts +0 -1
- package/dist/sanitize.js +84 -26
- package/dist/scene/SceneCamera.svelte +1 -1
- package/dist/scene/SceneCamera.svelte.d.ts +1 -1
- 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.js +159 -482
- package/dist/spectral/Bands.svelte +151 -158
- package/dist/spectral/BrillouinBandsDos.svelte +4 -19
- package/dist/spectral/Dos.svelte +26 -24
- package/dist/spectral/helpers.js +40 -105
- package/dist/structure/AtomLegend.svelte +8 -13
- package/dist/structure/AtomLegend.svelte.d.ts +2 -3
- package/dist/structure/CellSelect.svelte +35 -10
- package/dist/structure/Structure.svelte +177 -99
- package/dist/structure/Structure.svelte.d.ts +1 -1
- package/dist/structure/StructureCarousel.svelte +10 -3
- package/dist/structure/StructureControls.svelte +8 -26
- package/dist/structure/StructureControls.svelte.d.ts +1 -1
- package/dist/structure/StructureInfoPane.svelte +65 -76
- package/dist/structure/StructureScene.svelte +75 -109
- package/dist/structure/StructureScene.svelte.d.ts +3 -1
- package/dist/structure/StructureViewport.svelte +120 -55
- package/dist/structure/StructureViewport.svelte.d.ts +3 -1
- package/dist/structure/atom-properties.d.ts +1 -1
- package/dist/structure/atom-properties.js +4 -3
- package/dist/structure/bond-order-perception.js +3 -8
- package/dist/structure/bonding.d.ts +0 -1
- package/dist/structure/bonding.js +16 -23
- package/dist/structure/export.js +50 -74
- package/dist/structure/format-detect.js +5 -7
- package/dist/structure/index.js +6 -12
- package/dist/structure/parse.js +38 -100
- package/dist/structure/partial-occupancy.js +7 -4
- package/dist/structure/pbc.js +8 -10
- package/dist/structure/polyhedra.js +5 -4
- package/dist/structure/prop-groups.d.ts +85 -0
- package/dist/structure/prop-groups.js +18 -0
- package/dist/symmetry/SymmetryStats.svelte +0 -4
- package/dist/symmetry/WyckoffTable.svelte +5 -4
- package/dist/symmetry/cell-transform.js +5 -14
- package/dist/symmetry/index.js +6 -9
- package/dist/table/HeatmapTable.svelte +61 -103
- package/dist/table/ToggleMenu.svelte +166 -44
- package/dist/table/ToggleMenu.svelte.d.ts +1 -1
- package/dist/theme/embedded.d.ts +18 -0
- package/dist/theme/embedded.js +206 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/index.js +1 -2
- package/dist/theme/themes.mjs +31 -60
- package/dist/tooltip/TooltipContent.svelte +1 -1
- package/dist/tooltip/TooltipContent.svelte.d.ts +1 -1
- package/dist/tooltip/index.d.ts +8 -1
- package/dist/trajectory/Trajectory.svelte +140 -120
- package/dist/trajectory/TrajectoryError.svelte +1 -66
- package/dist/trajectory/TrajectoryExportPane.svelte +0 -1
- package/dist/trajectory/TrajectoryInfoPane.svelte +55 -80
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +2 -1
- package/dist/trajectory/extract.js +19 -29
- package/dist/trajectory/format-detect.d.ts +2 -0
- package/dist/trajectory/format-detect.js +7 -5
- package/dist/trajectory/frame-reader.js +3 -4
- package/dist/trajectory/helpers.js +16 -49
- package/dist/trajectory/index.js +2 -8
- package/dist/trajectory/parse/ase.js +1 -1
- package/dist/trajectory/parse/index.d.ts +4 -3
- package/dist/trajectory/parse/index.js +12 -17
- package/dist/trajectory/parse/vaspout-h5.d.ts +0 -1
- package/dist/trajectory/parse/vaspout-h5.js +1 -4
- package/dist/trajectory/parse/xyz.js +48 -2
- package/dist/trajectory/plotting.js +14 -37
- package/dist/xrd/XrdPlot.svelte +43 -68
- package/dist/xrd/calc-xrd.js +22 -58
- package/dist/xrd/parse.js +13 -22
- package/package.json +40 -8
- package/readme.md +6 -5
- 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,5 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
1
|
+
// JSON Tree utility functions
|
|
2
|
+
import { build_path, format_path, parse_path } from '../../json-path';
|
|
3
3
|
// Circular-safe JSON.stringify helper (hoisted for reuse)
|
|
4
4
|
function safe_stringify(val) {
|
|
5
5
|
const seen = new WeakSet();
|
|
@@ -26,34 +26,22 @@ export function get_value_type(value) {
|
|
|
26
26
|
if (value === undefined)
|
|
27
27
|
return `undefined`;
|
|
28
28
|
const type = typeof value;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return `date`;
|
|
46
|
-
if (value instanceof RegExp)
|
|
47
|
-
return `regexp`;
|
|
48
|
-
if (value instanceof Map)
|
|
49
|
-
return `map`;
|
|
50
|
-
if (value instanceof Set)
|
|
51
|
-
return `set`;
|
|
52
|
-
if (value instanceof Error)
|
|
53
|
-
return `error`;
|
|
54
|
-
return `object`;
|
|
55
|
-
}
|
|
56
|
-
return `object`; // fallback
|
|
29
|
+
// string/number/boolean/symbol/bigint/function map directly to JsonValueType
|
|
30
|
+
if (type !== `object`)
|
|
31
|
+
return type;
|
|
32
|
+
if (Array.isArray(value))
|
|
33
|
+
return `array`;
|
|
34
|
+
if (value instanceof Date)
|
|
35
|
+
return `date`;
|
|
36
|
+
if (value instanceof RegExp)
|
|
37
|
+
return `regexp`;
|
|
38
|
+
if (value instanceof Map)
|
|
39
|
+
return `map`;
|
|
40
|
+
if (value instanceof Set)
|
|
41
|
+
return `set`;
|
|
42
|
+
if (value instanceof Error)
|
|
43
|
+
return `error`;
|
|
44
|
+
return `object`;
|
|
57
45
|
}
|
|
58
46
|
// Check if a value type is expandable (has children)
|
|
59
47
|
export const is_expandable_type = (value_type) => value_type === `object` ||
|
|
@@ -82,40 +70,6 @@ export function get_child_count(value) {
|
|
|
82
70
|
return value.size;
|
|
83
71
|
return 0;
|
|
84
72
|
}
|
|
85
|
-
// Format a path segment for display
|
|
86
|
-
// Handles both string keys and numeric indices
|
|
87
|
-
// is_first: true for the first segment (no leading dot for valid identifiers)
|
|
88
|
-
function format_path_segment(segment, is_first = false) {
|
|
89
|
-
if (typeof segment === `number`) {
|
|
90
|
-
return `[${segment}]`;
|
|
91
|
-
}
|
|
92
|
-
// Check if the key is a valid identifier (can use dot notation)
|
|
93
|
-
if (VALID_IDENTIFIER_RE.test(segment)) {
|
|
94
|
-
return is_first ? segment : `.${segment}`;
|
|
95
|
-
}
|
|
96
|
-
// Use bracket notation for keys with special characters
|
|
97
|
-
return `["${segment.replaceAll('"', `\\"`)}"]`;
|
|
98
|
-
}
|
|
99
|
-
// Format a full path from segments
|
|
100
|
-
// e.g., ["users", 0, "name"] -> "users[0].name"
|
|
101
|
-
// e.g., [0, "name"] -> "[0].name" (root numeric index)
|
|
102
|
-
// e.g., ["key.with.dot"] -> '["key.with.dot"]' (root special key)
|
|
103
|
-
export function format_path(segments) {
|
|
104
|
-
if (segments.length === 0)
|
|
105
|
-
return ``;
|
|
106
|
-
let result = format_path_segment(segments[0], true);
|
|
107
|
-
for (let idx = 1; idx < segments.length; idx++) {
|
|
108
|
-
result += format_path_segment(segments[idx]);
|
|
109
|
-
}
|
|
110
|
-
return result;
|
|
111
|
-
}
|
|
112
|
-
// Build a path string from parent path and key
|
|
113
|
-
export function build_path(parent_path, key) {
|
|
114
|
-
if (!parent_path) {
|
|
115
|
-
return format_path_segment(key, true);
|
|
116
|
-
}
|
|
117
|
-
return parent_path + format_path_segment(key);
|
|
118
|
-
}
|
|
119
73
|
// Format a primitive/special value to string (shared by serialize and preview)
|
|
120
74
|
function format_special_value(value, type) {
|
|
121
75
|
if (type === `undefined`)
|
|
@@ -190,18 +144,13 @@ export function matches_search(path, key, value, query) {
|
|
|
190
144
|
if (!query)
|
|
191
145
|
return false;
|
|
192
146
|
const lower_query = query.toLowerCase();
|
|
193
|
-
// Check path
|
|
194
147
|
if (path.toLowerCase().includes(lower_query))
|
|
195
148
|
return true;
|
|
196
|
-
// Check key
|
|
197
149
|
if (key !== null && String(key).toLowerCase().includes(lower_query))
|
|
198
150
|
return true;
|
|
199
|
-
// Check value (
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
return String(value).toLowerCase().includes(lower_query);
|
|
203
|
-
}
|
|
204
|
-
return false;
|
|
151
|
+
// Check value (only primitives are searchable as strings)
|
|
152
|
+
return (is_primitive_type(get_value_type(value)) &&
|
|
153
|
+
String(value).toLowerCase().includes(lower_query));
|
|
205
154
|
}
|
|
206
155
|
// Iterate over children of an expandable value, calling visitor for each
|
|
207
156
|
function for_each_child(value, type, visitor) {
|
|
@@ -291,89 +240,31 @@ export function get_ancestor_paths(path) {
|
|
|
291
240
|
}
|
|
292
241
|
return ancestors;
|
|
293
242
|
}
|
|
294
|
-
// Parse a path string into segments
|
|
295
|
-
// e.g., "users[0].name" -> ["users", 0, "name"]
|
|
296
|
-
export function parse_path(path) {
|
|
297
|
-
if (!path)
|
|
298
|
-
return [];
|
|
299
|
-
const segments = [];
|
|
300
|
-
let current = ``;
|
|
301
|
-
let in_bracket = false;
|
|
302
|
-
// Bracket tokens are numeric indices or quoted keys (quotes stripped, \" unescaped)
|
|
303
|
-
const push_bracket_token = (token) => {
|
|
304
|
-
const num = Number(token);
|
|
305
|
-
if (Number.isNaN(num)) {
|
|
306
|
-
segments.push(token.replaceAll(/^"|"$/g, ``).replaceAll(String.raw `\"`, `"`));
|
|
307
|
-
}
|
|
308
|
-
else
|
|
309
|
-
segments.push(num);
|
|
310
|
-
};
|
|
311
|
-
for (const char of path) {
|
|
312
|
-
if (char === `.` && !in_bracket) {
|
|
313
|
-
if (current)
|
|
314
|
-
segments.push(current);
|
|
315
|
-
current = ``;
|
|
316
|
-
}
|
|
317
|
-
else if (char === `[`) {
|
|
318
|
-
if (current)
|
|
319
|
-
segments.push(current);
|
|
320
|
-
current = ``;
|
|
321
|
-
in_bracket = true;
|
|
322
|
-
}
|
|
323
|
-
else if (char === `]`) {
|
|
324
|
-
if (current)
|
|
325
|
-
push_bracket_token(current);
|
|
326
|
-
current = ``;
|
|
327
|
-
in_bracket = false;
|
|
328
|
-
}
|
|
329
|
-
else
|
|
330
|
-
current += char;
|
|
331
|
-
}
|
|
332
|
-
// Handle trailing content (e.g., unclosed bracket like "a[0")
|
|
333
|
-
if (current) {
|
|
334
|
-
if (in_bracket)
|
|
335
|
-
push_bracket_token(current);
|
|
336
|
-
else
|
|
337
|
-
segments.push(current);
|
|
338
|
-
}
|
|
339
|
-
return segments;
|
|
340
|
-
}
|
|
341
243
|
// Check if two values are deeply equal (for change detection)
|
|
342
244
|
export function values_equal(val_a, val_b) {
|
|
343
245
|
if (val_a === val_b)
|
|
344
246
|
return true;
|
|
345
|
-
//
|
|
346
|
-
if (typeof val_a === `number` &&
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
return true;
|
|
351
|
-
if (val_a === null || val_b === null)
|
|
352
|
-
return false;
|
|
353
|
-
if (typeof val_a !== typeof val_b)
|
|
247
|
+
// NaN !== NaN in JS, but we want NaN === NaN for change detection
|
|
248
|
+
if (typeof val_a === `number` && typeof val_b === `number`) {
|
|
249
|
+
return Number.isNaN(val_a) && Number.isNaN(val_b);
|
|
250
|
+
}
|
|
251
|
+
if (val_a === null || val_b === null || typeof val_a !== typeof val_b)
|
|
354
252
|
return false;
|
|
355
253
|
const type = get_value_type(val_a);
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if (type === `date`) {
|
|
254
|
+
if (type !== get_value_type(val_b))
|
|
255
|
+
return false;
|
|
256
|
+
if (is_primitive_type(type) || type === `symbol`)
|
|
257
|
+
return false; // strict equality failed above
|
|
258
|
+
if (type === `date`)
|
|
362
259
|
return val_a.getTime() === val_b.getTime();
|
|
363
|
-
|
|
364
|
-
// For regex, compare string representation
|
|
365
|
-
if (type === `regexp`) {
|
|
260
|
+
if (type === `regexp`)
|
|
366
261
|
return val_a.toString() === val_b.toString();
|
|
367
|
-
|
|
368
|
-
//
|
|
369
|
-
|
|
370
|
-
if (type === `array`) {
|
|
262
|
+
// Objects and arrays use shallow size comparison for performance —
|
|
263
|
+
// deep changes are detected at the child level
|
|
264
|
+
if (type === `array`)
|
|
371
265
|
return val_a.length === val_b.length;
|
|
372
|
-
}
|
|
373
266
|
if (type === `object`) {
|
|
374
|
-
|
|
375
|
-
const keys_b = Object.keys(val_b);
|
|
376
|
-
return keys_a.length === keys_b.length;
|
|
267
|
+
return Object.keys(val_a).length === Object.keys(val_b).length;
|
|
377
268
|
}
|
|
378
269
|
return false;
|
|
379
270
|
}
|
|
@@ -513,42 +404,27 @@ export function format_byte_size(bytes) {
|
|
|
513
404
|
export function compute_diff(old_val, new_val, current_path = ``, result = new Map(), seen = new WeakSet()) {
|
|
514
405
|
const old_type = get_value_type(old_val);
|
|
515
406
|
const new_type = get_value_type(new_val);
|
|
407
|
+
const mark_changed = () => result.set(current_path, {
|
|
408
|
+
status: `changed`,
|
|
409
|
+
path: current_path,
|
|
410
|
+
old_value: old_val,
|
|
411
|
+
new_value: new_val,
|
|
412
|
+
});
|
|
516
413
|
// Different types = changed
|
|
517
414
|
if (old_type !== new_type) {
|
|
518
|
-
|
|
519
|
-
status: `changed`,
|
|
520
|
-
path: current_path,
|
|
521
|
-
old_value: old_val,
|
|
522
|
-
new_value: new_val,
|
|
523
|
-
});
|
|
415
|
+
mark_changed();
|
|
524
416
|
return result;
|
|
525
417
|
}
|
|
526
|
-
// Both primitive: compare values (
|
|
418
|
+
// Both primitive: compare values (values_equal treats NaN === NaN)
|
|
527
419
|
if (is_primitive_type(old_type)) {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
Number.isNaN(old_val) &&
|
|
531
|
-
Number.isNaN(new_val);
|
|
532
|
-
if (!both_nan && old_val !== new_val) {
|
|
533
|
-
result.set(current_path, {
|
|
534
|
-
status: `changed`,
|
|
535
|
-
path: current_path,
|
|
536
|
-
old_value: old_val,
|
|
537
|
-
new_value: new_val,
|
|
538
|
-
});
|
|
539
|
-
}
|
|
420
|
+
if (!values_equal(old_val, new_val))
|
|
421
|
+
mark_changed();
|
|
540
422
|
return result;
|
|
541
423
|
}
|
|
542
424
|
// Non-expandable special types (date, regexp, etc): compare string forms
|
|
543
425
|
if (!is_expandable_type(old_type)) {
|
|
544
|
-
if (String(old_val) !== String(new_val))
|
|
545
|
-
|
|
546
|
-
status: `changed`,
|
|
547
|
-
path: current_path,
|
|
548
|
-
old_value: old_val,
|
|
549
|
-
new_value: new_val,
|
|
550
|
-
});
|
|
551
|
-
}
|
|
426
|
+
if (String(old_val) !== String(new_val))
|
|
427
|
+
mark_changed();
|
|
552
428
|
return result;
|
|
553
429
|
}
|
|
554
430
|
// Prevent circular references
|
|
@@ -616,13 +492,8 @@ export function compute_diff(old_val, new_val, current_path = ``, result = new M
|
|
|
616
492
|
}
|
|
617
493
|
// Maps: wrap entries as { key, value } to match JsonNode.get_children() rendering
|
|
618
494
|
if (old_type === `map`) {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
value: val,
|
|
622
|
-
})), Array.from(new_val.entries()).map(([key, val]) => ({
|
|
623
|
-
key,
|
|
624
|
-
value: val,
|
|
625
|
-
})));
|
|
495
|
+
const wrap_entries = (map) => Array.from(map, ([key, value]) => ({ key, value }));
|
|
496
|
+
diff_indexed(wrap_entries(old_val), wrap_entries(new_val));
|
|
626
497
|
return result;
|
|
627
498
|
}
|
|
628
499
|
if (old_type === `set`) {
|
package/dist/marching-cubes.d.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Matrix3x3, type Vec3 } from './math';
|
|
2
2
|
export interface MarchingCubesResult {
|
|
3
3
|
vertices: Vec3[];
|
|
4
4
|
faces: number[][];
|
|
5
5
|
normals: Vec3[];
|
|
6
6
|
}
|
|
7
|
+
export interface MarchingCubesBuffers {
|
|
8
|
+
positions: Float32Array;
|
|
9
|
+
indices: Uint32Array;
|
|
10
|
+
normals: Float32Array;
|
|
11
|
+
}
|
|
7
12
|
export interface MarchingCubesOptions {
|
|
8
13
|
periodic?: boolean;
|
|
9
14
|
interpolate?: boolean;
|
|
10
15
|
centered?: boolean;
|
|
11
16
|
normals?: boolean;
|
|
17
|
+
position_offset?: Vec3;
|
|
12
18
|
}
|
|
19
|
+
export declare function marching_cubes_buffers(grid: number[][][], iso_value: number, k_lattice: Matrix3x3, options?: MarchingCubesOptions): MarchingCubesBuffers;
|
|
13
20
|
export declare function marching_cubes(grid: number[][][], iso_value: number, k_lattice: Matrix3x3, options?: MarchingCubesOptions): MarchingCubesResult;
|
|
14
21
|
export declare function compute_vertex_normals(vertices: Vec3[], faces: number[][]): Vec3[];
|
package/dist/marching-cubes.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Marching Cubes algorithm for isosurface extraction
|
|
2
|
+
// Based on the classic algorithm by Lorensen & Cline (1987)
|
|
3
|
+
import { mat3x3_vec3_multiply, matrix_inverse_3x3 } from './math';
|
|
1
4
|
const wrap_grid_idx = (val, dim) => ((val % dim) + dim) % dim;
|
|
2
5
|
const clamp_grid_idx = (val, max) => Math.max(0, Math.min(val, max));
|
|
3
6
|
// Edge table: for each cube configuration (256 cases), which edges are intersected
|
|
@@ -311,18 +314,18 @@ function compute_gradient(grid, ix, iy, iz, nx, ny, nz, periodic) {
|
|
|
311
314
|
const [iz_m, iz_p] = periodic
|
|
312
315
|
? [wrap_grid_idx(iz - 1, nz), wrap_grid_idx(iz + 1, nz)]
|
|
313
316
|
: [Math.max(0, iz - 1), Math.min(nz - 1, iz + 1)];
|
|
314
|
-
const
|
|
315
|
-
const
|
|
316
|
-
const
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const
|
|
321
|
-
return [-
|
|
317
|
+
const x_lo = grid[ix_m][iy_w][iz_w];
|
|
318
|
+
const x_hi = grid[ix_p][iy_w][iz_w];
|
|
319
|
+
const y_lo = grid[ix_w][iy_m][iz_w];
|
|
320
|
+
const y_hi = grid[ix_w][iy_p][iz_w];
|
|
321
|
+
const z_row = grid[ix_w][iy_w];
|
|
322
|
+
const scale = (lo, hi) => 1 / Math.max(1, periodic ? 2 : hi - lo);
|
|
323
|
+
const gz = -(z_row[iz_p] - z_row[iz_m]) * scale(iz_m, iz_p);
|
|
324
|
+
return [-(x_hi - x_lo) * scale(ix_m, ix_p), -(y_hi - y_lo) * scale(iy_m, iy_p), gz];
|
|
322
325
|
}
|
|
323
326
|
// Main marching cubes algorithm (optimized version)
|
|
324
|
-
|
|
325
|
-
const { periodic = true, interpolate = true, centered = true, normals: compute_norms = true, } = options;
|
|
327
|
+
function marching_cubes_raw(grid, iso_value, k_lattice, options = {}) {
|
|
328
|
+
const { periodic = true, interpolate = true, centered = true, normals: compute_norms = true, position_offset, } = options;
|
|
326
329
|
// When centered=true, shift fractional coordinates by -0.5 so the grid is
|
|
327
330
|
// centered at the origin (Γ point). This is needed for proper BZ visualization.
|
|
328
331
|
const center_offset = centered ? 0.5 : 0;
|
|
@@ -330,24 +333,30 @@ export function marching_cubes(grid, iso_value, k_lattice, options = {}) {
|
|
|
330
333
|
const ny = grid[0]?.length || 0;
|
|
331
334
|
const nz = grid[0]?.[0]?.length || 0;
|
|
332
335
|
if (nx < 2 || ny < 2 || nz < 2) {
|
|
333
|
-
return {
|
|
336
|
+
return { positions: [], indices: [], normals: [] };
|
|
334
337
|
}
|
|
335
|
-
const
|
|
336
|
-
const
|
|
338
|
+
const positions = [];
|
|
339
|
+
const indices = [];
|
|
337
340
|
const normals = [];
|
|
338
|
-
//
|
|
339
|
-
|
|
340
|
-
const
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
//
|
|
344
|
-
//
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
341
|
+
// Iterate over all cubes in the grid
|
|
342
|
+
const max_x = periodic ? nx : nx - 1;
|
|
343
|
+
const max_y = periodic ? ny : ny - 1;
|
|
344
|
+
const max_z = periodic ? nz : nz - 1;
|
|
345
|
+
// Rolling typed edge caches retain only the current x slab. Coordinates stay
|
|
346
|
+
// UNWRAPPED (reach n in periodic mode), so opposite cell faces remain distinct
|
|
347
|
+
// and never create cell-spanning triangles.
|
|
348
|
+
const edge_stride = max_z + 1;
|
|
349
|
+
const edge_plane_size = (max_y + 1) * edge_stride;
|
|
350
|
+
const x_edge_cache = new Int32Array(edge_plane_size);
|
|
351
|
+
let y_edge_current = new Int32Array(edge_plane_size);
|
|
352
|
+
let y_edge_next = new Int32Array(edge_plane_size);
|
|
353
|
+
let z_edge_current = new Int32Array(edge_plane_size);
|
|
354
|
+
let z_edge_next = new Int32Array(edge_plane_size);
|
|
355
|
+
x_edge_cache.fill(-1);
|
|
356
|
+
y_edge_current.fill(-1);
|
|
357
|
+
y_edge_next.fill(-1);
|
|
358
|
+
z_edge_current.fill(-1);
|
|
359
|
+
z_edge_next.fill(-1);
|
|
351
360
|
// Precompute k_lattice values for faster coordinate transform
|
|
352
361
|
const [kx0, kx1, kx2] = k_lattice[0];
|
|
353
362
|
const [ky0, ky1, ky2] = k_lattice[1];
|
|
@@ -358,6 +367,16 @@ export function marching_cubes(grid, iso_value, k_lattice, options = {}) {
|
|
|
358
367
|
const inv_nx = 1 / (periodic ? nx : nx - 1);
|
|
359
368
|
const inv_ny = 1 / (periodic ? ny : ny - 1);
|
|
360
369
|
const inv_nz = 1 / (periodic ? nz : nz - 1);
|
|
370
|
+
// Singular lattices cannot map covectors; fall back to index-space unit gradients.
|
|
371
|
+
let normal_transform = null;
|
|
372
|
+
if (compute_norms) {
|
|
373
|
+
try {
|
|
374
|
+
normal_transform = matrix_inverse_3x3(k_lattice);
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
/* keep null */
|
|
378
|
+
}
|
|
379
|
+
}
|
|
361
380
|
// Get or create vertex on an edge (fully optimized with flat array lookups)
|
|
362
381
|
const get_vertex_on_edge = (ix, iy, iz, edge_idx, cube_values) => {
|
|
363
382
|
// Use flat arrays instead of destructuring
|
|
@@ -369,13 +388,24 @@ export function marching_cubes(grid, iso_value, k_lattice, options = {}) {
|
|
|
369
388
|
const ox2 = CUBE_VERTS_X[v2_idx];
|
|
370
389
|
const oy2 = CUBE_VERTS_Y[v2_idx];
|
|
371
390
|
const oz2 = CUBE_VERTS_Z[v2_idx];
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
391
|
+
// Key the edge's lower endpoint. For x-edges, x is the rolling slab and
|
|
392
|
+
// y/z are equal; y- and z-edges normalize their sole varying key coordinate.
|
|
393
|
+
let cache;
|
|
394
|
+
let cache_idx;
|
|
395
|
+
if (ox1 !== ox2) {
|
|
396
|
+
cache = x_edge_cache;
|
|
397
|
+
cache_idx = (iy + oy1) * edge_stride + iz + oz1;
|
|
398
|
+
}
|
|
399
|
+
else if (oy1 !== oy2) {
|
|
400
|
+
cache = ox1 === 0 ? y_edge_current : y_edge_next;
|
|
401
|
+
cache_idx = (iy + Math.min(oy1, oy2)) * edge_stride + iz + oz1;
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
cache = ox1 === 0 ? z_edge_current : z_edge_next;
|
|
405
|
+
cache_idx = (iy + oy1) * edge_stride + iz + Math.min(oz1, oz2);
|
|
406
|
+
}
|
|
407
|
+
const cached = cache[cache_idx];
|
|
408
|
+
if (cached >= 0)
|
|
379
409
|
return cached;
|
|
380
410
|
// Compute vertex position
|
|
381
411
|
const v1 = cube_values[v1_idx];
|
|
@@ -407,26 +437,37 @@ export function marching_cubes(grid, iso_value, k_lattice, options = {}) {
|
|
|
407
437
|
fz = (iz + (oz1 + oz2) * 0.5) * inv_nz - center_offset;
|
|
408
438
|
}
|
|
409
439
|
// Transform to Cartesian (inlined)
|
|
410
|
-
const vert_idx =
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
440
|
+
const vert_idx = positions.length / 3;
|
|
441
|
+
const cart_x = fx * kx0 + fy * ky0 + fz * kz0;
|
|
442
|
+
const cart_y = fx * kx1 + fy * ky1 + fz * kz1;
|
|
443
|
+
const cart_z = fx * kx2 + fy * ky2 + fz * kz2;
|
|
444
|
+
if (position_offset) {
|
|
445
|
+
positions.push(cart_x + position_offset[0], cart_y + position_offset[1], cart_z + position_offset[2]);
|
|
446
|
+
}
|
|
447
|
+
else
|
|
448
|
+
positions.push(cart_x, cart_y, cart_z);
|
|
417
449
|
if (compute_norms) {
|
|
418
|
-
|
|
450
|
+
const [gx, gy, gz] = compute_gradient(grid, ix + ox1, iy + oy1, iz + oz1, nx, ny, nz, periodic);
|
|
451
|
+
// Scale by grid spacing without a lattice inverse (singular / anisotropic grids)
|
|
452
|
+
const index_grad = [gx / inv_nx, gy / inv_ny, gz / inv_nz];
|
|
453
|
+
const [cx, cy, cz] = normal_transform
|
|
454
|
+
? mat3x3_vec3_multiply(normal_transform, index_grad)
|
|
455
|
+
: index_grad;
|
|
456
|
+
const length = Math.hypot(cx, cy, cz);
|
|
457
|
+
if (length > 1e-10)
|
|
458
|
+
normals.push(cx / length, cy / length, cz / length);
|
|
459
|
+
else
|
|
460
|
+
normals.push(0, 0, 1);
|
|
419
461
|
}
|
|
420
|
-
|
|
462
|
+
cache[cache_idx] = vert_idx;
|
|
421
463
|
return vert_idx;
|
|
422
464
|
};
|
|
423
|
-
// Iterate over all cubes in the grid
|
|
424
|
-
const max_x = periodic ? nx : nx - 1;
|
|
425
|
-
const max_y = periodic ? ny : ny - 1;
|
|
426
|
-
const max_z = periodic ? nz : nz - 1;
|
|
427
465
|
// Preallocate cube_values array (reuse across iterations)
|
|
428
466
|
const cube_values = Array(8);
|
|
429
467
|
for (let ix = 0; ix < max_x; ix++) {
|
|
468
|
+
x_edge_cache.fill(-1);
|
|
469
|
+
y_edge_next.fill(-1);
|
|
470
|
+
z_edge_next.fill(-1);
|
|
430
471
|
const ix_row = grid[ix];
|
|
431
472
|
const ix1_row = grid[(ix + 1) % nx];
|
|
432
473
|
for (let iy = 0; iy < max_y; iy++) {
|
|
@@ -476,13 +517,39 @@ export function marching_cubes(grid, iso_value, k_lattice, options = {}) {
|
|
|
476
517
|
const v2 = get_vertex_on_edge(ix, iy, iz, tri_list[tri_idx + 2], cube_values);
|
|
477
518
|
// Skip degenerate triangles
|
|
478
519
|
if (v0 !== v1 && v1 !== v2 && v0 !== v2) {
|
|
479
|
-
|
|
520
|
+
indices.push(v0, v1, v2);
|
|
480
521
|
}
|
|
481
522
|
}
|
|
482
523
|
}
|
|
483
524
|
}
|
|
525
|
+
;
|
|
526
|
+
[y_edge_current, y_edge_next] = [y_edge_next, y_edge_current];
|
|
527
|
+
[z_edge_current, z_edge_next] = [z_edge_next, z_edge_current];
|
|
484
528
|
}
|
|
485
|
-
return {
|
|
529
|
+
return { positions, indices, normals };
|
|
530
|
+
}
|
|
531
|
+
// Buffer-oriented result for renderers that otherwise immediately flatten the
|
|
532
|
+
// compatibility arrays. This avoids one Vec3 and one triangle-array allocation
|
|
533
|
+
// per emitted vertex/face while preserving the public marching_cubes() API.
|
|
534
|
+
export function marching_cubes_buffers(grid, iso_value, k_lattice, options = {}) {
|
|
535
|
+
const raw = marching_cubes_raw(grid, iso_value, k_lattice, options);
|
|
536
|
+
return {
|
|
537
|
+
positions: Float32Array.from(raw.positions),
|
|
538
|
+
indices: Uint32Array.from(raw.indices),
|
|
539
|
+
normals: Float32Array.from(raw.normals),
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
const packed_to_vec3 = (values) => Array.from({ length: values.length / 3 }, (_, idx) => {
|
|
543
|
+
const offset = idx * 3;
|
|
544
|
+
return [values[offset], values[offset + 1], values[offset + 2]];
|
|
545
|
+
});
|
|
546
|
+
export function marching_cubes(grid, iso_value, k_lattice, options = {}) {
|
|
547
|
+
const raw = marching_cubes_raw(grid, iso_value, k_lattice, options);
|
|
548
|
+
return {
|
|
549
|
+
vertices: packed_to_vec3(raw.positions),
|
|
550
|
+
faces: packed_to_vec3(raw.indices),
|
|
551
|
+
normals: packed_to_vec3(raw.normals),
|
|
552
|
+
};
|
|
486
553
|
}
|
|
487
554
|
// Compute per-vertex normals from faces using area-weighted averaging
|
|
488
555
|
// Uses fan triangulation for N-gon faces (quads, etc.)
|
package/dist/math.d.ts
CHANGED
|
@@ -63,6 +63,7 @@ export declare function vec9_to_mat3x3(flat_array: number[]): Matrix3x3;
|
|
|
63
63
|
export declare function tensor_to_flat_array(tensor: number[][]): number[];
|
|
64
64
|
export declare const transpose_3x3_matrix: (matrix: Matrix3x3) => Matrix3x3;
|
|
65
65
|
export declare function scale_lattice_matrix(orig_matrix: Matrix3x3, scaling_factors: Vec3): Matrix3x3;
|
|
66
|
+
export declare const create_cart_to_frac_matrix: (lattice: Matrix3x3) => Matrix3x3;
|
|
66
67
|
export declare const create_frac_to_cart: (lattice: Matrix3x3) => (frac: Vec3) => Vec3;
|
|
67
68
|
export declare const create_cart_to_frac: (lattice: Matrix3x3) => (cart: Vec3) => Vec3;
|
|
68
69
|
export type LatticeConverters = {
|
|
@@ -106,6 +107,6 @@ export declare function polygon_centroid(vertices: Vec2[]): Vec2;
|
|
|
106
107
|
export declare function solve_linear_system(A: number[][], // NxN coefficient matrix
|
|
107
108
|
b: number[]): number[] | null;
|
|
108
109
|
export declare const cross_2d: (origin: Vec2, point_a: Vec2, point_b: Vec2) => number;
|
|
109
|
-
export declare const monotone_chain: (sorted: Vec2[]) => Vec2[];
|
|
110
|
-
export declare function convex_hull_2d(points: Vec2[]): Vec2[];
|
|
110
|
+
export declare const monotone_chain: (sorted: Vec2[], tolerance?: number) => Vec2[];
|
|
111
|
+
export declare function convex_hull_2d(points: Vec2[], tolerance?: number): Vec2[];
|
|
111
112
|
export {};
|