@pirireis/webglobeplugins 0.6.49-a → 0.7.1

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 (33) hide show
  1. package/Math/angle-calculation.js +4 -2
  2. package/Math/methods.js +196 -0
  3. package/index.js +2 -1
  4. package/package.json +1 -1
  5. package/point-heat-map/adaptors/timetracksplugin-format-to-this.js +78 -0
  6. package/point-heat-map/index.js +3 -0
  7. package/point-heat-map/plugin-webworker.js +166 -0
  8. package/point-heat-map/plugin.js +134 -0
  9. package/point-heat-map/point-to-heat-map-flow.js +155 -0
  10. package/point-heat-map/readme.md +15 -0
  11. package/programs/data2legend/density-to-legend.js +115 -0
  12. package/programs/data2legend/point-to-density-texture.js +114 -0
  13. package/programs/line-on-globe/degree-padding-around-circle-3d.js +4 -4
  14. package/timetracks/adaptors-line-strip.js +1 -1
  15. package/timetracks/program-line-strip.js +1 -1
  16. package/timetracks/program.js +1 -1
  17. package/timetracks/programpoint-line-strip.js +1 -1
  18. package/timetracks/programpoint.js +1 -1
  19. package/timetracks/readme.md +1 -0
  20. package/util/algorithms/index.js +0 -0
  21. package/util/algorithms/search-binary.js +26 -0
  22. package/util/interpolation/index.js +0 -0
  23. package/util/interpolation/timetrack/index.js +9 -0
  24. package/util/interpolation/timetrack/timetrack-interpolator.js +89 -0
  25. package/util/interpolation/timetrack/web-worker-str.js +176 -0
  26. package/util/interpolation/timetrack/web-worker.js +46 -0
  27. package/util/programs/draw-texture-on-canvas.js +103 -0
  28. package/util/programs/texturetoglobe.js +1 -1
  29. package/util/webglobe/gldefaultstates.js +2 -1
  30. package/waveparticles/plugin.js +0 -2
  31. package/wind/index.js +0 -2
  32. package/wind/plugin.js +1 -1
  33. package/write-text/context-text3.js +1 -1
