@openglobus/og 0.13.4 → 0.13.7

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.
Files changed (55) hide show
  1. package/css/og.css +66 -25
  2. package/dist/@openglobus/og.css +1 -1
  3. package/dist/@openglobus/og.esm.js +2 -2
  4. package/dist/@openglobus/og.esm.js.map +1 -1
  5. package/dist/@openglobus/og.umd.js +2 -2
  6. package/dist/@openglobus/og.umd.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/og/Events.js +188 -188
  9. package/src/og/Extent.js +1 -9
  10. package/src/og/Globe.js +1 -0
  11. package/src/og/control/DebugInfo.js +15 -4
  12. package/src/og/control/EarthCoordinates.js +151 -160
  13. package/src/og/control/KeyboardNavigation.js +48 -2
  14. package/src/og/control/TouchNavigation.js +13 -13
  15. package/src/og/control/ZoomControl.js +1 -1
  16. package/src/og/ellipsoid/Ellipsoid.js +1 -1
  17. package/src/og/entity/Billboard.js +165 -165
  18. package/src/og/entity/BillboardHandler.js +1 -1
  19. package/src/og/entity/Geometry.js +319 -319
  20. package/src/og/entity/Label.js +348 -346
  21. package/src/og/entity/LabelHandler.js +44 -37
  22. package/src/og/input/input.js +7 -1
  23. package/src/og/layer/CanvasTiles.js +8 -8
  24. package/src/og/layer/KML.js +181 -12
  25. package/src/og/layer/Layer.js +4 -2
  26. package/src/og/layer/XYZ.js +4 -2
  27. package/src/og/quadTree/Node.js +1 -0
  28. package/src/og/renderer/RendererEvents.js +17 -3
  29. package/src/og/scene/Planet.js +89 -30
  30. package/src/og/segment/Segment.js +1 -0
  31. package/src/og/shaders/label.js +56 -13
  32. package/src/og/terrain/EmptyTerrain.js +164 -146
  33. package/src/og/terrain/Geoid.js +246 -241
  34. package/src/og/terrain/GlobusTerrain.js +23 -24
  35. package/src/og/terrain/MapboxTerrain.js +292 -294
  36. package/src/og/utils/FontAtlas.js +25 -15
  37. package/src/og/utils/Loader.js +53 -12
  38. package/src/og/utils/PlainSegmentWorker.js +38 -26
  39. package/src/og/utils/TextureAtlas.js +291 -280
  40. package/src/og/utils/units.js +78 -0
  41. package/types/control/EarthCoordinates.d.ts +27 -30
  42. package/types/control/KeyboardNavigation.d.ts +3 -0
  43. package/types/entity/Label.d.ts +1 -0
  44. package/types/entity/LabelHandler.d.ts +1 -1
  45. package/types/input/input.d.ts +6 -0
  46. package/types/layer/KML.d.ts +26 -1
  47. package/types/renderer/RendererEvents.d.ts +2 -0
  48. package/types/scene/Planet.d.ts +10 -1
  49. package/types/terrain/EmptyTerrain.d.ts +4 -1
  50. package/types/terrain/Geoid.d.ts +1 -10
  51. package/types/terrain/GlobusTerrain.d.ts +0 -2
  52. package/types/terrain/MapboxTerrain.d.ts +1 -1
  53. package/types/utils/Loader.d.ts +3 -0
  54. package/types/utils/TextureAtlas.d.ts +2 -0
  55. package/types/utils/units.d.ts +20 -0
