From e78ee9eda3b2bef2d546c73e36632c6b698565a6 Mon Sep 17 00:00:00 2001 From: ez_lcw Date: Tue, 4 Jul 2023 19:02:02 +0800 Subject: [PATCH] add Circle --- src/2d.js | 38 ++++++++++++++++++++++++++++++++++++++ tests/2d.test.js | 18 +++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/2d.js b/src/2d.js index 914e658..cfe66fa 100644 --- a/src/2d.js +++ b/src/2d.js @@ -2,12 +2,50 @@ function sqr(x) { return x * x; } +export class Circle { + constructor(o, r) { + this.o = o; + this.r = r; + } + + clone() { + return new Circle(this.o.clone(), this.r); + } + + equal(c) { + return this.o.equal(c.o) && this.r == c.r; + } + + static intersect(a, b) { + return a.o.sub(b.o).norm() <= sqr(a.r + b.r); + } + + static collisionElimation(a, b) { + if (!Circle.intersect(a, b)) { return false; } + const d = a.o.distanceTo(b.o); + const ad = (sqr(a.r) - sqr(b.r) + sqr(d)) / (2 * d); + const bd = d - ad; + const v = b.o.sub(a.o); + a.o.subTo(v.adjust(a.r - ad)); + b.o.addTo(v.adjust(b.r - bd)); + return true; + } +} + export class Vec2 { constructor(x, y) { this.x = x || 0; this.y = y || 0; } + adjust(len) { + return this.mul(len / this.abs()); + } + + distanceTo(b) { + return this.sub(b).abs(); + } + add(y) { return new Vec2(this.x + y.x, this.y + y.y); } diff --git a/tests/2d.test.js b/tests/2d.test.js index 6c603a0..1f0a90f 100644 --- a/tests/2d.test.js +++ b/tests/2d.test.js @@ -1,5 +1,5 @@ import assert from 'node:assert'; -import { Vec2 } from '../src/2d.js'; +import { Vec2, Circle } from '../src/2d.js'; describe('Vec2', function () { it('construct', function() { @@ -49,4 +49,20 @@ describe('Vec2', function () { assert.equal(p.dot(q), 10); assert.equal(p.cross(q), -10); }); + + it('circle intersect', function() { + let c1 = new Circle(new Vec2(0, 0), 1); + let c2 = new Circle(new Vec2(0, 1.5), 1); + let c3 = new Circle(new Vec2(2, 2), 1); + assert.ok(Circle.intersect(c1, c2)); + assert.ok(!Circle.intersect(c1, c3)); + }); + + it('circle collision elimation', function() { + let c1 = new Circle(new Vec2(0, 0), 1); + let c2 = new Circle(new Vec2(0, 1.5), 1); + assert.ok(Circle.collisionElimation(c1, c2)); + assert.ok(c1.equal(new Circle(new Vec2(0, -.25), 1))); + assert.ok(c2.equal(new Circle(new Vec2(0, 1.75), 1))); + }); }); \ No newline at end of file