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>
This commit is contained in:
Egon Elbre
2022-03-12 14:11:56 +02:00
committed by Elias Naur
parent 99f6224eb7
commit 3fd231367f
6 changed files with 16 additions and 7 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 B

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 B

After

Width:  |  Height:  |  Size: 692 B

+15 -4
View File
@@ -91,9 +91,8 @@ func (qs *StrokeQuads) lineTo(pt f32.Point) {
}
func (qs *StrokeQuads) arc(f1, f2 f32.Point, angle float32) {
const segments = 16
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++ {
p0 := qs.pen()
p1 := m.Transform(p0)
@@ -546,7 +545,19 @@ func strokePathRoundCap(qs *StrokeQuads, hw float32, pivot, n0 f32.Point) {
// cubic Bezier curves", L. Maisonobe
// An electronic version may be found at:
// 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
if f1 == f2 {
// 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
// to a frame centered to the ellipse (and warped into a unit circle), then rotate.
// 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 {
+1 -3
View File
@@ -286,9 +286,7 @@ func (p *Path) QuadTo(ctrl, to f32.Point) {
// The sign of angle determines the direction; positive being counter-clockwise,
// negative clockwise.
func (p *Path) ArcTo(f1, f2 f32.Point, angle float32) {
const segments = 16
m := stroke.ArcTransform(p.pen, f1, f2, angle, segments)
m, segments := stroke.ArcTransform(p.pen, f1, f2, angle)
for i := 0; i < segments; i++ {
p0 := p.pen
p1 := m.Transform(p0)