Skip to content

Instantly share code, notes, and snippets.

@tomowarkar
Last active April 11, 2021 12:40
Show Gist options
  • Save tomowarkar/ad80230715e8779920f9b16bd92eba53 to your computer and use it in GitHub Desktop.
Save tomowarkar/ad80230715e8779920f9b16bd92eba53 to your computer and use it in GitHub Desktop.
https://editor.p5js.org/ コピペで動かせるぞ
class RotMat2 {
constructor(angle) {
this.cosa = Math.cos(angle)
this.sina = Math.sin(angle)
}
apply(v) {
return new Vec2(
this.cosa * v.x - this.sina * v.y,
this.sina * v.x + this.cosa * v.y
)
}
}
class Vec2 {
constructor(x, y) {
this.x = x === undefined ? 0.0: x
this.y = y === undefined ? this.x: y
}
static _exec(left, right, operator) {
right = Number.isFinite(right) ? new Vec2(right) : right
switch (operator) {
case '+':
return new Vec2(left.x + right.x, left.y + right.y)
case '-':
return new Vec2(left.x - right.x, left.y - right.y)
case '*':
return new Vec2(left.x * right.x, left.y * right.y)
case '/':
return new Vec2(left.x / right.x, left.y / right.y)
case '==':
case '===':
return left.x === right.x && left.y === right.y
case 'dot':
return left.x * right.x + left.y * right.y
case 'det':
return left.x * right.y - left.y * right.x
case 'distance':
return Vec2._exec(left, right, "-").length
case 'angle':
const det = Vec2._exec(left, right, "det"),
dot = Vec2._exec(left, right, "dot")
return Math.atan2(det, dot);
default:
return left
}
}
apply(v) {
this.x = v.x
this.y = v.y
}
add(other) {
return Vec2._exec(this, other, "+")
}
addeq(other) {
this.apply(this.add(other))
}
sub(other) {
return Vec2._exec(this, other, "-")
}
subeq(other) {
this.apply(this.sub(other))
}
mul(other) {
return Vec2._exec(this, other, "*")
}
muleq(other) {
this.apply(this.mul(other))
}
div(other) {
return Vec2._exec(this, other, "/")
}
diveq(other) {
this.apply(this.div(other))
}
isEqual(other) {
return Vec2._exec(this, other, "==")
}
get length() {
// return Math.sqrt(this.x * this.x + this.y * this.y)
return Math.hypot(this.x, this.y)
}
get normal() {
return new Vec2(-this.y, this.x)
}
normalized() {
const length = this.length
return new Vec2(this.x / length, this.y / length)
}
rotated(angle, origin) {
const v = this.sub(origin),
m = new RotMat2(angle)
return m.apply(v).add(origin)
}
}
class Particule {
constructor(pos, m) {
pos = pos === undefined ? new Vec2() : pos
m = m === undefined ? 1.0 : m
this.position = pos
this.old_position = pos
this.acceleration = new Vec2(0.0, 0.0)
this.mass = m
}
get inv_mass() {
return 1/this.mass
}
update(dt, air_friction) {
air_friction = air_friction === undefined ? 0.5 : air_friction
const velocity = this.position.sub(this.old_position)
this.acceleration.subeq(velocity.mul(air_friction))
const new_pos = this.position.add(velocity.add(this.acceleration.mul(dt)))
this.old_position = this.position
this.position = new_pos
this.acceleration = new Vec2(0.0, 0.0)
}
applyForce(v) {
this.acceleration.addeq(v.mul(1-this.inv_mass))
}
move(v) {
this.position.addeq(add)
}
}
class pParticule extends Particule {
constructor(...params) {
super(...params)
}
get radius() {
return Math.cbrt(this.mass * 3 / 4 / Math.PI) * 30
}
draw() {
ellipse(
(this.position.x%width+width)%width,
(this.position.y%height+height)%height,
this.radius
);
}
}
let particules = []
const NUM = 50
function setup() {
createCanvas(400, 400);
for (let i = 0; i< NUM; i++) {
let pos = new Vec2(random(0, width), random(0, height))
particules.push(new pParticule(pos, random(2, 7)))
}
// noLoop()
}
function draw() {
background(220);
particules.sort((a, b)=>{
return b.mass - a.mass
})
for (let i = 0; i < particules.length; i++) {
let p = particules[i]
p.applyForce(new Vec2(random(-1, 1), random(-1, 1)))
p.applyForce(new Vec2(0, -5))
p.update(1)
p.draw()
}
}
class RotMat2 {
constructor(angle) {
this.cosa = Math.cos(angle)
this.sina = Math.sin(angle)
}
apply(v) {
return new Vec2(
this.cosa * v.x - this.sina * v.y,
this.sina * v.x + this.cosa * v.y
)
}
}
class MinMat2x2 {
constructor(...values) {
const flag = values.length === 4
this.a = flag ? values[0] : 1
this.b = flag ? values[1] : 0
this.c = flag ? values[2] : 0
this.d = flag ? values[3] : 1
}
det() {
return this.a * this.d - this.b * this.c
}
adj() {
return new MinMat2x2(this.d, -this.b, -this.c, this.a)
}
inv() {
const det = this.det()
if (det === 0) throw new Error("zerodiv")
return new MinMat2x2(...Object.values(this.adj()).map(e=>e/det))
}
dot(other) {
if (other.hasOwnProperty("x") && other.hasOwnProperty("y")) {
return new Vec2(
this.a * other.x + this.b * other.y,
this.c * other.x + this.d * other.y
)
}
return new MinMat2x2(
this.a * other.a + this.b * other.c,
this.a * other.b + this.b * other.d,
this.c * other.a + this.d * other.c,
this.c * other.b + this.d * other.d
)
}
}
class Vec2 {
constructor(x, y) {
this.x = x === undefined ? 0.0: x
this.y = y === undefined ? this.x: y
}
static _exec(left, right, operator) {
right = Number.isFinite(right) ? new Vec2(right) : right
switch (operator) {
case '+':
return new Vec2(left.x + right.x, left.y + right.y)
case '-':
return new Vec2(left.x - right.x, left.y - right.y)
case '*':
return new Vec2(left.x * right.x, left.y * right.y)
case '/':
return new Vec2(left.x / right.x, left.y / right.y)
case '==':
case '===':
return left.x === right.x && left.y === right.y
case 'dot':
return left.x * right.x + left.y * right.y
case 'det':
return left.x * right.y - left.y * right.x
case 'distance':
return Vec2._exec(left, right, "-").length
case 'angle':
const det = Vec2._exec(left, right, "det"),
dot = Vec2._exec(left, right, "dot")
return Math.atan2(det, dot);
default:
return left
}
}
apply(v) {
this.x = v.x
this.y = v.y
}
add(other) {
return Vec2._exec(this, other, "+")
}
addeq(other) {
this.apply(this.add(other))
}
sub(other) {
return Vec2._exec(this, other, "-")
}
subeq(other) {
this.apply(this.sub(other))
}
mul(other) {
return Vec2._exec(this, other, "*")
}
muleq(other) {
this.apply(this.mul(other))
}
div(other) {
return Vec2._exec(this, other, "/")
}
diveq(other) {
this.apply(this.div(other))
}
isEqual(other) {
return Vec2._exec(this, other, "==")
}
get length() {
// return Math.sqrt(this.x * this.x + this.y * this.y)
return Math.hypot(this.x, this.y)
}
get normal() {
return new Vec2(-this.y, this.x)
}
normalized() {
const length = this.length
return new Vec2(this.x / length, this.y / length)
}
rotated(angle, origin) {
const v = this.sub(origin),
m = new RotMat2(angle)
return m.apply(v).add(origin)
}
}
// round = (value, base) => Math.round(value * (10**base)) / (10**base)
class Vec2x2 {
constructor(x1, y1, x2, y2) {
this.v1 = new Vec2(x1, y1)
this.v2 = new Vec2(x2, y2)
}
static _intersect(l1, l2) {
const p12 = l1.v1.sub(l1.v2),
p43 = l2.v2.sub(l2.v1),
p42 = l2.v2.sub(l1.v2)
let flag = false,
m = new Vec2()
try {
m = new MinMat2x2(p12.x, p43.x, p12.y, p43.y).inv().dot(p42)
flag = (0 <= m.x && m.x <= 1 && 0 <= m.y && m.y <= 1)
} catch(err) {
}
return [flag, m.x, m.y]
}
static intersection(l1, l2) {
const [ok, t, s] = Vec2x2._intersect(l1, l2)
return [ok, l1.v1.mul(t).add(l1.v2.mul(1-t))]
}
static drawIntersection(l1, l2) {
const [ok, p] = Vec2x2.intersection(l1, l2)
if (ok) ellipse(p.x, p.y, 5)
}
draw(c) {
stroke(c)
line(this.v1.x, this.v1.y, this.v2.x, this.v2.y)
stroke(0)
// text(`(${Object.values(this.v1)})`, ...Object.values(this.v1))
// text(`(${Object.values(this.v2)})`, ...Object.values(this.v2))
}
}
let lines = [
new Vec2x2(50, 200, 350, 200),
new Vec2x2(200, 200, 350, 400),
]
const NUM = 20
function setup() {
createCanvas(400, 400);
for (let i = 0; i< NUM; i++) {
lines.push(new Vec2x2(random(0, width), random(0, height), random(0, width), random(0, height)))
}
noLoop();
}
function draw() {
background(220);
for (let i = 0; i < lines.length; i++) {
lines[i].draw(0)
}
for (let i = 0; i < lines.length; i++) {
for (let j = i+1; j < lines.length; j++) {
Vec2x2.drawIntersection(lines[i], lines[j])
}
}
}
import p5 from "p5";
class Vec2 {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
get length() {
return Math.hypot(this.x, this.y);
}
get normal() {
return new Vec2(-this.y, this.x);
}
}
class Segment {
p1: Vec2;
p2: Vec2;
constructor(p1: Vec2, p2: Vec2) {
this.p1 = p1;
this.p2 = p2;
}
get x() {
return this.p2.x - this.p1.x;
}
get y() {
return this.p2.y - this.p1.y;
}
}
class Intersection {
s: number;
t: number;
point: Vec2;
isCross: boolean;
constructor(p1: Vec2, p2: Vec2, p3: Vec2, p4: Vec2) {
this.isCross = false;
let s1 = new Segment(p1, p2),
s2 = new Segment(p3, p4);
this.s =
(-s1.y * (p1.x - p3.x) + s1.x * (p1.y - p3.y)) /
(-s2.x * s1.y + s1.x * s2.y);
this.t =
(s2.x * (p1.y - p3.y) - s2.y * (p1.x - p3.x)) /
(-s2.x * s1.y + s1.x * s2.y);
this.point = new Vec2(p1.x + this.t * s1.x, p1.y + this.t * s1.y);
if (this.s >= 0 && this.s <= 1 && this.t >= 0 && this.t <= 1) {
this.isCross = true;
}
}
}
const sketch = (p: p5) => {
const drawSegment = (p1: Vec2, p2: Vec2, c: any) => {
p.stroke(c);
p.line(p1.x, p1.y, p2.x, p2.y);
p.stroke(0);
};
const drawPoint = (v: Vec2, c: any) => {
p.ellipse(v.x, v.y, c);
};
const drawIntersection = (p1: Vec2, p2: Vec2, p3: Vec2, p4: Vec2) => {
let isec = new Intersection(p1, p2, p3, p4);
if (isec.isCross) {
drawPoint(isec.point, 5);
}
};
let segments: Segment[] = [],
num_segments = 10;
p.setup = () => {
p.createCanvas(p.windowWidth, p.windowHeight);
for (let i = 0; i < num_segments; i++) {
segments.push(
new Segment(
new Vec2(p.random(0, p.width), p.random(0, p.height)),
new Vec2(p.random(0, p.width), p.random(0, p.height))
)
);
}
p.noLoop();
};
p.draw = () => {
p.background(220);
for (let i = 0; i < segments.length; i++) {
let s = segments[i];
drawSegment(s.p1, s.p2, 0);
}
for (let i = 0; i < segments.length; i++) {
for (let j = i + 1; j < segments.length; j++) {
let s1 = segments[i],
s2 = segments[j];
drawIntersection(s1.p1, s1.p2, s2.p1, s2.p2);
}
}
};
};
export default sketch;
class Vec2 {
constructor(x, y) {
if (typeof x === "number" && typeof y === "number") {
this.x = x;
this.y = y;
} else if (typeof x === "object") {
this.x = x.x;
this.y = x.y;
} else {
this.x = 0;
this.y = 0;
}
}
get len2() {
return this.x * this.x + this.y * this.y;
}
get len() {
return Math.sqrt(this.len2);
}
get gradients() {
return this.y === 0 ? 0 : this.x / this.y;
}
add(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x + v.x, this.y + v.y);
}
sub(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x - v.x, this.y - v.y);
}
mul(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x * v.x, this.y * v.y);
}
div(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x / v.x, this.y / v.y);
}
_draw(d) {
circle(this.x, height - this.y, d || 10);
}
draw(d) {
this._draw(d);
}
}
class Segment {
constructor(p1, p2) {
this.p1 = p1;
this.p2 = p2;
}
static make(x1, y1, x2, y2) {
return new Segment(new Vec2(x1, y1), new Vec2(x2, y2));
}
get p() {
return this.p2.sub(this.p1);
}
get x() {
return this.p.x;
}
get y() {
return this.p.y;
}
get x1() {
return this.p1.x;
}
get y1() {
return this.p1.y;
}
get x2() {
return this.p2.x;
}
get y2() {
return this.p2.y;
}
get len2() {
return this.p.len2;
}
get len() {
return this.p.len;
}
get center() {
return this.p1.add(this.p2).div(2);
}
// ax + by + c = 0
get a() {
let p = this.p;
if (p.x === 0) return 0;
return p.y / p.x;
}
get b() {
return -1;
}
get c() {
return this.y1 - this.a * this.x1;
}
toCircle() {
return new Circle(this.center, this.len / 2);
}
d2(x, y) {
let a = this.a,
b = this.b,
d = a * x + b * y + this.c;
return (d * d) / (a * a + b * b);
}
draw() {
line(this.x1, height - this.y1, this.x2, height - this.y2);
}
}
class Rect {
constructor(leftbottom, righttop) {
this.p1 = leftbottom;
this.p3 = righttop;
this.p2 = new Vec2(leftbottom.x, righttop.y)
this.p4 = new Vec2(righttop.x, leftbottom.y)
}
static make(x, y, w, h) {
return new Rect(new Vec2(x, y), new Vec2(x+w, y+h))
}
get x1(){
return this.p1.x
}
get x2(){
return this.p3.x
}
get y1(){
return this.p1.y
}
get y2(){
return this.p3.y
}
get bottomSeg() {
return new Segment(this.p1, this.p4)
}
get topSeg() {
return new Segment(this.p2, this.p3)
}
get leftSeg() {
return new Segment(this.p1, this.p2)
}
get rightSeg() {
return new Segment(this.p3, this.p4)
}
draw() {
this.bottomSeg.draw();
this.topSeg.draw();
this.leftSeg.draw();
this.rightSeg.draw();
}
}
class Circle extends Vec2 {
constructor(x, y, r) {
if (typeof x === "object") {
super(x);
this.r = y;
} else {
super(x, y);
this.r = r;
}
this.r = this.r || 30;
}
draw() {
this._draw(this.r * 2);
}
}
class Intersection {
constructor(s1, s2) {
this.isCross = false;
let p1 = s1.p1,
p3 = s2.p1;
this.s =
(-s1.y * (p1.x - p3.x) + s1.x * (p1.y - p3.y)) /
(-s2.x * s1.y + s1.x * s2.y);
this.t =
(s2.x * (p1.y - p3.y) - s2.y * (p1.x - p3.x)) /
(-s2.x * s1.y + s1.x * s2.y);
this.point = new Vec2(p1.x + this.t * s1.x, p1.y + this.t * s1.y);
if (this.s >= 0 && this.s <= 1 && this.t >= 0 && this.t <= 1) {
this.isCross = true;
}
this.s1 = s1;
this.s2 = s2;
}
static make(p1, p2, p3, p4) {
return new Intersection(new Segment(p1, p2), new Segment(p3, p4));
}
static _(a1, b1, c1, a2, b2, c2) {
let d = a1 * b2 - a2 * b1;
if (d === 0) return;
return new Vec2((b1 * c2 - b2 * c1) / d, (a2 * c1 - a1 * c2) / d);
}
static foot(x, y, a, b, c) {
return Intersection._(a, b, c, b, -a, a * y - b + x);
}
draw() {
if (this.point) this.point.draw(10);
}
}
const CollisionCircles = (b1, b2) => {
let s = new Segment(b1, b2);
return s.len2 <= (b1.r + b2.r) * (b1.r + b2.r);
};
const CollisionCircleSeg = (circle, seg) => {
if (seg.d2(circle.x, circle.y) > circle.r * circle.r) {
return false;
}
return CollisionCircles(circle, seg.toCircle());
};
class A extends Circle {
constructor(x, y, r) {
super(x, y, r)
}
fix(rect) {
if (this.x < rect.x1+this.r) this.x = rect.x1+this.r
if (this.y < rect.y1+this.r) this.y = rect.y1+this.r
if (rect.x2-this.r < this.x ) this.x = rect.x2-this.r
if (rect.y2-this.r < this.y ) this.y = rect.y2-this.r
if (this.x < rect.x1+this.r && this.x < rect.x1+this.r){
this.x = (rect.x1 + rect.x2)/2
}
}
}
let bigRect, pointer, seg, smallRect;
let x, y;
function setup() {
createCanvas(400, 400);
bigRect = new Rect(new Vec2(10, 10), new Vec2(390, 390));
pointer = new A(width / 2, height / 2);
seg = Segment.make(100, 200, 300, 300);
smallRect = Rect.make(30, 30, 50, 100)
// noLoop()
}
function draw() {
background(220);
seg.draw();
bigRect.draw();
smallRect.draw()
pointer.x = mouseX;
pointer.y = height - mouseY;
pointer.fix(bigRect)
if (CollisionCircleSeg(pointer, seg)) fill("red");
// pointer.fix(r)
pointer.draw();
fill(255);
}
class Vec2 {
constructor(x, y) {
this.x = x || 0;
this.y = y || 0;
}
get len2() {
return this.x * this.x + this.y * this.y;
}
get len() {
return Math.sqrt(this.len2);
}
// get gradients() {
// return this.x === 0 ? 0 : this.y / this.x;
// }
get theta() {
return Math.atan2(this.y, this.x);
}
add(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x + v.x, this.y + v.y);
}
sub(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x - v.x, this.y - v.y);
}
mul(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x * v.x, this.y * v.y);
}
div(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x / v.x, this.y / v.y);
}
move(v) {
this.x += v.x;
this.y += v.y;
}
moveTo(v) {
this.x = v.x;
this.y = v.y;
}
draw() {
circle(this.x, height - this.y, 1);
}
}
const drawline = (v1, v2) => {
line(v1.x, height - v1.y, v2.x, height - v2.y);
};
class Shape extends Vec2 {
constructor(x, y, w, h) {
super(x, y);
this.w = w || 0;
this.h = h || 0;
}
get p1() {
return new Vec2(this.x - this.w / 2, this.y - this.h / 2);
}
set p1(v) {
this.move(v.sub(this.p1));
}
get p2() {
return new Vec2(this.x - this.w / 2, this.y + this.h / 2);
}
get p3() {
return new Vec2(this.x + this.w / 2, this.y + this.h / 2);
}
get p4() {
return new Vec2(this.x + this.w / 2, this.y - this.h / 2);
}
draw() {
this.frame();
}
frame() {
drawline(this.p1, this.p2);
drawline(this.p2, this.p3);
drawline(this.p3, this.p4);
drawline(this.p4, this.p1);
}
_hover(v) {
return (
this.p1.x <= v.x &&
v.x <= this.p3.x &&
this.p1.y <= v.y &&
v.y <= this.p3.y
);
}
hover(v) {
return this._hover(v);
}
}
class Ellipse extends Shape {
draw() {
ellipse(this.x, height - this.y, this.w, this.h);
}
hover(v) {
if (!this._hover(v)) {
return false;
}
let a2 = this.w/2 * this.w/2
let b2 = this.h/2 * this.h/2
let v2 = this.sub(v)
return (v2.x*v2.x/a2)+ (v2.y*v2.y/b2) <= 1
}
}
class Circle extends Ellipse {
constructor(x, y, r) {
super(x, y, 2 * r, 2 * r);
}
get r() {
return this.w / 2;
}
draw() {
circle(this.x, height - this.y, this.w);
}
}
class Fan extends Ellipse {
constructor(x, y, w, h, start, end) {
super(x, y, w, h);
this.start = start;
this.end = end;
}
draw() {
arc(
this.x,
height - this.y,
this.w,
this.h,
TWO_PI - this.end,
TWO_PI - this.start
);
}
}
class Rect extends Shape {
constructor(leftbottom, righttop) {
let c = righttop.add(leftbottom).div(2),
d = righttop.sub(leftbottom);
super(c.x, c.y, d.x, d.y);
}
}
let p, b;
function setup() {
createCanvas(400, 400);
p = new Circle(200, 200, 10);
b = new Shape(width / 2, height / 2, 380, 380);
// noLoop()
}
function draw() {
background(220);
b.frame();
p.moveTo(new Vec2(mouseX, height - mouseY));
// c = new Ellipse(width / 2, height / 2, 100, 200);
c = new Circle(100, 200, 100)
// c = new Fan(100, 200, 100, 200, -HALF_PI/2, PI)
c.draw();
c.frame();
drawline(c, p);
if (c.hover(p)) fill("red");
p.draw();
fill(220);
}
class Vec2 {
constructor(x, y) {
this.x = x || 0;
this.y = y || 0;
}
get len2() {
return this.x * this.x + this.y * this.y;
}
get len() {
return Math.sqrt(this.len2);
}
set len(l) {
let n = this.normalized().mul(l);
this.moveTo(n);
}
normal(){}
normalized() {
let len = this.len;
return new Vec2(this.x / len, this.y / len);
}
// get gradients() {
// return this.x === 0 ? 0 : this.y / this.x;
// }
get theta() {
return Math.atan2(this.y, this.x);
}
add(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x + v.x, this.y + v.y);
}
sub(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x - v.x, this.y - v.y);
}
mul(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x * v.x, this.y * v.y);
}
div(v) {
if (typeof v === "number") v = new Vec2(v, v);
return new Vec2(this.x / v.x, this.y / v.y);
}
move(v) {
this.x += v.x;
this.y += v.y;
}
moveTo(v) {
this.x = v.x;
this.y = v.y;
}
draw(s) {
circle(this.x, height - this.y, s || 10);
}
}
const drawline = (v1, v2) => {
line(v1.x, height - v1.y, v2.x, height - v2.y);
};
class Shape extends Vec2 {
constructor(x, y, w, h) {
super(x, y);
this.w = w || 0;
this.h = h || 0;
}
get p1() {
return new Vec2(this.x - this.w / 2, this.y - this.h / 2);
}
set p1(v) {
this.move(v.sub(this.p1));
}
get p2() {
return new Vec2(this.x - this.w / 2, this.y + this.h / 2);
}
get p3() {
return new Vec2(this.x + this.w / 2, this.y + this.h / 2);
}
get p4() {
return new Vec2(this.x + this.w / 2, this.y - this.h / 2);
}
draw() {
this.frame();
}
frame() {
drawline(this.p1, this.p2);
drawline(this.p2, this.p3);
drawline(this.p3, this.p4);
drawline(this.p4, this.p1);
}
_hover(v) {
return (
this.p1.x <= v.x &&
v.x <= this.p3.x &&
this.p1.y <= v.y &&
v.y <= this.p3.y
);
}
hover(v) {
return this._hover(v);
}
forceInside(v, c1, c2) {
if (this.p1.x > v.x) {
v.x = this.p1.x;
if (c1) c1()
}
if (v.x > this.p3.x) {
v.x = this.p3.x;
if (c1) c1()
}
if (this.p1.y > v.y) {
v.y = this.p1.y;
if (c2) c2()
}
if (v.y > this.p3.y) {
v.y = this.p3.y;
if (c2) c2()
}
}
}
class Segment extends Shape {
constructor(x1, y1, x2, y2) {
super((x1 + x2) / 2, (y1 + y2) / 2, x2 - x1, y2 - y1);
}
get x1() {
return this.p1.x;
}
get y1() {
return this.p1.y;
}
get x2() {
return this.p3.x;
}
get y2() {
return this.p3.y;
}
get len() {
return Math.hypot(this.w, this.h);
}
get a() {
if (this.w === 0) return 0;
return this.h / this.x;
}
get b() {
return -1;
}
get c() {
return this.y1 - this.a * this.x1;
}
d2(v) {
// vとの最短距離の乗数
let a = this.a,
b = this.b,
d = a * v.x + b * v.y + this.c;
return (d * d) / (a * a + b * b);
}
draw() {
drawline(this.p1, this.p3);
}
}
class Intersection {
constructor(s1, s2) {
this.isCross = false;
this.s =
(-s1.h * (s1.x - s2.x) + s1.w * (s1.y - s2.y)) /
(-s2.w * s1.h + s1.w * s2.h);
this.t =
(s2.w * (s1.y - s2.y) - s2.h * (s1.x - s2.x)) /
(-s2.w * s1.h + s1.w * s2.h);
this.point = new Vec2(s1.x + this.t * s1.w, s1.y + this.t * s1.h);
if (this.s >= 0 && this.s <= 1 && this.t >= 0 && this.t <= 1) {
this.isCross = true;
}
this.s1 = s1;
this.s2 = s2;
}
static _(a1, b1, c1, a2, b2, c2) {
let d = a1 * b2 - a2 * b1;
if (d === 0) return;
return new Vec2((b1 * c2 - b2 * c1) / d, (a2 * c1 - a1 * c2) / d);
}
static foot(x, y, a, b, c) {
return Intersection._(a, b, c, b, -a, a * y - b + x);
}
draw() {
if (this.point) this.point.draw(10);
}
}
class Ellipse extends Shape {
draw() {
ellipse(this.x, height - this.y, this.w, this.h);
}
hover(v) {
if (!this._hover(v)) {
return false;
}
let a2 = ((this.w / 2) * this.w) / 2;
let b2 = ((this.h / 2) * this.h) / 2;
let v2 = this.sub(v);
return (v2.x * v2.x) / a2 + (v2.y * v2.y) / b2 <= 1;
}
}
class Circle extends Ellipse {
constructor(x, y, r) {
super(x, y, 2 * r, 2 * r);
}
get r() {
return this.w / 2;
}
draw() {
circle(this.x, height - this.y, this.w);
}
}
class Fan extends Ellipse {
constructor(x, y, w, h, start, end) {
super(x, y, w, h);
this.start = start;
this.end = end;
}
draw() {
arc(
this.x,
height - this.y,
this.w,
this.h,
TWO_PI - this.end,
TWO_PI - this.start
);
}
}
class Rect extends Shape {
constructor(leftbottom, righttop) {
let c = righttop.add(leftbottom).div(2),
d = righttop.sub(leftbottom);
super(c.x, c.y, d.x, d.y);
}
}
class Particle extends Circle {
constructor(x, y, r) {
super(x, y, r);
this.mass = 1;
this.inv_mass = 1;
this.velocity = new Vec2(0, 0);
this.acceleration = new Vec2(0, 0);
}
get mass() {
return this._mass;
}
set mass(m) {
this._mass = m === 0 ? 0.0001 : m;
this.inv_mass = 1 / this._mass;
}
update(dt) {
this.velocity = this.velocity.add(this.acceleration.mul(dt));
this.move(this.velocity.mul(dt));
this.acceleration = new Vec2(0, 0);
}
}
let p, b, c;
let ball;
function setup() {
createCanvas(400, 400);
p = new Circle(200, 200, 10);
b = new Shape(width / 2, height / 2, 380, 380);
c = new Circle(200, 200, 100);
ball = new Particle(100, 100, 10);
// noLoop()
}
const ballUpdater = (b) => {
if (keyIsDown(LEFT_ARROW)) {
b.acceleration.x -= 100;
}
if (keyIsDown(RIGHT_ARROW)) {
b.acceleration.x += 100;
}
if (keyIsDown(UP_ARROW)) {
b.acceleration.y += 100;
}
if (keyIsDown(DOWN_ARROW)) {
b.acceleration.y -= 100;
}
// let v = b.sub(c)
// if (v.len <= c.r + b.r) {
// v.len = c.r + b.r
// b.moveTo(c.add(v))
// }
b.update(1 / 60);
new Shape(width / 2, height / 2, 380 - b.w, 380 - b.h).forceInside(b, ()=>{
b.velocity.x *= -1
}, ()=>{
b.velocity.y *= -1
});
return b;
};
function draw() {
background(220);
b.frame();
c.draw();
ballUpdater(ball);
if (c.hover(ball)) fill("red");
ball.draw();
fill(220);
p.moveTo(new Vec2(mouseX, height - mouseY));
p.draw();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment