Newer
Older
// Vec is a 2D vector type. It is unusually implemented as complex128 for convenience. Since
// Go does not allow operator overloading, implementing vector as a struct leads to a bunch of
// methods for addition, subtraction and multiplication of vectors. With complex128, much of
// this functionality is given through operators.
//
// Create vectors with the V constructor:
//
// u := pixel.V(1, 2)
// v := pixel.V(8, -3)
//
// Add and subtract them using the standard + and - operators:
//
// w := u + v
// fmt.Println(w) // Vec(9, -1)
// fmt.Println(u - v) // Vec(-7, 5)
//
// Additional standard vector operations can be obtained with methods:
//
// String returns the string representation of the vector u.
//
// u := pixel.V(4.5, -1.3)
// u.String() // returns "Vec(4.5, -1.3)"
// fmt.Println(u) // Vec(4.5, -1.3)
func (u Vec) String() string {
return fmt.Sprintf("Vec(%v, %v)", u.X(), u.Y())
// XY returns the components of the vector in two return values.
func (u Vec) XY() (x, y float64) {
return real(u), imag(u)
}
// Angle returns the angle between the vector u and the x-axis. The result is in the range [-Pi, Pi].
return cmplx.Phase(complex128(u))
}
// Unit returns a vector of length 1 with the same angle as u.
// Rotated returns the vector u rotated by the given angle in radians.
sin, cos := math.Sincos(angle)
return u * V(cos, sin)
return u.X()*v.X() + u.Y()*v.Y()
}
// Cross return the cross product of vectors u and v.
// Map applies the function f to both x and y components of the vector u and returns the modified
// Lerp returns a linear interpolation between vectors a and b.
//
// This function basically returns a point along the line between a and b and t chooses which point.
// If t is 0, then a will be returned, if t is 1, b will be returned. Anything between 0 and 1 will
// return the appropriate point between a and b and so on.
func Lerp(a, b Vec, t float64) Vec {
return a.Scaled(1-t) + b.Scaled(t)
}
// Rect is a 2D rectangle aligned with the axes of the coordinate system. It has a position
//
// You can manipulate the position and the size using the usual vector operations.
type Rect struct {
Pos, Size Vec
}
// R returns a new Rect with given position (x, y) and size (w, h).
func R(x, y, w, h float64) Rect {
return Rect{
Pos: V(x, y),
Size: V(w, h),
}
}
// String returns the string representation of the rectangle.
//
// r := pixel.R(100, 50, 200, 300)
// r.String() // returns "Rect(100, 50, 200, 300)"
// fmt.Println(r) // Rect(100, 50, 200, 300)
func (r Rect) String() string {
return fmt.Sprintf("Rect(%v, %v, %v, %v)", r.X(), r.Y(), r.W(), r.H())
}
// X returns the x coordinate of the position of the rectangle.
// Y returns the y coordinate of the position of the rectangle
// XYWH returns all of the four components of the rectangle in four return values.
func (r Rect) XYWH() (x, y, w, h float64) {
return r.X(), r.Y(), r.W(), r.H()
}
// Center returns the position of the center of the rectangle.
func (r Rect) Center() Vec {
return r.Pos + r.Size.Scaled(0.5)
}
// Contains checks whether a vector u is contained within this Rect (including it's borders).
func (r Rect) Contains(u Vec) bool {
min, max := r.Pos, r.Pos+r.Size
return min.X() <= u.X() && u.X() <= max.X() && min.Y() <= u.Y() && u.Y() <= max.Y()
}
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// Matrix is a 3x3 transformation matrix that can be used for all kinds of spacial transforms, such
// as movement, scaling and rotations.
//
// Matrix has a handful of useful methods, each of which adds a transformation to the matrix. For
// example:
//
// pixel.ZM.Move(pixel.V(100, 200)).Rotate(0, math.Pi/2)
//
// This code creates a Matrix that first moves everything by 100 units horizontaly and 200 units
// vertically and then rotates everything by 90 degrees around the origin.
type Matrix [9]float64
// ZM stands for Zero-Matrix which is the identity matrix. Does nothing, no transformation.
var ZM = Matrix(mgl64.Ident3())
// Move moves everything by the delta vector.
func (m Matrix) Move(delta Vec) Matrix {
m3 := mgl64.Mat3(m)
m3 = mgl64.Translate2D(delta.XY()).Mul3(m3)
return Matrix(m3)
}
// ScaleXY scales everything around a given point by the scale factor in each axis respectively.
func (m Matrix) ScaleXY(around Vec, scale Vec) Matrix {
m3 := mgl64.Mat3(m)
m3 = mgl64.Translate2D((-around).XY()).Mul3(m3)
m3 = mgl64.Scale2D(scale.XY()).Mul3(m3)
m3 = mgl64.Translate2D(around.XY()).Mul3(m3)
return Matrix(m3)
}
// Scale scales everything around a given point by the scale factor.
func (m Matrix) Scale(around Vec, scale float64) Matrix {
return m.ScaleXY(around, V(scale, scale))
}
// Rotate rotates everything around a given point by the given angle in radians.
func (m Matrix) Rotate(around Vec, angle float64) Matrix {
m3 := mgl64.Mat3(m)
m3 = mgl64.Translate2D((-around).XY()).Mul3(m3)
m3 = mgl64.Rotate3DZ(angle).Mul3(m3)
m3 = mgl64.Translate2D(around.XY()).Mul3(m3)
return Matrix(m3)
}
// Project applies all transformations added to the Matrix to a vector u and returns the result.
func (m Matrix) Project(u Vec) Vec {
m3 := mgl64.Mat3(m)
proj := m3.Mul3x1(mgl64.Vec3{u.X(), u.Y(), 1})
return V(proj.X(), proj.Y())
}
// Unproject does the inverse operation to Project.
func (m Matrix) Unproject(u Vec) Vec {
m3 := mgl64.Mat3(m)
inv := m3.Inv()
unproj := inv.Mul3x1(mgl64.Vec3{u.X(), u.Y(), 1})
return V(unproj.X(), unproj.Y())
}