您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

vector.ts 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. export interface VectorOptions {
  2. x: number
  3. y: number
  4. }
  5. export interface Point {
  6. x: number
  7. y: number
  8. }
  9. export default class Vector {
  10. x = 0
  11. y = 0
  12. constructor(x: number, y: number)
  13. constructor(vector: Vector, b?: undefined)
  14. constructor(options: Point, b?: undefined)
  15. constructor(a: VectorOptions | Vector | number, b?: number) {
  16. if (typeof a === 'number') {
  17. this.x = a
  18. this.y = b
  19. } else {
  20. const { x = 0, y = 0 } = a
  21. this.x = x
  22. this.y = y
  23. }
  24. }
  25. set(v: Vector | Point): Vector {
  26. this.x = v.x
  27. this.y = v.y
  28. return this
  29. }
  30. copy(): Vector {
  31. return new Vector(this)
  32. }
  33. clone(): Vector {
  34. return this.copy()
  35. }
  36. toArray(): number[] {
  37. return [this.x, this.y]
  38. }
  39. add(b: Vector): Vector {
  40. this.x += b.x
  41. this.y += b.y
  42. return this
  43. }
  44. static add(a: Vector, b: Vector): Vector {
  45. const n = new Vector(a)
  46. n.x += b.x
  47. n.y += b.y
  48. return n
  49. }
  50. sub(b: Vector): Vector {
  51. this.x -= b.x
  52. this.y -= b.y
  53. return this
  54. }
  55. static sub(a: Vector, b: Vector): Vector {
  56. const n = new Vector(a)
  57. n.x -= b.x
  58. n.y -= b.y
  59. return n
  60. }
  61. mul(b: number): Vector
  62. mul(b: Vector): Vector
  63. mul(b: Vector | number): Vector {
  64. if (b instanceof Vector) {
  65. this.x *= b.x
  66. this.y *= b.y
  67. } else {
  68. this.x *= b
  69. this.y *= b
  70. }
  71. return this
  72. }
  73. mulScalar(b: number): Vector {
  74. return this.mul(b)
  75. }
  76. static mulScalar(a: Vector, b: number): Vector {
  77. return Vector.mul(a, b)
  78. }
  79. static mul(a: Vector, b: number): Vector
  80. static mul(a: Vector, b: Vector): Vector
  81. static mul(a: Vector, b: Vector | number): Vector {
  82. const n = new Vector(a)
  83. if (b instanceof Vector) {
  84. n.x *= b.x
  85. n.y *= b.y
  86. } else {
  87. n.x *= b
  88. n.y *= b
  89. }
  90. return n
  91. }
  92. div(b: number): Vector
  93. div(b: Vector): Vector
  94. div(b: Vector | number): Vector {
  95. if (b instanceof Vector) {
  96. if (b.x) {
  97. this.x /= b.x
  98. }
  99. if (b.y) {
  100. this.y /= b.y
  101. }
  102. } else {
  103. if (b) {
  104. this.x /= b
  105. this.y /= b
  106. }
  107. }
  108. return this
  109. }
  110. static div(a: Vector, b: number): Vector
  111. static div(a: Vector, b: Vector): Vector
  112. static div(a: Vector, b: Vector | number): Vector {
  113. const n = new Vector(a)
  114. if (b instanceof Vector) {
  115. if (b.x) n.x /= b.x
  116. if (b.y) n.y /= b.y
  117. } else {
  118. if (b) {
  119. n.x /= b
  120. n.y /= b
  121. }
  122. }
  123. return n
  124. }
  125. divScalar(b: number): Vector {
  126. return this.div(b)
  127. }
  128. static divScalar(a: Vector, b: number): Vector {
  129. return Vector.div(a, b)
  130. }
  131. vec(b: Vector): Vector {
  132. const { x, y } = this
  133. this.x = b.x - x
  134. this.y = b.y - y
  135. return this
  136. }
  137. static vec(a: Vector, b: Vector): Vector {
  138. const n = new Vector(a)
  139. n.x = b.x - a.x
  140. n.y = b.y - a.y
  141. return n
  142. }
  143. pry(b: Vector): number {
  144. return this.dpr(b) / b.len()
  145. }
  146. static pry(a: Vector, b: Vector): number {
  147. return a.dpr(b) / b.len()
  148. }
  149. dpr(b: Vector): number {
  150. return this.x * b.x + this.y * b.y
  151. }
  152. static dpr(a: Vector, b: Vector): number {
  153. return a.x & (b.x + a.y * b.y)
  154. }
  155. cpr(b: Vector): number {
  156. return this.x * b.y - b.y * this.y
  157. }
  158. static cpr(a: Vector, b: Vector): number {
  159. return a.x * b.y - b.y * a.y
  160. }
  161. tangent(b: Vector): Vector {
  162. return this.sub(b).uni()
  163. }
  164. static tangent(a: Vector, b: Vector): Vector {
  165. const n = new Vector(a)
  166. return n.sub(b).uni()
  167. }
  168. dist2(b: Vector): number {
  169. return this.sub(b).len2()
  170. }
  171. static dist2(a: Vector, b: Vector): number {
  172. const n = new Vector(a)
  173. return n.sub(b).len2()
  174. }
  175. dist(b: Vector): number {
  176. return Math.hypot(b.y - this.y, b.x - this.x)
  177. }
  178. static dist(a: Vector, b: Vector): number {
  179. const n = new Vector(a)
  180. return Math.hypot(b.y - n.y, b.x - n.x)
  181. }
  182. ang(b: Vector): number {
  183. return Math.atan2(b.y - this.y, b.x - this.x)
  184. }
  185. static ang(a: Vector, b: Vector): number {
  186. const n = new Vector(a)
  187. return Math.atan2(b.y - n.y, b.x - n.x)
  188. }
  189. med(b: Vector): Vector {
  190. return this.add(b).mul(0.5)
  191. }
  192. static med(a: Vector, b: Vector): Vector {
  193. const n = new Vector(a)
  194. return n.add(b).mul(0.5)
  195. }
  196. rot(r: number): Vector {
  197. const { x, y } = this
  198. this.x = x * Math.cos(r) - y * Math.sin(r)
  199. this.y = x * Math.sin(r) + y * Math.cos(r)
  200. return this
  201. }
  202. static rot(a: Vector, r: number): Vector {
  203. const n = new Vector(a)
  204. n.x = a.x * Math.cos(r) - a.y * Math.sin(r)
  205. n.y = a.x * Math.sin(r) + a.y * Math.cos(r)
  206. return n
  207. }
  208. rotAround(b: Vector, r: number): Vector {
  209. const { x, y } = this
  210. const s = Math.sin(r)
  211. const c = Math.cos(r)
  212. const px = x - b.x
  213. const py = y - b.y
  214. this.x = px * c - py * s + b.x
  215. this.y = px * s + py * c + b.y
  216. return this
  217. }
  218. static rotAround(a: Vector, b: Vector, r: number): Vector {
  219. const n = new Vector(a)
  220. const s = Math.sin(r)
  221. const c = Math.cos(r)
  222. const px = n.x - b.x
  223. const py = n.y - b.y
  224. n.x = px * c - py * s + b.x
  225. n.y = px * s + py * c + b.y
  226. return n
  227. }
  228. lrp(b: Vector, t: number): Vector {
  229. const n = new Vector(this)
  230. this.vec(b).mul(t).add(n)
  231. return this
  232. }
  233. static lrp(a: Vector, b: Vector, t: number): Vector {
  234. const n = new Vector(a)
  235. n.vec(b).mul(t).add(a)
  236. return n
  237. }
  238. nudge(b: Vector, d: number): Vector {
  239. this.add(b.mul(d))
  240. return this
  241. }
  242. static nudge(a: Vector, b: Vector, d: number): Vector {
  243. const n = new Vector(a)
  244. return n.add(b.mul(d))
  245. }
  246. nudgeToward(b: Vector, d: number): Vector {
  247. return this.nudge(Vector.vec(this, b).uni(), d)
  248. }
  249. static nudgeToward(a: Vector, b: Vector, d: number): Vector {
  250. return Vector.nudge(a, Vector.vec(a, b).uni(), d)
  251. }
  252. int(b: Vector, from: number, to: number, s: number): Vector {
  253. const t = (Math.max(from, to) - from) / (to - from)
  254. this.add(Vector.mul(this, 1 - t).add(Vector.mul(b, s)))
  255. return this
  256. }
  257. static int(
  258. a: Vector,
  259. b: Vector,
  260. from: number,
  261. to: number,
  262. s: number
  263. ): Vector {
  264. const n = new Vector(a)
  265. const t = (Math.max(from, to) - from) / (to - from)
  266. n.add(Vector.mul(a, 1 - t).add(Vector.mul(b, s)))
  267. return n
  268. }
  269. equals(b: Vector): boolean {
  270. return this.x === b.x && this.y === b.y
  271. }
  272. static equals(a: Vector, b: Vector): boolean {
  273. return a.x === b.x && a.y === b.y
  274. }
  275. abs(): Vector {
  276. this.x = Math.abs(this.x)
  277. this.y = Math.abs(this.y)
  278. return this
  279. }
  280. static abs(a: Vector): Vector {
  281. const n = new Vector(a)
  282. n.x = Math.abs(n.x)
  283. n.y = Math.abs(n.y)
  284. return n
  285. }
  286. len(): number {
  287. return Math.hypot(this.x, this.y)
  288. }
  289. static len(a: Vector): number {
  290. return Math.hypot(a.x, a.y)
  291. }
  292. len2(): number {
  293. return this.x * this.x + this.y * this.y
  294. }
  295. static len2(a: Vector): number {
  296. return a.x * a.x + a.y * a.y
  297. }
  298. per(): Vector {
  299. const t = this.x
  300. this.x = this.y
  301. this.y = -t
  302. return this
  303. }
  304. static per(a: Vector): Vector {
  305. const n = new Vector(a)
  306. n.x = n.y
  307. n.y = -a.x
  308. return n
  309. }
  310. neg(): Vector {
  311. this.x *= -1
  312. this.y *= -1
  313. return this
  314. }
  315. static neg(v: Vector): Vector {
  316. const n = new Vector(v)
  317. n.x *= -1
  318. n.y *= -1
  319. return n
  320. }
  321. uni(): Vector {
  322. return this.div(this.len())
  323. }
  324. static uni(v: Vector): Vector {
  325. const n = new Vector(v)
  326. return n.div(n.len())
  327. }
  328. normalize(): Vector {
  329. return this.uni()
  330. }
  331. static normalize(v: Vector): Vector {
  332. return Vector.uni(v)
  333. }
  334. isLeft(center: Vector, b: Vector): number {
  335. return (
  336. (center.x - this.x) * (b.y - this.y) - (b.x - this.x) * (center.y - b.y)
  337. )
  338. }
  339. static isLeft(center: Vector, a: Vector, b: Vector): number {
  340. return (center.x - a.x) * (b.y - a.y) - (b.x - a.x) * (center.y - b.y)
  341. }
  342. static ang3(center: Vector, a: Vector, b: Vector): number {
  343. const v1 = Vector.vec(center, a)
  344. const v2 = Vector.vec(center, b)
  345. return Vector.ang(v1, v2)
  346. }
  347. static clockwise(center: Vector, a: Vector, b: Vector): boolean {
  348. return Vector.isLeft(center, a, b) > 0
  349. }
  350. static cast(v: Point | Vector): Vector {
  351. return 'cast' in v ? v : new Vector(v)
  352. }
  353. static from(v: Vector): Vector {
  354. return new Vector(v)
  355. }
  356. nearestPointOnLineThroughPoint(b: Vector, u: Vector): Vector {
  357. return this.clone().add(u.clone().mul(Vector.sub(this, b).pry(u)))
  358. }
  359. static nearestPointOnLineThroughPoint(
  360. a: Vector,
  361. b: Vector,
  362. u: Vector
  363. ): Vector {
  364. return a.clone().add(u.clone().mul(Vector.sub(a, b).pry(u)))
  365. }
  366. distanceToLineThroughPoint(b: Vector, u: Vector): number {
  367. return this.dist(Vector.nearestPointOnLineThroughPoint(b, u, this))
  368. }
  369. static distanceToLineThroughPoint(a: Vector, b: Vector, u: Vector): number {
  370. return a.dist(Vector.nearestPointOnLineThroughPoint(b, u, a))
  371. }
  372. nearestPointOnLineSegment(p0: Vector, p1: Vector, clamp = true): Vector {
  373. return Vector.nearestPointOnLineSegment(this, p0, p1, clamp)
  374. }
  375. static nearestPointOnLineSegment(
  376. a: Vector,
  377. p0: Vector,
  378. p1: Vector,
  379. clamp = true
  380. ): Vector {
  381. const delta = Vector.sub(p1, p0)
  382. const length = delta.len()
  383. const u = Vector.div(delta, length)
  384. const pt = Vector.add(p0, Vector.mul(u, Vector.pry(Vector.sub(a, p0), u)))
  385. if (clamp) {
  386. const da = p0.dist(pt)
  387. const db = p1.dist(pt)
  388. if (db < da && da > length) return p1
  389. if (da < db && db > length) return p0
  390. }
  391. return pt
  392. }
  393. distanceToLineSegment(p0: Vector, p1: Vector, clamp = true): number {
  394. return Vector.distanceToLineSegment(this, p0, p1, clamp)
  395. }
  396. static distanceToLineSegment(
  397. a: Vector,
  398. p0: Vector,
  399. p1: Vector,
  400. clamp = true
  401. ): number {
  402. return Vector.dist(a, Vector.nearestPointOnLineSegment(a, p0, p1, clamp))
  403. }
  404. }