Skip to content

Commit 04a47c2

Browse files
committed
Rotation #1
1 parent 6734453 commit 04a47c2

21 files changed

+1020
-169
lines changed

packages/box_transform/lib/src/enums.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,3 +413,21 @@ enum ResizeMode {
413413
/// w.r.t the center.
414414
bool get hasSymmetry => isSymmetric || isSymmetricScale;
415415
}
416+
417+
/// An enum that defines how a box should be constrained and/or clamped when
418+
/// undergoing a box transformation operation.
419+
enum BindingStrategy {
420+
/// When a box transformation occurs, clamps and constraints are considered
421+
/// on the original unrotated dimensions of the box. Rotation is not
422+
/// considered with this strategy, and therefore, if a box is rotated,
423+
/// its vertices may leak out of its terminal dimensions and positions.
424+
originalBox,
425+
426+
/// When a box transformation occurs, clamps and constraints are considered
427+
/// on the entire bounding box of the box. The bounding box is the smallest
428+
/// box that can contain all the vertices of its rotated box.
429+
///
430+
/// This is the default strategy to ensure that the box does not
431+
/// leak out of its terminal dimensions and positions.
432+
boundingBox,
433+
}

packages/box_transform/lib/src/geometry.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -474,8 +474,9 @@ class Box {
474474
static const Box largest =
475475
Box.fromLTRB(-_giantScalar, -_giantScalar, _giantScalar, _giantScalar);
476476

477-
/// Whether any of the coordinates of this rectangle are equal to positive infinity.
478-
// included for consistency with Vector2 and Dimension
477+
/// Whether any of the coordinates of this rectangle are equal to positive
478+
/// infinity.
479+
/// Included for consistency with Vector2 and Dimension
479480
bool get isInfinite =>
480481
left >= double.infinity ||
481482
top >= double.infinity ||
@@ -721,5 +722,5 @@ class Box {
721722

722723
@override
723724
String toString() =>
724-
'Box.fromLTRB(${left.toStringAsFixed(1)}, ${top.toStringAsFixed(1)}, ${right.toStringAsFixed(1)}, ${bottom.toStringAsFixed(1)})';
725+
'Box.fromLTWH(${left.toStringAsFixed(1)}, ${top.toStringAsFixed(1)}, ${width.toStringAsFixed(1)}, ${height.toStringAsFixed(1)})';
725726
}

packages/box_transform/lib/src/resizers/freeform_resizing.dart

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,49 +13,114 @@ final class FreeformResizer extends Resizer {
1313
required HandlePosition handle,
1414
required Constraints constraints,
1515
required Flip flip,
16+
required double rotation,
17+
required BindingStrategy bindingStrategy,
1618
}) {
19+
final Box effectiveInitialRect = flipRect(initialRect, flip, handle);
20+
final Box initialBoundingRect = BoxTransformer.calculateBoundingRect(
21+
rotation: rotation,
22+
unrotatedBox: effectiveInitialRect,
23+
);
24+
1725
final flippedHandle = handle.flip(flip);
18-
Box effectiveInitialRect = flipRect(initialRect, flip, handle);
26+
27+
final Box effectiveInitialBoundingRect =
28+
flipRect(initialBoundingRect, flip, handle);
1929

2030
Box newRect = Box.fromLTRB(
2131
max(explodedRect.left, clampingRect.left),
2232
max(explodedRect.top, clampingRect.top),
2333
min(explodedRect.right, clampingRect.right),
2434
min(explodedRect.bottom, clampingRect.bottom),
2535
);
36+
Box newBoundingRect = BoxTransformer.calculateBoundingRect(
37+
rotation: rotation,
38+
unrotatedBox: newRect,
39+
);
2640

2741
bool isValid = true;
2842
if (!constraints.isUnconstrained) {
29-
final constrainedWidth =
30-
newRect.width.clamp(constraints.minWidth, constraints.maxWidth);
31-
final constrainedHeight =
32-
newRect.height.clamp(constraints.minHeight, constraints.maxHeight);
43+
final bindingRect = bindingStrategy == BindingStrategy.originalBox
44+
? newRect
45+
: newBoundingRect;
46+
47+
final Dimension constrainedSize = Dimension(
48+
bindingRect.width.clamp(constraints.minWidth, constraints.maxWidth),
49+
bindingRect.height.clamp(constraints.minHeight, constraints.maxHeight),
50+
);
51+
final Dimension constrainedDelta = Dimension(
52+
constrainedSize.width - bindingRect.width,
53+
constrainedSize.height - bindingRect.height,
54+
);
3355

3456
newRect = Box.fromHandle(
3557
flippedHandle.anchor(effectiveInitialRect),
3658
flippedHandle,
37-
constrainedWidth,
38-
constrainedHeight,
59+
newRect.width + constrainedDelta.width,
60+
newRect.height + constrainedDelta.height,
61+
);
62+
newBoundingRect = Box.fromHandle(
63+
flippedHandle.anchor(effectiveInitialBoundingRect),
64+
flippedHandle,
65+
newBoundingRect.width + constrainedDelta.width,
66+
newBoundingRect.height + constrainedDelta.height,
3967
);
4068

41-
isValid = isValidRect(newRect, constraints, clampingRect);
69+
isValid = isValidRect(
70+
switch (bindingStrategy) {
71+
BindingStrategy.originalBox => newRect,
72+
BindingStrategy.boundingBox => newBoundingRect,
73+
},
74+
constraints,
75+
clampingRect,
76+
);
4277
if (!isValid) {
4378
newRect = Box.fromHandle(
4479
handle.anchor(initialRect),
4580
handle,
4681
!handle.isSide || handle.isHorizontal
4782
? constraints.minWidth
48-
: constrainedWidth,
83+
: newRect.width,
4984
!handle.isSide || handle.isVertical
5085
? constraints.minHeight
51-
: constrainedHeight,
86+
: newRect.height,
87+
);
88+
newBoundingRect = Box.fromHandle(
89+
handle.anchor(initialBoundingRect),
90+
handle,
91+
!handle.isSide || handle.isHorizontal
92+
? constraints.minWidth
93+
: newBoundingRect.width,
94+
!handle.isSide || handle.isVertical
95+
? constraints.minHeight
96+
: newBoundingRect.height,
5297
);
5398
}
5499
}
55100

56-
// Not used but calculating it for returning correct largest box.
101+
if (rotation != 0) {
102+
final Vector2 positionDelta = newRect.topLeft - initialRect.topLeft;
103+
final Vector2 newPos = BoxTransformer.calculateUnrotatedPos(
104+
initialRect,
105+
rotation,
106+
positionDelta,
107+
newRect.size,
108+
);
109+
newRect = Box.fromLTWH(newPos.x, newPos.y, newRect.width, newRect.height);
110+
}
111+
112+
final Box effectiveBindingRect = switch (bindingStrategy) {
113+
BindingStrategy.originalBox => effectiveInitialRect,
114+
BindingStrategy.boundingBox => effectiveInitialBoundingRect,
115+
};
116+
final Box bindingRect = switch (bindingStrategy) {
117+
BindingStrategy.originalBox => initialRect,
118+
BindingStrategy.boundingBox => initialBoundingRect,
119+
};
120+
121+
// Only used for calculating the correct largest box.
57122
final Box area = getAvailableAreaForHandle(
58-
rect: isValid ? effectiveInitialRect : initialRect,
123+
rect: isValid ? effectiveBindingRect : bindingRect,
59124
handle: isValid ? flippedHandle : handle,
60125
clampingRect: clampingRect,
61126
);

packages/box_transform/lib/src/resizers/resizer.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ library resize_handlers;
22

33
import 'dart:math';
44

5-
import '../enums.dart';
6-
import '../geometry.dart';
7-
import '../helpers.dart';
5+
import 'package:vector_math/vector_math.dart';
6+
7+
import '../../box_transform.dart';
88

99
part 'freeform_resizing.dart';
1010
part 'scale_resizing.dart';
@@ -43,5 +43,7 @@ sealed class Resizer {
4343
required HandlePosition handle,
4444
required Constraints constraints,
4545
required Flip flip,
46+
required double rotation,
47+
required BindingStrategy bindingStrategy,
4648
});
4749
}

packages/box_transform/lib/src/resizers/scale_resizing.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ final class ScaleResizer extends Resizer {
1313
required HandlePosition handle,
1414
required Constraints constraints,
1515
required Flip flip,
16+
required double rotation,
17+
required BindingStrategy bindingStrategy,
1618
}) {
1719
({Box rect, Box largest, bool hasValidFlip}) result = _resizeRect(
1820
initialRect: initialRect,

packages/box_transform/lib/src/resizers/symmetric_resizing.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ final class SymmetricResizer extends Resizer {
1313
required HandlePosition handle,
1414
required Constraints constraints,
1515
required Flip flip,
16+
required double rotation,
17+
required BindingStrategy bindingStrategy,
1618
}) {
1719
final double horizontalMirrorRight =
1820
clampingRect.right - explodedRect.center.x;

packages/box_transform/lib/src/resizers/symmetric_scale_resizing.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ final class SymmetricScaleResizer extends Resizer {
1313
required HandlePosition handle,
1414
required Constraints constraints,
1515
required Flip flip,
16+
required double rotation,
17+
required BindingStrategy bindingStrategy,
1618
}) {
1719
switch (handle) {
1820
case HandlePosition.none:

0 commit comments

Comments
 (0)