@kimap/indoor-positioning-sdk-vue2 4.2.0 → 4.2.2
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/package.json +1 -1
- package/src/core/KimapSDK.js +276 -16
- package/src/core/loaders.js +21 -1
package/package.json
CHANGED
package/src/core/KimapSDK.js
CHANGED
|
@@ -10,6 +10,9 @@ var SceneCore = require('./SceneCore.js');
|
|
|
10
10
|
// THREE.js 将在运行时加载
|
|
11
11
|
var THREE = null;
|
|
12
12
|
var loadThree = loaders.loadThree;
|
|
13
|
+
var loadOBJLoader = loaders.loadOBJLoader;
|
|
14
|
+
var loadFBXLoader = loaders.loadFBXLoader;
|
|
15
|
+
var loadGLTFLoader = loaders.loadGLTFLoader;
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
18
|
* KimapSDK 构造函数
|
|
@@ -140,7 +143,98 @@ KimapSDK.prototype.startRenderLoop = function() {
|
|
|
140
143
|
* @private
|
|
141
144
|
*/
|
|
142
145
|
KimapSDK.prototype._extractWallsFromModel = function() {
|
|
143
|
-
|
|
146
|
+
var self = this;
|
|
147
|
+
|
|
148
|
+
if (!self.core || !self.core.mapModel) {
|
|
149
|
+
console.warn('KimapSDK: 3D模型未加载,无法提取墙面数据');
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
var walls = [];
|
|
154
|
+
var floorGroups = {};
|
|
155
|
+
|
|
156
|
+
// 遍历场景中的所有对象,查找墙面
|
|
157
|
+
self.core.mapModel.traverse(function(child) {
|
|
158
|
+
if (child.name && child.name.startsWith('Wall_')) {
|
|
159
|
+
var box = new THREE.Box3().setFromObject(child);
|
|
160
|
+
var min = box.min;
|
|
161
|
+
var max = box.max;
|
|
162
|
+
|
|
163
|
+
var centerX = (min.x + max.x) / 2;
|
|
164
|
+
var centerZ = (min.z + max.z) / 2;
|
|
165
|
+
var width = max.x - min.x;
|
|
166
|
+
var depth = max.z - min.z;
|
|
167
|
+
var height = max.y - min.y;
|
|
168
|
+
|
|
169
|
+
var isHorizontal = width > depth;
|
|
170
|
+
var thickness = isHorizontal ? depth : width;
|
|
171
|
+
|
|
172
|
+
var points;
|
|
173
|
+
if (isHorizontal) {
|
|
174
|
+
points = [
|
|
175
|
+
{ x: min.x * 100, y: centerZ * 100 },
|
|
176
|
+
{ x: max.x * 100, y: centerZ * 100 }
|
|
177
|
+
];
|
|
178
|
+
} else {
|
|
179
|
+
points = [
|
|
180
|
+
{ x: centerX * 100, y: min.z * 100 },
|
|
181
|
+
{ x: centerX * 100, y: max.z * 100 }
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
var floorLevel = Math.floor(min.y / 3);
|
|
186
|
+
|
|
187
|
+
var wallData = {
|
|
188
|
+
type: 'wall',
|
|
189
|
+
id: child.name,
|
|
190
|
+
visible: true,
|
|
191
|
+
passable: false,
|
|
192
|
+
points: points,
|
|
193
|
+
thickness: thickness * 1000,
|
|
194
|
+
height: height * 1000,
|
|
195
|
+
floorLevel: floorLevel
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
walls.push(wallData);
|
|
199
|
+
|
|
200
|
+
if (!floorGroups[floorLevel]) {
|
|
201
|
+
floorGroups[floorLevel] = [];
|
|
202
|
+
}
|
|
203
|
+
floorGroups[floorLevel].push(wallData);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
console.log('✅ 从3D模型中提取墙面数据:', walls.length, '个墙面');
|
|
208
|
+
|
|
209
|
+
var floors = [];
|
|
210
|
+
Object.keys(floorGroups).sort().forEach(function(level) {
|
|
211
|
+
var floorId = 'floor_' + level;
|
|
212
|
+
var floorName = (parseInt(level) + 1) + '楼';
|
|
213
|
+
|
|
214
|
+
floors.push({
|
|
215
|
+
id: floorId,
|
|
216
|
+
name: floorName,
|
|
217
|
+
level: parseInt(level),
|
|
218
|
+
height: 3000,
|
|
219
|
+
elevation: parseInt(level) * 3000,
|
|
220
|
+
isDefault: level === '0',
|
|
221
|
+
layers: [
|
|
222
|
+
{
|
|
223
|
+
id: floorId + '_layer_walls',
|
|
224
|
+
name: '墙体图层',
|
|
225
|
+
visible: true,
|
|
226
|
+
elements: floorGroups[level]
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
if (floors.length > 0) {
|
|
233
|
+
self.setFloors(floors);
|
|
234
|
+
console.log('✅ 已自动设置楼层数据(从3D模型提取)');
|
|
235
|
+
} else {
|
|
236
|
+
console.warn('⚠️ 未从3D模型中提取到墙面数据');
|
|
237
|
+
}
|
|
144
238
|
};
|
|
145
239
|
|
|
146
240
|
// ==================== DOM 标记相关方法 ====================
|
|
@@ -306,19 +400,7 @@ KimapSDK.prototype.getDrawPoints = function() {
|
|
|
306
400
|
};
|
|
307
401
|
|
|
308
402
|
// ==================== 3D 模型加载相关方法 ====================
|
|
309
|
-
//
|
|
310
|
-
// 为了保持文件精简,这里只保留核心方法签名
|
|
311
|
-
// 完整实现请参考原 KimapCore.js 文件
|
|
312
|
-
|
|
313
|
-
KimapSDK.prototype.loadKidata = function(kidataUrl) {
|
|
314
|
-
// 实现:加载 kidata 文件
|
|
315
|
-
// 原代码约 200 行
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
KimapSDK.prototype._loadFurnitureModels = function() {
|
|
319
|
-
// 实现:加载家具 3D 模型
|
|
320
|
-
// 原代码约 150 行
|
|
321
|
-
};
|
|
403
|
+
// loadKidata 和 _loadFurnitureModels 的完整实现在文件后面部分
|
|
322
404
|
|
|
323
405
|
// ==================== 楼层管理相关方法 ====================
|
|
324
406
|
|
|
@@ -671,10 +753,188 @@ KimapSDK.prototype._loadFurnitureModels = function(kidataObj) {
|
|
|
671
753
|
this.core.scene.add(this.furnitureGroup);
|
|
672
754
|
}
|
|
673
755
|
|
|
756
|
+
// 清空现有家具
|
|
757
|
+
while (this.furnitureGroup.children.length > 0) {
|
|
758
|
+
var child = this.furnitureGroup.children[0];
|
|
759
|
+
this.furnitureGroup.remove(child);
|
|
760
|
+
|
|
761
|
+
// 释放资源
|
|
762
|
+
if (child.geometry) child.geometry.dispose();
|
|
763
|
+
if (child.material) {
|
|
764
|
+
if (Array.isArray(child.material)) {
|
|
765
|
+
child.material.forEach(function(m) { m.dispose(); });
|
|
766
|
+
} else {
|
|
767
|
+
child.material.dispose();
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// 优先使用dataUrl,如果不存在则使用serverUrl(兼容旧版本)
|
|
773
|
+
var serverUrl = kidataObj.dataUrl || kidataObj.serverUrl;
|
|
774
|
+
var loadPromises = [];
|
|
775
|
+
var loadedCount = 0;
|
|
776
|
+
var failedCount = 0;
|
|
777
|
+
|
|
674
778
|
console.log('📦 开始加载', kidataObj.furnitures.length, '个家具模型');
|
|
675
779
|
|
|
676
|
-
//
|
|
677
|
-
|
|
780
|
+
// 加载每个家具模型
|
|
781
|
+
kidataObj.furnitures.forEach(function(furniture) {
|
|
782
|
+
var promise = self._loadSingleFurniture(furniture, serverUrl)
|
|
783
|
+
.then(function(mesh) {
|
|
784
|
+
if (mesh) {
|
|
785
|
+
self.furnitureGroup.add(mesh);
|
|
786
|
+
loadedCount++;
|
|
787
|
+
} else {
|
|
788
|
+
failedCount++;
|
|
789
|
+
}
|
|
790
|
+
})
|
|
791
|
+
.catch(function(error) {
|
|
792
|
+
console.error('加载家具模型失败:', furniture.type, error);
|
|
793
|
+
failedCount++;
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
loadPromises.push(promise);
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
return Promise.all(loadPromises).then(function() {
|
|
800
|
+
return { loaded: loadedCount, failed: failedCount };
|
|
801
|
+
});
|
|
802
|
+
};
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* 加载单个家具模型
|
|
806
|
+
* @private
|
|
807
|
+
* @param {Object} furniture - 家具数据
|
|
808
|
+
* @param {string} serverUrl - 模型服务器URL
|
|
809
|
+
* @returns {Promise<THREE.Object3D>} 返回加载的模型对象
|
|
810
|
+
*/
|
|
811
|
+
KimapSDK.prototype._loadSingleFurniture = function(furniture, serverUrl) {
|
|
812
|
+
var self = this;
|
|
813
|
+
|
|
814
|
+
return new Promise(function(resolve, reject) {
|
|
815
|
+
// 构建模型URL
|
|
816
|
+
var baseUrl = serverUrl || self.dataUrl;
|
|
817
|
+
|
|
818
|
+
// 从 id 中解析扩展名
|
|
819
|
+
var rawId = furniture.id || '';
|
|
820
|
+
var ext = '.obj';
|
|
821
|
+
var id = rawId;
|
|
822
|
+
|
|
823
|
+
if (typeof rawId === 'string') {
|
|
824
|
+
var dotIndex = rawId.lastIndexOf('.');
|
|
825
|
+
if (dotIndex >= 0) {
|
|
826
|
+
ext = rawId.substring(dotIndex).toLowerCase();
|
|
827
|
+
id = rawId.substring(0, dotIndex);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
var modelUrl;
|
|
832
|
+
var loaderPromise;
|
|
833
|
+
|
|
834
|
+
// 根据文件扩展名选择合适的loader
|
|
835
|
+
if (ext === '.fbx') {
|
|
836
|
+
modelUrl = baseUrl + '/' + furniture.type + '/' + id + ext;
|
|
837
|
+
loaderPromise = loadFBXLoader().then(function(FBXLoader) {
|
|
838
|
+
return new FBXLoader();
|
|
839
|
+
});
|
|
840
|
+
} else if (ext === '.glb' || ext === '.gltf') {
|
|
841
|
+
modelUrl = baseUrl + '/' + furniture.type + '/' + id + ext;
|
|
842
|
+
loaderPromise = loadGLTFLoader().then(function(GLTFLoader) {
|
|
843
|
+
return new GLTFLoader();
|
|
844
|
+
});
|
|
845
|
+
} else {
|
|
846
|
+
// 默认使用OBJ格式
|
|
847
|
+
modelUrl = baseUrl + '/' + furniture.type + '/' + id + '.obj';
|
|
848
|
+
loaderPromise = loadOBJLoader().then(function(OBJLoader) {
|
|
849
|
+
return new OBJLoader();
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// 等待loader加载完成后再加载模型
|
|
854
|
+
loaderPromise.then(function(loader) {
|
|
855
|
+
loader.load(
|
|
856
|
+
modelUrl,
|
|
857
|
+
function(result) {
|
|
858
|
+
// GLTF/GLB格式返回的是gltf对象,需要提取scene
|
|
859
|
+
var obj = (ext === '.glb' || ext === '.gltf') ? result.scene : result;
|
|
860
|
+
// 应用旋转
|
|
861
|
+
obj.rotation.set(
|
|
862
|
+
furniture.rotation.x,
|
|
863
|
+
furniture.rotation.y,
|
|
864
|
+
furniture.rotation.z
|
|
865
|
+
);
|
|
866
|
+
|
|
867
|
+
// 应用缩放
|
|
868
|
+
if (furniture.targetSize) {
|
|
869
|
+
// 计算模型的边界框
|
|
870
|
+
var box = new THREE.Box3().setFromObject(obj);
|
|
871
|
+
var size = new THREE.Vector3();
|
|
872
|
+
box.getSize(size);
|
|
873
|
+
|
|
874
|
+
// 计算归一化缩放因子
|
|
875
|
+
var scaleX = size.x > 0 ? furniture.targetSize.width / size.x : 1;
|
|
876
|
+
var scaleY = size.y > 0 ? furniture.targetSize.height / size.y : 1;
|
|
877
|
+
var scaleZ = size.z > 0 ? furniture.targetSize.depth / size.z : 1;
|
|
878
|
+
var uniformScale = (scaleX + scaleY + scaleZ) / 3;
|
|
879
|
+
|
|
880
|
+
// 应用归一化缩放和用户缩放
|
|
881
|
+
var finalScale = uniformScale * furniture.scale.x;
|
|
882
|
+
obj.scale.set(finalScale, finalScale, finalScale);
|
|
883
|
+
} else {
|
|
884
|
+
// 兼容旧版本kidata,直接使用scale值
|
|
885
|
+
obj.scale.set(
|
|
886
|
+
furniture.scale.x,
|
|
887
|
+
furniture.scale.y,
|
|
888
|
+
furniture.scale.z
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// 应用颜色(如果有)
|
|
893
|
+
if (furniture.color) {
|
|
894
|
+
var color = new THREE.Color(furniture.color);
|
|
895
|
+
obj.traverse(function(child) {
|
|
896
|
+
if (child instanceof THREE.Mesh) {
|
|
897
|
+
if (Array.isArray(child.material)) {
|
|
898
|
+
child.material.forEach(function(mat) {
|
|
899
|
+
if (mat.color) mat.color.copy(color);
|
|
900
|
+
});
|
|
901
|
+
} else if (child.material && child.material.color) {
|
|
902
|
+
child.material.color.copy(color);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// 重新计算边界框,将模型底部对齐到地面
|
|
909
|
+
var scaledBox = new THREE.Box3().setFromObject(obj);
|
|
910
|
+
var bottomOffset = -scaledBox.min.y;
|
|
911
|
+
|
|
912
|
+
// 应用位置(包含底部对齐偏移)
|
|
913
|
+
obj.position.set(
|
|
914
|
+
furniture.position.x,
|
|
915
|
+
furniture.position.y + bottomOffset,
|
|
916
|
+
furniture.position.z
|
|
917
|
+
);
|
|
918
|
+
|
|
919
|
+
obj.userData = {
|
|
920
|
+
type: 'furniture',
|
|
921
|
+
furnitureId: furniture.id,
|
|
922
|
+
furnitureType: furniture.type
|
|
923
|
+
};
|
|
924
|
+
|
|
925
|
+
resolve(obj);
|
|
926
|
+
},
|
|
927
|
+
undefined,
|
|
928
|
+
function(error) {
|
|
929
|
+
console.error('❌ 家具模型加载失败:', furniture.type, error);
|
|
930
|
+
reject(error);
|
|
931
|
+
}
|
|
932
|
+
);
|
|
933
|
+
}).catch(function(error) {
|
|
934
|
+
console.error('❌ 加载家具模型loader失败:', furniture.type, error);
|
|
935
|
+
reject(error);
|
|
936
|
+
});
|
|
937
|
+
});
|
|
678
938
|
};
|
|
679
939
|
|
|
680
940
|
/**
|
package/src/core/loaders.js
CHANGED
|
@@ -108,11 +108,31 @@ function loadMTLLoader() {
|
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* 加载GLTFLoader
|
|
113
|
+
*/
|
|
114
|
+
function loadGLTFLoader() {
|
|
115
|
+
return new Promise(function(resolve, reject) {
|
|
116
|
+
if (!THREE) {
|
|
117
|
+
reject(new Error('Three.js未初始化,请先调用loadThree()'));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
var module = require('three/examples/jsm/loaders/GLTFLoader.js');
|
|
123
|
+
resolve(module.GLTFLoader);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
reject(new Error('Failed to load GLTFLoader: ' + error.message));
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
111
130
|
module.exports = {
|
|
112
131
|
setThreeInstance: setThreeInstance,
|
|
113
132
|
loadThree: loadThree,
|
|
114
133
|
loadOrbitControls: loadOrbitControls,
|
|
115
134
|
loadOBJLoader: loadOBJLoader,
|
|
116
135
|
loadFBXLoader: loadFBXLoader,
|
|
117
|
-
loadMTLLoader: loadMTLLoader
|
|
136
|
+
loadMTLLoader: loadMTLLoader,
|
|
137
|
+
loadGLTFLoader: loadGLTFLoader
|
|
118
138
|
};
|