I've googled till I'm blue in the face, and unless I'm missing something really obvious, I can't find any algorithms for calculating the bounding box of a 2D sector.
Given the centre point of the enclosing circle, the radius, and the angles of the extent of the sector, what's the best algorithm to calculate the axis-aligned bounding rectangle of that sector?
Generate the following points:
The circle's center
The positions of the start and end angles of the sector
Additionally, for the angles among 0, 90, 180, and 270 that are within the angle range of the sector, their respective points on the sector
Calculate the min and max x and y from the above points. This is your bounding box
I'm going to rephrase yairchu's answer so that it is clearer (to me, anyway).
Ignore the center coordinates for now and draw the circle at the origin. Convince yourself of the following:
Anywhere the arc intersects an axis will be a max or a min.
If the arc doesn't intersect an axis, then the center will be one corner of the bounding rectangle, and this is the only case when it will be.
The only other possible extreme points of the sector to consider are the endpoints of the radii.
You now have at most 4+1+2 points to find. Find the max and min of those coordinates to draw the rectangle.
The rectangle is easily translated to the original circle by adding the coordinates of the center of the original circle to the rectangle's coordinates.
First of all I apologize if I commit mistakes writing but english is not my first language, spanish is actually!
I faced this problem, and I think I found an efficient solution.
First of all let's see an image of the situation
So we have an ellipse (actually a circle) and two points (C, D) which indicates our sector.
We also have the center of our circle (B) and the angle of the Arc alpha.
Now, in this case I made it passing through 360º on porpouse to see if it would work.
Let's say alpha -> -251.1º (it negative cause its clockwise), lets transform it to positive value 360º - 251.1º = 108.9º now our goal is to find the angle of the bisection of that angle so we can find the max point for the bounding box (E in the image), actually as you may have realized, the length of the segment BE equals the radius of the circle but we must have the angle to obtain the actual coordinates of the E point.
So 108.9º / 2 -> 54.45º now we have the angle.
To find the coordinates of E we use polar coordinates so
x = r * Cos(theta)
y = r * Sin(theta)
we have r and theta so we can calculate x and y
in my example r = 2.82… (actually it's irational but I took the first two decimal digits as a matter of ease)
We know our first radii is 87.1º so theta would be 87.1 - 54.45º -> 32.65º
we know *theta * is 32.65º so let's do some math
x = 2.82 * Cos(32.65º) -> 2.37552
y = 2.82 * Sin(32.65º) -> 1.52213
Now we need to adjust these values to the actual center of the circle so
x = x + centerX
y = y + centerY
In the example, the circle is centered at (1.86, 4.24)
x -> 4.23552
y -> 5.76213
At this stage we should use some calculus. We know that one of the edges of the bounding box will be a tangent of the arc that passes through the point we just calculated so, lets find that tangent (the red line).
We know that the tangent passes through our point (4.23, 5.76) now we need a slope.
As you can see, the slope is the same as the slope of the rect that passes through our radii's so we have to find that slope.
For doing that we need to get the coordinates of our radii's (a fast conversion to cartessian coordinates from polar coordinates).
x = r * Cos(theta)
y = r * Sin(theta)
So
p0 = (centerX + 2.82 * Cos(87.1º), centerY + 2.82 * Sin(87.1º))
p1 = (centerX + 2.82 * Cos(-21.8º), centerY + 2.82 * Sin(-21.8º))
(21.8º is the angle measured clockwise from the horizontal axis to the radii that is below it and thus I put it negative)
p0 (2, 7.06)
p1 (4.48, 3.19)
now let's find the slope:
m = (y - y0) / (x - x0)
...
m = (3.19 - 7.06) / (4.48-2) = -3.87 / 2.48 = -1.56048
...
m = -1.56
having the slope we need to calculate the equation for the tangent, basically is a rect with an already known slope (m = -1.56) that passes through an already know point (E -> (4.23, 5.76))
So we have Y = mx + b where m = -1.56, y = 5.76 and x = 4.23 so b must be
b = 5.76 - (-1.56) * 4.23 = 12.36
Now we have the complete equation for our tangent -> Y = -1.56X + 12.36
All we must do know is project the points C and D over that rect.
We need the equations for the rects CH and DI so let's calculate 'em
Let's start with CH:
We know (from the tanget's equation) that our direction vector is (1.56, 1)
We need to find a rect that passes through the point C -> (2, 7.06)
(x - 2) / 1.56 = (y - 7.06) / 1
Doing some algebra -> y = 0.64x + 5.78
We know have the equation for the rect CH we must calculate the point H.
we have to solve a linear system as follows
y = -1.56x + 12.36
y = 1.56x + 5.78
Solving this we'll find the point H (3, 7.69)
We need to do the same with the rect DI so let's do it
Our direction vector is (1.56, 1) once again
D -> (4.48, 3.19)
(x - 4.48) / 1.56 = (y -3.19) / 1
Doing some algebra -> y = 0.64x + 0.32
Lets solve the linear system
y = -1.56x + 12.36
y = 0.64x + 0.32
I (5.47, 3.82)
At this stage we already have the four points that make our Bounding box -> C, H, D , I
Just in case you don't know or rememeber how to solve a linear system on a programming language, i'll give you a little example
It's pure algebra
Let's say we have the following system
Ax + By = C
Dx + Ey = F
then
Dx = F - Ey
x = (F - Ey) / D
x = F/D - (E/D)y
replacing on the other equation
A(F/D - (E/D)y) + By = C
AF/D - (AE/D)y + By = C
(AE/D)y + By = C - AF/D
y(-AE/D + B) = C - AF/D
y = (C - AF/D) / (-AE/D + B)
= ( (CD - AF) / D ) / ( (-AE + BD) / D) )
so
y = (CD - AF) / (BD - AE)
and for x we do the same
Dx = F - Ey
Dx - F = -Ey
Ey = F - Dx
y = F/E - (D/E)x
replacing on the other equation
Ax + B(F/E - (D/E)x) = C
Ax + (BF/E - (DB/E)x) = C
Ax - (DB/E)x = C - BF/E
x (A-(DB/E)) = C - BF/E
x = (C - BF/E)/(A-(DB/E))
= ((CE - BF) / E) / ((AE-DB) / E)
x = (CE - BF) / (AE - DB)
I apologize for the extent of my answer but I meant to be as clear as possible and thus, I made it almost step by step.
In C# code:
/// <summary>
/// The input parameters describe a circular arc going _clockwise_ from E to F.
/// The output is the bounding box.
/// </summary>
public Rect BoundingBox(Point E, Point F, Point C, double radius)
{
// Put the endpoints into the bounding box:
double x1 = E.X;
double y1 = E.Y;
double x2 = x1, y2 = y1;
if (F.X < x1)
x1 = F.X;
if (F.X > x2)
x2 = F.X;
if (F.Y < y1)
y1 = F.Y;
if (F.Y > y2)
y2 = F.Y;
// Now consider the top/bottom/left/right extremities of the circle:
double thetaE = Math.Atan2(E.Y - C.Y, E.X - C.X);
double thetaF = Math.Atan2(F.Y - C.Y, F.X - C.X);
if (AnglesInClockwiseSequence(thetaE, 0/*right*/, thetaF))
{
double x = (C.X + radius);
if (x > x2)
x2 = x;
}
if (AnglesInClockwiseSequence(thetaE, Math.PI/2/*bottom*/, thetaF))
{
double y = (C.Y + radius);
if (y > y2)
y2 = y;
}
if (AnglesInClockwiseSequence(thetaE, Math.PI/*left*/, thetaF))
{
double x = (C.X - radius);
if (x < x1)
x1 = x;
}
if (AnglesInClockwiseSequence(thetaE, Math.PI*3/2/*top*/, thetaF))
{
double y = (C.Y - radius);
if (y < y1)
y1 = y;
}
return new Rect(x1, y1, x2 - x1, y2 - y1);
}
/// <summary>
/// Do these angles go in clockwise sequence?
/// </summary>
private static bool AnglesInClockwiseSequence(double x, double y, double z)
{
return AngularDiffSigned(x, y) + AngularDiffSigned(y, z) < 2*Math.PI;
}
/// <summary>
/// Returns a number between 0 and 360 degrees, as radians, representing the
/// angle required to go clockwise from 'theta1' to 'theta2'. If 'theta2' is
/// 5 degrees clockwise from 'theta1' then return 5 degrees. If it's 5 degrees
/// anticlockwise then return 360-5 degrees.
/// </summary>
public static double AngularDiffSigned(double theta1, double theta2)
{
double dif = theta2 - theta1;
while (dif >= 2 * Math.PI)
dif -= 2 * Math.PI;
while (dif <= 0)
dif += 2 * Math.PI;
return dif;
}
I tried to implement jairchu's answer, but found some problems, which I would like to share:
My coordinate system for the circle starts with 0 degrees at the right side of the circle and runs counterclockwise through the top (90deg), the left(180deg) and the bottom (270deg). The angles can be between 0 and 359,9999 deg.
The center point should not be part of the list of points
You have to distinguish between clockwise and counterclockwise arcs in order to make the list of points that lie on 0,90,180,270 deg
It is tricky to determine if the angle span includes the angle 0,90,180 or 270 deg.
public override Rect Box()
{
List<Point> potentialExtrema = new List<Point>();
potentialExtrema.Add(StartPoint);
potentialExtrema.Add(EndPoint);
if (!ClockWise)
{
if (EndAngle < StartAngle || EndAngle == 0 || StartAngle == 0 || EndAngle == 360 || StartAngle == 360)
potentialExtrema.Add(new Point(Point.X + Radius, Point.Y));
if ((StartAngle <= 90 || StartAngle > EndAngle) && EndAngle >= 90)
potentialExtrema.Add(new Point(Point.X, Point.Y + Radius));
if ((StartAngle <= 180 || StartAngle > EndAngle) && EndAngle >= 180)
potentialExtrema.Add(new Point(Point.X - Radius, Point.Y));
if ((StartAngle <= 270 || StartAngle > EndAngle) && EndAngle >= 270)
potentialExtrema.Add(new Point(Point.X, Point.Y - Radius));
}
else
{
if (StartAngle < EndAngle || EndAngle == 0 || StartAngle == 0 || EndAngle == 360 || StartAngle == 360)
potentialExtrema.Add(new Point(Point.X + Radius, Point.Y));
if ((StartAngle >= 90 || StartAngle < EndAngle) && EndAngle <= 90)
potentialExtrema.Add(new Point(Point.X, Point.Y + Radius));
if ((StartAngle >= 180 || StartAngle < EndAngle) && EndAngle <= 180)
potentialExtrema.Add(new Point(Point.X - Radius, Point.Y));
if ((StartAngle >= 270 || StartAngle < EndAngle) && EndAngle <= 270)
potentialExtrema.Add(new Point(Point.X, Point.Y - Radius));
}
double maxX = double.NegativeInfinity;
double maxY = double.NegativeInfinity;
double minX = double.PositiveInfinity;
double minY = double.PositiveInfinity;
foreach (var point in potentialExtrema)
{
if (point.X > maxX)
maxX = point.X;
if (point.Y > maxY)
maxY = point.Y;
if (point.X < minX)
minX = point.X;
if (point.Y < minY)
minY = point.Y;
}
return new Rect(minX, minY, maxX - minX, maxY - minY);
}
}
There is a more elegant solution determining wether 0,90,180 or 270 deg lie within the angle span:
public override Rect Box()
{
List<Point> potentialExtrema = new List<Point>();
potentialExtrema.Add(StartPoint);
potentialExtrema.Add(EndPoint);
if (AngleProduct(0))
potentialExtrema.Add(new Point(Point.X + Radius, Point.Y));
if (AngleProduct(90))
potentialExtrema.Add(new Point(Point.X, Point.Y + Radius));
if (AngleProduct(180))
potentialExtrema.Add(new Point(Point.X - Radius, Point.Y));
if (AngleProduct(270))
potentialExtrema.Add(new Point(Point.X, Point.Y - Radius));
double maxX = double.NegativeInfinity;
double maxY = double.NegativeInfinity;
double minX = double.PositiveInfinity;
double minY = double.PositiveInfinity;
foreach (var point in potentialExtrema)
{
if (point.X > maxX)
maxX = point.X;
if (point.Y > maxY)
maxY = point.Y;
if (point.X < minX)
minX = point.X;
if (point.Y < minY)
minY = point.Y;
}
return new Rect(minX, minY, maxX - minX, maxY - minY);
}
private bool AngleProduct(int alpha)
{
if (StartAngle == EndAngle)
if (StartAngle == alpha)
return true;
else
return false;
double prod = 0;
if (ClockWise)
prod = -1 * (alpha - StartAngle) * (EndAngle - alpha) * (EndAngle - StartAngle);
else
prod = (alpha - StartAngle) * (EndAngle - alpha) * (EndAngle - StartAngle);
if (prod >= 0)
return true;
else
return false;
}
Related
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.
I am trying to implement the algorithm explained on this paper, used to traverse grid cells in order following a straight line, which is useful for ray tracing:
http://www.cse.yorku.ca/~amana/research/grid.pdf
The paper describes the algorithm as two parts: initialisation and iterative traversal. I can undersand the iterative traversal part, but I'm having trouble understanding how some of the variables in the initialisation part are calculated.
I need help initialising tMaxX, tMaxY, tDeltaX & tDeltaY. Their initialisation procedure is explained as follows:
Next, we determine the value of t at which the ray crosses the first
vertical voxel boundary and store it in variable tMaxX. We perform a
similar computation in y and store the result in tMaxY. The minimum of
these two values will indicate how much we can travel along the ray
and still remain in the current voxel.
Finally, we compute tDeltaX and tDeltaY. TDeltaX indicates how far
along the ray we must move (in units of t) for the horizontal
component of such a movement to equal the width of a voxel. Similarly,
store in tDeltaY the amount of movement along the ray which has a
vertical component equal to the height of a voxel.
I'm not able to deduce the code I need form the English description given above. Can someone translate it to a math/pseudocode expression for me?
Initialization for X-coordinate variables (the same for Y)
DX = X2 - X1
tDeltaX = GridCellWidth / DX
tMaxX = tDeltaX * (1.0 - Frac(X1 / GridCellWidth))
//Frac if fractional part of float, for example, Frac(1.3) = 0.3, Frac(-1.7)=0.3
Example:
GridCellWidth, Height = 20
X1 = 5, X2 = 105
Y1 = 5, Y2 = 55
DX = 100, DY = 50
tDeltaX = 0.2, tDeltaY = 0.4
tMaxX = 0.2 * (1.0 - 0.25) = 0.15 //ray will meet first vertical line at this param
tMaxY = 0.4 * (1.0 - 0.25) = 0.3 //ray will meet first horizontal line at this param
We can see that first cell border will be met at parameter t = 0.15
The one that worked for me in 3D for both positive and negative directions (in CUDA C):
#define SIGN(x) (x > 0 ? 1 : (x < 0 ? -1 : 0))
#define FRAC0(x) (x - floorf(x))
#define FRAC1(x) (1 - x + floorf(x))
float tMaxX, tMaxY, tMaxZ, tDeltaX, tDeltaY, tDeltaZ;
int3 voxel;
float x1, y1, z1; // start point
float x2, y2, z2; // end point
int dx = SIGN(x2 - x1);
if (dx != 0) tDeltaX = fmin(dx / (x2 - x1), 10000000.0f); else tDeltaX = 10000000.0f;
if (dx > 0) tMaxX = tDeltaX * FRAC1(x1); else tMaxX = tDeltaX * FRAC0(x1);
voxel.x = (int) x1;
int dy = SIGN(y2 - y1);
if (dy != 0) tDeltaY = fmin(dy / (y2 - y1), 10000000.0f); else tDeltaY = 10000000.0f;
if (dy > 0) tMaxY = tDeltaY * FRAC1(y1); else tMaxY = tDeltaY * FRAC0(y1);
voxel.y = (int) y1;
int dz = SIGN(z2 - z1);
if (dz != 0) tDeltaZ = fmin(dz / (z2 - z1), 10000000.0f); else tDeltaZ = 10000000.0f;
if (dz > 0) tMaxZ = tDeltaZ * FRAC1(z1); else tMaxZ = tDeltaZ * FRAC0(z1);
voxel.z = (int) z1;
while (true) {
if (tMaxX < tMaxY) {
if (tMaxX < tMaxZ) {
voxel.x += dx;
tMaxX += tDeltaX;
} else {
voxel.z += dz;
tMaxZ += tDeltaZ;
}
} else {
if (tMaxY < tMaxZ) {
voxel.y += dy;
tMaxY += tDeltaY;
} else {
voxel.z += dz;
tMaxZ += tDeltaZ;
}
}
if (tMaxX > 1 && tMaxY > 1 && tMaxZ > 1) break;
// process voxel here
}
Note, grid cell's width/height/depth are all equal to 1 in my case, but you can easily modify it for your needs.
I'm trying to find the best way to calculate the biggest (in area) rectangle which can be contained inside a rotated rectangle.
Some pictures should help (I hope) in visualizing what I mean:
The width and height of the input rectangle is given and so is the angle to rotate it. The output rectangle is not rotated or skewed.
I'm going down the longwinded route which I'm not even sure if it will handle the corner cases (no pun intended). I'm certain there is an elegant solution to this. Any tips?
EDIT: The output rectangle points don't necessarily have to touch the input rectangles edges. (Thanks to Mr E)
I just came here looking for the same answer. After shuddering at the thought of so much math involved, I thought I would resort to a semi-educated guess. Doodling a bit I came to the (intuitive and probably not entirely exact) conclusion that the largest rectangle is proportional to the outer resulting rectangle, and its two opposing corners lie at the intersection of the diagonals of the outer rectangle with the longest side of the rotated rectangle. For squares, any of the diagonals and sides would do... I guess I am happy enough with this and will now start brushing the cobwebs off my rusty trig skills (pathetic, I know).
Minor update... Managed to do some trig calculations. This is for the case when the Height of the image is larger than the Width.
Update. Got the whole thing working. Here is some js code. It is connected to a larger program, and most variables are outside the scope of the functions, and are modified directly from within the functions. I know this is not good, but I am using this in an isolated situation, where there will be no confusion with other scripts: redacted
I took the liberty of cleaning the code and extracting it to a function:
function getCropCoordinates(angleInRadians, imageDimensions) {
var ang = angleInRadians;
var img = imageDimensions;
var quadrant = Math.floor(ang / (Math.PI / 2)) & 3;
var sign_alpha = (quadrant & 1) === 0 ? ang : Math.PI - ang;
var alpha = (sign_alpha % Math.PI + Math.PI) % Math.PI;
var bb = {
w: img.w * Math.cos(alpha) + img.h * Math.sin(alpha),
h: img.w * Math.sin(alpha) + img.h * Math.cos(alpha)
};
var gamma = img.w < img.h ? Math.atan2(bb.w, bb.h) : Math.atan2(bb.h, bb.w);
var delta = Math.PI - alpha - gamma;
var length = img.w < img.h ? img.h : img.w;
var d = length * Math.cos(alpha);
var a = d * Math.sin(alpha) / Math.sin(delta);
var y = a * Math.cos(gamma);
var x = y * Math.tan(gamma);
return {
x: x,
y: y,
w: bb.w - 2 * x,
h: bb.h - 2 * y
};
}
I encountered some problems with the gamma-calculation, and modified it to take into account in which direction the original box is the longest.
-- Magnus Hoff
Trying not to break tradition putting the solution of the problem as a picture:)
Edit:
Third equations is wrong. The correct one is:
3.w * cos(α) * X + w * sin(α) * Y - w * w * sin(α) * cos(α) - w * h = 0
To solve the system of linear equations you can use Cramer rule, or Gauss method.
First, we take care of the trivial case where the angle is zero or a multiple of pi/2. Then the largest rectangle is the same as the original rectangle.
In general, the inner rectangle will have 3 points on the boundaries of the outer rectangle. If it does not, then it can be moved so that one vertex will be on the bottom, and one vertex will be on the left. You can then enlarge the inner rectangle until one of the two remaining vertices hits a boundary.
We call the sides of the outer rectangle R1 and R2. Without loss of generality, we can assume that R1 <= R2. If we call the sides of the inner rectangle H and W, then we have that
H cos a + W sin a <= R1
H sin a + W cos a <= R2
Since we have at least 3 points on the boundaries, at least one of these inequality must actually be an equality. Let's use the first one. It is easy to see that:
W = (R1 - H cos a) / sin a
and so the area is
A = H W = H (R1 - H cos a) / sin a
We can take the derivative wrt. H and require it to equal 0:
dA/dH = ((R1 - H cos a) - H cos a) / sin a
Solving for H and using the expression for W above, we find that:
H = R1 / (2 cos a)
W = R1 / (2 sin a)
Substituting this in the second inequality becomes, after some manipulation,
R1 (tan a + 1/tan a) / 2 <= R2
The factor on the left-hand side is always at least 1. If the inequality is satisfied, then we have the solution. If it isn't satisfied, then the solution is the one that satisfies both inequalities as equalities. In other words: it is the rectangle which touches all four sides of the outer rectangle. This is a linear system with 2 unknowns which is readily solved:
H = (R2 cos a - R1 sin a) / cos 2a
W = (R1 cos a - R2 sin a) / cos 2a
In terms of the original coordinates, we get:
x1 = x4 = W sin a cos a
y1 = y2 = R2 sin a - W sin^2 a
x2 = x3 = x1 + H
y3 = y4 = y2 + W
Edit: My Mathematica answer below is wrong - I was solving a slightly different problem than what I think you are really asking.
To solve the problem you are really asking, I would use the following algorithm(s):
On the Maximum Empty Rectangle Problem
Using this algorithm, denote a finite amount of points that form the boundary of the rotated rectangle (perhaps a 100 or so, and make sure to include the corners) - these would be the set S decribed in the paper.
.
.
.
.
.
For posterity's sake I have left my original post below:
The inside rectangle with the largest area will always be the rectangle where the lower mid corner of the rectangle (the corner near the alpha on your diagram) is equal to half of the width of the outer rectangle.
I kind of cheated and used Mathematica to solve the algebra for me:
From this you can see that the maximum area of the inner rectangle is equal to 1/4 width^2 * cosecant of the angle times the secant of the angle.
Now I need to figure out what is the x value of the bottom corner for this optimal condition. Using the Solve function in mathematica on my area formula, I get the following:
Which shows that the x coordinate of the bottom corner equals half of the width.
Now just to make sure, I'll going to test our answer empirically. With the results below you can see that indeed the highest area of all of my tests (definately not exhaustive but you get the point) is when the bottom corner's x value = half of the outer rectangle's width.
#Andri is not working correctly for image where width > height as I tested.
So, I fixed and optimized his code by such way (with only two trigonometric functions):
calculateLargestRect = function(angle, origWidth, origHeight) {
var w0, h0;
if (origWidth <= origHeight) {
w0 = origWidth;
h0 = origHeight;
}
else {
w0 = origHeight;
h0 = origWidth;
}
// Angle normalization in range [-PI..PI)
var ang = angle - Math.floor((angle + Math.PI) / (2*Math.PI)) * 2*Math.PI;
ang = Math.abs(ang);
if (ang > Math.PI / 2)
ang = Math.PI - ang;
var sina = Math.sin(ang);
var cosa = Math.cos(ang);
var sinAcosA = sina * cosa;
var w1 = w0 * cosa + h0 * sina;
var h1 = w0 * sina + h0 * cosa;
var c = h0 * sinAcosA / (2 * h0 * sinAcosA + w0);
var x = w1 * c;
var y = h1 * c;
var w, h;
if (origWidth <= origHeight) {
w = w1 - 2 * x;
h = h1 - 2 * y;
}
else {
w = h1 - 2 * y;
h = w1 - 2 * x;
}
return {
w: w,
h: h
}
}
UPDATE
Also I decided to post the following function for proportional rectange calculating:
calculateLargestProportionalRect = function(angle, origWidth, origHeight) {
var w0, h0;
if (origWidth <= origHeight) {
w0 = origWidth;
h0 = origHeight;
}
else {
w0 = origHeight;
h0 = origWidth;
}
// Angle normalization in range [-PI..PI)
var ang = angle - Math.floor((angle + Math.PI) / (2*Math.PI)) * 2*Math.PI;
ang = Math.abs(ang);
if (ang > Math.PI / 2)
ang = Math.PI - ang;
var c = w0 / (h0 * Math.sin(ang) + w0 * Math.cos(ang));
var w, h;
if (origWidth <= origHeight) {
w = w0 * c;
h = h0 * c;
}
else {
w = h0 * c;
h = w0 * c;
}
return {
w: w,
h: h
}
}
Coproc solved this problem on another thread (https://stackoverflow.com/a/16778797) in a simple and efficient way. Also, he gave a very good explanation and python code there.
Below there is my Matlab implementation of his solution:
function [ CI, T ] = rotateAndCrop( I, ang )
%ROTATEANDCROP Rotate an image 'I' by 'ang' degrees, and crop its biggest
% inner rectangle.
[h,w,~] = size(I);
ang = deg2rad(ang);
% Affine rotation
R = [cos(ang) -sin(ang) 0; sin(ang) cos(ang) 0; 0 0 1];
T = affine2d(R);
B = imwarp(I,T);
% Largest rectangle
% solution from https://stackoverflow.com/a/16778797
wb = w >= h;
sl = w*wb + h*~wb;
ss = h*wb + w*~wb;
cosa = abs(cos(ang));
sina = abs(sin(ang));
if ss <= 2*sina*cosa*sl
x = .5*min([w h]);
wh = wb*[x/sina x/cosa] + ~wb*[x/cosa x/sina];
else
cos2a = (cosa^2) - (sina^2);
wh = [(w*cosa - h*sina)/cos2a (h*cosa - w*sina)/cos2a];
end
hw = flip(wh);
% Top-left corner
tl = round(max(size(B)/2 - hw/2,1));
% Bottom-right corner
br = tl + round(hw);
% Cropped image
CI = B(tl(1):br(1),tl(2):br(2),:);
sorry for not giving a derivation here, but I solved this problem in Mathematica a few days ago and came up with the following procedure, which non-Mathematica folks should be able to read. If in doubt, please consult http://reference.wolfram.com/mathematica/guide/Mathematica.html
The procedure below returns the width and height for a rectangle with maximum area that fits into another rectangle of width w and height h that has been rotated by alpha.
CropRotatedDimensionsForMaxArea[{w_, h_}, alpha_] :=
With[
{phi = Abs#Mod[alpha, Pi, -Pi/2]},
Which[
w == h, {w,h} Csc[phi + Pi/4]/Sqrt[2],
w > h,
If[ Cos[2 phi]^2 < 1 - (h/w)^2,
h/2 {Csc[phi], Sec[phi]},
Sec[2 phi] {w Cos[phi] - h Sin[phi], h Cos[phi] - w Sin[phi]}],
w < h,
If[ Cos[2 phi]^2 < 1 - (w/h)^2,
w/2 {Sec[phi], Csc[phi]},
Sec[2 phi] {w Cos[phi] - h Sin[phi], h Cos[phi] - w Sin[phi]}]
]
]
Here is the easiest way to do this... :)
Step 1
//Before Rotation
int originalWidth = 640;
int originalHeight = 480;
Step 2
//After Rotation
int newWidth = 701; //int newWidth = 654; //int newWidth = 513;
int newHeight = 564; //int newHeight = 757; //int newHeight = 664;
Step 3
//Difference in height and width
int widthDiff ;
int heightDiff;
int ASPECT_RATIO = originalWidth/originalHeight; //Double check the Aspect Ratio
if (newHeight > newWidth) {
int ratioDiff = newHeight - newWidth;
if (newWidth < Constant.camWidth) {
widthDiff = (int) Math.floor(newWidth / ASPECT_RATIO);
heightDiff = (int) Math.floor((originalHeight - (newHeight - originalHeight)) / ASPECT_RATIO);
}
else {
widthDiff = (int) Math.floor((originalWidth - (newWidth - originalWidth) - ratioDiff) / ASPECT_RATIO);
heightDiff = originalHeight - (newHeight - originalHeight);
}
} else {
widthDiff = originalWidth - (originalWidth);
heightDiff = originalHeight - (newHeight - originalHeight);
}
Step 4
//Calculation
int targetRectanleWidth = originalWidth - widthDiff;
int targetRectanleHeight = originalHeight - heightDiff;
Step 5
int centerPointX = newWidth/2;
int centerPointY = newHeight/2;
Step 6
int x1 = centerPointX - (targetRectanleWidth / 2);
int y1 = centerPointY - (targetRectanleHeight / 2);
int x2 = centerPointX + (targetRectanleWidth / 2);
int y2 = centerPointY + (targetRectanleHeight / 2);
Step 7
x1 = (x1 < 0 ? 0 : x1);
y1 = (y1 < 0 ? 0 : y1);
This is just an illustration of Jeffrey Sax's solution above, for my future reference.
With reference to the diagram above, the solution is:
(I used the identity tan(t) + cot(t) = 2/sin(2t))
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)
If you have a circle with center (center_x, center_y) and radius radius, how do you test if a given point with coordinates (x, y) is inside the circle?
In general, x and y must satisfy (x - center_x)² + (y - center_y)² < radius².
Please note that points that satisfy the above equation with < replaced by == are considered the points on the circle, and the points that satisfy the above equation with < replaced by > are considered the outside the circle.
Mathematically, Pythagoras is probably a simple method as many have already mentioned.
(x-center_x)^2 + (y - center_y)^2 < radius^2
Computationally, there are quicker ways. Define:
dx = abs(x-center_x)
dy = abs(y-center_y)
R = radius
If a point is more likely to be outside this circle then imagine a square drawn around it such that it's sides are tangents to this circle:
if dx>R then
return false.
if dy>R then
return false.
Now imagine a square diamond drawn inside this circle such that it's vertices touch this circle:
if dx + dy <= R then
return true.
Now we have covered most of our space and only a small area of this circle remains in between our square and diamond to be tested. Here we revert to Pythagoras as above.
if dx^2 + dy^2 <= R^2 then
return true
else
return false.
If a point is more likely to be inside this circle then reverse order of first 3 steps:
if dx + dy <= R then
return true.
if dx > R then
return false.
if dy > R
then return false.
if dx^2 + dy^2 <= R^2 then
return true
else
return false.
Alternate methods imagine a square inside this circle instead of a diamond but this requires slightly more tests and calculations with no computational advantage (inner square and diamonds have identical areas):
k = R/sqrt(2)
if dx <= k and dy <= k then
return true.
Update:
For those interested in performance I implemented this method in c, and compiled with -O3.
I obtained execution times by time ./a.out
I implemented this method, a normal method and a dummy method to determine timing overhead.
Normal: 21.3s
This: 19.1s
Overhead: 16.5s
So, it seems this method is more efficient in this implementation.
// compile gcc -O3 <filename>.c
// run: time ./a.out
#include <stdio.h>
#include <stdlib.h>
#define TRUE (0==0)
#define FALSE (0==1)
#define ABS(x) (((x)<0)?(0-(x)):(x))
int xo, yo, R;
int inline inCircle( int x, int y ){ // 19.1, 19.1, 19.1
int dx = ABS(x-xo);
if ( dx > R ) return FALSE;
int dy = ABS(y-yo);
if ( dy > R ) return FALSE;
if ( dx+dy <= R ) return TRUE;
return ( dx*dx + dy*dy <= R*R );
}
int inline inCircleN( int x, int y ){ // 21.3, 21.1, 21.5
int dx = ABS(x-xo);
int dy = ABS(y-yo);
return ( dx*dx + dy*dy <= R*R );
}
int inline dummy( int x, int y ){ // 16.6, 16.5, 16.4
int dx = ABS(x-xo);
int dy = ABS(y-yo);
return FALSE;
}
#define N 1000000000
int main(){
int x, y;
xo = rand()%1000; yo = rand()%1000; R = 1;
int n = 0;
int c;
for (c=0; c<N; c++){
x = rand()%1000; y = rand()%1000;
// if ( inCircle(x,y) ){
if ( inCircleN(x,y) ){
// if ( dummy(x,y) ){
n++;
}
}
printf( "%d of %d inside circle\n", n, N);
}
You can use Pythagoras to measure the distance between your point and the centre and see if it's lower than the radius:
def in_circle(center_x, center_y, radius, x, y):
dist = math.sqrt((center_x - x) ** 2 + (center_y - y) ** 2)
return dist <= radius
EDIT (hat tip to Paul)
In practice, squaring is often much cheaper than taking the square root and since we're only interested in an ordering, we can of course forego taking the square root:
def in_circle(center_x, center_y, radius, x, y):
square_dist = (center_x - x) ** 2 + (center_y - y) ** 2
return square_dist <= radius ** 2
Also, Jason noted that <= should be replaced by < and depending on usage this may actually make sense even though I believe that it's not true in the strict mathematical sense. I stand corrected.
boolean isInRectangle(double centerX, double centerY, double radius,
double x, double y)
{
return x >= centerX - radius && x <= centerX + radius &&
y >= centerY - radius && y <= centerY + radius;
}
//test if coordinate (x, y) is within a radius from coordinate (center_x, center_y)
public boolean isPointInCircle(double centerX, double centerY,
double radius, double x, double y)
{
if(isInRectangle(centerX, centerY, radius, x, y))
{
double dx = centerX - x;
double dy = centerY - y;
dx *= dx;
dy *= dy;
double distanceSquared = dx + dy;
double radiusSquared = radius * radius;
return distanceSquared <= radiusSquared;
}
return false;
}
This is more efficient, and readable. It avoids the costly square root operation. I also added a check to determine if the point is within the bounding rectangle of the circle.
The rectangle check is unnecessary except with many points or many circles. If most points are inside circles, the bounding rectangle check will actually make things slower!
As always, be sure to consider your use case.
You should check whether the distance from the center of the circle to the point is smaller than the radius
using Python
if (x-center_x)**2 + (y-center_y)**2 <= radius**2:
# inside circle
Find the distance between the center of the circle and the points given. If the distance between them is less than the radius then the point is inside the circle.
if the distance between them is equal to the radius of the circle then the point is on the circumference of the circle.
if the distance is greater than the radius then the point is outside the circle.
int d = r^2 - ((center_x-x)^2 + (center_y-y)^2);
if(d>0)
print("inside");
else if(d==0)
print("on the circumference");
else
print("outside");
Calculate the Distance
D = Math.Sqrt(Math.Pow(center_x - x, 2) + Math.Pow(center_y - y, 2))
return D <= radius
that's in C#...convert for use in python...
As said above -- use Euclidean distance.
from math import hypot
def in_radius(c_x, c_y, r, x, y):
return math.hypot(c_x-x, c_y-y) <= r
The equation below is a expression that tests if a point is within a given circle where xP & yP are the coordinates of the point, xC & yC are the coordinates of the center of the circle and R is the radius of that given circle.
If the above expression is true then the point is within the circle.
Below is a sample implementation in C#:
public static bool IsWithinCircle(PointF pC, Point pP, Single fRadius){
return Distance(pC, pP) <= fRadius;
}
public static Single Distance(PointF p1, PointF p2){
Single dX = p1.X - p2.X;
Single dY = p1.Y - p2.Y;
Single multi = dX * dX + dY * dY;
Single dist = (Single)Math.Round((Single)Math.Sqrt(multi), 3);
return (Single)dist;
}
This is the same solution as mentioned by Jason Punyon, but it contains a pseudo-code example and some more details. I saw his answer after writing this, but I didn't want to remove mine.
I think the most easily understandable way is to first calculate the distance between the circle's center and the point. I would use this formula:
d = sqrt((circle_x - x)^2 + (circle_y - y)^2)
Then, simply compare the result of that formula, the distance (d), with the radius. If the distance (d) is less than or equal to the radius (r), the point is inside the circle (on the edge of the circle if d and r are equal).
Here is a pseudo-code example which can easily be converted to any programming language:
function is_in_circle(circle_x, circle_y, r, x, y)
{
d = sqrt((circle_x - x)^2 + (circle_y - y)^2);
return d <= r;
}
Where circle_x and circle_y is the center coordinates of the circle, r is the radius of the circle, and x and y is the coordinates of the point.
My answer in C# as a complete cut & paste (not optimized) solution:
public static bool PointIsWithinCircle(double circleRadius, double circleCenterPointX, double circleCenterPointY, double pointToCheckX, double pointToCheckY)
{
return (Math.Pow(pointToCheckX - circleCenterPointX, 2) + Math.Pow(pointToCheckY - circleCenterPointY, 2)) < (Math.Pow(circleRadius, 2));
}
Usage:
if (!PointIsWithinCircle(3, 3, 3, .5, .5)) { }
As stated previously, to show if the point is in the circle we can use the following
if ((x-center_x)^2 + (y - center_y)^2 < radius^2) {
in.circle <- "True"
} else {
in.circle <- "False"
}
To represent it graphically we can use:
plot(x, y, asp = 1, xlim = c(-1, 1), ylim = c(-1, 1), col = ifelse((x-center_x)^2 + (y - center_y)^2 < radius^2,'green','red'))
draw.circle(0, 0, 1, nv = 1000, border = NULL, col = NA, lty = 1, lwd = 1)
Moving into the world of 3D if you want to check if a 3D point is in a Unit Sphere you end up doing something similar. All that is needed to work in 2D is to use 2D vector operations.
public static bool Intersects(Vector3 point, Vector3 center, float radius)
{
Vector3 displacementToCenter = point - center;
float radiusSqr = radius * radius;
bool intersects = displacementToCenter.magnitude < radiusSqr;
return intersects;
}
iOS 15, Accepted Answer written in Swift 5.5
func isInRectangle(center: CGPoint, radius: Double, point: CGPoint) -> Bool
{
return point.x >= center.x - radius && point.x <= center.x + radius &&
point.y >= center.y - radius && point.y <= center.y + radius
}
//test if coordinate (x, y) is within a radius from coordinate (center_x, center_y)
func isPointInCircle(center: CGPoint,
radius:Double, point: CGPoint) -> Bool
{
if(isInRectangle(center: center, radius: radius, point: point))
{
var dx:Double = center.x - point.x
var dy:Double = center.y - point.y
dx *= dx
dy *= dy
let distanceSquared:Double = dx + dy
let radiusSquared:Double = radius * radius
return distanceSquared <= radiusSquared
}
return false
}
I used the code below for beginners like me :).
public class incirkel {
public static void main(String[] args) {
int x;
int y;
int middelx;
int middely;
int straal; {
// Adjust the coordinates of x and y
x = -1;
y = -2;
// Adjust the coordinates of the circle
middelx = 9;
middely = 9;
straal = 10;
{
//When x,y is within the circle the message below will be printed
if ((((middelx - x) * (middelx - x))
+ ((middely - y) * (middely - y)))
< (straal * straal)) {
System.out.println("coordinaten x,y vallen binnen cirkel");
//When x,y is NOT within the circle the error message below will be printed
} else {
System.err.println("x,y coordinaten vallen helaas buiten de cirkel");
}
}
}
}}
Here is the simple java code for solving this problem:
and the math behind it : https://math.stackexchange.com/questions/198764/how-to-know-if-a-point-is-inside-a-circle
boolean insideCircle(int[] point, int[] center, int radius) {
return (float)Math.sqrt((int)Math.pow(point[0]-center[0],2)+(int)Math.pow(point[1]-center[1],2)) <= radius;
}
PHP
if ((($x - $center_x) ** 2 + ($y - $center_y) ** 2) <= $radius **2) {
return true; // Inside
} else {
return false; // Outside
}