2D Vector Library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

geometry.go 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package vector
  2. import (
  3. "math"
  4. )
  5. // A and B represent two opposite corners of axis-aligned boundin box
  6. type AABB2d struct {
  7. A Point2d `json:"A"`
  8. B Point2d `json:"B"`
  9. }
  10. type Polygon2d struct {
  11. Points []Vector2d `json:"points"`
  12. Normals []Vector2d `json:"normals"`
  13. Origin Point2d `json:"origin"`
  14. }
  15. func (p Polygon2d) Edge(i int) (Point2d, Vector2d) {
  16. p1 := Point2d{}
  17. p2 := Point2d{}
  18. if i == len(p.Points)-1 {
  19. p1 = p.Origin.Add(p.Points[i])
  20. p2 = p.Origin.Add(p.Points[0])
  21. } else {
  22. p1 = p.Origin.Add(p.Points[i])
  23. p2 = p.Origin.Add(p.Points[i+1])
  24. }
  25. return p1, p2.Sub(p1)
  26. }
  27. type Vector2d struct {
  28. X float64 `json:"x"`
  29. Y float64 `json:"y"`
  30. }
  31. type Point2d struct {
  32. X float64 `json:"x"`
  33. Y float64 `json:"y"`
  34. }
  35. const Epsilon = 1e-7
  36. const Rad2deg = 180 / math.Pi
  37. const Deg2rad = math.Pi / 180
  38. func (p1 Point2d) Sub(p2 Point2d) Vector2d {
  39. return Vector2d{p1.X - p2.X, p1.Y - p2.Y}
  40. }
  41. func (p Point2d) Add(v Vector2d) Point2d {
  42. return Point2d{p.X + v.X, p.Y + v.Y}
  43. }
  44. func (v Vector2d) Mag() float64 {
  45. return math.Abs(math.Sqrt(v.X*v.X + v.Y*v.Y))
  46. }
  47. func (v Vector2d) MagSquared() float64 {
  48. return math.Abs(v.X*v.X + v.Y*v.Y)
  49. }
  50. func (v Vector2d) PopPop() float64 {
  51. return v.Mag()
  52. }
  53. func (v Vector2d) Scale(s float64) Vector2d {
  54. return Vector2d{v.X * s, v.Y * s}
  55. }
  56. func (v1 Vector2d) Cross(v2 Vector2d) float64 {
  57. return v1.X*v2.Y - v1.Y*v2.X
  58. }
  59. func (v1 Vector2d) Dot(v2 Vector2d) float64 {
  60. return (v1.X * v2.X) + (v1.Y * v2.Y)
  61. }
  62. func (p Point2d) ToVector() Vector2d {
  63. return Vector2d{p.X, p.Y}
  64. }
  65. func (v Vector2d) ToPoint() Point2d {
  66. return Point2d{v.X, v.Y}
  67. }
  68. func (v1 Vector2d) Rotate(a float64) Vector2d {
  69. x := float64(v1.X)*math.Cos(float64(a)) - float64(v1.Y)*math.Sin(float64(a))
  70. y := float64(v1.X)*math.Sin(float64(a)) + float64(v1.Y)*math.Cos(float64(a))
  71. return Vector2d{x, y}
  72. }
  73. func PointInRect(p Point2d, r AABB2d) bool {
  74. return (p.X > r.A.X) && (p.X < r.B.X) && (p.Y > r.A.Y) && (p.Y < r.B.Y)
  75. }
  76. func AASquareAtPoint(p Point2d, edgeLength float64) AABB2d {
  77. size := edgeLength / 2.0
  78. return AABB2d{
  79. A: Point2d{X: p.X - size, Y: p.Y - size},
  80. B: Point2d{X: p.X + size, Y: p.Y + size}}
  81. }
  82. func (r AABB2d) ToPolygon() Polygon2d {
  83. p := Polygon2d{}
  84. p.Origin = r.A
  85. p.Points = append(p.Points, r.A.Sub(p.Origin))
  86. p.Points = append(p.Points, Point2d{r.A.X, r.B.Y}.Sub(p.Origin))
  87. p.Points = append(p.Points, r.B.Sub(p.Origin))
  88. p.Points = append(p.Points, Point2d{r.B.X, r.A.Y}.Sub(p.Origin))
  89. return p
  90. }
  91. func OrientedSquare(center Point2d, heading Vector2d, size float64) Polygon2d {
  92. out := Polygon2d{}
  93. out.Origin.X = center.X
  94. out.Origin.Y = center.Y
  95. x := heading.Normalize().Scale(size)
  96. y := Vector2d{-x.Y, x.X}
  97. z := Point2d{}
  98. out.Points = append(out.Points, z.Add(x).Add(y).ToVector())
  99. out.Points = append(out.Points, z.Add(y).Sub(x.ToPoint()))
  100. out.Points = append(out.Points, z.Sub(x.ToPoint()).ToPoint().Sub(y.ToPoint()))
  101. out.Points = append(out.Points, z.Add(x).Sub(y.ToPoint()))
  102. return out
  103. }
  104. func (v Vector2d) Normalize() Vector2d {
  105. if v.X == 0 && v.Y == 0 {
  106. return v
  107. }
  108. m := v.Mag()
  109. return Vector2d{v.X / m, v.Y / m}
  110. }
  111. func Distance(p1, p2 Point2d) float64 {
  112. return p1.Sub(p2).Mag()
  113. }
  114. // returns radians
  115. func Angle(v1, v2 Vector2d) float64 {
  116. x := (v1.Dot(v2) / (v1.Mag() * v2.Mag()))
  117. angle := math.Acos(float64(x))
  118. if math.IsNaN(angle) {
  119. if math.Abs(float64(v1.X-v2.X)) > Epsilon {
  120. return 180.0
  121. } else {
  122. return 0
  123. }
  124. }
  125. // Determine the sign to see what direction
  126. // the angle should go in
  127. if v1.Y*v2.X > v1.X*v2.Y {
  128. angle = angle * -1.0
  129. }
  130. return angle
  131. }