-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from dnfield/geom
Add geometry classes
- Loading branch information
Showing
11 changed files
with
1,174 additions
and
1 deletion.
There are no files selected for viewing
1 change: 0 additions & 1 deletion
1
packages/vector_graphics_compiler/bin/vector_graphics_compiler.dart
This file was deleted.
Oops, something went wrong.
122 changes: 122 additions & 0 deletions
122
packages/vector_graphics_compiler/lib/src/geometry/basic_types.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import 'dart:math' as math; | ||
import 'package:meta/meta.dart'; | ||
|
||
/// An immutable position in two-dimensional space. | ||
/// | ||
/// This class is roughly compatible with dart:ui's Offset. | ||
@immutable | ||
class Point { | ||
/// Creates a point object with x,y coordinates. | ||
const Point(this.x, this.y); | ||
|
||
static const Point zero = Point(0, 0); | ||
|
||
/// The offset along the x-axis of this point. | ||
final double x; | ||
|
||
/// The offset along the y-axis of this point. | ||
final double y; | ||
|
||
@override | ||
int get hashCode => Object.hash(x, y); | ||
|
||
@override | ||
bool operator ==(Object other) { | ||
return other is Point && other.x == x && other.y == y; | ||
} | ||
|
||
Point operator /(double divisor) { | ||
return Point(x / divisor, y / divisor); | ||
} | ||
|
||
Point operator *(double multiplicand) { | ||
return Point(x * multiplicand, y * multiplicand); | ||
} | ||
|
||
@override | ||
String toString() => 'Point($x, $y)'; | ||
} | ||
|
||
/// An immutable, 2D, axis-aligned, floating-point rectangle whose coordinates | ||
/// are relative to a given origin. | ||
@immutable | ||
class Rect { | ||
/// Creates a rectangle from the specified left, top, right, and bottom | ||
/// positions. | ||
const Rect.fromLTRB(this.left, this.top, this.right, this.bottom); | ||
|
||
/// Creates a rectangle from the specified left and top positions with width | ||
/// and height dimensions. | ||
const Rect.fromLTWH(double left, double top, double width, double height) | ||
: this.fromLTRB(left, top, left + width, top + height); | ||
|
||
/// Creates a rectangle representing a circle with centerpoint `x,`y` and | ||
/// radius `r`. | ||
const Rect.fromCircle(double x, double y, double r) | ||
: this.fromLTRB(x - r, y - r, x + r, y + r); | ||
|
||
/// A rectangle covering the entire coordinate space, equal to dart:ui's | ||
/// definition. | ||
static const Rect largest = Rect.fromLTRB(-1e9, -1e9, 1e9, 1e9); | ||
|
||
/// A rectangle with the top, left, right, and bottom edges all at zero. | ||
static const Rect zero = Rect.fromLTRB(0, 0, 0, 0); | ||
|
||
/// The x-axis offset of left edge. | ||
final double left; | ||
|
||
/// The y-axis offset of the top edge. | ||
final double top; | ||
|
||
/// The x-axis offset of the right edge. | ||
final double right; | ||
|
||
/// The y-axis offset of the bottom edge. | ||
final double bottom; | ||
|
||
/// The width of the rectangle. | ||
double get width => right - left; | ||
|
||
/// The height of the rectangle. | ||
double get height => bottom - top; | ||
|
||
/// The top left corner of the rect. | ||
Point get topLeft => Point(left, top); | ||
|
||
/// The top right corner of the rect. | ||
Point get topRight => Point(right, top); | ||
|
||
/// The bottom left corner of the rect. | ||
Point get bottomLeft => Point(bottom, left); | ||
|
||
/// The bottom right corner of the rect. | ||
Point get bottomRight => Point(bottom, right); | ||
|
||
/// The size of the rectangle, expressed as a [Point]. | ||
Point get size => Point(width, height); | ||
|
||
/// Creates the smallest rectangle that covers the edges of this and `other`. | ||
Rect expanded(Rect other) { | ||
return Rect.fromLTRB( | ||
math.min(left, other.left), | ||
math.min(top, other.top), | ||
math.max(right, other.right), | ||
math.max(bottom, other.bottom), | ||
); | ||
} | ||
|
||
@override | ||
String toString() => 'Rect.fromLTRB($left, $top, $right, $bottom)'; | ||
|
||
@override | ||
int get hashCode => Object.hash(left, top, right, bottom); | ||
|
||
@override | ||
bool operator ==(Object other) { | ||
return other is Rect && | ||
other.left == left && | ||
other.top == top && | ||
other.right == right && | ||
other.bottom == bottom; | ||
} | ||
} |
193 changes: 193 additions & 0 deletions
193
packages/vector_graphics_compiler/lib/src/geometry/matrix.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
import 'dart:math' as math; | ||
import 'dart:typed_data'; | ||
|
||
import 'package:meta/meta.dart'; | ||
|
||
import 'basic_types.dart'; | ||
|
||
/// An immutable affine matrix, a 3x3 column-major-order matrix in which the | ||
/// last row is always set to the identity values, i.e. `0 0 1`. | ||
@immutable | ||
class AffineMatrix { | ||
/// Creates an immutable affine matrix. To work with the identity matrix, use | ||
/// the [identity] property. | ||
const AffineMatrix( | ||
this.a, | ||
this.b, | ||
this.c, | ||
this.d, | ||
this.e, | ||
this.f, [ | ||
this._m4_10 = 1.0, | ||
]); | ||
|
||
/// The identity affine matrix. | ||
static const AffineMatrix identity = AffineMatrix(1, 0, 0, 1, 0, 0); | ||
|
||
/// The 0,0 position of the matrix. | ||
final double a; | ||
|
||
/// The 1,0 position of the matrix. | ||
final double b; | ||
|
||
/// The 0,1 position of the matrix. | ||
final double c; | ||
|
||
/// The 1,1 position of the matrix. | ||
final double d; | ||
|
||
/// The 2,0 position of the matrix. | ||
final double e; | ||
|
||
/// The 2,1 position of the matrix. | ||
final double f; | ||
|
||
/// Translations can affect this value, so we have to track it. | ||
final double _m4_10; | ||
|
||
/// Creates a new affine matrix rotated by `radians`. | ||
AffineMatrix rotated(double radians) { | ||
if (radians == 0) { | ||
return this; | ||
} | ||
final double cosAngle = math.cos(radians); | ||
final double sinAngle = math.sin(radians); | ||
return AffineMatrix( | ||
(a * cosAngle) + (c * sinAngle), | ||
(b * cosAngle) + (d * sinAngle), | ||
(a * -sinAngle) + (c * cosAngle), | ||
(b * -sinAngle) + (d * cosAngle), | ||
e, | ||
f, | ||
_m4_10, | ||
); | ||
} | ||
|
||
/// Creates a new affine matrix rotated by `x` and `y`. | ||
/// | ||
/// If `y` is not specified, it is defaulted to the same value as `x`. | ||
AffineMatrix scaled(double x, [double? y]) { | ||
y ??= x; | ||
if (x == 1 && y == 1) { | ||
return this; | ||
} | ||
return AffineMatrix( | ||
a * x, | ||
b * x, | ||
c * y, | ||
d * y, | ||
e, | ||
f, | ||
_m4_10 * x, | ||
); | ||
} | ||
|
||
/// Creates a new affine matrix, translated along the x and y axis. | ||
AffineMatrix translated(double x, double y) { | ||
return AffineMatrix( | ||
a, | ||
b, | ||
c, | ||
d, | ||
(a * x) + (c * y) + e, | ||
(b * x) + (d * y) + f, | ||
_m4_10, | ||
); | ||
} | ||
|
||
/// Creates a new affine matrix of this concatenated with `other`. | ||
AffineMatrix multiplied(AffineMatrix other) { | ||
return AffineMatrix( | ||
(a * other.a) + (c * other.b), | ||
(b * other.a) + (d * other.b), | ||
(a * other.c) + (c * other.d), | ||
(b * other.c) + (d * other.d), | ||
(a * other.e) + (c * other.f) + e, | ||
(b * other.e) + (d * other.f) + f, | ||
_m4_10, | ||
); | ||
} | ||
|
||
/// Maps `point` using the values of this matrix. | ||
Point transformPoint(Point point) { | ||
return Point( | ||
(a * point.x) + (c * point.y) + e, | ||
(b * point.x) + (d * point.y) + f, | ||
); | ||
} | ||
|
||
/// Maps `rect` using the values of this matrix. | ||
Rect transformRect(Rect rect) { | ||
final double x = rect.left; | ||
final double y = rect.top; | ||
final double w = rect.width; | ||
final double h = rect.height; | ||
|
||
final double wx = a * w; | ||
final double hx = c * h; | ||
final double rx = a * x + c * y; | ||
|
||
final double wy = b * w; | ||
final double hy = d * h; | ||
final double ry = b * x + d * y; | ||
|
||
double left = rx; | ||
double right = rx; | ||
if (wx < 0) { | ||
left += wx; | ||
} else { | ||
right += wx; | ||
} | ||
if (hx < 0) { | ||
left += hx; | ||
} else { | ||
right += hx; | ||
} | ||
|
||
double top = ry; | ||
double bottom = ry; | ||
if (wy < 0) { | ||
top += wy; | ||
} else { | ||
bottom += wy; | ||
} | ||
if (hy < 0) { | ||
top += hy; | ||
} else { | ||
bottom += hy; | ||
} | ||
|
||
return Rect.fromLTRB(left, top, right, bottom); | ||
} | ||
|
||
/// Creates a typed data representatino of this matrix suitable for use with | ||
/// `package:vector_math_64` (and, by extension, Flutter/dart:ui). | ||
Float64List toMatrix4() { | ||
return Float64List.fromList(<double>[ | ||
a, b, 0, 0, // | ||
c, d, 0, 0, // | ||
0, 0, _m4_10, 0, // | ||
e, f, 0, 1.0, // | ||
]); | ||
} | ||
|
||
@override | ||
int get hashCode => Object.hash(a, b, c, d, e, f, _m4_10); | ||
|
||
@override | ||
bool operator ==(Object other) { | ||
return other is AffineMatrix && | ||
other.a == a && | ||
other.b == b && | ||
other.d == d && | ||
other.e == e && | ||
other._m4_10 == _m4_10; | ||
} | ||
|
||
@override | ||
String toString() => ''' | ||
[ $a, $c, $e ] | ||
[ $b, $d, $f ] | ||
[ 0.0, 0.0, 1.0 ] | ||
'''; | ||
} |
Oops, something went wrong.