s3m-three 0.1.0 → 0.2.0

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 (44) hide show
  1. package/LICENSE +202 -202
  2. package/dist/render/DatasetManager.d.ts +10 -3
  3. package/dist/render/DatasetManager.d.ts.map +1 -1
  4. package/dist/render/DatasetManager.js +14 -5
  5. package/dist/render/DatasetManager.js.map +1 -1
  6. package/dist/render/EdgeLines.js +46 -46
  7. package/dist/render/GroundManager.d.ts +9 -0
  8. package/dist/render/GroundManager.d.ts.map +1 -1
  9. package/dist/render/GroundManager.js +13 -1
  10. package/dist/render/GroundManager.js.map +1 -1
  11. package/dist/render/Picker.js +66 -66
  12. package/dist/render/S3MViewer.d.ts +11 -3
  13. package/dist/render/S3MViewer.d.ts.map +1 -1
  14. package/dist/render/S3MViewer.js +18 -3
  15. package/dist/render/S3MViewer.js.map +1 -1
  16. package/dist/render/StyleMaterial.js +265 -265
  17. package/dist/vendor/meshopt_decoder.module.js +118 -118
  18. package/docs/API.md +20 -0
  19. package/package.json +1 -1
  20. package/src/core/BinaryReader.ts +116 -116
  21. package/src/core/DXTTextureDecode.ts +260 -260
  22. package/src/core/FeatureInfo.ts +150 -150
  23. package/src/core/MeshOpt.ts +401 -401
  24. package/src/core/S3MBParser.ts +590 -590
  25. package/src/core/types.ts +222 -222
  26. package/src/render/DatasetManager.ts +17 -6
  27. package/src/render/EdgeLines.ts +343 -343
  28. package/src/render/GeometryBuilder.ts +840 -840
  29. package/src/render/GroundManager.ts +14 -1
  30. package/src/render/Picker.ts +293 -293
  31. package/src/render/S3MViewer.ts +18 -3
  32. package/src/render/StyleMaterial.ts +602 -602
  33. package/src/render/TextureFactory.ts +134 -134
  34. package/src/tileset/S3MTileset.ts +552 -552
  35. package/src/vendor/meshopt_decoder.module.d.ts +31 -31
  36. package/src/vendor/meshopt_decoder.module.js +118 -118
  37. package/dist/render/CoordinateHelper.d.ts +0 -90
  38. package/dist/render/CoordinateHelper.d.ts.map +0 -1
  39. package/dist/render/CoordinateHelper.js +0 -85
  40. package/dist/render/CoordinateHelper.js.map +0 -1
  41. package/dist/render/S3MLayer.d.ts +0 -457
  42. package/dist/render/S3MLayer.d.ts.map +0 -1
  43. package/dist/render/S3MLayer.js +0 -1860
  44. package/dist/render/S3MLayer.js.map +0 -1
