Skip to content

Commit bdf10bd

Browse files
authored
Merge pull request #95 from raphlinus/simplify
Simplifying Bézier paths
2 parents 3d05e69 + 285df34 commit bdf10bd

16 files changed

Lines changed: 1518 additions & 0 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
_site
22
.sass-cache
33
.jekyll-metadata
4+
target/
5+

_figures/simplify_figs/Cargo.lock

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

_figures/simplify_figs/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "simplify_figs"
3+
license = "Apache-2.0"
4+
version = "0.1.0"
5+
edition = "2021"
6+
7+
[dependencies]
8+
kurbo = "0.9.2"

_figures/simplify_figs/src/main.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2022 the raphlinus.github.io Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//! Program to generate figures for "Simplifying Bézier paths" blog. Run with
5+
//! figure type ("th" or "arc"), generates svg file as stdout.
6+
7+
use kurbo::{CubicBez, ParamCurve, ParamCurveArclen, ParamCurveDeriv, Point, Shape, Vec2};
8+
use kurbo::common::solve_cubic;
9+
10+
fn intersect(c: CubicBez, p: Point, tangent: Vec2) -> Vec<f64> {
11+
let p1 = 3.0 * (c.p1 - c.p0);
12+
let p2 = 3.0 * c.p2.to_vec2() - 6.0 * c.p1.to_vec2() + 3.0 * c.p0.to_vec2();
13+
let p3 = (c.p3 - c.p0) - 3.0 * (c.p2 - c.p1);
14+
let c0 = (c.p0 - p).dot(tangent);
15+
let c1 = p1.dot(tangent);
16+
let c2 = p2.dot(tangent);
17+
let c3 = p3.dot(tangent);
18+
solve_cubic(c0, c1, c2, c3)
19+
.into_iter()
20+
.filter(|t| (0.0..=1.0).contains(t))
21+
.collect()
22+
}
23+
24+
25+
fn main() {
26+
let fig = std::env::args().skip(1).next().expect("need figure type");
27+
let c1 = CubicBez::new((10., 150.), (300., 150.), (310., 150.), (310., 450.));
28+
let a: f64 = if fig == "arc2" { 40. } else { 400. };
29+
let c2 = CubicBez::new((10., 150.), (300. + a, 150.), (310., 150. - a), (310., 450.));
30+
let arclen = c1.arclen(1e-9);
31+
let arclen2 = c2.arclen(1e-9);
32+
println!("<svg width='450' height='480' xmlns='http://www.w3.org/2000/svg'>");
33+
println!(" <!-- figure generated by simplify_figs program in _figures subdir -->");
34+
println!(" <path d='{}' stroke='#000' fill='none'/>", c1.into_path(1e-9).to_svg());
35+
println!(" <path d='{}' stroke='#000' fill='none'/>", c2.into_path(1e-9).to_svg());
36+
const N: usize = 11;
37+
for i in 1..N {
38+
let s = (i as f64 / N as f64) * arclen;
39+
let t = c1.inv_arclen(s, 1e-9);
40+
let p = c1.eval(t);
41+
println!(" <circle cx='{}' cy='{}' r='2' fill='#008'/>", p.x, p.y);
42+
let t2;
43+
if fig == "th" {
44+
let d = c1.deriv().eval(t);
45+
let t2s = intersect(c2, p, d.to_vec2());
46+
t2 = t2s[0];
47+
} else {
48+
let s2 = (i as f64 / N as f64) * arclen2;
49+
t2 = c2.inv_arclen(s2, 1e-9);
50+
}
51+
let p2 = c2.eval(t2);
52+
if fig != "th" {
53+
println!(" <circle cx='{}' cy='{}' r='2' fill='#008'/>", p2.x, p2.y);
54+
}
55+
println!(" <line x1='{}' y1='{}' x2='{}' y2='{}' stroke='#000'/>",
56+
p.x, p.y, p2.x, p2.y);
57+
}
58+
println!("</svg>");
59+
}

_posts/2023-04-18-bezpath-simplify.md

Lines changed: 129 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)