arc transformation fix
This commit is contained in:
parent
57348acc02
commit
65ebe6af69
3 changed files with 61 additions and 17 deletions
14
math.go
14
math.go
|
@ -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])
|
||||
}
|
||||
|
|
59
path2d.go
59
path2d.go
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
5
paths.go
5
paths.go
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue