TorusKnotGeometryWireframeFriendly function

GeometryBuilder TorusKnotGeometryWireframeFriendly({
  1. double radius = 20.0,
  2. double tubeRadius = 4.0,
  3. int segmentsR = 128,
  4. int segmentsT = 16,
  5. int p = 2,
  6. int q = 3,
  7. double heightScale = 1.0,
  8. bool computeUVs = true,
  9. bool computeNormals = true,
  10. bool inside = false,
})

Like TorusKnotGeometry but with duplicate Vertices to make it possible to add aCenter attributes with GenerateWireframeCenters()

Implementation

GeometryBuilder TorusKnotGeometryWireframeFriendly(
    {double radius = 20.0,
    double tubeRadius = 4.0,
    int segmentsR = 128,
    int segmentsT = 16,
    int p = 2,
    int q = 3,
    double heightScale = 1.0,
    bool computeUVs = true,
    bool computeNormals = true,
    bool inside = false}) {
  void curveFunc(double u, VM.Vector3 out) {
    TorusKnotGetPos(u, q, p, radius, heightScale, out);
  }

  final List<VM.Vector3> pointsAndTangents = ParametricCurvePointsAndTangents(
      curveFunc, 0.0, 2.0 * Math.pi, segmentsR,
      halfOpen: true);
  pointsAndTangents.add(pointsAndTangents[0]);
  pointsAndTangents.add(pointsAndTangents[1]);
  final int h = segmentsR + 1;
  assert(pointsAndTangents.length == 2 * h);
  final List<List<VM.Vector3>> bands =
      TubeHullBands(pointsAndTangents, segmentsT, tubeRadius);
  for (List<VM.Vector3> b in bands) {
    b.add(b[0]);
    b.add(b[1]);
  }
  assert(bands.length == h);

  final GeometryBuilder gb = GeometryBuilder();

  for (int i = 0; i < segmentsR; ++i) {
    for (int j = 0; j < segmentsT; ++j) {
      final int ip = i + 1;
      final int jp = j + 1;
      gb.AddFaces4(1, inside);
      gb.AddVerticesTakeOwnership([
        bands[i][jp * 2],
        bands[ip][jp * 2],
        bands[ip][j * 2],
        bands[i][j * 2]
      ]);
    }
  }

  if (computeUVs) {
    gb..EnableAttribute(aTexUV);
    for (int i = segmentsR - 1; i >= 0; --i) {
      for (int j = 0; j < segmentsT; ++j) {
        final int ip = i + 1;
        final int jp = j + 1;
        gb.AddAttributesVector2TakeOwnership(aTexUV, [
          VM.Vector2(i / segmentsR, jp / segmentsT),
          VM.Vector2(ip / segmentsR, jp / segmentsT),
          VM.Vector2(ip / segmentsR, j / segmentsT),
          VM.Vector2(i / segmentsR, j / segmentsT)
        ]);
      }
    }
  }

  if (computeNormals) gb.GenerateNormalsAssumingTriangleMode();
  return gb;
}