sharpAgainstSmooth function

EditMesh sharpAgainstSmooth()

Two cylinders side by side, the left one with its wall marked sharp and the right one left smooth.

The one fixture whose whole point is a flag. Both halves have the same vertices, the same faces and the same volume; what differs is where the shading breaks. Sixteen sides puts each facet 22.5° from the next — inside the thirty degrees a smoothing threshold allows — so the angle alone would round both of them off, and only the flag makes one read as sixteen flat panels. Marking the rims instead would have shown nothing: a right angle between a cap and a wall breaks at any threshold anybody would set.

Implementation

EditMesh sharpAgainstSmooth() {
  final mesh = const ParametricCylinder(
    radiusTop: 0.5,
    radiusBottom: 0.5,
    height: 1.1,
    segments: 16,
  ).toEditMesh();

  final original = _allFaces(mesh);
  mesh.beginStep();
  final copy = duplicateSelection(mesh, original);
  translateSelection(mesh, copy.selection, by: Vector3(0.75, 0, 0));
  // The original goes the other way, so the pair straddles the origin and the
  // camera frames both.
  translateSelection(mesh, original, by: Vector3(-0.75, 0, 0));

  for (final face in original.ids) {
    mesh.forEachHalfEdge(face, (int half) {
      final from = mesh.positionOf(mesh.originOf(half));
      final to = mesh.positionOf(mesh.originOf(mesh.nextOf(half)));
      // The uprights of the wall, which is where the two halves part company.
      if ((from.y - to.y).abs() > 0.5) {
        mesh.setEdgeFlag(half, EdgeFlags.sharp, on: true);
      }
    });
  }
  for (final face in copy.selection.ids) {
    mesh.forEachHalfEdge(face, (int half) {
      mesh.setEdgeFlag(half, EdgeFlags.sharp, on: false);
    });
  }
  mesh
    ..endStep()
    ..clearJournal();
  return mesh;
}