@mapless/core 1.0.7 → 1.0.12
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/dist/index.js +822 -36
- package/dist/types/Mapless/Base.d.ts +5 -0
- package/dist/types/Mapless/Base.d.ts.map +1 -1
- package/dist/types/Mapless/mana/movable.d.ts +19 -3
- package/dist/types/Mapless/mana/movable.d.ts.map +1 -1
- package/dist/types/Mapless/mana-3d/airspace.d.ts +14 -0
- package/dist/types/Mapless/mana-3d/airspace.d.ts.map +1 -1
- package/dist/types/Mapless/mana-3d/elevatedLine.d.ts.map +1 -1
- package/dist/types/Mapless/mana-3d/mapModel.d.ts +27 -0
- package/dist/types/Mapless/mana-3d/mapModel.d.ts.map +1 -1
- package/dist/types/Mapless/mana-three/basicObject.d.ts +4 -0
- package/dist/types/Mapless/mana-three/basicObject.d.ts.map +1 -1
- package/dist/types/Mapless/mana-three/curve3d.d.ts +4 -0
- package/dist/types/Mapless/mana-three/curve3d.d.ts.map +1 -1
- package/dist/types/Mapless/mana-three/index.d.ts +2 -1
- package/dist/types/Mapless/mana-three/index.d.ts.map +1 -1
- package/dist/types/Mapless/mana-three/instancedModel.d.ts +158 -0
- package/dist/types/Mapless/mana-three/instancedModel.d.ts.map +1 -0
- package/dist/types/Mapless/mana-three/line2Manager.d.ts +4 -0
- package/dist/types/Mapless/mana-three/line2Manager.d.ts.map +1 -1
- package/dist/types/Mapless/mana-three/model.d.ts +5 -0
- package/dist/types/Mapless/mana-three/model.d.ts.map +1 -1
- package/dist/types/Mapless/mana-three/three.d.ts +18 -1
- package/dist/types/Mapless/mana-three/three.d.ts.map +1 -1
- package/dist/types/Mapless/types.d.ts +20 -0
- package/dist/types/Mapless/types.d.ts.map +1 -1
- package/dist/types/Three/MapThree.d.ts +39 -0
- package/dist/types/Three/MapThree.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { area as turf_area, center as turf_center, centroid, circle, distance as turf_distance, ellipse, length as turf_length, pointsWithinPolygon, polygon as turf_polygon } from "@turf/turf";
|
|
2
2
|
import mapbox_gl, { LngLat, MapMouseEvent, Marker, MercatorCoordinate, Popup } from "mapbox-gl";
|
|
3
|
-
import { AmbientLight, AnimationMixer, BoxGeometry, BoxHelper, BufferGeometry, CatmullRomCurve3, Clock, Color, ConeGeometry, CurvePath, CylinderGeometry, DirectionalLight, DoubleSide, Group, Line, LineBasicMaterial, LineCurve3, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, PerspectiveCamera, PointLight, Scene, SphereGeometry, SpotLight, TorusGeometry, TubeGeometry, Vector3, WebGLRenderer } from "three";
|
|
3
|
+
import { AmbientLight, AnimationMixer, BoxGeometry, BoxHelper, BufferGeometry, CatmullRomCurve3, Clock, Color, ConeGeometry, CurvePath, CylinderGeometry, DirectionalLight, DoubleSide, Group, InstancedMesh, Line, LineBasicMaterial, LineCurve3, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, Object3D, PerspectiveCamera, PointLight, Raycaster, Scene, SphereGeometry, SpotLight, TorusGeometry, TubeGeometry, Vector3, Vector4, WebGLRenderer } from "three";
|
|
4
4
|
import gcoord from "gcoord";
|
|
5
5
|
import mapbox_gl_draw from "@mapbox/mapbox-gl-draw";
|
|
6
6
|
import "@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css";
|
|
7
|
+
import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js";
|
|
7
8
|
import { GLTFLoader, Line2, LineGeometry, LineMaterial } from "three-stdlib";
|
|
8
9
|
class MapThree {
|
|
9
10
|
mapless = void 0;
|
|
@@ -16,6 +17,7 @@ class MapThree {
|
|
|
16
17
|
renderableObjects = new Map();
|
|
17
18
|
isInitialized = false;
|
|
18
19
|
customLayerId = null;
|
|
20
|
+
lastProjectionMatrix = null;
|
|
19
21
|
constructor(props){
|
|
20
22
|
const { mapless } = props;
|
|
21
23
|
this.mapless = mapless;
|
|
@@ -54,6 +56,7 @@ class MapThree {
|
|
|
54
56
|
renderableObj.mesh.visible = false;
|
|
55
57
|
});
|
|
56
58
|
this.camera.projectionMatrix = m;
|
|
59
|
+
this.lastProjectionMatrix = m.clone();
|
|
57
60
|
this.renderer.resetState();
|
|
58
61
|
this.renderer.render(this.scene, this.camera);
|
|
59
62
|
this.renderableObjects.forEach((renderableObj)=>{
|
|
@@ -317,6 +320,140 @@ class MapThree {
|
|
|
317
320
|
this.removeRenderableObject(id);
|
|
318
321
|
});
|
|
319
322
|
}
|
|
323
|
+
raycast(point, objects, tolerance = 30) {
|
|
324
|
+
if (!this.camera || !this.scene || !this.renderer) return null;
|
|
325
|
+
const map = this.mapless?.map;
|
|
326
|
+
if (!map) return null;
|
|
327
|
+
const mapContainer = map.getCanvas();
|
|
328
|
+
const ndcX = point.x / mapContainer.width * 2 - 1;
|
|
329
|
+
const ndcY = 2 * -(point.y / mapContainer.height) + 1;
|
|
330
|
+
const targetObjects = objects || Array.from(this.renderableObjects.values()).map((obj)=>obj.mesh);
|
|
331
|
+
let closestHit = null;
|
|
332
|
+
let minDistance = 1 / 0;
|
|
333
|
+
const screenPositions = new Map();
|
|
334
|
+
for (const targetObj of targetObjects){
|
|
335
|
+
const renderableObj = Array.from(this.renderableObjects.values()).find((obj)=>obj.mesh === targetObj);
|
|
336
|
+
if (renderableObj && this.lastProjectionMatrix) {
|
|
337
|
+
let l;
|
|
338
|
+
if (renderableObj.transform.matrix) l = renderableObj.transform.matrix.clone();
|
|
339
|
+
else {
|
|
340
|
+
l = new Matrix4().makeTranslation(renderableObj.transform.translateX, renderableObj.transform.translateY, renderableObj.transform.translateZ).scale(new Vector3(renderableObj.transform.scale, -renderableObj.transform.scale, renderableObj.transform.scale));
|
|
341
|
+
if (void 0 !== renderableObj.transform.rotateX || void 0 !== renderableObj.transform.rotateY || void 0 !== renderableObj.transform.rotateZ) {
|
|
342
|
+
const rotationX = new Matrix4().makeRotationAxis(new Vector3(1, 0, 0), renderableObj.transform.rotateX || 0);
|
|
343
|
+
const rotationY = new Matrix4().makeRotationAxis(new Vector3(0, 1, 0), renderableObj.transform.rotateY || 0);
|
|
344
|
+
const rotationZ = new Matrix4().makeRotationAxis(new Vector3(0, 0, 1), renderableObj.transform.rotateZ || 0);
|
|
345
|
+
l.multiply(rotationX).multiply(rotationY).multiply(rotationZ);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
const mvpMatrix = this.lastProjectionMatrix.clone().multiply(l);
|
|
349
|
+
const inverseMVP = mvpMatrix.invert();
|
|
350
|
+
const nearPoint = new Vector4(ndcX, ndcY, -1, 1).applyMatrix4(inverseMVP);
|
|
351
|
+
nearPoint.divideScalar(nearPoint.w);
|
|
352
|
+
const farPoint = new Vector4(ndcX, ndcY, 1, 1).applyMatrix4(inverseMVP);
|
|
353
|
+
farPoint.divideScalar(farPoint.w);
|
|
354
|
+
const origin = new Vector3(nearPoint.x, nearPoint.y, nearPoint.z);
|
|
355
|
+
const direction = new Vector3(farPoint.x - nearPoint.x, farPoint.y - nearPoint.y, farPoint.z - nearPoint.z).normalize();
|
|
356
|
+
const raycaster = new Raycaster(origin, direction);
|
|
357
|
+
const intersects = raycaster.intersectObject(targetObj, true);
|
|
358
|
+
const centerPoint = new Vector4(0, 0, 0, 1).applyMatrix4(mvpMatrix);
|
|
359
|
+
const screenX = (centerPoint.x / centerPoint.w + 1) * 0.5 * mapContainer.width;
|
|
360
|
+
const screenY = (-centerPoint.y / centerPoint.w + 1) * 0.5 * mapContainer.height;
|
|
361
|
+
const depth = centerPoint.z / centerPoint.w;
|
|
362
|
+
const scale = renderableObj.transform.scale;
|
|
363
|
+
const screenRadius = 50 * scale / Math.abs(depth);
|
|
364
|
+
screenPositions.set(targetObj, {
|
|
365
|
+
x: screenX,
|
|
366
|
+
y: screenY,
|
|
367
|
+
radius: screenRadius
|
|
368
|
+
});
|
|
369
|
+
if (intersects.length > 0 && intersects[0].distance < minDistance) {
|
|
370
|
+
minDistance = intersects[0].distance;
|
|
371
|
+
closestHit = {
|
|
372
|
+
object: intersects[0].object,
|
|
373
|
+
distance: intersects[0].distance,
|
|
374
|
+
point: intersects[0].point
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (!closestHit) for (const [obj, screenPos] of screenPositions){
|
|
380
|
+
const dx = screenPos.x - point.x;
|
|
381
|
+
const dy = screenPos.y - point.y;
|
|
382
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
383
|
+
if (distance < Math.max(screenPos.radius, tolerance)) return {
|
|
384
|
+
object: obj,
|
|
385
|
+
distance: 0,
|
|
386
|
+
point: new Vector3()
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
return closestHit;
|
|
390
|
+
}
|
|
391
|
+
registerRenderableObjectClick(id, onClick, tolerance = 30) {
|
|
392
|
+
const renderableObj = this.renderableObjects.get(id);
|
|
393
|
+
if (!renderableObj) {
|
|
394
|
+
console.warn(`RenderableObject with id "${id}" not found`);
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
const map = this.mapless?.map;
|
|
398
|
+
if (!map) {
|
|
399
|
+
console.warn('Map not initialized');
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
const handleClick = (e)=>{
|
|
403
|
+
map.triggerRepaint();
|
|
404
|
+
requestAnimationFrame(()=>{
|
|
405
|
+
const point = {
|
|
406
|
+
x: e.point.x,
|
|
407
|
+
y: e.point.y
|
|
408
|
+
};
|
|
409
|
+
const hit = this.raycast(point, [
|
|
410
|
+
renderableObj.mesh
|
|
411
|
+
], tolerance);
|
|
412
|
+
if (hit?.object) onClick(hit.object, hit.point);
|
|
413
|
+
});
|
|
414
|
+
};
|
|
415
|
+
map.on('click', handleClick);
|
|
416
|
+
return ()=>{
|
|
417
|
+
map.off('click', handleClick);
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
registerGlobalClick(onClick) {
|
|
421
|
+
const map = this.mapless?.map;
|
|
422
|
+
if (!map) {
|
|
423
|
+
console.warn('Map not initialized');
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
const handleClick = (e)=>{
|
|
427
|
+
const point = {
|
|
428
|
+
x: e.point.x,
|
|
429
|
+
y: e.point.y
|
|
430
|
+
};
|
|
431
|
+
const hit = this.raycast(point);
|
|
432
|
+
if (hit) {
|
|
433
|
+
let renderableId;
|
|
434
|
+
for (const [id, obj] of this.renderableObjects)if (this.isObjectInHierarchy(hit.object, obj.mesh)) {
|
|
435
|
+
renderableId = id;
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
onClick({
|
|
439
|
+
...hit,
|
|
440
|
+
renderableId
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
map.on('click', handleClick);
|
|
445
|
+
return ()=>{
|
|
446
|
+
map.off('click', handleClick);
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
isObjectInHierarchy(obj, root) {
|
|
450
|
+
let current = obj;
|
|
451
|
+
while(current){
|
|
452
|
+
if (current === root) return true;
|
|
453
|
+
current = current.parent;
|
|
454
|
+
}
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
320
457
|
dispose() {
|
|
321
458
|
this.clear();
|
|
322
459
|
this.clearRenderableObjects();
|
|
@@ -11224,6 +11361,17 @@ class Mapless extends Base {
|
|
|
11224
11361
|
pitch: 0
|
|
11225
11362
|
});
|
|
11226
11363
|
}
|
|
11364
|
+
setCoordSystem(coordSystem) {
|
|
11365
|
+
if (!this.CoordTrans) return;
|
|
11366
|
+
const prevSystem = this.CoordSystem || 'wgs84';
|
|
11367
|
+
if (prevSystem === coordSystem) return;
|
|
11368
|
+
this.CoordTrans = createCoordTransformer({
|
|
11369
|
+
dataSystem: coordSystem,
|
|
11370
|
+
tileSystem: this.CoordTrans.TileSystem
|
|
11371
|
+
});
|
|
11372
|
+
this.emitterless.emit('coordSystemChange', coordSystem, prevSystem);
|
|
11373
|
+
console.log(`CoordSystem changed: ${prevSystem} -> ${coordSystem}`);
|
|
11374
|
+
}
|
|
11227
11375
|
fitBounds(coordinates, padding = 20) {
|
|
11228
11376
|
if (!this.map || !coordinates.length) return;
|
|
11229
11377
|
const bounds = coordinates.reduce((bounds, coord)=>bounds.extend(coord), new mapbox_gl.LngLatBounds(coordinates[0], coordinates[0]));
|
|
@@ -13781,8 +13929,15 @@ const stateColorRule = [
|
|
|
13781
13929
|
];
|
|
13782
13930
|
class MovableManager extends EmitManager {
|
|
13783
13931
|
movables = void 0;
|
|
13932
|
+
iconRotationAlignment = 'map';
|
|
13933
|
+
showNameByDefault;
|
|
13934
|
+
iconBaseSize;
|
|
13935
|
+
circleBaseRadius;
|
|
13784
13936
|
constructor(mapless, options){
|
|
13785
13937
|
super(mapless, options, 'movable');
|
|
13938
|
+
this.showNameByDefault = options?.showNameByDefault ?? false;
|
|
13939
|
+
this.iconBaseSize = options?.iconBaseSize ?? 0.3;
|
|
13940
|
+
this.circleBaseRadius = options?.circleBaseRadius ?? 8;
|
|
13786
13941
|
this.onInitialized();
|
|
13787
13942
|
this.setupClickHandler();
|
|
13788
13943
|
this.setupHoverHandler();
|
|
@@ -13849,8 +14004,8 @@ class MovableManager extends EmitManager {
|
|
|
13849
14004
|
],
|
|
13850
14005
|
true
|
|
13851
14006
|
],
|
|
13852
|
-
0.
|
|
13853
|
-
|
|
14007
|
+
this.iconBaseSize + 0.1,
|
|
14008
|
+
this.iconBaseSize
|
|
13854
14009
|
],
|
|
13855
14010
|
'icon-rotate': [
|
|
13856
14011
|
'get',
|
|
@@ -13858,8 +14013,11 @@ class MovableManager extends EmitManager {
|
|
|
13858
14013
|
],
|
|
13859
14014
|
'icon-allow-overlap': true,
|
|
13860
14015
|
'icon-ignore-placement': true,
|
|
13861
|
-
'icon-rotation-alignment':
|
|
13862
|
-
'text-field': [
|
|
14016
|
+
'icon-rotation-alignment': this.iconRotationAlignment,
|
|
14017
|
+
'text-field': this.showNameByDefault ? [
|
|
14018
|
+
'get',
|
|
14019
|
+
'name'
|
|
14020
|
+
] : [
|
|
13863
14021
|
'case',
|
|
13864
14022
|
[
|
|
13865
14023
|
'==',
|
|
@@ -13927,8 +14085,8 @@ class MovableManager extends EmitManager {
|
|
|
13927
14085
|
],
|
|
13928
14086
|
true
|
|
13929
14087
|
],
|
|
13930
|
-
|
|
13931
|
-
|
|
14088
|
+
this.circleBaseRadius + 2,
|
|
14089
|
+
this.circleBaseRadius
|
|
13932
14090
|
],
|
|
13933
14091
|
'circle-color': stateColorRule,
|
|
13934
14092
|
'circle-stroke-width': [
|
|
@@ -14111,12 +14269,19 @@ class MovableManager extends EmitManager {
|
|
|
14111
14269
|
padding: padding ?? 50
|
|
14112
14270
|
});
|
|
14113
14271
|
}
|
|
14272
|
+
setIconRotationAlignment(alignment) {
|
|
14273
|
+
this.iconRotationAlignment = alignment;
|
|
14274
|
+
if (this.map && this.idHub?.detailLayerId) this.map.setLayoutProperty(this.idHub.detailLayerId, 'icon-rotation-alignment', alignment);
|
|
14275
|
+
}
|
|
14276
|
+
getIconRotationAlignment() {
|
|
14277
|
+
return this.iconRotationAlignment;
|
|
14278
|
+
}
|
|
14114
14279
|
destroy() {
|
|
14115
14280
|
super.destroy();
|
|
14116
14281
|
this.movables = void 0;
|
|
14117
14282
|
}
|
|
14118
14283
|
}
|
|
14119
|
-
const attachMovable = (mapless, name)=>mapless?.use(MovableManager, name);
|
|
14284
|
+
const attachMovable = (mapless, name, options)=>mapless?.use(MovableManager, name, options);
|
|
14120
14285
|
const getMovable = (mapless, name)=>mapless?.get(MovableManager, name);
|
|
14121
14286
|
const detachMovable = (mapless, name)=>mapless?.unuse(MovableManager, name);
|
|
14122
14287
|
const hasAzimuth = (station)=>maplessPreset.movableTypes.includes(station.category || '');
|
|
@@ -16440,6 +16605,7 @@ class AirspaceManager extends manager_Manager {
|
|
|
16440
16605
|
defaultFillOpacity: 0.3
|
|
16441
16606
|
};
|
|
16442
16607
|
originalProperties = {};
|
|
16608
|
+
originalGeometries = {};
|
|
16443
16609
|
constructor(mapless, options){
|
|
16444
16610
|
super(mapless, options, 'airspace');
|
|
16445
16611
|
this.onInitialized();
|
|
@@ -16453,7 +16619,19 @@ class AirspaceManager extends manager_Manager {
|
|
|
16453
16619
|
handleCoordSystemChange(_system) {
|
|
16454
16620
|
if (this.zones) Object.keys(this.zones).forEach((id)=>{
|
|
16455
16621
|
const zone = this.zones[id];
|
|
16456
|
-
this.
|
|
16622
|
+
const originalGeometry = this.originalGeometries[id];
|
|
16623
|
+
if (originalGeometry) this.drawZone(id, {
|
|
16624
|
+
name: zone.name,
|
|
16625
|
+
geometry: originalGeometry,
|
|
16626
|
+
minAltitude: zone.minAltitude,
|
|
16627
|
+
maxAltitude: zone.maxAltitude,
|
|
16628
|
+
color: zone.color,
|
|
16629
|
+
edgeColor: zone.edgeColor,
|
|
16630
|
+
edgeOpacity: zone.edgeOpacity,
|
|
16631
|
+
edgeWidth: zone.edgeWidth,
|
|
16632
|
+
fillColor: zone.fillColor,
|
|
16633
|
+
fillOpacity: zone.fillOpacity
|
|
16634
|
+
});
|
|
16457
16635
|
});
|
|
16458
16636
|
}
|
|
16459
16637
|
createIdHub(_idHub) {
|
|
@@ -16533,11 +16711,16 @@ class AirspaceManager extends manager_Manager {
|
|
|
16533
16711
|
}
|
|
16534
16712
|
drawZone(id, options) {
|
|
16535
16713
|
const { name = '', geometry, minAltitude = this.config.defaultMinAltitude, maxAltitude = this.config.defaultMaxAltitude, color = this.config.defaultColor, edgeColor = this.config.defaultEdgeColor, edgeOpacity = this.config.defaultEdgeOpacity, edgeWidth = this.config.defaultEdgeWidth, fillColor = this.config.defaultFillColor, fillOpacity = this.config.defaultFillOpacity } = options;
|
|
16714
|
+
this.originalGeometries[id] = geometry;
|
|
16715
|
+
const transformedGeometry = geometry.map((polygon)=>polygon.map((coord)=>this.mapless?.coordTrans('dataToTile', [
|
|
16716
|
+
coord[0],
|
|
16717
|
+
coord[1]
|
|
16718
|
+
])));
|
|
16536
16719
|
const feature = {
|
|
16537
16720
|
type: 'Feature',
|
|
16538
16721
|
geometry: {
|
|
16539
16722
|
type: 'Polygon',
|
|
16540
|
-
coordinates:
|
|
16723
|
+
coordinates: transformedGeometry
|
|
16541
16724
|
},
|
|
16542
16725
|
properties: {
|
|
16543
16726
|
id,
|
|
@@ -16555,7 +16738,7 @@ class AirspaceManager extends manager_Manager {
|
|
|
16555
16738
|
this.zones[id] = {
|
|
16556
16739
|
id,
|
|
16557
16740
|
name,
|
|
16558
|
-
geometry,
|
|
16741
|
+
geometry: transformedGeometry,
|
|
16559
16742
|
minAltitude,
|
|
16560
16743
|
maxAltitude,
|
|
16561
16744
|
color,
|
|
@@ -16604,11 +16787,13 @@ class AirspaceManager extends manager_Manager {
|
|
|
16604
16787
|
if (!this.zones[id]) return;
|
|
16605
16788
|
delete this.zones[id];
|
|
16606
16789
|
delete this.originalProperties[id];
|
|
16790
|
+
delete this.originalGeometries[id];
|
|
16607
16791
|
this.updateSource();
|
|
16608
16792
|
}
|
|
16609
16793
|
clearZones() {
|
|
16610
16794
|
this.zones = {};
|
|
16611
16795
|
this.originalProperties = {};
|
|
16796
|
+
this.originalGeometries = {};
|
|
16612
16797
|
this.mapless?.setEmptyData(this.idHub?.sourceId);
|
|
16613
16798
|
}
|
|
16614
16799
|
updateZone(id, options) {
|
|
@@ -16664,7 +16849,8 @@ class AirspaceManager extends manager_Manager {
|
|
|
16664
16849
|
});
|
|
16665
16850
|
});
|
|
16666
16851
|
if (coordinates.length > 0 && this.mapless?.map) {
|
|
16667
|
-
const
|
|
16852
|
+
const originalCoordinates = coordinates.map((coord)=>this.mapless?.coordTrans('tileToData', coord));
|
|
16853
|
+
const bounds = originalCoordinates.reduce((bounds, coord)=>bounds.extend(coord), new mapbox_gl.LngLatBounds(originalCoordinates[0], originalCoordinates[0]));
|
|
16668
16854
|
const currentPitch = this.mapless.map.getPitch();
|
|
16669
16855
|
const currentBearing = this.mapless.map.getBearing();
|
|
16670
16856
|
this.mapless.map.fitBounds(bounds, {
|
|
@@ -16674,10 +16860,26 @@ class AirspaceManager extends manager_Manager {
|
|
|
16674
16860
|
});
|
|
16675
16861
|
}
|
|
16676
16862
|
}
|
|
16863
|
+
setFillExtrusionVisible(visible) {
|
|
16864
|
+
if (this.map && this.idHub?.fillLayerId) this.map.setLayoutProperty(this.idHub.fillLayerId, 'visibility', visible ? 'visible' : 'none');
|
|
16865
|
+
}
|
|
16866
|
+
isFillExtrusionVisible() {
|
|
16867
|
+
if (this.map && this.idHub?.fillLayerId) {
|
|
16868
|
+
const visibility = this.map.getLayoutProperty(this.idHub.fillLayerId, 'visibility');
|
|
16869
|
+
return 'none' !== visibility;
|
|
16870
|
+
}
|
|
16871
|
+
return true;
|
|
16872
|
+
}
|
|
16873
|
+
toggleFillExtrusion() {
|
|
16874
|
+
const currentState = this.isFillExtrusionVisible();
|
|
16875
|
+
this.setFillExtrusionVisible(!currentState);
|
|
16876
|
+
return !currentState;
|
|
16877
|
+
}
|
|
16677
16878
|
destroy() {
|
|
16678
16879
|
super.destroy();
|
|
16679
16880
|
this.zones = {};
|
|
16680
16881
|
this.originalProperties = {};
|
|
16882
|
+
this.originalGeometries = {};
|
|
16681
16883
|
}
|
|
16682
16884
|
}
|
|
16683
16885
|
const attachAirspace = (mapless, name)=>mapless?.use(AirspaceManager, name);
|
|
@@ -16838,6 +17040,7 @@ class MapModelManager extends EmitManager {
|
|
|
16838
17040
|
0
|
|
16839
17041
|
];
|
|
16840
17042
|
themeColorModels = new Set();
|
|
17043
|
+
modelOptions = new Map();
|
|
16841
17044
|
constructor(mapless, options){
|
|
16842
17045
|
super(mapless, options, 'mapModel');
|
|
16843
17046
|
this.map = mapless.map;
|
|
@@ -16848,6 +17051,14 @@ class MapModelManager extends EmitManager {
|
|
|
16848
17051
|
this.onInitialized();
|
|
16849
17052
|
this.setupGlobalClickHandler();
|
|
16850
17053
|
}
|
|
17054
|
+
handleCoordSystemChange(_system) {
|
|
17055
|
+
if (this.modelOptions.size > 0) {
|
|
17056
|
+
this.clearModels();
|
|
17057
|
+
this.modelOptions.forEach((options)=>{
|
|
17058
|
+
this.addModel(options);
|
|
17059
|
+
});
|
|
17060
|
+
}
|
|
17061
|
+
}
|
|
16851
17062
|
setupGlobalClickHandler() {
|
|
16852
17063
|
if (!this.map) return;
|
|
16853
17064
|
this.globalClickHandler = (e)=>{
|
|
@@ -16930,12 +17141,17 @@ class MapModelManager extends EmitManager {
|
|
|
16930
17141
|
if (!this.map) throw new Error('Map not initialized');
|
|
16931
17142
|
const sourceId = this.generateSourceId();
|
|
16932
17143
|
const layerId = this.generateLayerId();
|
|
17144
|
+
const originalPosition = config.position || config.lngLat || [
|
|
17145
|
+
0,
|
|
17146
|
+
0
|
|
17147
|
+
];
|
|
17148
|
+
const transformedPosition = this.mapless?.coordTrans('dataToTile', originalPosition);
|
|
16933
17149
|
const sourceConfig = {
|
|
16934
17150
|
type: 'model',
|
|
16935
17151
|
models: {
|
|
16936
17152
|
[modelId]: {
|
|
16937
17153
|
uri: config.uri,
|
|
16938
|
-
position:
|
|
17154
|
+
position: transformedPosition,
|
|
16939
17155
|
altitude: config.altitude || 0
|
|
16940
17156
|
}
|
|
16941
17157
|
}
|
|
@@ -17080,6 +17296,7 @@ class MapModelManager extends EmitManager {
|
|
|
17080
17296
|
materialOverrides,
|
|
17081
17297
|
nodeOverrides
|
|
17082
17298
|
});
|
|
17299
|
+
this.modelOptions.set(id, options);
|
|
17083
17300
|
if (!materialOverrides || 0 === Object.keys(materialOverrides).length) {
|
|
17084
17301
|
this.themeColorModels.add(id);
|
|
17085
17302
|
const themeColor = this.getDefaultThemeColor();
|
|
@@ -17095,9 +17312,10 @@ class MapModelManager extends EmitManager {
|
|
|
17095
17312
|
const modelData = this.models.get(id);
|
|
17096
17313
|
if (!modelData) return;
|
|
17097
17314
|
if (!this.map) return;
|
|
17315
|
+
const transformedPosition = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
17098
17316
|
const source = this.map.getSource(modelData.sourceId);
|
|
17099
17317
|
if (source?.models?.[id]) {
|
|
17100
|
-
source.models[id].position =
|
|
17318
|
+
source.models[id].position = transformedPosition;
|
|
17101
17319
|
source.models[id].altitude = altitude;
|
|
17102
17320
|
}
|
|
17103
17321
|
if (this.map.getLayer(modelData.layerId)) this.map.setPaintProperty(modelData.layerId, 'model-translation', [
|
|
@@ -17105,6 +17323,11 @@ class MapModelManager extends EmitManager {
|
|
|
17105
17323
|
0,
|
|
17106
17324
|
altitude
|
|
17107
17325
|
]);
|
|
17326
|
+
const options = this.modelOptions.get(id);
|
|
17327
|
+
if (options) {
|
|
17328
|
+
options.lngLat = lngLat;
|
|
17329
|
+
if (void 0 !== altitude) options.altitude = altitude;
|
|
17330
|
+
}
|
|
17108
17331
|
}
|
|
17109
17332
|
updateModelRotation(id, rotation) {
|
|
17110
17333
|
const modelData = this.models.get(id);
|
|
@@ -17133,6 +17356,7 @@ class MapModelManager extends EmitManager {
|
|
|
17133
17356
|
if (this.map.getLayer(modelData.layerId)) this.map.removeLayer(modelData.layerId);
|
|
17134
17357
|
if (this.map.getSource(modelData.sourceId)) this.map.removeSource(modelData.sourceId);
|
|
17135
17358
|
this.models.delete(id);
|
|
17359
|
+
this.modelOptions.delete(id);
|
|
17136
17360
|
this.themeColorModels.delete(id);
|
|
17137
17361
|
if (this.selectedModelId === id) this.selectedModelId = null;
|
|
17138
17362
|
}
|
|
@@ -17182,10 +17406,52 @@ class MapModelManager extends EmitManager {
|
|
|
17182
17406
|
previousId
|
|
17183
17407
|
});
|
|
17184
17408
|
}
|
|
17409
|
+
hideLayer(id) {
|
|
17410
|
+
if (void 0 === id) return void this.models.forEach((modelData)=>{
|
|
17411
|
+
if (this.map?.getLayer(modelData.layerId)) this.map?.setLayoutProperty(modelData.layerId, 'visibility', 'none');
|
|
17412
|
+
});
|
|
17413
|
+
const modelData = this.models.get(id);
|
|
17414
|
+
if (!modelData) return;
|
|
17415
|
+
if (!this.map) return;
|
|
17416
|
+
if (this.map.getLayer(modelData.layerId)) this.map.setLayoutProperty(modelData.layerId, 'visibility', 'none');
|
|
17417
|
+
}
|
|
17418
|
+
showLayer(id) {
|
|
17419
|
+
if (void 0 === id) return void this.models.forEach((modelData)=>{
|
|
17420
|
+
if (this.map?.getLayer(modelData.layerId)) this.map?.setLayoutProperty(modelData.layerId, 'visibility', 'visible');
|
|
17421
|
+
});
|
|
17422
|
+
const modelData = this.models.get(id);
|
|
17423
|
+
if (!modelData) return;
|
|
17424
|
+
if (!this.map) return;
|
|
17425
|
+
if (this.map.getLayer(modelData.layerId)) this.map.setLayoutProperty(modelData.layerId, 'visibility', 'visible');
|
|
17426
|
+
}
|
|
17427
|
+
toggleLayer(id) {
|
|
17428
|
+
if (void 0 === id) {
|
|
17429
|
+
this.models.forEach((modelData)=>{
|
|
17430
|
+
const isVisible = this.isLayerVisible(modelData.id);
|
|
17431
|
+
if (isVisible) this.hideLayer(modelData.id);
|
|
17432
|
+
else this.showLayer(modelData.id);
|
|
17433
|
+
});
|
|
17434
|
+
return true;
|
|
17435
|
+
}
|
|
17436
|
+
const isVisible = this.isLayerVisible(id);
|
|
17437
|
+
if (isVisible) this.hideLayer(id);
|
|
17438
|
+
else this.showLayer(id);
|
|
17439
|
+
return !isVisible;
|
|
17440
|
+
}
|
|
17441
|
+
isLayerVisible(id) {
|
|
17442
|
+
const modelData = this.models.get(id);
|
|
17443
|
+
if (!modelData) return false;
|
|
17444
|
+
if (!this.map) return false;
|
|
17445
|
+
const layer = this.map.getLayer(modelData.layerId);
|
|
17446
|
+
if (!layer) return false;
|
|
17447
|
+
const visibility = layer.visibility;
|
|
17448
|
+
return 'none' !== visibility;
|
|
17449
|
+
}
|
|
17185
17450
|
destroy() {
|
|
17186
17451
|
if (this.map && this.globalClickHandler) this.map.off('click', this.globalClickHandler);
|
|
17187
17452
|
this.selectedModelId = null;
|
|
17188
17453
|
this.themeColorModels.clear();
|
|
17454
|
+
this.modelOptions.clear();
|
|
17189
17455
|
this.clearModels();
|
|
17190
17456
|
}
|
|
17191
17457
|
}
|
|
@@ -17272,7 +17538,8 @@ class BasicThreeObjectManager extends manager_Manager {
|
|
|
17272
17538
|
matrix: matrix.clone()
|
|
17273
17539
|
});
|
|
17274
17540
|
else {
|
|
17275
|
-
const
|
|
17541
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
17542
|
+
const modelAsMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, altitude);
|
|
17276
17543
|
const mercatorScale = modelAsMercator.meterInMercatorCoordinateUnits() * scale;
|
|
17277
17544
|
mapThree.addRenderableObject(id, mesh, {
|
|
17278
17545
|
translateX: modelAsMercator.x,
|
|
@@ -17289,7 +17556,13 @@ class BasicThreeObjectManager extends manager_Manager {
|
|
|
17289
17556
|
type,
|
|
17290
17557
|
mesh,
|
|
17291
17558
|
geometry,
|
|
17292
|
-
material
|
|
17559
|
+
material,
|
|
17560
|
+
originalOptions: {
|
|
17561
|
+
lngLat,
|
|
17562
|
+
altitude,
|
|
17563
|
+
rotation,
|
|
17564
|
+
scale
|
|
17565
|
+
}
|
|
17293
17566
|
});
|
|
17294
17567
|
console.log(`BasicThreeObject added: ${id}`, {
|
|
17295
17568
|
type,
|
|
@@ -17309,7 +17582,8 @@ class BasicThreeObjectManager extends manager_Manager {
|
|
|
17309
17582
|
if (!mapThree) return;
|
|
17310
17583
|
const objData = this.objects.get(id);
|
|
17311
17584
|
if (!objData) return void console.warn(`Object with id "${id}" not found`);
|
|
17312
|
-
const
|
|
17585
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
17586
|
+
const modelAsMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, altitude);
|
|
17313
17587
|
const renderableObj = mapThree.getRenderableObject(id);
|
|
17314
17588
|
if (renderableObj) mapThree.updateRenderableObjectTransform(id, {
|
|
17315
17589
|
...renderableObj.transform,
|
|
@@ -17317,6 +17591,10 @@ class BasicThreeObjectManager extends manager_Manager {
|
|
|
17317
17591
|
translateY: modelAsMercator.y,
|
|
17318
17592
|
translateZ: modelAsMercator.z
|
|
17319
17593
|
});
|
|
17594
|
+
if (objData.originalOptions) {
|
|
17595
|
+
objData.originalOptions.lngLat = lngLat;
|
|
17596
|
+
objData.originalOptions.altitude = altitude;
|
|
17597
|
+
}
|
|
17320
17598
|
}
|
|
17321
17599
|
updateObjectRotation(id, rotation) {
|
|
17322
17600
|
const mapThree = this.getMapThree();
|
|
@@ -17350,7 +17628,8 @@ class BasicThreeObjectManager extends manager_Manager {
|
|
|
17350
17628
|
if (!mapThree) return;
|
|
17351
17629
|
const objData = this.objects.get(id);
|
|
17352
17630
|
if (!objData) return void console.warn(`Object with id "${id}" not found`);
|
|
17353
|
-
const
|
|
17631
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
17632
|
+
const modelAsMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, altitude);
|
|
17354
17633
|
const mercatorScale = modelAsMercator.meterInMercatorCoordinateUnits() * scale;
|
|
17355
17634
|
const renderableObj = mapThree.getRenderableObject(id);
|
|
17356
17635
|
if (renderableObj) mapThree.updateRenderableObjectTransform(id, {
|
|
@@ -17421,6 +17700,27 @@ class BasicThreeObjectManager extends manager_Manager {
|
|
|
17421
17700
|
getObjectIds() {
|
|
17422
17701
|
return Array.from(this.objects.keys());
|
|
17423
17702
|
}
|
|
17703
|
+
handleCoordSystemChange(_system) {
|
|
17704
|
+
const mapThree = this.getMapThree();
|
|
17705
|
+
if (!mapThree || 0 === this.objects.size) return;
|
|
17706
|
+
this.objects.forEach((objData, id)=>{
|
|
17707
|
+
if (!objData.originalOptions) return;
|
|
17708
|
+
const { lngLat, altitude, rotation, scale } = objData.originalOptions;
|
|
17709
|
+
mapThree.removeRenderableObject(id);
|
|
17710
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
17711
|
+
const modelAsMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, altitude);
|
|
17712
|
+
const mercatorScale = modelAsMercator.meterInMercatorCoordinateUnits() * (scale || 1);
|
|
17713
|
+
mapThree.addRenderableObject(id, objData.mesh, {
|
|
17714
|
+
translateX: modelAsMercator.x,
|
|
17715
|
+
translateY: modelAsMercator.y,
|
|
17716
|
+
translateZ: modelAsMercator.z,
|
|
17717
|
+
rotateX: rotation?.[0] || 0,
|
|
17718
|
+
rotateY: rotation?.[1] || 0,
|
|
17719
|
+
rotateZ: rotation?.[2] || 0,
|
|
17720
|
+
scale: mercatorScale
|
|
17721
|
+
});
|
|
17722
|
+
});
|
|
17723
|
+
}
|
|
17424
17724
|
destroy() {
|
|
17425
17725
|
this.clearObjects();
|
|
17426
17726
|
}
|
|
@@ -17470,10 +17770,11 @@ class Curve3DManager extends manager_Manager {
|
|
|
17470
17770
|
}
|
|
17471
17771
|
calculateTransform(points) {
|
|
17472
17772
|
if (0 === points.length) throw new Error('Cannot calculate transform for empty points');
|
|
17473
|
-
const
|
|
17773
|
+
const transformedFirst = this.mapless?.coordTrans('dataToTile', [
|
|
17474
17774
|
points[0].lng,
|
|
17475
17775
|
points[0].lat
|
|
17476
|
-
]
|
|
17776
|
+
]);
|
|
17777
|
+
const firstPoint = mapbox_gl.MercatorCoordinate.fromLngLat(transformedFirst, points[0].alt);
|
|
17477
17778
|
return {
|
|
17478
17779
|
translateX: firstPoint.x,
|
|
17479
17780
|
translateY: firstPoint.y,
|
|
@@ -17486,10 +17787,11 @@ class Curve3DManager extends manager_Manager {
|
|
|
17486
17787
|
points.forEach((point, index)=>{
|
|
17487
17788
|
if (0 === index) vector3Points.push(new Vector3(0, 0, 0));
|
|
17488
17789
|
else {
|
|
17489
|
-
const
|
|
17790
|
+
const transformedPoint = this.mapless?.coordTrans('dataToTile', [
|
|
17490
17791
|
point.lng,
|
|
17491
17792
|
point.lat
|
|
17492
|
-
]
|
|
17793
|
+
]);
|
|
17794
|
+
const currentMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedPoint, point.alt);
|
|
17493
17795
|
const dx = currentMercator.x - transform.translateX;
|
|
17494
17796
|
const dy = currentMercator.y - transform.translateY;
|
|
17495
17797
|
const dz = currentMercator.z - transform.translateZ;
|
|
@@ -17498,6 +17800,33 @@ class Curve3DManager extends manager_Manager {
|
|
|
17498
17800
|
});
|
|
17499
17801
|
return vector3Points;
|
|
17500
17802
|
}
|
|
17803
|
+
handleCoordSystemChange(_system) {
|
|
17804
|
+
if (this.curves.size > 0 && this.getMapThree()) {
|
|
17805
|
+
const entries = Array.from(this.curves.entries());
|
|
17806
|
+
entries.forEach(([id, curveData])=>{
|
|
17807
|
+
const mapThree = this.getMapThree();
|
|
17808
|
+
if (mapThree) mapThree.removeRenderableObject(id);
|
|
17809
|
+
const transform = this.calculateTransform(curveData.originalPoints);
|
|
17810
|
+
const points = this.convertPoints(curveData.originalPoints, transform);
|
|
17811
|
+
const mesh = this.createMesh({
|
|
17812
|
+
...curveData,
|
|
17813
|
+
points
|
|
17814
|
+
});
|
|
17815
|
+
if (mapThree) mapThree.addRenderableObject(id, mesh, {
|
|
17816
|
+
translateX: transform.translateX,
|
|
17817
|
+
translateY: transform.translateY,
|
|
17818
|
+
translateZ: transform.translateZ,
|
|
17819
|
+
scale: transform.scale
|
|
17820
|
+
});
|
|
17821
|
+
this.curves.set(id, {
|
|
17822
|
+
...curveData,
|
|
17823
|
+
points,
|
|
17824
|
+
transform,
|
|
17825
|
+
mesh
|
|
17826
|
+
});
|
|
17827
|
+
});
|
|
17828
|
+
}
|
|
17829
|
+
}
|
|
17501
17830
|
addCurve(id, config) {
|
|
17502
17831
|
const mapThree = this.getMapThree();
|
|
17503
17832
|
if (!mapThree) throw new Error('Three scene not initialized. Call useThree first.');
|
|
@@ -17517,7 +17846,8 @@ class Curve3DManager extends manager_Manager {
|
|
|
17517
17846
|
points,
|
|
17518
17847
|
mesh: null,
|
|
17519
17848
|
transform,
|
|
17520
|
-
config: curveConfig
|
|
17849
|
+
config: curveConfig,
|
|
17850
|
+
originalPoints: config.points
|
|
17521
17851
|
};
|
|
17522
17852
|
if (points.length >= 2) {
|
|
17523
17853
|
const mesh = this.createMesh(curveData);
|
|
@@ -17550,6 +17880,7 @@ class Curve3DManager extends manager_Manager {
|
|
|
17550
17880
|
mapThree.removeRenderableObject(id);
|
|
17551
17881
|
curveData.transform = this.calculateTransform(config.points);
|
|
17552
17882
|
curveData.points = this.convertPoints(config.points, curveData.transform);
|
|
17883
|
+
curveData.originalPoints = config.points;
|
|
17553
17884
|
const mesh = this.createMesh(curveData);
|
|
17554
17885
|
curveData.mesh = mesh;
|
|
17555
17886
|
mapThree.addRenderableObject(id, mesh, {
|
|
@@ -17600,6 +17931,353 @@ const curve3d = Curve3DManager;
|
|
|
17600
17931
|
const attachCurve3D = (mapless, name, options)=>mapless?.use(Curve3DManager, name, options);
|
|
17601
17932
|
const getCurve3D = (mapless, name)=>mapless?.get(Curve3DManager, name);
|
|
17602
17933
|
const detachCurve3D = (mapless, name)=>mapless?.unuse(Curve3DManager, name);
|
|
17934
|
+
class InstancedModelManager extends manager_Manager {
|
|
17935
|
+
scene = null;
|
|
17936
|
+
camera = null;
|
|
17937
|
+
renderer = null;
|
|
17938
|
+
customLayerId;
|
|
17939
|
+
isInitialized = false;
|
|
17940
|
+
instancedMeshes = new Map();
|
|
17941
|
+
instanceDataMap = new Map();
|
|
17942
|
+
rotationAngles = new Map();
|
|
17943
|
+
autoRotateEnabled = new Map();
|
|
17944
|
+
rotationSpeeds = new Map();
|
|
17945
|
+
clickCallback = null;
|
|
17946
|
+
lastProjectionMatrix = null;
|
|
17947
|
+
originalConfigs = new Map();
|
|
17948
|
+
constructor(mapless){
|
|
17949
|
+
super(mapless);
|
|
17950
|
+
this.map = mapless.map;
|
|
17951
|
+
this.customLayerId = `instanced-model-layer-${this.gmid}`;
|
|
17952
|
+
}
|
|
17953
|
+
initThree() {
|
|
17954
|
+
if (this.isInitialized || !this.map) return;
|
|
17955
|
+
const canvas = this.map.getCanvas();
|
|
17956
|
+
const gl = canvas.getContext('webgl2') || canvas.getContext('webgl');
|
|
17957
|
+
if (!gl) return void console.error('InstancedModelManager: WebGL context not available');
|
|
17958
|
+
this.scene = new Scene();
|
|
17959
|
+
this.camera = new PerspectiveCamera(75, canvas.width / canvas.height, 0.1, 10000);
|
|
17960
|
+
this.renderer = new WebGLRenderer({
|
|
17961
|
+
canvas: canvas,
|
|
17962
|
+
context: gl,
|
|
17963
|
+
antialias: false
|
|
17964
|
+
});
|
|
17965
|
+
this.renderer.autoClear = false;
|
|
17966
|
+
this.renderer.setClearColor(0x000000, 0);
|
|
17967
|
+
this.renderer.setPixelRatio(window.devicePixelRatio);
|
|
17968
|
+
const ambientLight = new AmbientLight(0xffffff, 0.6);
|
|
17969
|
+
this.scene.add(ambientLight);
|
|
17970
|
+
const directionalLight = new DirectionalLight(0xffffff, 0.8);
|
|
17971
|
+
directionalLight.position.set(0, -70, 100);
|
|
17972
|
+
this.scene.add(directionalLight);
|
|
17973
|
+
const directionalLight2 = new DirectionalLight(0xffffff, 0.5);
|
|
17974
|
+
directionalLight2.position.set(0, 70, 100);
|
|
17975
|
+
this.scene.add(directionalLight2);
|
|
17976
|
+
this.setupCustomLayer();
|
|
17977
|
+
this.isInitialized = true;
|
|
17978
|
+
console.log('InstancedModelManager: Initialized', {
|
|
17979
|
+
canvas: `${canvas.width}x${canvas.height}`,
|
|
17980
|
+
customLayerId: this.customLayerId
|
|
17981
|
+
});
|
|
17982
|
+
}
|
|
17983
|
+
setupCustomLayer() {
|
|
17984
|
+
if (!this.map) return;
|
|
17985
|
+
const customLayer = {
|
|
17986
|
+
id: this.customLayerId,
|
|
17987
|
+
type: 'custom',
|
|
17988
|
+
renderingMode: '3d',
|
|
17989
|
+
onAdd: ()=>{
|
|
17990
|
+
console.log('InstancedModelManager: Custom layer added');
|
|
17991
|
+
this.setupClickHandler();
|
|
17992
|
+
},
|
|
17993
|
+
render: (_gl, matrix)=>{
|
|
17994
|
+
if (!this.camera || !this.renderer || !this.scene) return;
|
|
17995
|
+
this.updateAutoRotate();
|
|
17996
|
+
this.camera.projectionMatrix = new Matrix4().fromArray(matrix);
|
|
17997
|
+
this.lastProjectionMatrix = this.camera.projectionMatrix.clone();
|
|
17998
|
+
_gl.enable(_gl.DEPTH_TEST);
|
|
17999
|
+
this.renderer.resetState();
|
|
18000
|
+
this.renderer.render(this.scene, this.camera);
|
|
18001
|
+
if (this.map) this.map.triggerRepaint();
|
|
18002
|
+
}
|
|
18003
|
+
};
|
|
18004
|
+
this.map.addLayer(customLayer);
|
|
18005
|
+
}
|
|
18006
|
+
setupClickHandler() {
|
|
18007
|
+
if (!this.map) return;
|
|
18008
|
+
const canvas = this.map.getCanvas();
|
|
18009
|
+
const handleClick = (e)=>{
|
|
18010
|
+
if (!this.camera || !this.scene || !this.renderer || !this.lastProjectionMatrix) return;
|
|
18011
|
+
const rect = canvas.getBoundingClientRect();
|
|
18012
|
+
const ndcX = (e.clientX - rect.left) / rect.width * 2 - 1;
|
|
18013
|
+
const ndcY = 2 * -((e.clientY - rect.top) / rect.height) + 1;
|
|
18014
|
+
const meshes = Array.from(this.instancedMeshes.entries());
|
|
18015
|
+
let closestHit = null;
|
|
18016
|
+
let minDistance = 1 / 0;
|
|
18017
|
+
for (const [groupId, instancedMesh] of meshes){
|
|
18018
|
+
const inverseProj = this.lastProjectionMatrix.clone().invert();
|
|
18019
|
+
const nearPoint = new Vector4(ndcX, ndcY, -1, 1).applyMatrix4(inverseProj);
|
|
18020
|
+
nearPoint.divideScalar(nearPoint.w);
|
|
18021
|
+
const farPoint = new Vector4(ndcX, ndcY, 1, 1).applyMatrix4(inverseProj);
|
|
18022
|
+
farPoint.divideScalar(farPoint.w);
|
|
18023
|
+
const origin = new Vector3(0, 0, 0);
|
|
18024
|
+
const direction = new Vector3(farPoint.x - nearPoint.x, farPoint.y - nearPoint.y, farPoint.z - nearPoint.z).normalize();
|
|
18025
|
+
const raycaster = new Raycaster(origin, direction);
|
|
18026
|
+
const intersects = raycaster.intersectObject(instancedMesh, false);
|
|
18027
|
+
if (intersects.length > 0 && intersects[0].distance < minDistance) {
|
|
18028
|
+
const intersection = intersects[0];
|
|
18029
|
+
const instanceId = intersection.instanceId;
|
|
18030
|
+
if (void 0 !== instanceId) {
|
|
18031
|
+
minDistance = intersection.distance;
|
|
18032
|
+
closestHit = {
|
|
18033
|
+
groupId,
|
|
18034
|
+
instanceIndex: instanceId,
|
|
18035
|
+
point: intersection.point,
|
|
18036
|
+
distance: intersection.distance
|
|
18037
|
+
};
|
|
18038
|
+
}
|
|
18039
|
+
}
|
|
18040
|
+
}
|
|
18041
|
+
if (closestHit && this.clickCallback) {
|
|
18042
|
+
const instanceData = this.instanceDataMap.get(closestHit.groupId)?.[closestHit.instanceIndex];
|
|
18043
|
+
if (instanceData) this.clickCallback({
|
|
18044
|
+
id: closestHit.groupId,
|
|
18045
|
+
instanceIndex: closestHit.instanceIndex,
|
|
18046
|
+
point: closestHit.point,
|
|
18047
|
+
lngLat: instanceData.lngLat,
|
|
18048
|
+
altitude: instanceData.altitude
|
|
18049
|
+
});
|
|
18050
|
+
}
|
|
18051
|
+
};
|
|
18052
|
+
canvas.addEventListener('click', handleClick);
|
|
18053
|
+
}
|
|
18054
|
+
onClick(callback) {
|
|
18055
|
+
this.clickCallback = callback;
|
|
18056
|
+
}
|
|
18057
|
+
updateAutoRotate() {
|
|
18058
|
+
this.autoRotateEnabled.forEach((enabled, id)=>{
|
|
18059
|
+
if (!enabled) return;
|
|
18060
|
+
const instancedMesh = this.instancedMeshes.get(id);
|
|
18061
|
+
const angles = this.rotationAngles.get(id);
|
|
18062
|
+
const speed = this.rotationSpeeds.get(id) || 0.01;
|
|
18063
|
+
if (!instancedMesh || !angles) return;
|
|
18064
|
+
const dummy = new Object3D();
|
|
18065
|
+
const count = instancedMesh.count;
|
|
18066
|
+
for(let i = 0; i < count; i++){
|
|
18067
|
+
instancedMesh.getMatrixAt(i, dummy.matrix);
|
|
18068
|
+
dummy.matrix.decompose(dummy.position, dummy.quaternion, dummy.scale);
|
|
18069
|
+
angles[i] += speed;
|
|
18070
|
+
dummy.rotation.set(0, 0, angles[i]);
|
|
18071
|
+
dummy.updateMatrix();
|
|
18072
|
+
instancedMesh.setMatrixAt(i, dummy.matrix);
|
|
18073
|
+
}
|
|
18074
|
+
instancedMesh.instanceMatrix.needsUpdate = true;
|
|
18075
|
+
});
|
|
18076
|
+
}
|
|
18077
|
+
generateInstances(config) {
|
|
18078
|
+
const instances = [];
|
|
18079
|
+
for(let i = 0; i < config.count; i++){
|
|
18080
|
+
const lngOffset = (Math.random() - 0.5) * config.spread * 2;
|
|
18081
|
+
const latOffset = (Math.random() - 0.5) * config.spread * 2;
|
|
18082
|
+
const altitude = 500 * Math.random();
|
|
18083
|
+
const rotation = Math.random() * Math.PI * 2;
|
|
18084
|
+
const scaleVariation = 1 + 2 * Math.random();
|
|
18085
|
+
instances.push({
|
|
18086
|
+
lngLat: [
|
|
18087
|
+
config.center[0] + lngOffset,
|
|
18088
|
+
config.center[1] + latOffset
|
|
18089
|
+
],
|
|
18090
|
+
altitude,
|
|
18091
|
+
rotation,
|
|
18092
|
+
scale: scaleVariation
|
|
18093
|
+
});
|
|
18094
|
+
}
|
|
18095
|
+
return instances;
|
|
18096
|
+
}
|
|
18097
|
+
handleCoordSystemChange(_system) {
|
|
18098
|
+
if (!this.scene || !this.map || 0 === this.originalConfigs.size) return;
|
|
18099
|
+
this.originalConfigs.forEach((config, id)=>{
|
|
18100
|
+
this.remove(id);
|
|
18101
|
+
this.load(id, config).catch((error)=>{
|
|
18102
|
+
console.error(`Failed to reload instanced model "${id}" after coord system change:`, error);
|
|
18103
|
+
});
|
|
18104
|
+
});
|
|
18105
|
+
}
|
|
18106
|
+
async load(id, config) {
|
|
18107
|
+
this.initThree();
|
|
18108
|
+
if (!this.scene || !this.map) throw new Error('Three.js scene not initialized');
|
|
18109
|
+
this.remove(id);
|
|
18110
|
+
const loader = new GLTFLoader();
|
|
18111
|
+
try {
|
|
18112
|
+
console.log('InstancedModel: Loading model', config.url);
|
|
18113
|
+
const gltf = await new Promise((resolve, reject)=>{
|
|
18114
|
+
loader.load(config.url, resolve, void 0, reject);
|
|
18115
|
+
});
|
|
18116
|
+
const gltfScene = gltf.scene;
|
|
18117
|
+
const meshes = [];
|
|
18118
|
+
gltfScene.traverse((object)=>{
|
|
18119
|
+
if (object instanceof Mesh) meshes.push(object);
|
|
18120
|
+
});
|
|
18121
|
+
if (0 === meshes.length) throw new Error('No mesh found in model');
|
|
18122
|
+
console.log('InstancedModel: Found meshes', {
|
|
18123
|
+
count: meshes.length,
|
|
18124
|
+
details: meshes.map((m, i)=>({
|
|
18125
|
+
index: i,
|
|
18126
|
+
vertices: m.geometry.attributes.position?.count,
|
|
18127
|
+
hasMaterial: !!m.material,
|
|
18128
|
+
materialArray: Array.isArray(m.material)
|
|
18129
|
+
}))
|
|
18130
|
+
});
|
|
18131
|
+
let meshToUse;
|
|
18132
|
+
if (1 === meshes.length) meshToUse = meshes[0];
|
|
18133
|
+
else {
|
|
18134
|
+
const geometries = meshes.map((mesh)=>{
|
|
18135
|
+
const geometry = mesh.geometry.clone();
|
|
18136
|
+
geometry.applyMatrix4(mesh.matrixWorld);
|
|
18137
|
+
return geometry;
|
|
18138
|
+
});
|
|
18139
|
+
const geometry = mergeGeometries(geometries, false);
|
|
18140
|
+
if (geometry) meshToUse = new Mesh(geometry, meshes[0].material);
|
|
18141
|
+
else {
|
|
18142
|
+
console.warn('Failed to merge geometries, falling back to first mesh');
|
|
18143
|
+
meshToUse = meshes[0];
|
|
18144
|
+
}
|
|
18145
|
+
}
|
|
18146
|
+
const mesh = meshToUse;
|
|
18147
|
+
const materialToUse = Array.isArray(mesh.material) ? mesh.material[0] : mesh.material;
|
|
18148
|
+
const instancedMesh = new InstancedMesh(mesh.geometry.clone(), materialToUse.clone(), config.count);
|
|
18149
|
+
instancedMesh.castShadow = true;
|
|
18150
|
+
instancedMesh.receiveShadow = true;
|
|
18151
|
+
if ('side' in instancedMesh.material) instancedMesh.material.side = DoubleSide;
|
|
18152
|
+
const instances = this.generateInstances(config);
|
|
18153
|
+
const angles = new Float32Array(config.count);
|
|
18154
|
+
const transformedCenter = this.mapless?.coordTrans('dataToTile', config.center);
|
|
18155
|
+
const meterInMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedCenter, 0).meterInMercatorCoordinateUnits();
|
|
18156
|
+
console.log('InstancedModel: Creating instances', {
|
|
18157
|
+
instanceCount: config.count,
|
|
18158
|
+
center: config.center,
|
|
18159
|
+
scale: config.scale,
|
|
18160
|
+
meterInMercator,
|
|
18161
|
+
firstInstanceLngLat: instances[0].lngLat,
|
|
18162
|
+
firstInstanceAlt: instances[0].altitude
|
|
18163
|
+
});
|
|
18164
|
+
const dummy = new Object3D();
|
|
18165
|
+
instances.forEach((instance, i)=>{
|
|
18166
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', instance.lngLat);
|
|
18167
|
+
const mercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, instance.altitude);
|
|
18168
|
+
dummy.position.set(mercator.x, mercator.y, mercator.z);
|
|
18169
|
+
dummy.rotation.set(0, 0, instance.rotation);
|
|
18170
|
+
const scale = meterInMercator * config.scale * instance.scale;
|
|
18171
|
+
dummy.scale.set(scale, -scale, scale);
|
|
18172
|
+
dummy.updateMatrix();
|
|
18173
|
+
instancedMesh.setMatrixAt(i, dummy.matrix);
|
|
18174
|
+
angles[i] = instance.rotation;
|
|
18175
|
+
});
|
|
18176
|
+
instancedMesh.instanceMatrix.needsUpdate = true;
|
|
18177
|
+
this.scene.add(instancedMesh);
|
|
18178
|
+
this.instancedMeshes.set(id, instancedMesh);
|
|
18179
|
+
this.instanceDataMap.set(id, instances);
|
|
18180
|
+
this.rotationAngles.set(id, angles);
|
|
18181
|
+
this.autoRotateEnabled.set(id, config.autoRotate || false);
|
|
18182
|
+
this.rotationSpeeds.set(id, config.rotationSpeed || 0.01);
|
|
18183
|
+
this.originalConfigs.set(id, config);
|
|
18184
|
+
console.log(`InstancedModel "${id}" loaded with ${config.count} instances`);
|
|
18185
|
+
} catch (error) {
|
|
18186
|
+
console.error(`Failed to load instanced model "${id}":`, error);
|
|
18187
|
+
throw error;
|
|
18188
|
+
}
|
|
18189
|
+
}
|
|
18190
|
+
enableAutoRotate(id, speed = 0.01) {
|
|
18191
|
+
this.autoRotateEnabled.set(id, true);
|
|
18192
|
+
this.rotationSpeeds.set(id, speed);
|
|
18193
|
+
}
|
|
18194
|
+
disableAutoRotate(id) {
|
|
18195
|
+
this.autoRotateEnabled.set(id, false);
|
|
18196
|
+
}
|
|
18197
|
+
updateInstance(id, index, lngLat, altitude) {
|
|
18198
|
+
const instancedMesh = this.instancedMeshes.get(id);
|
|
18199
|
+
if (!instancedMesh) return;
|
|
18200
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
18201
|
+
const mercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, altitude);
|
|
18202
|
+
const dummy = new Object3D();
|
|
18203
|
+
instancedMesh.getMatrixAt(index, dummy.matrix);
|
|
18204
|
+
dummy.matrix.decompose(dummy.position, dummy.quaternion, dummy.scale);
|
|
18205
|
+
dummy.position.set(mercator.x, mercator.y, mercator.z);
|
|
18206
|
+
dummy.updateMatrix();
|
|
18207
|
+
instancedMesh.setMatrixAt(index, dummy.matrix);
|
|
18208
|
+
instancedMesh.instanceMatrix.needsUpdate = true;
|
|
18209
|
+
const instances = this.instanceDataMap.get(id);
|
|
18210
|
+
if (instances && instances[index]) {
|
|
18211
|
+
instances[index].lngLat = lngLat;
|
|
18212
|
+
instances[index].altitude = altitude;
|
|
18213
|
+
}
|
|
18214
|
+
}
|
|
18215
|
+
setInstanceVisible(id, visible) {
|
|
18216
|
+
const instancedMesh = this.instancedMeshes.get(id);
|
|
18217
|
+
if (instancedMesh) instancedMesh.visible = visible;
|
|
18218
|
+
}
|
|
18219
|
+
setVisible(visible) {
|
|
18220
|
+
this.IsVisible = visible;
|
|
18221
|
+
this.instancedMeshes.forEach((mesh)=>{
|
|
18222
|
+
mesh.visible = visible;
|
|
18223
|
+
});
|
|
18224
|
+
}
|
|
18225
|
+
getInstanceCount(id) {
|
|
18226
|
+
const instancedMesh = this.instancedMeshes.get(id);
|
|
18227
|
+
return instancedMesh?.count || 0;
|
|
18228
|
+
}
|
|
18229
|
+
getIds() {
|
|
18230
|
+
return Array.from(this.instancedMeshes.keys());
|
|
18231
|
+
}
|
|
18232
|
+
remove(id) {
|
|
18233
|
+
const instancedMesh = this.instancedMeshes.get(id);
|
|
18234
|
+
if (!instancedMesh) return;
|
|
18235
|
+
this.scene?.remove(instancedMesh);
|
|
18236
|
+
instancedMesh.geometry.dispose();
|
|
18237
|
+
if (Array.isArray(instancedMesh.material)) instancedMesh.material.forEach((m)=>{
|
|
18238
|
+
m.dispose();
|
|
18239
|
+
});
|
|
18240
|
+
else instancedMesh.material.dispose();
|
|
18241
|
+
this.instancedMeshes.delete(id);
|
|
18242
|
+
this.instanceDataMap.delete(id);
|
|
18243
|
+
this.rotationAngles.delete(id);
|
|
18244
|
+
this.autoRotateEnabled.delete(id);
|
|
18245
|
+
this.rotationSpeeds.delete(id);
|
|
18246
|
+
}
|
|
18247
|
+
clear() {
|
|
18248
|
+
const ids = this.getIds();
|
|
18249
|
+
ids.forEach((id)=>{
|
|
18250
|
+
this.remove(id);
|
|
18251
|
+
});
|
|
18252
|
+
}
|
|
18253
|
+
setColor(id, color) {
|
|
18254
|
+
const instancedMesh = this.instancedMeshes.get(id);
|
|
18255
|
+
if (!instancedMesh) return;
|
|
18256
|
+
const meshColor = 'string' == typeof color ? new Color(color) : color;
|
|
18257
|
+
if (Array.isArray(instancedMesh.material)) instancedMesh.material.forEach((m)=>{
|
|
18258
|
+
if ('color' in m) m.color.set(meshColor);
|
|
18259
|
+
});
|
|
18260
|
+
else if ('color' in instancedMesh.material) instancedMesh.material.color.set(meshColor);
|
|
18261
|
+
}
|
|
18262
|
+
destroy() {
|
|
18263
|
+
this.clear();
|
|
18264
|
+
if (this.map && this.customLayerId) try {
|
|
18265
|
+
this.map.removeLayer(this.customLayerId);
|
|
18266
|
+
} catch {}
|
|
18267
|
+
if (this.renderer) {
|
|
18268
|
+
this.renderer.dispose();
|
|
18269
|
+
this.renderer = null;
|
|
18270
|
+
}
|
|
18271
|
+
this.scene = null;
|
|
18272
|
+
this.camera = null;
|
|
18273
|
+
this.isInitialized = false;
|
|
18274
|
+
this.originalConfigs.clear();
|
|
18275
|
+
}
|
|
18276
|
+
}
|
|
18277
|
+
const instancedModel = InstancedModelManager;
|
|
18278
|
+
const attachInstancedModel = (mapless, name)=>mapless?.use(InstancedModelManager, name);
|
|
18279
|
+
const getInstancedModel = (mapless, name)=>mapless?.get(InstancedModelManager, name);
|
|
18280
|
+
const detachInstancedModel = (mapless, name)=>mapless?.unuse(InstancedModelManager, name);
|
|
17603
18281
|
class Line2Manager extends manager_Manager {
|
|
17604
18282
|
mapThree = null;
|
|
17605
18283
|
lines = new Map();
|
|
@@ -17664,10 +18342,11 @@ class Line2Manager extends manager_Manager {
|
|
|
17664
18342
|
}
|
|
17665
18343
|
calculateTransform(points) {
|
|
17666
18344
|
if (0 === points.length) throw new Error('Cannot calculate transform for empty points');
|
|
17667
|
-
const
|
|
18345
|
+
const transformedFirst = this.mapless?.coordTrans('dataToTile', [
|
|
17668
18346
|
points[0].lng,
|
|
17669
18347
|
points[0].lat
|
|
17670
|
-
]
|
|
18348
|
+
]);
|
|
18349
|
+
const firstPoint = mapbox_gl.MercatorCoordinate.fromLngLat(transformedFirst, points[0].alt);
|
|
17671
18350
|
return {
|
|
17672
18351
|
translateX: firstPoint.x,
|
|
17673
18352
|
translateY: firstPoint.y,
|
|
@@ -17680,10 +18359,11 @@ class Line2Manager extends manager_Manager {
|
|
|
17680
18359
|
points.forEach((point, index)=>{
|
|
17681
18360
|
if (0 === index) positions.push(0, 0, 0);
|
|
17682
18361
|
else {
|
|
17683
|
-
const
|
|
18362
|
+
const transformedPoint = this.mapless?.coordTrans('dataToTile', [
|
|
17684
18363
|
point.lng,
|
|
17685
18364
|
point.lat
|
|
17686
|
-
]
|
|
18365
|
+
]);
|
|
18366
|
+
const currentMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedPoint, point.alt);
|
|
17687
18367
|
const dx = currentMercator.x - transform.translateX;
|
|
17688
18368
|
const dy = currentMercator.y - transform.translateY;
|
|
17689
18369
|
const dz = currentMercator.z - transform.translateZ;
|
|
@@ -17692,6 +18372,23 @@ class Line2Manager extends manager_Manager {
|
|
|
17692
18372
|
});
|
|
17693
18373
|
return positions;
|
|
17694
18374
|
}
|
|
18375
|
+
handleCoordSystemChange(_system) {
|
|
18376
|
+
const mapThree = this.getMapThree();
|
|
18377
|
+
if (!mapThree || 0 === this.lines.size) return;
|
|
18378
|
+
this.lines.forEach((lineData, id)=>{
|
|
18379
|
+
mapThree.removeRenderableObject(id);
|
|
18380
|
+
lineData.transform = this.calculateTransform(lineData.points);
|
|
18381
|
+
const positions = this.convertPoints(lineData.points, lineData.transform);
|
|
18382
|
+
lineData.geometry.setPositions(positions);
|
|
18383
|
+
lineData.geometry.computeBoundingSphere();
|
|
18384
|
+
mapThree.addRenderableObject(id, lineData.line2, {
|
|
18385
|
+
translateX: lineData.transform.translateX,
|
|
18386
|
+
translateY: lineData.transform.translateY,
|
|
18387
|
+
translateZ: lineData.transform.translateZ,
|
|
18388
|
+
scale: lineData.transform.scale
|
|
18389
|
+
});
|
|
18390
|
+
});
|
|
18391
|
+
}
|
|
17695
18392
|
createMaterial(config) {
|
|
17696
18393
|
const colorNumber = 'string' == typeof config.color ? new Color(config.color).getHex() : 'number' == typeof config.color ? config.color : new Color(config.color).getHex();
|
|
17697
18394
|
const material = new LineMaterial({
|
|
@@ -17976,6 +18673,7 @@ class ModelManager extends manager_Manager {
|
|
|
17976
18673
|
prefabs = new Map();
|
|
17977
18674
|
mixers = new Map();
|
|
17978
18675
|
clock = new Clock();
|
|
18676
|
+
modelConfigs = new Map();
|
|
17979
18677
|
constructor(mapless){
|
|
17980
18678
|
super(mapless);
|
|
17981
18679
|
this.map = mapless.map;
|
|
@@ -18037,7 +18735,8 @@ class ModelManager extends manager_Manager {
|
|
|
18037
18735
|
});
|
|
18038
18736
|
this.prefabs.set(modelId, model);
|
|
18039
18737
|
}
|
|
18040
|
-
const
|
|
18738
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
18739
|
+
const modelAsMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, altitude);
|
|
18041
18740
|
const mercatorScale = modelAsMercator.meterInMercatorCoordinateUnits() * scale;
|
|
18042
18741
|
mapThree.addRenderableObject(modelId, model, {
|
|
18043
18742
|
translateX: modelAsMercator.x,
|
|
@@ -18048,6 +18747,13 @@ class ModelManager extends manager_Manager {
|
|
|
18048
18747
|
rotateZ: rotation[2],
|
|
18049
18748
|
scale: mercatorScale
|
|
18050
18749
|
});
|
|
18750
|
+
this.modelConfigs.set(modelId, {
|
|
18751
|
+
url,
|
|
18752
|
+
lngLat,
|
|
18753
|
+
altitude,
|
|
18754
|
+
rotation,
|
|
18755
|
+
scale
|
|
18756
|
+
});
|
|
18051
18757
|
console.log('Model loaded:', {
|
|
18052
18758
|
id: modelId,
|
|
18053
18759
|
transform: {
|
|
@@ -18135,7 +18841,8 @@ class ModelManager extends manager_Manager {
|
|
|
18135
18841
|
}
|
|
18136
18842
|
});
|
|
18137
18843
|
}
|
|
18138
|
-
const
|
|
18844
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
18845
|
+
const modelAsMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, altitude);
|
|
18139
18846
|
const mercatorScale = modelAsMercator.meterInMercatorCoordinateUnits() * scale;
|
|
18140
18847
|
if (groupId) {
|
|
18141
18848
|
const group = mapThree.getGroup(groupId);
|
|
@@ -18150,6 +18857,7 @@ class ModelManager extends manager_Manager {
|
|
|
18150
18857
|
rotateZ: rotation[2],
|
|
18151
18858
|
scale: mercatorScale
|
|
18152
18859
|
});
|
|
18860
|
+
this.modelConfigs.set(id, config);
|
|
18153
18861
|
console.log('Model added:', {
|
|
18154
18862
|
id,
|
|
18155
18863
|
transform: {
|
|
@@ -18167,7 +18875,8 @@ class ModelManager extends manager_Manager {
|
|
|
18167
18875
|
updateModelPosition(id, lngLat, altitude = 0) {
|
|
18168
18876
|
const mapThree = this.getMapThree();
|
|
18169
18877
|
if (!mapThree) return;
|
|
18170
|
-
const
|
|
18878
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
18879
|
+
const modelAsMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, altitude);
|
|
18171
18880
|
const renderableObj = mapThree.getRenderableObject(id);
|
|
18172
18881
|
if (renderableObj) mapThree.updateRenderableObjectTransform(id, {
|
|
18173
18882
|
...renderableObj.transform,
|
|
@@ -18175,6 +18884,11 @@ class ModelManager extends manager_Manager {
|
|
|
18175
18884
|
translateY: modelAsMercator.y,
|
|
18176
18885
|
translateZ: modelAsMercator.z
|
|
18177
18886
|
});
|
|
18887
|
+
const config = this.modelConfigs.get(id);
|
|
18888
|
+
if (config) {
|
|
18889
|
+
config.lngLat = lngLat;
|
|
18890
|
+
config.altitude = altitude;
|
|
18891
|
+
}
|
|
18178
18892
|
}
|
|
18179
18893
|
updateModelRotation(id, rotation) {
|
|
18180
18894
|
const mapThree = this.getMapThree();
|
|
@@ -18222,6 +18936,7 @@ class ModelManager extends manager_Manager {
|
|
|
18222
18936
|
if (!mapThree) return;
|
|
18223
18937
|
mapThree.removeRenderableObject(id);
|
|
18224
18938
|
this.stopAnimation(id);
|
|
18939
|
+
this.modelConfigs.delete(id);
|
|
18225
18940
|
}
|
|
18226
18941
|
clearModels() {
|
|
18227
18942
|
const mapThree = this.getMapThree();
|
|
@@ -18234,6 +18949,24 @@ class ModelManager extends manager_Manager {
|
|
|
18234
18949
|
mixer.stopAllAction();
|
|
18235
18950
|
});
|
|
18236
18951
|
this.mixers.clear();
|
|
18952
|
+
this.modelConfigs.clear();
|
|
18953
|
+
}
|
|
18954
|
+
handleCoordSystemChange(_system) {
|
|
18955
|
+
const mapThree = this.getMapThree();
|
|
18956
|
+
if (!mapThree || 0 === this.modelConfigs.size) return;
|
|
18957
|
+
this.modelConfigs.forEach((config, id)=>{
|
|
18958
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', config.lngLat);
|
|
18959
|
+
const modelAsMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, config.altitude || 0);
|
|
18960
|
+
const mercatorScale = modelAsMercator.meterInMercatorCoordinateUnits() * (config.scale || 1);
|
|
18961
|
+
const renderableObj = mapThree.getRenderableObject(id);
|
|
18962
|
+
if (renderableObj) mapThree.updateRenderableObjectTransform(id, {
|
|
18963
|
+
...renderableObj.transform,
|
|
18964
|
+
translateX: modelAsMercator.x,
|
|
18965
|
+
translateY: modelAsMercator.y,
|
|
18966
|
+
translateZ: modelAsMercator.z,
|
|
18967
|
+
scale: mercatorScale
|
|
18968
|
+
});
|
|
18969
|
+
});
|
|
18237
18970
|
}
|
|
18238
18971
|
getModel(id) {
|
|
18239
18972
|
const mapThree = this.getMapThree();
|
|
@@ -18290,6 +19023,8 @@ class ThreeManager extends manager_Manager {
|
|
|
18290
19023
|
};
|
|
18291
19024
|
boxHelper = null;
|
|
18292
19025
|
isSelected = false;
|
|
19026
|
+
clickCleanup = null;
|
|
19027
|
+
originalModelConfig = null;
|
|
18293
19028
|
constructor(mapless){
|
|
18294
19029
|
super(mapless);
|
|
18295
19030
|
this.map = mapless.map;
|
|
@@ -18315,18 +19050,18 @@ class ThreeManager extends manager_Manager {
|
|
|
18315
19050
|
0,
|
|
18316
19051
|
0,
|
|
18317
19052
|
0
|
|
18318
|
-
], scale = 1) {
|
|
19053
|
+
], scale = 1, color) {
|
|
18319
19054
|
const mapThree = this.getMapThree();
|
|
18320
19055
|
if (!mapThree) throw new Error('MapThree not initialized. Call useThree first.');
|
|
18321
19056
|
const loader = new GLTFLoader();
|
|
18322
19057
|
return new Promise((resolve, reject)=>{
|
|
18323
19058
|
loader.load(url, (gltf)=>{
|
|
18324
19059
|
this.model = gltf.scene;
|
|
18325
|
-
this.model.traverse((child)=>{
|
|
19060
|
+
if (color) this.model.traverse((child)=>{
|
|
18326
19061
|
if (child instanceof Mesh) {
|
|
18327
19062
|
const material = child.material;
|
|
18328
19063
|
if (material.emissive) {
|
|
18329
|
-
material.emissive = new Color(
|
|
19064
|
+
material.emissive = new Color(color);
|
|
18330
19065
|
material.emissiveIntensity = 0.5;
|
|
18331
19066
|
}
|
|
18332
19067
|
}
|
|
@@ -18335,7 +19070,8 @@ class ThreeManager extends manager_Manager {
|
|
|
18335
19070
|
this.baseRotation = [
|
|
18336
19071
|
...rotation
|
|
18337
19072
|
];
|
|
18338
|
-
const
|
|
19073
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
19074
|
+
const modelAsMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, altitude);
|
|
18339
19075
|
this.modelTransform = {
|
|
18340
19076
|
translateX: modelAsMercator.x,
|
|
18341
19077
|
translateY: modelAsMercator.y,
|
|
@@ -18357,6 +19093,14 @@ class ThreeManager extends manager_Manager {
|
|
|
18357
19093
|
action.play();
|
|
18358
19094
|
this.currentAction = action;
|
|
18359
19095
|
}
|
|
19096
|
+
this.originalModelConfig = {
|
|
19097
|
+
url,
|
|
19098
|
+
lngLat,
|
|
19099
|
+
altitude,
|
|
19100
|
+
rotation,
|
|
19101
|
+
scale,
|
|
19102
|
+
color
|
|
19103
|
+
};
|
|
18360
19104
|
const animationNames = this.animations.map((anim)=>anim.name);
|
|
18361
19105
|
resolve({
|
|
18362
19106
|
model: this.model,
|
|
@@ -18399,11 +19143,16 @@ class ThreeManager extends manager_Manager {
|
|
|
18399
19143
|
updatePosition(lngLat, altitude = 0) {
|
|
18400
19144
|
const mapThree = this.getMapThree();
|
|
18401
19145
|
if (!mapThree || !this.model) return;
|
|
18402
|
-
const
|
|
19146
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
19147
|
+
const modelAsMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, altitude);
|
|
18403
19148
|
this.modelTransform.translateX = modelAsMercator.x;
|
|
18404
19149
|
this.modelTransform.translateY = modelAsMercator.y;
|
|
18405
19150
|
this.modelTransform.translateZ = modelAsMercator.z;
|
|
18406
19151
|
this.modelTransform.scale = modelAsMercator.meterInMercatorCoordinateUnits() * this.userScale;
|
|
19152
|
+
if (this.originalModelConfig) {
|
|
19153
|
+
this.originalModelConfig.lngLat = lngLat;
|
|
19154
|
+
this.originalModelConfig.altitude = altitude;
|
|
19155
|
+
}
|
|
18407
19156
|
this._buildFullTransformMatrix(this.currentOrientation.heading, this.currentOrientation.pitch, this.currentOrientation.roll);
|
|
18408
19157
|
}
|
|
18409
19158
|
_applyBaseRotation() {
|
|
@@ -18535,13 +19284,37 @@ class ThreeManager extends manager_Manager {
|
|
|
18535
19284
|
if (!this.boxHelper || !this.model) return;
|
|
18536
19285
|
this.boxHelper.update();
|
|
18537
19286
|
}
|
|
19287
|
+
registerClick(onClick, tolerance = 30) {
|
|
19288
|
+
const mapThree = this.getMapThree();
|
|
19289
|
+
if (!mapThree || !this.modelId) {
|
|
19290
|
+
console.warn('ThreeManager: Cannot register click, MapThree or modelId not available');
|
|
19291
|
+
return null;
|
|
19292
|
+
}
|
|
19293
|
+
if (this.clickCleanup) {
|
|
19294
|
+
this.clickCleanup();
|
|
19295
|
+
this.clickCleanup = null;
|
|
19296
|
+
}
|
|
19297
|
+
const cleanup = mapThree.registerRenderableObjectClick(this.modelId, (_object, point)=>{
|
|
19298
|
+
if (onClick && this.model) onClick(this.model, point);
|
|
19299
|
+
}, tolerance);
|
|
19300
|
+
this.clickCleanup = cleanup;
|
|
19301
|
+
return cleanup;
|
|
19302
|
+
}
|
|
19303
|
+
unregisterClick() {
|
|
19304
|
+
if (this.clickCleanup) {
|
|
19305
|
+
this.clickCleanup();
|
|
19306
|
+
this.clickCleanup = null;
|
|
19307
|
+
}
|
|
19308
|
+
}
|
|
18538
19309
|
dispose() {
|
|
19310
|
+
this.unregisterClick();
|
|
18539
19311
|
this.deselect();
|
|
18540
19312
|
const mapThree = this.getMapThree();
|
|
18541
19313
|
if (mapThree && this.modelId) mapThree.removeRenderableObject(this.modelId);
|
|
18542
19314
|
this.model = null;
|
|
18543
19315
|
this.animations = [];
|
|
18544
19316
|
this.currentAction = null;
|
|
19317
|
+
this.originalModelConfig = null;
|
|
18545
19318
|
if (this.mixer) {
|
|
18546
19319
|
this.mixer.stopAllAction();
|
|
18547
19320
|
this.mixer = null;
|
|
@@ -18550,6 +19323,19 @@ class ThreeManager extends manager_Manager {
|
|
|
18550
19323
|
this.updateAnimation();
|
|
18551
19324
|
});
|
|
18552
19325
|
}
|
|
19326
|
+
handleCoordSystemChange(_system) {
|
|
19327
|
+
if (!this.originalModelConfig) return;
|
|
19328
|
+
const mapThree = this.getMapThree();
|
|
19329
|
+
if (!mapThree || !this.model) return;
|
|
19330
|
+
const { lngLat, altitude } = this.originalModelConfig;
|
|
19331
|
+
const transformedLngLat = this.mapless?.coordTrans('dataToTile', lngLat);
|
|
19332
|
+
const modelAsMercator = mapbox_gl.MercatorCoordinate.fromLngLat(transformedLngLat, altitude);
|
|
19333
|
+
this.modelTransform.translateX = modelAsMercator.x;
|
|
19334
|
+
this.modelTransform.translateY = modelAsMercator.y;
|
|
19335
|
+
this.modelTransform.translateZ = modelAsMercator.z;
|
|
19336
|
+
this.modelTransform.scale = modelAsMercator.meterInMercatorCoordinateUnits() * this.userScale;
|
|
19337
|
+
this._buildFullTransformMatrix(this.currentOrientation.heading, this.currentOrientation.pitch, this.currentOrientation.roll);
|
|
19338
|
+
}
|
|
18553
19339
|
destroy() {
|
|
18554
19340
|
this.dispose();
|
|
18555
19341
|
}
|
|
@@ -20482,4 +21268,4 @@ function detachPathTracker(mapless) {
|
|
|
20482
21268
|
pathTrackerManagers.delete(mapless);
|
|
20483
21269
|
}
|
|
20484
21270
|
}
|
|
20485
|
-
export { AirspaceManager, basicObject as BasicThreeObjectManager, ClickStrategy, CoordTransformer, curve3d as Curve3DManager, Draw, elevatedLine as ElevatedLineManager, EmitManager, FixedRectangleLayer as FixedRectangleLayerManager, FreeStrategy, Lang, line2Manager as Line2Manager, LngLat, manager_Manager as Manager, mapModel as MapModelManager, MapMouseEvent, Mapless_Base as Mapless, Marker, MercatorCoordinate, mana_three_model as ModelManager, MultiCoordTransformer, OldStationManager, paint_PaintBoard as PaintBoard, PathCollectionStrategy, path_PathTracker as PathTracker, Popup, PositionMarker, PositionMouse, QuickTrans, RectangleLayer as RectangleLayerManager, icons_Singleton as Singleton, three as ThreeManager, adjustMapConfigByCoord, attachAirspace, attachBasicObject, attachBoundary, attachCluster, attachCurve, attachCurve3D, attachElevatedLine, attachFixedRectangleLayer, attachHeatmap, attachImageData, attachLine, attachLine2, attachMapModel, attachMarker, attachModel, attachMovable, attachNewStation, attachNode, attachOldStation, attachPathTracker, attachPolygon, attachRectangleLayer, attachRoutes, attachShape, attachStep, attachText, attachThree, attachTrack, buildTileUrl, calculateObjectsInPolygon, createCoordTransformer, darkFog, darkSource, defaultSource, detachAirspace, detachBasicObject, detachBoundary, detachCluster, detachCurve, detachCurve3D, detachElevatedLine, detachFixedRectangleLayer, detachHeatmap, detachImageData, detachLine, detachLine2, detachMapModel, detachMarker, detachModel, detachMovable, detachNewStation, detachNode, detachOldStation, detachPathTracker, detachPolygon, detachRectangleLayer, detachRoutes, detachShape, detachStep, detachText, detachThree, detachTrack, ellipse, genPrefixId, getAirspace, getAllSourceCoordSystems, getBasicObject, getBoundary, getCluster, getCoordDisplayName, getCurve, getCurve3D, getElevatedLine, getFixedRectangleLayer, getHeatmap, getImageData, getLine, getLine2, getMapModel, getMarker, getModel, getMovable, getNewStation, getNode, getOldStation, getPaintCenter, getPaintCenterNRadius, getPaintPolygon, getPathTracker, getPolygon, getRectangleLayer, getRoutes, getShape, getSourceCoordSystem, getSourcesByCoordSystem, getStep, getText, getThree, getTrack, isValidCoordinate, lightFog, lightSource, lite, mapbox_gl as mapboxgl, maplessPreset, point2Feature, propwmsTransformRequest, sourcesMap, newstation_stateColorRule as stateColorRule, test2Point, throttle, transformCoordinate, transformCoordinateBetweenSources, transformCoordinates, transformMapCenter, tryFunc, tryTrans };
|
|
21271
|
+
export { AirspaceManager, basicObject as BasicThreeObjectManager, ClickStrategy, CoordTransformer, curve3d as Curve3DManager, Draw, elevatedLine as ElevatedLineManager, EmitManager, FixedRectangleLayer as FixedRectangleLayerManager, FreeStrategy, instancedModel as InstancedModelManager, Lang, line2Manager as Line2Manager, LngLat, manager_Manager as Manager, mapModel as MapModelManager, MapMouseEvent, Mapless_Base as Mapless, Marker, MercatorCoordinate, mana_three_model as ModelManager, MultiCoordTransformer, OldStationManager, paint_PaintBoard as PaintBoard, PathCollectionStrategy, path_PathTracker as PathTracker, Popup, PositionMarker, PositionMouse, QuickTrans, RectangleLayer as RectangleLayerManager, icons_Singleton as Singleton, three as ThreeManager, adjustMapConfigByCoord, attachAirspace, attachBasicObject, attachBoundary, attachCluster, attachCurve, attachCurve3D, attachElevatedLine, attachFixedRectangleLayer, attachHeatmap, attachImageData, attachInstancedModel, attachLine, attachLine2, attachMapModel, attachMarker, attachModel, attachMovable, attachNewStation, attachNode, attachOldStation, attachPathTracker, attachPolygon, attachRectangleLayer, attachRoutes, attachShape, attachStep, attachText, attachThree, attachTrack, buildTileUrl, calculateObjectsInPolygon, createCoordTransformer, darkFog, darkSource, defaultSource, detachAirspace, detachBasicObject, detachBoundary, detachCluster, detachCurve, detachCurve3D, detachElevatedLine, detachFixedRectangleLayer, detachHeatmap, detachImageData, detachInstancedModel, detachLine, detachLine2, detachMapModel, detachMarker, detachModel, detachMovable, detachNewStation, detachNode, detachOldStation, detachPathTracker, detachPolygon, detachRectangleLayer, detachRoutes, detachShape, detachStep, detachText, detachThree, detachTrack, ellipse, genPrefixId, getAirspace, getAllSourceCoordSystems, getBasicObject, getBoundary, getCluster, getCoordDisplayName, getCurve, getCurve3D, getElevatedLine, getFixedRectangleLayer, getHeatmap, getImageData, getInstancedModel, getLine, getLine2, getMapModel, getMarker, getModel, getMovable, getNewStation, getNode, getOldStation, getPaintCenter, getPaintCenterNRadius, getPaintPolygon, getPathTracker, getPolygon, getRectangleLayer, getRoutes, getShape, getSourceCoordSystem, getSourcesByCoordSystem, getStep, getText, getThree, getTrack, isValidCoordinate, lightFog, lightSource, lite, mapbox_gl as mapboxgl, maplessPreset, point2Feature, propwmsTransformRequest, sourcesMap, newstation_stateColorRule as stateColorRule, test2Point, throttle, transformCoordinate, transformCoordinateBetweenSources, transformCoordinates, transformMapCenter, tryFunc, tryTrans };
|