sphereHeightfield method

bool sphereHeightfield(
  1. Sphere si,
  2. Heightfield sj,
  3. Vec3 xi,
  4. Vec3 xj,
  5. Quaternion qi,
  6. Quaternion qj,
  7. Body bi,
  8. Body bj, [
  9. Shape? rsi,
  10. Shape? rsj,
  11. bool justTest = false,
])

Implementation

bool sphereHeightfield(
  Sphere si,
  Heightfield sj,
  Vec3 xi,
  Vec3 xj,
  Quaternion qi,
  Quaternion qj,
  Body bi,
  Body bj,
  [
    Shape? rsi,
    Shape? rsj,
    bool justTest = false
]){
  final data = sj.data;
  final radius = si.radius;
  final w = sj.elementSize;
  final worldPillarOffset = _sphereHeightfieldTmp2;

  // Get sphere position to heightfield local!
  final local = _sphereHeightfieldTmp1;
  Transform.pointToLocalFrame(xj, qj, xi, local);

  // Get the index of the data points to test against
  int iMinX = ((local.x - radius) / w).floor() - 1;
  int iMaxX = ((local.x + radius) / w).ceil() + 1;
  int iMinY = ((local.y - radius) / w).floor() - 1;
  int iMaxY = ((local.y + radius) / w).ceil() + 1;
  // Bail out if we are out of the terrain
  if (iMaxX < 0 || iMaxY < 0 || iMinX > data.length || iMinY > data[0].length) {
    return false;
  }

  // Clamp index to edges
  if (iMinX < 0) {
    iMinX = 0;
  }
  if (iMaxX < 0) {
    iMaxX = 0;
  }
  if (iMinY < 0) {
    iMinY = 0;
  }
  if (iMaxY < 0) {
    iMaxY = 0;
  }
  if (iMinX >= data.length) {
    iMinX = data.length - 1;
  }
  if (iMaxX >= data.length) {
    iMaxX = data.length - 1;
  }
  if (iMaxY >= data[0].length) {
    iMaxY = data[0].length - 1;
  }
  if (iMinY >= data[0].length) {
    iMinY = data[0].length - 1;
  }

  List<double> minMax = [];
  sj.getRectMinMax(iMinX, iMinY, iMaxX, iMaxY, minMax);
  final min = minMax[0];
  final max = minMax[1];

  // Bail out if we can't touch the bounding height box
  if (local.z - radius > max || local.z + radius < min) {
    return false;
  }

  final result = this.result;
  for (int i = iMinX; i < iMaxX; i++) {
    for (int j = iMinY; j < iMaxY; j++) {
      final numContactsBefore = result.length;

      bool intersecting = false;

      // Lower triangle
      sj.getConvexTrianglePillar(i, j, false);
      Transform.pointToWorldFrame(xj, qj, sj.pillarOffset, worldPillarOffset);
      if (
        xi.distanceTo(worldPillarOffset) <
        sj.pillarConvex.boundingSphereRadius + si.boundingSphereRadius
      ) {
        intersecting = sphereConvex(
          si,
          sj.pillarConvex,
          xi,
          worldPillarOffset,
          qi,
          qj,
          bi,
          bj,
          si,
          sj,
          justTest
        );
      }

      if (justTest && intersecting) {
        return true;
      }

      // Upper triangle
      sj.getConvexTrianglePillar(i, j, true);
      Transform.pointToWorldFrame(xj, qj, sj.pillarOffset, worldPillarOffset);
      if (
        xi.distanceTo(worldPillarOffset) <
        sj.pillarConvex.boundingSphereRadius + si.boundingSphereRadius
      ) {
        intersecting = sphereConvex(
          si,
          sj.pillarConvex,
          xi,
          worldPillarOffset,
          qi,
          qj,
          bi,
          bj,
          si,
          sj,
          justTest
        );
      }

      if (justTest && intersecting) {
        return true;
      }

      final numContacts = result.length - numContactsBefore;

      if (numContacts > 2) {
        return false;
      }
      /*
        // Skip all but 1
        for (let k = 0; k < numContacts - 1; k++) {
            result.pop();
        }
      */
    }
  }
  return false;
}