getHitTestRects method
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;
}