@manycore/aholo-splat-transform 1.2.7 → 1.2.9

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.
Files changed (98) hide show
  1. package/CHANGELOG.md +120 -106
  2. package/COPYRIGHT.md +17 -0
  3. package/README.md +39 -39
  4. package/THIRD_PARTY_LICENSES.txt +1373 -0
  5. package/bin/cli.js +125 -118
  6. package/dist/SplatData.d.ts +67 -67
  7. package/dist/SplatData.js +167 -156
  8. package/dist/constant.d.ts +3 -3
  9. package/dist/constant.js +13 -13
  10. package/dist/file/IFile.d.ts +5 -5
  11. package/dist/file/IFile.js +1 -1
  12. package/dist/file/esz.d.ts +11 -0
  13. package/dist/file/esz.js +337 -0
  14. package/dist/file/index.d.ts +8 -7
  15. package/dist/file/index.js +7 -6
  16. package/dist/file/ksplat.d.ts +12 -12
  17. package/dist/file/ksplat.js +293 -232
  18. package/dist/file/lcc.d.ts +11 -11
  19. package/dist/file/lcc.js +161 -157
  20. package/dist/file/ply.d.ts +13 -13
  21. package/dist/file/ply.js +439 -388
  22. package/dist/file/sog.d.ts +80 -80
  23. package/dist/file/sog.js +525 -504
  24. package/dist/file/splat.d.ts +6 -6
  25. package/dist/file/splat.js +119 -99
  26. package/dist/file/spz.d.ts +11 -8
  27. package/dist/file/spz.js +597 -400
  28. package/dist/file/voxel.d.ts +43 -37
  29. package/dist/file/voxel.js +411 -280
  30. package/dist/index.d.ts +33 -33
  31. package/dist/index.js +54 -54
  32. package/dist/native/index.d.ts +54 -54
  33. package/dist/native/index.js +122 -128
  34. package/dist/native/utils.d.ts +1 -0
  35. package/dist/native/utils.js +54 -0
  36. package/dist/tasks/AutoChunkLodTask.d.ts +13 -13
  37. package/dist/tasks/AutoChunkLodTask.js +117 -117
  38. package/dist/tasks/AutoLodTask.d.ts +10 -10
  39. package/dist/tasks/AutoLodTask.js +20 -20
  40. package/dist/tasks/BaseTask.d.ts +15 -15
  41. package/dist/tasks/BaseTask.js +5 -5
  42. package/dist/tasks/FlexLodTask.d.ts +12 -12
  43. package/dist/tasks/FlexLodTask.js +54 -44
  44. package/dist/tasks/ModifyTask.d.ts +9 -9
  45. package/dist/tasks/ModifyTask.js +166 -156
  46. package/dist/tasks/ReadTask.d.ts +9 -9
  47. package/dist/tasks/ReadTask.js +29 -29
  48. package/dist/tasks/SkeletonLodTask.d.ts +10 -10
  49. package/dist/tasks/SkeletonLodTask.js +176 -156
  50. package/dist/tasks/VoxelTask.d.ts +35 -30
  51. package/dist/tasks/VoxelTask.js +40 -37
  52. package/dist/tasks/WriteTask.d.ts +12 -11
  53. package/dist/tasks/WriteTask.js +70 -70
  54. package/dist/utils/BufferReader.d.ts +12 -12
  55. package/dist/utils/BufferReader.js +45 -47
  56. package/dist/utils/Logger.d.ts +11 -11
  57. package/dist/utils/Logger.js +40 -38
  58. package/dist/utils/StreamChunkDecoder.d.ts +16 -16
  59. package/dist/utils/StreamChunkDecoder.js +31 -36
  60. package/dist/utils/index.d.ts +27 -27
  61. package/dist/utils/index.js +101 -101
  62. package/dist/utils/k-means.d.ts +4 -4
  63. package/dist/utils/k-means.js +340 -350
  64. package/dist/utils/math.d.ts +46 -46
  65. package/dist/utils/math.js +350 -351
  66. package/dist/utils/quantize-1d.d.ts +4 -4
  67. package/dist/utils/quantize-1d.js +164 -164
  68. package/dist/utils/sh-rotate.d.ts +2 -2
  69. package/dist/utils/sh-rotate.js +236 -175
  70. package/dist/utils/splat.d.ts +21 -20
  71. package/dist/utils/splat.js +397 -378
  72. package/dist/utils/voxel/binary.d.ts +8 -0
  73. package/dist/utils/voxel/binary.js +176 -0
  74. package/dist/utils/voxel/common.d.ts +178 -162
  75. package/dist/utils/voxel/common.js +1752 -1700
  76. package/dist/utils/voxel/coplanar-merge.d.ts +63 -63
  77. package/dist/utils/voxel/coplanar-merge.js +818 -819
  78. package/dist/utils/voxel/filter-cluster.d.ts +20 -0
  79. package/dist/utils/voxel/filter-cluster.js +628 -0
  80. package/dist/utils/voxel/gpu-dilation.d.ts +2 -2
  81. package/dist/utils/voxel/gpu-dilation.js +677 -665
  82. package/dist/utils/voxel/marching-cubes.d.ts +42 -42
  83. package/dist/utils/voxel/marching-cubes.js +1645 -1657
  84. package/dist/utils/voxel/mesh.d.ts +3 -3
  85. package/dist/utils/voxel/mesh.js +130 -130
  86. package/dist/utils/voxel/nav.d.ts +29 -29
  87. package/dist/utils/voxel/nav.js +1068 -1043
  88. package/dist/utils/voxel/postprocess.d.ts +23 -23
  89. package/dist/utils/voxel/postprocess.js +408 -375
  90. package/dist/utils/voxel/voxel-faces.d.ts +18 -18
  91. package/dist/utils/voxel/voxel-faces.js +662 -663
  92. package/dist/utils/voxel/voxelize.d.ts +34 -33
  93. package/dist/utils/voxel/voxelize.js +1208 -1193
  94. package/dist/utils/webgpu.d.ts +8 -8
  95. package/dist/utils/webgpu.js +122 -122
  96. package/package.json +37 -30
  97. package/dist/native/cpp/bin/linux/binding.node +0 -0
  98. package/dist/native/cpp/bin/windows/binding.node +0 -0
