Related
I'm attempting to convert from state vectors (position and speed) into Kepler elements, however I'm running into problems where a negative velocity or position will give me wrong results when trying to calculate true anomaly.
Here are the different ways I'm trying to calculate the True Anomaly:
/// <summary>
/// https://en.wikipedia.org/wiki/True_anomaly#From_state_vectors
/// </summary>
public static double TrueAnomaly(Vector4 eccentVector, Vector4 position, Vector4 velocity)
{
var dotEccPos = Vector4.Dot(eccentVector, position);
var talen = eccentVector.Length() * position.Length();
talen = dotEccPos / talen;
talen = GMath.Clamp(talen, -1, 1);
var trueAnomoly = Math.Acos(talen);
if (Vector4.Dot(position, velocity) < 0)
trueAnomoly = Math.PI * 2 - trueAnomoly;
return trueAnomoly;
}
//sgp = standard gravitational parameter
public static double TrueAnomaly(double sgp, Vector4 position, Vector4 velocity)
{
var H = Vector4.Cross(position, velocity).Length();
var R = position.Length();
var q = Vector4.Dot(position, velocity); // dot product of r*v
var TAx = H * H / (R * sgp) - 1;
var TAy = H * q / (R * sgp);
var TA = Math.Atan2(TAy, TAx);
return TA;
}
public static double TrueAnomalyFromEccentricAnomaly(double eccentricity, double eccentricAnomaly)
{
var x = Math.Sqrt(1 - Math.Pow(eccentricity, 2)) * Math.Sin(eccentricAnomaly);
var y = Math.Cos(eccentricAnomaly) - eccentricity;
return Math.Atan2(x, y);
}
public static double TrueAnomalyFromEccentricAnomaly2(double eccentricity, double eccentricAnomaly)
{
var x = Math.Cos(eccentricAnomaly) - eccentricity;
var y = 1 - eccentricity * Math.Cos(eccentricAnomaly);
return Math.Acos(x / y);
}
Edit: another way of doing it which Spectre pointed out:
public static double TrueAnomaly(Vector4 position, double loP)
{
return Math.Atan2(position.Y, position.X) - loP;
}
Positions are all relative to the parent body.
These functions all agree if position.x, position.y and velocity.y are all positive.
How do I fix these so that I get a consistent results when position and velocity are negitive?
Just to clarify: My angles appear to be sort of correct, just pointing in the wrong quadrant depending on the position and or velocity vectors.
Yeah so I was wrong, the above all do return the correct values after all.
So I found an edge case where most of the above calculations fail.
Given position and velocity:
pos = new Vector4() { X = -0.208994076275941, Y = 0.955838328099748 };
vel = new Vector4() { X = -2.1678187689294E-07, Y = -7.93096769486992E-08 };
I get some odd results, ie ~ -31.1 degrees, when I think it should return ` 31.1 (non negative). one of them returns ~ 328.8.
However testing with this position and velocity the results apear to be ok:
pos = new Vector4() { X = -0.25, Y = 0.25 };
vel = new Vector4() { X = Distance.KmToAU(-25), Y = Distance.KmToAU(-25) };
See my answer for extra code on how I'm testing and the math I'm using for some of the other variables.
I'm going around in circles on this one. this is a result of a bug in my existing code that shows up under some conditions but not others.
I guess the real question now is WHY am I getting different results with position/velocity above that don't match to my expectations or each other?
Assuming 2D case... I am doing this differently:
compute radius of semi axises and rotation
so you need to remember whole orbit and find 2 most distant points on it that is major axis a. The minor axis b usually is 90 deg from major axis but to be sure just fins 2 perpendicularly most distant points on your orbit to major axis. So now you got both semi axises. The initial rotation is computed from the major axis by atan2.
compute true anomaly E
so if center is x0,y0 (intersection of a,b or center point of both) initial rotation is ang0 (angle of a) and your point on orbit is x,y then:
E = atan2(y-y0,x-x0) - ang0
However in order to match Newton/D'Alembert physics to Kepler orbital parameters you need to boost the integration precision like I did here:
Is it possible to make realistic n-body solar system simulation in matter of size and mass?
see the [Edit3] Improving Newton D'ALembert integration precision even more in there.
For more info and equations see:
Solving Kepler's equation
[Edit1] so you want to compute V I see it like this:
As you got your coordinates relative to parent you can assume they are already in focal point centered so no need for x0,y0 anymore. Of coarse if you want high precision and have more than 2 bodies (focal mass + object + proximity object(s) like moons) then the parent mass will no longer be in focal point of orbit but close to it ... and to remedy you need to use real focal point position so x0,y0 again... So how to do it:
compute center point (cx,cy) and a,b semi axises
so its the same as in previous text.
compute focal point (x0,y0) in orbit axis aligned coordinates
simple:
x0 = cx + sqrt( a^2 + b^2 );
y0 = cy;
initial angle ang0 of a
let xa,ya be the intersection of orbit and major axis a on the side with bigger speeds (near parent object focus). Then:
ang0 = atan2( ya-cy , xa-cx );
and finally the V fore any of yours x,y
V = atan2( y-y0 , x-x0 ) - ang0;
Ok so on further testing it appears my original calcs do all return the correct values, however when I was looking at the outputs I was not taking the LoP into account and basically not recognizing that 180 is essentially the same angle as -180.
(I was also looking at the output in radians and just didn't see what should have been obvious)
Long story short, I have a bug I thought was in this area of the code and got lost in the weeds.
Seems I was wrong above. see OP for edge case.
Here's some code I used to test these,
I used variations of the following inputs:
pos = new Vector4() { X = 0.25, Y = 0.25 };
vel = new Vector4() { X = Distance.KmToAU(-25), Y = Distance.KmToAU(25) };
And tested them with the following
double parentMass = 1.989e30;
double objMass = 2.2e+15;
double sgp = GameConstants.Science.GravitationalConstant * (parentMass + objMass) / 3.347928976e33;
Vector4 ev = OrbitMath.EccentricityVector(sgp, pos, vel);
double e = ev.Length();
double specificOrbitalEnergy = Math.Pow(vel.Length(), 2) * 0.5 - sgp / pos.Length();
double a = -sgp / (2 * specificOrbitalEnergy);
double ae = e * a;
double aop = Math.Atan2(ev.Y, ev.X);
double eccentricAnomaly = OrbitMath.GetEccentricAnomalyFromStateVectors(pos, a, ae, aop);
double aopD = Angle.ToDegrees(aop);
double directAngle = Math.Atan2(pos.Y, pos.X);
var θ1 = OrbitMath.TrueAnomaly(sgp, pos, vel);
var θ2 = OrbitMath.TrueAnomaly(ev, pos, vel);
var θ3 = OrbitMath.TrueAnomalyFromEccentricAnomaly(e, eccentricAnomaly);
var θ4 = OrbitMath.TrueAnomalyFromEccentricAnomaly2(e, eccentricAnomaly);
var θ5 = OrbitMath.TrueAnomaly(pos, aop);
double angleΔ = 0.0000001; //this is the "acceptable" amount of error, really only the TrueAnomalyFromEccentricAnomaly() calcs needed this.
Assert.AreEqual(0, Angle.DifferenceBetweenRadians(directAngle, aop - θ1), angleΔ);
Assert.AreEqual(0, Angle.DifferenceBetweenRadians(directAngle, aop - θ2), angleΔ);
Assert.AreEqual(0, Angle.DifferenceBetweenRadians(directAngle, aop - θ3), angleΔ);
Assert.AreEqual(0, Angle.DifferenceBetweenRadians(directAngle, aop - θ4), angleΔ);
Assert.AreEqual(0, Angle.DifferenceBetweenRadians(directAngle, aop - θ5), angleΔ);
and the following to compare the angles:
public static double DifferenceBetweenRadians(double a1, double a2)
{
return Math.PI - Math.Abs(Math.Abs(a1 - a2) - Math.PI);
}
And eccentricity Vector found thus:
public static Vector4 EccentricityVector(double sgp, Vector4 position, Vector4 velocity)
{
Vector4 angularMomentum = Vector4.Cross(position, velocity);
Vector4 foo1 = Vector4.Cross(velocity, angularMomentum) / sgp;
var foo2 = position / position.Length();
return foo1 - foo2;
}
And EccentricAnomaly:
public static double GetEccentricAnomalyFromStateVectors(Vector4 position, double a, double linierEccentricity, double aop)
{
var x = (position.X * Math.Cos(-aop)) - (position.Y * Math.Sin(-aop));
x = linierEccentricity + x;
double foo = GMath.Clamp(x / a, -1, 1); //because sometimes we were getting a floating point error that resulted in numbers infinatly smaller than -1
return Math.Acos(foo);
}
Thanks to Futurogogist and Spektre for their help.
I am assuming you are working in two dimensions?
Two dimensional vectors of position p and velocity v. The constant K is the the product of the gravitational constant and the mass of the gravity generating body. Calculate the eccentricity vector
eccVector = (dot(v, v)*p - dot(v, p)*v) / K - p / sqrt(dot(p, p));
eccentricity = sqrt(dot(eccVector, eccVector));
eccVector = eccVector / eccentricity;
b = { - eccVector.y, eccVector.x}; //unit vector perpendicular to eccVector
r = sqrt(dot(p, p));
cos_TA = dot(p, eccVector) / r; \\ cosine of true anomaly
sin_TA = dot(p, b) / r; \\ sine of true anomaly
if (sin_TA >= 0) {
trueAnomaly = arccos(cos_TA);
}
else if (sin_TA < 0){
trueAnomaly = 2*pi - arccos(cos_TA);
}
I recently made an application with C# and OpenGL using OpenTK. I've integrated a frustum culling system in order to improve performance, but for some reasons, objects aren't culled correctly. What I mean is that instead of showing all visibles objects nicely, it just cull random objects and when I rotate the camera, some objects appears and disappears. I know it's normal but not when I should see them. The actual frustum culling code is a C# port of my working C++/DirectXMath code used in something else.
Here's how I create the six frustum planes :
// Create a new view-projection matrices.
var vp = viewMatrix * projMatrix;
// Left plane.
frustumPlanes[0] = new Vector4
{
X = vp.M14 + vp.M11,
Y = vp.M24 + vp.M21,
Z = vp.M34 + vp.M31,
W = vp.M44 + vp.M41
};
// Right plane.
frustumPlanes[1] = new Vector4
{
X = vp.M14 - vp.M11,
Y = vp.M24 - vp.M21,
Z = vp.M34 - vp.M31,
W = vp.M44 - vp.M41
};
// Top plane.
frustumPlanes[2] = new Vector4
{
X = vp.M14 - vp.M12,
Y = vp.M24 - vp.M22,
Z = vp.M34 - vp.M32,
W = vp.M44 - vp.M42
};
// Bottom plane.
frustumPlanes[3] = new Vector4
{
X = vp.M14 + vp.M12,
Y = vp.M24 + vp.M22,
Z = vp.M34 + vp.M32,
W = vp.M44 + vp.M42
};
// Near plane.
frustumPlanes[4] = new Vector4
{
X = vp.M13,
Y = vp.M23,
Z = vp.M33,
W = vp.M43,
};
// Far plane.
frustumPlanes[5] = new Vector4
{
X = vp.M14 - vp.M13,
Y = vp.M24 - vp.M23,
Z = vp.M34 - vp.M33,
W = vp.M44 - vp.M43
};
// Normalize all the planes.
for (int i = 0; i < 6; i++)
frustumPlanes[i] = Vector4.Normalize(frustumPlanes[i]);
And I check if a sphere should be culled here :
public bool CullSphere(Vector3 position, float radius = 0.0f)
{
foreach (var plane in frustumPlanes)
{
// Verify if the point is behind the plane.
if (Vector3.Dot(plane.Xyz, position) + plane.W < -radius)
return true;
}
return false;
}
I saw on some other posts people multiplying the view and projection matrices manually, but I'm not sure that it's the cause of the problem. What I did wrong ?
Thanks
Try use my code implementation https://github.com/ALEXGREENALEX/LED_Engine/tree/master/LED_Engine/LED_Engine ("FrustumCulling.cs" and Draw call in "Game.cs"):
static void Draw(Mesh m)
{
m.CalculateMatrices(MainCamera);
FrustumCulling.ExtractFrustum(MainCamera.GetViewMatrix() * MainCamera.GetProjectionMatrix());
float Scale = Math.Max(m.Scale.X, Math.Max(m.Scale.Y, m.Scale.Z));
if (FrustumCulling.SphereInFrustum(m.Position, m.BoundingSphere.Outer * Scale))
for (int i = 0; i < m.Parts.Count; i++)
// ...
Draw(m, m.Parts[i]);
}
P.S.
1) After extracting frustum you must check intersection with Scaled objects (take maximum value of skale and multiply it by outer BoundingSphere radius).
2) In some old examples we can see MVP matrix in ExtractFrustum function (like there: http://www.codesampler.com/oglsrc/oglsrc_12.htm#ogl_frustum_culling). That's wrong name! They are use old API and Model matrix in this calculation is identity matrix (they call MV - ModelView matrix, but really thats only View matrix):
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
updateViewMatrix();
calculateFrustumPlanes();
void calculateFrustumPlanes(void)
{
float p[16]; // projection matrix
float mv[16]; // **VIEW MATRIX!!!**
float mvp[16]; // **View-Projection matrix!!!**
glGetFloatv( GL_PROJECTION_MATRIX, p );
glGetFloatv( GL_MODELVIEW_MATRIX, mv );
//...
}
I'm doing a school project about robocup where robots are playing football with AI. As everything works fine I am still stuck with something.
The robots are simple spheres drawn from top view. Both player shouldn't be allowed to walk into each other and should get a new updated position on the point of impact.
As the collision handler just checks if they collide or not.. I was hoping if there was a way to detect where the circles collide. So I can update the position of the colliding sphere to the last known non-colliding position so they can't walk trough each other and maybe bounce off.
All points on a circle's circumference are the same distacne, the radius, from the center of the circle. This is true for every circle on the playing field.
Therefore: two circles have collided EXACTLY when the distance between their centres is <= the sum of their respectve radii.
Well, you already marked an answer, but I went and put together a fully functioning piece of code, so maybe you can use it anyway. :) From my comment:
Since they're just circles, just calculate the midpoint between the
circles' centre points. If the circles have different radii, choose
one circle and calculate the point along the line one radius away from
its centre.
This might be a simple implementation. I created some very meager helper classes for it; I would totally encourage extending them, making the structs truly immutable, and all that good jazz, but for now serve okay for demonstration purposes.
So for helper classes:
public struct Point
{
public double X;
public double Y;
public double Distance(Point otherPoint)
{
double deltaX = this.X - otherPoint.X;
double deltaY = this.Y - otherPoint.Y;
return System.Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
}
public override string ToString()
{
return String.Format("({0}, {1})", X, Y);
}
}
public struct Polar
{
public double Radius;
public double Angle;
public double X { get { return Radius * System.Math.Cos(Angle); } }
public double Y { get { return Radius * System.Math.Sin(Angle); } }
public Point ToCartesian()
{
return new Point() { X = X, Y = Y };
}
}
public class Circle
{
public double Radius { get; set; }
public Point Position { get; set; }
}
Our meat-and-potatoes class/method is this:
public class CollisionResult
{
public Circle Circle1 { get; private set; }
public Circle Circle2 { get; private set; }
public Point Circle1SafeLocation { get; private set; }
public Point Circle2SafeLocation { get; private set; }
public Point CollisionLocation { get; private set; }
public CollisionResult(Circle circle1, Circle circle2)
{
this.Circle1 = circle1;
this.Circle2 = circle2;
}
public bool CalculateCollision()
{
double distanceFromCentres = Circle1.Position.Distance(Circle2.Position);
if (distanceFromCentres >= Circle1.Radius + Circle2.Radius)
return false;
double angleBetweenCircles = System.Math.Atan2(Circle2.Position.Y - Circle1.Position.Y, Circle2.Position.X - Circle1.Position.X);
Point midpointBetweenCircles = new Point(){X = (Circle1.Position.X + Circle2.Position.X)/2, Y = (Circle1.Position.Y + Circle2.Position.Y)/2};
Point circle1Offset = (new Polar() { Radius = Circle1.Radius, Angle = System.Math.PI + angleBetweenCircles }).ToCartesian();
Point circle2Offset = (new Polar() { Radius = Circle2.Radius, Angle = angleBetweenCircles }).ToCartesian();
CollisionLocation = midpointBetweenCircles;
Circle1SafeLocation = new Point(){X = midpointBetweenCircles.X + circle1Offset.X, Y = midpointBetweenCircles.Y + circle1Offset.Y };
Circle2SafeLocation = new Point(){X = midpointBetweenCircles.X + circle2Offset.X, Y = midpointBetweenCircles.Y + circle2Offset.Y };
return true;
}
}
Usage might look like:
private void CheckCollision(Circle circle1, Circle circle2)
{
CollisionResult result = new CollisionResult(circle1, circle2);
if (result.CalculateCollision())
{
Console.WriteLine(String.Format("Collision detected at {0}! Safe location for circle 1: {1}, circle 2: {2}", result.CollisionLocation, result.Circle1SafeLocation, result.Circle2SafeLocation));
}
else
{
Console.WriteLine("Did not collide.");
}
}
var circle1 = new Circle() {Radius = 5, Position = new Point(){X = 0, Y = 0} };
var circle2 = new Circle() {Radius = 5, Position = new Point(){X = 10, Y = 0} };
var circle3 = new Circle() {Radius = 3, Position = new Point(){X = 0, Y = 1} };
var circle4 = new Circle() {Radius = 5, Position = new Point(){X = 3, Y = 7} };
CheckCollision(circle1, circle2);
CheckCollision(circle3, circle4);
Outputs:
Did not collide.
Collision detected at (1.5, 4)! Safe location for circle 1: (0.158359213500125, 1.31671842700025), circle 2: (3.73606797749979, 8.47213595499958)
I don't know if it's necessary in your case to deal with the complexity of calculating true intersections of two circles (where they would intersect at two points) and such. Likely something along these lines would be sufficient for you. I definitely encourage healthy unit tests and making the classes proper beyond what I have here. :)
EDIT: Significantly in this case, and this would depend on what you want to do with it for your application, is that when the circles overlap, it simply calculates the midpoint between them then moves each circle away from that midpoint their respective radii. So depending on the speed and size of the circles, or how they are moving, it might produce weird results. For example, if you had a big 10 radius circle sitting still, then you throw in a 1 radius circle only 0.5 distance from the big circle's centre, that big circle is going to shift about 9.75 units! If you don't get into big overlapping conditions, then maybe it's not much of an issue. I think at the very least this will give you some information about the collision and then how you want your circles to react as a result will be up to you.
What you will need to do is to find the point of intersection between the two circles, which could be two points, one point, or none. This is basically done by solving the equations of the two circles together. Here's the math:
http://www.analyzemath.com/CircleEq/circle_intersection.html
Since this is for school I'll leave the coding to you :)
This question already has answers here:
circle-circle collision
(5 answers)
Closed 9 years ago.
Just made a little theory to simplify my problem.. I want to know if it's possible or easier way to do this.
I'm making a game simulation in C# where robots play soccer with AI. But need to prevent them from walking in eachother, find the exact point of impact to update their position so they can't walk into eachother.
Thanks.
This is not a duplicate since I was asking another theory I was working out.
Well, from the answer I already provided from your previous question, is there anything you don't understand or need help with? It does pretty much exactly what you're asking here (so "yes, you can employ polar coordinates like this.")
However, your comment about the "last known position where they didn't collide" would mean you would have to track their positions and maintain their last good state and revert to it. Not sure if that's necessary in this case or if you would rather just calculate a new "best-fit" location.
Well, you already marked an answer, but I went and put together a fully functioning piece of code, so maybe you can use it anyway. :) From my comment:
Since they're just circles, just calculate the midpoint between the
circles' centre points. If the circles have different radii, choose
one circle and calculate the point along the line one radius away from
its centre.
This might be a simple implementation. I created some very meager helper classes for it; I would totally encourage extending them, making the structs truly immutable, and all that good jazz, but for now serve okay for demonstration purposes.
So for helper classes:
public struct Point
{
public double X;
public double Y;
public double Distance(Point otherPoint)
{
double deltaX = this.X - otherPoint.X;
double deltaY = this.Y - otherPoint.Y;
return System.Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
}
public override string ToString()
{
return String.Format("({0}, {1})", X, Y);
}
}
public struct Polar
{
public double Radius;
public double Angle;
public double X { get { return Radius * System.Math.Cos(Angle); } }
public double Y { get { return Radius * System.Math.Sin(Angle); } }
public Point ToCartesian()
{
return new Point() { X = X, Y = Y };
}
}
public class Circle
{
public double Radius { get; set; }
public Point Position { get; set; }
}
Our meat-and-potatoes class/method is this:
public class CollisionResult
{
public Circle Circle1 { get; private set; }
public Circle Circle2 { get; private set; }
public Point Circle1SafeLocation { get; private set; }
public Point Circle2SafeLocation { get; private set; }
public Point CollisionLocation { get; private set; }
public CollisionResult(Circle circle1, Circle circle2)
{
this.Circle1 = circle1;
this.Circle2 = circle2;
}
public bool CalculateCollision()
{
double distanceFromCentres = Circle1.Position.Distance(Circle2.Position);
if (distanceFromCentres >= Circle1.Radius + Circle2.Radius)
return false;
double angleBetweenCircles = System.Math.Atan2(Circle2.Position.Y - Circle1.Position.Y, Circle2.Position.X - Circle1.Position.X);
Point midpointBetweenCircles = new Point(){X = (Circle1.Position.X + Circle2.Position.X)/2, Y = (Circle1.Position.Y + Circle2.Position.Y)/2};
Point circle1Offset = (new Polar() { Radius = Circle1.Radius, Angle = System.Math.PI + angleBetweenCircles }).ToCartesian();
Point circle2Offset = (new Polar() { Radius = Circle2.Radius, Angle = angleBetweenCircles }).ToCartesian();
CollisionLocation = midpointBetweenCircles;
Circle1SafeLocation = new Point(){X = midpointBetweenCircles.X + circle1Offset.X, Y = midpointBetweenCircles.Y + circle1Offset.Y };
Circle2SafeLocation = new Point(){X = midpointBetweenCircles.X + circle2Offset.X, Y = midpointBetweenCircles.Y + circle2Offset.Y };
return true;
}
}
Usage might look like:
private void CheckCollision(Circle circle1, Circle circle2)
{
CollisionResult result = new CollisionResult(circle1, circle2);
if (result.CalculateCollision())
{
Console.WriteLine(String.Format("Collision detected at {0}! Safe location for circle 1: {1}, circle 2: {2}", result.CollisionLocation, result.Circle1SafeLocation, result.Circle2SafeLocation));
}
else
{
Console.WriteLine("Did not collide.");
}
}
var circle1 = new Circle() {Radius = 5, Position = new Point(){X = 0, Y = 0} };
var circle2 = new Circle() {Radius = 5, Position = new Point(){X = 10, Y = 0} };
var circle3 = new Circle() {Radius = 3, Position = new Point(){X = 0, Y = 1} };
var circle4 = new Circle() {Radius = 5, Position = new Point(){X = 3, Y = 7} };
CheckCollision(circle1, circle2);
CheckCollision(circle3, circle4);
Outputs:
Did not collide.
Collision detected at (1.5, 4)! Safe location for circle 1: (0.158359213500125, 1.31671842700025), circle 2: (3.73606797749979, 8.47213595499958)
I don't know if it's necessary in your case to deal with the complexity of calculating true intersections of two circles (where they would intersect at two points) and such. Likely something along these lines would be sufficient for you. I definitely encourage healthy unit tests and making the classes proper beyond what I have here. :)
Significantly in this case, and this would depend on what you want to do with it for your application, is that when the circles overlap, it simply calculates the midpoint between them then moves each circle away from that midpoint their respective radii. So depending on the speed and size of the circles, or how they are moving, it might produce weird results. For example, if you had a big 10 radius circle sitting still, then you throw in a 1 radius circle only 0.5 distance from the big circle's centre, that big circle is going to shift about 9.75 units! If you don't get into big overlapping conditions, then maybe it's not much of an issue. I think at the very least this will give you some information about the collision and then how you want your circles to react as a result will be up to you.
Might be this is helpful for you:
http://www.emanueleferonato.com/2011/06/13/slicing-splitting-and-cutting-objects-with-box2d/
This tutorial consist of four parts and explain the 2D dynamics very well.
The faster way to see if the two circles are colliding is to constantly check their positions. Infact you have to check if the distance between their centers is smaller than the sum of their radius.
Some "pseudo code" could be:
distanceX = Math.Abs(circle1.X - cirlce2.X);
distanceY = Math.Abs(circle1.Y - cirlce2.Y);
distance = Math.Sqrt(distanceX * distanceX - distanceY * distanceY);
if(distance <= circle1.Radius + circle2.Radius){
//they're colliding and the point of collision is:
collisionX = distanceX / 2;
collisionY = distanceY / 2;
if(circle1.X < circle2.X)
collisionX += circle1.X;
else
collisionX += circle2.X;
if(circle1.Y < circle2.Y)
collisionY += circle1.Y;
else
collisionY += circle2.Y;
}
PS: Note that I didn't use Math.Pow() due to its performance.
I have a solution that uses spatial data to represent a cluster of points on a map. I have the need to used the coordinates that represent the extents of a cluster to find the minimum bounding rectangle that can contain said cluster of points.
Does any simple algorithm exist to be able to calculate this or is there any built in functionality in C# to achieve this. I am aware of the NetTopologySuite but am not sure how/if I could use this to achieve the same goal. I have a list of coordinates so I would need to pass this list of strings into it and get the MBR out.
The easiest solution, and I assume the one you're most likely to be looking for, is to calculate the axis-aligned bounding box, which is simply a case of finding the min/max x & y values, then constructing a box from those.
I'll give you pseudo-code for that, given that you haven't posted the types that your geometry is expressed in...
type point { float x; float y; }
type box { point topleft; point topright; point bottomleft; point bottomright; }
function bounding_box(points)
{
xmin = min(points.x)
xmax = max(points.x)
ymin = min(points.y)
ymax = max(points.y)
return new box{
topleft = { x = xmin, y = ymax },
topright = { x = xmax, y = ymax },
bottomleft = { x = xmin, y = ymin },
bottomright = { x = xmax, y = ymin }
};
}
So given these:
point[] points = [[x = -2, y = 0], [x = 1, y = 2], [x = 1, y = 1], [x = -1, y = -2]];
box bounds = bounding_box(points);
All of the following will be true:
bounds.topleft == [x = -2, y = 2];
bounds.topright == [x = 1, y = 2];
bounds.bottomleft == [x = -2, y = -2];
bounds.bottomright == [x = -1, y = -2];
Of course, if the coordinate system has the lowest coordinates at the top (e.g. like a typical display) - then you have to invert the calculation; or calculate the result in object-space first and then translate to logical space afterwards.
Notice I've gone for a type for the box that expresses all four corners, in case you decide in the future to update to an arbitrarily aligned box in the future (although by the same token you could just use a point + 2 vectors for that).
One possible, though simple, way to do it could be like this:
public Rectangle Test(List<Point> points)
{
// Add checks here, if necessary, to make sure that points is not null,
// and that it contains at least one (or perhaps two?) elements
var minX = points.Min(p => p.X);
var minY = points.Min(p => p.Y);
var maxX = points.Max(p => p.X);
var maxY = points.Max(p => p.Y);
return new Rectangle(new Point(minX, minY), new Size(maxX-minX, maxY-minY));
}
This does of course assume that you're looking for a rectangle that is aligned vertically and horizontally. So if you're looking for the smallest possible rectangle, no matter how it is rotated, this is not for you.
Try G# at http://www.ceometric.com/products/g.html
It has minimum area and minimum perimeter enclosing rectangles and also minimum enclosing circles.