arc method

Path arc()

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