package/src/core/types.ts CHANGED
@@ -1,222 +1,222 @@
1
- /**
2
- * 公共数据类型
3
- *
4
- * 这里只放「跨模块共享」的结构定义。模块内部的私有类型各自就近声明。
5
- */
6
- import type { Color } from 'three';
7
-
8
- /* ------------------------------------------------------------------ 数学 */
9
-
10
- export interface Vec3 {
11
- x: number;
12
- y: number;
13
- z: number;
14
- }
15
-
16
- export interface BoundingBox {
17
- center: Vec3;
18
- xExtent: Vec3;
19
- yExtent: Vec3;
20
- zExtent: Vec3;
21
- }
22
-
23
- /* ------------------------------------------------------------------ 几何 */
24
-
25
- export type AttrDType = 'f32' | 'u8' | 'u16' | 'u32';
26
-
27
- export interface VertexAttribute {
28
- semantic: string;
29
- /** 原始字节视图,生命周期绑定底层 buffer */
30
- data: Uint8Array;
31
- components: number;
32
- stride: number;
33
- offsetInBytes: number;
34
- /** 非 0 表示实例属性 */
35
- divisor?: number;
36
- dtype: AttrDType;
37
- }
38
-
39
- export interface IndexPackage {
40
- indexCount: number;
41
- /** 0 = UNSIGNED_SHORT,1/3 = UNSIGNED_INT */
42
- indexType: number;
43
- useIndex: number;
44
- /** 4 = TRIANGLES */
45
- primitiveType: number;
46
- indices: Uint8Array | null;
47
- passNames: string[];
48
- }
49
-
50
- export interface VertexPackage {
51
- verticesCount: number;
52
- vertexAttributes: VertexAttribute[];
53
- /** semantic → 在 vertexAttributes 中的下标 */
54
- attrLocation: Record<string, number>;
55
- instanceCount: number;
56
- /** 16 = 只有矩阵,17/29 = 矩阵 + 颜色 */
57
- instanceMode: number;
58
- /** -1 表示非实例化 */
59
- instanceIndex: number;
60
- instanceBuffer?: Uint8Array;
61
- /**
62
- * 实例化几何的逐实例控制位(长度 = instanceCount),-1 表示该实例不属于任何单体。
63
- * 注意顶点数 ≠ 实例数,所以它不能当逐顶点属性用,构建几何时要做成 InstancedBufferAttribute。
64
- */
65
- instanceBatchIds?: Float32Array;
66
- compressOptions?: number;
67
- customVertexAttribute?: unknown;
68
- textureCoordIsW?: boolean;
69
- }
70
-
71
- export interface PickSegment {
72
- vertexOffset: number;
73
- vertexCount: number;
74
- }
75
-
76
- export interface PickEntry {
77
- /** 顶点区间型单体:控制位(写进 `aBatchId`) */
78
- batchId?: number;
79
- segments?: PickSegment[];
80
- /** 实例化单体:落在哪几个实例上(一个单体可能对应多个实例) */
81
- instanceIds?: number[];
82
- /** 实例化单体:控制位(写进 `aInstanceBatchId`),等于 pickInfo 里的枚举序 */
83
- instanceBatchId?: number;
84
- }
85
-
86
- export interface GeoPackageEntry {
87
- name: string;
88
- vertexPackage: VertexPackage;
89
- indexPackages: IndexPackage[];
90
- /** SMID → batchId + 顶点区间(单体化信息) */
91
- pickInfo?: Record<number, PickEntry>;
92
- }
93
-
94
- /* ------------------------------------------------------------------ LOD 树 */
95
-
96
- export interface Geode {
97
- /** 列主序 4×4,平移在 [12][13][14] */
98
- matrix: number[];
99
- skeletonNames: string[];
100
- }
101
-
102
- export interface PageLOD {
103
- rangeValue: number;
104
- /** 0 = 视点距离,1 = 屏幕像素,2 = 几何误差 */
105
- rangeMode: number;
106
- boundingSphere: { center: Vec3; radius: number };
107
- obb?: BoundingBox;
108
- childTile: string;
109
- geodes: Geode[];
110
- }
111
-
112
- export interface GroupNode {
113
- pageLods: PageLOD[];
114
- }
115
-
116
- /* ------------------------------------------------------------------ 纹理 */
117
-
118
- export interface S3MTexture {
119
- code: string;
120
- level: number;
121
- width: number;
122
- height: number;
123
- compressType: number;
124
- pixelFormat: number;
125
- data: Uint8Array;
126
- }
127
-
128
- /* ------------------------------------------------------------------ 瓦片 */
129
-
130
- export interface ParsedTile {
131
- version: number;
132
- compressedType: number;
133
- options: number;
134
- groupNode: GroupNode;
135
- geoPackage: Record<string, GeoPackageEntry>;
136
- textures: Record<string, S3MTexture>;
137
- materials: unknown;
138
- pickInfo: unknown;
139
- extensions?: unknown;
140
- /** 实际消费的字节数,应与 bytesTotal 相等 */
141
- bytesRead: number;
142
- bytesTotal: number;
143
- }
144
-
145
- /* ------------------------------------------------------------------ 配置 */
146
-
147
- export interface Anchor {
148
- lon: number;
149
- lat: number;
150
- /** 锚点椭球高(米) */
151
- height: number;
152
- }
153
-
154
- export interface Stats {
155
- tiles: number;
156
- loading: number;
157
- failed: number;
158
- meshes: number;
159
- vertices: number;
160
- triangles: number;
161
- datasets: number;
162
- }
163
-
164
- /* ------------------------------------------------------------------ 单体属性 */
165
-
166
- export interface FeatureAttributes {
167
- smid: number | null;
168
- /** 建筑高度(米),单体包围盒 z 跨度 */
169
- height?: number;
170
- /** 基底高程(米),相对数据集锚点 */
171
- baseElevation?: number;
172
- /** 外接盒平面尺寸 [宽, 深](米) */
173
- size?: [number, number];
174
- /** 外接盒底面积(㎡),异形建筑会偏大 */
175
- bboxArea?: number;
176
- /** 楼层估算 = 高度 / 层高 */
177
- floors?: number;
178
- /** 本单体自身的三角面数 */
179
- triangles?: number;
180
- vertices?: number;
181
- /** 单体局部包围盒 [[minX,minY,minZ],[maxX,maxY,maxZ]](米) */
182
- bbox?: [[number, number, number], [number, number, number]];
183
- }
184
-
185
- export interface SegmentBox {
186
- minX: number;
187
- minY: number;
188
- minZ: number;
189
- maxX: number;
190
- maxY: number;
191
- maxZ: number;
192
- count: number;
193
- triangles: number;
194
- }
195
-
196
- /* ------------------------------------------------------------------ 着色 */
197
-
198
- /** 全局共享 uniform:所有材质引用同一批对象,改 .value 即全场景生效 */
199
- export interface StyleUniforms {
200
- uMode: { value: number };
201
- uColorA: { value: Color };
202
- uColorB: { value: Color };
203
- uColorC: { value: Color };
204
- uTime: { value: number };
205
- uHeightMin: { value: number };
206
- uHeightMax: { value: number };
207
- uFloorHeight: { value: number };
208
- uDim: { value: number };
209
- uDimFactor?: { value: number };
210
- uSelColor: { value: Color };
211
- uSelMix: { value: number };
212
- uSelMode?: { value: number };
213
- uSelOpacity?: { value: number };
214
- uSelEmissive?: { value: number };
215
- uSelElevation?: { value: number };
216
- uFilterMinZ?: { value: number };
217
- uFilterMaxZ?: { value: number };
218
- uFilterHeightActive?: { value: number };
219
- uRoofThreshold?: { value: number };
220
- uTexMix?: { value: number };
221
- [key: string]: { value: unknown } | undefined;
222
- }
1
+ /**
2
+ * 公共数据类型
3
+ *
4
+ * 这里只放「跨模块共享」的结构定义。模块内部的私有类型各自就近声明。
5
+ */
6
+ import type { Color } from 'three';
7
+
8
+ /* ------------------------------------------------------------------ 数学 */
9
+
10
+ export interface Vec3 {
11
+ x: number;
12
+ y: number;
13
+ z: number;
14
+ }
15
+
16
+ export interface BoundingBox {
17
+ center: Vec3;
18
+ xExtent: Vec3;
19
+ yExtent: Vec3;
20
+ zExtent: Vec3;
21
+ }
22
+
23
+ /* ------------------------------------------------------------------ 几何 */
24
+
25
+ export type AttrDType = 'f32' | 'u8' | 'u16' | 'u32';
26
+
27
+ export interface VertexAttribute {
28
+ semantic: string;
29
+ /** 原始字节视图,生命周期绑定底层 buffer */
30
+ data: Uint8Array;
31
+ components: number;
32
+ stride: number;
33
+ offsetInBytes: number;
34
+ /** 非 0 表示实例属性 */
35
+ divisor?: number;
36
+ dtype: AttrDType;
37
+ }
38
+
39
+ export interface IndexPackage {
40
+ indexCount: number;
41
+ /** 0 = UNSIGNED_SHORT,1/3 = UNSIGNED_INT */
42
+ indexType: number;
43
+ useIndex: number;
44
+ /** 4 = TRIANGLES */
45
+ primitiveType: number;
46
+ indices: Uint8Array | null;
47
+ passNames: string[];
48
+ }
49
+
50
+ export interface VertexPackage {
51
+ verticesCount: number;
52
+ vertexAttributes: VertexAttribute[];
53
+ /** semantic → 在 vertexAttributes 中的下标 */
54
+ attrLocation: Record<string, number>;
55
+ instanceCount: number;
56
+ /** 16 = 只有矩阵,17/29 = 矩阵 + 颜色 */
57
+ instanceMode: number;
58
+ /** -1 表示非实例化 */
59
+ instanceIndex: number;
60
+ instanceBuffer?: Uint8Array;
61
+ /**
62
+ * 实例化几何的逐实例控制位(长度 = instanceCount),-1 表示该实例不属于任何单体。
63
+ * 注意顶点数 ≠ 实例数,所以它不能当逐顶点属性用,构建几何时要做成 InstancedBufferAttribute。
64
+ */
65
+ instanceBatchIds?: Float32Array;
66
+ compressOptions?: number;
67
+ customVertexAttribute?: unknown;
68
+ textureCoordIsW?: boolean;
69
+ }
70
+
71
+ export interface PickSegment {
72
+ vertexOffset: number;
73
+ vertexCount: number;
74
+ }
75
+
76
+ export interface PickEntry {
77
+ /** 顶点区间型单体:控制位(写进 `aBatchId`) */
78
+ batchId?: number;
79
+ segments?: PickSegment[];
80
+ /** 实例化单体:落在哪几个实例上(一个单体可能对应多个实例) */
81
+ instanceIds?: number[];
82
+ /** 实例化单体:控制位(写进 `aInstanceBatchId`),等于 pickInfo 里的枚举序 */
83
+ instanceBatchId?: number;
84
+ }
85
+
86
+ export interface GeoPackageEntry {
87
+ name: string;
88
+ vertexPackage: VertexPackage;
89
+ indexPackages: IndexPackage[];
90
+ /** SMID → batchId + 顶点区间(单体化信息) */
91
+ pickInfo?: Record<number, PickEntry>;
92
+ }
93
+
94
+ /* ------------------------------------------------------------------ LOD 树 */
95
+
96
+ export interface Geode {
97
+ /** 列主序 4×4,平移在 [12][13][14] */
98
+ matrix: number[];
99
+ skeletonNames: string[];
100
+ }
101
+
102
+ export interface PageLOD {
103
+ rangeValue: number;
104
+ /** 0 = 视点距离,1 = 屏幕像素,2 = 几何误差 */
105
+ rangeMode: number;
106
+ boundingSphere: { center: Vec3; radius: number };
107
+ obb?: BoundingBox;
108
+ childTile: string;
109
+ geodes: Geode[];
110
+ }
111
+
112
+ export interface GroupNode {
113
+ pageLods: PageLOD[];
114
+ }
115
+
116
+ /* ------------------------------------------------------------------ 纹理 */
117
+
118
+ export interface S3MTexture {
119
+ code: string;
120
+ level: number;
121
+ width: number;
122
+ height: number;
123
+ compressType: number;
124
+ pixelFormat: number;
125
+ data: Uint8Array;
126
+ }
127
+
128
+ /* ------------------------------------------------------------------ 瓦片 */
129
+
130
+ export interface ParsedTile {
131
+ version: number;
132
+ compressedType: number;
133
+ options: number;
134
+ groupNode: GroupNode;
135
+ geoPackage: Record<string, GeoPackageEntry>;
136
+ textures: Record<string, S3MTexture>;
137
+ materials: unknown;
138
+ pickInfo: unknown;
139
+ extensions?: unknown;
140
+ /** 实际消费的字节数,应与 bytesTotal 相等 */
141
+ bytesRead: number;
142
+ bytesTotal: number;
143
+ }
144
+
145
+ /* ------------------------------------------------------------------ 配置 */
146
+
147
+ export interface Anchor {
148
+ lon: number;
149
+ lat: number;
150
+ /** 锚点椭球高(米) */
151
+ height: number;
152
+ }
153
+
154
+ export interface Stats {
155
+ tiles: number;
156
+ loading: number;
157
+ failed: number;
158
+ meshes: number;
159
+ vertices: number;
160
+ triangles: number;
161
+ datasets: number;
162
+ }
163
+
164
+ /* ------------------------------------------------------------------ 单体属性 */
165
+
166
+ export interface FeatureAttributes {
167
+ smid: number | null;
168
+ /** 建筑高度(米),单体包围盒 z 跨度 */
169
+ height?: number;
170
+ /** 基底高程(米),相对数据集锚点 */
171
+ baseElevation?: number;
172
+ /** 外接盒平面尺寸 [宽, 深](米) */
173
+ size?: [number, number];
174
+ /** 外接盒底面积(㎡),异形建筑会偏大 */
175
+ bboxArea?: number;
176
+ /** 楼层估算 = 高度 / 层高 */
177
+ floors?: number;
178
+ /** 本单体自身的三角面数 */
179
+ triangles?: number;
180
+ vertices?: number;
181
+ /** 单体局部包围盒 [[minX,minY,minZ],[maxX,maxY,maxZ]](米) */
182
+ bbox?: [[number, number, number], [number, number, number]];
183
+ }
184
+
185
+ export interface SegmentBox {
186
+ minX: number;
187
+ minY: number;
188
+ minZ: number;
189
+ maxX: number;
190
+ maxY: number;
191
+ maxZ: number;
192
+ count: number;
193
+ triangles: number;
194
+ }
195
+
196
+ /* ------------------------------------------------------------------ 着色 */
197
+
198
+ /** 全局共享 uniform:所有材质引用同一批对象,改 .value 即全场景生效 */
199
+ export interface StyleUniforms {
200
+ uMode: { value: number };
201
+ uColorA: { value: Color };
202
+ uColorB: { value: Color };
203
+ uColorC: { value: Color };
204
+ uTime: { value: number };
205
+ uHeightMin: { value: number };
206
+ uHeightMax: { value: number };
207
+ uFloorHeight: { value: number };
208
+ uDim: { value: number };
209
+ uDimFactor?: { value: number };
210
+ uSelColor: { value: Color };
211
+ uSelMix: { value: number };
212
+ uSelMode?: { value: number };
213
+ uSelOpacity?: { value: number };
214
+ uSelEmissive?: { value: number };
215
+ uSelElevation?: { value: number };
216
+ uFilterMinZ?: { value: number };
217
+ uFilterMaxZ?: { value: number };
218
+ uFilterHeightActive?: { value: number };
219
+ uRoofThreshold?: { value: number };
220
+ uTexMix?: { value: number };
221
+ [key: string]: { value: unknown } | undefined;
222
+ }
@@ -42,7 +42,9 @@ export interface S3MDatasetEntry {
42
42
  anchor: Anchor | null;
43
43
  /** 语义对齐方式计算出的基础偏移(米) */
44
44
  baseAlignOffset: number;
45
- /** 最终垂直高度偏移(米,含 baseAlignOffset 与附加 heightOffset) */
45
+ /** 应用层设置的额外垂直偏移(米,贴地高程 / 手动微调),与对齐基准相互独立 */
46
+ userOffset: number;
47
+ /** 最终垂直高度偏移(米)= baseAlignOffset + userOffset */
46
48
  heightOffset: number;
47
49
  /** 相对场景锚点的偏移(米) */
48
50
  offset: [number, number, number];
@@ -110,6 +112,7 @@ export class DatasetManager {
110
112
  tileset: null,
111
113
  anchor: null,
112
114
  baseAlignOffset: 0,
115
+ userOffset: ds.heightOffset ?? 0,
113
116
  heightOffset: ds.heightOffset ?? 0,
114
117
  offset: [0, 0, 0],
115
118
  visible: ds.visible !== false,
@@ -152,7 +155,8 @@ export class DatasetManager {
152
155
 
153
156
  entry.anchor = tileset.anchor;
154
157
  entry.baseAlignOffset = this.computeAlignOffset(tileset, ds.align);
155
- entry.heightOffset = entry.baseAlignOffset + (ds.heightOffset ?? 0);
158
+ entry.userOffset = ds.heightOffset ?? 0;
159
+ entry.heightOffset = entry.baseAlignOffset + entry.userOffset;
156
160
  this.layoutDataset(entry, geo);
157
161
  callbacks.onReady(entry);
158
162
  callbacks.triggerRepaint();
@@ -228,31 +232,38 @@ export class DatasetManager {
228
232
  }
229
233
 
230
234
  /**
231
- * 获取指定数据集的垂直高程偏移(米)
235
+ * 获取指定数据集的应用层附加垂直偏移(米,不含 align 基准)
232
236
  */
233
237
  getDatasetHeight(id?: string): number {
234
238
  const targetId = id ?? this.datasets.keys().next().value;
235
- return targetId ? this.datasets.get(targetId)?.heightOffset ?? 0 : 0;
239
+ return targetId ? this.datasets.get(targetId)?.userOffset ?? 0 : 0;
236
240
  }
237
241
 
238
242
  /**
239
- * 设置垂直高程偏移(米)
243
+ * 设置应用层附加垂直偏移(米)
244
+ *
245
+ * 语义为「在当前 align 基准之上再抬升/下沉多少米」,
246
+ * 与 align 基准解耦:贴地(把模型抬到真实地面高程)不会破坏 align 语义。
240
247
  */
241
248
  setDatasetHeight(id: string, height: number, geo: GeoAdapter | null): void {
242
249
  const entry = this.datasets.get(id);
243
250
  if (!entry) return;
244
- entry.heightOffset = height;
251
+ entry.userOffset = height;
252
+ entry.heightOffset = entry.baseAlignOffset + height;
245
253
  this.layoutDataset(entry, geo);
246
254
  }
247
255
 
248
256
  /**
249
257
  * 动态设置指定数据集的垂直对齐基准('origin' | 'bottom' | 'top' | 'center')
258
+ *
259
+ * 只更换 align 基准,应用层附加偏移(userOffset)保持不变。
250
260
  */
251
261
  setDatasetAlign(id: string, align: DatasetAlignment, geo: GeoAdapter | null): void {
252
262
  const entry = this.datasets.get(id);
253
263
  if (!entry) return;
254
264
  const manualOffset = entry.heightOffset - entry.baseAlignOffset;
255
265
  entry.baseAlignOffset = this.computeAlignOffset(entry.tileset, align);
266
+ entry.userOffset = manualOffset;
256
267
  entry.heightOffset = entry.baseAlignOffset + manualOffset;
257
268
  entry.options.align = align;
258
269
  this.layoutDataset(entry, geo);