linear equation java [closed] - java

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I am trying to convert the equation below into programming code. The purpose is to find the intersecting point of the two lines. And to pront
(y1 - y2)x - (x1 - x2)y = (y1 - y2)x1 - (x1 - x2)y1
(y3 - y4)x - (x3 - x4)y = (y3 - y4)x3 - (x3 - x4)y3
I've been told to use cramers rule, but cramers rule has 6 diff variables. I'll be starting off with 4 different points as 8 variables (x1, y1, x2, y2, x3, y3, x4, y4)
I'm using Java. Any help would be appreciated. All the asked questions on this site are for different types of linear equations with long complicated code, I didnt find anything that was relevant to me.
This is what I have, not much but the transition from the above equation to something programmable really stumps me.
import java.util.Scanner;
public class E325 {
public static void main(String[] args) {
/*
* The purpose of this program is to find the intersect
* of two lines given by the user by four points
*
* Get the four points. x1,y1 x2,y2 x3,y3 x4,y4
*/
Scanner input = new Scanner(System.in);
System.out.print("Enter x1 y1, x2 y2, x3 y3, x4 y4: ");
double x1 = input.nextDouble();
double y1 = input.nextDouble();
double x2 = input.nextDouble();
double y2 = input.nextDouble();
double x3 = input.nextDouble();
double y3 = input.nextDouble();
double x4 = input.nextDouble();
double y4 = input.nextDouble();
}
}

I don't know matrices, so I would solve it a different way.
You know enough to calculate m and b for each line
m = (y2-y1)/(x2-x1)
b = y1 - m(x1)
Calculate m and b for one line and m' and b' for the other.
Now at the intersection, x,y are the same on the two lines, so
y = mx + b and y = m'x + b'. Therefore
mx + b = m'x + b'
x = (m'x + b' - b)/m
Plug x into mx + b to get y for that x.
You still have to ensure that the x,y you have found are on your line SEGMENTS; unless the lines are parallel, they will intersect somewhere, but not necessarily between the endpoints of the line segments you've started with.

(y1 - y2)x - (x1 - x2)y = (y1 - y2)x1 - (x1 - x2)y1
(y3 - y4)x - (x3 - x4)y = (y3 - y4)x3 - (x3 - x4)y3
I've been told to use cramers rule, but cramers rule has 6 diff variables.
No. That's completely wrong. Cramer's rule is a simple technique to solve equations of the form Ax = b, but where A is a NxN matrix, and x and b are N vectors. What you need to do is to formulate those two equations as a matrix expression. I'll give you the left hand side that corresponds to the above. I'll leave the right hand side and the application of Cramer's rule up to you.
A * x = b
⌈ y1-y2 -(x1-x2) ⌉ ⌈ x ⌉
| | * | |
⌊ y3-y4 -(x3-x4) ⌋ ⌊ y ⌋
Multiplying that matrix A and the vector [x,y] yields
⌈ y1-y2 -(x1-x2) ⌉ ⌈ x ⌉ ⌈ (y1-y2)*x - (x1-x2)*y ⌉
| | * | | = | |
⌊ y3-y4 -(x3-x4) ⌋ ⌊ y ⌋ ⌊ (y3-y4)*x - (x3-x4)*y ⌋
Note that this result is exactly the same as the left hand sides of your pair of equations.

A line passes through two points.
You have four points and two lines.
The equation of a line is well known:
y = m*x + b
where m is the slope and b is the y-intercept.
If you have two lines, they look like this:
-m1*x + y = b1
-m2*x + y = b2
You can see the matrix equation, can't you?
[ -m1 1 ]{x} = {b1}
[ -m2 1 ]{y} {b2}
Invert this to solve for (x, y) where the two lines intersect. If you can't invert the matrix, it means they don't intersect.
Cramer's Rule? Sure, it's easy to write for a 2x2 case. LU decomposition would be more general.

Related

Test if point is within line range on 2D space

