C# Projectile Simulator - Applying Speed to X Position of Projectile Physics - c#

First of all, here is the code:
decimal gravity = decimal.Parse(gforce.Text) / 1000;
decimal speed = decimal.Parse(initialSpeed.Text) / 1000;
decimal newAngle = DegreesToRadians(decimal.Parse(angle.Text));
double doubleNewAngle = (double)newAngle;
decimal Px = Math.Round(((decimal)Math.Cos(doubleNewAngle) * 0.001M), 13);
decimal Py = Math.Round(((decimal)Math.Sin(doubleNewAngle) * 0.001M), 13);
string PxTemp = "";
for(decimal t = 0.001M; Py > 0; t = t + 0.001M)
{
gravity = gravity + gravity * 0.001M;
Py = Py + speed - gravity;
Px = (Px + speed * Px);
graphics.DrawArc(new Pen(Color.Magenta, 10f), 45 + (float)Px, 475 - (float)Py, 1, 1, 0, 360);
try
{
graphics.DrawArc(new Pen(Color.Magenta, 10f), 45 + (float)Px, 475 - (float)Py, 1, 1, 0, 360);
}
catch
{
MessageBox.Show("Error Px: " + Px.ToString() + " Py: " + Py.ToString(), "Error");
this.Close();
}
I am attempting to create a projectile simulator, I have successfully created the effect of gravity and acceleration on the y-axis. But however when applying the speed to the x axis(making the speed depend on the angle) I am having trouble. I can make it so every second the projectile moves 1 metre but for it to be correct the projectiles' speed across the x-axis should depend on the speed AND THE ANGLE.
To achieve this I have done:
Px = Px + (speed * Px)
Where Px is the value of distance across the axis Cosine of the angle:
decimal Px = Math.Round(((decimal)Math.Cos(doubleNewAngle) * 0.001M), 13);
When I do
Px = Px + (speed * Px)
The value returns some huge number for example 4412651515851.41214244121, I at first assumed this was because Px was going beyond its precision point but any rounding attempts I have made have failed, How should I achieve a correct Px number?
Here is an image to visualise it:
Any help would be greatly appreciated, I have been struggling all day and I couldn't find anything on-line. Thanks in advance.

The laws of motion are very different to the ones you use:
y'' = -g --> y(t) = y0 + vy0*t - g/2*t*t
x'' = 0 --> x(t) = x0 + vx0*t
These are the solutions for motion without air friction. Most complications of the equation of motion require numerical integration of the ODE.
The initial velocities vx0,vy0 are what you initially compute in Px,Py. But probably you should use
vx0 = speed*cos(angle)
vy0 = speed*sin(angle)
to get the initial velocity compatible with the inputs. Some additional unit conversions may be required.

For a useful tool to help workout the proper calculations.http://www.mrmont.com/teachers/physicsteachershelper-proj.html

Related

Why do these random events follow a specific pattern?

I have created a grid layout. It displays 100 balls. Initially, all the balls will be in a random position. Every 25 ms a ball will move some unit (this is common for all the balls) in a random direction. You can see this in action in the below image:
Even though the direction of the balls is random, after some time all the balls move towards the bottom right corner. This behavior repeats every time. You can see this in the below image:
Why do these random events follow a specific pattern?
Are random numbers truly random?
Is there is a problem with the C# random number generator?
Is there is any mathematical explanation for this?
C# Code
Random random = new Random();
var direction = random.NextDouble() * 360;
var ballTranslate = child.RenderTransform.TransformPoint(new Point(0, 0));
var x = ballTranslate.X;
var y = ballTranslate.Y;
var x1 = x + (parm.Speed * Math.Cos(direction));
while (x1 < 0 || x1 > (parm.CellSize * parm.NoOfSplit))
{
direction = random.NextDouble() * 360;
x1 = x + (parm.Speed * Math.Cos(direction));
}
var y1 = y + (parm.Speed * Math.Sin(direction));
while (y1 < 0 || y1 > (parm.CellSize * parm.NoOfSplit))
{
direction = random.NextDouble() * 360;
y1 = y + (parm.Speed * Math.Sin(direction));
}
TranslateTransform myTranslate = new TranslateTransform();
myTranslate.X = x1;
myTranslate.Y = y1;
child.RenderTransform = myTranslate;
Full Code
https://github.com/Vijay-Nirmal/ProjectChaos
You appear to be generating a direction in degrees and passing it to Math.Sin, which takes an angle in radians. 360/2PI = 57.3 (approximately), so you're slightly more likely to pick an angle between 0 and 0.3 radians than other, larger angles.
When you have so many iterations, it's also possible that there's a tiny rounding error somewhere

C# intersect a line bettween 2 Vector3 point on a plane

I have a line going bettween two Vector3 points and I want to find when the line is intersected at a height along the Z axis.
I am trying to write a function to calculate the intersection point.
void Main()
{
Vector3 A = new Vector3(2.0f, 2.0f, 2.0f);
Vector3 B = new Vector3(7.0f, 10.0f, 6.0f);
float Z = 3.0f;
Vector3 C = getIntersectingPoint(A, B, Z);
//C should be X=3.25, Y=4.0, Z=3.0
}
But trying to figure out how to do the math to handle possible negative numbers correctly is really starting to confuse me.
This is what I have and the moment, but this isn't correct.
public static Vector3 getIntersectingPoint(Vector3 A, Vector3 B, float Z)
{
// Assume z is bettween A and B and we don't need to validate
// Get ratio of triangle hight, height Z divided by (Za to Zb)
("absolute value: " + Math.Abs(A.Z-B.Z)).Dump();
("z offset: " + (Math.Abs(Z-B.Z)<Math.Abs(A.Z-Z)?Math.Abs(Z-B.Z):Math.Abs(A.Z-Z))).Dump();
float ratio = (Math.Abs(Z-B.Z)<Math.Abs(A.Z-Z)?Math.Abs(Z-B.Z):Math.Abs(A.Z-Z))/Math.Abs(A.Z-B.Z);
("ratio: " + ratio.ToString()).Dump();
float difX = ratio*Math.Abs(A.X-B.X);//this still needs to be added to or taken from the zero point offset
("difX: " + difX.ToString()).Dump();
float difY = ratio*Math.Abs(A.Y-B.Y);//this still needs to be added to or taken from the zero point offset
("difY: " + difY.ToString()).Dump();
float X = difX + (A.X<B.X?A.X:B.X);
("X: " + X).Dump();
float Y = difY + (A.Y<B.Y?A.Y:B.Y);
("Y: " + Y).Dump();
return new Vector3(X,Y,Z);
}
Does anyone know if there are any Math libraries that will already do this or examples that show how to do this that I can follow?
You have the starting (2.0f) and ending (6.0f) Z coordinates. The Z distance between the two points is 4.0f. You want to know the X and Y coordinates at the point where Z is 3.0f.
Remember that Z changes linearly along the segment. The segment is 4 units long, The point you're interested in is 1 unit from the start, or 1/4 of the length of the segment.
The X distance of the entire segment is 7.0 - 2.0, or 5 units. 1/4 of 5 is 1.25, so the X coordinate at the intersection is 3.25.
The Y distance of the entire segment is 8. 1/4 of 8 is 2. So the Y coordinate of the intersection point is 6.0.
The intersection point is (3.25f, 6.0f, 3.0f).
How to compute:
// start is the starting point
// end is the ending point
// target is the point you're looking for.
// It's pre-filled with the Z coordinate.
zDist = Math.Abs(end.z - start.z);
zDiff = Math.Abs(target.z - start.z);
ratio = zDiff / zDist;
xDist = Math.Abs(end.x - start.x);
xDiff = xDist * ratio;
xSign = (start.x < end.x) ? 1 : -1;
target.x = start.x + (xDiff * xSign);
yDist = Math.Abs(end.y - start.y);
yDiff = yDist * ratio;
ySign = (start.y < end.y) ? 1 : -1;
target.y = start.y + (yDiff * ySign);
Come to think of it, the whole sign thing shouldn't be necessary. Consider this, when end.x = 10 and start.x = 18:
xDist = end.x - start.x; // xDist = -8
xDiff = xDist * ratio; // xDiff = -2
target.x = start.x + xDiff; // target.x = 18 + (-2) = 16
Yeah, no need for sign silliness.
Also no need for the calls to Math.Abs when computing the ratio. We know that zDist and zDiff will both have the same sign, so ratio will always be positive.

Diagonal sweep and orthogonal distance of a point to diagonal

I have a problem where I'm required to find the maximum number of points that are less than or equal to a given distance D to a line drawn in a two-dimensional Euclidean plane. To solve this I wrote the algorithms that would compute a possible maximum if the line was orthogonal to either the x-axis or the y-axis. My problem is when only a diagonal line would yield the maximum number of points.
Given the constraints that both x and y have a minimum value of -1000000 and maximum of 1000000. I wrote the following algorithm to try and find out the maximum. I don't seem to be getting the right answer. Could someone please guide me on where I am going wrong. I've tried drawing a regression line as well but that used vertical distance which did not work for my purposes. Maybe I'm going all wrong and this problem can be solved as an optimization problem. Anyways' any help with a descent explanation is much appreciated.
// diagonal sweep
for (int degree = 1; degree < 180; degree++) if (degree % 90 != 0)
{
int k = 1, degrees = degree;
double x1 = -1000000, x2 = 1000000;
if (degree > 90 && degree < 180)
{
degrees = 180 - degrees;
k = -1;
}
//slope
double m1 = Math.Tan(Math.PI * degrees * k / 180.0);
//Point A
Point A = new Point(x1, m1 * x1);
//Point B
Point B = new Point(x2, m1 * x2);
for (int i = 0; i < x.Length; i++)
{
//Point P = household that needs power
Point P = new Point(x[i], y[i]);
double normalLength = Math.Sqrt((B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y));
double segmentLength = 1d * Math.Abs((P.X - A.X) * (B.Y - A.Y) - (P.Y - A.Y) * (B.X - A.X)) / normalLength;
if (segmentLength <= D)
tempCnt++;
}
maxConnections = Math.Max(maxConnections, tempCnt);
tempCnt = 0;
}
return maxConnections;
If you want to define this problem as an optimization problem, you should do it as follows, but it doesn't seem to me this optimization problem is solveable efficiently as is.
maximize: x_1 + x_2 + ... + x_n + 0*a + 0*b + 0*c
s.t.
x_i * d(p_i, line(a,b,c))/ MAX_DISTANCE <= 1
x_i is in {0,1}
Explanation:
x_i are inclusion variables - can get a value of 0 / 1 , and it indicates if the point p_i is in the required distance from the line.
a,b,c are the parameters for the line: ax + by + c = 0
The idea is to maximize the sum of included points, such that each included point is in the desired range. This is represented by the constraint, if x_i=0 - there is no restriction on the point p_i, as the constraint is always satisfied. Otherwise, x_i=1, and you need the distance from the line (let it be d) satisfy 1* d/MAX_DISTANCE <= 1 - which is exactly what you want.
Though I don't think there is an optimal efficient solution to this optimization problem, you might want to try some heuristical solutions for this optiization - such as Genetic Algorithms or Hill Climbing
As a side note, my gut says this problem is NP-Complete, though I have no proof for it yet - and will update this part of the answer if I (or someone else) can come up with a reduction/polynomial solution.

2D Elastic Collisions 'Sticking' Issue

I have a simulation with multiple circles moving in 2D space.
There is collision detection between them, and the elastic collisions work 95% of the time. Occasionally however, when two balls hit each other, they stick to each other and overlap, often orbiting each other while being stuck together.
I'm unsure how to solve this problem.
My collision management function looks like this:
void manageCollision(Particle particleA, Particle particleB)
{
float distanceX = particleA.Position.X - particleB.Position.X;
float distanceY = particleA.Position.Y - particleB.Position.Y;
double collisionAngle = Math.Atan2(distanceY, distanceX);
double pA_magnitude = Math.Sqrt(particleA.Velocity.X * particleA.Velocity.X + particleA.Velocity.Y * particleA.Velocity.Y);
double pB_magnitude = Math.Sqrt(particleB.Velocity.X * particleB.Velocity.X + particleB.Velocity.Y * particleB.Velocity.Y);
double pA_direction = Math.Atan2(particleA.Velocity.Y, particleA.Velocity.X);
double pB_direction = Math.Atan2(particleB.Velocity.Y, particleB.Velocity.X);
double pA_newVelocityX = pA_magnitude * Math.Cos(pA_direction - collisionAngle);
double pA_newVelocityY = pA_magnitude * Math.Sin(pA_direction - collisionAngle);
double pB_newVelocityX = pB_magnitude * Math.Cos(pB_direction - collisionAngle);
double pB_newVelocityY = pB_magnitude * Math.Sin(pB_direction - collisionAngle);
double pA_finalVelocityX = ((particleA.Mass - particleB.Mass) * pA_newVelocityX + (particleB.Mass + particleB.Mass) * pB_newVelocityX) / (particleA.Mass + particleB.Mass);
double pB_finalVelocityX = ((particleA.Mass + particleA.Mass) * pA_newVelocityX + (particleB.Mass - particleA.Mass) * pB_newVelocityX) / (particleA.Mass + particleB.Mass);
double pA_finalVelocityY = pA_newVelocityY;
double pB_finalVelocityY = pB_newVelocityY;
particleA.Velocity = new Vector2((float)(Math.Cos(collisionAngle) * pA_finalVelocityX + Math.Cos(collisionAngle + Math.PI / 2) * pA_finalVelocityY), (float)(Math.Sin(collisionAngle) * pA_finalVelocityX + Math.Sin(collisionAngle + Math.PI / 2) * pA_finalVelocityY));
particleB.Velocity = new Vector2((float)(Math.Cos(collisionAngle) * pB_finalVelocityX + Math.Cos(collisionAngle + Math.PI / 2) * pB_finalVelocityY), (float)(Math.Sin(collisionAngle) * pB_finalVelocityX + Math.Sin(collisionAngle + Math.PI / 2) * pB_finalVelocityY));
}
Each ball or particle spawns with a random mass and radius.
The function is called within an update type of method, like this:
Particle pA = particles[i];
for (int k = i + 1; k < particles.Count(); k++)
{
Particle pB = particles[k];
Vector2 delta = pA.Position - pB.Position;
float dist = delta.Length();
if (dist < particles[i].Radius + particles[k].Radius && !particles[i].Colliding && !particles[k].Colliding)
{
particles[i].Colliding = true;
particles[k].Colliding = true;
manageCollision(particles[i], particles[k]);
particles[i].initColorTable(); // Upon collision, change the color
particles[k].initColorTable();
totalCollisions++;
}
else
{
particles[i].Colliding = false;
particles[k].Colliding = false;
}
}
This situation stems from the discrete computation and big step size of duration.
When you observe the objects with some time interval dt, you can observe some intersection between two circles and call your collision method but in the next time step they may still overlap although they are going in different directions after the collision in the previous step.
To reduce this effect, you can try a lower time step size so that the overlap ratio between objects may be reduced.
As a more complicated solution, you can keep a list of your collided objects for every step and during iterations you can check this list if current intersected circles had any "affairs" in the previous step.

EmguCV - Motion detection not returning angles

I am runnng the motion detection algorithm against a video (file) and following the code sample motion detection, and trying to find the angle of each component and the overall motion. I do get a motion value back, with blobs etc., but the motion direction of each component always is always 0 degrees or 360 degrees and make no sense. What could I be doing wrong? Please help, thanks.
This is the constructor
_motionHistory = new MotionHistory(
10.0, //in second, the duration of motion history you wants to keep
0.05, //in second, parameter for cvCalcMotionGradient
0.5); //in second, parameter for cvCalcMotionGradient
The following is the code for looping through the motion components:
foreach (MCvConnectedComp comp in motionComponents)
{
//reject the components that have small area;
if (comp.area < 1) continue;
// find the angle and motion pixel count of the specific area
double angle, motionPixelCount;
_motionHistory.MotionInfo(comp.rect, out angle, out motionPixelCount);
string motion_direction = GetMotionDescriptor(comp.rect);
Console.writeline (motion_direction);
}
// find and draw the overall motion angle
double overallAngle, overallMotionPixelCount;
_motionHistory.MotionInfo(motionMask.ROI, out overallAngle, out overallMotionPixelCount);
And this where I get my motion descriptor angle
private string GetMotionDescriptor(Rectangle motionRegion)
{
float circleRadius = (motionRegion.Width + motionRegion.Height) >> 2;
Point center = new Point(motionRegion.X + motionRegion.Width >> 1, motionRegion.Y + motionRegion.Height >> 1);
int xDirection = (int)(Math.Cos(angle * (Math.PI / 180.0)) * circleRadius);
int yDirection = (int)(Math.Sin(angle * (Math.PI / 180.0)) * circleRadius);
//double movementAngle = Math.Atan(xDirection / yDirection) * 180 / Math.PI;
Point pointOnCircle = new Point(center.X + xDirection, center.Y - yDirection);
double slope = (double)(pointOnCircle.Y - center.Y)/(double)(pointOnCircle.X - center.X);
double ang = Math.Atan(slope) * 180/Math.PI;
return (ang).ToString() + " degrees";
}
aha! I figured out the reason and posting here if anyone is running into the same problem. The
_motionHistory = new MotionHistory(mhi, maxDelta, minDelta);
Should be adjusted to the frame rate and the motion. The trick lies in the 3 params
(1) motion history to keep, (2) max time delta, (3) min time delta.
They need to be adjusted in some way to reflect the motion you wish to capture.
Hope that helps.

Categories

Resources