fixed Arc and ArcTo scaling
This commit is contained in:
parent
50c77477c9
commit
259bb9e598
4 changed files with 42 additions and 20 deletions
|
@ -141,7 +141,7 @@ func New(backend backendbase.Backend) *Canvas {
|
||||||
cv.state.globalAlpha = 1
|
cv.state.globalAlpha = 1
|
||||||
cv.state.fill.color = color.RGBA{A: 255}
|
cv.state.fill.color = color.RGBA{A: 255}
|
||||||
cv.state.stroke.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
|
cv.path.cv = cv
|
||||||
return cv
|
return cv
|
||||||
}
|
}
|
||||||
|
@ -395,7 +395,7 @@ func (cv *Canvas) Restore() {
|
||||||
cv.b.ClearClip()
|
cv.b.ClearClip()
|
||||||
for _, st := range cv.stateStack {
|
for _, st := range cv.stateStack {
|
||||||
if len(st.clip.p) > 0 {
|
if len(st.clip.p) > 0 {
|
||||||
cv.clip(&st.clip, matIdentity())
|
cv.clip(&st.clip, matIdentity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cv.state = cv.stateStack[l-1]
|
cv.state = cv.stateStack[l-1]
|
||||||
|
|
4
math.go
4
math.go
|
@ -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])
|
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 {
|
var matIdentity = mat{
|
||||||
return mat{
|
|
||||||
1, 0,
|
1, 0,
|
||||||
0, 1,
|
0, 1,
|
||||||
0, 0}
|
0, 0}
|
||||||
}
|
|
||||||
|
|
||||||
func matTranslate(v vec) mat {
|
func matTranslate(v vec) mat {
|
||||||
return mat{
|
return mat{
|
||||||
|
|
37
path2d.go
37
path2d.go
|
@ -114,13 +114,21 @@ func (p *Path2D) lineTo(x, y float64, checkSelfIntersection bool) {
|
||||||
|
|
||||||
// Arc (see equivalent function on canvas type)
|
// Arc (see equivalent function on canvas type)
|
||||||
func (p *Path2D) Arc(x, y, radius, startAngle, endAngle float64, anticlockwise bool) {
|
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
|
checkSelfIntersection := len(p.p) > 0
|
||||||
|
|
||||||
lastWasMove := len(p.p) == 0 || p.p[len(p.p)-1].flags&pathMove != 0
|
lastWasMove := len(p.p) == 0 || p.p[len(p.p)-1].flags&pathMove != 0
|
||||||
|
|
||||||
if endAngle == startAngle {
|
if endAngle == startAngle {
|
||||||
s, c := math.Sincos(endAngle)
|
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 {
|
if lastWasMove {
|
||||||
p.p[len(p.p)-1].flags |= pathIsConvex
|
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 {
|
if !anticlockwise {
|
||||||
for a := startAngle; a < endAngle; a += step {
|
for a := startAngle; a < endAngle; a += step {
|
||||||
s, c := math.Sincos(a)
|
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 {
|
} else {
|
||||||
for a := startAngle; a > endAngle; a -= step {
|
for a := startAngle; a > endAngle; a -= step {
|
||||||
s, c := math.Sincos(a)
|
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)
|
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 {
|
if lastWasMove {
|
||||||
p.p[len(p.p)-1].flags |= pathIsConvex
|
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)
|
// ArcTo (see equivalent function on canvas type)
|
||||||
func (p *Path2D) ArcTo(x1, y1, x2, y2, radius float64) {
|
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 {
|
if len(p.p) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p0, p1, p2 := p.p[len(p.p)-1].pos, vec{x1, y1}, vec{x2, y2}
|
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()
|
v0, v1 := p0.sub(p1).norm(), p2.sub(p1).norm()
|
||||||
angle := math.Acos(v0.dot(v1))
|
angle := math.Acos(v0.dot(v1))
|
||||||
// should be in the range [0-pi]. if parallel, use a straight line
|
// 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
|
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)
|
// QuadraticCurveTo (see equivalent function on canvas type)
|
||||||
|
|
11
paths.go
11
paths.go
|
@ -32,11 +32,10 @@ func (cv *Canvas) LineTo(x, y float64) {
|
||||||
// is the radius, startAngle and endAngle are angles in radians, anticlockwise
|
// is the radius, startAngle and endAngle are angles in radians, anticlockwise
|
||||||
// means that the line is added anticlockwise
|
// means that the line is added anticlockwise
|
||||||
func (cv *Canvas) Arc(x, y, radius, startAngle, endAngle float64, anticlockwise bool) {
|
func (cv *Canvas) Arc(x, y, radius, startAngle, endAngle float64, anticlockwise bool) {
|
||||||
tf := cv.tf(vec{x, y})
|
|
||||||
ax, ay := math.Sincos(startAngle)
|
ax, ay := math.Sincos(startAngle)
|
||||||
startAngle2 := vec{ay, ax}.mulMat2(cv.state.transform.mat2()).atan2()
|
startAngle2 := vec{ay, ax}.mulMat2(cv.state.transform.mat2()).atan2()
|
||||||
endAngle2 := startAngle2 + (endAngle - startAngle)
|
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
|
// 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
|
// 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
|
// will only go to where the circle segment would touch the latter line
|
||||||
func (cv *Canvas) ArcTo(x1, y1, x2, y2, radius float64) {
|
func (cv *Canvas) ArcTo(x1, y1, x2, y2, radius float64) {
|
||||||
tf1 := cv.tf(vec{x1, y1})
|
cv.path.arcTo(x1, y1, x2, y2, radius, cv.state.transform, false)
|
||||||
tf2 := cv.tf(vec{x2, y2})
|
|
||||||
cv.path.ArcTo(tf1[0], tf1[1], tf2[0], tf2[1], radius)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// QuadraticCurveTo adds a quadratic curve to the path. It uses the current end
|
// 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
|
// Fill fills the current path with the current FillStyle
|
||||||
func (cv *Canvas) Fill() {
|
func (cv *Canvas) Fill() {
|
||||||
cv.fillPath(&cv.path, matIdentity())
|
cv.fillPath(&cv.path, matIdentity)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FillPath fills the given path with the current FillStyle
|
// 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
|
// Clip uses the current path to clip any further drawing. Use Save/Restore to
|
||||||
// remove the clipping again
|
// remove the clipping again
|
||||||
func (cv *Canvas) Clip() {
|
func (cv *Canvas) Clip() {
|
||||||
cv.clip(&cv.path, matIdentity())
|
cv.clip(&cv.path, matIdentity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cv *Canvas) clip(path *Path2D, tf mat) {
|
func (cv *Canvas) clip(path *Path2D, tf mat) {
|
||||||
|
|
Loading…
Reference in a new issue