solidPart static method

Shape3D? solidPart(
  1. SolidPart part,
  2. double sx,
  3. double sy,
  4. double sz,
)

part scaled by (sx, sy, sz) as a physics-engine shape, placed where it is; null for a hull of too few points.

Implementation

static Shape3D? solidPart(SolidPart part, double sx, double sy, double sz) {
  final ax = sx.abs(), ay = sy.abs(), az = sz.abs();
  Shape3D at(Shape3D shape, double x, double y, double z) =>
      x == 0 && y == 0 && z == 0
      ? shape
      : TransformedShape3D(shape, x: x * sx, y: y * sy, z: z * sz);
  switch (part) {
    case SolidBox(
      :final halfX,
      :final halfY,
      :final halfZ,
      :final x,
      :final y,
      :final z,
    ):
      return at(
        BoxShape3D(
          math.max(halfX * ax, minExtent),
          math.max(halfY * ay, minExtent),
          math.max(halfZ * az, minExtent),
        ),
        x,
        y,
        z,
      );
    case SolidSphere(:final radius, :final x, :final y, :final z):
      return at(
        SphereShape3D(
          math.max(radius * math.max(ax, math.max(ay, az)), minExtent),
        ),
        x,
        y,
        z,
      );
    case SolidCapsule(
      :final halfHeight,
      :final radius,
      :final x,
      :final y,
      :final z,
    ):
      final r = math.max(radius * math.max(ax, az), minExtent);
      final half = (halfHeight + radius) * ay - r;
      return at(
        half <= 1e-4 ? SphereShape3D(r) : CapsuleShape3D(half, r),
        x,
        y,
        z,
      );
    case SolidCylinder(
      :final halfHeight,
      :final radius,
      :final x,
      :final y,
      :final z,
    ):
      return at(
        CylinderShape3D(
          math.max(halfHeight * ay, minExtent),
          math.max(radius * math.max(ax, az), minExtent),
        ),
        x,
        y,
        z,
      );
    case SolidHull(:final points):
      if (points.length < 12) return null;
      final scaled = Float32List(points.length);
      for (var i = 0; i < points.length; i += 3) {
        scaled[i] = points[i] * sx;
        scaled[i + 1] = points[i + 1] * sy;
        scaled[i + 2] = points[i + 2] * sz;
      }
      return ConvexHullShape3D(scaled);
    case SolidMesh(:final positions, :final indices):
      if (indices.length < 3) return null;
      final scaled = Float32List(positions.length);
      for (var i = 0; i < positions.length; i += 3) {
        scaled[i] = positions[i] * sx;
        scaled[i + 1] = positions[i + 1] * sy;
        scaled[i + 2] = positions[i + 2] * sz;
      }
      var turned = indices;
      // A mirror turns triangles inside out; turn them back.
      if (sx * sy * sz < 0) {
        turned = Uint32List.fromList(indices);
        for (var i = 0; i + 2 < turned.length; i += 3) {
          final t = turned[i + 1];
          turned[i + 1] = turned[i + 2];
          turned[i + 2] = t;
        }
      }
      return MeshShape3D(scaled, turned);
    case SolidHeightField(
      :final heights,
      :final sampleCount,
      :final cellSize,
      :final x,
      :final y,
      :final z,
    ):
      if (sampleCount < 4 || heights.length < sampleCount * sampleCount) {
        return null;
      }
      final scaled = Float32List(sampleCount * sampleCount);
      for (var i = 0; i < scaled.length; i++) {
        final h = heights[i];
        scaled[i] = h >= SolidHeightField.holeHeight ? h : h * ay;
      }
      return at(
        HeightFieldShape3D(scaled, sampleCount, cellSize * ax),
        x,
        y,
        z,
      );
  }
}