getSmoothHandlePoints function

Tuple2<List<Vector3>, List<Vector3>> getSmoothHandlePoints(
  1. List<Vector3> points
)

Implementation

Tuple2<List<Vector3>, List<Vector3>> getSmoothHandlePoints(
    List<Vector3> points) {
  var numHandles = points.length - 1;

  if (numHandles < 1) {
    return Tuple2([ORIGIN], [ORIGIN]);
  }

  var l = 2;
  var u = 1;

  var diag = Array.zeros(shape: Tuple2(l + u + 1, 2 * numHandles));

  void setVal(double value, int col, {int start = 0, int? end, int step = 1}) {
    end ??= 2 * numHandles;

    for (var i in range(start: start, end: end, step: step)) {
      diag.setValue(Tuple2(col, i), value);
    }
  }

  setVal(-1, 0, start: 1, step: 2);
  setVal(1, 0, start: 2, step: 2);
  setVal(2, 1, start: 0, step: 2);
  setVal(1, 1, start: 1, step: 2);
  setVal(-2, 2, start: 1, end: 2 * numHandles - 2, step: 2);
  setVal(1, 3, start: 0, end: 2 * numHandles - 3, step: 2);
  diag.setValue(Tuple2(2, -2), -1);
  diag.setValue(Tuple2(1, -1), 2);

  var b = Array.zeros(shape: Tuple2(2 * numHandles, 3));
  var pointsWithoutFirst = withoutFirst(points);

  //* equivalent to b[1::2] = 2 * points[1:]
  for (var ij in enumerate((range(start: 1, end: 2 * numHandles, step: 2)))) {
    for (var k in range(end: 3)) {
      b.setValue(Tuple2(ij.item2, k),
          2 * pointsWithoutFirst[ij.item1].getComponent(k));
    }
  }

  //* equivalent to  b[0] = points[0]
  for (var k in range(end: 3)) {
    b.setValue(Tuple2(0, k), points.first.getComponent(k));
  }

  //* equivalent to  b[-1] = points[-1]

  for (var k in range(end: 3)) {
    b.setValue(Tuple2(2 * numHandles - 1, k), points.last.getComponent(k));
  }

  // TODO solve banded matrix instead of using getInverse
  var useClosedSolveFunction = isClosed(points);
  var handlePairs = Array.zeros(shape: Tuple2(2 * numHandles, 3));

  if (useClosedSolveFunction) {
    var matrix = diagToMatrix(Tuple2(l, u), diag);
    for (var i in IterableZip([
      [0, 1, -2, -1],
      [2, -1, 1, -2]
    ])) {
      var k = -1 % matrix.shape.item1;
      var j = i[0] % matrix.shape.item2;
      matrix.setValue(Tuple2(k, j), i[1].toDouble());
    }

    matrix.values = [
      [
        for (var i in range(end: matrix.shape.item2))
          if (i == 0 || i == matrix.shape.item2 - 1) 1 else 0
      ],
      ...withoutFirst(matrix.values)
    ];

    b.values.first = (points[0] * 2.0).toList();
    b.values.last = ORIGIN.toList();

    for (var i in range(end: 3)) {
      handlePairs.setColumn(i, matrix.getInverse().matMul(b).flat());
    }
  } else {
    for (var i in range(end: 3)) {
      handlePairs.setColumn(i, diag.getInverse().matMul(b).flat());
    }
  }

  var handlePairsVectors = [
    for (var line in handlePairs.getValues()) Vector3(line[0], line[1], line[2])
  ];

  var even = handlePairsVectors.whereIndexed((i, e) => i % 2 == 0).toList();
  var odd = handlePairsVectors.whereIndexed((i, e) => i % 2 == 1).toList();

  return Tuple2(even, odd);
}