intersectsWithTriangle method

bool intersectsWithTriangle(
  1. Triangle other,
  2. {double epsilon = 1e-3,
  3. IntersectionResult? result}
)

Return if this intersects with other. epsilon allows the caller to specify a custum eplsilon value that should be used for the test. If result is specified and an intersection is found, result is modified to contain more details about the type of intersection.

Implementation

bool intersectsWithTriangle(Triangle other,
    {double epsilon = 1e-3, IntersectionResult? result}) {
  double p0, p1, p2, r, len;
  double a;

  // This line isn't required if we are using center and half extents to
  // define a aabb
  copyCenterAndHalfExtents(_aabbCenter, _aabbHalfExtents);

  // Translate triangle as conceptually moving AABB to origin
  _v0
    ..setFrom(other.point0)
    ..sub(_aabbCenter);
  _v1
    ..setFrom(other.point1)
    ..sub(_aabbCenter);
  _v2
    ..setFrom(other.point2)
    ..sub(_aabbCenter);

  // Translate triangle as conceptually moving AABB to origin
  _f0
    ..setFrom(_v1)
    ..sub(_v0);
  _f1
    ..setFrom(_v2)
    ..sub(_v1);
  _f2
    ..setFrom(_v0)
    ..sub(_v2);

  // Test axes a00..a22 (category 3)
  // Test axis a00
  len = _f0.y * _f0.y + _f0.z * _f0.z;
  if (len > epsilon) {
    // Ignore tests on degenerate axes.
    p0 = _v0.z * _f0.y - _v0.y * _f0.z;
    p2 = _v2.z * _f0.y - _v2.y * _f0.z;
    r = _aabbHalfExtents[1] * _f0.z.abs() + _aabbHalfExtents[2] * _f0.y.abs();
    if (math.max(-math.max(p0, p2), math.min(p0, p2)) > r + epsilon) {
      return false; // Axis is a separating axis
    }

    a = math.min(p0, p2) - r;
    if (result != null && (result._depth == null || (result._depth!) < a)) {
      result._depth = a;
      _u0.crossInto(_f0, result.axis);
    }
  }

  // Test axis a01
  len = _f1.y * _f1.y + _f1.z * _f1.z;
  if (len > epsilon) {
    // Ignore tests on degenerate axes.
    p0 = _v0.z * _f1.y - _v0.y * _f1.z;
    p1 = _v1.z * _f1.y - _v1.y * _f1.z;
    r = _aabbHalfExtents[1] * _f1.z.abs() + _aabbHalfExtents[2] * _f1.y.abs();
    if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
      return false; // Axis is a separating axis
    }

    a = math.min(p0, p1) - r;
    if (result != null && (result._depth == null || (result._depth!) < a)) {
      result._depth = a;
      _u0.crossInto(_f1, result.axis);
    }
  }

  // Test axis a02
  len = _f2.y * _f2.y + _f2.z * _f2.z;
  if (len > epsilon) {
    // Ignore tests on degenerate axes.
    p0 = _v0.z * _f2.y - _v0.y * _f2.z;
    p1 = _v1.z * _f2.y - _v1.y * _f2.z;
    r = _aabbHalfExtents[1] * _f2.z.abs() + _aabbHalfExtents[2] * _f2.y.abs();
    if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
      return false; // Axis is a separating axis
    }

    a = math.min(p0, p1) - r;
    if (result != null && (result._depth == null || (result._depth!) < a)) {
      result._depth = a;
      _u0.crossInto(_f2, result.axis);
    }
  }

  // Test axis a10
  len = _f0.x * _f0.x + _f0.z * _f0.z;
  if (len > epsilon) {
    // Ignore tests on degenerate axes.
    p0 = _v0.x * _f0.z - _v0.z * _f0.x;
    p2 = _v2.x * _f0.z - _v2.z * _f0.x;
    r = _aabbHalfExtents[0] * _f0.z.abs() + _aabbHalfExtents[2] * _f0.x.abs();
    if (math.max(-math.max(p0, p2), math.min(p0, p2)) > r + epsilon) {
      return false; // Axis is a separating axis
    }

    a = math.min(p0, p2) - r;
    if (result != null && (result._depth == null || (result._depth!) < a)) {
      result._depth = a;
      _u1.crossInto(_f0, result.axis);
    }
  }

  // Test axis a11
  len = _f1.x * _f1.x + _f1.z * _f1.z;
  if (len > epsilon) {
    // Ignore tests on degenerate axes.
    p0 = _v0.x * _f1.z - _v0.z * _f1.x;
    p1 = _v1.x * _f1.z - _v1.z * _f1.x;
    r = _aabbHalfExtents[0] * _f1.z.abs() + _aabbHalfExtents[2] * _f1.x.abs();
    if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
      return false; // Axis is a separating axis
    }

    a = math.min(p0, p1) - r;
    if (result != null && (result._depth == null || (result._depth!) < a)) {
      result._depth = a;
      _u1.crossInto(_f1, result.axis);
    }
  }

  // Test axis a12
  len = _f2.x * _f2.x + _f2.z * _f2.z;
  if (len > epsilon) {
    // Ignore tests on degenerate axes.
    p0 = _v0.x * _f2.z - _v0.z * _f2.x;
    p1 = _v1.x * _f2.z - _v1.z * _f2.x;
    r = _aabbHalfExtents[0] * _f2.z.abs() + _aabbHalfExtents[2] * _f2.x.abs();
    if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
      return false; // Axis is a separating axis
    }

    a = math.min(p0, p1) - r;
    if (result != null && (result._depth == null || (result._depth!) < a)) {
      result._depth = a;
      _u1.crossInto(_f2, result.axis);
    }
  }

  // Test axis a20
  len = _f0.x * _f0.x + _f0.y * _f0.y;
  if (len > epsilon) {
    // Ignore tests on degenerate axes.
    p0 = _v0.y * _f0.x - _v0.x * _f0.y;
    p2 = _v2.y * _f0.x - _v2.x * _f0.y;
    r = _aabbHalfExtents[0] * _f0.y.abs() + _aabbHalfExtents[1] * _f0.x.abs();
    if (math.max(-math.max(p0, p2), math.min(p0, p2)) > r + epsilon) {
      return false; // Axis is a separating axis
    }

    a = math.min(p0, p2) - r;
    if (result != null && (result._depth == null || (result._depth!) < a)) {
      result._depth = a;
      _u2.crossInto(_f0, result.axis);
    }
  }

  // Test axis a21
  len = _f1.x * _f1.x + _f1.y * _f1.y;
  if (len > epsilon) {
    // Ignore tests on degenerate axes.
    p0 = _v0.y * _f1.x - _v0.x * _f1.y;
    p1 = _v1.y * _f1.x - _v1.x * _f1.y;
    r = _aabbHalfExtents[0] * _f1.y.abs() + _aabbHalfExtents[1] * _f1.x.abs();
    if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
      return false; // Axis is a separating axis
    }

    a = math.min(p0, p1) - r;
    if (result != null && (result._depth == null || (result._depth!) < a)) {
      result._depth = a;
      _u2.crossInto(_f1, result.axis);
    }
  }

  // Test axis a22
  len = _f2.x * _f2.x + _f2.y * _f2.y;
  if (len > epsilon) {
    // Ignore tests on degenerate axes.
    p0 = _v0.y * _f2.x - _v0.x * _f2.y;
    p1 = _v1.y * _f2.x - _v1.x * _f2.y;
    r = _aabbHalfExtents[0] * _f2.y.abs() + _aabbHalfExtents[1] * _f2.x.abs();
    if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
      return false; // Axis is a separating axis
    }

    a = math.min(p0, p1) - r;
    if (result != null && (result._depth == null || (result._depth!) < a)) {
      result._depth = a;
      _u2.crossInto(_f2, result.axis);
    }
  }

  // Test the three axes corresponding to the face normals of AABB b (category 1). // Exit if...
  // ... [-e0, e0] and [min(v0.x,v1.x,v2.x), max(v0.x,v1.x,v2.x)] do not overlap
  if (math.max(_v0.x, math.max(_v1.x, _v2.x)) < -_aabbHalfExtents[0] ||
      math.min(_v0.x, math.min(_v1.x, _v2.x)) > _aabbHalfExtents[0]) {
    return false;
  }
  a = math.min(_v0.x, math.min(_v1.x, _v2.x)) - _aabbHalfExtents[0];
  if (result != null && (result._depth == null || (result._depth!) < a)) {
    result._depth = a;
    result.axis.setFrom(_u0);
  }
  // ... [-e1, e1] and [min(v0.y,v1.y,v2.y), max(v0.y,v1.y,v2.y)] do not overlap
  if (math.max(_v0.y, math.max(_v1.y, _v2.y)) < -_aabbHalfExtents[1] ||
      math.min(_v0.y, math.min(_v1.y, _v2.y)) > _aabbHalfExtents[1]) {
    return false;
  }
  a = math.min(_v0.y, math.min(_v1.y, _v2.y)) - _aabbHalfExtents[1];
  if (result != null && (result._depth == null || (result._depth!) < a)) {
    result._depth = a;
    result.axis.setFrom(_u1);
  }
  // ... [-e2, e2] and [min(v0.z,v1.z,v2.z), max(v0.z,v1.z,v2.z)] do not overlap
  if (math.max(_v0.z, math.max(_v1.z, _v2.z)) < -_aabbHalfExtents[2] ||
      math.min(_v0.z, math.min(_v1.z, _v2.z)) > _aabbHalfExtents[2]) {
    return false;
  }
  a = math.min(_v0.z, math.min(_v1.z, _v2.z)) - _aabbHalfExtents[2];
  if (result != null && (result._depth == null || (result._depth!) < a)) {
    result._depth = a;
    result.axis.setFrom(_u2);
  }

  // It seems like that wee need to move the edges before creating the
  // plane
  _v0.add(_aabbCenter);

  // Test separating axis corresponding to triangle face normal (category 2)
  _f0.crossInto(_f1, _trianglePlane.normal);
  _trianglePlane.constant = _trianglePlane.normal.dot(_v0);
  return intersectsWithPlane(_trianglePlane, result: result);
}