segmentsIntersect function

bool segmentsIntersect(
  1. Offset a1,
  2. Offset a2,
  3. Offset b1,
  4. Offset b2,
)

Returns true if segments a1-a2 and b1-b2 intersect.

Implementation

bool segmentsIntersect(Offset a1, Offset a2, Offset b1, Offset b2) {
  // Shift to a local frame around a1 to reduce cancellation for very large
  // absolute coordinates. Epsilon uses local geometry scale and a clamped
  // precision factor derived from absolute magnitude.
  final p1 = Offset.zero;
  final p2 = a2 - a1;
  final p3 = b1 - a1;
  final p4 = b2 - a1;
  if (!p2.dx.isFinite ||
      !p2.dy.isFinite ||
      !p3.dx.isFinite ||
      !p3.dy.isFinite ||
      !p4.dx.isFinite ||
      !p4.dy.isFinite) {
    return false;
  }

  var localScale = 1.0;
  var absoluteScale = 1.0;

  void considerLocal(Offset p) {
    final dx = p.dx.abs();
    final dy = p.dy.abs();
    if (dx > localScale) localScale = dx;
    if (dy > localScale) localScale = dy;
  }

  void considerAbsolute(Offset p) {
    final dx = p.dx.abs();
    final dy = p.dy.abs();
    if (dx > absoluteScale) absoluteScale = dx;
    if (dy > absoluteScale) absoluteScale = dy;
  }

  considerLocal(p2);
  considerLocal(p3);
  considerLocal(p4);
  considerAbsolute(a1);
  considerAbsolute(a2);
  considerAbsolute(b1);
  considerAbsolute(b2);

  final localScaleSafe = localScale < 1.0 ? 1.0 : localScale;
  final precisionFactorRaw = absoluteScale / localScaleSafe;
  final precisionFactor = precisionFactorRaw.isFinite
      ? precisionFactorRaw.clamp(1.0, 1e6).toDouble()
      : 1e6;
  final orientationEpsilon =
      kEpsilon * localScaleSafe * localScaleSafe * precisionFactor;
  final coordinateEpsilon = kEpsilon * localScaleSafe * precisionFactor;

  int orientationEps(Offset p, Offset q, Offset r) {
    final val = (q.dy - p.dy) * (r.dx - q.dx) - (q.dx - p.dx) * (r.dy - q.dy);
    if (!val.isFinite) return 0;
    if (val.abs() <= orientationEpsilon) return 0;
    return val > 0 ? 1 : 2;
  }

  bool onSegmentEps(Offset p, Offset q, Offset r) {
    return q.dx <= math.max(p.dx, r.dx) + coordinateEpsilon &&
        q.dx >= math.min(p.dx, r.dx) - coordinateEpsilon &&
        q.dy <= math.max(p.dy, r.dy) + coordinateEpsilon &&
        q.dy >= math.min(p.dy, r.dy) - coordinateEpsilon;
  }

  final o1 = orientationEps(p1, p2, p3);
  final o2 = orientationEps(p1, p2, p4);
  final o3 = orientationEps(p3, p4, p1);
  final o4 = orientationEps(p3, p4, p2);

  if (o1 != o2 && o3 != o4) return true;

  if (o1 == 0 && onSegmentEps(p1, p3, p2)) return true;
  if (o2 == 0 && onSegmentEps(p1, p4, p2)) return true;
  if (o3 == 0 && onSegmentEps(p3, p1, p4)) return true;
  if (o4 == 0 && onSegmentEps(p3, p2, p4)) return true;

  return false;
}