internal/stroke: optimize arc drawing
Arc with a small angle doesn't need many segments. Updates: https://todo.sr.ht/~eliasnaur/gio/313 Signed-off-by: Egon Elbre <egonelbre@gmail.com>
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 390 B After Width: | Height: | Size: 692 B |
|
Before Width: | Height: | Size: 390 B After Width: | Height: | Size: 692 B |
@@ -91,9 +91,8 @@ func (qs *StrokeQuads) lineTo(pt f32.Point) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (qs *StrokeQuads) arc(f1, f2 f32.Point, angle float32) {
|
func (qs *StrokeQuads) arc(f1, f2 f32.Point, angle float32) {
|
||||||
const segments = 16
|
|
||||||
pen := qs.pen()
|
pen := qs.pen()
|
||||||
m := ArcTransform(pen, f1.Add(pen), f2.Add(pen), angle, segments)
|
m, segments := ArcTransform(pen, f1.Add(pen), f2.Add(pen), angle)
|
||||||
for i := 0; i < segments; i++ {
|
for i := 0; i < segments; i++ {
|
||||||
p0 := qs.pen()
|
p0 := qs.pen()
|
||||||
p1 := m.Transform(p0)
|
p1 := m.Transform(p0)
|
||||||
@@ -546,7 +545,19 @@ func strokePathRoundCap(qs *StrokeQuads, hw float32, pivot, n0 f32.Point) {
|
|||||||
// cubic Bezier curves", L. Maisonobe
|
// cubic Bezier curves", L. Maisonobe
|
||||||
// An electronic version may be found at:
|
// An electronic version may be found at:
|
||||||
// http://spaceroots.org/documents/ellipse/elliptical-arc.pdf
|
// http://spaceroots.org/documents/ellipse/elliptical-arc.pdf
|
||||||
func ArcTransform(p, f1, f2 f32.Point, angle float32, segments int) f32.Affine2D {
|
func ArcTransform(p, f1, f2 f32.Point, angle float32) (transform f32.Affine2D, segments int) {
|
||||||
|
const segmentsPerCircle = 16
|
||||||
|
const anglePerSegment = 2 * math.Pi / segmentsPerCircle
|
||||||
|
|
||||||
|
s := angle / anglePerSegment
|
||||||
|
if s < 0 {
|
||||||
|
s = -s
|
||||||
|
}
|
||||||
|
segments = int(math.Ceil(float64(s)))
|
||||||
|
if segments <= 0 {
|
||||||
|
segments = 1
|
||||||
|
}
|
||||||
|
|
||||||
var rx, ry, alpha float64
|
var rx, ry, alpha float64
|
||||||
if f1 == f2 {
|
if f1 == f2 {
|
||||||
// degenerate case of a circle.
|
// degenerate case of a circle.
|
||||||
@@ -605,7 +616,7 @@ func ArcTransform(p, f1, f2 f32.Point, angle float32, segments int) f32.Affine2D
|
|||||||
// Before applying the rotation matrix rot, transform the coordinates
|
// Before applying the rotation matrix rot, transform the coordinates
|
||||||
// to a frame centered to the ellipse (and warped into a unit circle), then rotate.
|
// to a frame centered to the ellipse (and warped into a unit circle), then rotate.
|
||||||
// Finally, transform back into the original frame.
|
// Finally, transform back into the original frame.
|
||||||
return inv.Mul(rot).Mul(ref)
|
return inv.Mul(rot).Mul(ref), segments
|
||||||
}
|
}
|
||||||
|
|
||||||
func dist(p1, p2 f32.Point) float64 {
|
func dist(p1, p2 f32.Point) float64 {
|
||||||
|
|||||||
@@ -286,9 +286,7 @@ func (p *Path) QuadTo(ctrl, to f32.Point) {
|
|||||||
// The sign of angle determines the direction; positive being counter-clockwise,
|
// The sign of angle determines the direction; positive being counter-clockwise,
|
||||||
// negative clockwise.
|
// negative clockwise.
|
||||||
func (p *Path) ArcTo(f1, f2 f32.Point, angle float32) {
|
func (p *Path) ArcTo(f1, f2 f32.Point, angle float32) {
|
||||||
const segments = 16
|
m, segments := stroke.ArcTransform(p.pen, f1, f2, angle)
|
||||||
m := stroke.ArcTransform(p.pen, f1, f2, angle, segments)
|
|
||||||
|
|
||||||
for i := 0; i < segments; i++ {
|
for i := 0; i < segments; i++ {
|
||||||
p0 := p.pen
|
p0 := p.pen
|
||||||
p1 := m.Transform(p0)
|
p1 := m.Transform(p0)
|
||||||
|
|||||||