///|
pub fn Matrix::map_point(self : Matrix, point : Point) -> Point {
let x = self.scale_x * point.x + self.skew_x * point.y + self.trans_x
let y = self.skew_y * point.x + self.scale_y * point.y + self.trans_y
let z = self.persp_0 * point.x + self.persp_1 * point.y + self.persp_2
if z == 0 || z == 1 {
Point::new(x, y)
} else {
Point::new(x / z, y / z)
}
}
///|
pub fn Matrix::map_xy(self : Matrix, x : Scalar, y : Scalar) -> Point {
self.map_point(Point::new(x, y))
}
///|
pub fn Matrix::map_origin(self : Matrix) -> Point {
self.map_xy(0, 0)
}
///|
pub fn Matrix::map_point_affine(self : Matrix, point : Point) -> Point? {
if self.has_perspective() {
None
} else {
Some(
Point::new(
self.scale_x * point.x + self.skew_x * point.y + self.trans_x,
self.skew_y * point.x + self.scale_y * point.y + self.trans_y,
),
)
}
}
///|
pub fn Matrix::map_points(self : Matrix, points : Array[Point]) -> Array[Point] {
points.map(fn(point) { self.map_point(point) })
}
///|
pub fn Matrix::map_vector(self : Matrix, vector : Point) -> Point {
Matrix::new_all(
self.scale_x,
self.skew_x,
0,
self.skew_y,
self.scale_y,
0,
self.persp_0,
self.persp_1,
self.persp_2,
).map_point(vector)
}
///|
pub fn Matrix::map_vectors(
self : Matrix,
vectors : Array[Point],
) -> Array[Point] {
vectors.map(fn(vector) { self.map_vector(vector) })
}
///|
pub fn Matrix::map_radius(self : Matrix, radius : Scalar) -> Scalar? {
if self.has_perspective() ||
!self.is_finite() ||
!geometry_scalar_is_finite(radius) {
None
} else {
let area_scale = self.scale_x * self.scale_y - self.skew_x * self.skew_y
let area_scale = if area_scale < 0 { -area_scale } else { area_scale }
let radius = radius * area_scale.sqrt()
if geometry_scalar_is_finite(radius) {
Some(radius)
} else {
None
}
}
}
///|
pub fn Matrix::map_rect_to_quad(self : Matrix, rect : Rect) -> Array[Point] {
let rect = rect.sorted()
[
self.map_point(Point::new(rect.left, rect.top)),
self.map_point(Point::new(rect.right, rect.top)),
self.map_point(Point::new(rect.right, rect.bottom)),
self.map_point(Point::new(rect.left, rect.bottom)),
]
}
///|
pub fn Matrix::map_rect_scale_translate(self : Matrix, rect : Rect) -> Rect? {
if self.is_scale_translate() {
Some(
Rect::new(
rect.left * self.scale_x + self.trans_x,
rect.top * self.scale_y + self.trans_y,
rect.right * self.scale_x + self.trans_x,
rect.bottom * self.scale_y + self.trans_y,
).sorted(),
)
} else {
None
}
}
///|
pub fn Matrix::map_rect(self : Matrix, rect : Rect) -> Rect {
let rect = rect.sorted()
if rect.is_empty() {
Rect::empty()
} else {
let p0 = self.map_point(Point::new(rect.left, rect.top))
let p1 = self.map_point(Point::new(rect.right, rect.top))
let p2 = self.map_point(Point::new(rect.right, rect.bottom))
let p3 = self.map_point(Point::new(rect.left, rect.bottom))
Rect::new(
Float::min(Float::min(p0.x, p1.x), Float::min(p2.x, p3.x)),
Float::min(Float::min(p0.y, p1.y), Float::min(p2.y, p3.y)),
Float::max(Float::max(p0.x, p1.x), Float::max(p2.x, p3.x)),
Float::max(Float::max(p0.y, p1.y), Float::max(p2.y, p3.y)),
)
}
}