This question is a bit hard to formulate so I'll start by showing this image:
I want to test if points (such as p1 and p2 on the image) are within the dotted lines that are perpendicular to the line at its limits. I know the coordinates of the points to test and the line's limits.
So for p1 it would be false, and for p2 it would be true.
What would be the most computationaly efficient way to calculate this?
I'm working with floats in Java.
This can be very efficiently done with the dot product:
This is positive if A has a component parallel to B, and negative if anti-parallel.
Therefore if you have a line segment defined by points A and B, and a test point P, you only need two dot product operations to test:
dot(A - B, P - B) >= 0 && dot(B - A, P - A) >= 0
EDIT: a graphical explanation:
The dot product can be shown to be:
Thus if θ > 90 then dot(A, B) < 0, and vice versa. Now for your problem:
In case 1, when dot(A - B, P - B) > 0 we say that P is on the correct side of the dotted line at B, and vice versa in case 2. By symmetry we can then do the same operation at A, by swapping A and B.
If the point to test (tp), together with start point (sp) and end point (ep) of the range, form an obtuse triangle and you can conclude that it is out of range.
https://en.wikipedia.org/wiki/Acute_and_obtuse_triangles
A special case would be tp is same slope as sp and ep, then you calculate the 2 distances:
distSpAndTp - distance between sp and tp
distEpAndTp - distance between ep and tp
If the sum of these 2 distances = distance between sp and ep, then tp is in range, otherwise it is out of range.
The best approach would be to first create a rectangle Rect (of android.graphics package), with x and width being the beginning and end of line, and y and height being the beginning and end of screen height.
Then use the Rect method Rect.contains(int x, int y) to check if the point coordinates lie within.
For floats, use RectF class instead.
This approach involves using 2D vectors (which you should have been using anyway, makes working in any coordinate system a lot easier) and the dot (scalar) product. It does not require any relatively expensive operations like the square root or trignometic functions, and therefore is very performant.
Let A and B be the start and end points (by point I mean a vector representing a position in 2D space) of the line segment, in any order. If P is the point to test, then:
If dot(PA, AB) and dot(PB, AB) have the same sign, the point lies outside the region (like p1 in your example).
If the dot products above have opposite signs, the point lies inside the region (like p2).
Where PA = A - P, PB = B - P and AB = B - A.
This condition can be surmised as follows:
if dot(PA, AB) * dot(PB, AB) <= 0 {
// Opposite signs, inside region
// If the product is equal to zero, the point is on one of the dotted lines
}
else {
// Same signs, outside region
}
Let's say, x1 is the beginning of the line and x2 is the end. Then ax is the dot in an horizontal plan and; y1, y2 and ay in vertical plan.
if((ax >= x1 && ax <= x2) && (ay >= y1 && ay <= y2)){ // do your work
}
There are a few answers already but there is another solution that will give you the unit distance on the line segment that the points is perpendicular to.
Where then line is x1,y1 to x2,y2 and the point is px,py
Find the vector from line start to end
vx = x2 - x1;
vy = y2 - y1;
And the vector from the line start (or end) to the point
vpx = px - x1;
vpy = py - y1;
And then divide the dot product of the two vectors by the length squared of the line.
unitDist = (vx * vpx + vy * vpy) / (vx * vx + vy * vy);
If the perpendicular intercept is on the line segment then unitDist will be 0 <= unitDist <= 1
In shortened form
x2 -= x1;
y2 -= y1;
unitDist = (x2 * (px - x1) + y2 * (py - y1)) / (x2^2 + y2^2);
if (unitDist >= 0 && unitDist <= 1) {
// point px,py perpendicular to line segment x1,y1,x2,y2
}
You also get the benefit of being able to get the point on the line where the intercept is.
p2x = vx * unitDist + x1;
p2y = vy * unitDist + y1;
And thus the distance that the point is from the line (note not line segment but line)
dist = hypot(p2x - px, p2y - py);
Which is handy if you are using a point to select from many lines by using the minimum distance to determine the selected line.
This can be solved nicely using complex numbers.
Let a and b the endpoints of the segment. We use the transformation that maps the origin 0 to a and the point 1 to b. This transformation is a similarity and its expresion is simply
p = (b - a) q + a
as you can verify by substituting q=0 or q=1. It maps the whole stripe perpendicular to the given segment to the stripe perpendicular to the segment 0-1.
Now the inverse transform is obviously
q = (p - a) / (b - a),
and the desired condition is
0 <= Re((p - a) / (b - a)) <= 1.
To avoid the division, you can rewrite
0 <= Re((p - a) (b - a)*) <= |b-a|²
or
0 <= (px - ax)(bx - ax) + (py - ay)(by - ay) <= (bx - ax)² + (by - ay)².

