vector/geometry.go

163 lines
3.5 KiB
Go
Raw Permalink Normal View History

2014-04-23 14:29:38 -07:00
package vector
2013-08-08 20:34:27 -07:00
import (
2013-08-08 20:36:15 -07:00
"math"
2013-08-08 20:34:27 -07:00
)
2014-01-07 21:21:43 -08:00
// A and B represent two opposite corners of axis-aligned boundin box
2013-11-24 14:25:19 -08:00
type AABB2d struct {
2014-04-23 14:56:23 -07:00
A Point2d `json:"A"`
B Point2d `json:"B"`
2013-08-08 21:54:52 -07:00
}
2013-11-24 14:25:19 -08:00
type Polygon2d struct {
Points []Vector2d `json:"points"`
Normals []Vector2d `json:"normals"`
Origin Point2d `json:"origin"`
}
2013-11-24 21:01:09 -08:00
func (p Polygon2d) Edge(i int) (Point2d, Vector2d) {
p1 := Point2d{}
p2 := Point2d{}
if i == len(p.Points)-1 {
p1 = p.Origin.Add(p.Points[i])
p2 = p.Origin.Add(p.Points[0])
} else {
p1 = p.Origin.Add(p.Points[i])
p2 = p.Origin.Add(p.Points[i+1])
2013-11-24 21:01:09 -08:00
}
return p1, p2.Sub(p1)
}
2013-08-08 20:36:15 -07:00
type Vector2d struct {
2014-04-26 14:40:18 -07:00
X float64 `json:"x"`
Y float64 `json:"y"`
2013-08-08 20:34:27 -07:00
}
2013-08-08 20:36:15 -07:00
type Point2d struct {
2014-04-26 14:40:18 -07:00
X float64 `json:"x"`
Y float64 `json:"y"`
2013-08-08 20:34:27 -07:00
}
2013-09-27 01:31:35 -07:00
const Epsilon = 1e-7
const Rad2deg = 180 / math.Pi
const Deg2rad = math.Pi / 180
2013-08-08 20:34:27 -07:00
2013-08-08 22:13:04 -07:00
func (p1 Point2d) Sub(p2 Point2d) Vector2d {
2013-08-08 21:54:52 -07:00
return Vector2d{p1.X - p2.X, p1.Y - p2.Y}
}
2013-08-08 22:13:04 -07:00
func (p Point2d) Add(v Vector2d) Point2d {
2013-08-08 21:54:52 -07:00
return Point2d{p.X + v.X, p.Y + v.Y}
2013-08-08 20:34:27 -07:00
}
2014-04-26 14:40:18 -07:00
func (v Vector2d) Mag() float64 {
return math.Abs(math.Sqrt(v.X*v.X + v.Y*v.Y))
2013-08-08 20:34:27 -07:00
}
2013-08-08 21:54:52 -07:00
2014-04-26 14:40:18 -07:00
func (v Vector2d) MagSquared() float64 {
return math.Abs(v.X*v.X + v.Y*v.Y)
}
2014-04-26 14:40:18 -07:00
func (v Vector2d) PopPop() float64 {
2013-08-08 22:13:04 -07:00
return v.Mag()
}
2014-04-26 14:40:18 -07:00
func (v Vector2d) Scale(s float64) Vector2d {
2013-08-08 21:54:52 -07:00
return Vector2d{v.X * s, v.Y * s}
}
2013-08-08 23:08:22 -07:00
2014-04-26 14:40:18 -07:00
func (v1 Vector2d) Cross(v2 Vector2d) float64 {
return v1.X*v2.Y - v1.Y*v2.X
}
2014-04-26 14:40:18 -07:00
func (v1 Vector2d) Dot(v2 Vector2d) float64 {
return (v1.X * v2.X) + (v1.Y * v2.Y)
}
func (p Point2d) ToVector() Vector2d {
return Vector2d{p.X, p.Y}
}
func (v Vector2d) ToPoint() Point2d {
return Point2d{v.X, v.Y}
}
2014-04-26 14:40:18 -07:00
func (v1 Vector2d) Rotate(a float64) Vector2d {
2013-10-19 16:15:27 -07:00
x := float64(v1.X)*math.Cos(float64(a)) - float64(v1.Y)*math.Sin(float64(a))
y := float64(v1.X)*math.Sin(float64(a)) + float64(v1.Y)*math.Cos(float64(a))
2014-04-26 14:40:18 -07:00
return Vector2d{x, y}
}
2013-11-24 14:25:19 -08:00
func PointInRect(p Point2d, r AABB2d) bool {
2013-09-27 01:31:35 -07:00
return (p.X > r.A.X) && (p.X < r.B.X) && (p.Y > r.A.Y) && (p.Y < r.B.Y)
}
2014-04-26 14:40:18 -07:00
func AASquareAtPoint(p Point2d, edgeLength float64) AABB2d {
2014-01-07 21:21:43 -08:00
size := edgeLength / 2.0
2013-11-24 14:25:19 -08:00
return AABB2d{
2013-10-21 07:50:16 -07:00
A: Point2d{X: p.X - size, Y: p.Y - size},
B: Point2d{X: p.X + size, Y: p.Y + size}}
}
func (r AABB2d) ToPolygon() Polygon2d {
p := Polygon2d{}
p.Origin = r.A
p.Points = append(p.Points, r.A.Sub(p.Origin))
p.Points = append(p.Points, Point2d{r.A.X, r.B.Y}.Sub(p.Origin))
p.Points = append(p.Points, r.B.Sub(p.Origin))
p.Points = append(p.Points, Point2d{r.B.X, r.A.Y}.Sub(p.Origin))
return p
}
2014-04-26 14:40:18 -07:00
func OrientedSquare(center Point2d, heading Vector2d, size float64) Polygon2d {
out := Polygon2d{}
out.Origin.X = center.X
out.Origin.Y = center.Y
x := heading.Normalize().Scale(size)
y := Vector2d{-x.Y, x.X}
z := Point2d{}
out.Points = append(out.Points, z.Add(x).Add(y).ToVector())
out.Points = append(out.Points, z.Add(y).Sub(x.ToPoint()))
out.Points = append(out.Points, z.Sub(x.ToPoint()).ToPoint().Sub(y.ToPoint()))
out.Points = append(out.Points, z.Add(x).Sub(y.ToPoint()))
return out
2013-09-27 01:31:35 -07:00
}
2013-08-08 23:08:22 -07:00
func (v Vector2d) Normalize() Vector2d {
2013-08-08 23:14:18 -07:00
if v.X == 0 && v.Y == 0 {
return v
}
2013-08-08 23:08:22 -07:00
m := v.Mag()
return Vector2d{v.X / m, v.Y / m}
}
2013-09-03 23:32:57 -07:00
2014-04-26 14:40:18 -07:00
func Distance(p1, p2 Point2d) float64 {
2013-09-03 23:32:57 -07:00
return p1.Sub(p2).Mag()
}
2013-09-21 18:34:53 -07:00
2014-01-07 17:21:04 -08:00
// returns radians
2014-04-26 14:40:18 -07:00
func Angle(v1, v2 Vector2d) float64 {
2013-09-21 18:34:53 -07:00
x := (v1.Dot(v2) / (v1.Mag() * v2.Mag()))
2013-10-19 16:15:27 -07:00
angle := math.Acos(float64(x))
if math.IsNaN(angle) {
if math.Abs(float64(v1.X-v2.X)) > Epsilon {
return 180.0
} else {
return 0
}
}
// Determine the sign to see what direction
// the angle should go in
if v1.Y*v2.X > v1.X*v2.Y {
angle = angle * -1.0
}
2014-04-26 14:40:18 -07:00
return angle
2013-09-21 18:34:53 -07:00
}