computeFrenetFrames method
Generates the Frenet Frames. Requires a curve definition in 3D space. Used
in geometries like TubeGeometry
or ExtrudeGeometry
.
Implementation
FrenetFrames computeFrenetFrames(int segments, bool closed) {
// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
final normal = Vector3();
final List<Vector3> tangents = [];
final List<Vector3> normals = [];
final List<Vector3> binormals = [];
final vec = Vector3();
final mat = Matrix4();
// compute the tangent vectors for each segment on the curve
for (int i = 0; i <= segments; i++) {
final u = i / segments;
tangents.add(
getTangentAt(u, Vector3()) as Vector3
);
tangents[i].normalize();
}
// select an initial normal vector perpendicular to the first tangent vector,
// and in the direction of the minimum tangent xyz component
normals.add(Vector3());
binormals.add(Vector3());
double min = double.maxFinite;
final tx = tangents[0].x.abs();
final ty = tangents[0].y.abs();
final tz = tangents[0].z.abs();
if (tx <= min) {
min = tx;
normal.setValues(1, 0, 0);
}
if (ty <= min) {
min = ty;
normal.setValues(0, 1, 0);
}
if (tz <= min) {
normal.setValues(0, 0, 1);
}
vec.cross2(tangents[0], normal).normalize();
normals[0].cross2(tangents[0], vec);
binormals[0].cross2(tangents[0], normals[0]);
// compute the slowly-varying normal and binormal vectors for each segment on the curve
for (int i = 1; i <= segments; i++) {
normals.add(normals[i - 1].clone());
binormals.add(binormals[i - 1].clone());
vec.cross2(tangents[i - 1], tangents[i]);
if (vec.length > MathUtils.epsilon) {
vec.normalize();
final theta = math.acos(MathUtils.clamp(tangents[i - 1].dot(tangents[i]),
-1, 1)); // clamp for floating pt errors
normals[i].applyMatrix4(mat.makeRotationAxis(vec, theta));
}
binormals[i].cross2(tangents[i], normals[i]);
}
// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
if (closed) {
double theta = math.acos(MathUtils.clamp(normals[0].dot(normals[segments]), -1, 1));
theta /= segments;
if (tangents[0].dot(vec.cross2(normals[0], normals[segments])) >
0) {
theta = -theta;
}
for (int i = 1; i <= segments; i++) {
// twist a little...
normals[i].applyMatrix4(mat.makeRotationAxis(tangents[i], theta * i));
binormals[i].cross2(tangents[i], normals[i]);
}
}
return FrenetFrames(tangents: tangents, normals: normals, binormals: binormals);
}