@@ -1,4 +1,4 @@
1
- export declare function quantize1d(fields: Float32Array[], k?: number, alpha?: number, transform?: (v: number) => number): {
2
- centroids: Float32Array<ArrayBuffer>;
3
- labels: Uint8Array<ArrayBuffer>[];
4
- };
1
+ export declare function quantize1d(fields: Float32Array[], k?: number, alpha?: number, transform?: (v: number) => number): {
2
+ centroids: Float32Array<ArrayBuffer>;
3
+ labels: Uint8Array<ArrayBuffer>[];
4
+ };
@@ -1,164 +1,164 @@
1
- // https://github.com/playcanvas/splat-transform/blob/main/src/lib/spatial/quantize-1d.ts
2
- export function quantize1d(fields, k = 256, alpha = 0.5, transform) {
3
- const numColumns = fields.length;
4
- const numRows = fields.length > 0 ? fields[0].length : 0;
5
- // pool all columns into a flat 1D array
6
- const N = numRows * numColumns;
7
- if (N === 0) {
8
- const centroids = new Float32Array(k);
9
- const labels = fields.map(_ => new Uint8Array(numRows));
10
- return { centroids, labels };
11
- }
12
- const data = new Float32Array(N);
13
- for (let i = 0; i < numColumns; ++i) {
14
- data.set(fields[i], i * numRows);
15
- }
16
- if (transform) {
17
- for (let i = 0; i < data.length; i++) {
18
- data[i] = transform(data[i]);
19
- }
20
- }
21
- // sort a copy for histogram binning (keep original for label assignment)
22
- const sortedData = new Float32Array(data);
23
- sortedData.sort();
24
- const vMin = sortedData[0];
25
- const vMax = sortedData[N - 1];
26
- // handle degenerate case where all values are identical
27
- if (vMax - vMin < 1e-20) {
28
- const centroids = new Float32Array(k);
29
- centroids.fill(vMin);
30
- const labels = fields.map(_ => new Uint8Array(numRows));
31
- return { centroids, labels };
32
- }
33
- // build histogram using blended uniform/quantile bin positions
34
- const H = Math.min(1024, N);
35
- const vRange = vMax - vMin;
36
- // adaptive blend ratio: when outliers are extreme (IQR << range), lean
37
- // strongly toward quantile to give the dense center adequate bins; when
38
- // the distribution has moderate tails (IQR ~ range), reduce quantile
39
- // bias somewhat, but keep at least 50% quantile to preserve density
40
- const iqr = sortedData[Math.floor(N * 0.75)] - sortedData[Math.floor(N * 0.25)];
41
- const beta = Math.max(0.5, Math.min(0.999, 1 - iqr / vRange));
42
- const counts = new Float64Array(H);
43
- const sums = new Float64Array(H);
44
- for (let i = 0; i < N; ++i) {
45
- const uniformPos = (sortedData[i] - vMin) / vRange;
46
- const quantilePos = i / N;
47
- const bin = Math.min(H - 1, Math.floor(H * (beta * quantilePos + (1 - beta) * uniformPos)));
48
- counts[bin]++;
49
- sums[bin] += sortedData[i];
50
- }
51
- const centers = new Float64Array(H);
52
- for (let i = 0; i < H; ++i) {
53
- centers[i] = counts[i] > 0 ? sums[i] / counts[i] : vMin + (i + 0.5) / H * vRange;
54
- }
55
- // compute weights: w = count^alpha (sub-linear density weighting)
56
- const weights = new Float64Array(H);
57
- for (let i = 0; i < H; ++i) {
58
- weights[i] = counts[i] > 0 ? Math.pow(counts[i], alpha) : 0;
59
- }
60
- // prefix sums for O(1) range cost queries
61
- // cost(a,b) = sum_wxx - sum_wx^2 / sum_w
62
- // centroid(a,b) = sum_wx / sum_w
63
- const prefW = new Float64Array(H + 1);
64
- const prefWX = new Float64Array(H + 1);
65
- const prefWXX = new Float64Array(H + 1);
66
- for (let i = 0; i < H; ++i) {
67
- prefW[i + 1] = prefW[i] + weights[i];
68
- prefWX[i + 1] = prefWX[i] + weights[i] * centers[i];
69
- prefWXX[i + 1] = prefWXX[i] + weights[i] * centers[i] * centers[i];
70
- }
71
- const rangeCost = (a, b) => {
72
- const w = prefW[b + 1] - prefW[a];
73
- if (w <= 0) {
74
- return 0;
75
- }
76
- const wx = prefWX[b + 1] - prefWX[a];
77
- const wxx = prefWXX[b + 1] - prefWXX[a];
78
- return wxx - (wx * wx) / w;
79
- };
80
- const rangeMean = (a, b) => {
81
- const w = prefW[b + 1] - prefW[a];
82
- if (w <= 0) {
83
- return (centers[a] + centers[b]) * 0.5;
84
- }
85
- return (prefWX[b + 1] - prefWX[a]) / w;
86
- };
87
- const nonEmpty = counts.reduce((n, c) => n + (c > 0 ? 1 : 0), 0);
88
- const effectiveK = Math.min(k, nonEmpty);
89
- // DP: dp[m][j] = min weighted SSE of quantizing bins 0..j into m centroids
90
- // Use two rows to save memory (only need previous row)
91
- const INF = 1e30;
92
- let dpPrev = new Float64Array(H).fill(INF);
93
- let dpCurr = new Float64Array(H).fill(INF);
94
- const splitTable = new Array(effectiveK + 1);
95
- // base case: m = 1
96
- const split1 = new Int32Array(H);
97
- for (let j = 0; j < H; ++j) {
98
- dpPrev[j] = rangeCost(0, j);
99
- split1[j] = -1;
100
- }
101
- splitTable[1] = split1;
102
- // fill DP for m = 2..effectiveK
103
- for (let m = 2; m <= effectiveK; ++m) {
104
- dpCurr.fill(INF);
105
- const splitM = new Int32Array(H);
106
- for (let j = m - 1; j < H; ++j) {
107
- let bestCost = INF;
108
- let bestS = m - 2;
109
- for (let s = m - 2; s < j; ++s) {
110
- const cost = dpPrev[s] + rangeCost(s + 1, j);
111
- if (cost < bestCost) {
112
- bestCost = cost;
113
- bestS = s;
114
- }
115
- }
116
- dpCurr[j] = bestCost;
117
- splitM[j] = bestS;
118
- }
119
- splitTable[m] = splitM;
120
- // swap rows
121
- const tmp = dpPrev;
122
- dpPrev = dpCurr;
123
- dpCurr = tmp;
124
- }
125
- // backtrack to find centroid values
126
- const centroidValues = new Float32Array(effectiveK);
127
- let j = H - 1;
128
- for (let m = effectiveK; m >= 1; --m) {
129
- const s = m > 1 ? splitTable[m][j] : -1;
130
- centroidValues[m - 1] = rangeMean(s + 1, j);
131
- j = s;
132
- }
133
- // sort centroids (should already be sorted, but ensure)
134
- centroidValues.sort();
135
- // pad to k entries if effectiveK < k (duplicate last centroid)
136
- const finalCentroids = new Float32Array(k);
137
- finalCentroids.set(centroidValues);
138
- for (let i = effectiveK; i < k; ++i) {
139
- finalCentroids[i] = centroidValues[effectiveK - 1];
140
- }
141
- // assign each data point to nearest centroid via binary search
142
- const labels = new Uint8Array(N);
143
- for (let i = 0; i < N; ++i) {
144
- const v = data[i];
145
- // binary search for nearest centroid
146
- let lo = 0;
147
- let hi = k - 1;
148
- while (lo < hi) {
149
- const mid = (lo + hi) >> 1;
150
- // compare against midpoint between centroids mid and mid+1
151
- if (v < (finalCentroids[mid] + finalCentroids[mid + 1]) * 0.5) {
152
- hi = mid;
153
- }
154
- else {
155
- lo = mid + 1;
156
- }
157
- }
158
- labels[i] = lo;
159
- }
160
- return {
161
- labels: fields.map((_, i) => labels.subarray(i * numRows, (i + 1) * numRows)),
162
- centroids: finalCentroids,
163
- };
164
- }
1
+ // https://github.com/playcanvas/splat-transform/blob/main/src/lib/spatial/quantize-1d.ts
2
+ export function quantize1d(fields, k = 256, alpha = 0.5, transform) {
3
+ const numColumns = fields.length;
4
+ const numRows = fields.length > 0 ? fields[0].length : 0;
5
+ // pool all columns into a flat 1D array
6
+ const N = numRows * numColumns;
7
+ if (N === 0) {
8
+ const centroids = new Float32Array(k);
9
+ const labels = fields.map(_ => new Uint8Array(numRows));
10
+ return { centroids, labels };
11
+ }
12
+ const data = new Float32Array(N);
13
+ for (let i = 0; i < numColumns; ++i) {
14
+ data.set(fields[i], i * numRows);
15
+ }
16
+ if (transform) {
17
+ for (let i = 0; i < data.length; i++) {
18
+ data[i] = transform(data[i]);
19
+ }
20
+ }
21
+ // sort a copy for histogram binning (keep original for label assignment)
22
+ const sortedData = new Float32Array(data);
23
+ sortedData.sort();
24
+ const vMin = sortedData[0];
25
+ const vMax = sortedData[N - 1];
26
+ // handle degenerate case where all values are identical
27
+ if (vMax - vMin < 1e-20) {
28
+ const centroids = new Float32Array(k);
29
+ centroids.fill(vMin);
30
+ const labels = fields.map(_ => new Uint8Array(numRows));
31
+ return { centroids, labels };
32
+ }
33
+ // build histogram using blended uniform/quantile bin positions
34
+ const H = Math.min(1024, N);
35
+ const vRange = vMax - vMin;
36
+ // adaptive blend ratio: when outliers are extreme (IQR << range), lean
37
+ // strongly toward quantile to give the dense center adequate bins; when
38
+ // the distribution has moderate tails (IQR ~ range), reduce quantile
39
+ // bias somewhat, but keep at least 50% quantile to preserve density
40
+ const iqr = sortedData[Math.floor(N * 0.75)] - sortedData[Math.floor(N * 0.25)];
41
+ const beta = Math.max(0.5, Math.min(0.999, 1 - iqr / vRange));
42
+ const counts = new Float64Array(H);
43
+ const sums = new Float64Array(H);
44
+ for (let i = 0; i < N; ++i) {
45
+ const uniformPos = (sortedData[i] - vMin) / vRange;
46
+ const quantilePos = i / N;
47
+ const bin = Math.min(H - 1, Math.floor(H * (beta * quantilePos + (1 - beta) * uniformPos)));
48
+ counts[bin]++;
49
+ sums[bin] += sortedData[i];
50
+ }
51
+ const centers = new Float64Array(H);
52
+ for (let i = 0; i < H; ++i) {
53
+ centers[i] = counts[i] > 0 ? sums[i] / counts[i] : vMin + ((i + 0.5) / H) * vRange;
54
+ }
55
+ // compute weights: w = count^alpha (sub-linear density weighting)
56
+ const weights = new Float64Array(H);
57
+ for (let i = 0; i < H; ++i) {
58
+ weights[i] = counts[i] > 0 ? Math.pow(counts[i], alpha) : 0;
59
+ }
60
+ // prefix sums for O(1) range cost queries
61
+ // cost(a,b) = sum_wxx - sum_wx^2 / sum_w
62
+ // centroid(a,b) = sum_wx / sum_w
63
+ const prefW = new Float64Array(H + 1);
64
+ const prefWX = new Float64Array(H + 1);
65
+ const prefWXX = new Float64Array(H + 1);
66
+ for (let i = 0; i < H; ++i) {
67
+ prefW[i + 1] = prefW[i] + weights[i];
68
+ prefWX[i + 1] = prefWX[i] + weights[i] * centers[i];
69
+ prefWXX[i + 1] = prefWXX[i] + weights[i] * centers[i] * centers[i];
70
+ }
71
+ const rangeCost = (a, b) => {
72
+ const w = prefW[b + 1] - prefW[a];
73
+ if (w <= 0) {
74
+ return 0;
75
+ }
76
+ const wx = prefWX[b + 1] - prefWX[a];
77
+ const wxx = prefWXX[b + 1] - prefWXX[a];
78
+ return wxx - (wx * wx) / w;
79
+ };
80
+ const rangeMean = (a, b) => {
81
+ const w = prefW[b + 1] - prefW[a];
82
+ if (w <= 0) {
83
+ return (centers[a] + centers[b]) * 0.5;
84
+ }
85
+ return (prefWX[b + 1] - prefWX[a]) / w;
86
+ };
87
+ const nonEmpty = counts.reduce((n, c) => n + (c > 0 ? 1 : 0), 0);
88
+ const effectiveK = Math.min(k, nonEmpty);
89
+ // DP: dp[m][j] = min weighted SSE of quantizing bins 0..j into m centroids
90
+ // Use two rows to save memory (only need previous row)
91
+ const INF = 1e30;
92
+ let dpPrev = new Float64Array(H).fill(INF);
93
+ let dpCurr = new Float64Array(H).fill(INF);
94
+ const splitTable = new Array(effectiveK + 1);
95
+ // base case: m = 1
96
+ const split1 = new Int32Array(H);
97
+ for (let j = 0; j < H; ++j) {
98
+ dpPrev[j] = rangeCost(0, j);
99
+ split1[j] = -1;
100
+ }
101
+ splitTable[1] = split1;
102
+ // fill DP for m = 2..effectiveK
103
+ for (let m = 2; m <= effectiveK; ++m) {
104
+ dpCurr.fill(INF);
105
+ const splitM = new Int32Array(H);
106
+ for (let j = m - 1; j < H; ++j) {
107
+ let bestCost = INF;
108
+ let bestS = m - 2;
109
+ for (let s = m - 2; s < j; ++s) {
110
+ const cost = dpPrev[s] + rangeCost(s + 1, j);
111
+ if (cost < bestCost) {
112
+ bestCost = cost;
113
+ bestS = s;
114
+ }
115
+ }
116
+ dpCurr[j] = bestCost;
117
+ splitM[j] = bestS;
118
+ }
119
+ splitTable[m] = splitM;
120
+ // swap rows
121
+ const tmp = dpPrev;
122
+ dpPrev = dpCurr;
123
+ dpCurr = tmp;
124
+ }
125
+ // backtrack to find centroid values
126
+ const centroidValues = new Float32Array(effectiveK);
127
+ let j = H - 1;
128
+ for (let m = effectiveK; m >= 1; --m) {
129
+ const s = m > 1 ? splitTable[m][j] : -1;
130
+ centroidValues[m - 1] = rangeMean(s + 1, j);
131
+ j = s;
132
+ }
133
+ // sort centroids (should already be sorted, but ensure)
134
+ centroidValues.sort();
135
+ // pad to k entries if effectiveK < k (duplicate last centroid)
136
+ const finalCentroids = new Float32Array(k);
137
+ finalCentroids.set(centroidValues);
138
+ for (let i = effectiveK; i < k; ++i) {
139
+ finalCentroids[i] = centroidValues[effectiveK - 1];
140
+ }
141
+ // assign each data point to nearest centroid via binary search
142
+ const labels = new Uint8Array(N);
143
+ for (let i = 0; i < N; ++i) {
144
+ const v = data[i];
145
+ // binary search for nearest centroid
146
+ let lo = 0;
147
+ let hi = k - 1;
148
+ while (lo < hi) {
149
+ const mid = (lo + hi) >> 1;
150
+ // compare against midpoint between centroids mid and mid+1
151
+ if (v < (finalCentroids[mid] + finalCentroids[mid + 1]) * 0.5) {
152
+ hi = mid;
153
+ }
154
+ else {
155
+ lo = mid + 1;
156
+ }
157
+ }
158
+ labels[i] = lo;
159
+ }
160
+ return {
161
+ labels: fields.map((_, i) => labels.subarray(i * numRows, (i + 1) * numRows)),
162
+ centroids: finalCentroids,
163
+ };
164
+ }
@@ -1,2 +1,2 @@
1
- import { Matrix3 } from './math.js';
2
- export declare function createSHRotateFn(mat: Matrix3): (shN: number[]) => void;
1
+ import type { Matrix3 } from './math.js';
2
+ export declare function createSHRotateFn(mat: Matrix3): (shN: number[]) => void;