Why same OpenModelica code behaves differently in two files? - graph

I'm trying to model the trajectory of projectile in modelica, but when I model air_pressure dependency on the height I get weird result, now if I simply copy only the air_pressure's code to another file, I get pretty fine output. Why's that so?
This is the original code for projectile,
class proj
//position
Real x(start = 6371000);
Real y(start = 0);
Real z(start = 0);
Real r(start = 6371000);
Real row(start = 6371000);
Real h(start = 0);
//velocity
Real v_x(start = 2000);
Real v_y(start = 0);
Real v_z(start = 0);
Real v_mag(start = sqrt(4000000));
Real v_row(start = sqrt(4000000));
//acceleration
Real a_x();
Real a_y();
Real a_z();
Real a_mag();
//total force
Real ft_x();
Real ft_y();
Real ft_z();
Real ft_mag();
//Gravitational force
Real fg_x();
Real fg_y();
Real fg_z();
Real fg_mag();
//Drag force
Real fd_x();
Real fd_y();
Real fd_z();
Real fd_mag();
Real energy();
//Fictitious force
Real ff_x();
Real ff_y();
Real ff_z();
Real ff_mag();
//gravitation variables
Real g(start = G * earth_mass / earth_radius ^ 2);
//Drag variables
Real air_density(start = surface_density);
Real air_pressure(start = surface_pressure);
//_________________________________________________________________________
//Earth parameters
parameter Real earth_radius = 6371000;
parameter Real earth_mass = 5.972 * 10 ^ 24;
parameter Real earth_rot_vel = 7.292115 * 10 ^ (-5);
//Missile parameters
parameter Real missile_effective_area = 0.785398;
parameter Real missile_mass = 200;
parameter Real Cd = 0.02;
//Air parameters
parameter Real temp_lapse_rate = 0.0065;
parameter Real air_molar_mass = 28.97 / 1000;
parameter Real surface_temp = 303.15;
parameter Real surface_pressure = 101325;
parameter Real surface_density = 1.1644;
//constants
parameter Real pi = 3.14159265358979;
parameter Real G = 6.67384 * 10 ^ (-11);
parameter Real R = 8.3144621;
//__________________________________________________________________________
equation
//position
der(x) = if h < 0 then 0 else v_x;
der(y) = if h < 0 then 0 else v_y;
der(z) = if h < 0 then 0 else v_z;
r = sqrt(x ^ 2 + y ^ 2 + z ^ 2);
row = sqrt(x ^ 2 + y ^ 2);
h = r - earth_radius;
//velocity
der(v_x) = a_x;
der(v_y) = a_y;
der(v_z) = a_z;
v_mag = sqrt(v_x ^ 2 + v_y ^ 2 + v_z ^ 2);
v_row = sqrt(v_x ^ 2 + v_y ^ 2);
//acceleration
a_x = ft_x / missile_mass;
a_y = ft_y / missile_mass;
a_z = ft_z / missile_mass;
a_mag = ft_mag / missile_mass;
//total force
ft_x = fg_x + fd_x + ff_x;
ft_y = fg_y + fd_y + ff_y;
ft_z = fg_z + fd_z + ff_z;
ft_mag = sqrt(ft_x ^ 2 + ft_y ^ 2 + ft_z ^ 2);
//Gravitational force
fg_x = -1 * fg_mag * row / r * x / r;
fg_y = -1 * fg_mag * row / r * y / r;
fg_z = -1 * fg_mag * z / r;
fg_mag = G * earth_mass * missile_mass / r ^ 2;
//Drag force
fd_x = if v_mag > 0 then -1 * fd_mag * v_row / v_mag * v_x / v_mag else 0;
fd_y = if v_mag > 0 then -1 * fd_mag * v_row / v_mag * v_y / v_mag else 0;
fd_z = if v_mag > 0 then -1 * fd_mag * v_z / v_mag else 0;
fd_mag = 0.5 * air_density * v_mag ^ 2 * Cd * missile_effective_area;
//Fictitious force
ff_x = missile_mass * earth_rot_vel * (2 * v_y + earth_rot_vel * x);
ff_y = missile_mass * earth_rot_vel * (-2 * v_x + earth_rot_vel * y);
ff_z = 0;
ff_mag = sqrt(ff_x ^ 2 + ff_y ^ 2 + ff_z ^ 2);
energy = 0.5 * missile_mass * v_mag * v_mag - G * earth_mass * missile_mass / r;
//Gravitation variables
g = fg_mag / missile_mass;
//Drag variables
air_density = air_pressure * air_molar_mass / (R * surface_temp);
air_pressure = if h > 46600 then 0 else surface_pressure * (1 - temp_lapse_rate * (r - earth_radius) / surface_temp) ^ (g * air_molar_mass / (R * temp_lapse_rate));
end proj;
This the extracted air_pressure's code,, that works fine alone but behaves weirdly with whole projectile code,
class check
Real g;
Real h(start = 0);
Real pressure;
//Earth parameters
parameter Real earth_radius = 6371000;
parameter Real earth_mass = 5.972 * 10 ^ 24;
//Air parameters
parameter Real temp_lapse_rate = 0.0065;
parameter Real air_molar_mass = 28.97 / 1000;
parameter Real surface_temp = 303.15;
parameter Real surface_pressure = 101325;
//constants
parameter Real pi = 3.14159265358979;
parameter Real G = 6.67384 * 10 ^ (-11);
parameter Real R = 8.3144621;
equation
g = G * earth_mass / (earth_radius + h) ^ 2;
h = time;
pressure = if h > 46600 then 0 else surface_pressure * (1 - temp_lapse_rate * h / surface_temp) ^ (g * air_molar_mass / (R * temp_lapse_rate));
end check;
This is the air_pressure graph vs time from the class proj
This the air_pressure graph vs time(=height) from class check containing only air_pressure's code

