I'm trying to calculate distance of cannon shot using velocity and angle. I'm testing results using utility tests. The formula for range should be someting like v^2 * sin2a aka velocity squared * sin2alpha . As far as i know, sin2a is supposed to be 2*sina*cosa, but i may be wrong.
Anyway, whatever i do, i get wrong results, because it doesn't seem to be calculating sin.
Here's the code
Cannon.cs
public int CalculateDistance(int angle, int velocity)
{
int distance = 0;
double radian_angle = (Math.PI / 180) * angle;
distance_of_shot = (Math.Pow(velocity, 2)) * (2 * Math.Sin(radian_angle) * Math.Cos(radian_angle));
distance = (int)distance_of_shot;
return distance;
}
CannonAttackTest.cs
[TestMethod]
public void Calculations()
{
Canon new_canon = new Canon();
var data = new_canon.CalculateDistance(45, 450);
Assert.AreEqual(20682, data);
}
The results is suppose to be 20682, but i get 202500, which is exactly a number of squared 450...whichs points to sin not being calculated.
Any help is appreciated!
Thank you!
Check your units, you need to divide by the value of "g" because velocity is m/s and your "distance of shot" is in m^2/s^2.
distance_of_shot = (Math.Pow(velocity, 2)) * (2 * Math.Sin(radian_angle) * Math.Cos(radian_angle))/9.81;
You have a mistake sin 0.70710678118654746 and cos 0.70710678118654757 but after
(2 * Math.Sin(radian_angle) * Math.Cos(radian_angle)) result coming 1
Related
I'm making a function that calculates the angle between 2 given vectors for my unity game using the dot product formula:
vector(a)*vector(b)=|vector(a)|*|vector(b)|*cos(the angle)
so I figured that the angle would equals
acos((vector(a)*vector(b))/(|vector(a)|*|vector(b)|))
Anyway here's my code:
float rotateAngle(Vector2 a,Vector2 b)
{
return Mathf.Acos((a.x * b.x + a.y * b.y) / ((Mathf.Sqrt(a.x * a.x + a.y * a.y)) * (Mathf.Sqrt(b.x * b.x + b.y * b.y)))) * (180 / Mathf.PI);
}
But when i played it the console showed NaN. I've tried and reviewed the code and the formula but returned empty-handed.
Can someone help me? Thank you in advanced!!
float.NaN is the result of undefined (for real numbers) mathematical operations such as 0 / 0 (note from the docs that x / 0 where x != 0 rather returns positive or negative infinity) or the square root of a negative value. As soon as one operant in an operation already is NaN then also the entire operation returns again NaN.
The second (square root of a negative value) can not happen here since you are using squared values so most probably your vectors have a magnitude of 0.
If you look at the Vector2 source code you will find their implementation of Vector2.Angle or Vector2.SignedAngle (which you should rather use btw as they are tested and way more efficient).
public static float Angle(Vector2 from, Vector2 to)
{
// sqrt(a) * sqrt(b) = sqrt(a * b) -- valid for real numbers
float denominator = (float)Math.Sqrt(from.sqrMagnitude * to.sqrMagnitude);
if (denominator < kEpsilonNormalSqrt)
return 0F;
float dot = Mathf.Clamp(Dot(from, to) / denominator, -1F, 1F);
return (float)Math.Acos(dot) * Mathf.Rad2Deg;
}
// Returns the signed angle in degrees between /from/ and /to/. Always returns the smallest possible angle
public static float SignedAngle(Vector2 from, Vector2 to)
{
float unsigned_angle = Angle(from, to);
float sign = Mathf.Sign(from.x * to.y - from.y * to.x);
return unsigned_angle * sign;
}
There you will find that the first thing they check is
float denominator = (float)Math.Sqrt(from.sqrMagnitude * to.sqrMagnitude);
if (denominator < kEpsilonNormalSqrt)
return 0F;
which basically makes exactly sure that both given vectors have a "big enough" magnitude, in particular one that is not 0 ;)
Long story short: Don't reinvent the wheel and rather use already built-in Vector2.Angle or Vector2.SignedAngle
NaN are typically the result of invalid mathematical operations on floating point numbers. A common source is division by zero, so my guess would be that the vector is 0,0.
I would also recommend using the built in functions for computing the normalization, Length/Magnitude, Dot etc. that will make the code much easier to read, and the compiler should be fairly good at optimizing that kind of code. If you need to do any additional optimization, only do so after you have done some measurements.
(Please keep in mind that I am new to coding so any glaring mistakes I apologize for in advance)
I am currently trying to calculate the Flight time (and eventually distance) of a ballistics cannon using velocity and angle of the cannon provided by a user through the console. However, the math is coming out wrong. The Tof calculation in comments was from an old line and am just using it for reference until everything works and I clean it up. Since the current Tof is exactly what the equation requires:
t = (v*sin(θ) + (v2sin2(θ) + 20*L*sin(θ))1/2 )/10 where v is the
velocity of the cannonball, θ is the angle to the ground, and L is the
length of the cannon barrel.)
(except for the swap of sin^2(theta) to its Trig Identity), i believe the problem lies in the conversion from degrees to radians. The current line was something I assumed, since I have not been taught anything regarding that. Any results online regarding the conversion give me something along the lines of:
private double DegreeToRadian(double angle)
{
return Math.PI * angle / 180.0;
}
Which when it is put in the place of the current line, causes a ton of errors for almost everything beneath it. I believe that chunk in meant to be a part of code on its own and not shoved into the middle of everything, but I do not know any other way to do this since all work must be done in the main method.
Any help is very much appreciated. The code in full is below:
Edit1: this is when the above code is entered
Edit2: the following changes were made:
#pilotcam's suggestion to change everything to doubles
#Shannon Holsinger's suggestion to change int.parse to double.parse
#Shannon Holsinger - the first error is at the end of
double EnteredVelocityNum = double.Parse(EnteredVelocity);
Immediately after the semicolon. It reads " } expected".
#MethodMan - I am very sorry, but I do not understand your suggestion regarding:
double EnteredAngleNum = 0d;
Where do I put it? I apologize again for my cluelessness, I have not learned this before and this is all rather new to me.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HW1
{
class Cannonball
{
static void Main(string[] args)
{
const double Length = 2;
//here the velocity of the cannonball is acquired from the player
string EnteredVelocity;
Console.WriteLine("Enter the velocity of the cannonball betweeen 0-100 meters: ");
EnteredVelocity = Console.ReadLine();
Console.WriteLine("You entered: " + EnteredVelocity);
// the angle of the cannon is acquired from the player
string EnteredAngle;
Console.WriteLine("Enter the angle of the cannon betweeen 0-90 degrees: ");
EnteredAngle = Console.ReadLine();
Console.WriteLine("You entered: " + EnteredAngle);
//calculating the Time of Flight
double EnteredAngleNum = double.Parse(EnteredAngle);
double EnteredVelocityNum = double.Parse(EnteredVelocity);
private double EnteredAngleRad(double EnteredAngleNum)
{
return (Math.PI / 180) * EnteredAngleNum;
}
//double EnteredAngleRad = (2 * Math.PI / 360) * EnteredAngleNum;
//double ToF = Math.Pow(EnteredVelocityNum * Math.Sin(EnteredAngleRad) + (Math.Pow(EnteredVelocityNum,2)) * (Math.Pow(Math.Sin(EnteredAngleRad),2)) + 20 * Length * (Math.Sin(EnteredAngleRad)) , 0.5 ) / 10; //This is trying to use Sin^2(theta) and gives 3.---
double ToF = (EnteredVelocityNum * Math.Sin(EnteredAngleRad) + (Math.Pow((Math.Pow(EnteredVelocityNum, 2.0) * ((1.0 / 2.0) - ((1.0 / 2.0) * Math.Cos(2 * EnteredAngleRad))) + 20.0 * Length * (Math.Sin(EnteredAngleRad))), 0.5))) / 10.0; //This is trying to use Trig Identities and gives 4.06----
Console.WriteLine("The Flight Time is: " + ToF);
}
}
}
Careful of the line where you are doing this sort of thing....
((1 / 2) * Math.Cos(2 * EnteredAngleRad))
The 1 / 2 evaluates to 0 because the 1 and 2 are interpreted as integers. Try changing everything to doubles by using literals like 1.0 / 2.0.
And use double.Parse instead of int.Parse.
Maths is not my strong suit and I think I have something mixed up here but I cannot figure out what.
I'm just trying to populate 2 new coordinates given a number of variables and constants.
if I make Origin coordinate 5,5 and Destination coordinate 10,5, I can work out that distance =5 and that the bearing from Origin to Destination is 90 using these two functions:
private static double GetDistance(PointF point1, PointF point2)
{
double a = (double)(point2.X - point1.X);
double b = (double)(point2.Y - point1.Y);
return Math.Sqrt(a * a + b * b);
}
public static double GetBearing(PointF coord1, PointF coord2)
{
double result = 0.0;
result = Math.Atan2(coord2.X - coord1.X, coord2.Y - coord1.Y) * (180 / Math.PI); //- Math.Atan2(coord4.y - coord3.y, coord4.x - coord3.x))
if (result < 0)
{
result = result + 360;
}
return result;
}
What I want to be able to do given an offset Distance of xd=1 and an offset bearing of 180(ie directly opposite direction to the destination) is plot the location 4,5. I'd also like to be able to feed a different offset bearing in of say 90 and plot 5,6.
Here's what I've tried but I get completely nonsensical values.
public static PointF CalculateCoordinate(double Angle, double Distance)
{
PointF coord = new PointF(Convert.ToSingle(Distance * Math.Cos(Angle)), Convert.ToSingle(Distance * Math.Sin(Angle)));
return coord;
}
and CalculateCoordinate(GetBearing(Destination, Origin),1) to reverse the bearing directly 180. I've tried this CalculateCoordinate(90,1) to calculate an offset to the side but that's not working either.
Where have I gone wrong, I'm sure it's something pretty stupid and simple.
There's two mistakes that I can see. First, Atan2 takes the Y value for the first parameter and the X value for the second:
Math.Atan2(coord2.Y - coord1.Y, coord2.X - coord1.X) * (180 / Math.PI);
Secondly, you're converting from radians to degrees in GetBearing, but you're not converting Angle from degrees to radians inside CalculateCoordinate e.g:
Math.Cos(Angle * (Math.PI / 180))
I am looking to add a feature to a order entry system to show the distance in KM between the order location and assigned delivery van in real time.
The vans have a GPS Tracking system from High Point GPS, comes with an API to query driver location, returns in format of LAT/LONG, and location address if available.
Once I get the location I can use a web service to calculate the distance between the 2 locations, does anyone know what is the best way to get the distance between 2 locations using LAT/LONG for vehicle and address lookup for the delivery location?
You can use Google Maps to get Lat/Long of address
See answer by Thomas Clayson
How can I get latitude, longitude of a location programmatically or using a api
Then you can calculate the distance between the two sets of coordinates by using the Law of Cosines or the Haversine formula
See Law of Cosines
It depends on the other services you are already using. For example, we already use google maps to display the route, so we use their geocoding service to translate from an address to coordinates, as well as their distance service to compute distances.
Create two DbGeography instance for source and destination point (http://msdn.microsoft.com/en-us/library/system.data.spatial.dbgeography.distance(v=vs.110).aspx). Then use distance method of DbGeography for find the distance between two points.
For distance unit refer this post : System.Data.Spatial DbGeography.Distance units?
The simple answer you may find , is a simple formula :
Calculate distance between two points in google maps V3
var rad = function(x) {
return x * Math.PI / 180;
};
var getDistance = function(p1, p2) {
var R = 6378137; // Earth’s mean radius in meter
var dLat = rad(p2.lat() - p1.lat());
var dLong = rad(p2.lng() - p1.lng());
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) *
Math.sin(dLong / 2) * Math.sin(dLong / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d; // returns the distance in meter
};
using google maps api will be the best solution:
https://developers.google.com/maps/documentation/distancematrix/
I've done this but in Java, probably you can port it to c# with no much effort.
This is very accurate for distances shorter than 2000 kilometers, then it can vary a little bit from the real distance. This is due to the earth curvature. But for small distances you can assume it is plain with none or very small impact in the result.
Here is a link I found useful.
And another link, an implementation of Haversine in C#.
Hope it helps.
Best regards, Federico.
public String execute(String plat1, String plon1, String plat2, String plon2) {
String distance;
double lat1, lon1, lat2, lon2;
try{
lat1 = Double.parseDouble(plat1);
lon1 = Double.parseDouble(plon1);
lat2 = Double.parseDouble(plat2);
lon2 = Double.parseDouble(plon2);
} catch (Exception e){
lat1 = 0.0d;
lon1 = 0.0d;
lat2 = 0.0d;
lon2 = 0.0d;
}
//theta and distance
double theta = lon1 - lon2;
double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
//distance
dist = Math.acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
dist = dist * 1.609344;
//convert to meters
dist = dist * 1000;
//output in meters
distance = Double.toString(dist);
return distance;
}
private double deg2rad(double deg) {
return (deg * Math.PI / 180.0);
}
private double rad2deg(double rad) {
return (rad * 180.0 / Math.PI);
}
A little explanation:
(plat1, plon1) is lat and lng of point 1 or origin
(plat2, plon2) is lat and lng of point 2 or destination
the method "execute" is the one you call, it returns a string containing the distance in meters (conversion to other units can be done easily)
two assisting functions are declared as "deg2rad" and "rad2deg".
I'm trying to rotate a 3D object on its Z axis (up/down).
public void RotateY(float angle)
{
foreach (CoordinateVertices cv in this.GetAll<CoordinateVertices>())
{
for (int i = 0; i < cv.Coordinates.Length; i++)
{
Vector3 old = cv.Coordinates[i];
float theta = Math.Atan2(old.Y, old.X) + angle;
float rayon = Math.Sqrt(Math.Pow(old.X, 2) + Math.Pow(old.Y, 2));
cv.Coordinates[i] = new Vector3(Math.Cos(theta) * rayon, Math.Sin(theta) * rayon, old.Z);
}
}
}
The trigonometry is fairly simple, and it seems to work fine, but for some reason, my 3D object gets cut in half.
Does anybody have an idea of what's going on? I would have posted this on the maths StackExchange, but it might be a problem with my programming too, and the trigonometry is really simple.
Edit: The following is an alternative for the doing the same as the above. It took me a few minutes to realize the following solution is identical to the code initially posted.
It should look like this:
double Xnew = X * cos(theta) + Y * sin(theta);
double Ynew = Y * cos(theta) - X * sin(theta);
Or in your code:
public void RotateY(float angle)
{
foreach (CoordinateVertices cv in this.GetAll<CoordinateVertices>())
{
for (int i = 0; i < cv.Coordinates.Length; i++)
{
Vector3 old = cv.Coordinates[i];
float xnew = old.X * Math.Cos(angle) + old.Y * Math.Sin(angle);
float ynew = old.Y * Math.Cos(angle) - old.X * Math.Sin(angle);
cv.Coordinates[i] = new Vector3(xnew, ynew, old.Z);
}
}
}
The above code assumes you're rotating about the origin. If you're not rotating about the origin, you just need to translate to the origin, rotate, then translate back.
See here for more details: http://en.wikipedia.org/wiki/Transformation_matrix#Rotation
As has been noted, nothing wrong with your code. However, you may also be interested in using the Transform function (which can operate on your entire array of coordinates at once). Vector3.Transform (Vector3[], Matrix). You can get your rotation with a rotation matrix calculated for a given angle, theta, about any axis. I would expect this to be significantly faster for large numbers of points. (Less trig calculations, and possibly hardware acceleration)
Actually, the bug disappeared, out of nowhere. I went on to test some more values, and they worked. I went back to the same value as before, and it worked. This is ridiculous, it always happens to me.
What's the name for that? Bugs that disappear by themselves.