Implementation
Path arc() {
double ir = innerRadius.toDouble();
double or = outRadius.toDouble();
double corner = min(cornerRadius, (or - ir) / 2).toDouble();
num swa = sweepAngle;
num sa = startAngle;
double direction = sweepAngle > 0 ? 1 : -1;
///修正相关的角度
if (swa.abs() > 360) {
swa %= 360;
}
if (swa.abs() == 0 && sweepAngle.abs() > 0) {
swa = 360 * direction;
}
num innerEndAngle = sa + swa;
num outerEndAngle = innerEndAngle;
bool largeArc = swa.abs() >= 180;
bool hasCorner = corner > 0.001;
bool circle = ir <= 0.001;
Path path = Path();
if (circle) {
path.moveTo(center.dx, center.dy);
if (!hasCorner) {
Offset o1 = circlePoint(or, sa, center);
Offset o2 = circlePoint(or, outerEndAngle, center);
path.lineTo(o1.dx, o1.dy);
path.arcToPoint(o2, radius: Radius.circular(or), largeArc: largeArc, clockwise: swa > 0);
} else {
if (swa > 0) {
List<Offset> offsetList = _computeLT(or, corner, sa);
Offset p1 = offsetList[0];
Offset p2 = offsetList[1];
path.lineTo(p1.dx, p1.dy);
path.arcToPoint(p2, radius: Radius.circular(corner.toDouble()), largeArc: false, clockwise: true);
offsetList = _computeRT(or, corner, outerEndAngle);
p1 = offsetList[0];
p2 = offsetList[1];
path.arcToPoint(p1, radius: Radius.circular(or), largeArc: largeArc, clockwise: true);
path.arcToPoint(p2, radius: Radius.circular(corner.toDouble()), largeArc: false, clockwise: true);
} else {
List<Offset> offsetList = _computeRT(or, corner, sa);
Offset p1 = offsetList[0];
Offset p2 = offsetList[1];
path.lineTo(p2.dx, p2.dy);
path.arcToPoint(p1, radius: Radius.circular(corner), largeArc: false, clockwise: false);
offsetList = _computeLT(or, corner, outerEndAngle);
p1 = offsetList[0];
p2 = offsetList[1];
path.arcToPoint(p2, radius: Radius.circular(or), largeArc: largeArc, clockwise: false);
path.arcToPoint(p1, radius: Radius.circular(corner), largeArc: false, clockwise: false);
}
}
path.close();
return path;
}
///修正存在angleGap时视觉上间隔不一致问题(只有为圆弧时才有效)
if (padAngle > 0) {
///计算对应弧长
double innerDiff = padAngle * Constants.angleUnit * ir;
double outerDiff = padAngle * Constants.angleUnit * or;
double outerAngleOffset = ((outerDiff - innerDiff) / (2 * pi * or)) * 360;
if (swa < 0) {
outerEndAngle -= outerAngleOffset;
} else {
outerEndAngle += outerAngleOffset;
}
}
if ((outerEndAngle - sa).abs() >= 360) {
Path p1 = Path();
Offset o1 = circlePoint(or, sa, center);
Offset o2 = circlePoint(or, sa + 360 * direction, center);
p1.moveTo(o1.dx, o1.dy);
p1.arcToPoint(o2, radius: Radius.circular(or), largeArc: true, clockwise: direction == 1);
p1.close();
Path p2 = Path();
o1 = circlePoint(ir, sa, center);
o2 = circlePoint(ir, sa + 360 * direction, center);
p2.lineTo(o2.dx, o2.dy);
p2.arcToPoint(o1, radius: Radius.circular(ir), largeArc: true, clockwise: direction != 1);
p2.close();
path = Path.combine(PathOperation.difference, p1, p2);
return path;
}
///圆弧
if (!hasCorner) {
bool clockwise = swa > 0;
clockwise = outerEndAngle - sa > 0;
Offset o1 = circlePoint(or, sa, center);
Offset o2 = circlePoint(or, outerEndAngle, center);
path.moveTo(o1.dx, o1.dy);
path.arcToPoint(o2, radius: Radius.circular(or), largeArc: largeArc, clockwise: clockwise);
o1 = circlePoint(ir, sa, center);
o2 = circlePoint(ir, innerEndAngle, center);
path.lineTo(o2.dx, o2.dy);
path.arcToPoint(o1, radius: Radius.circular(ir), largeArc: largeArc, clockwise: !clockwise);
} else {
if (swa > 0) {
///leftTop
List<Offset> offsetList = _computeLT(or, corner, sa);
Offset p1 = offsetList[0];
Offset p2 = offsetList[1];
path.moveTo(p1.dx, p1.dy);
path.arcToPoint(p2, radius: Radius.circular(corner.toDouble()), largeArc: false, clockwise: true);
///rightTop
offsetList = _computeRT(or, corner, outerEndAngle);
p1 = offsetList[0];
p2 = offsetList[1];
path.arcToPoint(p1, radius: Radius.circular(or), largeArc: largeArc, clockwise: true);
path.arcToPoint(p2, radius: Radius.circular(corner.toDouble()), largeArc: false, clockwise: true);
///rightBottom
offsetList = _computeRB(ir, corner, innerEndAngle);
p1 = offsetList[0];
p2 = offsetList[1];
path.lineTo(p1.dx, p1.dy);
path.arcToPoint(p2, radius: Radius.circular(corner.toDouble()), largeArc: false, clockwise: true);
///leftBottom
offsetList = _computeLB(ir, corner, sa);
p1 = offsetList[0];
p2 = offsetList[1];
path.arcToPoint(p1, radius: Radius.circular(ir), largeArc: largeArc, clockwise: false);
path.arcToPoint(p2, radius: Radius.circular(corner.toDouble()), largeArc: false, clockwise: true);
} else {
///rightTop
List<Offset> offsetList = _computeRT(or, corner, sa);
Offset p1 = offsetList[0];
Offset p2 = offsetList[1];
path.moveTo(p2.dx, p2.dy);
path.arcToPoint(p1, radius: Radius.circular(corner), largeArc: false, clockwise: false);
///leftTop
offsetList = _computeLT(or, corner, outerEndAngle);
p1 = offsetList[0];
p2 = offsetList[1];
path.arcToPoint(p2, radius: Radius.circular(or), largeArc: largeArc, clockwise: false);
path.arcToPoint(p1, radius: Radius.circular(corner), largeArc: false, clockwise: false);
///leftBottom
offsetList = _computeLB(ir, corner, innerEndAngle);
p1 = offsetList[0];
p2 = offsetList[1];
path.lineTo(p2.dx, p2.dy);
path.arcToPoint(p1, radius: Radius.circular(corner), largeArc: false, clockwise: false);
///rightBottom
offsetList = _computeRB(ir, corner, sa);
p1 = offsetList[0];
p2 = offsetList[1];
path.arcToPoint(p2, radius: Radius.circular(ir), largeArc: largeArc, clockwise: true);
path.arcToPoint(p1, radius: Radius.circular(corner), largeArc: false, clockwise: false);
}
}
path.close();
return path;
}