Cartesian coordinates algorithmb question - algorithm

On the 2D grid, there is a cartesian coordinate C(Cx,Cy) which is a center of square and it has 'b' of radius.
And there are two points P1(x1,y1), P2(x2,y2). When I connect P1 with P2 directly by line, there should be a straight line.
I wanna make the pseudo code that checking whether the straight line between P1 and P2 is on the square area or not.
The argument would be center point and two different points and radius.
Square center: (Cx,Cy)
Two points: P1(x1,y1), P2(x2,y2)
Radius: 'b'
function Straight ((x1,y1),(x2,y2),(Cx,Cy),b)
If the straight line is not on the square area, it should return true, if it is on the square area, it should return false.

You can convert this problem (by projecting the coordinates) to a square at (0, 0) with "radius" 1.
For determining whether the line segment (p1, p2) crosses the top side of the square, you can first test these conditions:
(y2 - 1) * (y2 - 1) > 0. If this is true, it means that the line segment is completely above the top of the square, or completely below it.
y1 = y2. If this is true, the line segment is parallel with the square.
In all other cases, the x-coordinate of the intersection point is:
x = x1 - y1 * (x2 - x1) / (y2 - y1)
If this x is not in the range [-1, 1], the line segment does not intersect the top of the square.
A similar operation can be done for the three other sides.
If any of them gives an intersection coordinate in the range [-1, 1], the function straight should return true, and false otherwise.
Here is an interactive JavaScript implementation with which you can draw a line segment (by "dragging" the mouse) near a square. The square will highlight when the call to straight returns true:
function intersectionWithXaxis(x1, y1, x2, y2) {
if (y1 * y2 > 0 || y1 === y2) return Infinity; // No intersection
return x1 - y1 * (x2 - x1) / (y2 - y1); // x-coordinate of intersection
}
function straight(x1, y1, x2, y2, cx, cy, b) {
// Project the coordinates so the square is at (0, 0) with "radius" 1
x1 = (x1-cx)/b;
y1 = (y1-cy)/b;
x2 = (x2-cx)/b;
y2 = (y2-cy)/b;
let z;
// Get intersections with top, bottom, left and right side of box:
z = intersectionWithXaxis(x1, y1-1, x2, y2-1);
if (Math.abs(z) <= 1) return true;
z = intersectionWithXaxis(x1, y1+1, x2, y2+1);
if (Math.abs(z) <= 1) return true;
// We can use the same function for vertical line intersections by swapping x and y
z = intersectionWithXaxis(y1, x1-1, y2, x2-1);
if (Math.abs(z) <= 1) return true;
z = intersectionWithXaxis(y1, x1+1, y2, x2+1);
if (Math.abs(z) <= 1) return true;
return false;
}
let cx = 100;
let cy = 60;
let b = 30;
let x1, y1, x2, y2;
// I/O handling
let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
ctx.fillStyle = "yellow";
let isMouseDown = false;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.rect(cx-b, cy-b, 2*b, 2*b);
ctx.stroke();
if (!isMouseDown) return;
// Call the main function. If true, highlight the square
if (straight(x1, y1, x2, y2, cx, cy, b)) ctx.fill();
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
canvas.addEventListener("mousedown", function(e) {
x1 = e.clientX - this.offsetLeft;
y1 = e.clientY - this.offsetTop;
isMouseDown = true;
});
canvas.addEventListener("mousemove", function(e) {
if (!isMouseDown) return;
x2 = e.clientX - this.offsetLeft;
y2 = e.clientY - this.offsetTop;
draw();
});
canvas.addEventListener("mouseup", function(e) {
isMouseDown = false;
});
draw();
<canvas width="400" height="180"></canvas>

Related

Best way for a Fox Rabbit Chase Simulation in QBasic