@@ -1,280 +1,291 @@
1
- "use strict";
2
-
3
- import { ImageCanvas } from "../ImageCanvas.js";
4
- import { Rectangle } from "../Rectangle.js";
5
- import { ImagesCacheManager } from "./ImagesCacheManager.js";
6
-
7
- /**
8
- * Texture atlas stores images in one texture. Each image has its own
9
- * atlas texture coordinates.
10
- * @class
11
- * @param {number} [width] - Texture atlas width, if it hasn't 1024 default.
12
- * @param {number} [height] - Texture atlas height, if it hasn't 1024 default..
13
- */
14
- class TextureAtlas {
15
- constructor(width = 1024, height = 1024) {
16
- /**
17
- * Atlas nodes where input images store. It can be access by image.__nodeIndex.
18
- * @public
19
- * @type {Array.<utils.TextureAtlasNode >}
20
- */
21
- this.nodes = [];
22
-
23
- /**
24
- * Created gl texture.
25
- * @public
26
- */
27
- this.texture = null;
28
-
29
- /**
30
- * Atlas canvas.
31
- * @public
32
- * @type {canvas}
33
- */
34
- this.canvas = new ImageCanvas(width, height);
35
- this.clearCanvas();
36
-
37
- this._handler = null;
38
- this._images = [];
39
- this._btree = null;
40
- this._imagesCacheManager = new ImagesCacheManager();
41
- this.borderSize = 4;
42
- }
43
-
44
- /**
45
- * Returns atlas javascript image object.
46
- * @public
47
- * @returns {Object} -
48
- */
49
- getImage() {
50
- return this.canvas.getImage();
51
- }
52
-
53
- /**
54
- * Returns canvas object.
55
- * @public
56
- * @returns {Object} -
57
- */
58
- getCanvas() {
59
- return this.canvas._canvas;
60
- }
61
-
62
- /**
63
- * Clear atlas with black.
64
- * @public
65
- */
66
- clearCanvas() {
67
- this.canvas.fillEmpty("black");
68
- }
69
-
70
- /**
71
- * Sets openglobus gl handler that creates gl texture.
72
- * @public
73
- * @param {Handler} handler - WebGL handler.
74
- */
75
- assignHandler(handler) {
76
- this._handler = handler;
77
- this.createTexture();
78
- }
79
-
80
- /**
81
- * Returns image diagonal size.
82
- * @param {Object} image - JavaSript image object.
83
- * @returns {number} -
84
- */
85
- getDiagonal(image) {
86
- var w = image.atlasWidth || image.width,
87
- h = image.atlasHeight || image.height;
88
- return Math.sqrt(w * w + h * h);
89
- }
90
-
91
- /**
92
- * Adds image to the atlas and returns creted node with texture coordinates of the stored image.
93
- * @public
94
- * @param {Object} image - Input javascript image object.
95
- * @param {boolean} [fastInsert] - If it's true atlas doesnt restore all images again
96
- * and store image in the curent atlas sheme.
97
- * @returns {utils.TextureAtlasNode} -
98
- */
99
- addImage(image, fastInsert) {
100
- if (!(image.width && image.height)) {
101
- return;
102
- }
103
-
104
- this._images.push(image);
105
-
106
- this._makeAtlas(fastInsert);
107
-
108
- return this.nodes[image.__nodeIndex];
109
- }
110
-
111
- _completeNode(nodes, node) {
112
- if (node) {
113
- var w = this.canvas.getWidth(),
114
- h = this.canvas.getHeight();
115
- var im = node.image;
116
- var r = node.rect;
117
- var bs = Math.round(this.borderSize * 0.5);
118
- this.canvas.drawImage(im, r.left + bs, r.top + bs, im.atlasWidth, im.atlasHeight);
119
- var tc = node.texCoords;
120
-
121
- tc[0] = (r.left + bs) / w;
122
- tc[1] = (r.top + bs) / h;
123
-
124
- tc[2] = (r.left + bs) / w;
125
- tc[3] = (r.bottom - bs) / h;
126
-
127
- tc[4] = (r.right - bs) / w;
128
- tc[5] = (r.bottom - bs) / h;
129
-
130
- tc[6] = (r.right - bs) / w;
131
- tc[7] = (r.bottom - bs) / h;
132
-
133
- tc[8] = (r.right - bs) / w;
134
- tc[9] = (r.top + bs) / h;
135
-
136
- tc[10] = (r.left + bs) / w;
137
- tc[11] = (r.top + bs) / h;
138
-
139
- nodes[im.__nodeIndex] = node;
140
- }
141
- }
142
-
143
- /**
144
- * Main atlas making function.
145
- * @private
146
- * @param {boolean} [fastInsert] - If it's true atlas doesnt restore all images again
147
- * and store image in the curent atlas sheme.
148
- */
149
- _makeAtlas(fastInsert) {
150
- if (fastInsert && this._btree) {
151
- let im = this._images[this._images.length - 1];
152
- this._completeNode(this.nodes, this._btree.insert(im));
153
- } else {
154
- let im = this._images.slice(0);
155
-
156
- im.sort(function (b, a) {
157
- return (
158
- (a.atlasWidth || a.width) - (b.atlasWidth || b.width) ||
159
- (a.atlasHeight || a.height) - (b.atlasHeight || b.height)
160
- );
161
- });
162
-
163
- this._btree = new TextureAtlasNode(
164
- new Rectangle(0, 0, this.canvas.getWidth(), this.canvas.getHeight())
165
- );
166
- this._btree.atlas = this;
167
-
168
- this.clearCanvas();
169
-
170
- var newNodes = [];
171
- for (var i = 0; i < im.length; i++) {
172
- this._completeNode(newNodes, this._btree.insert(im[i]));
173
- }
174
- this.nodes = [];
175
- this.nodes = newNodes;
176
- }
177
- }
178
-
179
- /**
180
- * Creates atlas gl texture.
181
- * @public
182
- */
183
- createTexture(img, internalFormat) {
184
- if (this._handler) {
185
- this._handler.gl.deleteTexture(this.texture);
186
- if (img) {
187
- this.canvas.resize(img.width, img.height);
188
- this.canvas.drawImage(img, 0, 0, img.width, img.height);
189
- }
190
- this.texture = this._handler.createTexture_l(this.canvas._canvas, internalFormat);
191
- }
192
- }
193
-
194
- /**
195
- * Image handler callback.
196
- * @callback Object~successCallback
197
- * @param {Image} img - Loaded image.
198
- */
199
-
200
- /**
201
- * Asynchronous function that loads and creates image to the image cache, and call success callback when it's done.
202
- * @public
203
- * @param {string} src - Image object src string.
204
- * @param {Object~successCallback} success - The callback that handles the image loads done.
205
- */
206
- loadImage(src, success) {
207
- this._imagesCacheManager.load(src, success);
208
- }
209
-
210
- getImageTexCoordinates(img) {
211
- if (img.__nodeIndex != null && this.nodes[img.__nodeIndex]) {
212
- return this.nodes[img.__nodeIndex].texCoords;
213
- }
214
- }
215
- }
216
-
217
- /**
218
- * Atlas binary tree node.
219
- * @class
220
- * @param {Rectangle} rect - Node image rectangle.
221
- */
222
- class TextureAtlasNode {
223
- constructor(rect, texCoords = []) {
224
- this.childNodes = null;
225
- this.image = null;
226
- this.rect = rect;
227
- this.texCoords = texCoords;
228
- this.atlas = null;
229
- }
230
-
231
- insert(img) {
232
- if (this.childNodes) {
233
- var newNode = this.childNodes[0].insert(img);
234
-
235
- if (newNode != null) {
236
- return newNode;
237
- }
238
-
239
- return this.childNodes[1].insert(img);
240
- } else {
241
- if (this.image != null) {
242
- return null;
243
- }
244
-
245
- var rc = this.rect;
246
- var w = (img.atlasWidth || img.width) + this.atlas.borderSize;
247
- var h = (img.atlasHeight || img.height) + this.atlas.borderSize;
248
-
249
- if (w > rc.getWidth() || h > rc.getHeight()) {
250
- return null;
251
- }
252
-
253
- if (rc.fit(w, h)) {
254
- this.image = img;
255
- return this;
256
- }
257
-
258
- this.childNodes = new Array(2);
259
- this.childNodes[0] = new TextureAtlasNode();
260
- this.childNodes[0].atlas = this.atlas;
261
- this.childNodes[1] = new TextureAtlasNode();
262
- this.childNodes[1].atlas = this.atlas;
263
-
264
- var dw = rc.getWidth() - w;
265
- var dh = rc.getHeight() - h;
266
-
267
- if (dw > dh) {
268
- this.childNodes[0].rect = new Rectangle(rc.left, rc.top, rc.left + w, rc.bottom);
269
- this.childNodes[1].rect = new Rectangle(rc.left + w, rc.top, rc.right, rc.bottom);
270
- } else {
271
- this.childNodes[0].rect = new Rectangle(rc.left, rc.top, rc.right, rc.top + h);
272
- this.childNodes[1].rect = new Rectangle(rc.left, rc.top + h, rc.right, rc.bottom);
273
- }
274
-
275
- return this.childNodes[0].insert(img);
276
- }
277
- }
278
- }
279
-
280
- export { TextureAtlas, TextureAtlasNode };
1
+ "use strict";
2
+
3
+ import { ImageCanvas } from "../ImageCanvas.js";
4
+ import { Rectangle } from "../Rectangle.js";
5
+ import { ImagesCacheManager } from "./ImagesCacheManager.js";
6
+
7
+ /**
8
+ * Texture atlas stores images in one texture. Each image has its own
9
+ * atlas texture coordinates.
10
+ * @class
11
+ * @param {number} [width] - Texture atlas width, if it hasn't 1024 default.
12
+ * @param {number} [height] - Texture atlas height, if it hasn't 1024 default..
13
+ */
14
+ class TextureAtlas {
15
+ constructor(width = 1024, height = 1024) {
16
+ /**
17
+ * Atlas nodes where input images store. It can be access by image.__nodeIndex.
18
+ * @public
19
+ * @type {Array.<utils.TextureAtlasNode >}
20
+ */
21
+ this.nodes = new Map();
22
+
23
+ /**
24
+ * Created gl texture.
25
+ * @public
26
+ */
27
+ this.texture = null;
28
+
29
+ /**
30
+ * Atlas canvas.
31
+ * @public
32
+ * @type {canvas}
33
+ */
34
+ this.canvas = new ImageCanvas(width, height);
35
+ this.clearCanvas();
36
+
37
+ this._handler = null;
38
+ this._images = [];
39
+ this._btree = null;
40
+ this._imagesCacheManager = new ImagesCacheManager();
41
+ this.borderSize = 4;
42
+ }
43
+
44
+ /**
45
+ * Returns atlas javascript image object.
46
+ * @public
47
+ * @returns {Object} -
48
+ */
49
+ getImage() {
50
+ return this.canvas.getImage();
51
+ }
52
+
53
+ /**
54
+ * Returns canvas object.
55
+ * @public
56
+ * @returns {Object} -
57
+ */
58
+ getCanvas() {
59
+ return this.canvas._canvas;
60
+ }
61
+
62
+ /**
63
+ * Clear atlas with black.
64
+ * @public
65
+ */
66
+ clearCanvas() {
67
+ this.canvas.fillEmpty("black");
68
+ }
69
+
70
+ /**
71
+ * Sets openglobus gl handler that creates gl texture.
72
+ * @public
73
+ * @param {Handler} handler - WebGL handler.
74
+ */
75
+ assignHandler(handler) {
76
+ this._handler = handler;
77
+ this.createTexture();
78
+ }
79
+
80
+ /**
81
+ * Returns image diagonal size.
82
+ * @param {Object} image - JavaSript image object.
83
+ * @returns {number} -
84
+ */
85
+ getDiagonal(image) {
86
+ var w = image.atlasWidth || image.width,
87
+ h = image.atlasHeight || image.height;
88
+ return Math.sqrt(w * w + h * h);
89
+ }
90
+
91
+ /**
92
+ * Adds image to the atlas and returns creted node with texture coordinates of the stored image.
93
+ * @public
94
+ * @param {Object} image - Input javascript image object.
95
+ * @param {boolean} [fastInsert] - If it's true atlas doesnt restore all images again
96
+ * and store image in the curent atlas sheme.
97
+ * @returns {utils.TextureAtlasNode} -
98
+ */
99
+ addImage(image, fastInsert) {
100
+ if (!(image.width && image.height)) {
101
+ return;
102
+ }
103
+
104
+ this._images.push(image);
105
+
106
+ this._makeAtlas(fastInsert);
107
+
108
+ return this.get(image.__nodeIndex);
109
+ }
110
+
111
+ _completeNode(nodes, node) {
112
+ if (node) {
113
+ var w = this.canvas.getWidth(),
114
+ h = this.canvas.getHeight();
115
+ var im = node.image;
116
+ var r = node.rect;
117
+ var bs = Math.round(this.borderSize * 0.5);
118
+ this.canvas.drawImage(im, r.left + bs, r.top + bs, im.atlasWidth, im.atlasHeight);
119
+ var tc = node.texCoords;
120
+
121
+ tc[0] = (r.left + bs) / w;
122
+ tc[1] = (r.top + bs) / h;
123
+
124
+ tc[2] = (r.left + bs) / w;
125
+ tc[3] = (r.bottom - bs) / h;
126
+
127
+ tc[4] = (r.right - bs) / w;
128
+ tc[5] = (r.bottom - bs) / h;
129
+
130
+ tc[6] = (r.right - bs) / w;
131
+ tc[7] = (r.bottom - bs) / h;
132
+
133
+ tc[8] = (r.right - bs) / w;
134
+ tc[9] = (r.top + bs) / h;
135
+
136
+ tc[10] = (r.left + bs) / w;
137
+ tc[11] = (r.top + bs) / h;
138
+
139
+ nodes.set(im.__nodeIndex, node);
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Main atlas making function.
145
+ * @private
146
+ * @param {boolean} [fastInsert] - If it's true atlas doesnt restore all images again
147
+ * and store image in the curent atlas sheme.
148
+ */
149
+ _makeAtlas(fastInsert) {
150
+ if (fastInsert && this._btree) {
151
+ let im = this._images[this._images.length - 1];
152
+ this._completeNode(this.nodes, this._btree.insert(im));
153
+ } else {
154
+ let im = this._images.slice(0);
155
+
156
+ im.sort(function (b, a) {
157
+ return (
158
+ (a.atlasWidth || a.width) - (b.atlasWidth || b.width) ||
159
+ (a.atlasHeight || a.height) - (b.atlasHeight || b.height)
160
+ );
161
+ });
162
+
163
+ this._btree = new TextureAtlasNode(
164
+ new Rectangle(0, 0, this.canvas.getWidth(), this.canvas.getHeight())
165
+ );
166
+ this._btree.atlas = this;
167
+
168
+ this.clearCanvas();
169
+
170
+ var newNodes = new Map();
171
+ for (var i = 0; i < im.length; i++) {
172
+ this._completeNode(newNodes, this._btree.insert(im[i]));
173
+ }
174
+ this.nodes = null;
175
+ this.nodes = newNodes;
176
+ }
177
+ }
178
+
179
+ get(key) {
180
+ return this.nodes.get(key);
181
+ }
182
+
183
+ set(key, value) {
184
+ this.nodes.set(key, value);
185
+ }
186
+
187
+ /**
188
+ * Creates atlas gl texture.
189
+ * @public
190
+ */
191
+ createTexture(img, internalFormat) {
192
+ if (this._handler) {
193
+ this._handler.gl.deleteTexture(this.texture);
194
+ if (img) {
195
+ this.canvas.resize(img.width, img.height);
196
+ this.canvas.drawImage(img, 0, 0, img.width, img.height);
197
+ }
198
+ this.texture = this._handler.createTexture_l(this.canvas._canvas, internalFormat);
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Image handler callback.
204
+ * @callback Object~successCallback
205
+ * @param {Image} img - Loaded image.
206
+ */
207
+
208
+ /**
209
+ * Asynchronous function that loads and creates image to the image cache, and call success callback when it's done.
210
+ * @public
211
+ * @param {string} src - Image object src string.
212
+ * @param {Object~successCallback} success - The callback that handles the image loads done.
213
+ */
214
+ loadImage(src, success) {
215
+ this._imagesCacheManager.load(src, success);
216
+ }
217
+
218
+ getImageTexCoordinates(img) {
219
+ if (img.__nodeIndex != null) {
220
+ let n = this.get(img.__nodeIndex);
221
+ if (n) {
222
+ return n.texCoords;
223
+ }
224
+ }
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Atlas binary tree node.
230
+ * @class
231
+ * @param {Rectangle} rect - Node image rectangle.
232
+ */
233
+ class TextureAtlasNode {
234
+ constructor(rect, texCoords = []) {
235
+ this.childNodes = null;
236
+ this.image = null;
237
+ this.rect = rect;
238
+ this.texCoords = texCoords;
239
+ this.atlas = null;
240
+ }
241
+
242
+ insert(img) {
243
+ if (this.childNodes) {
244
+ var newNode = this.childNodes[0].insert(img);
245
+
246
+ if (newNode != null) {
247
+ return newNode;
248
+ }
249
+
250
+ return this.childNodes[1].insert(img);
251
+ } else {
252
+ if (this.image != null) {
253
+ return null;
254
+ }
255
+
256
+ var rc = this.rect;
257
+ var w = (img.atlasWidth || img.width) + this.atlas.borderSize;
258
+ var h = (img.atlasHeight || img.height) + this.atlas.borderSize;
259
+
260
+ if (w > rc.getWidth() || h > rc.getHeight()) {
261
+ return null;
262
+ }
263
+
264
+ if (rc.fit(w, h)) {
265
+ this.image = img;
266
+ return this;
267
+ }
268
+
269
+ this.childNodes = new Array(2);
270
+ this.childNodes[0] = new TextureAtlasNode();
271
+ this.childNodes[0].atlas = this.atlas;
272
+ this.childNodes[1] = new TextureAtlasNode();
273
+ this.childNodes[1].atlas = this.atlas;
274
+
275
+ var dw = rc.getWidth() - w;
276
+ var dh = rc.getHeight() - h;
277
+
278
+ if (dw > dh) {
279
+ this.childNodes[0].rect = new Rectangle(rc.left, rc.top, rc.left + w, rc.bottom);
280
+ this.childNodes[1].rect = new Rectangle(rc.left + w, rc.top, rc.right, rc.bottom);
281
+ } else {
282
+ this.childNodes[0].rect = new Rectangle(rc.left, rc.top, rc.right, rc.top + h);
283
+ this.childNodes[1].rect = new Rectangle(rc.left, rc.top + h, rc.right, rc.bottom);
284
+ }
285
+
286
+ return this.childNodes[0].insert(img);
287
+ }
288
+ }
289
+ }
290
+
291
+ export { TextureAtlas, TextureAtlasNode };
@@ -0,0 +1,78 @@
1
+ 'use strict';
2
+
3
+ export const ELL = 0;
4
+ export const MSL = 1;
5
+ export const GND = 2;
6
+
7
+ export const heightMode = {
8
+ "ell": ELL,
9
+ "msl": MSL,
10
+ "gnd": GND
11
+ };
12
+
13
+ const KM_to_M = 1000.0;
14
+ const M_to_KM = 1.0 / KM_to_M;
15
+ const FT_to_M = 0.3048;
16
+ const M_to_FT = 1.0 / FT_to_M;
17
+ const MS_to_KMH = 3.6;
18
+ const KMH_to_MS = 1.0 / MS_to_KMH;
19
+ const MS_to_FTS = 3.28084;
20
+ const FT_to_KM = FT_to_M * M_to_KM;
21
+ const KM_to_FT = 1.0 / FT_to_KM;
22
+
23
+ export const m = 0;
24
+ export const km = 1;
25
+ export const ft = 2;
26
+ export const s = 3;
27
+ export const h = 4;
28
+ export const ms = 5;
29
+ export const kmh = 6;
30
+ export const fts = 7;
31
+
32
+ const DEFAULT_NAN = "--";
33
+
34
+ const _abbr = ["m", "km", "ft", "s", "h", "m/s", "km/h", "ft/s"];
35
+
36
+ export const _tenth = [0, 2, 0, 0, 0, 0, 0, 0];
37
+
38
+ let _convFn = [];
39
+
40
+ _convFn[m] = [];
41
+ _convFn[m][m] = (v) => v;
42
+ _convFn[m][km] = (v) => v * M_to_KM;
43
+ _convFn[m][ft] = (v) => v * M_to_FT;
44
+
45
+ _convFn[ft] = [];
46
+ _convFn[ft][m] = (v) => v * FT_to_M;
47
+ _convFn[ft][km] = (v) => v * FT_to_KM;
48
+ _convFn[ft][ft] = (v) => v;
49
+
50
+ _convFn[km] = [];
51
+ _convFn[km][m] = (v) => v * KM_to_M;
52
+ _convFn[km][km] = (v) => v;
53
+ _convFn[km][ft] = (v) => v * KM_to_FT;
54
+
55
+ _convFn[ms] = [];
56
+ _convFn[ms][ms] = (v) => v;
57
+ _convFn[ms][kmh] = (v) => v * MS_to_KMH;
58
+ _convFn[ms][fts] = (v) => v * MS_to_FTS;
59
+
60
+ _convFn[kmh] = [];
61
+ _convFn[kmh][ms] = (v) => v * KMH_to_MS;
62
+ _convFn[kmh][kmh] = (v) => v;
63
+ //_convFn[kmh][fts] = (v) => v * KMH_to_FTS;
64
+
65
+ export function convert(from, to, val) {
66
+ return _convFn[from][to](val);
67
+ }
68
+
69
+ export function convertExt(isNotNaN, unitFrom, unitTo, val, fixed) {
70
+ if (isNotNaN) {
71
+ return convert(unitFrom, unitTo, val).toFixed(fixed || _tenth[unitTo]);
72
+ }
73
+ return DEFAULT_NAN;
74
+ }
75
+
76
+ export function toString(u) {
77
+ return _abbr[u];
78
+ }