You should check the value of h in your system. I suspect something strange is happening with h.

Its not clear what x refers to. From the start value, x seems to refer to the distance from the center of the earth and if this is the case then what is r? I am assuming x,y & z refer to the position of the projectile in 3D space w.r.t a point of reference on the ground (surface of the earth) and if this correct, then I would suggest defining x, y in terms of latitude and longitude and z as the height from the surface of the earth.
This should fix the ambiguity in h.

Related

Intersection between two vectors

Is there efficient way to find intersection between two vectors?
Ray is infinite so one way is to turn one vector to ray, find intersection between that ray and other vector. Then if there is intersection, find distance between intersection and first vector.
If it is 0 then there is intersection between two vectors, if i don't miss something.
But is there better way in three.js?
That is more a math question than a three.js one, as you mentioned you could use existing methods on the Ray object and work your way out from there, but I doubt this would be optimal as you are concerned about performance.
The right approach is probably to determine the shortest distance between two segments and if this distance is zero then they intersect. You can find a similar discussion on that thread: The Algorithm to Find the Point of Intersection of Two 3D Line Segment
And here I found a C algorithm that does exactly that, it should translate to Javascript without much efforts:
typedef struct {
double x,y,z;
} XYZ;
/*
Calculate the line segment PaPb that is the shortest route between
two lines P1P2 and P3P4. Calculate also the values of mua and mub where
Pa = P1 + mua (P2 - P1)
Pb = P3 + mub (P4 - P3)
Return FALSE if no solution exists.
*/
int LineLineIntersect(
XYZ p1,XYZ p2,XYZ p3,XYZ p4,XYZ *pa,XYZ *pb,
double *mua, double *mub)
{
XYZ p13,p43,p21;
double d1343,d4321,d1321,d4343,d2121;
double numer,denom;
p13.x = p1.x - p3.x;
p13.y = p1.y - p3.y;
p13.z = p1.z - p3.z;
p43.x = p4.x - p3.x;
p43.y = p4.y - p3.y;
p43.z = p4.z - p3.z;
if (ABS(p43.x) < EPS && ABS(p43.y) < EPS && ABS(p43.z) < EPS)
return(FALSE);
p21.x = p2.x - p1.x;
p21.y = p2.y - p1.y;
p21.z = p2.z - p1.z;
if (ABS(p21.x) < EPS && ABS(p21.y) < EPS && ABS(p21.z) < EPS)
return(FALSE);
d1343 = p13.x * p43.x + p13.y * p43.y + p13.z * p43.z;
d4321 = p43.x * p21.x + p43.y * p21.y + p43.z * p21.z;
d1321 = p13.x * p21.x + p13.y * p21.y + p13.z * p21.z;
d4343 = p43.x * p43.x + p43.y * p43.y + p43.z * p43.z;
d2121 = p21.x * p21.x + p21.y * p21.y + p21.z * p21.z;
denom = d2121 * d4343 - d4321 * d4321;
if (ABS(denom) < EPS)
return(FALSE);
numer = d1343 * d4321 - d1321 * d4343;
*mua = numer / denom;
*mub = (d1343 + d4321 * (*mua)) / d4343;
pa->x = p1.x + *mua * p21.x;
pa->y = p1.y + *mua * p21.y;
pa->z = p1.z + *mua * p21.z;
pb->x = p3.x + *mub * p43.x;
pb->y = p3.y + *mub * p43.y;
pb->z = p3.z + *mub * p43.z;
return(TRUE);
}

