@pirireis/webglobeplugins 0.9.14 → 0.10.0-alpha
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/Math/arc.js +188 -60
- package/Math/juction/arc-plane.js +38 -30
- package/Math/juction/line-sphere.js +14 -14
- package/Math/juction/plane-plane.js +9 -9
- package/Math/line.js +51 -52
- package/Math/plane.js +55 -56
- package/Math/quaternion.js +102 -97
- package/Math/vec3.js +120 -121
- package/heatwave/plugins/heatwaveglobeshell.js +7 -6
- package/package.json +1 -1
- package/programs/index.js +1 -1
- package/programs/vectorfields/logics/drawrectangleparticles.js +7 -13
- package/programs/vectorfields/logics/index.js +1 -3
- package/programs/vectorfields/logics/pixelbased.js +7 -16
- package/shape-on-terrain/arc/naive/plugin.js +22 -21
- package/util/heatwavedatamanager/pointcoordinatesdatacalculator.js +6 -6
- package/util/heatwavedatamanager/pointcoordsmeta.js +7 -2
- package/util/heatwavedatamanager/texture-point-sampler.js +160 -0
- package/util/webglobjectbuilders.js +13 -20
- package/waveparticles/plugin.js +14 -9
package/Math/arc.js
CHANGED
|
@@ -1,62 +1,190 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { create as vec3create, set as vec3set, cross, dot, normalize, clone as vec3clone, copy as vec3copy, equals as vec3equals, lengthSquared, fromUnitVectorLongLat, subtract, applyQuaternion, toUnitVectorLongLat } from "./vec3";
|
|
2
|
+
import { create as planeCreate, fromPoints as planeFromPoints, distanceToPoint as planeDistanceToPoint, projectPoint as planeProjectPoint } from "./plane";
|
|
3
|
+
import { create as quaternionCreate, fromAxisAngle } from "./quaternion";
|
|
2
4
|
import { EPSILON } from "./constants";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
out.coverPlane.
|
|
36
|
-
out.coverPlane.distance = a.coverPlane.distance;
|
|
37
|
-
},
|
|
38
|
-
clone(a) {
|
|
39
|
-
return {
|
|
40
|
-
p0: vec3.clone(a.p0),
|
|
41
|
-
p1: vec3.clone(a.p1),
|
|
42
|
-
normal: vec3.clone(a.normal),
|
|
43
|
-
coverPlane: {
|
|
44
|
-
normal: vec3.clone(a.coverPlane.normal),
|
|
45
|
-
distance: a.coverPlane.distance
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
},
|
|
49
|
-
isPointOn(arc, point) {
|
|
50
|
-
const alignment = Math.abs(vec3.dot(point, arc.normal)) < EPSILON;
|
|
51
|
-
const distance = Math.abs(vec3.lengthSquared(point) - 1) < EPSILON;
|
|
52
|
-
const cover = vec3.dot(arc.coverPlane.normal, point) >= arc.coverPlane.distance;
|
|
53
|
-
return alignment || distance || cover;
|
|
54
|
-
},
|
|
55
|
-
equals(a, b) {
|
|
56
|
-
return vec3.equals(a.p0, b.p0) && vec3.equals(a.p1, b.p1);
|
|
57
|
-
},
|
|
58
|
-
populatePoints(out, arc, count) {
|
|
59
|
-
// rotate p0 around normal vector with a quaternion
|
|
60
|
-
// calculate angle
|
|
5
|
+
import * as vec3 from "./vec3";
|
|
6
|
+
import * as quat from "./quaternion";
|
|
7
|
+
const _0vector = /*@__PURE__*/ vec3create(0, 0, 0);
|
|
8
|
+
const _closestPoint = /*@__PURE__*/ vec3create();
|
|
9
|
+
const _originPlane = /*@__PURE__*/ planeCreate(vec3create(0, 0, 1), 0);
|
|
10
|
+
// dont change distance of _originPlane
|
|
11
|
+
const _rotationQuaternion = /*@__PURE__*/ quaternionCreate();
|
|
12
|
+
const _longLat = /*@__PURE__*/ [0, 0];
|
|
13
|
+
function create(p0, p1) {
|
|
14
|
+
const normal = vec3create(0, 0, 0);
|
|
15
|
+
cross(normal, p0, p1);
|
|
16
|
+
const coverPlaneNormal = [p0[0] + p1[0], p0[1] + p1[1], p0[2] + p1[2]];
|
|
17
|
+
normalize(coverPlaneNormal, coverPlaneNormal);
|
|
18
|
+
const dot_ = dot(coverPlaneNormal, p0);
|
|
19
|
+
return {
|
|
20
|
+
p0: vec3clone(p0),
|
|
21
|
+
p1: vec3clone(p1),
|
|
22
|
+
normal: vec3clone(normal),
|
|
23
|
+
coverPlane: {
|
|
24
|
+
normal: coverPlaneNormal,
|
|
25
|
+
distance: dot_
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function set(out, p0, p1) {
|
|
30
|
+
vec3copy(out.p0, p0);
|
|
31
|
+
vec3copy(out.p1, p1);
|
|
32
|
+
cross(out.normal, p0, p1);
|
|
33
|
+
vec3set(_0vector, p0[0] + p1[0], p0[1] + p1[1], p0[2] + p1[2]);
|
|
34
|
+
const ls = lengthSquared(_0vector);
|
|
35
|
+
if (ls > EPSILON) {
|
|
36
|
+
normalize(out.coverPlane.normal, _0vector);
|
|
37
|
+
out.coverPlane.distance = dot(out.coverPlane.normal, p0);
|
|
61
38
|
}
|
|
62
|
-
|
|
39
|
+
else {
|
|
40
|
+
_oppositePointsHandle(p0, p1, out.normal, out.coverPlane);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function copy(out, a) {
|
|
44
|
+
vec3copy(out.p0, a.p0);
|
|
45
|
+
vec3copy(out.p1, a.p1);
|
|
46
|
+
vec3copy(out.normal, a.normal);
|
|
47
|
+
out.coverPlane.normal = vec3clone(a.coverPlane.normal);
|
|
48
|
+
out.coverPlane.distance = a.coverPlane.distance;
|
|
49
|
+
}
|
|
50
|
+
function clone(a) {
|
|
51
|
+
return {
|
|
52
|
+
p0: vec3clone(a.p0),
|
|
53
|
+
p1: vec3clone(a.p1),
|
|
54
|
+
normal: vec3clone(a.normal),
|
|
55
|
+
coverPlane: {
|
|
56
|
+
normal: vec3clone(a.coverPlane.normal),
|
|
57
|
+
distance: a.coverPlane.distance
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function isPointOn(arc, point) {
|
|
62
|
+
const alignment = Math.abs(dot(point, arc.normal)) < EPSILON;
|
|
63
|
+
const distance = Math.abs(lengthSquared(point) - 1) < EPSILON;
|
|
64
|
+
const cover = dot(arc.coverPlane.normal, point) >= arc.coverPlane.distance;
|
|
65
|
+
return alignment || distance || cover;
|
|
66
|
+
}
|
|
67
|
+
function equals(a, b) {
|
|
68
|
+
return (vec3equals(a.p0, b.p0) && vec3equals(a.p1, b.p1))
|
|
69
|
+
|| (vec3equals(a.p0, b.p1) && vec3equals(a.p1, b.p0));
|
|
70
|
+
}
|
|
71
|
+
function closestPoint(out, inArc, point) {
|
|
72
|
+
// 1. calculate the projection of the point onto the plane definned by the arc.normal, distance 0
|
|
73
|
+
// 2. calculate projection distance to the arc.coverPlane.
|
|
74
|
+
// * if the distance is negative, the point is outside the arc
|
|
75
|
+
// * copy (the closest of [inArc.p0, inArc.p1] to the point) to the output
|
|
76
|
+
// * return false that indicates the point is outside the arc
|
|
77
|
+
// * if the distance is positive, the point is inside the arc
|
|
78
|
+
// * normalize the projection and copy it to out
|
|
79
|
+
// * return true that indicates the point is inside the arc
|
|
80
|
+
const distance = planeDistanceToPoint(inArc.coverPlane, point);
|
|
81
|
+
if (distance < -EPSILON) {
|
|
82
|
+
// point is outside the arc
|
|
83
|
+
// this case also covers point is on center shaft line of the arc
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
vec3copy(_originPlane.normal, inArc.normal);
|
|
87
|
+
planeProjectPoint(_0vector, _originPlane, point);
|
|
88
|
+
// point is inside the arc
|
|
89
|
+
normalize(out, _0vector);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
function populatePoints(out, arc, count, pointOfProjection = undefined) {
|
|
93
|
+
// rotate p0 around normal vector with a quaternion
|
|
94
|
+
// calculate angle
|
|
95
|
+
_distanceSampling(out, count, arc, pointOfProjection || [0, 0, 0], 1);
|
|
96
|
+
}
|
|
97
|
+
function _oppositePointsHandle(p0, p1, outNormal, outCoverPlane) {
|
|
98
|
+
// first choice pass through Anitkabir
|
|
99
|
+
const radians = Math.PI / 180;
|
|
100
|
+
fromUnitVectorLongLat(_0vector, [39.9334 * radians, 32.8597 * radians]); // Anitkabir
|
|
101
|
+
if (vec3equals(p0, _0vector) || vec3equals(p1, _0vector)) {
|
|
102
|
+
// if Anitkabir is too close to p0 or p1, use Selanic
|
|
103
|
+
fromUnitVectorLongLat(_0vector, [37.0016 * radians, 35.3213 * radians]); // Selanic
|
|
104
|
+
}
|
|
105
|
+
planeFromPoints({ normal: outNormal, distance: 0 }, p0, _0vector, p1);
|
|
106
|
+
cross(outCoverPlane.normal, outNormal, p0);
|
|
107
|
+
}
|
|
108
|
+
function _populatePointsWithClosestPointInsideArc(out, arc, count, closestPoint) {
|
|
109
|
+
// two parts divided by closest point will be populated seperately
|
|
110
|
+
// pop1 + pop2 = count
|
|
111
|
+
// angular distance between [arc.p0, closestPoint] and [arc.p1, closestPoint]
|
|
112
|
+
// will be used to decide ratio between pop1 and pop2
|
|
113
|
+
const angleP0 = Math.acos(dot(arc.p0, closestPoint));
|
|
114
|
+
const angleP1 = Math.acos(dot(arc.p1, closestPoint));
|
|
115
|
+
const pop1 = Math.floor(count * (angleP0 / (angleP0 + angleP1)));
|
|
116
|
+
const pop2 = count - pop1;
|
|
117
|
+
const angleStep1 = angleP0 / pop1;
|
|
118
|
+
const angleStep2 = angleP1 / pop2;
|
|
119
|
+
fromAxisAngle(_rotationQuaternion, arc.normal, angleStep1);
|
|
120
|
+
}
|
|
121
|
+
function _populatePointsWithoutClosestPoint(out, arc, count) {
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Samples points along an arc with density biased by the camera's distance,
|
|
125
|
+
* reusing the rotation quaternion to improve performance.
|
|
126
|
+
*
|
|
127
|
+
* @param {Float32Array} out - The output array to store longitude and latitude pairs.
|
|
128
|
+
* @param {number} count - The total number of points to sample.
|
|
129
|
+
* @param {Arc} inArc - The arc to sample from, containing p0, p1, and normal.
|
|
130
|
+
* @param {Vec3} cameraPosition - The position of the camera.
|
|
131
|
+
* @param {number} quaternionReuseCount - The number of times to apply the same rotation before recalculating. Higher is faster but less accurate.
|
|
132
|
+
*/
|
|
133
|
+
function _distanceSampling(out, count, inArc, cameraPosition = vec3create(0, 0, 0), // TODO
|
|
134
|
+
quaternionReuseCount = 1) {
|
|
135
|
+
if (count === 0) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const _0vector = vec3.create();
|
|
139
|
+
const _longLat = [0, 0];
|
|
140
|
+
const _rotationQuaternion = quat.create();
|
|
141
|
+
// Ensure reuse count is at least 1 to prevent division by zero or infinite loops.
|
|
142
|
+
const reuseCount = Math.max(1, quaternionReuseCount);
|
|
143
|
+
subtract(_0vector, inArc.p0, cameraPosition);
|
|
144
|
+
const d2_0 = lengthSquared(_0vector);
|
|
145
|
+
subtract(_0vector, inArc.p1, cameraPosition);
|
|
146
|
+
const d2_1 = lengthSquared(_0vector);
|
|
147
|
+
const total = d2_0 + d2_1;
|
|
148
|
+
const ratio0 = Math.min(0.995, Math.max(0.005, d2_0 / total));
|
|
149
|
+
const is0Closer = d2_0 < d2_1;
|
|
150
|
+
const totalAngle = Math.acos(dot(inArc.p0, inArc.p1));
|
|
151
|
+
let accumulatedAngle = 0;
|
|
152
|
+
// This variable will hold the step angle for the current "chunk" of reused rotations.
|
|
153
|
+
let chunkStepAngle = 0;
|
|
154
|
+
let currentPoint = vec3.clone(is0Closer ? inArc.p0 : inArc.p1);
|
|
155
|
+
const angleSign = is0Closer ? 1 : -1;
|
|
156
|
+
// The loop generates all points *except* the very last one.
|
|
157
|
+
for (let i = 0; i < count - 1; i++) {
|
|
158
|
+
// First, store the longitude/latitude of the current point.
|
|
159
|
+
toUnitVectorLongLat(_longLat, currentPoint);
|
|
160
|
+
out[i * 2] = _longLat[0];
|
|
161
|
+
out[i * 2 + 1] = _longLat[1];
|
|
162
|
+
// --- OPTIMIZATION LOGIC ---
|
|
163
|
+
// We only update the quaternion and step angle periodically.
|
|
164
|
+
if (i % reuseCount === 0) {
|
|
165
|
+
// This is the start of a new chunk. Calculate the step angle that will be
|
|
166
|
+
// reused for the next `reuseCount` iterations.
|
|
167
|
+
const t = (i + 1) / (count - 1);
|
|
168
|
+
const biasedT = Math.sin(t * Math.PI / 2);
|
|
169
|
+
const targetAngleForNextStep = (is0Closer ? biasedT : 1.0 - biasedT) * totalAngle;
|
|
170
|
+
// Calculate the single step angle based on the progress at the start of the chunk.
|
|
171
|
+
chunkStepAngle = targetAngleForNextStep - accumulatedAngle;
|
|
172
|
+
// Update the quaternion. This expensive call now runs much less frequently.
|
|
173
|
+
fromAxisAngle(_rotationQuaternion, inArc.normal, chunkStepAngle * angleSign);
|
|
174
|
+
}
|
|
175
|
+
// Apply the rotation. This happens on every iteration, but uses the
|
|
176
|
+
// same quaternion for `reuseCount` steps.
|
|
177
|
+
applyQuaternion(currentPoint, currentPoint, _rotationQuaternion);
|
|
178
|
+
// We must still update the accumulated angle on every step to track our progress.
|
|
179
|
+
accumulatedAngle += chunkStepAngle;
|
|
180
|
+
}
|
|
181
|
+
// Set the final point directly to the endpoint to guarantee precision.
|
|
182
|
+
if (count > 0) {
|
|
183
|
+
const finalIndex = count - 1;
|
|
184
|
+
const endPoint = is0Closer ? inArc.p1 : inArc.p0;
|
|
185
|
+
toUnitVectorLongLat(_longLat, endPoint);
|
|
186
|
+
out[finalIndex * 2] = _longLat[0];
|
|
187
|
+
out[finalIndex * 2 + 1] = _longLat[1];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
export { create, set, copy, clone, isPointOn, equals, closestPoint, populatePoints };
|
|
@@ -1,45 +1,53 @@
|
|
|
1
1
|
import { EPSILON } from "../constants";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { create as vec3create, copy as vec3copy, dot, distanceSquared, } from "../vec3";
|
|
3
|
+
import { create as lineCreate } from "../line";
|
|
4
|
+
import { create as planeCreate, distanceToPoint, getUnitSphereRadiusAngle } from "../plane";
|
|
5
|
+
import { copy as arcCopy, set as arcSet } from "../arc";
|
|
6
6
|
import { planePlaneJuction } from "./plane-plane";
|
|
7
7
|
import { lineSphereIntersection } from "./line-sphere";
|
|
8
|
-
const _intersectionLine = /*@__PURE__*/
|
|
9
|
-
const _originPlane = /*@__PURE__*/
|
|
8
|
+
const _intersectionLine = /*@__PURE__*/ lineCreate();
|
|
9
|
+
const _originPlane = /*@__PURE__*/ planeCreate();
|
|
10
10
|
_originPlane.distance = 0;
|
|
11
|
-
const _originSphere = /*@__PURE__*/ { center:
|
|
12
|
-
const _intersectionPoints = /*@__PURE__*/ [
|
|
11
|
+
const _originSphere = /*@__PURE__*/ { center: vec3create(0, 0, 0), radius: 1 };
|
|
12
|
+
const _intersectionPoints = /*@__PURE__*/ [vec3create(), vec3create()];
|
|
13
13
|
// 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
|
|
14
14
|
/**
|
|
15
15
|
*
|
|
16
16
|
* @param out \
|
|
17
17
|
* @param inArc
|
|
18
|
-
* @param
|
|
18
|
+
* @param junctionPlane
|
|
19
19
|
* @returns number of arcs segments in the junction divided by the junction plane.
|
|
20
20
|
*/
|
|
21
|
-
export function arcSlice(out, inArc,
|
|
21
|
+
export function arcSlice(out, inArc, junctionPlane) {
|
|
22
|
+
if (junctionPlane.distance < -1 + EPSILON) {
|
|
23
|
+
arcCopy(out[0], inArc);
|
|
24
|
+
return 1;
|
|
25
|
+
}
|
|
22
26
|
// arc coverPlane and junctionPlane intersection exist in the range of unit sphere
|
|
23
|
-
const coverRadiusAngle =
|
|
24
|
-
const visibleRadiusAngle =
|
|
27
|
+
const coverRadiusAngle = getUnitSphereRadiusAngle(inArc.coverPlane);
|
|
28
|
+
const visibleRadiusAngle = getUnitSphereRadiusAngle(junctionPlane);
|
|
25
29
|
// TODO: RESEARCH efficient approach --
|
|
26
|
-
const angleBetween_Cover_Visible = Math.acos(
|
|
30
|
+
const angleBetween_Cover_Visible = Math.acos(dot(inArc.coverPlane.normal, junctionPlane.normal));
|
|
27
31
|
if (coverRadiusAngle + visibleRadiusAngle < angleBetween_Cover_Visible - EPSILON) { // case A: out of range
|
|
28
32
|
return 0; // No intersection
|
|
29
33
|
}
|
|
30
34
|
// ------------------------------------
|
|
31
35
|
// the case when the arc is completely covered by the juction plane
|
|
32
36
|
if (visibleRadiusAngle + EPSILON >= angleBetween_Cover_Visible + coverRadiusAngle) { // case B: fully visible
|
|
33
|
-
|
|
37
|
+
arcCopy(out[0], inArc);
|
|
34
38
|
return 1;
|
|
35
39
|
}
|
|
36
40
|
// plane-plane intersection line should be calculated for the rest of the calculations
|
|
37
|
-
|
|
38
|
-
const isPlaneJunctions = planePlaneJuction(_intersectionLine, _originPlane,
|
|
41
|
+
vec3copy(_originPlane.normal, inArc.normal);
|
|
42
|
+
const isPlaneJunctions = planePlaneJuction(_intersectionLine, _originPlane, junctionPlane);
|
|
39
43
|
if (!isPlaneJunctions) { // case C: planes are parallel.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
if (junctionPlane.distance <= 0) {
|
|
45
|
+
arcCopy(out[0], inArc);
|
|
46
|
+
return 1; // No intersection
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
return 0; // No intersection
|
|
50
|
+
}
|
|
43
51
|
}
|
|
44
52
|
// --- read until here ---
|
|
45
53
|
// calculate the intersection points
|
|
@@ -48,33 +56,33 @@ export function arcSlice(out, inArc, juctionPlane) {
|
|
|
48
56
|
// other edge caes should be covered by now
|
|
49
57
|
return 0; // No intersection
|
|
50
58
|
}
|
|
51
|
-
const i0IsCovered =
|
|
52
|
-
const i1IsCovered =
|
|
53
|
-
const p0IsVisible =
|
|
54
|
-
const p1IsVisible =
|
|
59
|
+
const i0IsCovered = distanceToPoint(inArc.coverPlane, _intersectionPoints[0]) > -EPSILON;
|
|
60
|
+
const i1IsCovered = distanceToPoint(inArc.coverPlane, _intersectionPoints[1]) > -EPSILON;
|
|
61
|
+
const p0IsVisible = distanceToPoint(junctionPlane, inArc.p0) > -EPSILON;
|
|
62
|
+
const p1IsVisible = distanceToPoint(junctionPlane, inArc.p1) > -EPSILON;
|
|
55
63
|
if (!p0IsVisible && !p1IsVisible && !i0IsCovered && !i1IsCovered) {
|
|
56
64
|
return 0; // No intersection
|
|
57
65
|
}
|
|
58
66
|
if (i0IsCovered && i1IsCovered && p0IsVisible && p1IsVisible) {
|
|
59
67
|
// calculate which points are closer
|
|
60
|
-
const p0i0DistanceSquared =
|
|
61
|
-
const p0i1DistanceSquared =
|
|
68
|
+
const p0i0DistanceSquared = distanceSquared(inArc.p0, _intersectionPoints[0]);
|
|
69
|
+
const p0i1DistanceSquared = distanceSquared(inArc.p0, _intersectionPoints[1]);
|
|
62
70
|
const case0 = p0i0DistanceSquared < p0i1DistanceSquared;
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
arcSet(out[0], inArc.p0, case0 ? _intersectionPoints[0] : _intersectionPoints[1]);
|
|
72
|
+
arcSet(out[1], inArc.p1, !case0 ? _intersectionPoints[0] : _intersectionPoints[1]);
|
|
65
73
|
return 2;
|
|
66
74
|
}
|
|
67
75
|
if (i0IsCovered && i1IsCovered) {
|
|
68
|
-
|
|
76
|
+
arcSet(out[0], _intersectionPoints[0], _intersectionPoints[1]);
|
|
69
77
|
return 1;
|
|
70
78
|
}
|
|
71
79
|
if (p0IsVisible && p1IsVisible) {
|
|
72
|
-
|
|
80
|
+
arcCopy(out[0], inArc);
|
|
73
81
|
return 1;
|
|
74
82
|
}
|
|
75
83
|
if ((p0IsVisible || p1IsVisible) !== (i0IsCovered || i1IsCovered)) {
|
|
76
84
|
throw new Error("Unexpected case: one covered and one visible point must be present");
|
|
77
85
|
}
|
|
78
|
-
|
|
86
|
+
arcSet(out[0], p0IsVisible ? inArc.p0 : inArc.p1, i0IsCovered ? _intersectionPoints[0] : _intersectionPoints[1]);
|
|
79
87
|
return 1;
|
|
80
88
|
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
const _0vector = /*@__PURE__*/
|
|
1
|
+
import { create, dot, lengthSquared, subtract } from "../vec3";
|
|
2
|
+
import { at } from "../line";
|
|
3
|
+
const _0vector = /*@__PURE__*/ create(0, 0, 0);
|
|
4
4
|
export function lineSphereIntersection(out, inLine, inSphere) {
|
|
5
|
-
|
|
6
|
-
const distanceSquared =
|
|
5
|
+
subtract(_0vector, inLine.origin, inSphere.center);
|
|
6
|
+
const distanceSquared = lengthSquared(_0vector);
|
|
7
7
|
const radiusSquared = inSphere.radius * inSphere.radius;
|
|
8
|
-
const
|
|
9
|
-
const dotSquared =
|
|
10
|
-
const
|
|
11
|
-
if (
|
|
8
|
+
const dot_ = dot(_0vector, inLine.direction);
|
|
9
|
+
const dotSquared = dot_ * dot_;
|
|
10
|
+
const discriminant = dotSquared + radiusSquared - distanceSquared;
|
|
11
|
+
if (discriminant < 0) {
|
|
12
12
|
return false; // no intersection
|
|
13
13
|
}
|
|
14
14
|
else {
|
|
15
|
-
const a = Math.sqrt(
|
|
16
|
-
const t1 =
|
|
17
|
-
const t2 =
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const a = Math.sqrt(discriminant);
|
|
16
|
+
const t1 = -dot_ - a;
|
|
17
|
+
const t2 = -dot_ + a;
|
|
18
|
+
at(out[0], inLine, t1);
|
|
19
|
+
at(out[1], inLine, t2);
|
|
20
20
|
return true;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { EPSILON } from "../constants";
|
|
2
|
-
import {
|
|
3
|
-
const _normal1 =
|
|
4
|
-
const _normal2 =
|
|
2
|
+
import { copy, create, dot, cross, lengthSquared } from "../vec3";
|
|
3
|
+
const _normal1 = create();
|
|
4
|
+
const _normal2 = create();
|
|
5
5
|
export function planePlaneJuction(out, plane1, plane2) {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
copy(_normal1, plane1.normal);
|
|
7
|
+
copy(_normal2, plane2.normal);
|
|
8
8
|
const distance1 = plane1.distance;
|
|
9
9
|
const distance2 = plane2.distance;
|
|
10
10
|
const { origin, direction } = out;
|
|
11
|
-
const
|
|
12
|
-
if (Math.abs(
|
|
11
|
+
const d = dot(_normal1, _normal2);
|
|
12
|
+
if (Math.abs(d) > 1 - EPSILON) {
|
|
13
13
|
return false; // Planes are parallel, no intersection
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
const magnitudeSquired =
|
|
15
|
+
cross(direction, _normal1, _normal2);
|
|
16
|
+
const magnitudeSquired = lengthSquared(out.direction);
|
|
17
17
|
if (magnitudeSquired < EPSILON) {
|
|
18
18
|
return false; // No valid intersection line
|
|
19
19
|
}
|
package/Math/line.js
CHANGED
|
@@ -1,53 +1,52 @@
|
|
|
1
1
|
import { EPSILON } from './constants';
|
|
2
|
-
import {
|
|
3
|
-
const _0vector = /*@__PURE__*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
});
|
|
2
|
+
import { subtract, applyQuaternion as vec3applyQuaternion, add, multiplyScalar, normalize, dot, cross, lengthSquared, clone as vec3clone, create as vec3create, copy as vec3copy } from './vec3';
|
|
3
|
+
const _0vector = /*@__PURE__*/ vec3create(0, 0, 0);
|
|
4
|
+
function create(origin = vec3create(), direction = vec3create()) {
|
|
5
|
+
const direction_ = vec3clone(direction);
|
|
6
|
+
normalize(direction_, direction_);
|
|
7
|
+
return {
|
|
8
|
+
origin: vec3clone(origin),
|
|
9
|
+
direction: direction_
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function set(out, origin, direction) {
|
|
13
|
+
vec3copy(out.origin, origin);
|
|
14
|
+
vec3copy(out.direction, direction);
|
|
15
|
+
}
|
|
16
|
+
function copy(out, a) {
|
|
17
|
+
out.origin = vec3copy(out.origin, a.origin);
|
|
18
|
+
out.direction = vec3copy(out.direction, a.direction);
|
|
19
|
+
}
|
|
20
|
+
function clone(a) {
|
|
21
|
+
return {
|
|
22
|
+
origin: vec3clone(a.origin),
|
|
23
|
+
direction: vec3clone(a.direction)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function fromTwoPoints(out, a, b) {
|
|
27
|
+
subtract(out.direction, b, a);
|
|
28
|
+
normalize(out.direction, out.direction);
|
|
29
|
+
vec3copy(out.origin, a);
|
|
30
|
+
}
|
|
31
|
+
function at(out, line, distance) {
|
|
32
|
+
multiplyScalar(_0vector, line.direction, distance);
|
|
33
|
+
add(out, _0vector, line.origin);
|
|
34
|
+
}
|
|
35
|
+
function closestPoint(out, line, point) {
|
|
36
|
+
subtract(_0vector, point, line.origin);
|
|
37
|
+
const dot_ = dot(_0vector, line.direction);
|
|
38
|
+
vec3copy(out, line.direction);
|
|
39
|
+
multiplyScalar(out, out, dot_);
|
|
40
|
+
add(out, out, line.origin);
|
|
41
|
+
}
|
|
42
|
+
function contains(line, point) {
|
|
43
|
+
subtract(_0vector, point, line.origin);
|
|
44
|
+
cross(_0vector, _0vector, line.direction);
|
|
45
|
+
return lengthSquared(_0vector) < EPSILON;
|
|
46
|
+
}
|
|
47
|
+
function applyQuaternion(out, line, quaternion) {
|
|
48
|
+
vec3applyQuaternion(out.origin, line.origin, quaternion);
|
|
49
|
+
vec3applyQuaternion(out.direction, line.direction, quaternion);
|
|
50
|
+
normalize(out.direction, out.direction);
|
|
51
|
+
}
|
|
52
|
+
export { create, set, copy, clone, fromTwoPoints, at, closestPoint, contains, applyQuaternion };
|