How to separate two colliding circles? - c#

I'm looking to separate two colliding circles, to push them back equally by the minimum amount so that they're perfectly separated.
I have this so far:
var totalRadius : Number = _circle1.radius + _circle2.radius;
var x : Number = _circle1.position.x - _circle2.position.x;
var y : Number = _circle1.position.y - _circle2.position.y;
var distanceSquared : Number = (x * x) + (y * y);
if (distanceSquared < totalRadius * totalRadius)
{
var distance : Number = Math.sqrt(distanceSquared);
var separation : Number = totalRadius - distance;
// No idea what to do now!
}
That much I've figured out so far. So I know a collision has occurred and I know that each circle is separation amount into each other (so I guess divide by 2 to separate them equally).
The problem is that separation doesn't have any implied directionality and I don't know what to do. I can't just do circle1.position -= separation / 2; circle2.position += separation / 2 because that'll move both the X and Y axis equally.
How do I add directionality to separation?
Thanks!

Use unit vector to move both circles by separation / 2.
unitVector = (circle1.Position - circle2.Position) / distance
circle1.Position += unitVector * seperation / 2
circle2.Position -= unitVector * seperation / 2
Edit:
just change seperation / 2 and/or +- part. It will allow you to move it by any distance you want.

Related

How to divide objects into limited area with C#?

im currently working on a game and i need to divide a changeable amount of objects in to a limited area. I made a image to explain better:
(I know its a bit difficult to understand)
So i can't find a solution and couldn't figure it out myself. I tried a few ways to multiply and divide the object count with the index and the xMaximum but it didn't work as expected.
This is what i tried:
public float xMin, xMax;
private void UpdateValues()
{
for(int i = 0; i < transform.childCount; i++)
{
float value = xMin;
float maxIndex = transform.childCount;
float index = i;
value = transform.position.x + xMax / (maxIndex * index);
transform.GetChild(i).transform.position = new Vector3(transform.position.x, transform.position.y, value);
}
}
It just gave me the wrong numbers and i can't figure the right way out.
The available variables are:
xMinimum, xMaximum
objectcount
objectindex
If you want it to look exactly how you have shown it on images then it might be a little more tricky. Objects don’t fill the area always the same, so we need to add some exceptions:
if there is only 1 item, then just set it’s position to (xMin + xMax) / 2f
if item is first, and there are more than one, set its position to xMin + (squareWidth / 2f) (or something else if pivot is not in the middle)
if item is last and there are more than one, set its position to xMax - (squareWidth / 2f)
the remaining area, which is of size xMax - 2 * squareWidth need to be divided equally between all remaining objects. Compute the amount remaining objects (which will be all objects - 2 (first and last)). Divide remaining area by number of objects plus 1. Set remaining objects position in a loop, the statement inside will look something like this: value = (i+1) * remainingArea / (transform.childCount - 2 + 1)
That’s the rough list of steps that might help. In this example I assume, that xMin is 0, otherwise you will need to take that into account and for eg. Remaining area won’t be just xMax - 2 * squareWidth, but xMax - xMin - 2 * squareWidth.
Also you might find yourself being off a half a square here and there, but that should be easy to correct.

Randomly pick two numbers in a range so that the sum of their squares is constant

I'm currently developing a 2-player Ping-Pong game (in 2D - real simple) from scratch, and it's going good. However Theres a problem I just can't seem to solve - I'm not sure if this should be located here or on MathExchange - anyway here goes.
Initially the ball should be located in the center of the canvas. When pressing a button the ball should be fired off in a completely random direction - but always with the same velocity.
The Ball object has (simplified) 4 fields - The position in X and Y, and the velocity in X and Y. This makes it simple to bounce the ball off the walls when it hits, simple by inverting the velocities.
public void Move()
{
if (X - Radius < 0 || X + Radius > GameWidth)
{
XVelocity = -XVelocity;
}
if (Y - Radius < 0 || Y + Radius > GameHeight)
{
YVelocity = -YVelocity;
}
X+= XVelocity;
Y+= YVelocity;
}
I figured the velocity should be the same in each game, so I figures I would use Pythagoras - the square of the two velocities should always be the same.
SO for the question:
Is there a way to randomly select two numbers (doubles) such that the sum of their squares is always a specific number - more formally:
double x = RandomDouble();
double y = RandomDouble();
if (x^2 + y^2 = 16) {/* should always be true */ }
Any help appreciated :)
Randomly pick an angle theta and multiply that by the magnitude of the distance d you want. Something like:
double theta = rand.NextDouble() * 2.0 * Math.PI;
double x = d * Math.Cos(theta);
double y = d * Math.Sin(theta);
If the constant is C, pick a number x between 0 and sqrt(C).
Solve for the other number y using simple algebra.
why not try this:
double x = RandomDouble();
double y = square(16-x^2);
as your application allow double type.
does this solve your problem?
if not, please let me know

