roundedPath function

Path roundedPath(
  1. List<VertexDefinition> vertices,
  2. double radiusAll
)

Implementation

Path roundedPath(
  List<VertexDefinition> vertices,
  double radiusAll,
) {
  var radius = radiusAll;
  late double cRadius;

  final verticesCount = vertices.length;
  var p1 = vertices[verticesCount - 1];

  final path = Path();
  for (int i = 0; i < verticesCount; i++) {
    var p2 = vertices[i % verticesCount];
    final p3 = vertices[(i + 1) % verticesCount];

    final v1 = p1 - p2;
    final v2 = p3 - p2;
    final sinA = v1.nx * v2.ny - v1.ny * v2.nx;
    final sinA90 = v1.nx * v2.nx - v1.ny * -v2.ny;
    var angle = math.asin(sinA < -1
        ? -1
        : sinA > 1
            ? 1
            : sinA);

    int radDirection = 1;
    bool drawDirection = false;
    if (sinA90 < 0) {
      if (angle < 0) {
        angle = math.pi + angle;
      } else {
        angle = math.pi - angle;
        radDirection = -1;
        drawDirection = true;
      }
    } else {
      if (angle > 0) {
        radDirection = -1;
        drawDirection = true;
      }
    }

    if (p2.radius != null) {
      radius = p2.radius!;
    } else {
      radius = radiusAll;
    }

    final halfAngle = angle / 2;

    var lenOut = (math.cos(halfAngle) * radius / math.sin(halfAngle)).abs();

    if (lenOut > math.min(v1.distance / 2, v2.distance / 2)) {
      lenOut = math.min(v1.distance / 2, v2.distance / 2);
      cRadius = (lenOut * math.sin(halfAngle) / math.cos(halfAngle)).abs();
    } else {
      cRadius = radius;
    }

    var x = p2.x + v2.nx * lenOut;
    var y = p2.y + v2.ny * lenOut;

    x += -v2.ny * cRadius * radDirection;
    y += v2.nx * cRadius * radDirection;

    final startAngle = v1.direction + math.pi / 2 * radDirection;
    final endAngle = v2.direction - math.pi / 2 * radDirection;

    double toSweepAngle(double startAngle, double endAngle) {
      const circle = math.pi * 2;
      const halfCircle = math.pi;

      final sweepAngle = endAngle - startAngle;

      if (drawDirection && sweepAngle > halfCircle) {
        return sweepAngle - circle;
      } else if (!drawDirection && sweepAngle < halfCircle) {
        return sweepAngle + circle;
      } else {
        return sweepAngle;
      }
    }

    path.arcTo(
      Rect.fromCircle(center: Offset(x, y), radius: cRadius),
      startAngle,
      toSweepAngle(startAngle, endAngle),
      false,
    );

    p1 = p2;
    p2 = p3;
  }

  return path;
}