moveCorner method

Rect moveCorner({
  1. required Offset delta,
  2. required Corner corner,
  3. required Size shortest,
  4. required Size? longest,
  5. required double? largest,
  6. required Rect boundaries,
  7. required double? aspectRatio,
})

Implementation

Rect moveCorner({
  required Offset delta,
  required Corner corner,
  required Size shortest,
  required Size? longest,
  required double? largest,
  required Rect boundaries,
  required double? aspectRatio,
}) {
  double l = left, t = top, r = right, b = bottom;
  lLarge([double? largest]) => [left + delta.dx, boundaries.left, if (longest != null) right - longest.width, ?largest].reduce(max);
  lEnlarge([double? largest]) => l = lLarge(largest);
  lShort() => min(left + delta.dx, right - shortest.width);
  lShorten() => l = lShort();
  tLarge([double? largest]) => [top + delta.dy, boundaries.top, if (longest != null) bottom - longest.height, ?largest].reduce(max);
  tEnlarge([double? largest]) => t = tLarge(largest);
  tShort() => min(top + delta.dy, bottom - shortest.height);
  tShorten() => t = tShort();
  rLarge([double? largest]) => [right + delta.dx, boundaries.right, if (longest != null) left + longest.width, ?largest].reduce(min);
  rEnlarge([double? largest]) => r = rLarge(largest);
  rShort() => max(right + delta.dx, left + shortest.width);
  rShorten() => r = rShort();
  bLarge([double? largest]) => [bottom + delta.dy, boundaries.bottom, if (longest != null) top + longest.height, ?largest].reduce(min);
  bEnlarge([double? largest]) => b = bLarge(largest);
  bShort() => max(bottom + delta.dy, top + shortest.height);
  bShorten() => b = bShort();
  if (aspectRatio != null) {
    double boundaryX, boundaryY, overflowX, overflowY;
    Function() boundByX, boundByY;
    final denom = aspectRatio + 1.0;
    switch (corner) {
      case .topLeft:
        final part = (delta.dx + delta.dy) / denom;
        l = left + part * aspectRatio;
        t = top + part;
        if (t < top) {
          boundaryX = longest == null ? boundaries.left : max(boundaries.left, right - longest.width);
          boundaryY = longest == null ? boundaries.top : max(boundaries.top, bottom - longest.height);
          overflowX = boundaryX - l;
          overflowY = boundaryY - t;
        } else {
          boundaryX = right - shortest.width;
          boundaryY = bottom - shortest.height;
          overflowX = l - boundaryX;
          overflowY = t - boundaryY;
        }
        boundByX = () {
          l = boundaryX;
          t = bottom - (right - l) / aspectRatio;
        };
        boundByY = () {
          t = boundaryY;
          l = right - (bottom - t) * aspectRatio;
        };
      case .topRight:
        final part = (-delta.dx + delta.dy) / denom;
        t = top + part;
        r = right - part * aspectRatio;
        if (t < top) {
          boundaryX = longest == null ? boundaries.right : min(boundaries.right, left + longest.width);
          boundaryY = longest == null ? boundaries.top : max(boundaries.top, bottom - longest.height);
          overflowX = r - boundaryX;
          overflowY = boundaryY - t;
        } else {
          boundaryX = left + shortest.width;
          boundaryY = bottom - shortest.height;
          overflowX = boundaryX - r;
          overflowY = t - boundaryY;
        }
        boundByX = () {
          r = boundaryX;
          t = bottom - (r - left) / aspectRatio;
        };
        boundByY = () {
          t = boundaryY;
          r = left + (bottom - t) * aspectRatio;
        };
      case .bottomLeft:
        final part = (-delta.dx + delta.dy) / denom;
        l = left - part * aspectRatio;
        b = bottom + part;
        if (b > bottom) {
          boundaryX = longest == null ? boundaries.left : max(boundaries.left, right - longest.width);
          boundaryY = longest == null ? boundaries.bottom : min(boundaries.bottom, top + longest.height);
          overflowX = boundaryX - l;
          overflowY = b - boundaryY;
        } else {
          boundaryX = right - shortest.width;
          boundaryY = top + shortest.height;
          overflowX = l - boundaryX;
          overflowY = boundaryY - b;
        }
        boundByX = () {
          l = boundaryX;
          b = top + (right - l) / aspectRatio;
        };
        boundByY = () {
          b = boundaryY;
          l = right - (b - top) * aspectRatio;
        };
      case .bottomRight:
        final part = (delta.dx + delta.dy) / denom;
        b = bottom + part;
        r = right + part * aspectRatio;
        if (b > bottom) {
          boundaryX = longest == null ? boundaries.right : min(boundaries.right, left + longest.width);
          boundaryY = longest == null ? boundaries.bottom : min(boundaries.bottom, top + longest.height);
          overflowX = r - boundaryX;
          overflowY = b - boundaryY;
        } else {
          boundaryX = left + shortest.width;
          boundaryY = top + shortest.height;
          overflowX = boundaryX - r;
          overflowY = boundaryY - b;
        }
        boundByX = () {
          r = boundaryX;
          b = top + (r - left) / aspectRatio;
        };
        boundByY = () {
          b = boundaryY;
          r = left + (b - top) * aspectRatio;
        };
    }
    if (overflowX > 0) {
      if (overflowY > 0) {
        if (overflowX > overflowY) {
          boundByX();
        } else {
          boundByY();
        }
      } else {
        boundByX();
      }
    } else if (overflowY > 0) {
      boundByY();
    }
  } else if (largest != null) {
    largeBound() {
      final y = delta.dy.abs();
      final x = delta.dx.abs();
      double k = 1;
      if (x != 0 && y != 0) {
        /// k == largestDelta.distance / delta.distance
        /// (kx + width)(ky + height) == largest --> Quadratic equation
        k = -height/2/y -width/2/x + sqrt(pow(x * height + y * width, 2) - 4 * x * y * (width * height - largest)) / 2 / x / y;
      } else if (x != 0) {
        k = (largest/height - width) / x;
      } else if (y != 0) {
        k = (largest/width - height) / y;
      }
      if (k < 1) {
        delta = delta * k;
      }
    }
    /// first shorten then enlarge -> thus the enlarge can get more space
    switch (corner) {
      case .topLeft:
        if (delta.dx > 0) {
          lShorten();
          if (delta.dy > 0) {
            tShorten();
          } else {
            tEnlarge(bottom - largest/(right - l));
          }
        } else {
          if (delta.dy > 0) {
            tShorten();
            lEnlarge(right - largest/(bottom - t));
          } else {
            delta = Offset(lLarge(), tLarge()) - topLeft;
            largeBound();
            l = left + delta.dx;
            t = top + delta.dy;
          }
        }
      case .topRight:
        if (delta.dx < 0) {
          rShorten();
          if (delta.dy > 0) {
            tShorten();
          } else {
            tEnlarge(bottom - largest/(r - left));
          }
        } else {
          if (delta.dy > 0) {
            tShorten();
            rEnlarge(left + largest/(bottom - t));
          } else {
            delta = Offset(rLarge(), tLarge()) - topRight;
            largeBound();
            r = right + delta.dx;
            t = top + delta.dy;
          }
        }
      case .bottomLeft:
        if (delta.dx > 0) {
          lShorten();
          if (delta.dy < 0) {
            bShorten();
          } else {
            bEnlarge(top + largest/(right - l));
          }
        } else {
          if (delta.dy < 0) {
            bShorten();
            lEnlarge(right - largest/(b - top));
          } else {
            delta = Offset(lLarge(), bLarge()) - bottomLeft;
            largeBound();
            l = left + delta.dx;
            b = bottom + delta.dy;
          }
        }
      case .bottomRight:
        if (delta.dx < 0) {
          rShorten();
          if (delta.dy < 0) {
            bShorten();
          } else {
            bEnlarge(top + largest/(r - left));
          }
        } else {
          if (delta.dy < 0) {
            bShorten();
            rEnlarge(left + largest/(b - top));
          } else {
            delta = Offset(rLarge(), bLarge()) - bottomRight;
            largeBound();
            r = right + delta.dx;
            b = bottom + delta.dy;
          }
        }
    }
  } else {
    ll() => delta.dx < 0 ? lEnlarge() : lShorten();
    tt() => delta.dy < 0 ? tEnlarge() : tShorten();
    rr() => delta.dx > 0 ? rEnlarge() : rShorten();
    bb() => delta.dy > 0 ? bEnlarge() : bShorten();
    switch (corner) {
      case .topLeft: tt(); ll();
      case .topRight: tt(); rr();
      case .bottomLeft: bb(); ll();
      case .bottomRight: bb(); rr();
    }
  }
  return Rect.fromLTRB(l, t, r, b);
}