calculateBounds method

void calculateBounds(
  1. List<double> bounds, {
  2. bool approximate = false,
})

Returns the true bounds of this curve, filling bounds with the axis-aligned bounding box values for left, top, right, and bottom, in that order.

Implementation

void calculateBounds(List<double> bounds, {bool approximate = false}) {
  assert(bounds.length == 4, 'Bounds array size should be 4.');

  // A curve might be of zero-length, with both anchors co-lated.
  // Just return the point itself.
  if (zeroLength()) {
    bounds[0] = anchor0X;
    bounds[1] = anchor0Y;
    bounds[2] = anchor0X;
    bounds[3] = anchor0Y;
    return;
  }

  var minX = math.min(anchor0X, anchor1X);
  var minY = math.min(anchor0Y, anchor1Y);
  var maxX = math.max(anchor0X, anchor1X);
  var maxY = math.max(anchor0Y, anchor1Y);

  if (approximate) {
    // Approximate bounds use the bounding box of all anchors and
    // controls.
    bounds[0] = math.min(minX, math.min(control0X, control1X));
    bounds[1] = math.min(minY, math.min(control0Y, control1Y));
    bounds[2] = math.max(maxX, math.max(control0X, control1X));
    bounds[3] = math.max(maxY, math.max(control0Y, control1Y));
    return;
  }

  // Find the derivative, which is a quadratic Bezier. Then we can solve
  // for t using the quadratic formula.
  final xa = -anchor0X + 3 * control0X - 3 * control1X + anchor1X;
  final xb = 2 * anchor0X - 4 * control0X + 2 * control1X;
  final xc = -anchor0X + control0X;

  if (_zeroIsh(xa)) {
    // Try Muller's method instead; it can find a single root when a is 0.
    if (xb != 0) {
      final t = 2 * xc / (-2 * xb);
      if (t >= 0 && t <= 1) {
        final x = pointOnCurve(t).x;
        if (x < minX) minX = x;
        if (x > maxX) maxX = x;
      }
    }
  } else {
    final xs = xb * xb - 4 * xa * xc;
    if (xs >= 0) {
      final t1 = (-xb + math.sqrt(xs)) / (2 * xa);
      if (t1 >= 0 && t1 <= 1) {
        final x = pointOnCurve(t1).x;
        if (x < minX) minX = x;
        if (x > maxX) maxX = x;
      }

      final t2 = (-xb - math.sqrt(xs)) / (2 * xa);
      if (t2 >= 0 && t2 <= 1) {
        final x = pointOnCurve(t2).x;
        if (x < minX) minX = x;
        if (x > maxX) maxX = x;
      }
    }
  }

  // Repeat the above for y coordinate
  final ya = -anchor0Y + 3 * control0Y - 3 * control1Y + anchor1Y;
  final yb = 2 * anchor0Y - 4 * control0Y + 2 * control1Y;
  final yc = -anchor0Y + control0Y;

  if (_zeroIsh(ya)) {
    if (yb != 0) {
      final t = 2 * yc / (-2 * yb);
      if (t >= 0 && t <= 1) {
        final y = pointOnCurve(t).y;
        if (y < minY) minY = y;
        if (y > maxY) maxY = y;
      }
    }
  } else {
    final ys = yb * yb - 4 * ya * yc;
    if (ys >= 0) {
      final t1 = (-yb + math.sqrt(ys)) / (2 * ya);
      if (t1 >= 0 && t1 <= 1) {
        final y = pointOnCurve(t1).y;
        if (y < minY) minY = y;
        if (y > maxY) maxY = y;
      }

      final t2 = (-yb - math.sqrt(ys)) / (2 * ya);
      if (t2 >= 0 && t2 <= 1) {
        final y = pointOnCurve(t2).y;
        if (y < minY) minY = y;
        if (y > maxY) maxY = y;
      }
    }
  }

  bounds[0] = minX;
  bounds[1] = minY;
  bounds[2] = maxX;
  bounds[3] = maxY;
}