computeFrenetFrames method

dynamic computeFrenetFrames(
  1. dynamic segments,
  2. dynamic closed
)

Implementation

computeFrenetFrames(segments, closed) {
  // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf

  var normal = Vector3.init();

  var tangents = [];
  var normals = [];
  var binormals = [];

  var vec = Vector3.init();
  var mat = Matrix4();

  // compute the tangent vectors for each segment on the curve

  for (var i = 0; i <= segments; i++) {
    var u = i / segments;

    tangents.add(getTangentAt(u, Vector3.init()));
    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.init());
  binormals.add(Vector3.init());
  var min = Math.maxValue;
  final tx = Math.abs(tangents[0].x).toDouble();
  final ty = Math.abs(tangents[0].y).toDouble();
  final tz = Math.abs(tangents[0].z).toDouble();

  if (tx <= min) {
    min = tx;
    normal.set(1, 0, 0);
  }

  if (ty <= min) {
    min = ty;
    normal.set(0, 1, 0);
  }

  if (tz <= min) {
    normal.set(0, 0, 1);
  }

  vec.crossVectors(tangents[0], normal).normalize();

  normals[0].crossVectors(tangents[0], vec);
  binormals[0].crossVectors(tangents[0], normals[0]);

  // compute the slowly-varying normal and binormal vectors for each segment on the curve

  for (var i = 1; i <= segments; i++) {
    normals.add(normals[i - 1].clone());

    binormals.add(binormals[i - 1].clone());

    vec.crossVectors(tangents[i - 1], tangents[i]);

    if (vec.length() > Math.epsilon) {
      vec.normalize();

      var 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].crossVectors(tangents[i], normals[i]);
  }

  // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same

  if (closed == true) {
    var theta = Math.acos(MathUtils.clamp(normals[0].dot(normals[segments]), -1, 1));
    theta /= segments;

    if (tangents[0].dot(vec.crossVectors(normals[0], normals[segments])) > 0) {
      theta = -theta;
    }

    for (var i = 1; i <= segments; i++) {
      // twist a little...
      normals[i].applyMatrix4(mat.makeRotationAxis(tangents[i], theta * i));
      binormals[i].crossVectors(tangents[i], normals[i]);
    }
  }

  return {"tangents": tangents, "normals": normals, "binormals": binormals};
}