From b7397ee4dc21d0824fd39b26cf2930a129881ea6 Mon Sep 17 00:00:00 2001 From: Thomas Friedel Date: Sat, 30 Mar 2019 11:24:05 +0100 Subject: [PATCH] fixed stroke scaling --- README.md | 1 - paths.go | 61 +++++++++++++++++++++++----------------- testdata/Transform2.png | Bin 543 -> 536 bytes 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index ecad403..be7ca5a 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,6 @@ These features *should* work just like their HTML5 counterparts, but there are l - textBaseline hanging and ideographic (currently work just like top and bottom) - full self intersecting polygon support - image patterns with repeat and transform -- line width and cap scaling doesn't work right yet # Version history diff --git a/paths.go b/paths.go index 6f1546e..5d29505 100644 --- a/paths.go +++ b/paths.go @@ -74,28 +74,31 @@ func (cv *Canvas) ClosePath() { // Stroke uses the current StrokeStyle to draw the current path func (cv *Canvas) Stroke() { - cv.strokePath(&cv.path) + cv.strokePath(&cv.path, cv.state.transform.invert(), true) } // StrokePath uses the current StrokeStyle to draw the given path func (cv *Canvas) StrokePath(path *Path2D) { + // todo avoid allocation path2 := Path2D{ p: make([]pathPoint, len(path.p)), } - // todo avoid allocation - for i, pt := range path.p { - path2.p[i].pos = cv.tf(pt.pos) - path2.p[i].next = cv.tf(pt.next) - path2.p[i].flags = pt.flags - } - cv.strokePath(&path2) + copy(path2.p, path.p) + cv.strokePath(&path2, mat{}, false) } -func (cv *Canvas) strokePath(path *Path2D) { +func (cv *Canvas) strokePath(path *Path2D, inv mat, doInv bool) { if len(path.p) == 0 { return } + if doInv { + for i, pt := range path.p { + path.p[i].pos = pt.pos.mulMat(inv) + path.p[i].next = pt.next.mulMat(inv) + } + } + dashedPath := cv.applyLineDash(path.p) var triBuf [500][2]float64 @@ -144,10 +147,10 @@ func (cv *Canvas) strokePath(path *Path2D) { } } - tris = append(tris, lp0, lp1, lp3, lp0, lp3, lp2) + tris = append(tris, cv.tf(lp0), cv.tf(lp1), cv.tf(lp3), cv.tf(lp0), cv.tf(lp3), cv.tf(lp2)) if p.flags&pathAttach != 0 && cv.state.lineWidth > 1 { - tris = cv.lineJoint(p, p0, p1, p.next, lp0, lp1, lp2, lp3, tris) + tris = cv.lineJoint(p0, p1, p.next, lp0, lp1, lp2, lp3, tris) } p0 = p1 @@ -216,7 +219,7 @@ func (cv *Canvas) applyLineDash(path []pathPoint) []pathPoint { return path2 } -func (cv *Canvas) lineJoint(p pathPoint, p0, p1, p2, l0p0, l0p1, l0p2, l0p3 vec, tris [][2]float64) [][2]float64 { +func (cv *Canvas) lineJoint(p0, p1, p2, l0p0, l0p1, l0p2, l0p3 vec, tris [][2]float64) [][2]float64 { v2 := p1.sub(p2).norm() v3 := vec{v2[1], -v2[0]}.mulf(cv.state.lineWidth * 0.5) @@ -242,7 +245,8 @@ func (cv *Canvas) lineJoint(p pathPoint, p0, p1, p2, l0p0, l0p1, l0p2, l0p3 vec, l1p1 := p1.sub(v3) l1p3 := p1.add(v3) - tris = append(tris, p1, l0p1, l1p1, p1, l1p3, l0p3) + tris = append(tris, cv.tf(p1), cv.tf(l0p1), cv.tf(l1p1), + cv.tf(p1), cv.tf(l1p3), cv.tf(l0p3)) return tris } @@ -260,16 +264,21 @@ func (cv *Canvas) lineJoint(p pathPoint, p0, p1, p2, l0p0, l0p1, l0p2, l0p3 vec, l1p1 := p1.sub(v3) l1p3 := p1.add(v3) - tris = append(tris, p1, l0p1, l1p1, p1, l1p3, l0p3) + tris = append(tris, cv.tf(p1), cv.tf(l0p1), cv.tf(l1p1), + cv.tf(p1), cv.tf(l1p3), cv.tf(l0p3)) return tris } - tris = append(tris, p1, l0p1, ip0, p1, ip0, l1p1, p1, l1p3, ip1, p1, ip1, l0p3) + tris = append(tris, cv.tf(p1), cv.tf(l0p1), cv.tf(ip0), + cv.tf(p1), cv.tf(ip0), cv.tf(l1p1), + cv.tf(p1), cv.tf(l1p3), cv.tf(ip1), + cv.tf(p1), cv.tf(ip1), cv.tf(l0p3)) case Bevel: l1p1 := p1.sub(v3) l1p3 := p1.add(v3) - tris = append(tris, p1, l0p1, l1p1, p1, l1p3, l0p3) + tris = append(tris, cv.tf(p1), cv.tf(l0p1), cv.tf(l1p1), + cv.tf(p1), cv.tf(l1p3), cv.tf(l0p3)) case Round: tris = cv.addCircleTris(p1, cv.state.lineWidth*0.5, tris) } @@ -284,11 +293,12 @@ func (cv *Canvas) addCircleTris(center vec, radius float64, tris [][2]float64) [ } else if step < 0.05 { step = 0.05 } - p0 := vec{center[0], center[1] + radius} + centertf := cv.tf(center) + p0 := cv.tf(vec{center[0], center[1] + radius}) for angle := step; angle <= math.Pi*2+step; angle += step { s, c := math.Sincos(angle) - p1 := vec{center[0] + s*radius, center[1] + c*radius} - tris = append(tris, center, p0, p1) + p1 := cv.tf(vec{center[0] + s*radius, center[1] + c*radius}) + tris = append(tris, centertf, p0, p1) p0 = p1 } return tris @@ -415,15 +425,14 @@ func (cv *Canvas) StrokeRect(x, y, w, h float64) { v1 := vec{x + w, y} v2 := vec{x + w, y + h} v3 := vec{x, y + h} - v0t, v1t, v2t, v3t := cv.tf(v0), cv.tf(v1), cv.tf(v2), cv.tf(v3) var p [5]pathPoint - p[0] = pathPoint{pos: v0t, flags: pathMove | pathAttach, next: v1t} - p[1] = pathPoint{pos: v1t, next: v2, flags: pathAttach} - p[2] = pathPoint{pos: v2t, next: v3, flags: pathAttach} - p[3] = pathPoint{pos: v3t, next: v0, flags: pathAttach} - p[4] = pathPoint{pos: v0t, next: v1, flags: pathAttach} + p[0] = pathPoint{pos: v0, flags: pathMove | pathAttach, next: v1} + p[1] = pathPoint{pos: v1, next: v2, flags: pathAttach} + p[2] = pathPoint{pos: v2, next: v3, flags: pathAttach} + p[3] = pathPoint{pos: v3, next: v0, flags: pathAttach} + p[4] = pathPoint{pos: v0, next: v1, flags: pathAttach} path := Path2D{p: p[:]} - cv.strokePath(&path) + cv.strokePath(&path, mat{}, false) } // FillRect fills a rectangle with the active fill style diff --git a/testdata/Transform2.png b/testdata/Transform2.png index df69ea47e44cb4fbd8f8219b2dc3eba808d6468d..6dd639aa2f2e06d61d73f98fb0281a6cf4c9fdfe 100755 GIT binary patch literal 536 zcmeAS@N?(olHy`uVBq!ia0vp^DImcQn_K45oyqFJA3Q9f8FyBA72*WYG?nZAgS>PQzxqsw~CmD&V&esjSdijUsiwZ zub0;TdA>=x7>!{U4uK0lkE{4^`O8*+sa@-s&$VBd zCxpglKFPF@ja=S-vrpvz9iA_Y^7R+W_|jT*`z%vq*S8(-uDpBa{uGYGUn2xInM(_L zWLc4s#_*RQd*3q~Y zrm^)!#8QQn;)JPflh3wnHTBB%S`$>isdJ;3?a5`wZ@pSDjeYf%DLT?&E3ax_j?yvl zE4?}?d1}_gyG*M?9{Mhtx-DhXxxFjDEsKcm&pN&7NX?^yQ%tsNW$a-Qff6|TfYJN^ Zf1Byj|CNG6Oq|>*IukZHpfN6-f4jeOUi$CD zg)*Pz{9oLtEL+emzlHJU7Slh6H~KKVj_>;vw>Y9%VC&uzQx@LDtMjIReC8jP7`ax_ zBSImuv4vGgj3mYhme)0@A1Buu&skHI@+>=|^UXior7NV&7p$vm^ta7ee17v$$z`)Q zxn@^H?z+qK(N6nxUfY4Jqw36`_y6!=diQM0|HQ-)4WmB+F=nb9H|MfH{Bi2h>TfS@ z#AU^$2>0#czq#e{+YPfn^9NU4Si=`E>CCsA8rx=fZ`*rpf$rV~DeA=)hbNVr+uj#g zE^YF^zF1Z1^YN^uH_mEA>^;#e#