@@ -1,4 +1,4 @@
1
- export function bearingRealAngle(long, lat, endLong, endLat) {
1
+ function bearingRealAngle(long, lat, endLong, endLat) {
2
2
  const rLong = Radians * long;
3
3
  const rLat = Radians * lat;
4
4
  const rEndLong = Radians * endLong;
@@ -9,4 +9,6 @@ export function bearingRealAngle(long, lat, endLong, endLat) {
9
9
  let initialBearing = Math.atan2(x, y) / Radians;
10
10
  initialBearing = (initialBearing + 360) % 360;
11
11
  return initialBearing;
12
- }
12
+ }
13
+
14
+ export { bearingRealAngle };
@@ -0,0 +1,196 @@
1
+
2
+ const WORLD_RADIUS_3D = 6378.137;
3
+ const WORLD_RADIUS_MERCATOR = 6378136.99911;
4
+
5
+ /**
6
+ * @typedef {Array<number>} vec3 [x, y, z]
7
+ * @typedef {Array<number>} vec2 [x, y]
8
+ * @typedef {Array<number>} vec4 [x, y, z, w]
9
+ * @typedef {number} fraction a number between 0 and 1
10
+ * @typedef {Array<number>} wgs84 [long, lat]
11
+ */
12
+
13
+ // *********************************************************
14
+ // **************** VECTOR OPERATIONS **********************
15
+ // *********************************************************
16
+ const RADIANS = Math.PI / 180;
17
+
18
+
19
+ /**
20
+ * @param {vec3} a
21
+ * @returns {vec3}
22
+ */
23
+ const normalize3 = (a) => {
24
+ const len = length3(a);
25
+ return [a[0] / len, a[1] / len, a[2] / len];
26
+ }
27
+
28
+
29
+ /**
30
+ * @param {vec3} a
31
+ * @param {vec3} b
32
+ * @returns {number}
33
+ */
34
+ const dot3 = (a, b) => {
35
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
36
+ }
37
+
38
+
39
+ /**
40
+ * @param {vec3} a
41
+ * @returns {number}
42
+ */
43
+ const length3 = (a) => {
44
+ return Math.sqrt(dot3(a, a));
45
+ }
46
+
47
+
48
+ // *********************************************************
49
+ // **************** TRANSFORMATIONS ************************
50
+ // *********************************************************
51
+
52
+ /**
53
+ * @param {vec3} cartesian
54
+ * @returns {vec2} long lat in radians
55
+ */
56
+ const cartesian3dToRadian = (cartesian) => {
57
+ const x = cartesian[0];
58
+ const y = cartesian[1];
59
+ const z = cartesian[2];
60
+ // const length = Math.sqrt(x * x + y * y + z * z);
61
+ const long = Math.atan2(y, x);
62
+ const lat = Math.asin(z)// length);
63
+ return [long, lat];
64
+ }
65
+
66
+
67
+ /**
68
+ * @param {vec2} xy long lat in radians
69
+ * @returns {vec2} long lat in mercator meters
70
+ */
71
+ const radianToMercator = (xy) => {
72
+ return [WORLD_RADIUS_MERCATOR * xy[0], WORLD_RADIUS_MERCATOR * Math.log(Math.tan(Math.PI / 4 + xy[1] / 2))];
73
+ }
74
+
75
+ /**
76
+ * @param {vec2} xy long lat radians
77
+ * @returns {vec3} cartesian
78
+ */
79
+
80
+ const radianToCartesian3d = (xy) => {
81
+ const x = Math.cos(xy[1]) * Math.cos(xy[0]);
82
+ const y = Math.cos(xy[1]) * Math.sin(xy[0]);
83
+ const z = -Math.sin(xy[1]);
84
+ return [x, y, z];
85
+ }
86
+
87
+
88
+ // *********************************************************
89
+ // ***************** INTERPOLATIONS ************************
90
+ // *********************************************************
91
+
92
+ /**
93
+ * @param {vec3} normalizedA
94
+ * @param {vec3} normalizedB
95
+ * @param {fraction} ratio
96
+ * @returns {vec3}
97
+ */
98
+ const sphericalLinearInterpolation_UnitVector = (normalizedA, normalizedB, ratio) => {
99
+ const theta = Math.acos(dot3(normalizedA, normalizedB));
100
+ if (theta < 0.000001) return normalizedA; // CALIBRATE?
101
+ const sinTheta = Math.sin(theta);
102
+ const result = [
103
+ (Math.sin((1.0 - ratio) * theta) * normalizedA[0] + Math.sin(ratio * theta) * normalizedB[0]) / sinTheta,
104
+ (Math.sin((1.0 - ratio) * theta) * normalizedA[1] + Math.sin(ratio * theta) * normalizedB[1]) / sinTheta,
105
+ (Math.sin((1.0 - ratio) * theta) * normalizedA[2] + Math.sin(ratio * theta) * normalizedB[2]) / sinTheta
106
+ ];
107
+ return result;
108
+ }
109
+
110
+
111
+ /**
112
+ * @param {vec3} normalizedA
113
+ * @param {vec3} normalizedB
114
+ * @param {fraction} ratio
115
+ * @returns
116
+ */
117
+ const sphericalLinearInterpolation_Mercator = (normalizedA, normalizedB, ratio) => {
118
+ const unitVector = sphericalLinearInterpolation_UnitVector(normalizedA, normalizedB, ratio);
119
+ const angles = cartesian3dToRadian(unitVector);
120
+ return radianToMercator(angles);
121
+ }
122
+
123
+ /**
124
+ * @param {vec4} a vec3 unit vector and length
125
+ * @param {vec4} b vec3 unit vector and length
126
+ * @param {fraction} ratio
127
+ */
128
+ const sphericalLinearInterpolation_Cartesian3d = (a, b, ratio) => {
129
+ const unitVector = sphericalLinearInterpolation_UnitVector(a, b, ratio);
130
+ const height = a[3] + (b[3] - a[3]) * ratio;
131
+ return [unitVector[0] * height, unitVector[1] * height, unitVector[2] * height];
132
+ }
133
+
134
+
135
+ /**
136
+ *
137
+ * @param {wgs84} coordinates
138
+ * @returns {vec3}
139
+ */
140
+ const wgs84ToUnitVector = (coordinates) => {
141
+ const long = coordinates[0] * RADIANS;
142
+ const lat = coordinates[1] * RADIANS;
143
+
144
+ const x = Math.cos(lat) * Math.cos(long);
145
+ const y = Math.cos(lat) * Math.sin(long);
146
+ const z = Math.sin(lat);
147
+ return [x, y, z];
148
+ }
149
+
150
+
151
+ /**
152
+ * @param {vec3} cartesian
153
+ * @returns {vec4} unit vector and length
154
+ */
155
+ const cartesian3dToUnitVectorWithHeight = (cartesian) => {
156
+ const x = cartesian[0];
157
+ const y = cartesian[1];
158
+ const z = cartesian[2];
159
+ const height = Math.sqrt(x * x + y * y + z * z);
160
+ return [x / height, y / height, z / height, height];
161
+ }
162
+
163
+ /**
164
+ * @param {vec2} pixelXY
165
+ * @returns {vec2} long lat in radians
166
+ */
167
+
168
+ const pixelXYToRadians = (pixelXY) => {
169
+ const long = (2.0 * pixelXY[0] - 1.0) * Math.PI;
170
+ const lat = (2.0 * pixelXY[1] - 1.0) * Math.PI / 2.0;
171
+ return [long, lat]
172
+ }
173
+
174
+ const pixelXYLenghtToUnitVectorWithHeight = (pixelXYHeight) => {
175
+ const [long, lat] = pixelXYToRadians(pixelXYHeight);
176
+ const radius = WORLD_RADIUS_3D + pixelXYHeight[2];
177
+ return radianToCartesian3d([long, lat]).concat(radius);
178
+ }
179
+
180
+ export {
181
+ RADIANS,
182
+ WORLD_RADIUS_3D,
183
+ normalize3,
184
+ dot3,
185
+ length3,
186
+ cartesian3dToRadian,
187
+ radianToMercator,
188
+ radianToCartesian3d,
189
+ sphericalLinearInterpolation_UnitVector,
190
+ sphericalLinearInterpolation_Mercator,
191
+ sphericalLinearInterpolation_Cartesian3d,
192
+ wgs84ToUnitVector,
193
+ cartesian3dToUnitVectorWithHeight,
194
+ pixelXYLenghtToUnitVectorWithHeight
195
+ }
196
+
package/index.js CHANGED
@@ -8,4 +8,5 @@ import * as compassrose from "./compassrose";
8
8
  import * as heatwave from "./heatwave";
9
9
  import * as util from "./util";
10
10
  import * as programs from "./programs";
11
- export { wind, waveparticles, timetracks, rangerings, compassrose, heatwave, util, programs, arrowfield, partialring };
11
+ import * as pointheatmap from "./point-heat-map";
12
+ export { wind, waveparticles, timetracks, rangerings, compassrose, heatwave, util, programs, arrowfield, partialring, pointheatmap };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pirireis/webglobeplugins",
3
- "version": "0.6.49-a",
3
+ "version": "0.7.1",
4
4
  "main": "index.js",
5
5
  "author": "Toprak Nihat Deniz Ozturk",
6
6
  "license": "MIT"
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @typedef {Float32Array} TimeTrackMultiColorData | A linestring is representation, let A{a1, a2, a3}, B{b1, b2} be the points of the line.
3
+ * TimeTrackMultiColorData is [
4
+ * a1x, a1y, a1z, a1time, a1r, a1g, a1b, a1time, a3time,
5
+ * a2x, a2y, a2z, a2time, a2r, a2g, a2b, a1time, a3time,
6
+ * a3x, a3y, a3z, a3time, a3r, a3g, a3b, a1time, a3time,
7
+ * 0, 0, 0, 0, -1, -1, -1, 0, 0,
8
+ * b1x, b1y, b1z, b1time, b1r, b1g, b1b, b1time, b2time,
9
+ * b2x, b2y, b2z, b2time, b2r, b2g, b2b, BstartTime, BendTime
10
+ * ]
11
+ * there is a cutting point between A and B
12
+ *
13
+ */
14
+
15
+ /**
16
+ * ABOVE
17
+ * TO
18
+ * BELOW
19
+
20
+ /**
21
+ * @typedef {Array<number>} vec3 [x, y, z]
22
+ * @typedef {Array<number>} vec2 [x, y]
23
+ * @typedef {Array<number>} vec4 [x, y, z, w]
24
+ * @typedef {number} fraction a number between 0 and 1
25
+ * @typedef {Array<number>} wgs84 [long, lat]
26
+ */
27
+
28
+
29
+ /**
30
+ * @typedef Timetrack
31
+ * @property {Array<vec4>}} coordinates [x,y,z, length]
32
+ * @property {Array<Number>} times
33
+ * @param {Array<Timetrack>} timeTracks
34
+ */
35
+
36
+
37
+
38
+ import { pixelXYLenghtToUnitVectorWithHeight } from "../../Math/methods";
39
+
40
+
41
+
42
+ const processACut = (array, offset) => {
43
+ // first 3 values of array
44
+ const v3 = array.slice(offset, offset + 3);
45
+ const v4 = pixelXYLenghtToUnitVectorWithHeight(v3);
46
+ const time = array[offset + 3];
47
+ return [v4, time];
48
+ }
49
+
50
+
51
+ const timeTrackPluginDataToPointHeatInterpolatorAdapter = (timeTrackPluginData) => {
52
+ const timeTracks = []
53
+
54
+ let offset = 0;
55
+
56
+ let timeTrack = {
57
+ coordinates: [],
58
+ times: []
59
+ }
60
+ while (offset < timeTrackPluginData.length) {
61
+ if (!timeTrackPluginData[offset]) {
62
+ timeTracks.push(timeTrack);
63
+ timeTrack = {
64
+ coordinates: [],
65
+ times: []
66
+ }
67
+ offset += 9;
68
+ }
69
+ const point = processACut(timeTrackPluginData, offset);
70
+ offset += 9;
71
+ timeTrack.coordinates.push(point[0]);
72
+ timeTrack.times.push(point[1]);
73
+ }
74
+ return timeTracks;
75
+ }
76
+
77
+
78
+ export { timeTrackPluginDataToPointHeatInterpolatorAdapter };
@@ -0,0 +1,3 @@
1
+ import { PointHeatmapPlugin } from "./plugin-webworker";
2
+ import { timeTrackPluginDataToPointHeatInterpolatorAdapter } from "./adaptors/timetracksplugin-format-to-this";
3
+ // export { PointHeatmapPlugin, timeTrackPluginDataToPointHeatInterpolatorAdapter };
@@ -0,0 +1,166 @@
1
+ import { PointHeatmapFlow } from "./point-to-heat-map-flow";
2
+ import { webworkerStr } from "../util/interpolation/timetrack/web-worker-str";
3
+ import { createTexture, getColorRampModed } from "../util";
4
+
5
+ class PointHeatmapPlugin {
6
+
7
+ constructor(id, { opacity = 1.0, pointSize = 5.0, onInterpolationComplete = () => { } } = {}) {
8
+ this.id = id;
9
+ this.globe = null;
10
+ this.gl = null;
11
+ this.densityToLegendProgram = null;
12
+ this._time = null;
13
+
14
+ this._opacity = opacity;
15
+ this._pointSize = pointSize;
16
+ this._legendTexture = null;
17
+
18
+ this._throttleListener = null;
19
+
20
+ try {
21
+
22
+ this.timeTrackInterpolationWorker = new Worker(
23
+ new URL(
24
+ '../util/interpolation/timetrack/web-worker.js',
25
+ import.meta.url
26
+ ), { type: 'module' }
27
+ );
28
+ } catch (e) {
29
+ console.log(e);
30
+ const blob = new Blob([webworkerStr], { type: 'application/javascript' });
31
+ this.timeTrackInterpolationWorker = new Worker(URL.createObjectURL(blob), { type: 'module' });
32
+ }
33
+ this.timeTrackInterpolationWorker.onmessage = (e) => {
34
+ if (e.data.error) {
35
+ throw new Error(e.data.error);
36
+ }
37
+ if (e.data === true) {
38
+ onInterpolationComplete()
39
+ }
40
+ if (e.data instanceof Float32Array) {
41
+ this.flow.setData(e.data);
42
+ this._throttleListener = null;
43
+ onInterpolationComplete();
44
+ }
45
+ }
46
+ }
47
+
48
+ // globe interaction
49
+
50
+ init(globe, gl) {
51
+ this.globe = globe;
52
+ this.gl = gl;
53
+ this.flow = new PointHeatmapFlow(globe);
54
+
55
+ }
56
+
57
+
58
+ setPointSize(pointSize) {
59
+ if (typeof pointSize !== 'number' || pointSize <= 0) {
60
+ throw new Error('Invalid pointSize');
61
+ }
62
+ this._pointSize = pointSize;
63
+ this.globe.DrawRender();
64
+ }
65
+
66
+
67
+ /**
68
+ * @param {Array<string>}
69
+ * @param {string} mode "interpolated" | "discrete"
70
+ */
71
+
72
+ setColorRamp(values, thresholds, mode = "interpolated") {
73
+ const gl = this.gl
74
+ if (this.gl === null) {
75
+ throw new Error('Plugin not initialized');
76
+ };
77
+ console.log(values, thresholds, mode);
78
+ const rampData = getColorRampModed(values, thresholds, mode);
79
+ console.log(rampData);
80
+ const texture = createTexture(gl, gl.LINEAR, rampData, 256, 1);
81
+ console.log(texture);
82
+ if (this._legendTexture) {
83
+ this.gl.deleteTexture(this._legendTexture);
84
+ }
85
+ this._legendTexture = texture;
86
+ this.globe.DrawRender();
87
+ }
88
+
89
+
90
+ setTime(time) {
91
+ // TODO: WORK ON THIS
92
+ this._time = time;
93
+ if (this._throttleListener === null) {
94
+ this._throttleListener = setTimeout(() => {
95
+ this.timeTrackInterpolationWorker.postMessage({ time: this._time });
96
+ }, 0);
97
+ }
98
+ }
99
+
100
+
101
+ setTimetracks(timeTracks) {
102
+ this.timeTrackInterpolationWorker.postMessage({ timeTracks });
103
+ if (this._time !== null) {
104
+ this.setTime(this._time);
105
+ }
106
+ this.globe.DrawRender();
107
+ }
108
+
109
+
110
+ setOpacity(opacity) {
111
+ if (typeof opacity !== 'number' || opacity < 0 || opacity > 1) {
112
+ throw new Error('Invalid opacity');
113
+ }
114
+ this._opacity = opacity;
115
+ this.globe.DrawRender();
116
+ }
117
+
118
+
119
+
120
+ setGeometry() {
121
+ const geometry = this.globe.api_GetCurrentGeometry();
122
+ this.timeTrackInterpolationWorker.postMessage({ geometry });
123
+ if (this._time !== null) {
124
+ this.setTime(this._time);
125
+ }
126
+ }
127
+
128
+
129
+ draw3D() {
130
+ if (this.isReady()) {
131
+ this.flow.draw(this._legendTexture, this._pointSize, this._opacity);
132
+ }
133
+ }
134
+
135
+
136
+ resize() {
137
+ this.flow.resize();
138
+ if (this._time !== null) {
139
+ this.setTime(this._time);
140
+ }
141
+ }
142
+
143
+
144
+ isReady() {
145
+ return (this.gl !== null && this._legendTexture !== null);
146
+ }
147
+
148
+ free() {
149
+ if (this._isFreed) return;
150
+ this.gl.deleteTexture(this._legendTexture);
151
+ this.flow.free();
152
+ this.flow = null;
153
+ this.gl = null;
154
+ this._isFreed = true;
155
+ this.timeTrackInterpolator = null;
156
+ this._legendTexture = null;
157
+ this.timeTrackInterpolationWorker.terminate();
158
+ this.timeTrackInterpolationWorker = null;
159
+ }
160
+ }
161
+
162
+
163
+
164
+
165
+
166
+ export { PointHeatmapPlugin };
@@ -0,0 +1,134 @@
1
+ import { PointHeatmapFlow } from "./point-to-heat-map-flow";
2
+ import { TimeTrackInterpolator } from "../util/interpolation/timetrack/timetrack-interpolator";
3
+ import { createTexture, getColorRampModed } from "../util";
4
+
5
+ class PointHeatmapPlugin {
6
+
7
+ constructor(id, { opacity = 1.0, pointSize = 5.0 } = {}) {
8
+ this.id = id;
9
+ this.globe = null;
10
+ this.gl = null;
11
+ this.densityToLegendProgram = null;
12
+ this._time = null;
13
+
14
+
15
+ this._opacity = opacity;
16
+ this._pointSize = pointSize;
17
+ this._legendTexture = null;
18
+ this.timeTrackInterpolator = new TimeTrackInterpolator();
19
+ }
20
+
21
+ // globe interaction
22
+
23
+ init(globe, gl) {
24
+ this.globe = globe;
25
+ this.gl = gl;
26
+ this.flow = new PointHeatmapFlow(globe);
27
+
28
+ }
29
+
30
+
31
+ setPointSize(pointSize) {
32
+ if (typeof pointSize !== 'number' || pointSize <= 0) {
33
+ throw new Error('Invalid pointSize');
34
+ }
35
+ this._pointSize = pointSize;
36
+ this.globe.DrawRender();
37
+ }
38
+
39
+
40
+ /**
41
+ * @param {Array<string>}
42
+ * @param {string} mode "interpolated" | "discrete"
43
+ */
44
+
45
+ setColorRamp(values, thresholds, mode = "interpolated") {
46
+ const gl = this.gl
47
+ if (this.gl === null) {
48
+ throw new Error('Plugin not initialized');
49
+ };
50
+ console.log(values, thresholds, mode);
51
+ const rampData = getColorRampModed(values, thresholds, mode);
52
+ console.log(rampData);
53
+ const texture = createTexture(gl, gl.LINEAR, rampData, 256, 1);
54
+ console.log(texture);
55
+ if (this._legendTexture) {
56
+ this.gl.deleteTexture(this._legendTexture);
57
+ }
58
+ this._legendTexture = texture;
59
+ this.globe.DrawRender();
60
+ }
61
+
62
+
63
+ setTime(time) {
64
+ this._time = time;
65
+ const data = this.timeTrackInterpolator.interpolate(time);
66
+ if (data === null) {
67
+ return;
68
+ }
69
+ this.flow.setData(data);
70
+ }
71
+
72
+
73
+ setTimetracks(timeTracks) {
74
+ this.timeTrackInterpolator.setTimetracks(timeTracks);
75
+ if (this._time !== null) {
76
+ this.setTime(this._time);
77
+ }
78
+ this.globe.DrawRender();
79
+ }
80
+
81
+
82
+ setOpacity(opacity) {
83
+ if (typeof opacity !== 'number' || opacity < 0 || opacity > 1) {
84
+ throw new Error('Invalid opacity');
85
+ }
86
+ this._opacity = opacity;
87
+ this.globe.DrawRender();
88
+ }
89
+
90
+
91
+
92
+ setGeometry() {
93
+ const geometry = this.globe.api_GetCurrentGeometry();
94
+ this.timeTrackInterpolator.setGeometry(geometry);
95
+ if (this._time !== null) {
96
+ this.setTime(this._time);
97
+ }
98
+ }
99
+
100
+
101
+ draw3D() {
102
+ if (this.isReady()) {
103
+ this.flow.draw(this._legendTexture, this._pointSize, this._opacity);
104
+ }
105
+ }
106
+
107
+
108
+ resize() {
109
+ this.timeTrackInterpolator.setGeometry(this.globe.api_GetCurrentGeometry());
110
+ this.flow.resize();
111
+ if (this._time !== null) {
112
+ this.setTime(this._time);
113
+ }
114
+ }
115
+
116
+
117
+ isReady() {
118
+ return (this.gl !== null && this._legendTexture !== null);
119
+ }
120
+
121
+ free() {
122
+ if (this._isFreed) return;
123
+ this.gl.deleteTexture(this._legendTexture);
124
+ this.flow.free();
125
+ this.flow = null;
126
+ this.gl = null;
127
+ this._isFreed = true;
128
+ this.timeTrackInterpolator = null;
129
+ this._legendTexture = null;
130
+ }
131
+ }
132
+
133
+
134
+ export { PointHeatmapPlugin };