Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new hyperbezier math #28

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ name = "spline"
version = "0.3.0"
license = "MIT/Apache-2.0"
authors = ["Raph Levien <[email protected]>"]
edition = "2018"
edition = "2021"
keywords = ["graphics", "curve", "curves", "bezier", "spline"]
repository = "https://github.com/linebender/spline"
description = "A spline for interactive 2D curve design"
readme = "README.md"
categories = ["graphics"]

[dependencies]
kurbo = "0.9"
kurbo = "0.11"
serde_ = { version = "1.0.117", package="serde", features = ["derive"], optional = true }

[dev-dependencies]
Expand Down
24 changes: 17 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,32 @@ This crate implements a new spline designed and optimized for interactive design

The work builds on previous iterations, notably the [Spiro] spline, and then another [research spline].

## Hyperbeziers
## Status: in transition

The major innovation of this spline is the "hyperbezier" curve family. Like cubic Béziers and the Spiro curve, it is a four-parameter curve family. In fact, it's closely based on Spiro and there is significant overlap of the parameter space, including Euler spirals.
This crate is in transition from supporting the first draft of hyperbeziers to the second. The first draft had a reasonably clean mapping from Bézier control points to curve parameters (something still in progress for the second), but a number of shortcomings:

There is a significant difference, however. In the Spiro curve family, curvature is bounded, so it is not capable of cusp-like behavior. Rather, when "pushed," Spiro tends to wiggly, Shmoo-like shapes. Béziers are of course capable of high curvature regions, as are elastica when placed under very high tension.
* It was not closed under subdivision

A good way to parametrize the hyperbezier is by tangent angle and "tension," which correlates strongly with curvature at the endpoint. At low tension, the hyperbezier is equivalent to the Spiro curve. A natural tension value produces the Euler spiral (curvature is a linear function of arclength). But for higher tension values, a different function takes over, which approaches a cusp at the endpoint as tension increases.
* It was not capable of superellipse-like shapes

Unlike Béziers, the cusp happens *only* at the endpoint. Curvature maxima in the interior of a curve are ugly. With the hyperbezier, if the designer wants a sharp curvature maximum, simply place an on-curve point there.
* The shape when high tension on one side and low tension on the other was lumpy, with an undesirable curvature minimum

A particular strength of the hyperbezier is smooth (G2-continuous) transitions from straight to curved sections. The hyperbezier is capable (unlike a cubic Bézier) of an S-shaped curve with zero curvature at both ends. It's also capable of a wide range of Euler spiral like behavior where one end has zero curvature and the other is a nice rounded shape (in the general case a designer would use at least two Béziers to create this effect).
The new hyperbezier addresses all these problems.

The name "hyperbezier" clearly references its roots in the [cubic Bézier][A Primer on Bézier Curves], and the "hyper" part is a reference to the fact that the Euler spiral, an important section of its parameter space, is an instance of the [Hypergeometric function].
## Hyperbeziers

The major innovation of this spline is the "hyperbezier" curve family. Like cubic Béziers and the Spiro curve, it is a four-parameter curve family. In fact, it's based on Spiro and there is significant overlap of the parameter space, including Euler spirals.

There is a significant difference, however. In the Spiro curve family, curvature is bounded, so it is not capable of cusp-like behavior. Rather, when "pushed," Spiro tends to wiggly, Shmoo-like shapes. Béziers are of course capable of high curvature regions, as are elastica when placed under very high tension.

A good way to parametrize the hyperbezier is by tangent angle and "tension," which correlates strongly with curvature at the endpoint. At low tension, the hyperbezier has similar behavior to the Spiro curve. A natural tension value produces the Euler spiral (curvature is a linear function of arclength). But for higher tension values, curvature rises more sharply near the endpoints. In addition, the hyperbezier has a region of parameter space which produces curves resembling hyperbolas (also usable as a quadrant of a superellipse-like shape).

The name "hyperbezier" references its roots in the [cubic Bézier][A Primer on Bézier Curves], and the "hyper" part is a reference to the fact that the Euler spiral, an important section of its parameter space, is an instance of the [Hypergeometric function]. Additionally, the "hyper" can be seen as a reference to hyperbola-like shapes, which it approximates and a cubic Bézier cannot.

## Focus on UX

Status: this section may be revised, as the new hyperbezier has not yet been hooked up to an interactive example.

A persistent challenge with spline-based curve design is getting the UX right. Bézier curves are not easy to master, but the [pen tool] has become highly refined over time, and is an extremely productive interface for designers. A major motivation for this work is to retain the good parts of the Bézier UX.

In particular, the "control handle" maps to hyperbezier parameters in a natural, intuitive way. The tangent angle is obvious, and tension similarly dependent on the length of the control arm. So it's completely valid to use hyperbeziers simply as a drop-in replacement for Béziers.
Expand Down
14 changes: 14 additions & 0 deletions examples/hyperbez.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use kurbo::{fit_to_bezpath, ParamCurve, Point};
use spline::hyperbezier::{HyperbezParams, Hyperbezier};

fn main() {
let params = HyperbezParams::new(-10., 5., 2.0, -2.0);
let p0 = Point::new(100., 100.);
let p1 = Point::new(300., 200.);
let hb = Hyperbezier::from_points_params(params, p0, p1);
println!("{hb:?}");
let p = fit_to_bezpath(&hb, 1.0);
println!("{}", p.to_svg());
let p = fit_to_bezpath(&hb.subsegment(0.1 .. 0.8), 1.0);
println!("{}", p.to_svg());
}
Loading