Skip to content

Commit

Permalink
moved math code to backendbase package so that backends can also use it
Browse files Browse the repository at this point in the history
  • Loading branch information
tfriedel6 committed Mar 22, 2020
1 parent 066f4f5 commit cc9247c
Show file tree
Hide file tree
Showing 9 changed files with 365 additions and 358 deletions.
140 changes: 140 additions & 0 deletions backend/backendbase/math.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package backendbase

import (
"fmt"
"math"
)

type Vec [2]float64

func (v Vec) String() string {
return fmt.Sprintf("[%f,%f]", v[0], v[1])
}

func (v Vec) Add(v2 Vec) Vec {
return Vec{v[0] + v2[0], v[1] + v2[1]}
}

func (v Vec) Sub(v2 Vec) Vec {
return Vec{v[0] - v2[0], v[1] - v2[1]}
}

func (v Vec) Mul(v2 Vec) Vec {
return Vec{v[0] * v2[0], v[1] * v2[1]}
}

func (v Vec) Mulf(f float64) Vec {
return Vec{v[0] * f, v[1] * f}
}

func (v Vec) MulMat(m Mat) Vec {
return Vec{
m[0]*v[0] + m[2]*v[1] + m[4],
m[1]*v[0] + m[3]*v[1] + m[5]}
}

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 (v Vec) Div(v2 Vec) Vec {
return Vec{v[0] / v2[0], v[1] / v2[1]}
}

func (v Vec) Divf(f float64) Vec {
return Vec{v[0] / f, v[1] / f}
}

func (v Vec) Dot(v2 Vec) float64 {
return v[0]*v2[0] + v[1]*v2[1]
}

func (v Vec) Len() float64 {
return math.Sqrt(v[0]*v[0] + v[1]*v[1])
}

func (v Vec) LenSqr() float64 {
return v[0]*v[0] + v[1]*v[1]
}

func (v Vec) Norm() Vec {
return v.Mulf(1.0 / v.Len())
}

func (v Vec) Atan2() float64 {
return math.Atan2(v[1], v[0])
}

func (v Vec) Angle() float64 {
return math.Pi*0.5 - math.Atan2(v[1], v[0])
}

func (v Vec) AngleTo(v2 Vec) float64 {
return math.Acos(v.Norm().Dot(v2.Norm()))
}

type Mat [6]float64

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])
}

var MatIdentity = Mat{
1, 0,
0, 1,
0, 0}

func MatTranslate(v Vec) Mat {
return Mat{
1, 0,
0, 1,
v[0], v[1]}
}

func MatScale(v Vec) Mat {
return Mat{
v[0], 0,
0, v[1],
0, 0}
}

func MatRotate(radians float64) Mat {
s, c := math.Sincos(radians)
return Mat{
c, s,
-s, c,
0, 0}
}

func (m Mat) Mul(m2 Mat) Mat {
return Mat{
m[0]*m2[0] + m[1]*m2[2],
m[0]*m2[1] + m[1]*m2[3],
m[2]*m2[0] + m[3]*m2[2],
m[2]*m2[1] + m[3]*m2[3],
m[4]*m2[0] + m[5]*m2[2] + m2[4],
m[4]*m2[1] + m[5]*m2[3] + m2[5]}
}

func (m Mat) Invert() Mat {
identity := 1.0 / (m[0]*m[3] - m[2]*m[1])

return Mat{
m[3] * identity,
-m[1] * identity,
-m[2] * identity,
m[0] * identity,
(m[2]*m[5] - m[3]*m[4]) * identity,
(m[1]*m[4] - m[0]*m[5]) * identity,
}
}

type Mat2 [4]float64

func (m Mat) Mat2() Mat2 {
return Mat2{m[0], m[1], m[2], m[3]}
}

func (m *Mat2) String() string {
return fmt.Sprintf("[%f,%f,\n %f,%f]", m[0], m[2], m[1], m[3])
}
30 changes: 15 additions & 15 deletions canvas.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type Canvas struct {
}

