curves.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package math32
  5. // Curve constructs an array of Vector3
  6. type Curve struct {
  7. points []Vector3
  8. length float32
  9. }
  10. func (c *Curve) GetPoints() []Vector3 {
  11. return c.points
  12. }
  13. func (c *Curve) GetLength() float32 {
  14. return c.length
  15. }
  16. func (c *Curve) SetLength() {
  17. points := c.points
  18. l := float32(0.0)
  19. for i := 1; i < len(points); i++ {
  20. p0 := points[i].Clone()
  21. p1 := points[i - 1].Clone()
  22. l += (p0.Sub(p1)).Length()
  23. }
  24. c.length = l
  25. }
  26. // Continue combines two curves
  27. // creates and returns a pointer to a new curve
  28. // combined curves are unaffected
  29. func (c *Curve) Continue(other *Curve) *Curve {
  30. last := c.points[len(c.points) - 1].Clone()
  31. first := other.points[0].Clone()
  32. var continued, otherpoints []Vector3
  33. for i := 0; i < len(c.points); i++ {
  34. continued = append(continued, *c.points[i].Clone())
  35. }
  36. for i := 1; i < len(other.points); i++ {
  37. otherpoints = append(otherpoints, *other.points[i].Clone())
  38. }
  39. for i := 0; i < len(otherpoints); i++ {
  40. continued = append(continued, *otherpoints[i].Sub(first).Add(last))
  41. }
  42. newC := new(Curve)
  43. newC.points = continued
  44. newC.SetLength()
  45. return newC
  46. }
  47. // NewBezierQuadratic creates and returns a pointer to a new curve
  48. // Uses Vector3 pointers origin, control, and destination to calculate with
  49. // int npoints as the desired number of points along the curve
  50. func NewBezierQuadratic(origin, control, destination *Vector3, npoints int) *Curve {
  51. c := new(Curve)
  52. if npoints <= 2 {
  53. npoints = 3
  54. }
  55. var equation func(float32, float32, float32, float32) float32
  56. equation = func(t, v0, v1, v2 float32) float32 {
  57. a0 := 1.0 - t
  58. result := a0 * a0 * v0 + 2.0 * t * a0 * v1 + t * t * v2
  59. return result
  60. }
  61. var bezier []Vector3
  62. for i := 0; i <= npoints; i++ {
  63. t := float32(i) / float32(npoints)
  64. x := equation(t, origin.X, control.X, destination.X)
  65. y := equation(t, origin.Y, control.Y, destination.Y)
  66. z := equation(t, origin.Z, control.Z, destination.Z)
  67. vect := NewVector3(x, y, z)
  68. bezier = append(bezier, *vect)
  69. }
  70. c.points = bezier
  71. c.SetLength()
  72. return c
  73. }
  74. // NewBezierCubic creates and returns a pointer to a new curve
  75. // Uses Vector3 pointers origin, control1, control2, and destination to calculate with
  76. // int npoints as the desired number of points along the curve
  77. func NewBezierCubic(origin, control1, control2, destination *Vector3, npoints int) *Curve {
  78. c := new(Curve)
  79. if npoints <= 3 {
  80. npoints = 4
  81. }
  82. var equation func(float32, float32, float32, float32, float32) float32
  83. equation = func(t, v0, v1, v2, v3 float32) float32 {
  84. a0 := 1.0 - t
  85. result := a0 * a0 * a0 * v0 + 3.0 * t * a0 * a0 * v1 + 3.0 * t * t * a0 * v2 + t * t * t * v3
  86. return result
  87. }
  88. var bezier []Vector3
  89. for i := 0; i <= npoints; i++ {
  90. t := float32(i) / float32(npoints)
  91. x := equation(t, origin.X, control1.X, control2.X, destination.X)
  92. y := equation(t, origin.Y, control1.Y, control2.Y, destination.Y)
  93. z := equation(t, origin.Z, control1.Z, control2.Z, destination.Z)
  94. vect := NewVector3(x, y, z)
  95. bezier = append(bezier, *vect)
  96. }
  97. c.points = bezier
  98. c.SetLength()
  99. return c
  100. }
  101. // NewHermiteSpline creates and returns a pointer to a new curve
  102. // Uses Vector3 pointers origin, tangent1, destination, and tangent2 to calculate with
  103. // int npoints as the desired number of points along the curve
  104. func NewHermiteSpline(origin, tangent1, destination, tangent2 *Vector3, npoints int) *Curve {
  105. c := new(Curve)
  106. var equation func(float32, *Vector3, *Vector3, *Vector3, *Vector3) *Vector3
  107. equation = func(t float32, v0, tan0, v1, tan1 *Vector3) *Vector3 {
  108. t2 := t * t
  109. t3 := t * t2
  110. p0 := (2.0 * t3) - (3.0 * t2) + 1.0
  111. p1 := (-2.0 * t3) + (3.0 * t2)
  112. p2 := t3 - (2.0 * t2) + t
  113. p3 := t3 - t2
  114. x := (v0.X * p0) + (v1.X * p1) + (tan0.X * p2) + (tan1.X * p3)
  115. y := (v0.Y * p0) + (v1.Y * p1) + (tan0.Y * p2) + (tan1.Y * p3)
  116. z := (v0.Z * p0) + (v1.Z * p1) + (tan0.Z * p2) + (tan1.Z * p3)
  117. return NewVector3(x, y, z)
  118. }
  119. step := float32(1.0) / float32(npoints)
  120. var hermite []Vector3
  121. for i := 0; i <= npoints; i++ {
  122. vect := equation(float32(i) * step, origin, tangent1, destination, tangent2)
  123. hermite = append(hermite, *vect)
  124. }
  125. c.points = hermite
  126. c.SetLength()
  127. return c
  128. }
  129. // NewCatmullRomSpline creates and returns a pointer to a new curve
  130. // Uses array of Vector3 pointers with int npoints as the desired number of points between supplied points
  131. // Use Boolean closed with true to close the start and end points
  132. func NewCatmullRomSpline(points []*Vector3, npoints int, closed bool) *Curve {
  133. c := new(Curve)
  134. var equation func(float32, *Vector3, *Vector3, *Vector3, *Vector3) *Vector3
  135. equation = func(t float32, v0, v1, v2, v3 *Vector3) *Vector3 {
  136. t2 := t * t;
  137. t3 := t * t2;
  138. x := 0.5 * ((((2.0 * v1.X) + ((-v0.X + v2.X) * t)) +
  139. (((((2.0 * v0.X) - (5.0 * v1.X)) + (4.0 * v2.X)) - v3.X) * t2)) +
  140. ((((-v0.X + (3.0 * v1.X)) - (3.0 * v2.X)) + v3.X) * t3));
  141. y := 0.5 * ((((2.0 * v1.Y) + ((-v0.Y + v2.Y) * t)) +
  142. (((((2.0 * v0.Y) - (5.0 * v1.Y)) + (4.0 * v2.Y)) - v3.Y) * t2)) +
  143. ((((-v0.Y + (3.0 * v1.Y)) - (3.0 * v2.Y)) + v3.Y) * t3));
  144. z := 0.5 * ((((2.0 * v1.Z) + ((-v0.Z + v2.Z) * t)) +
  145. (((((2.0 * v0.Z) - (5.0 * v1.Z)) + (4.0 * v2.Z)) - v3.Z) * t2)) +
  146. ((((-v0.Z + (3.0 * v1.Z)) - (3.0 * v2.Z)) + v3.Z) * t3));
  147. return NewVector3(x, y, z);
  148. }
  149. step := float32(1.0) / float32(npoints)
  150. var catmull []Vector3
  151. var t float32
  152. if closed {
  153. count := len(points)
  154. for i := 0; i < count; i++ {
  155. t = 0.0
  156. for n := 0; n < npoints; n++ {
  157. vect := equation(t, points[i % count], points[(i + 1) % count], points[(i + 2) % count], points[(i + 3) % count])
  158. catmull = append(catmull, *vect)
  159. t += step
  160. }
  161. }
  162. catmull = append(catmull, catmull[0])
  163. } else {
  164. total := []*Vector3{points[0].Clone()}
  165. total = append(total, points...)
  166. total = append(total, points[len(points) - 1].Clone())
  167. var i int
  168. for i = 0; i < len(total) - 3; i++ {
  169. t = 0
  170. for n := 0; n < npoints; n++ {
  171. vect := equation(t, total[i], total[i + 1], total[i + 2], total[i + 3])
  172. catmull = append(catmull, *vect)
  173. t += step
  174. }
  175. }
  176. i--
  177. vect := equation(t, total[i], total[i + 1], total[i + 2], total[i + 3])
  178. catmull = append(catmull, *vect)
  179. }
  180. c.points = catmull
  181. c.SetLength()
  182. return c
  183. }