Finding the change needed in location to move around the circumference of a circle#2

I asked about this yesterday as well and was told that I needed to be using radians. I had assumed that was the answer but there does appear to be another problem with the code below. I am trying to write a method which will allow my Gladiators to rotate a central point between the two, to circle each other so to speak. Below is my code. Gladiator variable target is of Gladiator type and is set to the second party in the rotation. center[0] is the x location, center[1] is y.
public void rotate(Gladiator a, int angle) {
double x1;
double y1;
double x2;
double y2;
double r;
double midx;
double midy;
int currentAngle;
r = getDistance(a,a.target)/2;
midx = (a.center[0]-a.target.center[0])/2;
midy = (a.center[1]-a.target.center[1])/2;
currentAngle = (int)Math.toDegrees(Math.atan2(a.center[1] - midy, a.center[0] - midx));
x1 = Math.cos(Math.toRadians(currentAngle+angle)) * r;
y1 = Math.sin(Math.toRadians(currentAngle+angle)) * r;
x2 = Math.cos(Math.toRadians(currentAngle+angle)) * -r;
y2 = Math.sin(Math.toRadians(currentAngle+angle)) * -r;
a.move((int)x1,(int)y1);
a.target.move((int)x2,(int)y2);
}
Anyone see anything wrong with this? At the moment they end up meeting towards what I would think would be the middle of my circle, waaay closer than they were. Any thoughts?
Edit: Also, I am currently running this twice... once for each Gladiator involved. I can do that and just have them rotate half the desired amount each time, but it would be better if I could rotate them as a whole then disinclude the second party from the Gladiator list I am iterating through. What would be the most simple implementation of this?
Edit2: I think part of my problem was that I wasn't calling Math.toDegrees on my atan2 equation. I noticed it wasn't getting any new angle value other than 0, now it is. Still, there is something wrong. They rotate from horizontal to vertical but are moving much further from each other on each rotation and once they get to the vertical alignment they end up rotating the other direction just a few degrees (rather than 45, my current input) and then do get much closer together like before.
Edit3: Note that the move method's parameters are the change needed, not the actual coordinates.
I see you are using int a lot, be very careful since you may get stuck depending on angle.
I did a quick rewrite to simplify your repetition and use the radian logic that was recommended. (Untested).
I also converted your locations to double to avoid odd integer arithmetic problems. (Your midx/midy calculations were in int math)
After finishing I realized you were rotating around (0,0) rather than the midpoint, and your mid variables were confusingly named.
//I would do double inline with the initialization, but left here in case you had another reason
double x1,y1, x2,y2, r, midx,midy, newAngle;
x1 = a.center[0];
y1 = a.center[1];
x2 = a.target.center[0];
y1 = a.target.center[1];
r = getDistance(a, a.target)/2;
midx = x1 + (x2 - x1)/2;
midy = y1 + (y2 - y1)/2;
newAngle = Math.toRadians(angle) +
Math.atan2(midy, midx);
x1 = Math.cos(newAngle) * r + midx;
y1 = Math.sin(newAngle) * r + midy;
x2 = Math.cos(newAngle) * -r + midx;
y2 = Math.sin(newAngle) * -r + midy;
a.move((int)x1,(int)y1);
a.target.move((int)x2,(int)y2);

Line2D Java - Get coordinates where y = value?

