Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

shapes.ts 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. import {
  2. boundsCollide,
  3. boundsContain,
  4. pointInBounds,
  5. } from "state/sessions/brush-session"
  6. import {
  7. Shape,
  8. Bounds,
  9. ShapeType,
  10. CircleShape,
  11. DotShape,
  12. RectangleShape,
  13. Shapes,
  14. EllipseShape,
  15. LineShape,
  16. RayShape,
  17. LineSegmentShape,
  18. } from "types"
  19. import { intersectCircleBounds } from "./intersections"
  20. import * as vec from "./vec"
  21. type BaseShapeUtils<K extends ShapeType> = {
  22. getBounds(shape: Shapes[K]): Bounds
  23. hitTest(shape: Shapes[K], test: number[] | Bounds): boolean
  24. rotate(shape: Shapes[K]): Shapes[K]
  25. translate(shape: Shapes[K]): Shapes[K]
  26. scale(shape: Shapes[K], scale: number): Shapes[K]
  27. stretch(shape: Shapes[K], scaleX: number, scaleY: number): Shapes[K]
  28. }
  29. /* ----------------------- Dot ---------------------- */
  30. const DotUtils: BaseShapeUtils<ShapeType.Dot> = {
  31. getBounds(shape) {
  32. const {
  33. point: [cx, cy],
  34. } = shape
  35. return {
  36. minX: cx - 2,
  37. maxX: cx + 2,
  38. minY: cy - 2,
  39. maxY: cy + 2,
  40. width: 4,
  41. height: 4,
  42. }
  43. },
  44. hitTest(shape, test) {
  45. if ("minX" in test) {
  46. return pointInBounds(shape.point, test)
  47. }
  48. return vec.dist(shape.point, test) < 4
  49. },
  50. rotate(shape) {
  51. return shape
  52. },
  53. translate(shape) {
  54. return shape
  55. },
  56. scale(shape, scale: number) {
  57. return shape
  58. },
  59. stretch(shape, scaleX: number, scaleY: number) {
  60. return shape
  61. },
  62. }
  63. /* --------------------- Circle --------------------- */
  64. const CircleUtils: BaseShapeUtils<ShapeType.Circle> = {
  65. getBounds(shape) {
  66. const {
  67. point: [cx, cy],
  68. radius,
  69. } = shape
  70. return {
  71. minX: cx - radius,
  72. maxX: cx + radius,
  73. minY: cy - radius,
  74. maxY: cy + radius,
  75. width: radius * 2,
  76. height: radius * 2,
  77. }
  78. },
  79. hitTest(shape, test) {
  80. if ("minX" in test) {
  81. const bounds = CircleUtils.getBounds(shape)
  82. return (
  83. boundsContain(bounds, test) ||
  84. intersectCircleBounds(shape.point, shape.radius, bounds).length > 0
  85. )
  86. }
  87. return vec.dist(shape.point, test) < 4
  88. },
  89. rotate(shape) {
  90. return shape
  91. },
  92. translate(shape) {
  93. return shape
  94. },
  95. scale(shape, scale: number) {
  96. return shape
  97. },
  98. stretch(shape, scaleX: number, scaleY: number) {
  99. return shape
  100. },
  101. }
  102. /* --------------------- Ellipse -------------------- */
  103. const EllipseUtils: BaseShapeUtils<ShapeType.Ellipse> = {
  104. getBounds(shape) {
  105. return {
  106. minX: 0,
  107. minY: 0,
  108. maxX: 0,
  109. maxY: 0,
  110. width: 0,
  111. height: 0,
  112. }
  113. },
  114. hitTest(shape) {
  115. return true
  116. },
  117. rotate(shape) {
  118. return shape
  119. },
  120. translate(shape) {
  121. return shape
  122. },
  123. scale(shape, scale: number) {
  124. return shape
  125. },
  126. stretch(shape, scaleX: number, scaleY: number) {
  127. return shape
  128. },
  129. }
  130. /* ---------------------- Line ---------------------- */
  131. const LineUtils: BaseShapeUtils<ShapeType.Line> = {
  132. getBounds(shape) {
  133. return {
  134. minX: 0,
  135. minY: 0,
  136. maxX: 0,
  137. maxY: 0,
  138. width: 0,
  139. height: 0,
  140. }
  141. },
  142. hitTest(shape) {
  143. return true
  144. },
  145. rotate(shape) {
  146. return shape
  147. },
  148. translate(shape) {
  149. return shape
  150. },
  151. scale(shape, scale: number) {
  152. return shape
  153. },
  154. stretch(shape, scaleX: number, scaleY: number) {
  155. return shape
  156. },
  157. }
  158. /* ----------------------- Ray ---------------------- */
  159. const RayUtils: BaseShapeUtils<ShapeType.Ray> = {
  160. getBounds(shape) {
  161. return {
  162. minX: Infinity,
  163. minY: Infinity,
  164. maxX: Infinity,
  165. maxY: Infinity,
  166. width: Infinity,
  167. height: Infinity,
  168. }
  169. },
  170. hitTest(shape) {
  171. return true
  172. },
  173. rotate(shape) {
  174. return shape
  175. },
  176. translate(shape) {
  177. return shape
  178. },
  179. scale(shape, scale: number) {
  180. return shape
  181. },
  182. stretch(shape, scaleX: number, scaleY: number) {
  183. return shape
  184. },
  185. }
  186. /* ------------------ Line Segment ------------------ */
  187. const LineSegmentUtils: BaseShapeUtils<ShapeType.LineSegment> = {
  188. getBounds(shape) {
  189. return {
  190. minX: 0,
  191. minY: 0,
  192. maxX: 0,
  193. maxY: 0,
  194. width: 0,
  195. height: 0,
  196. }
  197. },
  198. hitTest(shape) {
  199. return true
  200. },
  201. rotate(shape) {
  202. return shape
  203. },
  204. translate(shape) {
  205. return shape
  206. },
  207. scale(shape, scale: number) {
  208. return shape
  209. },
  210. stretch(shape, scaleX: number, scaleY: number) {
  211. return shape
  212. },
  213. }
  214. /* -------------------- Rectangle ------------------- */
  215. const RectangleUtils: BaseShapeUtils<ShapeType.Rectangle> = {
  216. getBounds(shape) {
  217. const {
  218. point: [x, y],
  219. size: [width, height],
  220. } = shape
  221. return {
  222. minX: x,
  223. maxX: x + width,
  224. minY: y,
  225. maxY: y + height,
  226. width,
  227. height,
  228. }
  229. },
  230. hitTest(shape) {
  231. return true
  232. },
  233. rotate(shape) {
  234. return shape
  235. },
  236. translate(shape) {
  237. return shape
  238. },
  239. scale(shape, scale: number) {
  240. return shape
  241. },
  242. stretch(shape, scaleX: number, scaleY: number) {
  243. return shape
  244. },
  245. }
  246. const shapeUtils: { [K in ShapeType]: BaseShapeUtils<K> } = {
  247. [ShapeType.Dot]: DotUtils,
  248. [ShapeType.Circle]: CircleUtils,
  249. [ShapeType.Ellipse]: EllipseUtils,
  250. [ShapeType.Line]: LineUtils,
  251. [ShapeType.Ray]: RayUtils,
  252. [ShapeType.LineSegment]: LineSegmentUtils,
  253. [ShapeType.Rectangle]: RectangleUtils,
  254. }
  255. export default shapeUtils