///|
/// Builds a transform from a design-friendly set of parameters.
pub(all) struct TransformSpec {
position : Vec2
scale : Vec2
rotation : Double
pivot : Vec2
} derive(Eq, Debug, ToJson)
///|
pub fn TransformSpec::new(position : Vec2) -> TransformSpec {
{ position, scale: Vec2::new(1.0, 1.0), rotation: 0.0, pivot: Vec2::zero() }
}
///|
pub fn TransformSpec::matrix(self : TransformSpec) -> Matrix2D {
Matrix2D::translate(self.position.x, self.position.y)
.multiply(Matrix2D::translate(self.pivot.x, self.pivot.y))
.multiply(Matrix2D::rotate(self.rotation))
.multiply(Matrix2D::scale(self.scale.x, self.scale.y))
.multiply(Matrix2D::translate(-self.pivot.x, -self.pivot.y))
}
///|
pub fn TransformSpec::at(
self : TransformSpec,
position : Vec2,
) -> TransformSpec {
{ ..self, position, }
}
///|
pub fn TransformSpec::scaled(
self : TransformSpec,
scale : Vec2,
) -> TransformSpec {
{ ..self, scale, }
}
///|
pub fn TransformSpec::rotated(
self : TransformSpec,
rotation : Double,
) -> TransformSpec {
{ ..self, rotation, }
}
///|
pub fn TransformSpec::around(
self : TransformSpec,
pivot : Vec2,
) -> TransformSpec {
{ ..self, pivot, }
}
///|
pub fn map_motifs(
motifs : Array[Motif],
transform : TransformSpec,
) -> Array[Motif] {
let result = []
let matrix = transform.matrix()
for motif in motifs {
let (x, y) = matrix.transform_point(motif.anchor.x, motif.anchor.y)
result.push(
motif.placed(x, y, motif.scale, motif.rotation + transform.rotation),
)
}
result
}
///|
pub fn transform_path_about(
path : Path,
center : Vec2,
scale : Double,
rotation : Double,
) -> Path {
let matrix = Matrix2D::translate(center.x, center.y)
.multiply(Matrix2D::rotate(rotation))
.multiply(Matrix2D::scale(scale, scale))
.multiply(Matrix2D::translate(-center.x, -center.y))
path.transform(matrix)
}
///|
pub fn fit_rect(source : Rect, target : Rect, contain : Bool) -> Matrix2D {
let sx = target.width / source.width
let sy = target.height / source.height
let scale = if contain { sx.min(sy) } else { sx.max(sy) }
let source_center = source.center()
let target_center = target.center()
Matrix2D::translate(target_center.x, target_center.y)
.multiply(Matrix2D::scale(scale, scale))
.multiply(Matrix2D::translate(-source_center.x, -source_center.y))
}
///|
pub fn fit_points(
points : Array[Vec2],
target : Rect,
contain : Bool,
) -> Array[Vec2] {
let source = bounds_of_points(points)
transform_points(points, fit_rect(source, target, contain))
}
///|
pub fn cascade_transforms(
base : Matrix2D,
transforms : Array[Matrix2D],
) -> Array[Matrix2D] {
let result = []
let mut current = base
for transform in transforms {
current = current.multiply(transform)
result.push(current)
}
result
}