Given a line segment defined by (x1, y1) and (x2, y2), find the location on the line where y = a certain value.
I understand I could obtain the equation of the line, then solve using simultaneous equations, but is this possible using Line2D or any other Java classes?
Any suggestions or comments would be appreciated!
Kelvin.
I don't think there's anything in the Java API to actually calculate the intersection. The closest you can get, I think, is to use Line2D to test whether the line segment intersects the (vertical) line y = k for some constant k:
Line2D line = new Line2D.Double(x1, y1, x2, y2);
if (line.intersectsLine(Double.MIN_VALUE, k, Double.MAX_VALUE, k)) {
double x = (x2 - x1) * (k - y1) / (y2 - y1);
// intersection is at (x, k)
} else {
// intersection is outside extend of the line segment
}
However, it would probably be more efficient to just check that y1 != y2, compute the intersection, and then check whether the x coordinate is in the range [x1, x2].
I would suggest apache commons math for tasks like this.
http://commons.apache.org/math/apidocs/index.html
There are a number of ways you can do this. One way would be
org.apache.commons.math3.geometry.euclidean.twod.Line lineOne = new org.apache.commons.math3.geometry.euclidean.twod.Line(p,angle);
org.apache.commons.math3.geometry.euclidean.twod.Line horizontalLine = new org.apache.commons.math3.geometry.euclidean.twod.Line(new vector2d(0,yToSolveFor),pi/2);
Vector2D intersection=lineOne.intersect(horizontalLine);
intersection.getX(); // The answer

Check if point is on line in Java Swing

I have drawn a line and then a point, and then I want to check if the point is on the line or not. I have taken a line coordinate in array (as there was more than one line). I want to check the current point in on the last line or not?
if (positionX1 == positionX2 && positionY1 == positionY2) {
float m = line.getSlope(
drawLines[currentLines - 1][2], drawLines[currentLines - 1][3],
drawLines[currentLines - 1][0], drawLines[currentLines - 1][1]);
m = Float.parseFloat(df.format(m));
float c = line.getIntercept(
drawLines[currentLines - 1][2], drawLines[currentLines - 1][3],
drawLines[currentLines - 1][0], drawLines[currentLines - 1][1]);
c = Math.round(c);
m1 = line.getSlope(positionX2, positionY2,
drawLines[currentLines - 1][0], drawLines[currentLines - 1][1]);
m1 = Float.parseFloat(df.format(m1));
System.out.println(m + " " + m1);
c1 = line.getIntercept(positionX2, positionY2,
drawLines[currentLines - 1][0], drawLines[currentLines - 1][1]);
c1 = Math.round(c1);
if (m == m1 && ((c == c1) || (c == c1 - 1) || (c == c1 + 1))) {
System.out.println("Point is on Line");
}
}
Problem is when a point is near the starting point of line or when a line is about vertical values of m1 and c1 changes with big difference. So, there's a problem for detecting if a point on line or not. How can I check for this situation?
Line2D.ptSegDist(x1, y1, x2, y2, xP, yP) returns 0.0 if the point (xP, yP) is on the line segment from (x1, y1) to (x2, y2). Line2D.ptLineDist does the same thing for the infinite line.
Use the vector form of the distance from a point to a line where the line is x = a + t n.
If instead of a unit vector n you use a non-unit vector N, then d = ||(a - p) - ((a - p) · N) N / ( N · N) ||, which eliminates a square root.
Assuming that the arrays of floats you are using to describe lines are interpreted as { x1, y1, x2, y2 }, then a = ( x1, y1 ) and N = ( x2 - x1, y2 - y1 ).
If the calculated distance is comparable to the measurement or arithmetic errors, the point is on the line. Again, you don't need to calculate the square root in the modulus but can compare the squared value.
In terms of an algorithm, a line (other than one which is vertical which has equation like x = constant) has a form y = mx + b. If your point satisfies that equation, then it is on the line. So all you need to is find the slope value of the line, and its y-intercept and check to see if the point's x and y values satisfy the equation for each line.
EDIT:
As is pointed out in an above comment, you could use the point-slope form (with slope being (y2-y1)/(x2/x1)) instead of the slope-intercept form. This would give you an equation that depends solely on y,x and the start and end points of the lines which would be much easier to code out (since you define a line by its start and end points, at least in swing). The only reason I suggested the slope-intercept form was because you were already attempting to use it in your algorithm.

Area of intersection between circle and rectangle

