arc transformation fix

This commit is contained in:
Thomas Friedel 2019-02-21 11:03:38 +01:00
parent 57348acc02
commit 65ebe6af69
3 changed files with 61 additions and 17 deletions

14
math.go
View file

@ -34,6 +34,10 @@ func (v vec) mulMat(m mat) (vec, float64) {
m[2]*v[0] + m[5]*v[1] + m[8]
}
func (v vec) mulMat2(m mat2) vec {
return vec{m[0]*v[0] + m[2]*v[1], m[1]*v[0] + m[3]*v[1]}
}
func (v1 vec) div(v2 vec) vec {
return vec{v1[0] / v2[0], v1[1] / v2[1]}
}
@ -139,3 +143,13 @@ func (m mat) f32() [9]float32 {
float32(m[3]), float32(m[4]), float32(m[5]),
float32(m[6]), float32(m[7]), float32(m[8])}
}
func (m mat) mat2() mat2 {
return mat2{m[0], m[1], m[3], m[4]}
}
type mat2 [4]float64
func (m *mat2) String() string {
return fmt.Sprintf("[%f,%f,\n %f,%f]", m[0], m[2], m[1], m[3])
}

View file

@ -1,6 +1,8 @@
package canvas
import "math"
import (
"math"
)
type Path2D struct {
p []pathPoint
@ -113,27 +115,43 @@ func (p *Path2D) Arc(x, y, radius, startAngle, endAngle float64, anticlockwise b
lastWasMove := len(p.p) == 0 || p.p[len(p.p)-1].flags&pathMove != 0
startAngle = math.Mod(startAngle, math.Pi*2)
if startAngle < 0 {
startAngle += math.Pi * 2
if endAngle == startAngle {
s, c := math.Sincos(endAngle)
p.lineTo(x+radius*c, y+radius*s, checkSelfIntersection)
if lastWasMove {
p.p[len(p.p)-1].flags |= pathIsConvex
}
endAngle = math.Mod(endAngle, math.Pi*2)
if endAngle < 0 {
endAngle += math.Pi * 2
return
}
if !anticlockwise && endAngle <= startAngle {
endAngle += math.Pi * 2
} else if anticlockwise && endAngle >= startAngle {
endAngle -= math.Pi * 2
if (!anticlockwise && endAngle < startAngle) || (anticlockwise && endAngle > startAngle) {
endAngle, startAngle = startAngle, endAngle
}
const step = math.Pi * 2 / 360
if anticlockwise {
for a := startAngle; a > endAngle; a -= step {
if !anticlockwise {
diff := endAngle - startAngle
if diff >= math.Pi*4 {
diff = math.Mod(diff, math.Pi*2) + math.Pi*2
endAngle = startAngle + diff
}
} else {
diff := startAngle - endAngle
if diff >= math.Pi*4 {
diff = math.Mod(diff, math.Pi*2)
endAngle = startAngle - diff
}
}
const step = math.Pi * 2 / 90
if !anticlockwise {
for a := startAngle; a < endAngle; a += step {
s, c := math.Sincos(a)
p.lineTo(x+radius*c, y+radius*s, checkSelfIntersection)
}
} else {
for a := startAngle; a < endAngle; a += step {
for a := startAngle; a > endAngle; a -= step {
s, c := math.Sincos(a)
p.lineTo(x+radius*c, y+radius*s, checkSelfIntersection)
}
@ -159,7 +177,7 @@ func (p *Path2D) ArcTo(x1, y1, x2, y2, radius float64) {
p.LineTo(x2, y2)
return
}
// cv are the vectors orthogonal to the lines that point to the center of the circle
// cv0 and cv1 are vectors that point to the center of the circle
cv0 := vec{-v0[1], v0[0]}
cv1 := vec{v1[1], -v1[0]}
x := cv1.sub(cv0).div(v0.sub(v1))[0] * radius
@ -169,6 +187,15 @@ func (p *Path2D) ArcTo(x1, y1, x2, y2, radius float64) {
}
center := p1.add(v0.mulf(math.Abs(x))).add(cv0.mulf(radius))
a0, a1 := cv0.mulf(-1).atan2(), cv1.mulf(-1).atan2()
if x > 0 {
if a1-a0 > 0 {
a0 += math.Pi * 2
}
} else {
if a0-a1 > 0 {
a1 += math.Pi * 2
}
}
p.Arc(center[0], center[1], radius, a0, a1, x > 0)
}

View file

@ -34,7 +34,10 @@ func (cv *Canvas) LineTo(x, y float64) {
// means that the line is added anticlockwise
func (cv *Canvas) Arc(x, y, radius, startAngle, endAngle float64, anticlockwise bool) {
tf := cv.tf(vec{x, y})
cv.path.Arc(tf[0], tf[1], radius, startAngle, endAngle, anticlockwise)
ax, ay := math.Sincos(startAngle)
startAngle2 := vec{ay, ax}.mulMat2(cv.state.transform.mat2()).atan2()
endAngle2 := startAngle2 + (endAngle - startAngle)
cv.path.Arc(tf[0], tf[1], radius, startAngle2, endAngle2, anticlockwise)
}
// ArcTo adds to the current path by drawing a line toward x1/y1 and a circle