@pirireis/webglobeplugins 0.8.26 → 0.9.2

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 (66) hide show
  1. package/Math/arc.ts +74 -245
  2. package/Math/constants.ts +4 -1
  3. package/Math/frustum/camera.ts +32 -0
  4. package/Math/frustum/from-globeinfo.ts +63 -0
  5. package/Math/frustum/types.ts +11 -0
  6. package/Math/globe-util/horizon-plane.ts +137 -0
  7. package/Math/juction/arc-plane.ts +90 -0
  8. package/Math/juction/line-sphere.ts +30 -0
  9. package/Math/juction/plane-plane.ts +66 -0
  10. package/Math/line.ts +70 -0
  11. package/Math/methods.js +29 -1
  12. package/Math/plane.ts +57 -138
  13. package/Math/quaternion.ts +108 -144
  14. package/Math/types.ts +39 -30
  15. package/Math/vec3.ts +155 -0
  16. package/altitude-locator/plugin.js +1 -1
  17. package/bearing-line/plugin.js +1 -1
  18. package/circle-line-chain/plugin.js +1 -1
  19. package/globe-types.ts +13 -0
  20. package/heatwave/plugins/heatwaveglobeshell.js +5 -9
  21. package/index.js +3 -0
  22. package/package.json +1 -1
  23. package/programs/interface.ts +7 -0
  24. package/programs/line-on-globe/circle-accurate-3d.js +1 -1
  25. package/programs/line-on-globe/degree-padding-around-circle-3d.js +1 -1
  26. package/programs/line-on-globe/lines-color-instanced-flat.js +1 -1
  27. package/programs/line-on-globe/linestrip.ts +228 -0
  28. package/programs/line-on-globe/naive-accurate-flexible.js +1 -1
  29. package/programs/line-on-globe/to-the-surface.js +1 -1
  30. package/programs/picking/pickable-renderer.js +1 -1
  31. package/programs/point-on-globe/element-globe-surface-glow.js +1 -1
  32. package/programs/point-on-globe/element-point-glow.js +1 -1
  33. package/programs/totems/camerauniformblock.js +24 -1
  34. package/shape-on-terrain/arc/naive/plugin.ts +304 -0
  35. package/tests/Math/junction/arc-plane.test.ts +129 -0
  36. package/tests/Math/junction/plane-plane.test.ts +82 -0
  37. package/tests/Math/plane.test.ts +30 -32
  38. package/tests/Math/vec3.test.ts +14 -0
  39. package/timetracks/plugin-line-strip.js +3 -1
  40. package/{types.js → types.ts} +2 -1
  41. package/util/account/{index.js → index.ts} +1 -2
  42. package/util/account/single-attribute-buffer-management/buffer-orchestrator.js +0 -31
  43. package/util/account/single-attribute-buffer-management/index.ts +13 -0
  44. package/util/gl-util/buffer/{integrate-buffer.js → attribute-loader.ts} +17 -6
  45. package/util/gl-util/buffer/index.ts +6 -0
  46. package/util/gl-util/buffer/types.ts +13 -0
  47. package/util/gl-util/draw-options/methods.js +4 -4
  48. package/util/gl-util/draw-options/{types.js → types.ts} +10 -0
  49. package/util/gl-util/uniform-block/{manager.js → manager.ts} +24 -13
  50. package/util/gl-util/uniform-block/types.ts +27 -0
  51. package/util/heatwavedatamanager/pointcoordinatesdatacalculator.js +17 -17
  52. package/waveparticles/plugin.js +3 -0
  53. package/wind/plugin.js +39 -52
  54. package/Math/methodology/arc-part-on-screen.ts +0 -47
  55. package/Math/ray.ts +0 -101
  56. package/Math/vector3d.ts +0 -241
  57. package/shape-on-terrain/tree-search.js +0 -0
  58. package/surface-cover-shapes/arc/naive/data-manager.ts +0 -0
  59. package/surface-cover-shapes/arc/naive/plugin.ts +0 -0
  60. package/tests/Math/arc.test.ts +0 -112
  61. package/tests/Math/quaternion.test.ts +0 -98
  62. package/tests/Math/ray-plane.test.ts +0 -176
  63. package/tests/Math/vector3d.test.ts +0 -104
  64. package/util/account/single-attribute-buffer-management/index.js +0 -4
  65. package/util/gl-util/uniform-block/types.js +0 -7
  66. /package/{shape-on-terrain/intersection.js → Math/matrix4.ts} +0 -0