How to find the surrounding area 25 miles using latitude & longitude from the current user location

I found Haversine Formula in C# is there any other method better than this.
public double HaversineDistance(LatLng pos1, LatLng pos2, DistanceUnit unit)
{
double R = (unit == DistanceUnit.Miles) ? 3960 : 6371;
var lat = (pos2.Latitude - pos1.Latitude).ToRadians();
var lng = (pos2.Longitude - pos1.Longitude).ToRadians();
var h1 = Math.Sin(lat / 2) * Math.Sin(lat / 2) +
Math.Cos(pos1.Latitude.ToRadians()) * Math.Cos(pos2.Latitude.ToRadians()) *
Math.Sin(lng / 2) * Math.Sin(lng / 2);
var h2 = 2 * Math.Asin(Math.Min(1, Math.Sqrt(h1)));
return R * h2;
}
I suppose it is a matter of what you want to do with it. My guess is that you are trying to calculate distance based on a ZIP (Post) code and you want to know if pos2 is within x distance of pos1.
What you first need to understand is that (unless you have some awesome Geo Spatial data to work with) all calculations do not generally take into account elevation or any other topographical attributes of the given area so your calculations won't be exact. Further these calculations are "as the crow flies" which means point x to point y is a straight line so while point y may lie within 25 miles of central point x it may actually be 30 miles to travel from central point x to point y.
That being said the Haversine Formula is your best bet unless you are calculating small distances (< ~12 miles) in which case you could use Pythagorean's theorem which is expressed as:
d = sqrt((X2 - X1)^2 + (Y2 - Y1)^2)
Where X and Y are your coordinates, obviously. This is much faster but is far less accurate especially as distance increases.
The Haversine Formula is slow especially if you are repeated calling it but I am unaware of any faster methods for calculating distance based on this formula.

Separating two colliding circles

I'm trying to separate two circles that are colliding. Thanks to the help of others, I'm right there!
This is my code:
var totalRadius : Number = _circle1.radius + _circle2.radius;
var x : Number = _circle1.position.x - _circle2.position.x;
var y : Number = _circle1.position.y - _circle2.position.y;
var distanceSquared : Number = (x * x) + (y * y);
if (distanceSquared < totalRadius * totalRadius)
{
var distance : Number = Math.sqrt(distanceSquared);
var separation : Number = totalRadius - distance;
var unitVectorX : Number = (_circle1.position.x - _circle2.position.x) / distance;
var unitVectorY : Number = (_circle1.position.y - _circle2.position.y) / distance;
_circle1.position.x += unitVectorX * (separation / 2);
_circle1.position.y += unitVectorY * (separation / 2);
_circle2.position.x -= unitVectorX * (separation / 2);
_circle2.position.y -= unitVectorY * (separation / 2);
}
It works great if the circles have the same velocity. The problem occurs when they have different velocities and the problem is because I'm splitting the separation evenly (separation / 2) I think!
Everything works perfectly if circle1 has a velocity of 1,0 and circle2 has a velocity of -1,0. The two circles hit each other and stop.
If circle1 has a velocity of 2,0 and circle2 has a velocity of -1,0, the circles gradually move to the right. I imagine this is what's happening:
frame1:
circle1 (99, 100)
circle2 (101, 100)
frame2:
circle1 (101, 100)
circle2 (100, 100)
collision detected, corrected position of -0.5 and +0.5 respectively.
circle1 (100.5, 100)
circle2 (100.5, 100)
frame3:
circle1 (102.5, 100)
circle2 (99.5, 100)
collision detected, corrected position of -1.5 and +1.5 respectively.
circle1 (101, 100)
circle2 (101, 100)
frame4:
circle1 (103, 100)
circle2 (100, 100)
collision detected, corrected position of -1.5 and +1.5 respectively.
circle1 (101.5, 100)
circle2 (101.5, 100)
As you can see, both circles are gaining +0.5 to the right because of the difference of velocity.
So finally, my question: How can I factor in their velocity into the equation so that it doesn't play a factor in their separation?
Thanks!
You need to calculate the point of impact, rather than just (arbitrarily) moving them both backwards equally.
A quick search found these links:
http://www.t3hprogrammer.com/research/circle-circle-collision-tutorial#TOC-Static-Circle-Circle-Collision-Dete (the section "Dynamic Circle-Circle Collision")
http://nonlinear.openspark.com/tutorials/vectors/index.htm (section "Impact, not intersection")
to make the answer short: you will have to get momentum in there ;)
As I guess you want to have the masses the same it comes down to "v1_before^2 + v2_before^2 = v1_after^2 + v2_after^2". As the wiki-article suggests I just "switch" the velocities.
What I do not understand is why you think the circles will both move to the right? Isn't this suppost to be a elastic collision? Then they should go in different directions if you want them to have same mass.

