///|
/// Applies a transform to every point in a point cloud.
pub fn transform_points(points : Array[Vec2], matrix : Matrix2D) -> Array[Vec2] {
let result = []
for point in points {
let (x, y) = matrix.transform_point(point.x, point.y)
result.push(Vec2::new(x, y))
}
result
}
///|
/// Creates a translated shadow copy of a motif.
pub fn drop_shadow(
motif : Motif,
offset : Vec2,
color : Color,
opacity : Double,
) -> Motif {
let shadow_style = SvgStyle::new(fill=color.to_hex(), stroke="none", opacity~)
Motif::new(motif.name + "-shadow", motif.path, shadow_style).placed(
motif.anchor.x + offset.x,
motif.anchor.y + offset.y,
motif.scale,
motif.rotation,
)
}
///|
/// Creates a set of concentric outline copies to simulate a glow.
pub fn glow_motifs(
motif : Motif,
layers : Int,
spread : Double,
color : Color,
) -> Array[Motif] {
let result = []
for i in 1..<=layers {
let amount = i.to_double() / layers.to_double()
let style = SvgStyle::new(
fill="none",
stroke=color.to_hex(),
stroke_width=spread * amount,
opacity=(1.0 - amount) * motif.style.opacity,
)
result.push(
Motif::new(motif.name + "-glow-{i}", motif.path, style).placed(
motif.anchor.x,
motif.anchor.y,
motif.scale + amount * 0.03,
motif.rotation,
),
)
}
result
}
///|
/// Interpolates two paths when they have matching segment shapes.
pub fn interpolate_paths(left : Path, right : Path, amount : Double) -> Path {
let result = Path::new()
let count = if left.segments.length() < right.segments.length() {
left.segments.length()
} else {
right.segments.length()
}
for i in 0.. {
let _ = result.move_to(
animate_double(x1, x2, amount),
animate_double(y1, y2, amount),
)
}
(LineTo(x1, y1), LineTo(x2, y2)) => {
let _ = result.line_to(
animate_double(x1, x2, amount),
animate_double(y1, y2, amount),
)
}
(QuadTo(x1~, y1~, x~, y~), QuadTo(x1=x2, y1=y2, x=x3, y=y3)) => {
let _ = result.quad_to(
animate_double(x1, x2, amount),
animate_double(y1, y2, amount),
animate_double(x, x3, amount),
animate_double(y, y3, amount),
)
}
(
CubicTo(x1~, y1~, x2~, y2~, x~, y~),
CubicTo(x1=a1, y1=b1, x2=a2, y2=b2, x=a3, y=a4),
) => {
let _ = result.cubic_to(
animate_double(x1, a1, amount),
animate_double(y1, b1, amount),
animate_double(x2, a2, amount),
animate_double(y2, b2, amount),
animate_double(x, a3, amount),
animate_double(y, a4, amount),
)
}
(ClosePath, ClosePath) => {
let _ = result.close()
}
(MoveTo(x, y), _) => {
let _ = result.move_to(x, y)
}
(_, LineTo(x, y)) => {
let _ = result.line_to(x, y)
}
_ => ()
}
}
result
}
///|
/// Repeats a motif with a rotation and scale progression.
pub fn spiral_motifs(
motif : Motif,
count : Int,
angle_step : Double,
scale_step : Double,
) -> Array[Motif] {
let result = []
for i in 0..