@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kimap/indoor-positioning-sdk-vue2",
3
- "version": "4.2.0",
3
+ "version": "4.2.2",
4
4
  "description": "Vue2自包含室内定位SDK - 完全兼容Webpack3+Babel6 | Vue2 Self-Contained Indoor Positioning SDK",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -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
- // 注意:这部分代码较长,包含 kidata 加载、家具模型加载等
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
- return Promise.resolve({ loaded: 0, failed: 0, message: '家具加载功能需要完整实现' });
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
  /**
@@ -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
  };