How to make an animated wave in threejs

I am trying to make an animated 3D wave with Three.js and Points. It is kind of working. It is starting slow and then the applitude is increasing. But after some time it gets too high and unsteady.
This is how it should be looking. However after some time it is loosing it's shape. The problem is the decreasing period of the sine and increasing amplitude. But I am failing to fix it.
Here is some code.
Creating of the points mesh.
this.particleGeometry = new Geometry()
for (let ix = 0; ix < this.WIDTH; ix++) {
for (let iz = 0; iz < this.HEIGHT; iz++) {
let vert = new Vector3()
vert.x = ix * this.SEPERATION - ((this.WIDTH * this.SEPERATION) / 2)
vert.y = (Math.cos((ix / this.WIDTH) * Math.PI * 6) + Math.sin((iz / this.HEIGHT) * Math.PI * 6))
vert.z = iz * this.SEPERATION - ((this.HEIGHT * this.SEPERATION) / 2)
this.particleGeometry.vertices.push(vert)
}
}
this.particleCloud = new Points(this.particleGeometry, this.material)
this.scene.add(this.particleCloud)
The initial generation is pretty good. But the updating is buggy.
animate() code:
render () {
let index = 0
let time = Date.now() * 0.00005
let h = (360 * (1.0 + time) % 360) / 360
this.theta += 0.0008
this.material.color.setHSL(h, 0.5, 0.5)
for (let ix = 0; ix < this.WIDTH; ix++) {
for (let iz = 0; iz < this.HEIGHT; iz++) {
this.particleCloud.geometry.vertices[index].y = (Math.cos((ix * this.theta / this.WIDTH) * Math.PI * 6) + Math.sin((iz * this.theta / this.HEIGHT) * Math.PI * 6))
index++
}
}
this.particleCloud.geometry.verticesNeedUpdate = true
this.updateGuiSettings()
this.renderer.render(this.scene, this.camera)
},
this.theta starts at 0 and then slowly increasing.
Okay, got it working with (Math.cos((ix / this.WIDTH * PI * 8 + this.theta)) + Math.sin((iz / this.HEIGHT * PI * 8 + this.theta)))
Now it is steady. However will tweak it maybe more.

Why we use CORDIC gain?

