Skip to content

Commit 2dd3360

Browse files
authored
Merge pull request #3 from dnfield/geom
Add geometry classes
2 parents f3b5c35 + b872ed1 commit 2dd3360

File tree

11 files changed

+1174
-1
lines changed

11 files changed

+1174
-1
lines changed

packages/vector_graphics_compiler/bin/vector_graphics_compiler.dart

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import 'dart:math' as math;
2+
import 'package:meta/meta.dart';
3+
4+
/// An immutable position in two-dimensional space.
5+
///
6+
/// This class is roughly compatible with dart:ui's Offset.
7+
@immutable
8+
class Point {
9+
/// Creates a point object with x,y coordinates.
10+
const Point(this.x, this.y);
11+
12+
static const Point zero = Point(0, 0);
13+
14+
/// The offset along the x-axis of this point.
15+
final double x;
16+
17+
/// The offset along the y-axis of this point.
18+
final double y;
19+
20+
@override
21+
int get hashCode => Object.hash(x, y);
22+
23+
@override
24+
bool operator ==(Object other) {
25+
return other is Point && other.x == x && other.y == y;
26+
}
27+
28+
Point operator /(double divisor) {
29+
return Point(x / divisor, y / divisor);
30+
}
31+
32+
Point operator *(double multiplicand) {
33+
return Point(x * multiplicand, y * multiplicand);
34+
}
35+
36+
@override
37+
String toString() => 'Point($x, $y)';
38+
}
39+
40+
/// An immutable, 2D, axis-aligned, floating-point rectangle whose coordinates
41+
/// are relative to a given origin.
42+
@immutable
43+
class Rect {
44+
/// Creates a rectangle from the specified left, top, right, and bottom
45+
/// positions.
46+
const Rect.fromLTRB(this.left, this.top, this.right, this.bottom);
47+
48+
/// Creates a rectangle from the specified left and top positions with width
49+
/// and height dimensions.
50+
const Rect.fromLTWH(double left, double top, double width, double height)
51+
: this.fromLTRB(left, top, left + width, top + height);
52+
53+
/// Creates a rectangle representing a circle with centerpoint `x,`y` and
54+
/// radius `r`.
55+
const Rect.fromCircle(double x, double y, double r)
56+
: this.fromLTRB(x - r, y - r, x + r, y + r);
57+
58+
/// A rectangle covering the entire coordinate space, equal to dart:ui's
59+
/// definition.
60+
static const Rect largest = Rect.fromLTRB(-1e9, -1e9, 1e9, 1e9);
61+
62+
/// A rectangle with the top, left, right, and bottom edges all at zero.
63+
static const Rect zero = Rect.fromLTRB(0, 0, 0, 0);
64+
65+
/// The x-axis offset of left edge.
66+
final double left;
67+
68+
/// The y-axis offset of the top edge.
69+
final double top;
70+
71+
/// The x-axis offset of the right edge.
72+
final double right;
73+
74+
/// The y-axis offset of the bottom edge.
75+
final double bottom;
76+
77+
/// The width of the rectangle.
78+
double get width => right - left;
79+
80+
/// The height of the rectangle.
81+
double get height => bottom - top;
82+
83+
/// The top left corner of the rect.
84+
Point get topLeft => Point(left, top);
85+
86+
/// The top right corner of the rect.
87+
Point get topRight => Point(right, top);
88+
89+
/// The bottom left corner of the rect.
90+
Point get bottomLeft => Point(bottom, left);
91+
92+
/// The bottom right corner of the rect.
93+
Point get bottomRight => Point(bottom, right);
94+
95+
/// The size of the rectangle, expressed as a [Point].
96+
Point get size => Point(width, height);
97+
98+
/// Creates the smallest rectangle that covers the edges of this and `other`.
99+
Rect expanded(Rect other) {
100+
return Rect.fromLTRB(
101+
math.min(left, other.left),
102+
math.min(top, other.top),
103+
math.max(right, other.right),
104+
math.max(bottom, other.bottom),
105+
);
106+
}
107+
108+
@override
109+
String toString() => 'Rect.fromLTRB($left, $top, $right, $bottom)';
110+
111+
@override
112+
int get hashCode => Object.hash(left, top, right, bottom);
113+
114+
@override
115+
bool operator ==(Object other) {
116+
return other is Rect &&
117+
other.left == left &&
118+
other.top == top &&
119+
other.right == right &&
120+
other.bottom == bottom;
121+
}
122+
}
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import 'dart:math' as math;
2+
import 'dart:typed_data';
3+
4+
import 'package:meta/meta.dart';
5+
6+
import 'basic_types.dart';
7+
8+
/// An immutable affine matrix, a 3x3 column-major-order matrix in which the
9+
/// last row is always set to the identity values, i.e. `0 0 1`.
10+
@immutable
11+
class AffineMatrix {
12+
/// Creates an immutable affine matrix. To work with the identity matrix, use
13+
/// the [identity] property.
14+
const AffineMatrix(
15+
this.a,
16+
this.b,
17+
this.c,
18+
this.d,
19+
this.e,
20+
this.f, [
21+
this._m4_10 = 1.0,
22+
]);
23+
24+
/// The identity affine matrix.
25+
static const AffineMatrix identity = AffineMatrix(1, 0, 0, 1, 0, 0);
26+
27+
/// The 0,0 position of the matrix.
28+
final double a;
29+
30+
/// The 1,0 position of the matrix.
31+
final double b;
32+
33+
/// The 0,1 position of the matrix.
34+
final double c;
35+
36+
/// The 1,1 position of the matrix.
37+
final double d;
38+
39+
/// The 2,0 position of the matrix.
40+
final double e;
41+
42+
/// The 2,1 position of the matrix.
43+
final double f;
44+
45+
/// Translations can affect this value, so we have to track it.
46+
final double _m4_10;
47+
48+
/// Creates a new affine matrix rotated by `radians`.
49+
AffineMatrix rotated(double radians) {
50+
if (radians == 0) {
51+
return this;
52+
}
53+
final double cosAngle = math.cos(radians);
54+
final double sinAngle = math.sin(radians);
55+
return AffineMatrix(
56+
(a * cosAngle) + (c * sinAngle),
57+
(b * cosAngle) + (d * sinAngle),
58+
(a * -sinAngle) + (c * cosAngle),
59+
(b * -sinAngle) + (d * cosAngle),
60+
e,
61+
f,
62+
_m4_10,
63+
);
64+
}
65+
66+
/// Creates a new affine matrix rotated by `x` and `y`.
67+
///
68+
/// If `y` is not specified, it is defaulted to the same value as `x`.
69+
AffineMatrix scaled(double x, [double? y]) {
70+
y ??= x;
71+
if (x == 1 && y == 1) {
72+
return this;
73+
}
74+
return AffineMatrix(
75+
a * x,
76+
b * x,
77+
c * y,
78+
d * y,
79+
e,
80+
f,
81+
_m4_10 * x,
82+
);
83+
}
84+
85+
/// Creates a new affine matrix, translated along the x and y axis.
86+
AffineMatrix translated(double x, double y) {
87+
return AffineMatrix(
88+
a,
89+
b,
90+
c,
91+
d,
92+
(a * x) + (c * y) + e,
93+
(b * x) + (d * y) + f,
94+
_m4_10,
95+
);
96+
}
97+
98+
/// Creates a new affine matrix of this concatenated with `other`.
99+
AffineMatrix multiplied(AffineMatrix other) {
100+
return AffineMatrix(
101+
(a * other.a) + (c * other.b),
102+
(b * other.a) + (d * other.b),
103+
(a * other.c) + (c * other.d),
104+
(b * other.c) + (d * other.d),
105+
(a * other.e) + (c * other.f) + e,
106+
(b * other.e) + (d * other.f) + f,
107+
_m4_10,
108+
);
109+
}
110+
111+
/// Maps `point` using the values of this matrix.
112+
Point transformPoint(Point point) {
113+
return Point(
114+
(a * point.x) + (c * point.y) + e,
115+
(b * point.x) + (d * point.y) + f,
116+
);
117+
}
118+
119+
/// Maps `rect` using the values of this matrix.
120+
Rect transformRect(Rect rect) {
121+
final double x = rect.left;
122+
final double y = rect.top;
123+
final double w = rect.width;
124+
final double h = rect.height;
125+
126+
final double wx = a * w;
127+
final double hx = c * h;
128+
final double rx = a * x + c * y;
129+
130+
final double wy = b * w;
131+
final double hy = d * h;
132+
final double ry = b * x + d * y;
133+
134+
double left = rx;
135+
double right = rx;
136+
if (wx < 0) {
137+
left += wx;
138+
} else {
139+
right += wx;
140+
}
141+
if (hx < 0) {
142+
left += hx;
143+
} else {
144+
right += hx;
145+
}
146+
147+
double top = ry;
148+
double bottom = ry;
149+
if (wy < 0) {
150+
top += wy;
151+
} else {
152+
bottom += wy;
153+
}
154+
if (hy < 0) {
155+
top += hy;
156+
} else {
157+
bottom += hy;
158+
}
159+
160+
return Rect.fromLTRB(left, top, right, bottom);
161+
}
162+
163+
/// Creates a typed data representatino of this matrix suitable for use with
164+
/// `package:vector_math_64` (and, by extension, Flutter/dart:ui).
165+
Float64List toMatrix4() {
166+
return Float64List.fromList(<double>[
167+
a, b, 0, 0, //
168+
c, d, 0, 0, //
169+
0, 0, _m4_10, 0, //
170+
e, f, 0, 1.0, //
171+
]);
172+
}
173+
174+
@override
175+
int get hashCode => Object.hash(a, b, c, d, e, f, _m4_10);
176+
177+
@override
178+
bool operator ==(Object other) {
179+
return other is AffineMatrix &&
180+
other.a == a &&
181+
other.b == b &&
182+
other.d == d &&
183+
other.e == e &&
184+
other._m4_10 == _m4_10;
185+
}
186+
187+
@override
188+
String toString() => '''
189+
[ $a, $c, $e ]
190+
[ $b, $d, $f ]
191+
[ 0.0, 0.0, 1.0 ]
192+
''';
193+
}

0 commit comments

Comments
 (0)