Bezier.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /** @format */
  2. export class Bezier {
  3. // 对外变量
  4. private static p0: cc.Vec2 // 起点
  5. private static p1: cc.Vec2 // 贝塞尔点
  6. private static p2: cc.Vec2 // 终点
  7. private static step: number = 0 // 分割份数
  8. // 辅助变量
  9. private static ax: number = 0
  10. private static ay: number = 0
  11. private static bx: number = 0
  12. private static by: number = 0
  13. private static A: number = 0
  14. private static B: number = 0
  15. private static C: number = 0
  16. private static total_length: number = 0 // 长度
  17. public constructor() {}
  18. // 速度函数
  19. private static Speed(t: number): number {
  20. return Math.sqrt(this.A * t * t + this.B * t + this.C)
  21. }
  22. // 长度函数
  23. private static Length(t: number): number {
  24. let temp1: number = Math.sqrt(this.C + t * (this.B + this.A * t))
  25. let temp2: number = 2 * this.A * t * temp1 + this.B * (temp1 - Math.sqrt(this.C))
  26. let temp3: number = Math.log(this.B + 2 * Math.sqrt(this.A) * Math.sqrt(this.C))
  27. let temp4: number = Math.log(this.B + 2 * this.A * t + 2 * Math.sqrt(this.A) * temp1)
  28. let temp5: number = 2 * Math.sqrt(this.A) * temp2
  29. let temp6: number = (this.B * this.B - 4 * this.A * this.C) * (temp3 - temp4)
  30. return (temp5 + temp6) / (8 * Math.pow(this.A, 1.5))
  31. }
  32. // 长度函数反函数,使用牛顿切线法求解
  33. private static InvertL(t: number, l: number): number {
  34. let t1: number = t
  35. let t2: number = 0
  36. do {
  37. t2 = t1 - (this.Length(t1) - l) / this.Speed(t1)
  38. if (Math.abs(t1 - t2) < 0.000001) break
  39. t1 = t2
  40. } while (true)
  41. return t2
  42. }
  43. // 返回所需总步数
  44. public static init($p0: cc.Vec2, $p1: cc.Vec2, $p2: cc.Vec2, $speed: number): number {
  45. this.p0 = $p0
  46. this.p1 = $p1
  47. this.p2 = $p2
  48. //step = 30;
  49. this.ax = this.p0.x - 2 * this.p1.x + this.p2.x
  50. this.ay = this.p0.y - 2 * this.p1.y + this.p2.y
  51. this.bx = 2 * this.p1.x - 2 * this.p0.x
  52. this.by = 2 * this.p1.y - 2 * this.p0.y
  53. this.A = 4 * (this.ax * this.ax + this.ay * this.ay)
  54. this.B = 4 * (this.ax * this.bx + this.ay * this.by)
  55. this.C = this.bx * this.bx + this.by * this.by
  56. // 计算长度
  57. this.total_length = this.Length(1)
  58. // 计算步数
  59. this.step = Math.floor(this.total_length / $speed)
  60. if (this.total_length % $speed > $speed / 2) this.step++
  61. return this.step
  62. }
  63. // 根据指定nIndex位置获取锚点:返回坐标和角度
  64. public static getAnchorPoint(nIndex: number): any[] {
  65. if (nIndex >= 0 && nIndex <= this.step) {
  66. let t: number = nIndex / this.step
  67. // 如果按照线性增长,此时对应的曲线长度
  68. let l: number = t * this.total_length
  69. // 根据L函数的反函数,求得l对应的t值
  70. t = this.InvertL(t, l)
  71. // 根据贝塞尔曲线函数,求得取得此时的x,y坐标
  72. let xx: number = (1 - t) * (1 - t) * this.p0.x + 2 * (1 - t) * t * this.p1.x + t * t * this.p2.x
  73. let yy: number = (1 - t) * (1 - t) * this.p0.y + 2 * (1 - t) * t * this.p1.y + t * t * this.p2.y
  74. // 获取切线
  75. let Q0: cc.Vec2 = new cc.Vec2((1 - t) * this.p0.x + t * this.p1.x, (1 - t) * this.p0.y + t * this.p1.y)
  76. let Q1: cc.Vec2 = new cc.Vec2((1 - t) * this.p1.x + t * this.p2.x, (1 - t) * this.p1.y + t * this.p2.y)
  77. // 计算角度
  78. let dx: number = Q1.x - Q0.x
  79. let dy: number = Q1.y - Q0.y
  80. let radians: number = Math.atan2(dy, dx)
  81. let degrees: number = (radians * 180) / Math.PI
  82. return [xx, yy, degrees]
  83. } else {
  84. return []
  85. }
  86. }
  87. }