Guest User

Untitled

a guest
Oct 23rd, 2017
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.32 KB | None | 0 0
  1. /* camera.js */
  2.  
  3. // MAY FAIL FOR POINTS INSIDE ELLIPSE
  4. function closestPointOnEllipse (c, e, ITERATIONS) {
  5. ITERATIONS = ITERATIONS || 2 // >= 2 is good enough
  6. var t = Math.atan2(e.rx * c.y, e.ry * c.x)
  7.  
  8. var X = c.x * e.rx
  9. var Y = c.y * e.ry
  10. var D = (e.rx * e.rx - e.ry * e.ry)
  11.  
  12. for (var i = 0; i < ITERATIONS; i++) {
  13. // netwon's method: t = t - f(t) / f'(t)
  14. var cos_t = Math.cos(t)
  15. var sin_t = Math.sin(t)
  16. t -= (D * cos_t * sin_t - X * sin_t + Y * cos_t) / (D * (cos_t * cos_t - sin_t * sin_t) - X * cos_t - Y * sin_t)
  17. }
  18. return {
  19. x: e.rx * Math.cos(t),
  20. y: e.ry * Math.sin(t)
  21. }
  22. }
  23.  
  24. function softBound (t, pull, push) {
  25. if (pull >= 1) return 0
  26. let slope = 1 - pull
  27. let threshold = (1 + pull) * (1 - push)
  28. let u
  29. if (t > threshold) {
  30. u = 1
  31. if (push > 0) {
  32. let c = 1 - slope * threshold
  33. let k = 1 - c * Math.pow(Math.exp(slope / c), -t + threshold)
  34. u *= k
  35. }
  36. } else {
  37. u = t * slope
  38. }
  39. return u
  40. }
  41.  
  42. function ovalBound (p, {rx, ry}, {pull, push}) {
  43. let dr = push * ((rx > ry) ? ry : rx)
  44. rx -= dr
  45. ry -= dr
  46. let x = p.x / rx
  47. let y = p.y / ry
  48. // (x,y) is point on inner ellipse, t is relative distance from center
  49. let t = x * x + y * y
  50. let innerLength, distance, outerDistance, dx, dy
  51. if (t <= 1) {
  52. t = Math.sqrt(t)
  53. x = p.x / t
  54. y = p.y / t
  55. innerLength = Math.sqrt(x * x + y * y)
  56. distance = Math.sqrt(p.x * p.x + p.y * p.y)
  57. } else {
  58. ({x, y} = closestPointOnEllipse(p, {rx, ry}))
  59. dx = p.x - x
  60. dy = p.y - y
  61. innerLength = Math.sqrt(x * x + y * y)
  62. outerDistance = Math.sqrt(dx * dx + dy * dy)
  63. distance = outerDistance + innerLength
  64. }
  65. let totalLength = dr + innerLength
  66. let pushThreshold = dr / totalLength
  67. t = distance / totalLength
  68. let u = softBound(t, pull, pushThreshold)
  69. if (u <= (1 - pushThreshold)) {
  70. return {
  71. x: x * u * totalLength / innerLength,
  72. y: y * u * totalLength / innerLength
  73. }
  74. } else {
  75. let k = (u - (1 - pushThreshold)) / pushThreshold
  76. return {
  77. x: dx * k * dr / outerDistance + x,
  78. y: dy * k * dr / outerDistance + y
  79. }
  80. }
  81. }
  82.  
  83. function rectBound ({x, y}, {rx, ry}, {pull, push}) {
  84. return {
  85. x: Math.sign(x) * rx * softBound(Math.abs(x) / rx, pull, push),
  86. y: Math.sign(y) * ry * softBound(Math.abs(y) / ry, pull, push)
  87. }
  88. }
  89.  
  90. function smoothBound (pos, {rx, ry}, {squareness, roundness, ...settings}) {
  91. if (rx > ry) {
  92. rx = squareness * ry + (1 - squareness) * rx
  93. } else {
  94. ry = squareness * rx + (1 - squareness) * ry
  95. }
  96. let ovalBounded = ovalBound(pos, {rx, ry}, settings)
  97. let rectBounded = rectBound(pos, {rx, ry}, settings)
  98. return {
  99. x: roundness * ovalBounded.x + (1 - roundness) * rectBounded.x,
  100. y: roundness * ovalBounded.y + (1 - roundness) * rectBounded.y
  101. }
  102. }
  103.  
  104. function makeCamera (bound) {
  105. return (prevPos, {x, y}, z, {w, h}, {area, ...settings}) => {
  106. let delta = {
  107. x: x - prevPos.x,
  108. y: y - prevPos.y
  109. }
  110. if (delta.x === 0 && delta.y === 0) {
  111. return prevPos
  112. }
  113. let bounded = bound(delta, {rx: area * z * w / 2, ry: area * z * h / 2}, settings)
  114. return {
  115. x: prevPos.x + delta.x - bounded.x,
  116. y: prevPos.y + delta.y - bounded.y
  117. }
  118. }
  119. }
  120.  
  121. export const defaultSettings = {
  122. area: 0.4,
  123. pull: 0.01,
  124. push: 0.8,
  125. roundness: 0.5,
  126. squareness: 0
  127. }
  128. export const smoothCam = makeCamera(smoothBound)
Add Comment
Please, Sign In to add comment