-
Notifications
You must be signed in to change notification settings - Fork 3
/
CircleSuperCurve3.js
184 lines (147 loc) · 5.88 KB
/
CircleSuperCurve3.js
1
2
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import { Vector3 } from 'three/src/math/Vector3.js';
import { Quaternion } from 'three/src/math/Quaternion.js';
import { SuperCurve } from './SuperCurve.js';
import * as tram from './tram.js'
class CircleSuperCurve3 extends SuperCurve {
constructor(centerPoint, axisOfRotation, pointOnCircle, length, normalInwards = false) {
// If the length is positive, the curve starts at pointOnCircle. If the length is negative, the curve ends at pointOnCircle.
super();
this.isCircleSuperCurve3 = true;
this.type = 'CircleSuperCurve3';
this.update(centerPoint, axisOfRotation, pointOnCircle, length, normalInwards)
}
update(centerPoint, axisOfRotation, pointOnCircle, length, normalInwards = false) {
this.centerPoint = centerPoint
this.axisOfRotation = axisOfRotation // Perhaps this should be called "circleNormal"
this.pointOnCircle = pointOnCircle
// ToDo: Don't like this API where negative lengths are allowed. Better to add another parameter.
this.length = Math.abs(length)
this.lengthSign = Math.sign(length)
this.normalInwards = normalInwards
this.centerToPointOnCircle = pointOnCircle.clone().sub(centerPoint)
this.radius = this.centerToPointOnCircle.length()
this.normalizedCenterToPointOnCircle = this.centerToPointOnCircle.clone().normalize()
this.binormal = this.axisOfRotation.normalize()
this.duration = 0;
}
getLength() {
return this.length
}
setDuration(duration) {
this.duration = duration
}
getDuration() {
return this.duration
}
getPoint(t, optionalTarget) {
const d = this.tTod(t) / this.length
return this.getPointAt(d, optionalTarget)
}
getPointAt(d, optionalTarget) {
// d is a number from 0 to 1 which indicates the desired distance along the curve
const point = optionalTarget || new Vector3();
const angle = (this.lengthSign>0) ? d * this.length / this.radius : (-1 + d) * this.length / this.radius
point.copy(this.centerToPointOnCircle)
point.applyAxisAngle(this.axisOfRotation, angle).add(this.centerPoint)
return point
}
getTangent(t, optionalTarget) {
const d = this.tTod(t) / this.length
return this.getTangentAt(d, optionalTarget)
}
getTangentAt(d, optionalTarget) {
// d is a number from 0 to 1 which indicates the desired distance along the curve
const vector = optionalTarget || new Vector3();
const angle = (this.lengthSign>0) ? d * this.length / this.radius : (-1 + d) * this.length / this.radius
vector.copy(this.normalizedCenterToPointOnCircle)
vector.applyAxisAngle(this.axisOfRotation, angle + Math.PI/2)
return vector
}
getNormal(t, optionalTarget) {
const d = this.tTod(t) / this.length
return this.getNormalAt(d, optionalTarget)
}
getNormalAt(d, optionalTarget) {
// d is a number from 0 to 1 which indicates the desired distance along the curve
const vector = optionalTarget || new Vector3();
const angle = (this.lengthSign>0) ? d * this.length / this.radius : (-1 + d) * this.length / this.radius
vector.copy(this.normalizedCenterToPointOnCircle)
vector.applyAxisAngle(this.axisOfRotation, angle)
if (this.normalInwards) vector.negate()
return vector
}
getBinormal(t, optionalTarget) {
const d = this.tTod(t) / this.length
return this.getBinormalAt(d, optionalTarget)
}
getBinormalAt(d, optionalTarget) {
const vector = optionalTarget || new Vector3();
vector.copy(this.binormal)
return vector
}
addtToiConvertor(tToiConvertor) {
this.tToi = tToiConvertor
}
addtTodConvertor(tTodConvertor) {
this.tTod = tTodConvertor
}
addtTosConvertor(tTosConvertor) {
this.tTos = tTosConvertor
}
getQuaternion(t, objectForward = new Vector3(0, 1, 0), objectUpward = new Vector3(0, 0, 1), optionalTarget = new Quaternion() ) {
const d = this.tTod(t) / this.length
return this.getQuaternionAt(d, objectForward, objectUpward, optionalTarget)
}
getQuaternionAt(d, objectForward = new Vector3(0, 1, 0), objectUpward = new Vector3(0, 0, 1), optionalTarget = new Quaternion() ) {
const q1 = optionalTarget
const tangent = this.getTangentAt(d)
const normal = this.getNormalAt(d)
q1.setFromUnitVectors(objectForward, tangent)
const rotatedObjectUpwardVector = objectUpward.clone().applyQuaternion(q1)
const q2 = new Quaternion
q2.setFromUnitVectors(rotatedObjectUpwardVector, normal)
q2.multiply(q1)
return q2
}
getStartFinishZoneIndices(sphereCenter, sphereRadius) {
const circleCenter = this.centerPoint.clone()
const circleNormal = this.axisOfRotation.clone().normalize()
const circleRadius = this.radius
const intersections = tram.findCircleSphereIntersections(circleCenter, circleNormal, circleRadius, sphereCenter, sphereRadius)
const dValues = []
intersections.forEach(intersection => {
const dValue = this.convertPointToDValue(intersection)
if (dValue>=0 && dValue<=1) dValues.push(dValue)
})
const startPoint = this.getPointAt(0)
// Check if either of the curve's endpoints are inside (or on) the sphere...
if (startPoint.distanceTo(sphereCenter) <= sphereRadius) {
dValues.push(0)
}
const endPoint = this.getPointAt(1)
if (endPoint.distanceTo(sphereCenter) <= sphereRadius) {
dValues.push(1)
}
if (dValues.length==1) {
console.log("Warning: Circle curve really should not have only one intersetion point with a sphere if the algorithm is working correctly...")
// But we'll handle it anyway...
dValues.push(dValues[0])
}
if (dValues.length>=2) {
dValues.sort()
return [dValues[0], dValues[dValues.length-1]]
}
else {
return []
}
}
convertPointToDValue(point) {
const zeroVector = this.getPointAt(0).sub(this.centerPoint)
const pointVector = point.clone().sub(this.centerPoint)
const angle = Math.asin(zeroVector.clone().cross(pointVector).dot(this.axisOfRotation)/zeroVector.length()/pointVector.length())
//const posAngle = (Math.PI*2 + angle) % (Math.PI*2)
const dValue = angle * this.radius / this.length
return dValue
}
}
export { CircleSuperCurve3 };