package/Math/arc.ts CHANGED
@@ -1,247 +1,76 @@
1
-
2
- import { Vector3D } from "./vector3d";
3
- import { Plane } from "./plane";
4
- import { Quaternion } from "./quaternion";
5
- import { Radians } from "./types";
6
- import { Ray } from "./ray";
7
-
8
- const _quaternion = /*@__PURE__*/ new Quaternion(0, 0, 0, 0);
9
- const _ray = /*@__PURE__*/ new Ray(new Vector3D(0, 0, 0), new Vector3D(0, 0, 0));
10
- const _0vector = /*@__PURE__*/ new Vector3D(0, 0, 0);
11
- const _0plane = /*@__PURE__*/ new Plane(_0vector, 0);
12
-
13
- const _A_x_otherA = /*@__PURE__*/ new Vector3D(0, 0, 0);
14
- const _A_x_otherB = /*@__PURE__*/ new Vector3D(0, 0, 0);
15
- const _AxB = /*@__PURE__*/ new Vector3D(0, 0, 0);
16
-
17
-
18
-
19
-
20
-
21
- export class Arc {
22
- pointA: Vector3D;
23
- pointB: Vector3D;
24
- _dot: number;
25
- _AxB: Vector3D;
26
- _theta: Radians;
27
- _imageinaryPlane: Plane;
28
- constructor(
29
- pointA: Vector3D,
30
- pointB: Vector3D,
31
- ) {
32
- this.pointA = pointA.normalize();
33
- this.pointB = pointB.normalize();
34
- this._AxB = pointA.clone().cross(pointB);
35
- this._dot = this.pointA.dot(this.pointB);
36
- this._theta = Math.acos(this._dot);
37
- this._imageinaryPlane = new Plane(this._AxB.clone().normalize(), 0);
38
- }
39
-
40
-
41
- copy(arc: Arc): Arc {
42
- this.pointA.copy(arc.pointA);
43
- this.pointB.copy(arc.pointB);
44
- this._AxB.copy(arc._AxB);
45
- this._dot = arc._dot;
46
- this._theta = arc._theta;
47
- this._imageinaryPlane.copy(arc._imageinaryPlane);
48
- return this;
49
- }
50
-
51
-
52
- clone(): Arc {
53
- return new Arc(this.pointA.clone(), this.pointB.clone());
54
- }
55
-
56
-
57
- equals(arc: Arc): boolean {
58
- return (this.pointA.equals(arc.pointA) && this.pointB.equals(arc.pointB)) || (this.pointA.equals(arc.pointB) && this.pointB.equals(arc.pointA));
59
- }
60
-
61
-
62
- slerp(t: number): Vector3D {
63
-
64
- const pointA = this.pointA;
65
- const pointB = this.pointB;
66
-
67
- const step = t / this._theta;
68
- const sinTheta = Math.sin(this._theta);
69
- const sinStep = Math.sin(step * this._theta);
70
- const sinOneMinusStep = Math.sin((1 - step) * this._theta);
71
-
72
- const x = (sinOneMinusStep * pointA[0] + sinStep * pointB[0]) / sinTheta;
73
- const y = (sinOneMinusStep * pointA[1] + sinStep * pointB[1]) / sinTheta;
74
- const z = (sinOneMinusStep * pointA[2] + sinStep * pointB[2]) / sinTheta;
75
-
76
- return new Vector3D(x, y, z);
77
-
78
- }
79
-
80
-
81
-
82
- intersectionMedium(medium: Plane, target: Arc | null = null): Arc | null {
83
- // Orianted in right hand rule
84
- if (this.pointA.equals(this.pointB)) return null; // arc is too short
85
-
86
- const result = this._imageinaryPlane.intersectionPlane(medium);
87
- if (result instanceof Plane) {
88
- return this.clone();
89
- }
90
-
91
- if (result === null) { console.log("null intersection"); return null; } // planes are parallel
92
-
93
- const intersectionPoints = _ray.set(result.origin, result.direction).intersectionSphere(_0vector.set(0, 0, 0), 1);
94
- if (intersectionPoints === null) {
95
- return null; // no intersection
96
- }
97
-
98
- // think as this.pointA is on y=1 on a x-y space. this.pointB is on the x>0 part of the space.
99
- // any point on x<0 is outside. Any point y<this._dot is outside.
100
-
101
- // A is before B with right hand rule
102
- const [A, B] = (() => {
103
- Vector3D.crossVectors(...intersectionPoints, _AxB);
104
- if (_AxB.dot(this._AxB) >= 0) {
105
- return [intersectionPoints[0], intersectionPoints[1]];
106
- } else {
107
- return [intersectionPoints[1], intersectionPoints[0]];
108
- }
109
- })();
110
-
111
-
112
- Vector3D.crossVectors(this.pointA, A, _A_x_otherA);
113
- Vector3D.crossVectors(this.pointA, B, _A_x_otherB);
114
-
115
- const _yA = this.pointA.dot(A);
116
- const _yB = this.pointA.dot(B);
117
-
118
- const _xA = _A_x_otherA.dot(this._imageinaryPlane.normal); // this._AxB.normalize() == this._imageinaryPlane.normal
119
- const _xB = _A_x_otherB.dot(this._imageinaryPlane.normal);
120
-
121
-
122
- if (_xA < 0 && _xB < 0) {
123
- if (_yA > _yB) {
124
- throw new Error("A is before B with right hand rule but A is on the left side of the arc. This should not happen.");
125
- }
126
- return null; // no intersection
127
- } else if (_xA > 0 && _xB > 0 && _yA < this._dot && _yB < this._dot) {
128
- return null; // no intersection
129
- }
130
-
131
-
132
- const resultPoints: [Vector3D, Vector3D] = [
133
- _xA < 0 ? this.pointA.clone() : A,
134
- _yB <= this._dot ? this.pointB.clone() : B
135
- ];
136
- if (target === null) {
137
- target = new Arc(...resultPoints);
138
- } else if (target instanceof Arc) {
139
- target.setFromUnitVectors(...resultPoints);
140
- } else {
141
- throw new Error("target is not null or an Arc instance");
142
- }
143
-
144
- return target;
145
- }
146
-
147
-
148
-
149
-
150
- setFromUnitVectors(
151
- pointA: Vector3D,
152
- pointB: Vector3D,
153
- ) {
154
-
155
- // following values might be calculated lazily
156
- this.pointA.copy(pointA).normalize();
157
- this.pointB.copy(pointB).normalize();
158
- this._AxB = pointA.clone().cross(pointB);
159
- this._dot = this.pointA.dot(this.pointB);
160
- this._theta = Math.acos(this._dot);
161
- this._imageinaryPlane = new Plane(this._AxB.clone().normalize(), 0);
162
- }
163
-
164
-
165
-
166
- populatePoints3D(pointCount: number, startProportion: number = 0, endProportion: number = 1): Float32Array {
167
-
168
- const points3D = new Float32Array(pointCount * 3);
169
- const step = (endProportion - startProportion) / (pointCount - 1);
170
- const _AxBnormalized = this._AxB.clone().normalize();
171
-
172
- _0vector.copy(this.pointA);
173
-
174
- if (startProportion > 0) {
175
- _quaternion.setFromAxisAngle(_AxBnormalized, this._theta * startProportion);
176
- _0vector.applyQuaternion(_quaternion);
1
+ import { Vec3, Plane, Arc } from "./types";
2
+
3
+ import { vec3 } from "./vec3";
4
+ import { EPSILON } from "./constants";
5
+
6
+ const _0vector = /*@__PURE__*/ vec3.create(0, 0, 0);
7
+ const _1vector = /*@__PURE__*/ vec3.create(1, 1, 1);
8
+
9
+ export const arc = Object.freeze({
10
+ create(p0: Vec3, p1: Vec3): Arc {
11
+ const normal = vec3.create(0, 0, 0);
12
+ vec3.cross(normal, p0, p1);
13
+ const coverPlaneNormal = [p0[0] + p1[0], p0[1] + p1[1], p0[2] + p1[2]] as Vec3;
14
+ vec3.normalize(coverPlaneNormal, coverPlaneNormal);
15
+ const dot = vec3.dot(coverPlaneNormal, p0);
16
+ return {
17
+ p0: vec3.clone(p0),
18
+ p1: vec3.clone(p1),
19
+ normal: vec3.clone(normal),
20
+ coverPlane: {
21
+ normal: coverPlaneNormal,
22
+ distance: dot
23
+ } as Plane
177
24
  }
178
- _quaternion.setFromAxisAngle(_AxBnormalized, this._theta * step);
179
- let index = 0;
180
- for (let i = 0; i < pointCount; i++) {
181
- points3D[index++] = _0vector.x;
182
- points3D[index++] = _0vector.y;
183
- points3D[index++] = _0vector.z;
184
- _0vector.applyQuaternion(_quaternion);
185
- }
186
-
187
- return points3D;
25
+ },
26
+
27
+ set(out: Arc, p0: Vec3, p1: Vec3) {
28
+ vec3.copy(out.p0, p0);
29
+ vec3.copy(out.p1, p1);
30
+ vec3.cross(out.normal, p0, p1);
31
+ const coverPlaneNormal = [p0[0] + p1[0], p0[1] + p1[1], p0[2] + p1[2]] as Vec3;
32
+ vec3.normalize(coverPlaneNormal, coverPlaneNormal);
33
+ out.coverPlane.normal = coverPlaneNormal;
34
+ out.coverPlane.distance = vec3.dot(coverPlaneNormal, p0);
35
+ },
36
+
37
+
38
+ copy(out: Arc, a: Arc) {
39
+ vec3.copy(out.p0, a.p0);
40
+ vec3.copy(out.p1, a.p1);
41
+ vec3.copy(out.normal, a.normal);
42
+ out.coverPlane.normal = vec3.clone(a.coverPlane.normal);
43
+ out.coverPlane.distance = a.coverPlane.distance;
44
+ },
45
+
46
+ clone(a: Arc): Arc {
47
+ return {
48
+ p0: vec3.clone(a.p0),
49
+ p1: vec3.clone(a.p1),
50
+ normal: vec3.clone(a.normal),
51
+ coverPlane: {
52
+ normal: vec3.clone(a.coverPlane.normal),
53
+ distance: a.coverPlane.distance
54
+ } as Plane
55
+ };
56
+ },
57
+
58
+
59
+
60
+ isPointOn(arc: Arc, point: Vec3): boolean {
61
+ const alignment = Math.abs(vec3.dot(point, arc.normal)) < EPSILON;
62
+ const distance = Math.abs(vec3.lengthSquared(point) - 1) < EPSILON;
63
+ const cover = vec3.dot(arc.coverPlane.normal, point) >= arc.coverPlane.distance;
64
+ return alignment || distance || cover;
65
+ },
66
+
67
+
68
+ equals(a: Arc, b: Arc): boolean {
69
+ return vec3.equals(a.p0, b.p0) && vec3.equals(a.p1, b.p1)
70
+ },
71
+
72
+ populatePoints(out: Float32Array, arc: Arc, count: number) {
73
+ // rotate p0 around normal vector with a quaternion
74
+ // calculate angle
188
75
  }
189
-
190
-
191
- // cutBoundingBoxes(dotStep: number = 0.025): { minX: number, minY: number, maxX: number, maxY: number }[] {
192
- // const pointA = this.pointA;
193
- // const to = this.pointB;
194
- // const a = [pointA.x, pointA.y, pointA.z];
195
- // const b = [to.x, to.y, to.z];
196
-
197
- // const theta = Math.acos(a[0] * b[0] + a[1] * b[1] + a[2] * b[2]);
198
- // const step = dotStep / theta;
199
-
200
- // if (step >= 1) {
201
- // return [{ minX: Math.min(pointA.x, to.x), minY: Math.min(pointA.y, to.y), maxX: Math.max(pointA.x, to.x), maxY: Math.max(pointA.y, to.y) }];
202
- // }
203
-
204
- // let points = [pointA] as Vector3D[];
205
- // let currentStep = 0;
206
- // while (currentStep < 1) {
207
- // currentStep += step;
208
- // points.push(this.slerp(currentStep, currentStep + step, 1)[0]);
209
- // }
210
-
211
- // return points.map(point => ({ minX: point.x, minY: point.y, maxX: point.x, maxY: point.y }));
212
- // }
213
-
214
- // boundingBox(): { minLon: Radians, minLat: Radians, maxLon: Radians, maxLat: Radians } {
215
-
216
- // // Do two poınts remaın on the same half when the circle is cut by Z axis?
217
- // const Z = Math.sign(this.pointA.z + this.pointB.z);
218
- // _0vector.set(0, 0, Z);
219
- // const zDot = this.greatCirclePlaneNormalVector.dot(_0vector);
220
- // const zDif = Math.abs(this.pointA.z - this.pointB.z);
221
- // const minPossibleZDistanceIfOnTheSameHalf = (1 - this.dot) * zDot;
222
-
223
- // const aLonLat = this.pointA.toLonLat();
224
- // const bLonLat = this.pointB.toLonLat();
225
-
226
- // if (zDif >= minPossibleZDistanceIfOnTheSameHalf) {
227
- // return {
228
- // minLon: Math.min(aLonLat.lon, bLonLat.lon),
229
- // minLat: Math.min(aLonLat.lat, bLonLat.lat),
230
- // maxLon: Math.max(aLonLat.lon, bLonLat.lon),
231
- // maxLat: Math.max(aLonLat.lat, bLonLat.lat)
232
- // }
233
- // }
234
-
235
- // // if not, we need to calculate Z peek of the arc
236
- // const z = Math.asin(zDot * Z);
237
- // return {
238
- // minLon: Math.min(aLonLat.lon, bLonLat.lon),
239
- // minLat: Math.min(aLonLat.lat, bLonLat.lat, z),
240
- // maxLon: Math.max(aLonLat.lon, bLonLat.lon),
241
- // maxLat: Math.max(aLonLat.lat, bLonLat.lat, z)
242
-
243
- // }
244
- // }
245
-
246
- }
247
-
76
+ });
package/Math/constants.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  const WORLD_RADIUS_3D = 6378.137;
2
2
  const WORLD_RADIUS_MERCATOR = 6378136.99911;
3
3
 
4
+ const EPSILON = 1e-10; // Used for floating point comparisons
5
+
4
6
  export {
5
7
  WORLD_RADIUS_3D,
6
- WORLD_RADIUS_MERCATOR
8
+ WORLD_RADIUS_MERCATOR,
9
+ EPSILON
7
10
  }
8
11
 
@@ -0,0 +1,32 @@
1
+ // import { WORLD_RADIUS_3D } from '../constants';
2
+ // import { Plane } from '../plane';
3
+ // import { Vector3D } from '../vector3d';
4
+ // import { Quaternion } from '../quaternion';
5
+
6
+
7
+ // function cameraFrustum(
8
+
9
+ // globe: any,
10
+ // out: {
11
+ // near: Plane,
12
+ // far: Plane,
13
+ // left: Plane,
14
+ // right: Plane,
15
+ // top: Plane,
16
+ // bottom: Plane
17
+ // },
18
+ // fieldOfView: number = 50 // in degrees
19
+
20
+ // ): void {
21
+
22
+ // const lookinfo = globe.api_GetCurrentLookInfo();
23
+
24
+ // lookinfo.CenterLong *= Math.PI / 180; // convert degrees to radians
25
+ // lookinfo.CenterLat *= Math.PI / 180; // convert degrees to radians
26
+
27
+ // const lookAtPosition = Vector3D.fromLongLatRadians(lookinfo.CenterLong, lookinfo.CenterLat);
28
+
29
+ // const cameraPosition = new Vector3D(globe.Fp.x, globe.Fp.y, globe.Fp.z).divideByScaler(WORLD_RADIUS_3D);
30
+
31
+ // return
32
+ // }
@@ -0,0 +1,63 @@
1
+ // import { Plane } from "../plane";
2
+ // import { Vector3D } from "../vector3d";
3
+ // import { WORLD_RADIUS_3D } from "../constants";
4
+ // import { Quaternion } from "../quaternion";
5
+
6
+ // import { FrustumPlanes } from "./types";
7
+
8
+ // const _quaternion = new Quaternion();
9
+
10
+ // export function getFrustum(globe: any, fieldOfView: number = 50 * Math.PI / 180,
11
+ // out: FrustumPlanes): void {
12
+
13
+ // const lookinfo = globe.api_GetCurrentLookInfo();
14
+ // lookinfo.CenterLong *= Math.PI / 180; // convert degrees to radians
15
+ // lookinfo.CenterLat *= Math.PI / 180; // convert degrees to radians
16
+ // lookinfo.NorthAng *= Math.PI / 180; // convert degrees to radians
17
+
18
+ // const lookAtPosition = Vector3D.fromLongLatRadians(lookinfo.CenterLong, lookinfo.CenterLat);
19
+ // const cameraPosition = new Vector3D(globe.Fp.x, globe.Fp.y, globe.Fp.z).divideByScaler(WORLD_RADIUS_3D);
20
+ // const lookFromCamera = lookAtPosition.clone().subtract(cameraPosition).normalize();
21
+
22
+
23
+ // const cameraZ = new Vector3D(globe.Fu.x, globe.Fu.y, globe.Fu.z);
24
+ // const cameraY = cameraZ.clone().cross(lookFromCamera).normalize();
25
+
26
+ // const bottomNormal = cameraZ.clone().applyQuaternion(
27
+ // _quaternion.setFromAxisAngle(cameraY, -fieldOfView)
28
+ // ).normalize();
29
+
30
+ // const topNormal = cameraZ.clone().applyQuaternion(
31
+ // _quaternion.setFromAxisAngle(cameraY, fieldOfView)
32
+ // ).negate().normalize();
33
+ // const leftNormal = cameraY.clone().applyQuaternion(
34
+ // _quaternion.setFromAxisAngle(cameraZ, fieldOfView)
35
+ // ).negate().normalize();
36
+
37
+ // const rightNormal = cameraY.clone().applyQuaternion(
38
+ // _quaternion.setFromAxisAngle(cameraZ, -fieldOfView)
39
+ // ).normalize();
40
+
41
+
42
+ // out.top.set(topNormal, topNormal.dot(cameraPosition));
43
+ // out.bottom.set(bottomNormal, bottomNormal.dot(cameraPosition));
44
+ // out.left.set(leftNormal, leftNormal.dot(cameraPosition));
45
+ // out.right.set(rightNormal, rightNormal.dot(cameraPosition));
46
+ // out.far.set(cameraPosition.normalize(), 0.01);
47
+ // out.near = null; // Near plane is not calculated in this function, set to null
48
+ // vectorInfo(globe, [out]);
49
+
50
+ // }
51
+
52
+ // let interval = 0;
53
+
54
+ // const vectorInfo = (globe, args: null | Array<any>) => {
55
+ // interval++;
56
+ // if (interval % 100 === 0) {
57
+ // console.log("Fp:", globe.Fp.x / WORLD_RADIUS_3D, globe.Fp.y / WORLD_RADIUS_3D, globe.Fp.z / WORLD_RADIUS_3D);
58
+ // console.log("Fu:", globe.Fu.x, globe.Fu.y, globe.Fu.z);
59
+
60
+ // if (args) console.log(...args)
61
+ // interval = 0;
62
+ // }
63
+ // }
@@ -0,0 +1,11 @@
1
+ import { Plane } from "../types";
2
+
3
+ export type FrustumPlanes =
4
+ {
5
+ top: Plane,
6
+ bottom: Plane,
7
+ left: Plane,
8
+ right: Plane,
9
+ near: Plane | null,
10
+ far: Plane
11
+ };
@@ -0,0 +1,137 @@
1
+ // TODO: REMOVE
2
+
3
+ // // import { Vector3D, Quaternion, Plane, Ray, Matrix4 } from 'your-3d-math-library'; // <-- ADAPT THIS IMPORT
4
+
5
+ // import { Vector3D } from '../vector3d';
6
+ // import { Plane } from '../plane';
7
+ // import { Line } from '../line';
8
+ // import { Matrix4 } from '../matrix4';
9
+ // import { Quaternion } from '../quaternion';
10
+
11
+ // // --- Assume these static helper variables exist within your class ---
12
+ // const _lookFromOrigin = new Vector3D();
13
+ // const _cameraPosition = new Vector3D();
14
+ // const _finalForward = new Vector3D();
15
+ // const _approxUp = new Vector3D();
16
+ // const _finalRight = new Vector3D();
17
+ // const _finalUp = new Vector3D();
18
+ // const _tempVec = new Vector3D(); // General purpose helper
19
+ // const _initialBottomRayDir = new Vector3D();
20
+ // const _qOrient = new Quaternion();
21
+ // const _rollQuaternion = new Quaternion();
22
+ // const _rotationMatrix = new Matrix4();
23
+ // const _fieldOfViewBottomRay = new Line(new Vector3D(), new Vector3D());
24
+ // const _origin3d = new Vector3D(0, 0, 0); // Globe Center
25
+
26
+ // // --- Assume these constants exist ---
27
+ // const WORLD_RADIUS_3D = 6371000; // Example: Earth radius
28
+ // const FIELD_OF_VIEW = (25 * Math.PI) / 180; // Example: 25 degrees half-FOV in radians
29
+
30
+ // // // --- Assume Plane class has these methods ---
31
+ // // interface Plane {
32
+ // // setFromNormalAndPoint(normal: Vector3D, point: Vector3D): this;
33
+ // // set(normal: Vector3D, constant: number): this;
34
+ // // // ... other plane methods
35
+ // // }
36
+
37
+ // // // --- Assume Ray class has these methods ---
38
+ // // interface Ray {
39
+ // // origin: Vector3D;
40
+ // // direction: Vector3D;
41
+ // // intersectionSphere(center: Vector3D, radius: number): Vector3D[] | null; // Or similar
42
+ // // // ... other ray methods
43
+ // // }
44
+
45
+ // // // --- Assume Vector3D has setFromLongLat ---
46
+ // // interface Vector3D {
47
+ // // setFromLongLat(lon: number, lat: number): this;
48
+ // // // ... other vector methods
49
+ // // }
50
+ // // // --- END OF ASSUMPTIONS ---
51
+
52
+
53
+ // /**
54
+ // * Calculates a culling plane representing the bottom edge of the camera's field of view.
55
+ // * @param globe - The globe object, expected to have api_GetCurrentLookInfo and Fp properties.
56
+ // * @param out - The Plane object to store the result.
57
+ // * @param fieldOfView - The vertical half-angle of the field of view in radians.
58
+ // * @returns The calculated Plane.
59
+ // */
60
+ // function calculateHorizonPlane(globe: any, out: Plane, fieldOfView: number = FIELD_OF_VIEW): Plane {
61
+
62
+ // const cameraLookInfo = globe.api_GetCurrentLookInfo();
63
+ // cameraLookInfo.CenterLong *= Math.PI / 180;
64
+ // cameraLookInfo.CenterLat *= Math.PI / 180;
65
+ // // cameraLookInfo.Tilt *= Math.PI / 180; // Tilt is now implicitly handled
66
+ // cameraLookInfo.NorthAng *= Math.PI / 180;
67
+
68
+ // // Set _lookFromOrigin based on camera target (Lon/Lat)
69
+ // (_lookFromOrigin as any).setFromLongLat(cameraLookInfo.CenterLong, cameraLookInfo.CenterLat); // Cast to any if setFromLongLat is custom
70
+
71
+ // // 1. Calculate _cameraPosition and _finalForward (_lookFromCamera)
72
+ // _cameraPosition.set(globe.Fp.x, globe.Fp.y, globe.Fp.z); // Using your X negation
73
+ // _cameraPosition.divideScalar(WORLD_RADIUS_3D); // Scale to unit sphere
74
+
75
+ // Vector3D.subVectors(_lookFromOrigin, _cameraPosition, _finalForward).normalize();
76
+
77
+ // // 2. Calculate Q_orient (Final Camera Orientation Quaternion)
78
+
79
+ // // Use the vector from origin to camera as an initial 'up' reference
80
+ // _approxUp.copy(_cameraPosition).normalize();
81
+
82
+ // // Calculate Right vector using cross product
83
+ // Vector3D.crossVectors(_finalForward, _approxUp, _finalRight).normalize();
84
+
85
+ // // Handle edge case: If looking straight along (or opposite to) _approxUp
86
+ // if (_finalRight.lengthSq() < 0.0001) {
87
+ // // If vectors are parallel, _approxUp is not good.
88
+ // // Choose a different 'up', e.g., if _approxUp is near Z, use Y.
89
+ // if (Math.abs(_approxUp.z) > 0.9) {
90
+ // _approxUp.set(0, 1, 0);
91
+ // } else {
92
+ // _approxUp.set(0, 0, 1);
93
+ // }
94
+ // Vector3D.crossVectors(_finalForward, _approxUp, _finalRight).normalize();
95
+ // }
96
+
97
+ // // Calculate the 'true' Up vector, orthogonal to Right and Forward
98
+ // Vector3D.crossVectors(_finalRight, _finalForward, _finalUp).normalize();
99
+
100
+ // // Apply NorthAng (Roll) around the Forward axis
101
+ // _rollQuaternion.setFromAxisAngle(_finalForward, cameraLookInfo.NorthAng);
102
+ // _finalUp.applyQuaternion(_rollQuaternion);
103
+ // _finalRight.applyQuaternion(_rollQuaternion); // Must rotate Right as well!
104
+
105
+ // // Create Q_orient from the final basis vectors (Right, Up, -Forward)
106
+ // // This assumes a Matrix4.makeBasis(x, y, z) exists and builds a rotation matrix.
107
+ // // It also assumes local camera looks down -Z, hence negating _finalForward for the Z basis.
108
+ // _tempVec.copy(_finalForward).negate();
109
+ // _rotationMatrix.makeBasis(_finalRight, _finalUp, _tempVec); // <-- ADAPT: Ensure your library has makeBasis or equivalent
110
+ // _qOrient.setFromRotationMatrix(_rotationMatrix); // <-- ADAPT: Ensure this function exists
111
+
112
+ // // 3. Calculate Initial Bottom Ray (Local: -Z forward, Y up, X right)
113
+ // // Rotates (0, 0, -1) around (1, 0, 0) by fieldOfView
114
+ // _initialBottomRayDir.set(0, -Math.sin(fieldOfView), -Math.cos(fieldOfView));
115
+
116
+ // // 4. Calculate Final Bottom Ray (World)
117
+ // _fieldOfViewBottomRay.direction.copy(_initialBottomRayDir).applyQuaternion(_qOrient).normalize();
118
+ // _fieldOfViewBottomRay.origin.copy(_cameraPosition);
119
+
120
+ // // 5. Intersection and Plane
121
+ // const intersection = (_fieldOfViewBottomRay as any).intersectionSphere(_origin3d, 1); // Cast to any if method isn't standard
122
+
123
+ // if (intersection && intersection.length > 0) {
124
+ // // If ray intersects, use the closest point for the plane
125
+ // out.setFromNormalAndPoint(_lookFromOrigin, intersection[0]);
126
+ // } else {
127
+ // // If ray does not intersect (FOV covers globe or misses)
128
+ // // WARNING: This sets a plane through the globe's center.
129
+ // // This might not be the desired behavior for culling.
130
+ // // Consider what should happen if the whole globe *is* visible.
131
+ // out.set(_lookFromOrigin, 0.0);
132
+ // }
133
+
134
+ // return out;
135
+ // }
136
+
137
+ // export { calculateHorizonPlane };
@@ -0,0 +1,90 @@
1
+ import { Vec3, Plane, Line, Sphere, Arc } from "../types";
2
+ import { EPSILON } from "../constants";
3
+ import { vec3 } from "../vec3";
4
+ import { line } from "../line";
5
+ import { plane } from "../plane";
6
+ import { arc } from "../arc";
7
+ import { planePlaneJuction } from "./plane-plane";
8
+ import { lineSphereIntersection } from "./line-sphere";
9
+
10
+ const _intersectionLine = /*@__PURE__*/ line.create();
11
+ const _originPlane = /*@__PURE__*/ plane.create();
12
+ _originPlane.distance = 0;
13
+ const _originSphere = /*@__PURE__*/ { center: vec3.create(0, 0, 0), radius: 1 } as Sphere;
14
+
15
+ const _intersectionPoints: [Vec3, Vec3] = /*@__PURE__*/[vec3.create(), vec3.create()];
16
+
17
+ // TODO: out must be [Arc, Arc] there is a case where split into three arcs, visible by points or arcs but middle is not visible
18
+ export function arcSlice(out: Arc, inArc: Arc, juctionPlane: Plane): boolean {
19
+
20
+ // arc coverPlane and junctionPlane intersection exist in the range of unit sphere
21
+ const coverRadiusAngle = plane.getUnitSphereRadiusAngle(inArc.coverPlane);
22
+ const visibleRadiusAngle = plane.getUnitSphereRadiusAngle(juctionPlane);
23
+ // TODO: RESEARCH efficient approach --
24
+ const angleBetween_Cover_Visible = Math.acos(vec3.dot(inArc.coverPlane.normal, juctionPlane.normal));
25
+
26
+ if (coverRadiusAngle + visibleRadiusAngle < angleBetween_Cover_Visible - EPSILON) { // case A: out of range
27
+ return false; // No intersection
28
+ }
29
+ // ------------------------------------
30
+
31
+ // the case when the arc is completely covered by the juction plane
32
+
33
+ if (visibleRadiusAngle + EPSILON >= angleBetween_Cover_Visible + coverRadiusAngle) { // case B: fully visible
34
+ arc.copy(out, inArc);
35
+ return true;
36
+ }
37
+ // plane-plane intersection line should be calculated for the rest of the calculations
38
+
39
+ vec3.copy(_originPlane.normal, inArc.normal);
40
+ const isPlaneJunctions = planePlaneJuction(_intersectionLine, _originPlane, juctionPlane);
41
+
42
+ if (!isPlaneJunctions) { // case C: planes are parallel.
43
+ // case A covers opposite directions
44
+ // case B Covers they face each other
45
+ throw new Error("Unexpected case: planes are parallel, case A and B should Cover it");
46
+ }
47
+
48
+
49
+ // calculate the intersection points
50
+
51
+ const isSphereIntersection = lineSphereIntersection(_intersectionPoints, _intersectionLine, _originSphere);
52
+
53
+ if (!isSphereIntersection) {
54
+ // other edge caes should be covered by now
55
+ return false; // No intersection
56
+ }
57
+
58
+
59
+ const i0IsCovered = plane.distanceToPoint(inArc.coverPlane, _intersectionPoints[0]) > -EPSILON;
60
+ const i1IsCovered = plane.distanceToPoint(inArc.coverPlane, _intersectionPoints[1]) > -EPSILON;
61
+
62
+ if (i0IsCovered && i1IsCovered) {
63
+ arc.set(out, _intersectionPoints[0], _intersectionPoints[1]);
64
+ return true;
65
+ }
66
+
67
+ const p0IsVisible = plane.distanceToPoint(juctionPlane, inArc.p0) > -EPSILON;
68
+ const p1IsVisible = plane.distanceToPoint(juctionPlane, inArc.p1) > -EPSILON;
69
+
70
+ if (p0IsVisible && p1IsVisible) {
71
+ arc.copy(out, inArc);
72
+ return true;
73
+ }
74
+
75
+ if (!p0IsVisible && !p1IsVisible && !i0IsCovered && !i1IsCovered) {
76
+ return false; // No intersection
77
+ }
78
+
79
+ if ((p0IsVisible || p1IsVisible) !== (i0IsCovered || i1IsCovered)) {
80
+ throw new Error("Unexpected case: one covered and one visible point must be present");
81
+ }
82
+
83
+ arc.set(
84
+ out,
85
+ p0IsVisible ? inArc.p0 : inArc.p1,
86
+ i0IsCovered ? _intersectionPoints[0] : _intersectionPoints[1]
87
+ );
88
+
89
+ return true;
90
+ }