algorithm for a random space bordered by elements of equal length

I am an architecture student trying to solve a spatial problem with C# in Grasshopper for Rhino.
The space I am trying to create is an exhibition space in an airport. The space will be made up of elements of similar length. The idea is to connect them with a hinge and thereby allow them to create spaces of different layout and size according to how many elements are used.
As you can see from the illustration I would like the space to end with an opening an element length away from the starting point.
My first attempt has been to create equilateral triangles depending on the number of segments (walls) needed.
In short, from the starting point, triangles are created, and then the sides of the triangle that form the outer border are added to a list of points. This point list is returned to the Grasshopper application, which draws lines between the points. A little point is that I made the creation of the next triangle randomly either from the side AC or BC from the last triangle.
Here is an example of the spaces created (for 12 - 8 - 14 - 20 elements):
Here is the source code that creates these point lists:
private void RunScript(double radius, int walls, ref object A)
{
//
List<Point3d> pointList = new List<Point3d>();
List<Point3d> lastList = new List<Point3d>();
bool alternate = true;
bool swapped = false;
Random turn = new Random();
// set up the first part of the triangle
Point3d point1 = new Point3d(0, 0, 0);
Point3d point2 = new Point3d(0, radius, 0);
pointList.Add(point1);
pointList.Add(point2);
Point3d calcPoint;
for(int i = 0; i < walls - 1; i++) // walls - 1, is because I need one less triangle to get to the amount of walls
{
// use the method to create two similar circles and return the intersection point
// in order to create an equilateral triangle
calcPoint = FindCircleIntersections(point1.X, point1.Y, point2.X, point2.Y, radius, alternate);
// random generator: will decide if the new triangle should be created from side BC or AC
bool rotate = turn.Next(2) != 0;
Print("\n" + rotate);
// set the 2nd and 3rd point as 1st and 2nd - depending on random generator.
if(rotate)
{
point1 = point2;
if(swapped == true)
swapped = false;
else
swapped = true;
}
// if the direction is swapped, the next point created will not be a part of the outer border
if(swapped)
lastList.Add(calcPoint);
else
pointList.Add(calcPoint);
point2 = calcPoint;
// swap direction of intersection
if(rotate)
{
if(alternate)
alternate = false;
else
alternate = true;
}
}
lastList.Reverse();
foreach (Point3d value in lastList)
{
pointList.Add(value);
}
A = pointList;
}
// Find the points where the two circles intersect.
private Point3d FindCircleIntersections(
double cx0, double cy0, double cx1, double cy1, double rad, bool alternate)
{
// Find the distance between the centers.
double dx = cx0 - cx1;
double dy = cy0 - cy1;
double dist = Math.Sqrt(dx * dx + dy * dy);
// Find a and h.
double a = (rad * rad - rad * rad + dist * dist) / (2 * dist);
double h = Math.Sqrt(rad * rad - a * a);
// Find P2.
double cx2 = cx0 + a * (cx1 - cx0) / dist;
double cy2 = cy0 + a * (cy1 - cy0) / dist;
// Get the points P3.
if(alternate)
return new Point3d((double) (cx2 + h * (cy1 - cy0) / dist), (double) (cy2 - h * (cx1 - cx0) / dist), 0);
else
return new Point3d((double) (cx2 - h * (cy1 - cy0) / dist), (double) (cy2 + h * (cx1 - cx0) / dist), 0);
}
What I would like to do, is to vary the creation of these shapes, so that they are not only corridors, but resemble my initial sketches. I would like an algorithm to take an input of segments (number and length) and then propose different space layouts which are possible to create with this number of segments. I guess because of tesselation the space would have to be created with triangles, squares or hexagons? Do you think I should look into this "maximum area" algorithm : Covering an arbitrary area with circles of equal radius here on stackoverflow?
I would greatly appreciate any help on this algorithm. Cheers, Eirik
If you're merely interested in a program to generate instances to be externally evaluated (and not all such instances), you could "inflate" your curve. For example, in the 14-segment instance in your second image, there is a place where the curve goes inward and doubles back -- so your list of points has one point repeated. For curves like this you could cut out everything between the two (identical) points (A and B), as well as one of the surrounding points (A or B), and you have reclaimed some points to expand your curve - possibly resulting in a non-corridor structure. You may have to work some magic to ensure it is a "closed" curve, though, buy alternately adding segments to the front and the back of the curve.
Another opportunity: if you can identify the curve's interior (and there are algorithms for this), then anywhere that two segments form a concave angle with respect to your curve, you could blow it out to make a non-corridorish area. E.g. the second and third segments of your 14-segment curve above could be blown out to the left.
Successively applying these two methods to your corridor-like curve should generate many of the shapes you're looking for. Good luck!

Categories