1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
// Copyright ©2013 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package bezier implements 2D Bézier curve calculation.
package bezier // import "gonum.org/v1/plot/tools/bezier"
import "gonum.org/v1/plot/vg"
type point struct {
Point, Control vg.Point
}
// Curve implements Bezier curve calculation according to the algorithm of Robert D. Miller.
//
// Graphics Gems 5, 'Quick and Simple Bézier Curve Drawing', pages 206-209.
type Curve []point
// NewCurve returns a Curve initialized with the control points in cp.
func New(cp ...vg.Point) Curve {
if len(cp) == 0 {
return nil
}
c := make(Curve, len(cp))
for i, p := range cp {
c[i].Point = p
}
var w vg.Length
for i, p := range c {
switch i {
case 0:
w = 1
case 1:
w = vg.Length(len(c)) - 1
default:
w *= vg.Length(len(c)-i) / vg.Length(i)
}
c[i].Control.X = p.Point.X * w
c[i].Control.Y = p.Point.Y * w
}
return c
}
// Point returns the point at t along the curve, where 0 ≤ t ≤ 1.
func (c Curve) Point(t float64) vg.Point {
c[0].Point = c[0].Control
u := t
for i, p := range c[1:] {
c[i+1].Point = vg.Point{p.Control.X * vg.Length(u), p.Control.Y * vg.Length(u)}
u *= t
}
var (
t1 = 1 - t
tt = t1
)
p := c[len(c)-1].Point
for i := len(c) - 2; i >= 0; i-- {
p.X += c[i].Point.X * vg.Length(tt)
p.Y += c[i].Point.Y * vg.Length(tt)
tt *= t1
}
return p
}
// Curve returns a slice of vg.Point, p, filled with points along the Bézier curve described by c.
// If the length of p is less than 2, the curve points are undefined. The length of p is not
// altered by the call.
func (c Curve) Curve(p []vg.Point) []vg.Point {
for i, nf := 0, float64(len(p)-1); i < len(p); i++ {
p[i] = c.Point(float64(i) / nf)
}
return p
}
|