I'm studying the cordic. And I found the cordic gain. K=0.607XXX.
From CORDIC, K_i = cos(tan^-1(2^i)).
As I know the K is approched 0.607xxx.when I is going to infinity
this value come up with from all K multiplying.
I understand the reason of exist each k. But I am curioused Where does it used ? Why we use that value K=0.607xx?
The scale factor for the rotation mode of the circular variant of CORDIC can easily be established from first principles. The idea behind CORDIC is to take a point on the unit circle and rotate it, in steps, through the angle u whose sine and cosine we want to determine.
To that end we define a set of incremental angles a0, ..., an-1, such that ak = atan(0.5k). We sum these incremental angles appropriately into a partial sum of angles sk, such than sn ~= u. Let yk = cos(sk) and xk = sin(sk). If in a given step k we rotate by ak, we have
yk+1 = cos (sk+1) = cos (sk + ak)
xk+1 = sin (sk+1) = sin (sk + ak)
we can compute xk+1 and yk+1 from xk and yk as follows:
yk+1 = yk * cos (ak) - xk * sin (ak)
xk+1 = xk * cos (ak) + yk * sin (ak)
Considering that we may both add and subtract ak, and that tan(ak) = sin(ak)/cos(ak), we get:
yk+1 = cos (ak) * (yk ∓ xk * tan(ak)) = cos (sk+1)
xk+1 = cos (ak) * (xk ± yk * tan(ak)) = sin (sk+1)
To simplify this computation, we can leave out the multiplication with cos(ak) in every step, which gives us our CORDIC iteration scheme:
yk+1 = y ∓ xk * tan(ak)
xk+1 = x ± yk * tan(ak)
Because of our choice of ak, the multiplications with tan(ak) turn into simple right shifts if we compute in fixed-point arithmetic. Because we left off the factors cos(ak), we wind up with
yn ~= cos(u) * (1 / (cos (a0) * cos (a1) * ... * cos (an))
xn ~= sin(u) * (1 / (cos (a0) * cos (a1) * ... * cos (an))
The factor f = cos (a0) * cos (a1) * ... * cos (an) is 0.607..., as already noted. We incorporate it into the computation by setting the starting values
y0 = f * cos(0) = f
x0 = f * sin(0) = 0
Here is C code that shows the entire computation in action, using 16-bit fixed-point arithmetic. Input angles are scaled such that 360 degrees correspond to 216, while sine and cosine outputs are scaled such that 1 corresponds to 215.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* round (atand (0.5**i) * 65536/360) */
static const short a[15] =
{
0x2000, 0x12e4, 0x09fb, 0x0511,
0x028b, 0x0146, 0x00a3, 0x0051,
0x0029, 0x0014, 0x000a, 0x0005,
0x0003, 0x0001, 0x0001
};
#define swap(a,b){a=a^b; b=b^a; a=a^b;}
void cordic (unsigned short u, short *s, short *c)
{
short x, y, oldx, oldy, q;
int i;
x = 0;
y = 0x4dba; /* 0.60725 */
oldx = x;
oldy = y;
q = u >> 14; /* quadrant */
u = u & 0x3fff; /* reduced angle */
u = -(short)u;
i = 0;
do {
if ((short)u < 0) {
x = x + oldy;
y = y - oldx;
u = u + a[i];
} else {
x = x - oldy;
y = y + oldx;
u = u - a[i];
}
oldx = x;
oldy = y;
i++;
/* right shift of signed negative number implementation defined in C */
oldx = (oldx < 0) ? (-((-oldx) >> i)) : (oldx >> i);
oldy = (oldy < 0) ? (-((-oldy) >> i)) : (oldy >> i);
} while (i < 15);
for (i = 0; i < q; i++) {
swap (x, y);
y = -y;
}
*s = x;
*c = y;
}
int main (void)
{
float angle;
unsigned short u;
short s, c;
printf ("angle in degrees [0,360): ");
scanf ("%f", &angle);
u = (unsigned short)(angle * 65536.0f / 360.0f + 0.5f);
cordic (u, &s, &c);
printf ("sin = % f (ref: % f) cos = % f (ref: % f)\n",
s/32768.0f, sinf(angle/360*2*3.14159265f),
c/32768.0f, cosf(angle/360*2*3.14159265f));
return EXIT_SUCCESS;
}

Intersection between a line and a sphere

I'm trying to find the point of intersection between a sphere and a line but honestly, I don't have any idea of how to do so.
Could anyone help me on this one ?
Express the line as an function of t:
{ x(t) = x0*(1-t) + t*x1
{ y(t) = y0*(1-t) + t*y1
{ z(t) = z0*(1-t) + t*z1
When t = 0, it will be at one end-point (x0,y0,z0). When t = 1, it will be at the other end-point (x1,y1,z1).
Write a formula for the distance to the center of the sphere (squared) in t (where (xc,yc,zc) is the center of the sphere):
f(t) = (x(t) - xc)^2 + (y(t) - yc)^2 + (z(t) - zc)^2
Solve for t when f(t) equals R^2 (R being the radius of the sphere):
(x(t) - xc)^2 + (y(t) - yc)^2 + (z(t) - zc)^2 = R^2
A = (x0-xc)^2 + (y0-yc)^2 + (z0-zc)^2 - R^2
B = (x1-xc)^2 + (y1-yc)^2 + (z1-zc)^2 - A - C - R^2
C = (x0-x1)^2 + (y0-y1)^2 + (z0-z1)^2
Solve A + B*t + C*t^2 = 0 for t. This is a normal quadratic equation.
You can get up to two solutions. Any solution where t lies between 0 and 1 are valid.
If you got a valid solution for t, plug it in the first equations to get the point of intersection.
I assumed you meant a line segment (two end-points). If you instead want a full line (infinite length), then you could pick two points along the line (not too close), and use them. Also let t be any real value, not just between 0 and 1.
Edit: I fixed the formula for B. I was mixing up the signs. Thanks M Katz, for mentioning that it didn't work.
I believe there is an inaccuracy in the solution by Markus Jarderot. Not sure what the problem is, but I'm pretty sure I translated it faithfully to code, and when I tried to find the intersection of a line segment known to cross into a sphere, I got a negative discriminant (no solutions).
I found this: http://www.codeproject.com/Articles/19799/Simple-Ray-Tracing-in-C-Part-II-Triangles-Intersec, which gives a similar but slightly different derivation.
I turned that into the following C# code and it works for me:
public static Point3D[] FindLineSphereIntersections( Point3D linePoint0, Point3D linePoint1, Point3D circleCenter, double circleRadius )
{
// http://www.codeproject.com/Articles/19799/Simple-Ray-Tracing-in-C-Part-II-Triangles-Intersec
double cx = circleCenter.X;
double cy = circleCenter.Y;
double cz = circleCenter.Z;
double px = linePoint0.X;
double py = linePoint0.Y;
double pz = linePoint0.Z;
double vx = linePoint1.X - px;
double vy = linePoint1.Y - py;
double vz = linePoint1.Z - pz;
double A = vx * vx + vy * vy + vz * vz;
double B = 2.0 * (px * vx + py * vy + pz * vz - vx * cx - vy * cy - vz * cz);
double C = px * px - 2 * px * cx + cx * cx + py * py - 2 * py * cy + cy * cy +
pz * pz - 2 * pz * cz + cz * cz - circleRadius * circleRadius;
// discriminant
double D = B * B - 4 * A * C;
if ( D < 0 )
{
return new Point3D[ 0 ];
}
double t1 = ( -B - Math.Sqrt ( D ) ) / ( 2.0 * A );
Point3D solution1 = new Point3D( linePoint0.X * ( 1 - t1 ) + t1 * linePoint1.X,
linePoint0.Y * ( 1 - t1 ) + t1 * linePoint1.Y,
linePoint0.Z * ( 1 - t1 ) + t1 * linePoint1.Z );
if ( D == 0 )
{
return new Point3D[] { solution1 };
}
double t2 = ( -B + Math.Sqrt( D ) ) / ( 2.0 * A );
Point3D solution2 = new Point3D( linePoint0.X * ( 1 - t2 ) + t2 * linePoint1.X,
linePoint0.Y * ( 1 - t2 ) + t2 * linePoint1.Y,
linePoint0.Z * ( 1 - t2 ) + t2 * linePoint1.Z );
// prefer a solution that's on the line segment itself
if ( Math.Abs( t1 - 0.5 ) < Math.Abs( t2 - 0.5 ) )
{
return new Point3D[] { solution1, solution2 };
}
return new Point3D[] { solution2, solution1 };
}
Don't have enough reputation to comment on M Katz answer, but his answer assumes that the line can go on infinitely in each direction. If you need only the line SEGMENT's intersection points, you need t1 and t2 to be less than one (based on the definition of a parameterized equation). Please see my answer in C# below:
public static Point3D[] FindLineSphereIntersections(Point3D linePoint0, Point3D linePoint1, Point3D circleCenter, double circleRadius)
{
double cx = circleCenter.X;
double cy = circleCenter.Y;
double cz = circleCenter.Z;
double px = linePoint0.X;
double py = linePoint0.Y;
double pz = linePoint0.Z;
double vx = linePoint1.X - px;
double vy = linePoint1.Y - py;
double vz = linePoint1.Z - pz;
double A = vx * vx + vy * vy + vz * vz;
double B = 2.0 * (px * vx + py * vy + pz * vz - vx * cx - vy * cy - vz * cz);
double C = px * px - 2 * px * cx + cx * cx + py * py - 2 * py * cy + cy * cy +
pz * pz - 2 * pz * cz + cz * cz - circleRadius * circleRadius;
// discriminant
double D = B * B - 4 * A * C;
double t1 = (-B - Math.Sqrt(D)) / (2.0 * A);
Point3D solution1 = new Point3D(linePoint0.X * (1 - t1) + t1 * linePoint1.X,
linePoint0.Y * (1 - t1) + t1 * linePoint1.Y,
linePoint0.Z * (1 - t1) + t1 * linePoint1.Z);
double t2 = (-B + Math.Sqrt(D)) / (2.0 * A);
Point3D solution2 = new Point3D(linePoint0.X * (1 - t2) + t2 * linePoint1.X,
linePoint0.Y * (1 - t2) + t2 * linePoint1.Y,
linePoint0.Z * (1 - t2) + t2 * linePoint1.Z);
if (D < 0 || t1 > 1 || t2 >1)
{
return new Point3D[0];
}
else if (D == 0)
{
return new [] { solution1 };
}
else
{
return new [] { solution1, solution2 };
}
}
You may use Wolfram Alpha to solve it in the coordinate system where the sphere is centered.
In this system, the equations are:
Sphere:
x^2 + y^2 + z^2 = r^2
Straight line:
x = x0 + Cos[x1] t
y = y0 + Cos[y1] t
z = z0 + Cos[z1] t
Then we ask Wolfram Alpha to solve for t: (Try it!)
and after that you may change again to your original coordinate system (a simple translation)
Find the solution of the two equations in (x,y,z) describing the line and the sphere.
There may be 0, 1 or 2 solutions.
0 implies they don't intersect
1 implies the line is a tangent to the sphere
2 implies the line passes through the sphere.
Here's a more concise formulation using inner products, less than 100 LOCs, and no external links. Also, the question was asked for a line, not a line segment.
Assume that the sphere is centered at C with radius r. The line is described by P+l*D where D*D=1. P and C are points, D is a vector, l is a number.
We set PC = P-C, pd = PC*D and s = pd*pd - PC*PC + r*r. If s < 0 there are no solutions, if s == 0 there is just one, otherwise there are two. For the solutions we set l = -pd +- sqrt(s), then plug into P+l*D.
Or you can just find the formula of both:
line: (x-x0)/a=(y-y0)/b=(z-z0)/c, which are symmetric equations of the line segment between the points you can find.
sphere: (x-xc)^2+(y-yc)^2+(z-zc)^2 = R^2.
Use the symmetric equation to find relationship between x and y, and x and z.
Then plug in y and z in terms of x into the equation of the sphere.
Then find x, and then you can find y and z.
If x gives you an imaginary result, that means the line and the sphere doesn't intersect.
I don't have the reputation to comment on Ashavsky's solution, but the check at the end needed a bit more tweaking.
if (D < 0)
return new Point3D[0];
else if ((t1 > 1 || t1 < 0) && (t2 > 1 || t2 < 0))
return new Point3D[0];
else if (!(t1 > 1 || t1 < 0) && (t2 > 1 || t2 < 0))
return new [] { solution1 };
else if ((t1 > 1 || t1 < 0) && !(t2 > 1 || t2 < 0))
return new [] { solution2 };
else if (D == 0)
return new [] { solution1 };
else
return new [] { solution1, solution2 };

Area of Intersection between Two Circles

Given two circles:
C1 at (x1, y1) with radius1
C2 at (x2, y2) with radius2
How do you calculate the area of their intersection? All standard math functions (sin, cos, etc.) are available, of course.
Okay, using the Wolfram link and Misnomer's cue to look at equation 14, I have derived the following Java solution using the variables I listed and the distance between the centers (which can trivially be derived from them):
double r = radius1;
double R = radius2;
double d = distance;
if(R < r){
// swap
r = radius2;
R = radius1;
}
double part1 = r*r*Math.acos((d*d + r*r - R*R)/(2*d*r));
double part2 = R*R*Math.acos((d*d + R*R - r*r)/(2*d*R));
double part3 = 0.5*Math.sqrt((-d+r+R)*(d+r-R)*(d-r+R)*(d+r+R));
double intersectionArea = part1 + part2 - part3;
Here is a JavaScript function that does exactly what Chris was after:
function areaOfIntersection(x0, y0, r0, x1, y1, r1)
{
var rr0 = r0 * r0;
var rr1 = r1 * r1;
var d = Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
var phi = (Math.acos((rr0 + (d * d) - rr1) / (2 * r0 * d))) * 2;
var theta = (Math.acos((rr1 + (d * d) - rr0) / (2 * r1 * d))) * 2;
var area1 = 0.5 * theta * rr1 - 0.5 * rr1 * Math.sin(theta);
var area2 = 0.5 * phi * rr0 - 0.5 * rr0 * Math.sin(phi);
return area1 + area2;
}
However, this method will return NaN if one circle is completely inside the other, or they are not touching at all. A slightly different version that doesn't fail in these conditions is as follows:
function areaOfIntersection(x0, y0, r0, x1, y1, r1)
{
var rr0 = r0 * r0;
var rr1 = r1 * r1;
var d = Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
// Circles do not overlap
if (d > r1 + r0)
{
return 0;
}
// Circle1 is completely inside circle0
else if (d <= Math.abs(r0 - r1) && r0 >= r1)
{
// Return area of circle1
return Math.PI * rr1;
}
// Circle0 is completely inside circle1
else if (d <= Math.abs(r0 - r1) && r0 < r1)
{
// Return area of circle0
return Math.PI * rr0;
}
// Circles partially overlap
else
{
var phi = (Math.acos((rr0 + (d * d) - rr1) / (2 * r0 * d))) * 2;
var theta = (Math.acos((rr1 + (d * d) - rr0) / (2 * r1 * d))) * 2;
var area1 = 0.5 * theta * rr1 - 0.5 * rr1 * Math.sin(theta);
var area2 = 0.5 * phi * rr0 - 0.5 * rr0 * Math.sin(phi);
// Return area of intersection
return area1 + area2;
}
}
I wrote this function by reading the information found at the Math Forum. I found this clearer than the Wolfram MathWorld explanation.
You might want to check out this analytical solution and apply the formula with your input values.
Another Formula is given here for when the radii are equal:
Area = r^2*(q - sin(q)) where q = 2*acos(c/2r),
where c = distance between centers and r is the common radius.
Here is an example in Python.
"""Intersection area of two circles"""
import math
from dataclasses import dataclass
from typing import Tuple
#dataclass
class Circle:
x: float
y: float
r: float
#property
def coord(self):
return self.x, self.y
def find_intersection(c1: Circle, c2: Circle) -> float:
"""Finds intersection area of two circles.
Returns intersection area of two circles otherwise 0
"""
d = math.dist(c1.coord, c2.coord)
rad1sqr = c1.r ** 2
rad2sqr = c2.r ** 2
if d == 0:
# the circle centers are the same
return math.pi * min(c1.r, c2.r) ** 2
angle1 = (rad1sqr + d ** 2 - rad2sqr) / (2 * c1.r * d)
angle2 = (rad2sqr + d ** 2 - rad1sqr) / (2 * c2.r * d)
# check if the circles are overlapping
if (-1 <= angle1 < 1) or (-1 <= angle2 < 1):
theta1 = math.acos(angle1) * 2
theta2 = math.acos(angle2) * 2
area1 = (0.5 * theta2 * rad2sqr) - (0.5 * rad2sqr * math.sin(theta2))
area2 = (0.5 * theta1 * rad1sqr) - (0.5 * rad1sqr * math.sin(theta1))
return area1 + area2
elif angle1 < -1 or angle2 < -1:
# Smaller circle is completely inside the largest circle.
# Intersection area will be area of smaller circle
# return area(c1_r), area(c2_r)
return math.pi * min(c1.r, c2.r) ** 2
return 0
if __name__ == "__main__":
#dataclass
class Test:
data: Tuple[Circle, Circle]
expected: float
tests = [
Test((Circle(2, 4, 2), Circle(3, 9, 3)), 0),
Test((Circle(0, 0, 2), Circle(-1, 1, 2)), 7.0297),
Test((Circle(1, 3, 2), Circle(1, 3, 2.19)), 12.5664),
Test((Circle(0, 0, 2), Circle(-1, 0, 2)), 8.6084),
Test((Circle(4, 3, 2), Circle(2.5, 3.5, 1.4)), 3.7536),
Test((Circle(3, 3, 3), Circle(2, 2, 1)), 3.1416)
]
for test in tests:
result = find_intersection(*test.data)
assert math.isclose(result, test.expected, rel_tol=1e-4), f"{test=}, {result=}"
print("PASSED!!!")
Here here i was making character generation tool, based on circle intersections... you may find it useful.
with dynamically provided circles:
C: {
C1: {id: 'C1',x:105,y:357,r:100,color:'red'},
C2: {id: 'C2',x:137,y:281,r:50, color:'lime'},
C3: {id: 'C3',x:212,y:270,r:75, color:'#00BCD4'}
},
Check FULL fiddle...
FIDDLE

Resources