I'm looking for a fast way to determine the area of intersection between a rectangle and a circle (I need to do millions of these calculations).
A specific property is that in all cases the circle and rectangle always have 2 points of intersection.
Given 2 points of intersection:
0 vertices is inside the circle: The area of a circular segment
XXXXX -------------------
X X X X Circular segment
X X XX XX
+-X-------X--+ XXXXXXXX
| X X |
| XXXXX |
1 vertex is inside the circle: The sum of the areas of a circular segment and a triangle.
XXXXX XXXXXXXXX
X X Triangle ->X _-X
X X X _- X
X +--X--+ X _- X <- Circular segment
X | X | X- XXX
XXXXX | XXXX
| |
2 vertices are inside the circle: The sum of the area of two triangles and a circular segment
XXXXX +------------X
X X | _--'/'X
X +--X--- Triangle->| _-- / X
X | X |_-- /XX <- Circular segment
X +-X---- +-------XX
XXXXX Triangle^
3 vertices are inside the circle: The area of the rectangle minus the area of a triangle plus the area of a circular segment
XXXXX
X +--X+ XXX
X | X -------XXX-----+ <- Triangle outside
X | |X Rect ''. XXX |
X +---+X ''. XX|
X X ''. X <- Circular segment inside
X X ^|X
X X | X
XXXXX
To calculate these areas:
Most of the points you'll need to use can be found by finding the intersection of a line and a circle
The areas you need to compute can be found by computing the area of a circular segment and computing the area of a triangle.
You can determine if a vertex is inside the circle by calculating if its distance from the center is less than the radius.
I realize this was answered a while ago but I'm solving the same problem and I couldn't find an out-of-the box workable solution I could use. Note that my boxes are axis aligned, this is not quite specified by the OP. The solution below is completely general, and will work for any number of intersections (not only two). Note that if your boxes are not axis-aligned (but still boxes with right angles, rather than general quads), you can take advantage of the circles being round, rotate the coordinates of everything so that the box ends up axis-aligned and then use this code.
I want to use integration - that seems like a good idea. Let's start with writing an obvious formula for plotting a circle:
x = center.x + cos(theta) * radius
y = center.y + sin(theta) * radius
^
|
|**### **
| #* # * * x
|# * # * # y
|# * # *
+-----------------------> theta
* # * #
* # * #
* #* #
***###
This is nice, but I'm unable to integrate the area of that circle over x or y; those are different quantities. I can only integrate over the angle theta, yielding areas of pizza slices. Not what I want. Let's try to change the arguments:
(x - center.x) / radius = cos(theta) // the 1st equation
theta = acos((x - center.x) / radius) // value of theta from the 1st equation
y = center.y + sin(acos((x - center.x) / radius)) * radius // substitute to the 2nd equation
That's more like it. Now given the range of x, I can integrate over y, to get an area of the upper half of a circle. This only holds for x in [center.x - radius, center.x + radius] (other values will cause imaginary outputs) but we know that the area outside that range is zero, so that is handled easily. Let's assume unit circle for simplicity, we can always plug the center and radius back later on:
y = sin(acos(x)) // x in [-1, 1]
y = sqrt(1 - x * x) // the same thing, arguably faster to compute http://www.wolframalpha.com/input/?i=sin%28acos%28x%29%29+
^ y
|
***|*** <- 1
**** | ****
** | **
* | *
* | *
----|----------+----------|-----> x
-1 1
This function indeed has an integral of pi/2, since it is an upper half of a unit circle (the area of half a circle is pi * r^2 / 2 and we already said unit, which means r = 1). Now we can calculate area of intersection of a half-circle and an infinitely tall box, standing on the x axis (the center of the circle also lies on the the x axis) by integrating over y:
f(x): integral(sqrt(1 - x * x) * dx) = (sqrt(1 - x * x) * x + asin(x)) / 2 + C // http://www.wolframalpha.com/input/?i=sqrt%281+-+x*x%29
area(x0, x1) = f(max(-1, min(1, x1))) - f(max(-1, min(1, x0))) // the integral is not defined outside [-1, 1] but we want it to be zero out there
~ ~
| ^ |
| | |
| ***|*** <- 1
****###|##|****
**|######|##| **
* |######|##| *
* |######|##| *
----|---|------+--|-------|-----> x
-1 x0 x1 1
This may not be very useful, as infinitely tall boxes are not what we want. We need to add one more parameter in order to be able to free the bottom edge of the infinitely tall box:
g(x, h): integral((sqrt(1 - x * x) - h) * dx) = (sqrt(1 - x * x) * x + asin(x) - 2 * h * x) / 2 + C // http://www.wolframalpha.com/input/?i=sqrt%281+-+x*x%29+-+h
area(x0, x1, h) = g(min(section(h), max(-section(h), x1))) - g(min(section(h), max(-section(h), x0)))
~ ~
| ^ |
| | |
| ***|*** <- 1
****###|##|****
**|######|##| **
* +------+--+ * <- h
* | *
----|---|------+--|-------|-----> x
-1 x0 x1 1
Where h is the (positive) distance of the bottom edge of our infinite box from the x axis. The section function calculates the (positive) position of intersection of the unit circle with the horizontal line given by y = h and we could define it by solving:
sqrt(1 - x * x) = h // http://www.wolframalpha.com/input/?i=sqrt%281+-+x+*+x%29+%3D+h
section(h): (h < 1)? sqrt(1 - h * h) : 0 // if h is 1 or above, then the section is an empty interval and we want the area integral to be zero
^ y
|
***|*** <- 1
**** | ****
** | **
-----*---------+---------*------- y = h
* | *
----||---------+---------||-----> x
-1| |1
-section(h) section(h)
Now we can get the things going. So how to calculate the area of intersection of a finite box intersecting a unit circle above the x axis:
area(x0, x1, y0, y1) = area(x0, x1, y0) - area(x0, x1, y1) // where x0 <= x1 and y0 <= y1
~ ~ ~ ~
| ^ | | ^ |
| | | | | |
| ***|*** | ***|***
****###|##|**** ****---+--+**** <- y1
**|######|##| ** ** | **
* +------+--+ * <- y0 * | *
* | * * | *
----|---|------+--|-------|-----> x ----|---|------+--|-------|-----> x
x0 x1 x0 x1
^
|
***|***
****---+--+**** <- y1
**|######|##| **
* +------+--+ * <- y0
* | *
----|---|------+--|-------|-----> x
x0 x1
That's nice. So how about a box which is not above the x axis? I'd say not all the boxes are. Three simple cases arise:
the box is above the x axis (use the above equation)
the box is below the x axis (flip the sign of y coordinates and use the above equation)
the box is intersecting the x axis (split the box to upper and lower half, calculate the area of both using the above and sum them)
Easy enough? Let's write some code:
float section(float h, float r = 1) // returns the positive root of intersection of line y = h with circle centered at the origin and radius r
{
assert(r >= 0); // assume r is positive, leads to some simplifications in the formula below (can factor out r from the square root)
return (h < r)? sqrt(r * r - h * h) : 0; // http://www.wolframalpha.com/input/?i=r+*+sin%28acos%28x+%2F+r%29%29+%3D+h
}
float g(float x, float h, float r = 1) // indefinite integral of circle segment
{
return .5f * (sqrt(1 - x * x / (r * r)) * x * r + r * r * asin(x / r) - 2 * h * x); // http://www.wolframalpha.com/input/?i=r+*+sin%28acos%28x+%2F+r%29%29+-+h
}
float area(float x0, float x1, float h, float r) // area of intersection of an infinitely tall box with left edge at x0, right edge at x1, bottom edge at h and top edge at infinity, with circle centered at the origin with radius r
{
if(x0 > x1)
std::swap(x0, x1); // this must be sorted otherwise we get negative area
float s = section(h, r);
return g(max(-s, min(s, x1)), h, r) - g(max(-s, min(s, x0)), h, r); // integrate the area
}
float area(float x0, float x1, float y0, float y1, float r) // area of the intersection of a finite box with a circle centered at the origin with radius r
{
if(y0 > y1)
std::swap(y0, y1); // this will simplify the reasoning
if(y0 < 0) {
if(y1 < 0)
return area(x0, x1, -y0, -y1, r); // the box is completely under, just flip it above and try again
else
return area(x0, x1, 0, -y0, r) + area(x0, x1, 0, y1, r); // the box is both above and below, divide it to two boxes and go again
} else {
assert(y1 >= 0); // y0 >= 0, which means that y1 >= 0 also (y1 >= y0) because of the swap at the beginning
return area(x0, x1, y0, r) - area(x0, x1, y1, r); // area of the lower box minus area of the higher box
}
}
float area(float x0, float x1, float y0, float y1, float cx, float cy, float r) // area of the intersection of a general box with a general circle
{
x0 -= cx; x1 -= cx;
y0 -= cy; y1 -= cy;
// get rid of the circle center
return area(x0, x1, y0, y1, r);
}
And some basic unit tests:
printf("%f\n", area(-10, 10, -10, 10, 0, 0, 1)); // unit circle completely inside a huge box, area of intersection is pi
printf("%f\n", area(-10, 0, -10, 10, 0, 0, 1)); // half of unit circle inside a large box, area of intersection is pi/2
printf("%f\n", area(0, 10, -10, 10, 0, 0, 1)); // half of unit circle inside a large box, area of intersection is pi/2
printf("%f\n", area(-10, 10, -10, 0, 0, 0, 1)); // half of unit circle inside a large box, area of intersection is pi/2
printf("%f\n", area(-10, 10, 0, 10, 0, 0, 1)); // half of unit circle inside a large box, area of intersection is pi/2
printf("%f\n", area(0, 1, 0, 1, 0, 0, 1)); // unit box covering one quadrant of the circle, area of intersection is pi/4
printf("%f\n", area(0, -1, 0, 1, 0, 0, 1)); // unit box covering one quadrant of the circle, area of intersection is pi/4
printf("%f\n", area(0, -1, 0, -1, 0, 0, 1)); // unit box covering one quadrant of the circle, area of intersection is pi/4
printf("%f\n", area(0, 1, 0, -1, 0, 0, 1)); // unit box covering one quadrant of the circle, area of intersection is pi/4
printf("%f\n", area(-.5f, .5f, -.5f, .5f, 0, 0, 10)); // unit box completely inside a huge circle, area of intersection is 1
printf("%f\n", area(-20, -10, -10, 10, 0, 0, 1)); // huge box completely outside a circle (left), area of intersection is 0
printf("%f\n", area(10, 20, -10, 10, 0, 0, 1)); // huge box completely outside a circle (right), area of intersection is 0
printf("%f\n", area(-10, 10, -20, -10, 0, 0, 1)); // huge box completely outside a circle (below), area of intersection is 0
printf("%f\n", area(-10, 10, 10, 20, 0, 0, 1)); // huge box completely outside a circle (above), area of intersection is 0
The output of this is:
3.141593
1.570796
1.570796
1.570796
1.570796
0.785398
0.785398
0.785398
0.785398
1.000000
-0.000000
0.000000
0.000000
0.000000
Which seems correct to me. You may want to inline the functions if you don't trust your compiler to do it for you.
This uses 6 sqrt, 4 asin, 8 div, 16 mul and 17 adds for boxes that do not intersect the x axis and a double of that (and 1 more add) for boxes that do. Note that the divisions are by radius and could be reduced to two divisions and a bunch of multiplications. If the box in question intersected the x axis but did not intersect the y axis, you could rotate everything by pi/2 and do the calculation in the original cost.
I'm using it as a reference to debug subpixel-precise antialiased circle rasterizer. It is slow as hell :), I need to calculate the area of intersection of each pixel in the bounding box of the circle with the circle to get alpha. You can sort of see that it works and no numerical artifacts seem to appear. The figure below is a plot of a bunch of circles with the radius increasing from 0.3 px to about 6 px, laid out in a spiral.
I hope its not bad form to post an answer to such an old question. I looked over the above solutions and worked out an algorithm which is similar to Daniels first answer, but a good bit tighter.
In short, assume the full area is in the rectangle, subtract off the four segments in the external half planes, then add any the areas in the four external quadrants, discarding trivial cases along the way.
pseudocde (my actual code is only ~12 lines..)
find the signed (negative out) normalized distance from the circle center
to each of the infinitely extended rectangle edge lines,
ie.
d_1=(xcenter-xleft)/r
d_2=(ycenter-ybottom)/r
etc
for convenience order 1,2,3,4 around the edge. If the rectangle is not
aligned with the cartesian coordinates this step is more complicated but
the remainder of the algorithm is the same
If ANY d_i <=- 1 return 0
if ALL d_i >= 1 return Pi r^2
this leave only one remaining fully outside case: circle center in
an external quadrant, and distance to corner greater than circle radius:
for each adjacent i,j (ie. i,j=1,2;2,3;3,4;4,1)
if d_i<=0 and d_j <= 0 and d_i^2+d_j^2 > 1 return 0
now begin with full circle area and subtract any areas in the
four external half planes
Area= Pi r^2
for each d_i>-1
a_i=arcsin( d_i ) #save a_i for next step
Area -= r^2/2 (Pi - 2 a_i - sin(2 a_i))
At this point note we have double counted areas in the four external
quadrants, so add back in:
for each adjacent i,j
if d_i < 1 and d_j < 1 and d_i^2+d_j^2 < 1
Area += r^2/4 (Pi- 2 a_i - 2 a_j -sin(2 a_i) -sin(2 a_j) + 4 sin(a_i) sin(a_j))
return Area
Incidentally, that last formula for the area of a circle contained in a plane quadrant is readily derived as the sum of a circular segment, two right triangles and a rectangle.
Enjoy.
The following is how to calculate the overlapping area between circle and rectangle where the center of circle lies outside the rectangle. Other cases can be reduced to this problem.
The area can be calculate by integrating the circle equation y = sqrt[a^2 - (x-h)^2] + k where a is radius, (h,k) is circle center, to find the area under curve. You may use computer integration where the area is divided into many small rectangle and calculating the sum of them, or just use closed form here.
And here is a C# source implementing the concept above. Note that there is a special case where the specified x lies outside the boundaries of the circle. I just use a simple workaround here (which is not producing the correct answers in all cases)
public static void RunSnippet()
{
// test code
double a,h,k,x1,x2;
a = 10;
h = 4;
k = 0;
x1 = -100;
x2 = 100;
double r1 = Integrate(x1, a, h, k);
double r2 = Integrate(x2, a, h, k);
Console.WriteLine(r2 - r1);
}
private static double Integrate(double x, double a,double h, double k)
{
double a0 = a*a - (h-x)*(h-x);
if(a0 <= 0.0){
if(k == 0.0)
return Math.PI * a * a / 4.0 * Math.Sign(x);
else
throw new Exception("outside boundaries");
}
double a1 = Math.Sqrt(a*a - (h-x)*(h-x)) * (h-x);
double area = 0.5 * Math.Atan(a1 / ((h-x)*(h-x) - a*a))*a*a - 0.5 * a1 + k * x;
return area;
}
Note: This problem is very similar to one in Google Code Jam 2008 Qualification round problem: Fly Swatter. You can click on the score links to download the source code of the solution too.
Thanks for the answers,
I forgot to mention that area estimatations were enough.
That; s why in the end, after looking at all the options, I went with monte-carlo estimation where I generate random points in the circle and test if they're in the box.
In my case this is likely more performant. (I have a grid placed over the circle and I have to measure the ratio of the circle belonging to each of the grid-cells. )
Thanks
Perhaps you can use the answer to this question, where the area of intersection between a circle and a triangle is asked. Split your rectangle into two triangles and use the algorithms described there.
Another way is to draw a line between the two intersection points, this splits your area into a polygon (3 or 4 edges) and a circular segment, for both you should be able to find libraries easier or do the calculations yourself.
Here is another solution for the problem:
public static bool IsIntersected(PointF circle, float radius, RectangleF rectangle)
{
var rectangleCenter = new PointF((rectangle.X + rectangle.Width / 2),
(rectangle.Y + rectangle.Height / 2));
var w = rectangle.Width / 2;
var h = rectangle.Height / 2;
var dx = Math.Abs(circle.X - rectangleCenter.X);
var dy = Math.Abs(circle.Y - rectangleCenter.Y);
if (dx > (radius + w) || dy > (radius + h)) return false;
var circleDistance = new PointF
{
X = Math.Abs(circle.X - rectangle.X - w),
Y = Math.Abs(circle.Y - rectangle.Y - h)
};
if (circleDistance.X <= (w))
{
return true;
}
if (circleDistance.Y <= (h))
{
return true;
}
var cornerDistanceSq = Math.Pow(circleDistance.X - w, 2) +
Math.Pow(circleDistance.Y - h, 2);
return (cornerDistanceSq <= (Math.Pow(radius, 2)));
}

Categories

Resources