|
6 | 6 | // @description:zh-CN GeoFS 的 GLTF 模型导入工具 |
7 | 7 | // @description:zh-TW GeoFS 的 GLTF 模型匯入工具 |
8 | 8 | // @namespace https://github.com/GeofsExplorer/GeoFS-Model-Importer |
9 | | -// @version 1.0.1 |
| 9 | +// @version 1.0.4 |
10 | 10 | // @author GeofsExplorer and 31124呀 |
11 | 11 | // @match https://www.geo-fs.com/geofs.php?v=3.9 |
12 | 12 | // @match https://geo-fs.com/geofs.php* |
|
26 | 26 | this.placedModels = []; |
27 | 27 | this.isDraggingUI = false; |
28 | 28 | this.dragOffset = { x: 0, y: 0 }; |
| 29 | + this.currentAircraftModel = null; |
| 30 | + this.showCenterOfMass = true; |
| 31 | + this.aircraftModelUpdateHandler = null; |
29 | 32 | this.init(); |
30 | 33 | } |
31 | 34 |
|
|
98 | 101 | style="width: 100%; min-width: 100%; max-width: 100%; padding: 8px; height: 32px; border: 1px solid #555; border-radius: 4px; background: #222; color: white; font-size: 12px; box-sizing: border-box; overflow: hidden;"> |
99 | 102 | </div> |
100 | 103 |
|
| 104 | + <div style="margin-bottom: 15px;"> |
| 105 | + <label style="display: flex; align-items: center; gap: 8px; font-size: 12px; cursor: pointer;"> |
| 106 | + <input type="checkbox" id="show-center-of-mass" checked> |
| 107 | + Show Center of Mass Marker |
| 108 | + </label> |
| 109 | + </div> |
| 110 | +
|
101 | 111 | <div style="display: flex; gap: 8px;"> |
102 | 112 | <button id="place-model-btn" style="flex: 1; padding: 8px; border: none; border-radius: 3px; background: #2d5aa0; color: white; font-size: 11px; cursor: pointer;"> |
103 | 113 | Place Here |
|
106 | 116 | Use as Aircraft |
107 | 117 | </button> |
108 | 118 | </div> |
| 119 | +
|
| 120 | + <div style="margin-top: 15px; padding: 10px; background: rgba(255,255,255,0.05); border-radius: 3px;"> |
| 121 | + <div style="font-size: 11px; color: #aaa;"> |
| 122 | + <strong>Note:</strong> Placing a new model or using as aircraft will remove previous ones. |
| 123 | + </div> |
| 124 | + </div> |
109 | 125 | </div> |
110 | 126 | `; |
111 | 127 | document.body.appendChild(controlPanel); |
|
136 | 152 | this.updateScaleValue(value); |
137 | 153 | }); |
138 | 154 |
|
| 155 | + const centerOfMassCheckbox = document.getElementById("show-center-of-mass"); |
| 156 | + centerOfMassCheckbox.addEventListener('change', (e) => { |
| 157 | + this.showCenterOfMass = e.target.checked; |
| 158 | + this.updateAllCenterOfMassMarkers(); |
| 159 | + }); |
| 160 | + |
139 | 161 | document.getElementById("place-model-btn").onclick = () => this.place3DModel(); |
140 | 162 | document.getElementById("use-as-aircraft-btn").onclick = () => this.replaceAircraftModel(); |
141 | 163 |
|
|
160 | 182 | this.placedModels.forEach(model => { |
161 | 183 | this.adjustModelScale(model.entity, this.scaleValue); |
162 | 184 | }); |
| 185 | + |
| 186 | + if (this.currentAircraftModel) { |
| 187 | + this.updateAircraftModelScale(); |
| 188 | + } |
163 | 189 | } |
164 | 190 |
|
165 | 191 | adjustModelScale(modelEntity, scale) { |
|
171 | 197 | } |
172 | 198 | } |
173 | 199 |
|
| 200 | + createCenterOfMassMarker(position) { |
| 201 | + if (!this.showCenterOfMass) return null; |
| 202 | + |
| 203 | + try { |
| 204 | + return window.geofs.api.viewer.entities.add({ |
| 205 | + position: position, |
| 206 | + point: { |
| 207 | + pixelSize: 8, |
| 208 | + color: window.Cesium.Color.RED, |
| 209 | + outlineColor: window.Cesium.Color.WHITE, |
| 210 | + outlineWidth: 2, |
| 211 | + heightReference: window.Cesium.HeightReference.NONE, |
| 212 | + disableDepthTestDistance: Number.POSITIVE_INFINITY |
| 213 | + }, |
| 214 | + label: { |
| 215 | + text: "Center of Mass", |
| 216 | + font: "12pt Arial", |
| 217 | + pixelOffset: new window.Cesium.Cartesian2(0, -20), |
| 218 | + fillColor: window.Cesium.Color.WHITE, |
| 219 | + outlineColor: window.Cesium.Color.BLACK, |
| 220 | + outlineWidth: 2, |
| 221 | + showBackground: true, |
| 222 | + backgroundColor: new window.Cesium.Color(0.1, 0.1, 0.1, 0.7), |
| 223 | + verticalOrigin: window.Cesium.VerticalOrigin.BOTTOM, |
| 224 | + heightReference: window.Cesium.HeightReference.NONE |
| 225 | + } |
| 226 | + }); |
| 227 | + } catch(error) { |
| 228 | + console.warn('Failed to create center of mass marker:', error); |
| 229 | + return null; |
| 230 | + } |
| 231 | + } |
| 232 | + |
| 233 | + updateAllCenterOfMassMarkers() { |
| 234 | + this.placedModels.forEach(model => { |
| 235 | + if (model.centerOfMassMarker) { |
| 236 | + model.centerOfMassMarker.show = this.showCenterOfMass; |
| 237 | + } |
| 238 | + }); |
| 239 | + } |
| 240 | + |
| 241 | + removeAllPlacedModels() { |
| 242 | + this.placedModels.forEach(model => { |
| 243 | + try { |
| 244 | + window.geofs.api.viewer.entities.remove(model.entity); |
| 245 | + if (model.centerOfMassMarker) { |
| 246 | + window.geofs.api.viewer.entities.remove(model.centerOfMassMarker); |
| 247 | + } |
| 248 | + } catch(error) { |
| 249 | + console.warn('Failed to remove model:', error); |
| 250 | + } |
| 251 | + }); |
| 252 | + this.placedModels = []; |
| 253 | + } |
| 254 | + |
| 255 | + removeAircraftModel() { |
| 256 | + if (this.currentAircraftModel) { |
| 257 | + try { |
| 258 | + if (this.aircraftModelUpdateHandler) { |
| 259 | + window.geofs.api.viewer.scene.preRender.removeEventListener(this.aircraftModelUpdateHandler); |
| 260 | + this.aircraftModelUpdateHandler = null; |
| 261 | + } |
| 262 | + |
| 263 | + if (window.geofs && window.geofs.aircraft && window.geofs.aircraft.instance) { |
| 264 | + window.geofs.aircraft.instance.setVisibility(1); |
| 265 | + } |
| 266 | + |
| 267 | + try { |
| 268 | + if (typeof this.currentAircraftModel.destroy === 'function') { |
| 269 | + this.currentAircraftModel.destroy(); |
| 270 | + } |
| 271 | + } catch(e) { |
| 272 | + console.warn('Cannot destroy aircraft model, but it will be replaced:', e); |
| 273 | + } |
| 274 | + |
| 275 | + this.currentAircraftModel = null; |
| 276 | + } catch(error) { |
| 277 | + console.warn('Failed to remove aircraft model:', error); |
| 278 | + } |
| 279 | + } |
| 280 | + } |
| 281 | + |
| 282 | + removeAllModels() { |
| 283 | + this.removeAllPlacedModels(); |
| 284 | + this.removeAircraftModel(); |
| 285 | + } |
| 286 | + |
174 | 287 | startDragging(event) { |
175 | 288 | this.isDraggingUI = true; |
176 | 289 | this.dragOffset.initialX = event.clientX - this.dragOffset.x; |
|
248 | 361 | } |
249 | 362 |
|
250 | 363 | try { |
| 364 | + this.removeAllModels(); |
| 365 | + |
251 | 366 | const modelDataURL = await this.convertFileToDataURL(selectedFile); |
252 | 367 | const aircraft = window.geofs.aircraft.instance; |
253 | 368 | const groundPosition = window.geofs.getGroundAltitude(aircraft.llaLocation).location; |
|
270 | 385 | } |
271 | 386 | }); |
272 | 387 |
|
| 388 | + const centerOfMassMarker = this.createCenterOfMassMarker(worldPosition); |
| 389 | + |
273 | 390 | const modelData = { |
274 | 391 | entity: modelEntity, |
| 392 | + centerOfMassMarker: centerOfMassMarker, |
275 | 393 | scale: this.scaleValue |
276 | 394 | }; |
277 | 395 | this.placedModels.push(modelData); |
278 | 396 |
|
279 | | - this.setupModelTracking(modelData); |
280 | | - this.showMessage("Model placed successfully! Congratulations!"); |
| 397 | + this.showMessage("Model placed successfully! Previous models have been removed."); |
281 | 398 | this.controlPanel.style.display = 'none'; |
282 | 399 | } catch (error) { |
283 | 400 | this.showMessage("Error placing model: " + error.message); |
|
299 | 416 | } |
300 | 417 |
|
301 | 418 | try { |
| 419 | + this.removeAllModels(); |
| 420 | + |
302 | 421 | const modelDataURL = await this.convertFileToDataURL(selectedFile); |
303 | 422 | const aircraft = window.geofs.aircraft.instance; |
304 | 423 |
|
305 | | - const customModel = new window.geofs.api.Model(null, { |
| 424 | + this.currentAircraftModel = new window.geofs.api.Model(null, { |
306 | 425 | url: modelDataURL, |
307 | 426 | location: aircraft.llaLocation, |
308 | 427 | rotation: aircraft.htr |
309 | 428 | }); |
310 | 429 |
|
311 | | - const updateHandler = () => { |
312 | | - try { |
313 | | - const currentAircraft = window.geofs.aircraft.instance; |
314 | | - customModel.setPositionOrientationAndScale( |
315 | | - currentAircraft.llaLocation, |
316 | | - currentAircraft.htr, |
317 | | - this.scaleValue |
318 | | - ); |
319 | | - currentAircraft.setVisibility(0); |
320 | | - } catch(error) { |
321 | | - console.warn('Aircraft model update failed:', error); |
322 | | - } |
323 | | - }; |
324 | | - |
325 | | - window.geofs.api.viewer.scene.preRender.addEventListener(updateHandler); |
326 | | - this.showMessage("Aircraft model replaced!"); |
| 430 | + this.setupAircraftModelTracking(); |
| 431 | + this.showMessage("Aircraft model replaced! Previous models have been removed."); |
327 | 432 | this.controlPanel.style.display = 'none'; |
328 | 433 | } catch (error) { |
329 | 434 | this.showMessage("Error replacing aircraft: " + error.message); |
330 | 435 | } |
331 | 436 | } |
332 | 437 |
|
333 | | - setupModelTracking(modelData) { |
334 | | - const updateProcedure = () => { |
| 438 | + setupAircraftModelTracking() { |
| 439 | + if (this.aircraftModelUpdateHandler) { |
| 440 | + window.geofs.api.viewer.scene.preRender.removeEventListener(this.aircraftModelUpdateHandler); |
| 441 | + } |
| 442 | + |
| 443 | + this.aircraftModelUpdateHandler = () => { |
335 | 444 | try { |
336 | | - const aircraft = window.geofs.aircraft.instance; |
337 | | - const position = aircraft.llaLocation; |
338 | | - const rotation = aircraft.htr || aircraft.hpr || [0, 0, 0]; |
339 | | - |
340 | | - const worldPos = window.Cesium.Cartesian3.fromDegrees( |
341 | | - position[1], |
342 | | - position[0], |
343 | | - position[2] |
344 | | - ); |
345 | | - |
346 | | - modelData.entity.position = worldPos; |
347 | | - modelData.entity.orientation = window.Cesium.Transforms.headingPitchRollQuaternion( |
348 | | - worldPos, |
349 | | - new window.Cesium.HeadingPitchRoll(rotation[0], rotation[1], rotation[2]) |
350 | | - ); |
351 | | - this.adjustModelScale(modelData.entity, modelData.scale); |
| 445 | + const currentAircraft = window.geofs.aircraft.instance; |
| 446 | + if (this.currentAircraftModel) { |
| 447 | + this.currentAircraftModel.setPositionOrientationAndScale( |
| 448 | + currentAircraft.llaLocation, |
| 449 | + currentAircraft.htr, |
| 450 | + this.scaleValue |
| 451 | + ); |
| 452 | + currentAircraft.setVisibility(0); |
| 453 | + } |
352 | 454 | } catch(error) { |
353 | | - console.warn('Model tracking update failed:', error); |
| 455 | + console.warn('Aircraft model update failed:', error); |
354 | 456 | } |
355 | 457 | }; |
356 | 458 |
|
357 | | - window.geofs.api.viewer.scene.preRender.addEventListener(updateProcedure); |
| 459 | + window.geofs.api.viewer.scene.preRender.addEventListener(this.aircraftModelUpdateHandler); |
| 460 | + } |
| 461 | + |
| 462 | + updateAircraftModelScale() { |
358 | 463 | } |
359 | 464 |
|
360 | 465 | checkGeoFSReady() { |
|
0 commit comments