getHitTestRects method

  1. @override
List<Rect> getHitTestRects(
  1. Offset start,
  2. double tolerance
)
override

Generates hit test rectangles for this segment.

start is the starting point of this segment. tolerance is the hit test tolerance (half-width of the hit area).

Returns a list of rectangles that cover the segment path.

Implementation

@override
List<Rect> getHitTestRects(Offset start, double tolerance) {
  if (!generateHitTestRects) return [];

  // Maximum perpendicular expansion allowed (same constraint as StraightSegment)
  final maxPerpExpansion = PathSegment.maxHitTestSize(tolerance);

  // Calculate chord from start to end
  final chordDx = end.dx - start.dx;
  final chordDy = end.dy - start.dy;
  final chordLength = math.sqrt(chordDx * chordDx + chordDy * chordDy);

  // Very short curves - single rectangle
  if (chordLength < 0.1) {
    return [
      Rect.fromCenter(
        center: start,
        width: tolerance * 2,
        height: tolerance * 2,
      ),
    ];
  }

  // Calculate AABB for small curve check
  final aabb = _boundingBox(start);

  // For very small curves (both dimensions within perpendicular limit), single rectangle
  if (aabb.width < maxPerpExpansion && aabb.height < maxPerpExpansion) {
    return [aabb.inflate(tolerance)];
  }

  // Calculate maximum perpendicular deviation from chord
  // This tells us how "curved" the path is
  final maxDeviation = _maxDeviationFromChord(
    start,
    chordDx,
    chordDy,
    chordLength,
  );

  // Calculate chord "diagonality" - same approach as StraightSegment
  // minTrigComponent is ~0 for horizontal/vertical, ~0.707 for 45° diagonal
  final cosAngle = chordDx.abs() / chordLength;
  final sinAngle = chordDy.abs() / chordLength;
  final minTrigComponent = math.min(sinAngle, cosAngle);

  // Perpendicular expansion of chord (same formula as StraightSegment)
  // - Horizontal/vertical: ~2*tolerance (minimal)
  // - Diagonal: length * minTrigComponent + 2*tolerance (significant)
  final chordPerpExpansion = chordLength * minTrigComponent + 2 * tolerance;

  // Segment count based on perpendicular expansion constraints:
  // 1. Length-based: ONLY for diagonal curves where perpExpansion exceeds limit
  // 2. Deviation: curves with more bulge need more segments
  // 3. Curvature: higher curvature means sharper curves
  final lengthBasedCount = chordPerpExpansion > maxPerpExpansion
      ? (chordPerpExpansion / maxPerpExpansion).ceil()
      : 1; // Horizontal/vertical curves don't need length-based splitting
  final deviationBasedCount = maxDeviation > 0
      ? math.max(2, (maxDeviation / (maxPerpExpansion / 2)).ceil())
      : 1;
  final curvatureBasedCount = math.max(1, (curvature * 3).ceil());

  final segmentCount = math.max(
    curvatureBasedCount,
    math.max(lengthBasedCount, deviationBasedCount),
  );

  // Generate tight rectangles for each segment (like StraightSegment's diagonal handling)
  final rects = <Rect>[];
  Offset prevPoint = start;

  for (int i = 1; i <= segmentCount; i++) {
    final t = i / segmentCount;
    final point = _evaluate(start, t);

    rects.add(_createTightSegmentRect(prevPoint, point, tolerance));
    prevPoint = point;
  }

  return rects;
}