mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-26 10:47:11 -06:00
35 lines
1.3 KiB
Rust
35 lines
1.3 KiB
Rust
//! Warp effects: 15 envelope styles plus horizontal/vertical perspective distortion.
|
|
//!
|
|
//! Each style is a map on normalised box coordinates (x, y) ∈ [-1, 1]² (y down). The path is
|
|
//! split into short pieces whose control points are mapped (see `map_nonlinear`).
|
|
|
|
use serde_json::Value;
|
|
use vectorcraft_geom::{PathData, Point, Rect};
|
|
|
|
use crate::util::*;
|
|
|
|
pub use vectorcraft_doc::live::{WarpStyle, warp_point};
|
|
|
|
/// Apply a warp to `path` using box `b`.
|
|
pub fn warp(path: &PathData, b: Rect, style: WarpStyle, p: &Value) -> PathData {
|
|
let bend = num(p, "bend", 50.0).clamp(-100.0, 100.0) / 100.0;
|
|
let dh = num(p, "horizontal", 0.0).clamp(-100.0, 100.0) / 100.0;
|
|
let dv = num(p, "vertical", 0.0).clamp(-100.0, 100.0) / 100.0;
|
|
let vertical = text(p, "orientation", "horizontal").eq_ignore_ascii_case("vertical");
|
|
let c = b.center();
|
|
let hw = (b.width() / 2.0).max(1e-9);
|
|
let hh = (b.height() / 2.0).max(1e-9);
|
|
let f = |q: Point| {
|
|
let (x, y) = ((q.x - c.x) / hw, (q.y - c.y) / hh);
|
|
let (x2, y2) = if vertical {
|
|
let (a, b2) = warp_point(style, bend, dh, dv, y, x);
|
|
(b2, a)
|
|
} else {
|
|
warp_point(style, bend, dh, dv, x, y)
|
|
};
|
|
Point::new(c.x + x2 * hw, c.y + y2 * hh)
|
|
};
|
|
let piece = b.width().hypot(b.height()) / 24.0;
|
|
map_nonlinear(path, piece, f)
|
|
}
|