type drawState struct {
transform mat
transform backendbase.Mat
fill drawStyle
stroke drawStyle
font *Font
Expand Down Expand Up @@ -150,7 +150,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 = backendbase.MatIdentity
cv.path.cv = cv
return cv
}
Expand All @@ -170,8 +170,8 @@ func (cv *Canvas) Height() int {
// Size returns the internal width and height of the canvas
func (cv *Canvas) Size() (int, int) { return cv.b.Size() }

func (cv *Canvas) tf(v vec) vec {
return v.mulMat(cv.state.transform)
func (cv *Canvas) tf(v backendbase.Vec) backendbase.Vec {
return v.MulMat(cv.state.transform)
}

const alphaTexSize = 2048
Expand Down Expand Up @@ -380,7 +380,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, backendbase.MatIdentity)
}
}
cv.state = cv.stateStack[l-1]
Expand All @@ -389,27 +389,27 @@ func (cv *Canvas) Restore() {

// Scale updates the current transformation with a scaling by the given values
func (cv *Canvas) Scale(x, y float64) {
cv.state.transform = matScale(vec{x, y}).mul(cv.state.transform)
cv.state.transform = backendbase.MatScale(backendbase.Vec{x, y}).Mul(cv.state.transform)
}

// Translate updates the current transformation with a translation by the given values
func (cv *Canvas) Translate(x, y float64) {
cv.state.transform = matTranslate(vec{x, y}).mul(cv.state.transform)
cv.state.transform = backendbase.MatTranslate(backendbase.Vec{x, y}).Mul(cv.state.transform)
}

// Rotate updates the current transformation with a rotation by the given angle
func (cv *Canvas) Rotate(angle float64) {
cv.state.transform = matRotate(angle).mul(cv.state.transform)
cv.state.transform = backendbase.MatRotate(angle).Mul(cv.state.transform)
}

// Transform updates the current transformation with the given matrix
func (cv *Canvas) Transform(a, b, c, d, e, f float64) {
cv.state.transform = mat{a, b, c, d, e, f}.mul(cv.state.transform)
cv.state.transform = backendbase.Mat{a, b, c, d, e, f}.Mul(cv.state.transform)
}

// SetTransform replaces the current transformation with the given matrix
func (cv *Canvas) SetTransform(a, b, c, d, e, f float64) {
cv.state.transform = mat{a, b, c, d, e, f}
cv.state.transform = backendbase.Mat{a, b, c, d, e, f}
}

// SetShadowColor sets the color of the shadow. If it is fully transparent (default)
Expand Down Expand Up @@ -456,14 +456,14 @@ func (cv *Canvas) IsPointInStroke(x, y float64) bool {
}

var triBuf [500][2]float64
tris := cv.strokeTris(&cv.path, cv.state.transform.invert(), true, triBuf[:0])
tris := cv.strokeTris(&cv.path, cv.state.transform.Invert(), true, triBuf[:0])

pt := vec{x, y}
pt := backendbase.Vec{x, y}

for i := 0; i < len(tris); i += 3 {
a := vec{tris[i][0], tris[i][1]}
b := vec{tris[i+1][0], tris[i+1][1]}
c := vec{tris[i+2][0], tris[i+2][1]}
a := backendbase.Vec{tris[i][0], tris[i][1]}
b := backendbase.Vec{tris[i+1][0], tris[i+1][1]}
c := backendbase.Vec{tris[i+2][0], tris[i+2][1]}
if triangleContainsPoint(a, b, c, pt) {
return true
}
Expand Down
12 changes: 6 additions & 6 deletions gradients.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
// will correspond to a straight line
type LinearGradient struct {
cv *Canvas
from, to vec
from, to backendbase.Vec
created bool
loaded bool
opaque bool
Expand All @@ -27,7 +27,7 @@ type LinearGradient struct {
// will correspond to a circle
type RadialGradient struct {
cv *Canvas
from, to vec
from, to backendbase.Vec
radFrom float64
radTo float64
created bool
Expand All @@ -44,8 +44,8 @@ func (cv *Canvas) CreateLinearGradient(x0, y0, x1, y1 float64) *LinearGradient {
lg := &LinearGradient{
cv: cv,
opaque: true,
from: vec{x0, y0},
to: vec{x1, y1},
from: backendbase.Vec{x0, y0},
to: backendbase.Vec{x1, y1},
data: make(backendbase.Gradient, 0, 20),
}
runtime.SetFinalizer(lg, func(*LinearGradient) {
Expand All @@ -62,8 +62,8 @@ func (cv *Canvas) CreateRadialGradient(x0, y0, r0, x1, y1, r1 float64) *RadialGr
rg := &RadialGradient{
cv: cv,
opaque: true,
from: vec{x0, y0},
to: vec{x1, y1},
from: backendbase.Vec{x0, y0},
to: backendbase.Vec{x1, y1},
radFrom: r0,
radTo: r1,
data: make(backendbase.Gradient, 0, 20),
Expand Down
18 changes: 9 additions & 9 deletions images.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,10 @@ func (cv *Canvas) DrawImage(image interface{}, coords ...float64) {
}

var data [4][2]float64
data[0] = cv.tf(vec{dx, dy})
data[1] = cv.tf(vec{dx, dy + dh})
data[2] = cv.tf(vec{dx + dw, dy + dh})
data[3] = cv.tf(vec{dx + dw, dy})
data[0] = cv.tf(backendbase.Vec{dx, dy})
data[1] = cv.tf(backendbase.Vec{dx, dy + dh})
data[2] = cv.tf(backendbase.Vec{dx + dw, dy + dh})
data[3] = cv.tf(backendbase.Vec{dx + dw, dy})

cv.drawShadow(data[:], nil, false)

Expand All @@ -207,7 +207,7 @@ func (cv *Canvas) PutImageData(img *image.RGBA, x, y int) {
type ImagePattern struct {
cv *Canvas
img *Image
tf mat
tf backendbase.Mat
rep imagePatternRepeat
ip backendbase.ImagePattern
}
Expand All @@ -222,8 +222,8 @@ const (
NoRepeat = imagePatternRepeat(backendbase.NoRepeat)
)

func (ip *ImagePattern) data(tf mat) backendbase.ImagePatternData {
m := tf.invert().mul(ip.tf.invert())
func (ip *ImagePattern) data(tf backendbase.Mat) backendbase.ImagePatternData {
m := tf.Invert().Mul(ip.tf.Invert())
return backendbase.ImagePatternData{
Image: ip.img.img,
Transform: [9]float64{
Expand All @@ -239,7 +239,7 @@ func (ip *ImagePattern) data(tf mat) backendbase.ImagePatternData {
// to the given matrix. The matrix is a 3x3 matrix, but three
// of the values are always identity values
func (ip *ImagePattern) SetTransform(tf [6]float64) {
ip.tf = mat(tf)
ip.tf = backendbase.Mat(tf)
}

// CreatePattern creates a new image pattern with the specified
Expand All @@ -249,7 +249,7 @@ func (cv *Canvas) CreatePattern(src interface{}, repeat imagePatternRepeat) *Ima
cv: cv,
img: cv.getImage(src),
rep: repeat,
tf: mat{1, 0, 0, 1, 0, 0},
tf: backendbase.Mat{1, 0, 0, 1, 0, 0},
}
if ip.img != nil {
ip.ip = cv.b.LoadImagePattern(ip.data(cv.state.transform))
Expand Down
Loading

0 comments on commit cc9247c

Please sign in to comment.