135 lines
3.4 KiB
Dart
135 lines
3.4 KiB
Dart
import 'dart:math';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:vector_math/vector_math_64.dart';
|
|
|
|
extension PaintExtension on Paint {
|
|
void setAlpha(int alpha) {
|
|
color = color.withAlpha(alpha);
|
|
}
|
|
}
|
|
|
|
extension PathExtension on Path {
|
|
void set(Path path) {
|
|
reset();
|
|
addPath(path, Offset.zero);
|
|
}
|
|
|
|
void offset(Offset offset) {
|
|
set(shift(offset));
|
|
}
|
|
}
|
|
|
|
extension Matrix4Extension on Matrix4 {
|
|
void preConcat(Matrix4 matrix) {
|
|
multiply(matrix);
|
|
}
|
|
|
|
void reset() {
|
|
setIdentity();
|
|
}
|
|
|
|
void set(Matrix4 matrix) {
|
|
matrix.copyInto(this);
|
|
}
|
|
|
|
Rect mapRect(Rect rect) {
|
|
return MatrixUtils.transformRect(this, rect);
|
|
}
|
|
|
|
/// Apply this matrix to the array of 2D points, and write the transformed points back into the
|
|
/// array
|
|
///
|
|
/// @param pts The array [x0, y0, x1, y1, ...] of points to transform.
|
|
void mapPoints(List<double> array) {
|
|
for (var i = 0; i < array.length; i += 2) {
|
|
final v = MatrixUtils.transformPoint(
|
|
this,
|
|
Offset(array[i], array[i + 1]),
|
|
);
|
|
|
|
array[i] = v.dx;
|
|
array[i + 1] = v.dy;
|
|
}
|
|
}
|
|
|
|
double getScale() {
|
|
var p0 = Vector3(0, 0, 0)..applyMatrix4(this);
|
|
var p1 = Vector3(1 / sqrt(2), 1 / sqrt(2), 0)..applyMatrix4(this);
|
|
|
|
var dx = p1.x - p0.x;
|
|
var dy = p1.y - p0.y;
|
|
|
|
return hypot(dx, dy).toDouble();
|
|
}
|
|
|
|
bool get hasZeroScaleAxis {
|
|
var p0 = Vector3(0, 0, 0)..applyMatrix4(this);
|
|
// Random numbers. The only way these should map to the same thing as 0,0 is if the scale is 0.
|
|
var p1 = Vector3(37394.729378, 39575.2343807, 0)..applyMatrix4(this);
|
|
|
|
return p0.x == p1.x || p0.y == p1.y;
|
|
}
|
|
|
|
/// Sets this matrix to map `p -> (p - sourceRect.topLeft) * scale`,
|
|
/// i.e. crop to [sourceRect] and scale it to fit [destinationSize].
|
|
void setSourceToDestinationScale(Rect sourceRect, Size destinationSize) {
|
|
var scaleX = destinationSize.width / sourceRect.width;
|
|
var scaleY = destinationSize.height / sourceRect.height;
|
|
setIdentity();
|
|
translateByDouble(
|
|
-sourceRect.left * scaleX,
|
|
-sourceRect.top * scaleY,
|
|
0,
|
|
1,
|
|
);
|
|
scaleByDouble(scaleX, scaleY, scaleX, 1);
|
|
}
|
|
}
|
|
|
|
extension CanvasExtension on Canvas {
|
|
/// Applies `destinationRect.topLeft + (p - sourceRect.topLeft) * scale`
|
|
/// to subsequent drawing, i.e. positions and crops/scales a source rect
|
|
/// into a destination rect.
|
|
void applySourceToDestinationTransform(
|
|
Rect sourceRect,
|
|
Rect destinationRect,
|
|
) {
|
|
var scaleX = destinationRect.width / sourceRect.width;
|
|
var scaleY = destinationRect.height / sourceRect.height;
|
|
translate(destinationRect.left, destinationRect.top);
|
|
scale(scaleX, scaleY);
|
|
translate(-sourceRect.left, -sourceRect.top);
|
|
}
|
|
}
|
|
|
|
extension OffsetExtension on Offset {
|
|
bool get isZero => dx == 0 && dy == 0;
|
|
}
|
|
|
|
num hypot(num x, num y) {
|
|
return sqrt(x * x + y * y);
|
|
}
|
|
|
|
extension IterableExtension<T> on Iterable<T> {
|
|
T? firstWhereOrNull(bool Function(T element) test) {
|
|
for (var element in this) {
|
|
if (test(element)) return element;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
class ListEquality<E> {
|
|
const ListEquality();
|
|
|
|
bool equals(List<E>? list1, List<E>? list2) {
|
|
if (identical(list1, list2)) return true;
|
|
if (list1 == null || list2 == null) return false;
|
|
var length = list1.length;
|
|
if (length != list2.length) return false;
|
|
for (var i = 0; i < length; i++) {
|
|
if (list1[i] != list2[i]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|