提交 66b4b8da 编写于 作者: I Ian Hickson

Merge pull request #2147 from Hixie/RRect

Make RRect useful
......@@ -4,31 +4,34 @@
part of dart_ui;
/// An immutable 2D floating-point offset
/// An immutable 2D floating-point offset.
///
/// An Offset represents a vector from an unspecified point
class Offset extends OffsetBase {
const Offset(double dx, double dy) : super(dx, dy);
/// The x component of the offset
/// The x component of the offset.
double get dx => _dx;
/// The y component of the offset
/// The y component of the offset.
double get dy => _dy;
/// The magnitude of the offset
/// The magnitude of the offset.
double get distance => math.sqrt(_dx * _dx + _dy * _dy);
/// An offset with zero magnitude
/// The square of the magnitude of the offset.
double get distanceSquared => _dx * _dx + _dy * _dy;
/// An offset with zero magnitude.
static const Offset zero = const Offset(0.0, 0.0);
/// An offset with infinite x and y components
/// An offset with infinite x and y components.
static const Offset infinite = const Offset(double.INFINITY, double.INFINITY);
/// Returns a new offset with the x component scaled by scaleX and the y component scaled by scaleY
/// Returns a new offset with the x component scaled by scaleX and the y component scaled by scaleY.
Offset scale(double scaleX, double scaleY) => new Offset(dx * scaleX, dy * scaleY);
/// Returns a new offset with translateX added to the x component and translateY added to the y component
/// Returns a new offset with translateX added to the x component and translateY added to the y component.
Offset translate(double translateX, double translateY) => new Offset(dx + translateX, dy + translateY);
Offset operator -() => new Offset(-dx, -dy);
......@@ -39,13 +42,13 @@ class Offset extends OffsetBase {
Offset operator ~/(double operand) => new Offset((dx ~/ operand).toDouble(), (dy ~/ operand).toDouble());
Offset operator %(double operand) => new Offset(dx % operand, dy % operand);
/// Returns a rect of the given size that starts at (0, 0) plus this offset
/// Returns a rect of the given size that starts at (0, 0) plus this offset.
Rect operator &(Size other) => new Rect.fromLTWH(dx, dy, other.width, other.height);
/// Returns the point at (0, 0) plus this offset.
Point toPoint() => new Point(dx, dy);
/// Linearly interpolate between two offsets
/// Linearly interpolate between two offsets.
///
/// If either offset is null, this function interpolates from [Offset.zero].
static Offset lerp(Offset a, Offset b, double t) {
......
part of dart_ui;
// A rounded rectangle.
// A rounded rectangle with the same radii for all four corners.
class RRect {
RRect();
RRect._();
/// Initialize with the same radii for all four corners.
RRect.fromRectXY(Rect rect, double xRadius, double yRadius) {
/// Construct a rounded rectangle from its left, top, right, and bottom edges,
/// and the radii along its horizontal axis and its vertical axis.
RRect.fromLTRBXY(double left, double top, double right, double bottom, double radiusX, double radiusY) {
_value
..[0] = left
..[1] = top
..[2] = right
..[3] = bottom
..[4] = radiusX
..[5] = radiusY;
}
/// Construct a rounded rectangle from its bounding box and the radii along
/// its horizontal axis and its vertical axis.
RRect.fromRectXY(Rect rect, double radiusX, double radiusY) {
_value
..[0] = rect.left
..[1] = rect.top
..[2] = rect.right
..[3] = rect.bottom
..[4] = xRadius
..[5] = yRadius;
..[4] = radiusX
..[5] = radiusY;
}
final Float32List _value = new Float32List(6);
static const int _kDataSize = 6;
final Float32List _value = new Float32List(_kDataSize);
/// The offset of the left edge of this rectangle from the x axis.
double get left => _value[0];
/// The offset of the top edge of this rectangle from the y axis.
double get top => _value[1];
/// The offset of the right edge of this rectangle from the x axis.
double get right => _value[2];
/// The offset of the bottom edge of this rectangle from the y axis.
double get bottom => _value[3];
/// The horizontal semi-axis of the corners.
double get radiusX => _value[4];
/// The vertical semi-axis of the corners.
double get radiusY => _value[5];
/// A rounded rectangle with all the values set to zero.
static final RRect zero = new RRect._();
/// Returns a new RRect translated by the given offset.
RRect shift(Offset offset) {
RRect result = new RRect();
result._value
..[0] = _value[0] + offset.dx
..[1] = _value[1] + offset.dy
..[2] = _value[2] + offset.dx
..[3] = _value[3] + offset.dy
..[4] = _value[4]
..[5] = _value[5];
return result;
return new RRect.fromLTRBXY(
_value[0] + offset.dx,
_value[1] + offset.dy,
_value[2] + offset.dx,
_value[3] + offset.dy,
_value[4],
_value[5]
);
}
/// Returns a new RRect with edges and radii moved outwards by the given delta.
RRect inflate(double delta) {
return new RRect.fromLTRBXY(
_value[0] - delta,
_value[1] - delta,
_value[2] + delta,
_value[3] + delta,
_value[4] + delta,
_value[5] + delta
);
}
/// Returns a new RRect with edges and radii moved inwards by the given delta.
RRect deflate(double delta) => inflate(-delta);
/// The distance between the left and right edges of this rectangle.
double get width => right - left;
/// The distance between the top and bottom edges of this rectangle.
double get height => bottom - top;
/// The bounding box of this rounded rectangle (the rectangle with no rounded corners).
Rect get outerRect => new Rect.fromLTRB(left, top, right, bottom);
/// The non-rounded rectangle that fits inside this rounded rectangle by
/// touching the middle of each curved corner.
Rect get safeInnerRect {
const double kInsetFactor = 0.29289321881; // 1-cos(pi/4)
return new Rect.fromLTRB(
left + radiusX * kInsetFactor,
top + radiusY * kInsetFactor,
right - radiusX * kInsetFactor,
bottom - radiusY * kInsetFactor
);
}
/// The rectangle that would be formed using only the straight sides of the
/// rounded rectangle, i.e., the rectangle formed from the centers of the
/// ellipses that form the corners. This is the intersection of the
/// [wideMiddleRect] and the [tallMiddleRect].
Rect get middleRect {
return new Rect.fromLTRB(
left + radiusX,
top + radiusY,
right - radiusX,
bottom - radiusY
);
}
/// The biggest rectangle that is entirely inside the rounded rectangle and
/// has the full width of the rounded rectangle.
Rect get wideMiddleRect {
return new Rect.fromLTRB(
left,
top + radiusY,
right,
bottom - radiusY
);
}
/// The biggest rectangle that is entirely inside the rounded rectangle and
/// has the full height of the rounded rectangle.
Rect get tallMiddleRect {
return new Rect.fromLTRB(
left + radiusX,
top,
right - radiusX,
bottom
);
}
/// Whether this rounded rectangle encloses a non-zero area.
/// Negative areas are considered empty.
bool get isEmpty => left >= right || top >= bottom;
/// Whether this rounded rectangle has a side with no straight section.
bool get isStadium => width <= 2 * radiusX || height <= 2 * radiusY;
/// Whether this rounded rectangle has no side with a straight section.
bool get isEllipse => width <= 2 * radiusX && height <= 2 * radiusY;
/// Whether this rounded rectangle would draw as a circle.
bool get isCircle => width == height && isEllipse;
/// The lesser of the magnitudes of the width and the height of this rounded
/// rectangle.
double get shortestSide {
double w = width.abs();
double h = height.abs();
return w < h ? w : h;
}
/// The point halfway between the left and right and the top and bottom edges of this rectangle.
Point get center => new Point(left + width / 2.0, top + height / 2.0);
/// Whether the given point lies inside the rounded rectangle.
bool contains(Point point) {
if (point.x < left || point.x >= right || point.y < top || point.y >= bottom)
return false; // outside bounding box
double leftInner = left + radiusX;
double rightInner = right - radiusX;
double topInner = top + radiusY;
double bottomInner = bottom - radiusY;
if (point.x >= leftInner && point.x <= rightInner)
return true; // inside tallMiddleRect
if (point.y >= topInner && point.y <= bottomInner)
return true; // inside wideMiddleRect
// it is in one of the corners
// convert this to a test of the unit circle
double x, y;
if (point.x > leftInner) {
assert(point.x > rightInner);
x = point.x - (rightInner - leftInner);
} else {
x = point.x;
}
if (point.y > topInner) {
assert(point.y > bottomInner);
y = point.y - (bottomInner - topInner);
} else {
y = point.y;
}
x = x / (radiusX * 2) - 0.5;
y = y / (radiusY * 2) - 0.5;
// check if the point is outside the unit circle
if (x * x + y * y > 0.25)
return false;
return true;
}
/// Linearly interpolate between two rounded rectangles.
///
/// If either is null, this function substitutes [RRect.zero] instead.
static RRect lerp(RRect a, RRect b, double t) {
if (a == null && b == null)
return null;
if (a == null)
return new RRect.fromLTRBXY(b.left * t, b.top * t, b.right * t, b.bottom * t, b.radiusX * t, b.radiusY * t);
if (b == null) {
double k = 1.0 - t;
return new RRect.fromLTRBXY(a.left * k, a.top * k, a.right * k, a.bottom * k, a.radiusX * k, a.radiusY * k);
}
return new RRect.fromLTRBXY(
lerpDouble(a.left, b.left, t),
lerpDouble(a.top, b.top, t),
lerpDouble(a.right, b.right, t),
lerpDouble(a.bottom, b.bottom, t),
lerpDouble(a.radiusX, b.radiusX, t),
lerpDouble(a.radiusY, b.radiusY, t)
);
}
bool operator ==(dynamic other) {
if (identical(this, other))
return true;
if (other is! RRect)
return false;
final RRect typedOther = other;
for (int i = 0; i < _kDataSize; i += 1) {
if (_value[i] != typedOther._value[i])
return false;
}
return true;
}
int get hashCode => _value.fold(373, (value, item) => (37 * value + item.hashCode));
String toString() => "RRect.fromLTRBXY(${left.toStringAsFixed(1)}, ${top.toStringAsFixed(1)}, ${right.toStringAsFixed(1)}, ${bottom.toStringAsFixed(1)}, ${radiusX.toStringAsFixed(1)}, ${radiusY.toStringAsFixed(1)})";
}
......@@ -7,9 +7,9 @@ part of dart_ui;
/// An immutable 2D, axis-aligned, floating-point rectangle whose coordinates
/// are relative to an origin point.
class Rect {
Rect();
Rect._();
/// Construct a rectangle from left, top, right, and bottom edges.
/// Construct a rectangle from its left, top, right, and bottom edges.
Rect.fromLTRB(double left, double top, double right, double bottom) {
_value
..[0] = left
......@@ -18,7 +18,7 @@ class Rect {
..[3] = bottom;
}
/// Construct a rectangle from left, top edges and a width and height.
/// Construct a rectangle from its left and top edges, its width, and its height.
Rect.fromLTWH(double left, double top, double width, double height) {
_value
..[0] = left
......@@ -27,7 +27,8 @@ class Rect {
..[3] = top + height;
}
final Float32List _value = new Float32List(4);
static const int _kDataSize = 4;
final Float32List _value = new Float32List(_kDataSize);
/// The offset of the left edge of this rectangle from the x axis.
double get left => _value[0];
......@@ -42,7 +43,7 @@ class Rect {
double get bottom => _value[3];
/// A rectangle with left, top, right, and bottom edges all at zero.
static final Rect zero = new Rect();
static final Rect zero = new Rect._();
/// Returns a new rectangle translated by the given offset.
Rect shift(Offset offset) {
......@@ -79,7 +80,8 @@ class Rect {
/// Negative areas are considered empty.
bool get isEmpty => left >= right || top >= bottom;
/// The lesser of the width and the height of this rectangle.
/// The lesser of the magnitudes of the width and the height of this
/// rectangle.
double get shortestSide {
double w = width.abs();
double h = height.abs();
......@@ -110,7 +112,7 @@ class Rect {
/// Linearly interpolate between two rectangles.
///
/// If either rect is null, this function interpolates from [Rect.zero].
/// If either rect is null, [Rect.zero] is used as a substitute.
static Rect lerp(Rect a, Rect b, double t) {
if (a == null && b == null)
return null;
......@@ -118,7 +120,7 @@ class Rect {
return new Rect.fromLTRB(b.left * t, b.top * t, b.right * t, b.bottom * t);
if (b == null) {
double k = 1.0 - t;
return new Rect.fromLTRB(b.left * k, b.top * k, b.right * k, b.bottom * k);
return new Rect.fromLTRB(a.left * k, a.top * k, a.right * k, a.bottom * k);
}
return new Rect.fromLTRB(
lerpDouble(a.left, b.left, t),
......@@ -134,7 +136,7 @@ class Rect {
if (other is! Rect)
return false;
final Rect typedOther = other;
for (var i = 0; i < 4; ++i) {
for (int i = 0; i < _kDataSize; i += 1) {
if (_value[i] != typedOther._value[i])
return false;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册