@openglobus/og 0.10.3 → 0.10.6
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/css/og.css +1 -1
- package/package.json +4 -4
- package/src/og/Extent.js +274 -273
- package/src/og/Globe.js +11 -3
- package/src/og/LonLat.js +148 -147
- package/src/og/camera/PlanetCamera.js +110 -38
- package/src/og/control/EarthNavigation.js +259 -0
- package/src/og/control/MouseNavigation.js +68 -40
- package/src/og/layer/CanvasTiles.js +32 -30
- package/src/og/layer/KML.js +157 -0
- package/src/og/quadTree/Node.js +72 -19
- package/src/og/renderer/RendererEvents.js +21 -16
- package/src/og/scene/Planet.js +7 -2
- package/src/og/segment/Segment.js +2 -4
- package/src/og/utils/FontAtlas.js +1 -0
- package/src/og/{segment → utils}/PlainSegmentWorker.js +425 -407
- package/src/og/webgl/Handler.js +866 -845
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module og/layer/KML
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
import { Entity } from '../entity/Entity.js';
|
|
7
|
+
import { Extent } from '../Extent.js';
|
|
8
|
+
import { LonLat } from '../LonLat.js';
|
|
9
|
+
import { Vector } from './Vector.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Layer to render KMLs files
|
|
13
|
+
* @class
|
|
14
|
+
* @extends {og.Vector}
|
|
15
|
+
*/
|
|
16
|
+
export class KML extends Vector {
|
|
17
|
+
|
|
18
|
+
_billboard = { src: 'https://openglobus.org/examples/billboards/carrot.png' };
|
|
19
|
+
_color = '#6689db';
|
|
20
|
+
|
|
21
|
+
constructor(name, options = {}) {
|
|
22
|
+
super(name, options);
|
|
23
|
+
this._extent = null;
|
|
24
|
+
this._billboard = options.billboard || this._billboard;
|
|
25
|
+
this._color = options.color || this._color;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get instanceName() {
|
|
29
|
+
return 'KML';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @private
|
|
34
|
+
*/
|
|
35
|
+
_extractCoordonatesFromKml(xmlDoc) {
|
|
36
|
+
const raw = Array.from(xmlDoc.getElementsByTagName('coordinates'));
|
|
37
|
+
const coordinates = raw.map(item => item.textContent.trim().replace(/\n/g, ' ').split(' ').map(co => co.split(',').map(parseFloat)));
|
|
38
|
+
return coordinates;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Creates billboards or polylines from array of lonlat.
|
|
43
|
+
* @private
|
|
44
|
+
* @param {Array} coordonates
|
|
45
|
+
* @param {string} color
|
|
46
|
+
* @returns {Array<og.Entity>}
|
|
47
|
+
*/
|
|
48
|
+
_convertCoordonatesIntoEntities(coordinates, color, billboard) {
|
|
49
|
+
const extent = new Extent(new LonLat(180.0, 90.0), new LonLat(-180.0, -90.0));
|
|
50
|
+
const addToExtent = (c) => {
|
|
51
|
+
const lon = c[0], lat = c[1];
|
|
52
|
+
if (lon < extent.southWest.lon) extent.southWest.lon = lon;
|
|
53
|
+
if (lat < extent.southWest.lat) extent.southWest.lat = lat;
|
|
54
|
+
if (lon > extent.northEast.lon) extent.northEast.lon = lon;
|
|
55
|
+
if (lat > extent.northEast.lat) extent.northEast.lat = lat;
|
|
56
|
+
};
|
|
57
|
+
const _pathes = [];
|
|
58
|
+
coordinates.forEach(kmlFile => kmlFile.forEach(p => _pathes.push(p)));
|
|
59
|
+
const entities = _pathes.map(path => {
|
|
60
|
+
if (path.length === 1) {
|
|
61
|
+
const lonlat = path[0];
|
|
62
|
+
const _entity = new Entity({ lonlat, billboard });
|
|
63
|
+
addToExtent(lonlat);
|
|
64
|
+
return _entity;
|
|
65
|
+
} else if (path.length > 1) {
|
|
66
|
+
const pathLonLat = path.map(item => {
|
|
67
|
+
addToExtent(item);
|
|
68
|
+
return new LonLat(item[0], item[1], item[2]);
|
|
69
|
+
});
|
|
70
|
+
const _entity = new Entity({ polyline: { pathLonLat: [pathLonLat], thickness: 3, color, isClosed: false } });
|
|
71
|
+
return _entity;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return { entities, extent };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
80
|
+
_getXmlContent(file) {
|
|
81
|
+
return new Promise(resolve => {
|
|
82
|
+
const fileReader = new FileReader();
|
|
83
|
+
fileReader.onload = async i => resolve((new DOMParser()).parseFromString(i.target.result, 'text/xml'));
|
|
84
|
+
fileReader.readAsText(file);
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
91
|
+
_expandExtents(extent1, extent2) {
|
|
92
|
+
if (!extent1) return extent2;
|
|
93
|
+
if (extent2.southWest.lon < extent1.southWest.lon) extent1.southWest.lon = extent2.southWest.lon;
|
|
94
|
+
if (extent2.southWest.lat < extent1.southWest.lat) extent1.southWest.lat = extent2.southWest.lat;
|
|
95
|
+
if (extent2.northEast.lon > extent1.northEast.lon) extent1.northEast.lon = extent2.northEast.lon;
|
|
96
|
+
if (extent2.northEast.lat > extent1.northEast.lat) extent1.northEast.lat = extent2.northEast.lat;
|
|
97
|
+
return extent1;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @public
|
|
102
|
+
* @param {File[]} kmls
|
|
103
|
+
* @returns {Promise}
|
|
104
|
+
*/
|
|
105
|
+
async addKmlFromFiles(kmls) {
|
|
106
|
+
const kmlObjs = await Promise.all(kmls.map(this._getXmlContent));
|
|
107
|
+
const coordonates = kmlObjs.map(this._extractCoordonatesFromKml);
|
|
108
|
+
const { entities, extent } = this._convertCoordonatesIntoEntities(coordonates, this._color, this._billboard);
|
|
109
|
+
this._extent = this._expandExtents(this._extent, extent);
|
|
110
|
+
entities.forEach(this.add.bind(this));
|
|
111
|
+
return { entities, extent };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @param {string} color
|
|
116
|
+
* @public
|
|
117
|
+
*/
|
|
118
|
+
setColor(color) {
|
|
119
|
+
this._color = color;
|
|
120
|
+
this._billboard.color = color;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @private
|
|
125
|
+
*/
|
|
126
|
+
_getKmlFromUrl(url) {
|
|
127
|
+
return new Promise((resolve, reject) => {
|
|
128
|
+
const request = new XMLHttpRequest();
|
|
129
|
+
request.open('GET', url, true);
|
|
130
|
+
request.responseType = 'document';
|
|
131
|
+
request.overrideMimeType('text/xml');
|
|
132
|
+
request.onload = () => {
|
|
133
|
+
if (request.readyState === request.DONE && request.status === 200) {
|
|
134
|
+
resolve(request.responseXML);
|
|
135
|
+
} else {
|
|
136
|
+
reject(new Error('no valid kml file'));
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
request.send();
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @public
|
|
145
|
+
* @param {string} url - Url of the KML to display. './myFile.kml' or 'http://mySite/myFile.kml' for example.
|
|
146
|
+
* @returns {Promise}
|
|
147
|
+
*/
|
|
148
|
+
async addKmlFromUrl(url) {
|
|
149
|
+
const kml = await this._getKmlFromUrl(url);
|
|
150
|
+
const coordonates = this._extractCoordonatesFromKml(kml);
|
|
151
|
+
const { entities, extent } = this._convertCoordonatesIntoEntities([coordonates], this._color, this._billboard);
|
|
152
|
+
this._extent = this._expandExtents(this._extent, extent);
|
|
153
|
+
entities.forEach(this.add.bind(this));
|
|
154
|
+
return { entities, extent };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
};
|
package/src/og/quadTree/Node.js
CHANGED
|
@@ -32,8 +32,7 @@ import {
|
|
|
32
32
|
|
|
33
33
|
import { MAX_NORMAL_ZOOM } from "../segment/Segment.js";
|
|
34
34
|
|
|
35
|
-
const
|
|
36
|
-
const VISIBLE_HEIGHT = 3000000.0;
|
|
35
|
+
const VISIBLE_HEIGHT = 1400000.0;
|
|
37
36
|
|
|
38
37
|
let _tempHigh = new Vec3(),
|
|
39
38
|
_tempLow = new Vec3();
|
|
@@ -255,7 +254,7 @@ Node.prototype.renderTree = function (cam, maxZoom, terrainReadySegment, stopLoa
|
|
|
255
254
|
}
|
|
256
255
|
}
|
|
257
256
|
} else {
|
|
258
|
-
let commonFrustumFlag = 1 << (numFrustums - 1 - 1);
|
|
257
|
+
let commonFrustumFlag = 1 << (numFrustums - 1 - 1);
|
|
259
258
|
for (let i = 0; commonFrustumFlag && i < numFrustums; i++) {
|
|
260
259
|
if (seg.terrainReady) {
|
|
261
260
|
if (frustums[i].containsBox(seg.bbox)) {
|
|
@@ -332,13 +331,13 @@ Node.prototype.prepareForRendering = function (
|
|
|
332
331
|
} else {
|
|
333
332
|
if (seg.tileZoom < 2) {
|
|
334
333
|
this.renderNode(inFrustum, !inFrustum, terrainReadySegment, stopLoading);
|
|
335
|
-
} else if (seg.tileZoom
|
|
334
|
+
} else if (seg.tileZoom > MAX_NORMAL_ZOOM) {
|
|
336
335
|
this.renderNode(inFrustum, !inFrustum, terrainReadySegment, stopLoading);
|
|
337
336
|
} else if (
|
|
338
|
-
seg._swNorm.dot(cam.
|
|
339
|
-
seg._nwNorm.dot(cam.
|
|
340
|
-
seg._neNorm.dot(cam.
|
|
341
|
-
seg._seNorm.dot(cam.
|
|
337
|
+
seg._swNorm.dot(cam._n) > 0.0 ||
|
|
338
|
+
seg._nwNorm.dot(cam._n) > 0.0 ||
|
|
339
|
+
seg._neNorm.dot(cam._n) > 0.0 ||
|
|
340
|
+
seg._seNorm.dot(cam._n) > 0.0
|
|
342
341
|
) {
|
|
343
342
|
this.renderNode(inFrustum, !inFrustum, terrainReadySegment, stopLoading);
|
|
344
343
|
} else {
|
|
@@ -478,26 +477,80 @@ Node.prototype.getCommonSide = function (node) {
|
|
|
478
477
|
b_sw_lon = b_sw.lon,
|
|
479
478
|
b_sw_lat = b_sw.lat;
|
|
480
479
|
|
|
480
|
+
if (as._tileGroup === bs._tileGroup) {
|
|
481
|
+
if (
|
|
482
|
+
a_ne_lon === b_sw_lon &&
|
|
483
|
+
((a_ne_lat <= b_ne_lat && a_sw_lat >= b_sw_lat) ||
|
|
484
|
+
(a_ne_lat >= b_ne_lat && a_sw_lat <= b_sw_lat))
|
|
485
|
+
) {
|
|
486
|
+
return E;
|
|
487
|
+
} else if (
|
|
488
|
+
a_sw_lon === b_ne_lon &&
|
|
489
|
+
((a_ne_lat <= b_ne_lat && a_sw_lat >= b_sw_lat) ||
|
|
490
|
+
(a_ne_lat >= b_ne_lat && a_sw_lat <= b_sw_lat))
|
|
491
|
+
) {
|
|
492
|
+
return W;
|
|
493
|
+
} else if (
|
|
494
|
+
a_ne_lat === b_sw_lat &&
|
|
495
|
+
((a_sw_lon >= b_sw_lon && a_ne_lon <= b_ne_lon) ||
|
|
496
|
+
(a_sw_lon <= b_sw_lon && a_ne_lon >= b_ne_lon))
|
|
497
|
+
) {
|
|
498
|
+
return N;
|
|
499
|
+
} else if (
|
|
500
|
+
a_sw_lat === b_ne_lat &&
|
|
501
|
+
((a_sw_lon >= b_sw_lon && a_ne_lon <= b_ne_lon) ||
|
|
502
|
+
(a_sw_lon <= b_sw_lon && a_ne_lon >= b_ne_lon))
|
|
503
|
+
) {
|
|
504
|
+
return S;
|
|
505
|
+
} else if (
|
|
506
|
+
bs.tileX === 0 &&
|
|
507
|
+
as.tileX === Math.pow(2, as.tileZoom) - 1 &&
|
|
508
|
+
((a_ne_lat <= b_ne_lat && a_sw_lat >= b_sw_lat) ||
|
|
509
|
+
(a_ne_lat >= b_ne_lat && a_sw_lat <= b_sw_lat))
|
|
510
|
+
) {
|
|
511
|
+
return E;
|
|
512
|
+
} else if (
|
|
513
|
+
as.tileX === 0 &&
|
|
514
|
+
bs.tileX === Math.pow(2, bs.tileZoom) - 1 &&
|
|
515
|
+
((a_ne_lat <= b_ne_lat && a_sw_lat >= b_sw_lat) ||
|
|
516
|
+
(a_ne_lat >= b_ne_lat && a_sw_lat <= b_sw_lat))
|
|
517
|
+
) {
|
|
518
|
+
return W;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
481
522
|
if (
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
523
|
+
as._tileGroup === 0 &&
|
|
524
|
+
bs._tileGroup === 1 &&
|
|
525
|
+
as.tileY === 0 &&
|
|
526
|
+
bs.tileY === Math.pow(2, bs.tileZoom) - 1 &&
|
|
527
|
+
((a_sw_lon >= b_sw_lon && a_ne_lon <= b_ne_lon) ||
|
|
528
|
+
(a_sw_lon <= b_sw_lon && a_ne_lon >= b_ne_lon))
|
|
485
529
|
) {
|
|
486
|
-
return
|
|
530
|
+
return N;
|
|
487
531
|
} else if (
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
532
|
+
as._tileGroup === 2 &&
|
|
533
|
+
bs._tileGroup === 0 &&
|
|
534
|
+
as.tileY === 0 &&
|
|
535
|
+
bs.tileY === Math.pow(2, bs.tileZoom) - 1 &&
|
|
536
|
+
((a_sw_lon >= b_sw_lon && a_ne_lon <= b_ne_lon) ||
|
|
537
|
+
(a_sw_lon <= b_sw_lon && a_ne_lon >= b_ne_lon))
|
|
491
538
|
) {
|
|
492
|
-
return
|
|
539
|
+
return N;
|
|
493
540
|
} else if (
|
|
494
|
-
|
|
541
|
+
bs._tileGroup === 1 &&
|
|
542
|
+
as._tileGroup === 0 &&
|
|
543
|
+
as.tileY === Math.pow(2, as.tileZoom) - 1 &&
|
|
544
|
+
bs.tileY === 0 &&
|
|
495
545
|
((a_sw_lon >= b_sw_lon && a_ne_lon <= b_ne_lon) ||
|
|
496
546
|
(a_sw_lon <= b_sw_lon && a_ne_lon >= b_ne_lon))
|
|
497
547
|
) {
|
|
498
|
-
return
|
|
548
|
+
return S;
|
|
499
549
|
} else if (
|
|
500
|
-
|
|
550
|
+
as._tileGroup === 1 &&
|
|
551
|
+
bs._tileGroup === 0 &&
|
|
552
|
+
as.tileY === Math.pow(2, as.tileZoom) - 1 &&
|
|
553
|
+
bs.tileY === 0 &&
|
|
501
554
|
((a_sw_lon >= b_sw_lon && a_ne_lon <= b_ne_lon) ||
|
|
502
555
|
(a_sw_lon <= b_sw_lon && a_ne_lon >= b_ne_lon))
|
|
503
556
|
) {
|
|
@@ -301,33 +301,38 @@ class RendererEvents extends Events {
|
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
/**
|
|
304
|
-
* @
|
|
304
|
+
* @protected
|
|
305
305
|
*/
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
this.mouseState.leftButtonDown = true;
|
|
306
|
+
updateButtonsStates(buttons) {
|
|
307
|
+
var ms = this.mouseState;
|
|
308
|
+
if (buttons & LB_M) {
|
|
309
|
+
ms.leftButtonDown = true;
|
|
311
310
|
} else {
|
|
312
|
-
|
|
313
|
-
|
|
311
|
+
ms.leftButtonHold = false;
|
|
312
|
+
ms.leftButtonDown = false;
|
|
314
313
|
}
|
|
315
314
|
|
|
316
|
-
if (
|
|
317
|
-
|
|
315
|
+
if (buttons & RB_M) {
|
|
316
|
+
ms.rightButtonDown = true;
|
|
318
317
|
} else {
|
|
319
|
-
|
|
320
|
-
|
|
318
|
+
ms.rightButtonHold = false;
|
|
319
|
+
ms.rightButtonDown = false;
|
|
321
320
|
}
|
|
322
321
|
|
|
323
|
-
if (
|
|
324
|
-
|
|
322
|
+
if (buttons & MB_M) {
|
|
323
|
+
ms.middleButtonDown = true;
|
|
325
324
|
} else {
|
|
326
|
-
|
|
327
|
-
|
|
325
|
+
ms.middleButtonHold = false;
|
|
326
|
+
ms.middleButtonDown = false;
|
|
328
327
|
}
|
|
328
|
+
}
|
|
329
329
|
|
|
330
|
+
/**
|
|
331
|
+
* @private
|
|
332
|
+
*/
|
|
333
|
+
onMouseMove(event, sys) {
|
|
330
334
|
var ms = this.mouseState;
|
|
335
|
+
this.updateButtonsStates(sys.buttons)
|
|
331
336
|
ms.sys = event;
|
|
332
337
|
|
|
333
338
|
let ex = event.clientX,
|
package/src/og/scene/Planet.js
CHANGED
|
@@ -24,7 +24,7 @@ import { PlanetCamera } from "../camera/PlanetCamera.js";
|
|
|
24
24
|
import { RenderNode } from "./RenderNode.js";
|
|
25
25
|
import { Segment } from "../segment/Segment.js";
|
|
26
26
|
import { SegmentLonLat } from "../segment/SegmentLonLat.js";
|
|
27
|
-
import { PlainSegmentWorker } from "../
|
|
27
|
+
import { PlainSegmentWorker } from "../utils/PlainSegmentWorker.js";
|
|
28
28
|
import { TerrainWorker } from "../utils/TerrainWorker.js";
|
|
29
29
|
import { VectorTileCreator } from "../utils/VectorTileCreator.js";
|
|
30
30
|
import { wgs84 } from "../ellipsoid/wgs84.js";
|
|
@@ -174,6 +174,9 @@ class Planet extends RenderNode {
|
|
|
174
174
|
*/
|
|
175
175
|
this.camera = null;
|
|
176
176
|
|
|
177
|
+
this._minAltitude = options.minAltitude;
|
|
178
|
+
this._maxAltitude = options.maxAltitude;
|
|
179
|
+
|
|
177
180
|
/**
|
|
178
181
|
* Screen mouse pointer projected to planet cartesian position.
|
|
179
182
|
* @public
|
|
@@ -699,7 +702,9 @@ class Planet extends RenderNode {
|
|
|
699
702
|
this.camera = this.renderer.activeCamera = new PlanetCamera(this, {
|
|
700
703
|
eye: new Vec3(0, 0, 28000000),
|
|
701
704
|
look: new Vec3(0, 0, 0),
|
|
702
|
-
up: new Vec3(0, 1, 0)
|
|
705
|
+
up: new Vec3(0, 1, 0),
|
|
706
|
+
minAltitude: this._minAltitude,
|
|
707
|
+
maxAltitude: this._maxAltitude
|
|
703
708
|
});
|
|
704
709
|
|
|
705
710
|
this.camera.update();
|
|
@@ -31,8 +31,6 @@ var _RenderingSlice = function (p) {
|
|
|
31
31
|
};
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
//const BSPHERERADIUSEXT = 2;
|
|
35
|
-
|
|
36
34
|
/**
|
|
37
35
|
* Planet segment Web Mercator tile class that stored and rendered with quad tree.
|
|
38
36
|
* @class
|
|
@@ -1002,7 +1000,7 @@ Segment.prototype.createBoundsByExtent = function () {
|
|
|
1002
1000
|
var coord_ne = ellipsoid.geodeticToCartesian(extent.northEast.lon, extent.northEast.lat);
|
|
1003
1001
|
|
|
1004
1002
|
// check for zoom
|
|
1005
|
-
if (this.tileZoom
|
|
1003
|
+
if (this.tileZoom <= MAX_NORMAL_ZOOM) {
|
|
1006
1004
|
var coord_nw = ellipsoid.geodeticToCartesian(extent.southWest.lon, extent.northEast.lat);
|
|
1007
1005
|
var coord_se = ellipsoid.geodeticToCartesian(extent.northEast.lon, extent.southWest.lat);
|
|
1008
1006
|
|
|
@@ -1039,7 +1037,7 @@ Segment.prototype.createBoundsByParent = function () {
|
|
|
1039
1037
|
this.bsphere.center.z = pn.segment.bsphere.center.z;
|
|
1040
1038
|
this.bsphere.radius = pn.segment.bsphere.radius;
|
|
1041
1039
|
|
|
1042
|
-
if (this.tileZoom
|
|
1040
|
+
if (this.tileZoom <= MAX_NORMAL_ZOOM) {
|
|
1043
1041
|
let i0 = gridSize * offsetY;
|
|
1044
1042
|
let j0 = gridSize * offsetX;
|
|
1045
1043
|
|