I need some help with a homework.
Problem Definition
There is a rabbit 100 meters away from its hole and a fox 100 meters away from the rabbit in perpendicular direction to the hole.
(rabbit at (100,0), hole at (100,100), fox at (0,0)
The rabbit starts running straight to the hole with a given V1 speed and Fox chases the rabbit with a given V2 speed. Simulate the chase using QBasic and print if the rabbit gets caught or escapes.
I wrote some code, but it isn't working as it is supposed to. Even if the fox catches the rabbit, it prints that the rabbit escapes
My code so far:
CLS
SCREEN 12
WINDOW (-20, 120)-(120, -20)
LINE (0, 0)-(100, 0)
LINE (0, 100)-(0, 0)
CIRCLE (100, 100), 1
INPUT "Input speed of rabbit, v1=", v1
INPUT "input speed of fox, v2=", v2
dlt=0.01
x1 = 0: x2 = 0
y1 = 100: y2 = 0
drw: PSET (x1, y1), 1: PSET (x2, y2), 2
x1 = x1 + dlt * v1
x2 = x2 + dlt * v2 * (x1 - x2) / SQR((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
y2 = y2 + dlt * v2 * (y1 - y2) / SQR((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
IF SQR((x1 - x2) ^ 2 + (y1 - y2) ^ 2) < 0.01 GOTO caught
IF x1 > 100 GOTO escaped
GOTO drw
caught: PRINT "rabbit got caught": GOTO finish
escaped: PRINT "rabbit escaped"
finish: END
If you don't know about QBasic, you could also help me with an algorithm in any language. I just need a better algorithm to solve it.
First of all: although your assignment speaks of the rabbit moving along the Y-axis, you seem to have swapped X/Y coordinates throughout your code, so that actually the rabbit moves along the X axis in your implementation. This is a bit confusing, but it is not the cause of your problem.
The issue may be resulting from the margin of 0.01 you have in this test:
IF SQR((x1 - x2) ^ 2 + (y1 - y2) ^ 2) < 0.01 GOTO caught
If the speed of the fox is high enough, it may be that it "overshoots" the rabbit each time its new position is calculated, and end up at the other (alternating) side of the rabbit with a distance that is each time greater than 0.01. And so the above condition will never be true.
Instead test for the Y coordinate only (in your interpretation of X and Y), with:
IF y2 >= 100 GOTO caught
I also made an implementation in JavaScript (but with X and Y as given in the question), both with your "0.01" condition, and with the proposed fix. If you enter speeds V1=5 and V2=9, the fox can catch the rabbit, but you'll see the different outcome in both snippets:
Wrong:
async function animate() {
cls();
line(0, 0, 100, 0, "black");
line(0, 100, 0, 0, "black");
circle(100, 100, 3, "black");
let v1 = input("rabbit");
let v2 = input("fox");
let dlt = 0.1;
let x1 = 100, y1 = 0; // rabbit
let x2 = 0, y2 = 0; // fox
while (true) {
let y1to = y1 + dlt * v1;
let dist = Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2);
let x2to = x2 + dlt * v2 * (x1 - x2) / dist;
let y2to = y2 + dlt * v2 * (y1 - y2) / dist;
line(x1, y1, x1, y1to, "green");
line(x2, y2, x2to, y2to, "red");
y1 = y1to;
x2 = x2to;
y2 = y2to;
// Problematic condition:
if (dist < 0.01) return output("rabbit got caught");
if (y1 >= 100) return output("rabbit escaped");
await delay(5);
}
}
let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
// Some helper functions for JavaScript:
const input = (id) => +document.getElementById(id).value;
function line(x1, y1, x2, y2, color) {
ctx.beginPath();
ctx.moveTo(x1+0.5, y1+0.5);
ctx.lineTo(x2+0.5, y2+0.5);
ctx.strokeStyle = color;
ctx.stroke();
}
function circle(x, y, r, color) {
ctx.beginPath();
ctx.strokeStyle = color;
ctx.arc(x+0.5, y+0.5, r, 0, 2 * Math.PI);
ctx.stroke();
}
const output = (msg) => document.querySelector("#result").textContent = msg;
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
function cls() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
output("");
}
// Bind a click handler for the button
document.querySelector("button").addEventListener("click", animate);
input { width: 4em }
.left { float: left; height: 180px; margin-right: 10px }
<div class="left">
<h3>Wrong implementation</h3>
Input speed of rabbit, v1= <input id="rabbit" type="number" value="5"><br>
Input speed of fox, v2= <input id="fox" type="number" value="9"><br>
<button>Go!</button><br>
</div>
<div>
<canvas width="105" height="105"></canvas>
<div id="result"></div>
</div>
Corrected:
async function animate() {
cls();
line(0, 0, 100, 0, "black");
line(0, 100, 0, 0, "black");
circle(100, 100, 3, "black");
let v1 = input("rabbit");
let v2 = input("fox");
let dlt = 0.1;
let x1 = 100, y1 = 0; // rabbit
let x2 = 0, y2 = 0; // fox
while (true) {
let y1to = y1 + dlt * v1;
let dist = Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2);
let x2to = x2 + dlt * v2 * (x1 - x2) / dist;
let y2to = y2 + dlt * v2 * (y1 - y2) / dist;
line(x1, y1, x1, y1to, "green");
line(x2, y2, x2to, y2to, "red");
y1 = y1to;
x2 = x2to;
y2 = y2to;
// Corrected condition:
if (x2 >= 100) return output("rabbit got caught");
if (y1 >= 100) return output("rabbit escaped");
await delay(5);
}
}
let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
// Some helper functions for JavaScript:
const input = (id) => +document.getElementById(id).value;
function line(x1, y1, x2, y2, color) {
ctx.beginPath();
ctx.moveTo(x1+0.5, y1+0.5);
ctx.lineTo(x2+0.5, y2+0.5);
ctx.strokeStyle = color;
ctx.stroke();
}
function circle(x, y, r, color) {
ctx.beginPath();
ctx.strokeStyle = color;
ctx.arc(x+0.5, y+0.5, r, 0, 2 * Math.PI);
ctx.stroke();
}
const output = (msg) => document.querySelector("#result").textContent = msg;
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
function cls() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
output("");
}
// Bind a click handler for the button
document.querySelector("button").addEventListener("click", animate);
input { width: 4em }
.left { float: left; height: 180px; margin-right: 10px }
<div class="left">
<h3>Corrected implementation</h3>
Input speed of rabbit, v1= <input id="rabbit" type="number" value="5"><br>
Input speed of fox, v2= <input id="fox" type="number" value="9"><br>
<button>Go!</button><br>
</div>
<div>
<canvas width="105" height="105"></canvas>
<div id="result"></div>
</div>
A final remark on your code: the use of GOTO is frowned upon. You should instead use a DO WHILE loop for looping here, potentially with an EXIT statement if really needed.

Moving along Bezier Curve in processing

My code for the ball moving in a Bezier Curve from start to the middle of the curve is:
void ballMove()
{
if(y[0]==height*1/10)
{
bezier (x[0], y[0],x[1], y[1], x[2], y[2], x[3], y[3]);
float x0; float x1; float x2; float x3;
float y0; float y1; float y2; float y3;
x0 = x[0]; x1 = x[1]; x2 = x[2]; x3 = x[3];
y0 = y[0]; y1 = y[1]; y2 = y[2]; y3 = y[3];
float t = (frameCount/100.0)%1;
float x = bezierPoint(x0, x1, x2, x3, t);
float y = bezierPoint( y0, y1, y2, y3, t);
if(t>=0.5)
{
t=0;
}
while(t==0.5)
{
a=x;
b=y;
}
while(t>0.5)
{
ellipse(a,b,30,30);
}
fill(255,0,0);
if(t!=0)
{
ellipse(x, y, 15, 15);
}
}
}
I have defined everything in setup, draw etc, but i want to launch the ball from the start to the middle of the Bezier Curve only one time whenever space is pressed.
The current version shows me the loop. How can i do that?
Tried Everything like return, break, changing the t parameter etc, but the code doesn't work. I'm new in processing.
Do you have any suggestions?
Biggest mistake that you make is altering value of t after you calculated x and y positions of red ball. To avoid this you need first calculate t between [0, 1] in you case [0, 0.5] and then alter this value according to state of your program.
Second mistake you made while calculating t from frameCount. First you use modulo to extract numbers [0, 50] and then map it in range [0, 0.5] like this
float t = (frameCount % 50) * 0.01;
You also mentioned that you want to repeat this animation after pressing some key. For this you will need keyPressed method and some global variables to represent state of program and store starting frame of animation (because frameCount should be read only). So basic functionality can be achieved like this:
boolean run = false;
float f_start = 0;
void ballMove() {
noFill();
bezier (x0, y0, x1, y1, x2, y2, x3, y3);
float t = ((frameCount - f_start) % 50) * 0.01;
if (run == false) {
t = 0;
}
float x = bezierPoint(x0, x1, x2, x3, t);
float y = bezierPoint( y0, y1, y2, y3, t);
fill(255, 0, 0);
ellipse(x, y, 5, 5);
}
void keyPressed() {
run = !run;
f_start = frameCount;
}
Hope this will help you. Next time pls post an MCVE so we do not need to fight with your code.

Finding the line along the intersection of two planes

I am trying to draw the line formed by the intersections of two planes in 3D, but I am having trouble understanding the math, which has been explained here and here.
I tried to figure it out myself, but the closest that I got to a solution was a vector pointing along the same direction as the intersection line, by using the cross product of the normals of the planes. I have no idea how to find a point on the intersection line, any point would do. I think that this method is a dead end. Here is a screenshot of this attempt:
I tried to use the solution mentioned in this question, but it has a dead link to the original explanation, and the equation didn't work for me (it has unbalanced parentheses, which I tried to correct below).
var planeA = new THREE.Plane((new THREE.Vector3(0, 0, 1)).normalize(), 100);
var planeB = new THREE.Plane((new THREE.Vector3(1, 1, 1)).normalize(), -100);
var x1 = planeA.normal.x,
y1 = planeA.normal.y,
z1 = planeA.normal.z,
d1 = planeA.constant;
var x2 = planeB.normal.x,
y2 = planeB.normal.y,
z2 = planeB.normal.z,
d2 = planeB.constant;
var point1 = new THREE.Vector3();
point1.x = 0;
point1.z = (y2 / y1) * (d1 - d2) / (z2 - z1 * y2 / y1);
point1.y = (-z1 * point1.z - d1) / y1;
var point2 = new THREE.Vector3();
point2.x = 1;
point2.z = (y2 / y1) * (x1 * point2.x + d1) - (x2 * point2.x - d2) / (z2 - z1 * y2 / y1);
point2.y = (-z1 * point2.z - x1 * point2.x - d1) / y1;
console.log(point1, point2);
output:
THREE.Vector3 {x: -1, y: NaN, z: NaN, …}
THREE.Vector3 {x: 1, y: Infinity, z: -Infinity, …}
expected output:
A point along the intersection where x = 0, and
Another point on the same line where x = 1
If someone could point me to a good explanation of how this is supposed to work, or an example of a plane-plane intersection algorithm, I would be grateful.
Here is an implementation of a solution for plane-plane intersections described at http://geomalgorithms.com/a05-_intersect-1.html . Essentially, you first use the cross product of the normals of the planes to find the direction of a line in both planes. Secondly, you use some algebra on the implicit equation of the planes (P . n + d = 0 where P is some point on the plane, n is the normal and d is the plane constant) to solve for a point which is on the intersection of the planes and also on one of the x=0, y=0 or z=0 planes. The solution is then the line described by a point and a vector. I was using three.js version 79
/*
Algorithm taken from http://geomalgorithms.com/a05-_intersect-1.html. See the
section 'Intersection of 2 Planes' and specifically the subsection
(A) Direct Linear Equation
*/
function intersectPlanes(p1, p2) {
// the cross product gives us the direction of the line at the intersection
// of the two planes, and gives us an easy way to check if the two planes
// are parallel - the cross product will have zero magnitude
var direction = new THREE.Vector3().crossVectors(p1.normal, p2.normal)
var magnitude = direction.distanceTo(new THREE.Vector3(0, 0, 0))
if (magnitude === 0) {
return null
}
// now find a point on the intersection. We use the 'Direct Linear Equation'
// method described in the linked page, and we choose which coordinate
// to set as zero by seeing which has the largest absolute value in the
// directional vector
var X = Math.abs(direction.x)
var Y = Math.abs(direction.y)
var Z = Math.abs(direction.z)
var point
if (Z >= X && Z >= Y) {
point = solveIntersectingPoint('z', 'x', 'y', p1, p2)
} else if (Y >= Z && Y >= X){
point = solveIntersectingPoint('y', 'z', 'x', p1, p2)
} else {
point = solveIntersectingPoint('x', 'y', 'z', p1, p2)
}
return [point, direction]
}
/*
This method helps finding a point on the intersection between two planes.
Depending on the orientation of the planes, the problem could solve for the
zero point on either the x, y or z axis
*/
function solveIntersectingPoint(zeroCoord, A, B, p1, p2){
var a1 = p1.normal[A]
var b1 = p1.normal[B]
var d1 = p1.constant
var a2 = p2.normal[A]
var b2 = p2.normal[B]
var d2 = p2.constant
var A0 = ((b2 * d1) - (b1 * d2)) / ((a1 * b2 - a2 * b1))
var B0 = ((a1 * d2) - (a2 * d1)) / ((a1 * b2 - a2 * b1))
var point = new THREE.Vector3()
point[zeroCoord] = 0
point[A] = A0
point[B] = B0
return point
}
var planeA = new THREE.Plane((new THREE.Vector3(0, 0, 1)).normalize(), 100)
var planeB = new THREE.Plane((new THREE.Vector3(1, 1, 1)).normalize(), -100)
var [point, direction] = intersectPlanes(planeA, planeB)
When I have problems like this, I usually let a symbolic algebra package (Mathematica in this case) deal with it. After typing
In[1]:= n1={x1,y1,z1};n2={x2,y2,z2};p={x,y,z};
In[2]:= Solve[n1.p==d1&&n2.p==d2,p]
and simplifying and substituting x=0 and x=1, I get
d2 z1 - d1 z2 d2 y1 - d1 y2
Out[5]= {{{y -> -------------, z -> ----------------}},
y2 z1 - y1 z2 -(y2 z1) + y1 z2
d2 z1 - x2 z1 - d1 z2 + x1 z2
> {{y -> -----------------------------,
y2 z1 - y1 z2
d2 y1 - x2 y1 + (-d1 + x1) y2
> z -> -----------------------------}}}
-(y2 z1) + y1 z2
It is easy to let three.js solve this for you.
If you were to express your problem in matrix notation
m * x = v
Then the solution for x is
x = inverse( m ) * v
We'll use a 4x4 matrix for m, because three.js has an inverse() method for the Matrix4 class.
var x1 = 0,
y1 = 0,
z1 = 1,
d1 = 100;
var x2 = 1,
y2 = 1,
z2 = 1,
d2 = -100;
var c = 0; // the desired value for the x-coordinate
var v = new THREE.Vector4( d1, d2, c, 1 );
var m = new THREE.Matrix4( x1, y1, z1, 0,
x2, y2, z2, 0,
1, 0, 0, 0,
0, 0, 0, 1
);
var minv = new THREE.Matrix4().getInverse( m );
v.applyMatrix4( minv );
console.log( v );
The x-component of v will be equal to c, as desired, and the y- and z-components will contain the values you are looking for. The w-component is irrelevalent.
Now, repeat for the next value of c, c = 1.
three.js r.58
Prerequisites
Recall that to represent a line we need a vector describing its direction and a point through which this line goes. This is called parameterized form:
line_point(t) = t * (point_2 - point_1) + point_1
where point_1 and point_2 are arbitrary points through which the line goes, and t is a scalar which parameterizes our line. Now we can find any point line_point(t) on the line if we put arbitrary t into the equation above.
NOTE: The term (point_2 - point_1) is nothing, but a vector describing the direction of our line, and the term point_1 is nothing, but a point through which our line goes (of course point_2) would also be fine to use too.
The Algorithm
Find the direction direction of the intersection line by taking
cross product of plane normals, i.e. direction = cross(normal_1,
normal_2).
Take any plane, for example the first one, and find any 2 distinct points
on this plane: point_1 and point_2. If we assume that the plane equation
is of the form a1 * x + b1 * y + c1 * z + d1 = 0, then to find 2
distinct points we could do the following:
y1 = 1
z1 = 0
x1 = -(b1 + d1) / a1
y2 = 0
z2 = 1
x2 = -(c1 + d1) / a1
where point_1 = (x1, y1, z1) and point_2 = (x2, y2, z2).
Now that we have 2 points, we can construct the parameterized
representation of the line lying on this first plane:
line_point(t) = t * (point_2 - point_1) + point_1, where line_point(t)
describes any point on this line, and t is just an input scalar
(frequently called parameter).
Find the intersection point intersection_point of the line
line_point(t) and the second plane a2 * x + b2 * y + c2 * z + d2 = 0 by using
the standard line-plane intersection algorithm (pay attention to the
Algebraic form section as this is all you need to implement line-plane
intersection, if you haven't done so already).
Our intersection line is now found and can be constructed in
parameterized form as usual: intersection_line_point(s) = s *
direction + intersection_point, where intersection_line_point(s)
describes any point on this intersection line, and s is parameter.
NOTE: I didn't read this algorithm anywhere, I've just devised it from the top of my head based on my knowledge of linear algebra. That doesn't mean that it doesn't work, but it might be possible that this algorithm can be optimized further.
Conditioning
When 2 normal vectors normal_1 and normal_2 are almost collinear this problem gets extremely ill-conditioned. Geometrically it means that the 2 planes are almost parallel to each other and determining the intersection line with acceptable precision becomes impossible in finite-precision arithmetic which is floating-point arithmetic in this case.

how to calculate the dist() from mouseX, mouseY to a rectangle in Processing

If it was the dist to a point it would be
dist(mouseX, mouseY, x, y)
for
point(x,y)
but how can I calculate dist() from the mouse's current position to
rectMode(CORNERS);
rect(x1,y2,x2,y2);
Thanks
Something like this should do it:
float distrect(float x, float y, float x1, float y1, float x2, float y2){
float dx1 = x - x1;
float dx2 = x - x2;
float dy1 = y - y1;
float dy2 = y - y2;
if (dx1*dx2 < 0) { // x is between x1 and x2
if (dy1*dy2 < 0) { // (x,y) is inside the rectangle
return min(min(abs(dx1), abs(dx2)),min(abs(dy1),abs(dy2)));
}
return min(abs(dy1),abs(dy2));
}
if (dy1*dy2 < 0) { // y is between y1 and y2
// we don't have to test for being inside the rectangle, it's already tested.
return min(abs(dx1),abs(dx2));
}
return min(min(dist(x,y,x1,y1),dist(x,y,x2,y2)),min(dist(x,y,x1,y2),dist(x,y,x2,y1)));
}
Basically, you need to figure out if the closes point is on one of the sides, or in the corner. This picture may help, it shows the distance of a point from a rectangle for different positions of the point:
Here's a somewhat interactive program which accomplishes what you're looking for. You can drop it into Processing and run it if you would like.
EDIT: Here's a screenshot:
// Declare vars.
int x_click = -20; // Initializes circle and point off-screen (drawn when draw executes)
int y_click = -20;
float temp = 0.0;
float min_dist = 0.0;
int x1, x2, x3, x4, y1, y2, y3, y4;
// Setup loop.
void setup() {
size(400, 400);
// Calculate the points of a 40x40 centered rectangle
x1 = width/2 - 20;
y1 = height/2 - 20;
x2 = width/2 + 20;
y2 = y1;
x3 = x1;
y3 = height/2 + 20;
x4 = x2;
y4 = y3;
}
// Draw loop.
void draw(){
background(255);
// Draws a purple rectangle in the center of the screen.
rectMode(CENTER);
fill(154, 102, 200);
rect(width/2, height/2, 40, 40);
// Draws an orange circle where the user last clicked.
ellipseMode(CENTER);
fill(204, 102, 0);
ellipse(x_click, y_click, 10, 10);
// Draws black point where the user last clicked.
fill(0);
point(x_click, y_click);
// Draws min dist onscreen.
textAlign(CENTER);
fill(0);
text("min dist = " + min_dist, width/2, height/2 + 150);
}
void mousePressed(){
x_click = mouseX;
y_click = mouseY;
// If the click isn't perpendicular to any side of the rectangle, the min dist is a corner.
if ( ((x_click <= x1) || (x_click >= x2)) && ((y_click <= y1) || (y_click >= y3)) ) {
min_dist = min(min(dist(x1,y1,x_click,y_click),dist(x2,y2,x_click,y_click)), min(dist(x3,y3,x_click,y_click),dist(x4,y4,x_click,y_click)));
} else if( (x_click > x1) && (x_click < x2) && ((y_click < y1) || (y_click > y3)) ) {
// outside of box, closer to top or bottom
min_dist = min(abs(y_click - y1), abs(y_click - y3));
} else if( (y_click > y1) && (y_click < y3) && ((x_click < x1) || (x_click > x2)) ) {
// outside of box, closer to right left
min_dist = min(abs(x_click - x1), abs(x_click - x2));
} else {
// inside of box, check against all boundaries
min_dist = min(min(abs(y_click - y1), abs(y_click - y3)),min(abs(x_click - x1), abs(x_click - x2)));
}
// Print to console for debugging.
//println("minimum distance = " + min_dist);
}
This is what I use. If you are only interested in the relative distance there is probably no need to take the square root which should make it slightly quicker.
- (NSInteger) distanceFromRect: (CGPoint) aPoint rect: (CGRect) aRect
{
NSInteger posX = aPoint.x;
NSInteger posY = aPoint.y;
NSInteger leftEdge = aRect.origin.x;
NSInteger rightEdge = aRect.origin.x + aRect.size.width;
NSInteger topEdge = aRect.origin.y;
NSInteger bottomEdge = aRect.origin.y + aRect.size.height;
NSInteger deltaX = 0;
NSInteger deltaY = 0;
if (posX < leftEdge) deltaX = leftEdge - posX;
else if (posX > rightEdge) deltaX = posX - rightEdge;
if (posY < topEdge) deltaY = topEdge - posY;
else if (posY > bottomEdge) deltaY = posY - bottomEdge;
NSInteger distance = sqrt(deltaX * deltaX + deltaY * deltaY);
return distance;
}

Circle-circle intersection points

How do I calculate the intersection points of two circles. I would expect there to be either two, one or no intersection points in all cases.
I have the x and y coordinates of the centre-point, and the radius for each circle.
An answer in python would be preferred, but any working algorithm would be acceptable.
Intersection of two circles
Written by Paul Bourke
The following note describes how to find the intersection point(s)
between two circles on a plane, the following notation is used. The
aim is to find the two points P3 = (x3,
y3) if they exist.
First calculate the distance d between the center
of the circles. d = ||P1 - P0||.
If d > r0 + r1 then there are no solutions,
the circles are separate. If d < |r0 -
r1| then there are no solutions because one circle is
contained within the other. If d = 0 and r0 =
r1 then the circles are coincident and there are an
infinite number of solutions.
Considering the two triangles P0P2P3
and P1P2P3 we can write
a2 + h2 = r02 and
b2 + h2 = r12
Using d = a + b we can solve for a, a =
(r02 - r12 +
d2 ) / (2 d)
It can be readily shown that this reduces to
r0 when the two circles touch at one point, ie: d =
r0 + r1
Solve for h by substituting a into the first
equation, h2 = r02 - a2
So P2 = P0 + a ( P1 -
P0 ) / d And finally, P3 =
(x3,y3) in terms of P0 =
(x0,y0), P1 =
(x1,y1) and P2 =
(x2,y2), is x3 =
x2 +- h ( y1 - y0 ) / d
y3 = y2 -+ h ( x1 - x0 ) /
d
Source: http://paulbourke.net/geometry/circlesphere/
Here is my C++ implementation based on Paul Bourke's article. It only works if there are two intersections, otherwise it probably returns NaN NAN NAN NAN.
class Point{
public:
float x, y;
Point(float px, float py) {
x = px;
y = py;
}
Point sub(Point p2) {
return Point(x - p2.x, y - p2.y);
}
Point add(Point p2) {
return Point(x + p2.x, y + p2.y);
}
float distance(Point p2) {
return sqrt((x - p2.x)*(x - p2.x) + (y - p2.y)*(y - p2.y));
}
Point normal() {
float length = sqrt(x*x + y*y);
return Point(x/length, y/length);
}
Point scale(float s) {
return Point(x*s, y*s);
}
};
class Circle {
public:
float x, y, r, left;
Circle(float cx, float cy, float cr) {
x = cx;
y = cy;
r = cr;
left = x - r;
}
pair<Point, Point> intersections(Circle c) {
Point P0(x, y);
Point P1(c.x, c.y);
float d, a, h;
d = P0.distance(P1);
a = (r*r - c.r*c.r + d*d)/(2*d);
h = sqrt(r*r - a*a);
Point P2 = P1.sub(P0).scale(a/d).add(P0);
float x3, y3, x4, y4;
x3 = P2.x + h*(P1.y - P0.y)/d;
y3 = P2.y - h*(P1.x - P0.x)/d;
x4 = P2.x - h*(P1.y - P0.y)/d;
y4 = P2.y + h*(P1.x - P0.x)/d;
return pair<Point, Point>(Point(x3, y3), Point(x4, y4));
}
};
Why not just use 7 lines of your favorite procedural language (or programmable calculator!) as below.
Assuming you are given P0 coords (x0,y0), P1 coords (x1,y1), r0 and r1 and you want to find P3 coords (x3,y3):
d=sqr((x1-x0)^2 + (y1-y0)^2)
a=(r0^2-r1^2+d^2)/(2*d)
h=sqr(r0^2-a^2)
x2=x0+a*(x1-x0)/d
y2=y0+a*(y1-y0)/d
x3=x2+h*(y1-y0)/d // also x3=x2-h*(y1-y0)/d
y3=y2-h*(x1-x0)/d // also y3=y2+h*(x1-x0)/d
Here's an implementation in Javascript using vectors. The code is well documented, you should be able to follow it. Here's the original source
See live demo here:
// Let EPS (epsilon) be a small value
var EPS = 0.0000001;
// Let a point be a pair: (x, y)
function Point(x, y) {
this.x = x;
this.y = y;
}
// Define a circle centered at (x,y) with radius r
function Circle(x,y,r) {
this.x = x;
this.y = y;
this.r = r;
}
// Due to double rounding precision the value passed into the Math.acos
// function may be outside its domain of [-1, +1] which would return
// the value NaN which we do not want.
function acossafe(x) {
if (x >= +1.0) return 0;
if (x <= -1.0) return Math.PI;
return Math.acos(x);
}
// Rotates a point about a fixed point at some angle 'a'
function rotatePoint(fp, pt, a) {
var x = pt.x - fp.x;
var y = pt.y - fp.y;
var xRot = x * Math.cos(a) + y * Math.sin(a);
var yRot = y * Math.cos(a) - x * Math.sin(a);
return new Point(fp.x+xRot,fp.y+yRot);
}
// Given two circles this method finds the intersection
// point(s) of the two circles (if any exists)
function circleCircleIntersectionPoints(c1, c2) {
var r, R, d, dx, dy, cx, cy, Cx, Cy;
if (c1.r < c2.r) {
r = c1.r; R = c2.r;
cx = c1.x; cy = c1.y;
Cx = c2.x; Cy = c2.y;
} else {
r = c2.r; R = c1.r;
Cx = c1.x; Cy = c1.y;
cx = c2.x; cy = c2.y;
}
// Compute the vector <dx, dy>
dx = cx - Cx;
dy = cy - Cy;
// Find the distance between two points.
d = Math.sqrt( dx*dx + dy*dy );
// There are an infinite number of solutions
// Seems appropriate to also return null
if (d < EPS && Math.abs(R-r) < EPS) return [];
// No intersection (circles centered at the
// same place with different size)
else if (d < EPS) return [];
var x = (dx / d) * R + Cx;
var y = (dy / d) * R + Cy;
var P = new Point(x, y);
// Single intersection (kissing circles)
if (Math.abs((R+r)-d) < EPS || Math.abs(R-(r+d)) < EPS) return [P];
// No intersection. Either the small circle contained within
// big circle or circles are simply disjoint.
if ( (d+r) < R || (R+r < d) ) return [];
var C = new Point(Cx, Cy);
var angle = acossafe((r*r-d*d-R*R)/(-2.0*d*R));
var pt1 = rotatePoint(C, P, +angle);
var pt2 = rotatePoint(C, P, -angle);
return [pt1, pt2];
}
Try this;
def ri(cr1,cr2,cp1,cp2):
int1=[]
int2=[]
ori=0
if cp1[0]<cp2[0] and cp1[1]!=cp2[1]:
p1=cp1
p2=cp2
r1=cr1
r2=cr2
if cp1[1]<cp2[1]:
ori+=1
elif cp1[1]>cp2[1]:
ori+=2
elif cp1[0]>cp2[0] and cp1[1]!=cp2[1]:
p1=cp2
p2=cp1
r1=cr2
r2=cr1
if p1[1]<p2[1]:
ori+=1
elif p1[1]>p2[1]:
ori+=2
elif cp1[0]==cp2[0]:
ori+=4
if cp1[1]>cp2[1]:
p1=cp1
p2=cp2
r1=cr1
r2=cr2
elif cp1[1]<cp2[1]:
p1=cp2
p2=cp1
r1=cr2
r2=cr1
elif cp1[1]==cp2[1]:
ori+=3
if cp1[0]>cp2[0]:
p1=cp2
p2=cp1
r1=cr2
r2=cr1
elif cp1[0]<cp2[0]:
p1=cp1
p2=cp2
r1=cr1
r2=cr2
if ori==1:#+
D=calc_dist(p1,p2)
tr=r1+r2
el=tr-D
a=r1-el
b=r2-el
A=a+(el/2)
B=b+(el/2)
thta=math.degrees(math.acos(A/r1))
rs=p2[1]-p1[1]
rn=p2[0]-p1[0]
gd=rs/rn
yint=p1[1]-((gd)*p1[0])
dty=calc_dist(p1,[0,yint])
aa=p1[1]-yint
bb=math.degrees(math.asin(aa/dty))
d=90-bb
e=180-d-thta
g=(dty/math.sin(math.radians(e)))*math.sin(math.radians(thta))
f=(g/math.sin(math.radians(thta)))*math.sin(math.radians(d))
oty=yint+g
h=f+r1
i=90-e
j=180-90-i
l=math.sin(math.radians(i))*h
k=math.cos(math.radians(i))*h
iy2=oty-l
ix2=k
int2.append(ix2)
int2.append(iy2)
m=90+bb
n=180-m-thta
p=(dty/math.sin(math.radians(n)))*math.sin(math.radians(m))
o=(p/math.sin(math.radians(m)))*math.sin(math.radians(thta))
q=p+r1
r=90-n
s=math.sin(math.radians(r))*q
t=math.cos(math.radians(r))*q
otty=yint-o
iy1=otty+s
ix1=t
int1.append(ix1)
int1.append(iy1)
elif ori==2:#-
D=calc_dist(p1,p2)
tr=r1+r2
el=tr-D
a=r1-el
b=r2-el
A=a+(el/2)
B=b+(el/2)
thta=math.degrees(math.acos(A/r1))
rs=p2[1]-p1[1]
rn=p2[0]-p1[0]
gd=rs/rn
yint=p1[1]-((gd)*p1[0])
dty=calc_dist(p1,[0,yint])
aa=yint-p1[1]
bb=math.degrees(math.asin(aa/dty))
c=180-90-bb
d=180-c-thta
e=180-90-d
f=math.tan(math.radians(e))*p1[0]
g=math.sqrt(p1[0]**2+f**2)
h=g+r1
i=180-90-e
j=math.sin(math.radians(e))*h
jj=math.cos(math.radians(i))*h
k=math.cos(math.radians(e))*h
kk=math.sin(math.radians(i))*h
l=90-bb
m=90-e
tt=l+m+thta
n=(dty/math.sin(math.radians(m)))*math.sin(math.radians(thta))
nn=(g/math.sin(math.radians(l)))*math.sin(math.radians(thta))
oty=yint-n
iy1=oty+j
ix1=k
int1.append(ix1)
int1.append(iy1)
o=bb+90
p=180-o-thta
q=90-p
r=180-90-q
s=(dty/math.sin(math.radians(p)))*math.sin(math.radians(o))
t=(s/math.sin(math.radians(o)))*math.sin(math.radians(thta))
u=s+r1
v=math.sin(math.radians(r))*u
vv=math.cos(math.radians(q))*u
w=math.cos(math.radians(r))*u
ww=math.sin(math.radians(q))*u
ix2=v
otty=yint+t
iy2=otty-w
int2.append(ix2)
int2.append(iy2)
elif ori==3:#y
D=calc_dist(p1,p2)
tr=r1+r2
el=tr-D
a=r1-el
b=r2-el
A=a+(el/2)
B=b+(el/2)
b=math.sqrt(r1**2-A**2)
int1.append(p1[0]+A)
int1.append(p1[1]+b)
int2.append(p1[0]+A)
int2.append(p1[1]-b)
elif ori==4:#x
D=calc_dist(p1,p2)
tr=r1+r2
el=tr-D
a=r1-el
b=r2-el
A=a+(el/2)
B=b+(el/2)
b=math.sqrt(r1**2-A**2)
int1.append(p1[0]+b)
int1.append(p1[1]-A)
int2.append(p1[0]-b)
int2.append(p1[1]-A)
return [int1,int2]
def calc_dist(p1,p2):
return math.sqrt((p2[0] - p1[0]) ** 2 +
(p2[1] - p1[1]) ** 2)

Resources