Skip to content

Instantly share code, notes, and snippets.

@yjbanov
Created June 17, 2020 23:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yjbanov/722afbf5950b590972180007c4c7edea to your computer and use it in GitHub Desktop.
Save yjbanov/722afbf5950b590972180007c4c7edea to your computer and use it in GitHub Desktop.
void _buildSegments() {
assert(_segments.isEmpty, '_buildSegments should be called once');
_isClosed = false;
double distance = 0.0;
bool haveSeenMoveTo = false;
final List<PathCommand> commands = subPath.commands;
double currentX = 0.0, currentY = 0.0;
final Function lineToHandler = (double x, double y) {
final double dx = currentX - x;
final double dy = currentY - y;
final double prevDistance = distance;
distance += math.sqrt(dx * dx + dy * dy);
// As we accumulate distance, we have to check that the result of +=
// actually made it larger, since a very small delta might be > 0, but
// still have no effect on distance (if distance >>> delta).
if (distance > prevDistance) {
_segments.add(_PathSegment(
PathCommandTypes.lineTo, distance, [currentX, currentY, x, y]));
}
currentX = x;
currentY = y;
};
_EllipseSegmentResult? ellipseResult;
for (PathCommand command in commands) {
switch (command.type) {
case PathCommandTypes.moveTo:
final MoveTo moveTo = command as MoveTo;
currentX = moveTo.x;
currentY = moveTo.y;
haveSeenMoveTo = true;
break;
case PathCommandTypes.lineTo:
assert(haveSeenMoveTo);
final LineTo lineTo = command as LineTo;
lineToHandler(lineTo.x, lineTo.y);
break;
case PathCommandTypes.bezierCurveTo:
assert(haveSeenMoveTo);
final BezierCurveTo curve = command as BezierCurveTo;
// Compute cubic curve distance.
distance = _computeCubicSegments(
currentX,
currentY,
curve.x1,
curve.y1,
curve.x2,
curve.y2,
curve.x3,
curve.y3,
distance,
0,
_kMaxTValue,
_segments);
break;
case PathCommandTypes.quadraticCurveTo:
assert(haveSeenMoveTo);
final QuadraticCurveTo quadraticCurveTo = command as QuadraticCurveTo;
// Compute quad curve distance.
distance = _computeQuadSegments(
currentX,
currentY,
quadraticCurveTo.x1,
quadraticCurveTo.y1,
quadraticCurveTo.x2,
quadraticCurveTo.y2,
distance,
0,
_kMaxTValue);
break;
case PathCommandTypes.close:
break;
case PathCommandTypes.ellipse:
final Ellipse ellipse = command as Ellipse;
ellipseResult ??= _EllipseSegmentResult();
_computeEllipseSegments(
currentX,
currentY,
distance,
ellipse.x,
ellipse.y,
ellipse.startAngle,
ellipse.endAngle,
ellipse.rotation,
ellipse.radiusX,
ellipse.radiusY,
ellipse.anticlockwise,
ellipseResult,
_segments);
distance = ellipseResult.distance;
currentX = ellipseResult.endPointX;
currentY = ellipseResult.endPointY;
_isClosed = true;
break;
case PathCommandTypes.rRect:
final RRectCommand rrectCommand = command as RRectCommand;
final ui.RRect rrect = rrectCommand.rrect;
RRectMetricsRenderer(moveToCallback: (double x, double y) {
currentX = x;
currentY = y;
_isClosed = true;
haveSeenMoveTo = true;
}, lineToCallback: (double x, double y) {
lineToHandler(x, y);
}, ellipseCallback: (double centerX,
double centerY,
double radiusX,
double radiusY,
double rotation,
double startAngle,
double endAngle,
bool antiClockwise) {
ellipseResult ??= _EllipseSegmentResult();
_computeEllipseSegments(
currentX,
currentY,
distance,
centerX,
centerY,
startAngle,
endAngle,
rotation,
radiusX,
radiusY,
antiClockwise,
ellipseResult!,
_segments);
distance = ellipseResult!.distance;
currentX = ellipseResult!.endPointX;
currentY = ellipseResult!.endPointY;
}).render(rrect);
_isClosed = true;
break;
case PathCommandTypes.rect:
final RectCommand rectCommand = command as RectCommand;
final double x = rectCommand.x;
final double y = rectCommand.y;
final double width = rectCommand.width;
final double height = rectCommand.height;
currentX = x;
currentY = y;
lineToHandler(x + width, y);
lineToHandler(x + width, y + height);
lineToHandler(x, y + height);
lineToHandler(x, y);
_isClosed = true;
break;
default:
throw UnimplementedError('Unknown path command $command');
}
}
if (!_isClosed && forceClosed && _segments.isNotEmpty) {
_PathSegment firstSegment = _segments.first;
lineToHandler(firstSegment.points[0], firstSegment.points[1]);
}
_contourLength = distance;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment