fixed Arc and ArcTo scaling

This commit is contained in:
Thomas Friedel 2020-02-11 10:59:55 +01:00
parent 50c77477c9
commit 259bb9e598
4 changed files with 42 additions and 20 deletions

View file

@ -141,7 +141,7 @@ func New(backend backendbase.Backend) *Canvas {
cv.state.globalAlpha = 1
cv.state.fill.color = color.RGBA{A: 255}
cv.state.stroke.color = color.RGBA{A: 255}
cv.state.transform = matIdentity()
cv.state.transform = matIdentity
cv.path.cv = cv
return cv
}
@ -395,7 +395,7 @@ func (cv *Canvas) Restore() {
cv.b.ClearClip()
for _, st := range cv.stateStack {
if len(st.clip.p) > 0 {
cv.clip(&st.clip, matIdentity())
cv.clip(&st.clip, matIdentity)
}
}
cv.state = cv.stateStack[l-1]

View file

@ -79,12 +79,10 @@ func (m *mat) String() string {
return fmt.Sprintf("[%f,%f,0,\n %f,%f,0,\n %f,%f,1,]", m[0], m[2], m[4], m[1], m[3], m[5])
}
func matIdentity() mat {
return mat{
var matIdentity = mat{
1, 0,
0, 1,
0, 0}
}
func matTranslate(v vec) mat {
return mat{

View file

@ -114,13 +114,21 @@ func (p *Path2D) lineTo(x, y float64, checkSelfIntersection bool) {
// Arc (see equivalent function on canvas type)
func (p *Path2D) Arc(x, y, radius, startAngle, endAngle float64, anticlockwise bool) {
p.arc(x, y, radius, startAngle, endAngle, anticlockwise, matIdentity, true)
}
func (p *Path2D) arc(x, y, radius, startAngle, endAngle float64, anticlockwise bool, m mat, ident bool) {
checkSelfIntersection := len(p.p) > 0
lastWasMove := len(p.p) == 0 || p.p[len(p.p)-1].flags&pathMove != 0
if endAngle == startAngle {
s, c := math.Sincos(endAngle)
p.lineTo(x+radius*c, y+radius*s, checkSelfIntersection)
pt := vec{x + radius*c, y + radius*s}
if !ident {
pt = pt.mulMat(m)
}
p.lineTo(pt[0], pt[1], checkSelfIntersection)
if lastWasMove {
p.p[len(p.p)-1].flags |= pathIsConvex
@ -153,16 +161,28 @@ func (p *Path2D) Arc(x, y, radius, startAngle, endAngle float64, anticlockwise b
if !anticlockwise {
for a := startAngle; a < endAngle; a += step {
s, c := math.Sincos(a)
p.lineTo(x+radius*c, y+radius*s, checkSelfIntersection)
pt := vec{x + radius*c, y + radius*s}
if !ident {
pt = pt.mulMat(m)
}
p.lineTo(pt[0], pt[1], checkSelfIntersection)
}
} else {
for a := startAngle; a > endAngle; a -= step {
s, c := math.Sincos(a)
p.lineTo(x+radius*c, y+radius*s, checkSelfIntersection)
pt := vec{x + radius*c, y + radius*s}
if !ident {
pt = pt.mulMat(m)
}
p.lineTo(pt[0], pt[1], checkSelfIntersection)
}
}
s, c := math.Sincos(endAngle)
p.lineTo(x+radius*c, y+radius*s, checkSelfIntersection)
pt := vec{x + radius*c, y + radius*s}
if !ident {
pt = pt.mulMat(m)
}
p.lineTo(pt[0], pt[1], checkSelfIntersection)
if lastWasMove {
p.p[len(p.p)-1].flags |= pathIsConvex
@ -171,10 +191,17 @@ func (p *Path2D) Arc(x, y, radius, startAngle, endAngle float64, anticlockwise b
// ArcTo (see equivalent function on canvas type)
func (p *Path2D) ArcTo(x1, y1, x2, y2, radius float64) {
p.arcTo(x1, y1, x2, y2, radius, matIdentity, true)
}
func (p *Path2D) arcTo(x1, y1, x2, y2, radius float64, m mat, ident bool) {
if len(p.p) == 0 {
return
}
p0, p1, p2 := p.p[len(p.p)-1].pos, vec{x1, y1}, vec{x2, y2}
if !ident {
p0 = p0.mulMat(m.invert())
}
v0, v1 := p0.sub(p1).norm(), p2.sub(p1).norm()
angle := math.Acos(v0.dot(v1))
// should be in the range [0-pi]. if parallel, use a straight line
@ -201,7 +228,7 @@ func (p *Path2D) ArcTo(x1, y1, x2, y2, radius float64) {
a1 += math.Pi * 2
}
}
p.Arc(center[0], center[1], radius, a0, a1, x > 0)
p.arc(center[0], center[1], radius, a0, a1, x > 0, m, ident)
}
// QuadraticCurveTo (see equivalent function on canvas type)

View file

@ -32,11 +32,10 @@ func (cv *Canvas) LineTo(x, y float64) {
// is the radius, startAngle and endAngle are angles in radians, anticlockwise
// 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})
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)
cv.path.arc(x, y, radius, startAngle2, endAngle2, anticlockwise, cv.state.transform, false)
}
// ArcTo adds to the current path by drawing a line toward x1/y1 and a circle
@ -44,9 +43,7 @@ func (cv *Canvas) Arc(x, y, radius, startAngle, endAngle float64, anticlockwise
// lines from the end of the path to x1/y1, and from x1/y1 to x2/y2. The line
// will only go to where the circle segment would touch the latter line
func (cv *Canvas) ArcTo(x1, y1, x2, y2, radius float64) {
tf1 := cv.tf(vec{x1, y1})
tf2 := cv.tf(vec{x2, y2})
cv.path.ArcTo(tf1[0], tf1[1], tf2[0], tf2[1], radius)
cv.path.arcTo(x1, y1, x2, y2, radius, cv.state.transform, false)
}
// QuadraticCurveTo adds a quadratic curve to the path. It uses the current end
@ -368,7 +365,7 @@ func linePointDistSqr(a, b, p vec) float64 {
// Fill fills the current path with the current FillStyle
func (cv *Canvas) Fill() {
cv.fillPath(&cv.path, matIdentity())
cv.fillPath(&cv.path, matIdentity)
}
// FillPath fills the given path with the current FillStyle
@ -426,7 +423,7 @@ func appendSubPathTriangles(tris [][2]float64, mat mat, path []pathPoint) [][2]f
// Clip uses the current path to clip any further drawing. Use Save/Restore to
// remove the clipping again
func (cv *Canvas) Clip() {
cv.clip(&cv.path, matIdentity())
cv.clip(&cv.path, matIdentity)
}
func (cv *Canvas) clip(path *Path2D, tf mat) {