So im trying to get a point on a sphere via an angle.
double X = Math.Cos(pitch * (Math.PI / 180));
double Y = Math.Sin(pitch * (Math.PI / 180)) * Math.Sin(yaw * (Math.PI / 180));
double Z = Math.Sin(pitch * (Math.PI / 180)) * Math.Cos(yaw * (Math.PI / 180));
I've tried this, but the point it outputs seems to be clamped to the XZ axis, and increasing/decreasing the yaw doesn't do anything to the point it spits out.
I cant figure out whats wrong with this code? Could someone help me identify the problem?
Related
I have a program which visualizes translation and rotation on a 3D space. I have no problem with the main code but after hours of testing i found out that the function which causes inaccuracies is the rotation on arbitrary axis.
My object contains array of points, and three vectors which is its local axes. I use rotation function with these axes. The function works well when my position is at the origin, but once the point is translated to other than the origin it shows slightly wrong rotation until the point is out of place.
I have used this website as my guide, please jump to the bottom of the page at 6.2 and see the function with 10 parameters. On the same page, there's a link to a sample usage of the process. I have confirmed that the problem lies with floating-point inaccuracy with this application.
The sample point I wish to rotate: ( 0, -9, 0)
The point that intersects the axis of rotation: ( 0, -10, 0)
The direction vector of the axis of rotation: < 1, 0, 0>
The angle of rotation: 2 degrees
For each loop, the current point is rotated by 2 degrees, and is repeated 20 times. The correct Y value for the first iteration is -9.0006, while in my case it gives -8.9945 and continuously fluctuates until the 5th or 6th iteration, then the correct value shows after those iterations.
Here's the rotation function, take note that Point is the point you wish to rotate, AxisPoint is the point that intersects the axis of rotation, AxisDirection is the direction vector parallel to the axis of rotation, and Degrees is the amount of angle to rotate:
private static Vector3d RotateArbitrary(Vector3d Point, Vector3d AxisPoint, Vector3d AxisDirection, double Degrees)
{
return new Vector3d(
((AxisPoint.X * (Math.Pow(AxisDirection.Y, 2) + Math.Pow(AxisDirection.Z, 2)) - AxisDirection.X * (AxisPoint.Y * AxisDirection.Y + AxisPoint.Z * AxisDirection.Z - AxisDirection.X * Point.X - AxisDirection.Y * Point.Y - AxisDirection.Z * Point.Z)) * (1 - Math.Cos(MathHelper.DegreesToRadians(Degrees))) + Point.X * Math.Cos(MathHelper.DegreesToRadians(Degrees)) + (-AxisPoint.Z * AxisDirection.Y + AxisPoint.Y * AxisDirection.Z - AxisDirection.Z * Point.Y + AxisDirection.Y * Point.Z) * Math.Sin(MathHelper.DegreesToRadians(Degrees))),
((AxisPoint.X * (Math.Pow(AxisDirection.X, 2) + Math.Pow(AxisDirection.Z, 2)) - AxisDirection.Y * (AxisPoint.X * AxisDirection.X + AxisPoint.Z * AxisDirection.Z - AxisDirection.X * Point.X - AxisDirection.Y * Point.Y - AxisDirection.Z * Point.Z)) * (1 - Math.Cos(MathHelper.DegreesToRadians(Degrees))) + Point.Y * Math.Cos(MathHelper.DegreesToRadians(Degrees)) + (AxisPoint.Z * AxisDirection.X - AxisPoint.X * AxisDirection.Z + AxisDirection.Z * Point.X - AxisDirection.X * Point.Z) * Math.Sin(MathHelper.DegreesToRadians(Degrees))),
((AxisPoint.X * (Math.Pow(AxisDirection.X, 2) + Math.Pow(AxisDirection.Y, 2)) - AxisDirection.Z * (AxisPoint.X * AxisDirection.X + AxisPoint.Y * AxisDirection.Y - AxisDirection.X * Point.X - AxisDirection.Y * Point.Y - AxisDirection.Z * Point.Z)) * (1 - Math.Cos(MathHelper.DegreesToRadians(Degrees))) + Point.Z * Math.Cos(MathHelper.DegreesToRadians(Degrees)) + (-AxisPoint.Y * AxisDirection.X + AxisPoint.X * AxisDirection.Y - AxisDirection.Y * Point.X + AxisDirection.X * Point.Y) * Math.Sin(MathHelper.DegreesToRadians(Degrees)))
);
}
I have already tried both float and double data type, the result is still the same, any solutions you can offer, even a change in method of rotation, I'm all open. Please help.
Due to my lengthy web searches, I finally arrived to the conclusion that I should use Quaternions. Using the current method, I found out that excessive operations on floating point variables will increase round errors. Using Quaternions was simpler and cleaner.
Here's the code if anyone is interested:
private static Vector3 RotateArbitrary(Vector3 Point, Vector3 AxisPoint, Vector3 AxisDirection, float Radians)
{
return Vector3.Add(Vector3.Transform(Vector3.Subtract(Point, AxisPoint), Quaternion.FromAxisAngle(AxisDirection, Radians)), AxisPoint);
}
Take note that the the Point was translated first such that the AxisPoint is at the origin, with that, rotations can be done. The result is then translated to its original position.
I am struggling with a situation, where I want to draw a circle with GDI+ and some points on it (drawn as smaller circles), but the circle seems to be noncircular. By implementing scaling and zero point shifting, I zoom into the points and the circle, and find the points not lying exactly on the circle.
When I add a 'discrete' circle drawn with line segments, this circle does fit the points very well, if enough segments are used. Since the math is the same, I think that roundoff errors in my code can not be the cause of the circle deviations (although probably in the implementation of DrawEllipse).
In fact the deviations are biggest on 45/135/225/315 degrees.
I made a small project reproducing the effect with a slightly different setup: I draw multiple circles with their origins lying on an other circle with its center on the center of the form with the same radius. If everything goes well all circles shoud touch the center of the form. But with big radii like 100'000, they dont pass throug the center anymore, but miss it by a screendistance of maybe 15 pixel.
To reproduce the situation make a new c# project, put on form1 button1, and call the function Draw() from it:
private void Draw()
{
Graphics g = this.CreateGraphics();
g.Clear(this.BackColor );
double hw = this.Width / 2;
double hh = this.Height / 2;
double scale = 100000;
double R = 1;
for (int i = 0; i < 12; i++)
{
double angle = i * 30;
double cx = R * Math.Cos(angle * Math.PI / 180);
double cy = R * Math.Sin(angle * Math.PI / 180);
g.DrawEllipse(new Pen(Color.Blue, 1f), (float)(hw - scale * (cx + R)), (float)(hh + scale * (cy - R)), (float)(2 * R * scale), (float)(2 * R * scale));
g.DrawLine(Pens.Black, new Point(0, (int)hh), new Point(this.Width, (int)hh));
g.DrawLine(Pens.Black, new Point((int)hw, 0), new Point((int)hw, this.Height));
double r = 3;
g.DrawEllipse(new Pen(Color.Green, 1f), (float)(hw - r), (float)(hh - r), (float)(2 * r), (float)(2 * r));
//Pen magpen = new Pen(Color.Magenta, 1);
//double n = 360d / 1000;
//for (double j = 0; j < 360; j += n)
//{
// double p1x = R * Math.Cos(j * Math.PI / 180) + cx;
// double p1y = R * Math.Sin(j * Math.PI / 180) + cy;
// double p2x = R * Math.Cos((j + n) * Math.PI / 180) + cx;
// double p2y = R * Math.Sin((j + n) * Math.PI / 180) + cy;
// g.DrawLine(magpen, (float)(hw - scale * p1x), (float)(hh + scale * p1y), (float)(hw - scale * p2x), (float)(hh + scale * p2y));
//}
}
}
use the variable scale from 100 to 100'000 to see the effect: The circles don't touch the origin anymore, but wobble around it. If you uncomment the commented lines you can see, that the magenta 'discrete' circle performs much better.
Since using 'discrete' circles and arcs is a performance killer, I am looking for a way to draw better circles with GDI+.
Any ideas, suggestions?
GDI+ (at least in its native version) doesn't draw ellipses: it uses the cubic Bezier approximation, as described here and here.
That is, instead of
c = cos(angle);
s = sin(angle);
x = c * radius;
y = s * radius;
or, for an ellipse (a & b as semi major and semi minor axes in some order)
x = c * a;
y = s * b;
it uses
K = (sqrt(2) - 1) * 4.0 / 3;
t = angle * 0.5 / pi;
u = 1 - t;
c = (u * u * u) * 1 + (3 * u * u * t) * 1 + (3 * u * t * t) * K + (t * t * t) * 0;
s = (u * u * u) * 0 + (3 * u * u * t) * K + (3 * u * t * t) * 1 + (t * t * t) * 1;
(for angle in the range [0, pi/2]: other quadrants can be calculated by symmetry).
g.DrawArc(new Pen(Color.Blue, 1f), (float)((hw) - R * scale), -(float)((2 * R * scale) - hh), (float)(2 * R * scale), (float)(2 * R * scale), 0, 360);
Well I got somewhat precise results with this method.However this is only a sample.
I need to calculate Longitude and Latitude based on an old Longitude and Latitude, with distance and direction from that point.
From this link: http://www.movable-type.co.uk/scripts/latlong.html
I got these Formulae:
newLatitude = Math.Asin(Math.Sin(oldLatitude) * Math.Cos(distanceTravelled / earthRadius) + Math.Cos(oldLatitude) * Math.Sin(distanceTravelled / earthRadius) * Math.Cos(currentDirection));
newLongitude = oldLongitude + Math.Atan2(Math.Sin(currentDirection) * Math.Sin(distanceTravelled / earthRadius) * Math.Cos(oldLatitude), Math.Cos(distanceTravelled / earthRadius) - Math.Sin(oldLatitude) * Math.Sin(oldLatitude));
I have Acceleration e.g. 0.1 m/sec2
time travelled: Calculated from current time - start time.
Then I calculate the Distance travelled:
distanceTravelled = distanceTravelled/1000;
I also have movement of direction in degrees: e.g. 90 degree. (East)
But I am getting Error in new Latitude see-image:
Do I have to enter direction in Radian?
Distance in KM instead of meter?
Please help me get the right Latitude?
I found at the solution.
I was using degree and decimal of latitude and longitude in above formulae.
We have to use Radians
so convert Latitude, Longitude and Direction to Radians:
oldLatitude = Math.PI * oldLatitude / 180;
oldLongitude = Math.PI * oldLongitude / 180;
currentDirection = Math.PI * currentDirection / 180.0;
then convert new Longitude and latitude from Radians to Degree again
newLatitude = 180 * newLatitude / Math.PI;
newLongitude = 180 * newLongitude / Math.PI;
How to turn a point3d array from Cartesian coordinates into Spherical coordinate system (assuming its geometric center is 0,0,0 in spherical system)?
Copying the formula from Wikipedia, apply this to each entry in the array:
r = Math.Sqrt(p.X*p.X + p.Y*p.Y + p.Z*p.Z);
if (r == 0) {
theta = 0;
phi = 0;
} else {
theta = Math.Acos(p.Z/r);
phi = Math.Atan2(p.Y, p.X);
}
Yes, it's completly possible. So look here Spherical coordinates and here Spherical Coordinates in C#.
You can achieve what do you want reading these articles. I don't find any problem. So please, if there is something you don't understand comment.
Here is some code:
public Point3 Spherical(float r, float theta, float phi)
{
Point3 pt = new Point3();
float snt = (float)Math.Sin(theta * Math.PI / 180);
float cnt = (float)Math.Cos(theta * Math.PI / 180);
float snp = (float)Math.Sin(phi * Math.PI / 180);
float cnp = (float)Math.Cos(phi * Math.PI / 180);
pt.X = r * snt * cnp;
pt.Y = r * cnt;
pt.Z = -r * snt * snp;
pt.W = 1;
return pt;
}
I have two functions that are intended to contain angles between (-180,180] and (-π,π]. The intent is that given any angle from -inf to +inf it will retain the equivalent angle in the intervals specified. For example the angle for 1550° is 110°.
public double WrapBetween180(double angle)
{
return angle - 360d * Math.Round(angle / 360d, MidpointRounding.AwayFromZero);
}
public double WrapBetweenPI(double angle)
{
const double twopi = 2d * Math.PI;
return angle - twopi * Math.Round(angle / twopi, MidpointRounding.AwayFromZero);
}
which yields the following results
WrapBetween180(-180) = -180
WrapBetween180( 180) = 180
WrapBetweenPI(-Math.PI) = Math.PI
WrapBetweenPI( Math.PI) = -Math.PI
none of which is what I want. What I wanted is:
WrapBetween180(-180) = 180
WrapBetween180( 180) = 180
WrapBetweenPI(-Math.PI) = Math.PI
WrapBetweenPI( Math.PI) = Math.PI
I tryied playing around with the rounding methods, but still cannot get the desired results. The problem is pronounced because sometimes the angles I deal with are only approximately close to -π or π and I am getting discontinuities it my results.
Any suggestions on how to best implement angle wrapping functions with non-inclusive low limit and inclusive high limits?
For the angle in degrees, if x is between -180 and 180, then 180 - x is between 0 and 360. What you want is equivalent to asking that 180 - x is between 0 (inclusive), and 360 (exclusive). So, as soon as 180 - x reaches 360, we want to add 360 to the angle. This gives us:
return angle + 360d * Math.Floor((180d - angle) / 360d);
Same thing for the angle in radians:
return angle + twopi * Math.Floor((Math.PI - angle) / twopi);
It does not address the rounding issue, but here is how I would to what you want to do :
private static double ConvertAngle(double angle)
{
bool isNegative = angle < 0;
if (isNegative)
angle *= -1;
angle = angle % 360;
if (isNegative)
angle = -1 * angle + 360;
if (angle > 180)
angle = (angle - 360);
return angle;
}
Note: This way supposes you want "behind" to be 180 degrees, not -180 degrees.
Isn't this a case for a modulo operation?
private double Wrap180(double value)
{
// exact rounding of corner values
if (value == 180) return 180.0;
if (value == -180) return 180.0;
// "shift" by 180 and use module, then shift back.
double wrapped = ((Math.Abs(value) + 180.0) % 360.0) - 180.0;
// handle negative values correctly
if (value < 0) return -wrapped;
return wrapped;
}
It passes this tests
Assert.AreEqual(170.0, wrap(-190.0));
Assert.AreEqual(180.0, wrap(-180.0));
Assert.AreEqual(-170.0, wrap(-170.0));
Assert.AreEqual(0.0, wrap(0.0));
Assert.AreEqual(10.0, wrap(10.0));
Assert.AreEqual(170.0, wrap(170.0));
Assert.AreEqual(180.0, wrap(180.0));
Assert.AreEqual(-170.0, wrap(190.0));