bouncing ball with friction (lower speed when touching the edge) problem in p5.js - p5.js

I´m trying to make a bouncing ball with friction (lower speed when touching the edge) but there is a problem in my code. d is a var for the friction and every time the ellipse touch the edge 1 will be added to d. In another words, every time the ellipse touches the edge of the canvas, the friction should be higher.
My code:
let x = 100;
let y = 100;
let xspeed = 5;
let yspeed = 5;
let r = 20;
let d = 0; //friction
function setup() {
createCanvas(400, 300);
frameRate(60);
}
function draw() {
background(0);
ellipse(x, y, r * 2);
x += xspeed;
y += yspeed;
if (d < 10 && d > -1) {
if (x - d > width - r) {
// width - r = 380
xspeed = xspeed - d;
xspeed = -xspeed;
d++;
console.log(d, x + d, y - d, x-d);
}
if (y - d > height - r -1) {
//height - r = 280
yspeed = yspeed - d;
yspeed = -yspeed;
d++;
console.log(d, x + d, y - d, x-d);
}
if (x - 5 + d < r) {
xspeed = xspeed + d;
xspeed = -xspeed;
d++;
console.log(d, x + d, y - d, x-d);
}
if (y + d < r) {
yspeed = yspeed + d;
yspeed = -yspeed;
d++;
console.log(d, x + d, y - d, x-d);
}
}
if (d == 11) {
if (x > width - r || x < r) {
xspeed = -xspeed;
}
if (y > height - r || y < r) {
yspeed = -yspeed;
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
Could someone please correct my script?

Friction occurs at the contact of an object with a surface. The phenomenon you're looking for is more like an inelastic impact.
I am hearing and trying to find recommendations.
Add sound that will be triggered with every bounch and lower amplitude sound when bounching ball's speed is lower

Related

Drawing two parallel lines with a certain distance away

I made a program that creates parallel lines from the mouse coordinates with a certain distance away which can be modified by the distance variable at the beginning of the code. The problem is that it does not work as it should when drawing.
Line 1 and Line 2 are the lines that are parallel to the line formed from the mouse coordinates, the "pointSlope" variable.
distance = 30
function setup() {
createCanvas(600, 600);
}
function draw() {
lineCreate([pmouseX,pmouseY], [mouseX,mouseY])
}
function lineCreate(point1, point2) {
fill(0)
stroke(0)
x0 = point1[0];
x1 = point2[0];
y0 = point1[1];
y1 = point2[1];
if (abs(x1 - x0) > abs(y1 - y0)) {
if (x0 > x1) {
let t = x0; x0 = x1; x1 = t;
t = y0; y0 = y1; y1 = t;
}
for (let x = x0; x <= x1; x++) {
let slope = (y1-y0) * (x-x0) / (x1-x0)
let y = y0 + (y1-y0) * (x-x0) / (x1-x0);
line1 = y + distance*Math.sqrt(1+pow(slope,2))
line2 = y - distance*Math.sqrt(1+pow(slope,2))
circle(x, line1, 2, 2);
circle(x, line2, 2, 2);
}
} else {
if (y0 > y1) {
let t = x0; x0 = x1; x1 = t;
t = y0; y0 = y1; y1 = t;
}
for (let y = y0; y <= y1; y++) {
let x = x0 + (x1-x0) * (y-y0) / (y1-y0);
circle(x, y, 2, 2);
}
}
}
I think that using vectors may help you in this situation, try this code as example:
let dist = 40;
function setup() {
createCanvas(600, 600);
v = createVector();
noStroke();
}
function draw() {
lineCreate();
}
function lineCreate() {
v.x = mouseX-pmouseX; v.y = mouseY-pmouseY;
h = v.heading();
LX = dist*cos(h+PI/2); LY = dist*sin(h+PI/2);
RX = dist*cos(h-PI/2); RY = dist*sin(h-PI/2);
for (let i=0; i<v.mag(); i++) {
fill(0).circle(pmouseX+i*cos(h),pmouseY+i*sin(h),2);
fill(160).circle(pmouseX+LX+i*cos(h),pmouseY+LY+i*sin(h),2);
fill(160).circle(pmouseX+RX+i*cos(h),pmouseY+RY+i*sin(h),2);
}
}
Here we are drawing two parallel lines in road-like path, but as you can see there are gaps in turns caused by using pmouse. I think, that it will not be possible to get rid of these artifacts, if you not move away from using the pmouse to more complex ways of calculating the trajectory.

Loop through a array in circle shape without repeat indexes

I need to loop through a array in circle in arc shape with a small radius (like draw a circle pixel by pixel), but all algorithm i tried, checks duplicate indexes of array (it's got the same x and y several times).
I have a radius of 3, with a circle form of 28 elements (not filled), but the algorithm iterate 360 times. I can check if x or y change before i do something, but it's lame.
My code now:
for (int radius = 1; radius < 6; radius++)
{
for (double i = 0; i < 360; i += 1)
{
double angle = i * System.Math.PI / 180;
int x = (int)(radius * System.Math.Cos(angle)) + centerX;
int y = (int)(radius * System.Math.Sin(angle)) + centerY;
// do something
// if (array[x, y]) ....
}
}
PS: I can't use midpoint circle, because i need to increment radius starting from 2 until 6, and not every index is obtained, because his circle it's not real (according trigonometry)
EDIT:
What i really need, is scan a full circle edge by edge, starting by center.
360 steps (it's get all coordinates):
Full scan
for (int radius = 2; radius <= 7; radius++)
{
for (double i = 0; i <= 360; i += 1)
{
double angle = i * System.Math.PI / 180;
int x = (int)(radius * System.Math.Cos(angle));
int y = (int)(radius * System.Math.Sin(angle));
print(x, y, "X");
}
}
Using Midpoint Circle or other algorithm skipping steps (missing coordinates):
Midpoint Circle Algorithm
for (int radius = 2; radius <= 7; radius++)
{
int x = radius;
int y = 0;
int err = 0;
while (x >= y)
{
print(x, y, "X");
print(y, x, "X");
print(-y, x, "X");
print(-y, x, "X");
print(-x, y, "X");
print(-x, -y, "X");
print(-y, -x, "X");
print(y, -x, "X");
print(x, -y, "X");
y += 1;
err += 1 + 2 * y;
if (2 * (err - x) + 1 > 0)
{
x -= 1;
err += 1 - 2 * x;
}
}
}
There are two algorithmic ideas in play here: one is rasterizing a circle. The OP code presents a couple opportunities for improvement on that front: (a) one needn't sample the entire 360 degree circle, realizing that a circle is symmetric across both axes. (x,y) can be reflected in the other three quadrants as (-x,y), (-x,-y), and (x,-y). (b) the step on the loop should be related to the curvature. A simple heuristic is to use the radius as the step. So...
let step = MIN(radius, 90)
for (double i=0; i<90; i += step) {
add (x,y) to results
reflect into quadrants 2,3,4 and add to results
}
With these couple improvements, you may no longer care about duplicate samples being generated. If you still do, then the second idea, independent of the circle, is how to hash a pair of ints. There's a good article about that here: Mapping two integers to one, in a unique and deterministic way.
In a nutshell, we compute an int from our x,y pair that's guaranteed to map uniquely, and then check that for duplicates...
cantor(x, y) = 1/2(x + y)(x + y + 1) + y
This works only for positive values of x,y, which is just what you need since we're only computing (and then reflecting) in the first quadrant. For each pair, check that they are unique
let s = an empty set
int step = MIN(radius, 90)
for (double i=0; i<90; i += step) {
generate (x,y)
let c = cantor(x,y)
if (not(s contains c)) {
add (x,y) to results
reflect into quadrants 2,3,4 and add to results
add c to s
}
}
Got it!
It's not beautiful, but work for me.
int maxRadius = 7;
for (int radius = 1; radius <= maxRadius; radius++)
{
x = position.X - radius;
y = position.Y - radius;
x2 = position.X + radius;
y2 = position.Y + radius;
for (int i = 0; i <= radius * 2; i++)
{
if (InCircle(position.X, position.Y, x + i, y, maxRadius)) // Top X
myArray[position, x + i, y]; // check array
if (InCircle(position.X, position.Y, x + i, y2, maxRadius)) // Bottom X
myArray[position, x + i, y2]; // check array
if (i > 0 && i < radius * 2)
{
if (InCircle(position.X, position.Y, x, y + i, maxRadius)) // Left Y
myArray[position, x, y + i]; // check array
if (InCircle(position.X, position.Y, x2, y + i, maxRadius)) // Right Y
myArray[position, x2, y + i]; // check array
}
}
}
public static bool InCircle(int originX, int originY, int x, int y, int radius)
{
int dx = Math.Abs(x - originX);
if (dx > radius) return false;
int dy = Math.Abs(y - originY);
if (dy > radius) return false;
if (dx + dy <= radius) return true;
return (dx * dx + dy * dy <= radius * radius);
}

Algorithm to access the tiles in a matrix (game map) that are in a disc

I am developping a tile mapped game.
I need to access the tiles that are in a disc, with a given radius and centered on a given point.
Accessing the tiles that are in a square is easy, we only need to use two loops :
for(int i=xmin; i<xmax; ++i)
for(int j=ymin; j<ymax; ++j)
// the tile map[i][j] is in the square
But how do you access the tiles that are in a given disc (full circle) ?
EDIT:
I mean, I could process each tile in a bounding rectangle (bounding the disc), and determine whether or not a tile in that rectangle is in the disk, by using (x-x0)²+(y-y0)²<R², but with that algorithm, we would explore useless tiles.
When using a large radius, there are many tiles to process, and it will be slow because calculating (x-x0)²+(y-y0)²<R² many times is heavy
What I want is an algorithm more efficient than this one.
EDIT2:
I don't need a perfect disk
We can do a linear scan through x, calculating the range of y. Then we only have to scan through the tiles that are in the circle, like in this badly drawn picture. (Christmas colors?)
If we have a circle with radius r and an x-position x, we can figure out the maximum length of y:
y = sqrt(r * r - x * x);
So the code for iterating through the tiles would look like:
int center_x = (xmin + xmax) / 2;
int center_y = (ymin + ymax) / 2;
for(int x = xmin; x <= xmax; x++) {
int ydist = sqrt(r * r - (center_x - x) * (center_x - x));
for(int y = center_y - ydist; y <= center_y + ydist; y++) {
// these are the tiles in the disc
}
}
Here's some Python code:
from Tkinter import *
from math import *
tk = Tk()
g = Canvas(tk, width=500, height=500)
g.pack()
x0 = 25 # x center
y0 = 25 # y center
r = 17 # radius
t = 10 # tile side length
for x in range(x0 - r, x0 + r + 1):
ydist = int(round(sqrt(r**2 - (x0 - x)**2), 1))
for y in range(y0 - ydist, y0 + ydist + 1):
g.create_rectangle(x * t, y * t, x * t + t, y * t + t
, fill='#'
+ '0123456789ABCDEF'[15 - int(15 * sqrt((x0 - x)**2 + (y0 - y)**2) / r)]
+ '0123456789ABCDEF'[int(15 * sqrt((x0 - x)**2 + (y0 - y)**2) / r)]
+ '0')
g.create_oval((x0 - r) * t, (y0 - r) * t, (x0 + r) * t + t, (y0 + r) * t + t, outline="red", width=2)
mainloop()
And the resulting disk:
Not perfect at the ends, but I hope it works well enough for you (or you can modify it).
You can use the Bresenham's circle Algorithm (section 3.3, Scan Converting Circles) (it uses integer arithmetic only, is very accurate and process fourth part of the whole circle to produce the entire circumference) in your tile matrix to detect those tiles that forms the circumference, then trace lines between them from up-to-down (or left-to-right):
The following is a pseudo implementation of the circle algorithm:
static void circle(int x0, int y0, int x1, int y1) {
// Bresenham's Circle Algorithm
int x, y, d, deltaE, deltaSE;
int radius, center_x, center_y;
bool change_x = false;
bool change_y = false;
if( x0 > x1 ) {
// swap x values
x = x0;
x0 = x1;
x1 = x;
change_x = true;
}
if( y0 > y1 ) {
// swap y values
y = y0;
y0 = y1;
y1 = y;
change_y = true;
}
int dx = x1 - x0;
int dy = y1 - y0;
radius = dx > dy ? (dy >> 1) : (dx >> 1);
center_x = change_x ? x0 - radius : x0 + radius;
center_y = change_y ? y0 - radius : y0 + radius;
x = 0;
y = radius;
d = 1 - radius;
deltaE = 3;
// -2 * radius + 5
deltaSE = -(radius << 1) + 5;
while(y > x) {
if(d < 0) {
d += deltaE;
deltaE += 2;
deltaSE += 2;
x++;
} else {
d += deltaSE;
deltaE += 2;
deltaSE += 4;
x++;
y--;
}
checkTiles(x, y, center_x, center_y);
}
}
void checkTiles(int x, int y, int center_x, int center_y) {
// here, you iterate tiles up-to-down from ( x + center_x, -y + center_y) to (x + center_x, y + center_y)
// in one straigh line using a for loop
for (int j = -y + center_y; j < y + center_y; ++j)
checkTileAt(x + center_x, j);
// Iterate tiles up-to-down from ( y + center_x, -x + center_y) to ( y + center_x, x + center_y)
for (int j = -x + center_y; j < x + center_y; ++j)
checkTileAt(y + center_x, j);
// Iterate tiles up-to-down from (-x + center_x, -y + center_y) to (-x + center_x, y + center_y)
for (int j = -y + center_y; j < y + center_y; ++j)
checkTileAt(-x + center_x, j);
// here, you iterate tiles up-to-down from (-y + center_x, -x + center_y) to (-y + center_x, x + center_y)
for (int j = -x + center_y; j < x + center_y; ++j)
checkTileAt(-y + center_x, j);
}
With this technique you should process only the required tiles (and after processing only a quarter of the circle), none unnecessary tiles would be checked. Beside that, it uses integer arithmetic only, wich makes it really fast (the deduction and explanation can be found in the provided book link) and the generated circumference is proven to be the best approximation for the real one.
Excluding tiles outside the square wont be much faster. I would just use a square but ignore tiles outside the circle. (e.g. by checking how far the tile is from the circle center)
for(int i=xmin; i<xmax; ++i):
for(int j=ymin; j<ymax; ++j):
if map[i][j] not in the circle:
break
// the tile map[i][j] is in the square
A rough estimate on performance overhead:
Area Square = 2*r*2*r
Area Circle = pi*r*r
Area Square / Area Circle = 4/pi = 1.27
This means using a square instead of a circle is only 1.27 times slower (assuming using a circle doesn't have its own inefficiencies)
Also because you will likely perform some operation on the tiles, (making the iterations involving tiles in the circle much slower) it means the performance gain will go down to almost 0 using a circle layout instead of a square layout.
Use a bounding octagon. It's the bounding square with corners cut off. You need these tests for if a point (any corner of a tile) is in that shape. Put this inside the 2D loop.
abs(x) < R
abs(y) < R
abs(x)+abs(y) < sqrt(2)*R
Precalculate sqrt(2)*R, of course.
This isn't the same as a circle, obviously, but cuts down nicely the amount of wasted space compared to a square.
It'll be hard to generate a loop that goes over only the tile centers or tile corners perfectly, without needing some sort of test in the loop. Any hope for writing such loops would be from use Bresenham's algorithm.

Generate a random point on a rectangle's perimeter with uniform distribution

Given any particular rectangle (x1,y1)-(x2,y2), how can I generate a random point on its perimeter?
I've come up with a few approaches, but it seems like there ought to be a pretty canonical way to do it.
First, I thought I'd generate a random point within the rectangle and clamp it to the closest side, but the distribution didn't seem uniform (points almost never fell on the shorter sides). Second, I picked a side at random and then chose a random point on that side. The code was kind of clunky and it wasn't uniform either - but in the exact opposite way (short sides had the same chance of getting points as long sides). Finally, I've been thinking about "unfolding" the rectangle into a single line and picking a random point on the line. I think that would generate a uniform distribution, but I thought I'd ask here before embarking down that road.
Your last approach is what I would have recommended just from reading your title. Go with that. Your second approach (pick a side at random) would work if you picked a side with probability proportional to the side length.
here is the unfolding idea in objective-c, seems to work, doesn't it :)
//randomness macro
#define frandom (float)arc4random()/UINT64_C(0x100000000)
#define frandom_range(low,high) ((high-low)*frandom)+low
//this will pick a random point on the rect edge
- (CGPoint)pickPointOnRectEdge:(CGRect)edge {
CGPoint pick = CGPointMake(edge.origin.x, edge.origin.y);
CGFloat a = edge.size.height;
CGFloat b = edge.size.width;
CGFloat edgeLength = 2*a + 2*b;
float randomEdgeLength = frandom_range(0.0f, (float)edgeLength);
//going from bottom left counter-clockwise
if (randomEdgeLength<a) {
//left side a1
pick = CGPointMake(edge.origin.x, edge.origin.y + a);
} else if (randomEdgeLength < a+b) {
//top side b1
pick = CGPointMake(edge.origin.x + randomEdgeLength - a, edge.origin.y + edge.size.height );
} else if (randomEdgeLength < (a + b) + a) {
//right side a2
pick = CGPointMake(edge.origin.x + edge.size.width, edge.origin.y + randomEdgeLength - (a+b));
} else {
//bottom side b2
pick = CGPointMake(edge.origin.x + randomEdgeLength - (a + b + a), edge.origin.y);
}
return pick;
}
If by 'random point on the perimeter' you do in fact mean 'point selected from a uniform random distribution over the length of the perimeter', then yes, your 'unfolding' approach is correct.
It should be mentioned however that both your previous approaches do qualify as being a 'random point on the perimeter', just with a non-uniform distribution.
Figured I would try to do this without branching, expressing both X and Y coords as a function of the random number that walks the "unfolded" rectangle.
JS:
function randomOnRect() {
let r = Math.random();
return [Math.min(1, Math.max(0, Math.abs((r * 4 - .5) % 4 - 2) - .5)),
Math.min(1, Math.max(0, Math.abs((r * 4 + .5) % 4 - 2) - .5))]
}
Your last suggestion seems best to me.
Look at the perimeter as a single long line [of length 2*a + 2*b], generate a random number within it, calculate where the point is on the rectangle [assume it starts from some arbitrary point, it doesn't matter which].
It requires only one random and thus is relatively cheap [random sometimes are costly operations].
It is also uniform, and trivial to prove it, there is an even chance the random will get you to each point [assuming the random function is uniform, of course].
For example:
static Random random = new Random();
/** returns a point (x,y) uniformly distributed
* in the border of the rectangle 0<=x<=a, 0<=y<=b
*/
public static Point2D.Double randomRect(double a, double b) {
double x = random.nextDouble() * (2 * a + 2 * b);
if (x < a)
return new Point2D.Double(x, 0);
x -= a;
if (x < b)
return new Point2D.Double(a, x);
x -= b;
if (x < a)
return new Point2D.Double(x, b);
else
return new Point2D.Double(0, x-a);
}
Here is my implementation with uniform distribution (assumes x1 < x2 and y1 < y2):
void randomPointsOnPerimeter(int x1, int y1, int x2, int y2) {
int width = abs(x2 - x1);
int height = abs(y2 - y1);
int perimeter = (width * 2) + (height * 2);
// number of points proportional to perimeter
int n = (int)(perimeter / 8.0f);
for (int i = 0; i < n; i++) {
int x, y;
int dist = rand() % perimeter;
if (dist <= width) {
x = (rand() % width) + x1;
y = y1;
} else if (dist <= width + height) {
x = x2;
y = (rand() % height) + y1;
} else if (dist <= (width * 2) + height) {
x = (rand() % width) + x1;
y = y2;
} else {
x = x1;
y = (rand() % height) + y1;
}
// do something with (x, y)...
}
}
Here's my implementation in Javascript
function pickPointOnRectEdge(width,height){
var randomPoint = Math.random() * (width * 2 + height * 2);
if (randomPoint > 0 && randomPoint < height){
return {
x: 0,
y: height - randomPoint
}
}
else if (randomPoint > height && randomPoint < (height + width)){
return {
x: randomPoint - height,
y: 0
}
}
else if (randomPoint > (height + width) && randomPoint < (height * 2 + width)){
return {
x: width,
y: randomPoint - (width + height)
}
}
else {
return {
x: width - (randomPoint - (height * 2 + width)),
y: height
}
}
}

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