Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
projections
<body><script>
// Returns the two points of intersection
// of a line and a circle, if they exist.
function circle_line_intersection(circle, line) {
var cx = circle.pos.x;
var cy = circle.pos.y;
var dx = line.dir.x;
var dy = line.dir.y;
var x1 = line.pos.x - cx;
var y1 = line.pos.y - cy;
var x2 = line.pos.x + dx - cx;
var y2 = line.pos.y + dy - cy;
var dd = x1 * y2 - x2 * y1;
var de = circle.rad * circle.rad - dd * dd;
if (de <= 0) {
return null;
} else {
var sx = dy < 0 ? -dx : dx;
var sy = dy < 0 ? -dy : dy;
var px = sx*Math.sqrt(de);
var py = sy*Math.sqrt(de);
var qx = dd*dy;
var qy = -dd*dx;
var ax = qx - px;
var ay = qy - py;
var bx = qx + px;
var by = qy + py;
return [{x:ax+cx,y:ay+cy}, {x:bx+cx,y:by+cy}];
}
}
function add(a,b) {
return {x:a.x+b.x, y:a.y+b.y};
}
function sub(a,b) {
return {x:a.x-b.x, y:a.y-b.y};
}
function scale(a,x) {
return {x:a.x*x, y:a.y*x};
}
function norm(a) {
var l = Math.sqrt(a.x*a.x + a.y*a.y);
return {x:a.x/l, y:a.y/l};
}
function sqrdist(a, b) {
return (a.x-b.x)**2 + (a.y-b.y)**2;
}
function dot(a,b){
return a.x*b.x + a.y*b.y;
}
// Attempts to move circle `a`, towards `dir`, until it hits
// the circle `b`; returns the stop position or null
function circle_to_circle_hitpos(a, dir, b) {
var r = a.rad + b.rad;
let c = {pos:b.pos, rad:a.rad+b.rad};
let l = {pos:a.pos, dir: norm(dir)};
var p = circle_line_intersection(c, l);
if (p) {
var d0 = sqrdist(a.pos, p[0]);
var d1 = sqrdist(a.pos, p[1]);
var cp = d0 < d1 ? p[0] : p[1];
var dp = dot(dir, sub(cp, a.pos))
//console.log(d0, d1, p[0], p[1]);
return dp > 0 ? cp : null;
} else {
return null;
}
}
// Attempts to move circle `a`, towards `dir`, until it hits
// the segment `s`; returns the stop position or null
function circle_to_segment_hitpos(a, dir, s) {
return null;
};
window.onload = () => {
var canvas = document.createElement("canvas");
canvas.width = 512;
canvas.height = 512;
canvas.style.border = "1px solid gray";
document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");
// Draws a circle
function circle(a, r, col = "black") {
ctx.strokeStyle = col;
ctx.beginPath();
ctx.arc(a.x, a.y, r, 0, 2 * Math.PI);
ctx.stroke();
};
// Draws a line
function line(a, b, col = "black") {
ctx.strokeStyle = col;
ctx.beginPath();
ctx.moveTo(a.x,a.y);
ctx.lineTo(b.x,b.y);
ctx.stroke();
}
// Creates the test objects
var a = {pos:{x:64,y:256}, rad:10}; // circle that moves
var b = {pos:{x:256,y:256}, rad:40}; // static circle
var s = {a:{x:224,y:128}, b:{x:288,y:192}}; // static segment
// Draws the screen
setInterval(() => {
// direction that circle will move
var t = Date.now()/1000;
var d = {x:Math.cos(t),y:Math.sin(t)};
// clears screen
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw path lines
line(a.pos, add(a.pos, scale(d, 512)), "gray");
// draw objects
circle(a.pos, a.rad);
circle(b.pos, b.rad);
line(s.a, s.b);
// draw hitpos of circle `a` towards circle `b`
var hpos = circle_to_circle_hitpos(a, d, b);
if (hpos) {
circle(hpos, a.rad);
}
// draw hitpos of circle `a` towards segment `s`
var hpos = circle_to_segment_hitpos(a, d, s);
if (hpos) {
circle(hpos, a.rad);
}
}, 50);
canvas.onclick = (e) => {
a.pos.x = e.offsetX;
a.pos.y = e.offsetY;
};
console.log("ata");
};
</script></body>
@MaiaVictor

This comment has been minimized.

Copy link
Owner Author

MaiaVictor commented Jan 22, 2020

type Point = (Double, Double)

norm :: Point -> Double
norm (ax, ay) = sqrt (ax**2 + ay**2)

normalize :: Point -> Point
normalize a@(ax, ay) = (ax / norm a, ay / norm a)

-- Difference of points
(-&) :: Point -> Point -> Point
(ax, ay) -& (bx, by) = (ax-bx, ay-by)

-- Scalar product
(*&) :: Double -> Point -> Point
a *& (bx, by) = (a*bx, a*by)

dist :: Point -> Point -> Double
dist a b = norm $ b -& a

crossProd :: Point -> Point -> Double
crossProd (ax, ay) (bx, by) = ax*by-ay*bx

-- distance between a point `c` and a line defined by the points `a` and `b`
distFromLine :: Point -> Point -> Point -> Double
distFromLine a b c = abs (crossProd c (b -& a) - crossProd a b) / dist a b

circleCollision :: Point -> Point -> Point -> Double -> Point -> Double 
circleCollision a b c r v =
  let d        = distFromLine a b c
      sinTheta = crossProd (normalize (b -& a)) (normalize v)
  in (d-r)/sinTheta

circleCollisionCenter :: Point -> Point -> Point -> Double -> Point -> Point
circleCollisionCenter a b c@(cx, cy) r v =
  let (dx, dy) = circleCollision a b c r v *& v
  in (cx + dx, cy + dy)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.