Rotating 3D scatter plot data in WPF not working as expected - c#

I have followed the model presented in this article for displaying scatter plot data in WPF. I can easily rotate the image in the view matrix but I need to rotate the raw data points and do a least squares fit of the z-axis values to the z=0 plane. I only need to rotate the data 5-20 degrees so I don't think I need quaternions to avoid gimble lock. I have tried the following methods and have also tried translating the data to the origin before rotating but it has not worked as expected. The RotateX method seems to work but the other 2 methods seem to squish all the data together either in the y axis or the z axis. I've checked the formulas with about 10 different sites and can't find any errors but the results still don't make sense.
public static Point3D RotateAboutX(Point3D pt1, double aX)
{
double angleX = 3.1415926 * aX / 180;
double x2 = pt1.X;
double y2 = (pt1.Y * Math.Cos(angleX)) - (pt1.Z * Math.Sin(angleX));
double z2 = (pt1.Y * Math.Sin(angleX)) + (pt1.Z * Math.Cos(angleX));
return new Point3D(x2, y2, z2);
}
public static Point3D RotateAboutY(Point3D pt1, double aY)
{
double angleY = 3.1415926 * aY / 180;
double x2 = (pt1.X * Math.Cos(angleY)) - (pt1.Z * Math.Sin(angleY));
double y2 = pt1.Y;
double z2 = (pt1.X * Math.Sin(angleY)) + (pt1.Z * Math.Cos(angleY));
return new Point3D(x2, y2, z2);
}
public static Point3D RotateAboutZ(Point3D pt1, double aZ)
{
double angleZ = 3.1415926 * aZ / 180;
double x2 = (pt1.X * Math.Cos(angleZ)) - (pt1.Y * Math.Sin(angleZ));
double y2 = (pt1.X * Math.Sin(angleZ)) + (pt1.Y * Math.Cos(angleZ));
double z2 = pt1.Z;
return new Point3D(x2, y2, z2);
}

I found my own error. The mistake is in the RotateAboutY() method above. The correct method is like this...
public static Point3D RotateAboutY(Point3D pt1, double aY)
{
double angleY = 3.1415926 * aY / 180;
double x2 = (pt1.Z * Math.Sin(angleY)) + (pt1.X * Math.Cos(angleY));
double y2 = pt1.Y;
double z2 = (pt1.Z * Math.Cos(angleY)) - (pt1.X * Math.Sin(angleY));
return new Point3D(x2, y2, z2);
}
The short treatment of this topic can be found here with the correct formulas. There is a more detailed explanation of this topic on Kirupa.com where the correct formulas are also included.

Related

How to calculate coordinate X meters away from a point but towards another in C#

Let's say I have 2 coordinates that are ~222.33 meters away from each other :
A: 49.25818, -123.20626
B: 49.25813, -123.2032
Those 2 points makes a segment.
How can I calculate the coordinate of point Z that is X meters away from either A or B but towards the other point?
I already know the distance between my 2 points using System.Device.Location library.
GeoCoordinate A = new GeoCoordinate(49.25818, -123.20626);
GeoCoordinate B = new GeoCoordinate(49.25813, -123.2032);
var distanceInMeters = A.GetDistanceTo(B);
// distanceInMeters = 222.33039783713738
I'm looking for something like this:
GeoCoordinate GetPointTowards(GeoCoordinate fromPoint, GeoCoordinate towardPoint, double distanceInMeter) {
[???]
}
I think I may need the bearing or something to be able to get the new point location.
Most examples I've found are for iOS, Android or GMaps with specific libraries..
Here's an outline of how I would do it. With this approach, there is no need to explicitly deal with the difference in units between coordinates and distances because taking the ratio of target to total distance eliminates the unit.
totalDistance = distance in meters between point A and point B.
targetDistance = distance in meters to travel from point A to point B
ratio = targetDistance / totalDistance
diffX = B.X - A.X
diffY = B.Y - A.Y
targetX = A.X + (ratio * diffX)
targetY = A.Y + (ratio * diffY)
But this wouldn't handle the edge cases like being at 179 degrees longitude and adding 3 degrees which would put you at -178 longitude.
This is my code converted to C# from http://www.movable-type.co.uk/scripts/latlong.html. The fraction is from 0 to 1 and is the fraction along the distance from the first point to the second point the output position will be. You could always modify it to take a straight distance value.
public static (double Lat, double Lon) IntermediatePoint((double Lat, double Lon) StartPoint, (double Lat, double Lon) EndPoint, double fraction)
{
if (fraction < 0 || fraction > 1)
throw new ArgumentOutOfRangeException();
double angDist = Distance(StartPoint, EndPoint) / radius;
double lat1 = StartPoint.Lat * (Math.PI / 180);
double lon1 = StartPoint.Lon * (Math.PI / 180);
double lat2 = EndPoint.Lat * (Math.PI / 180);
double lon2 = EndPoint.Lon * (Math.PI / 180);
double a = Math.Sin((1 - fraction) * angDist) / Math.Sin(angDist);
double b = Math.Sin(fraction * angDist) / Math.Sin(angDist);
double x = a * Math.Cos(lat1) * Math.Cos(lon1) + b * Math.Cos(lat2) * Math.Cos(lon2);
double y = a * Math.Cos(lat1) * Math.Sin(lon1) + b * Math.Cos(lat2) * Math.Sin(lon2);
double z = a * Math.Sin(lat1) + b * Math.Sin(lat2);
double lat3 = Math.Atan2(z, Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2)));
double lon3 = Math.Atan2(y, x);
return (lat3 * (180 / Math.PI), lon3 * (180 / Math.PI));
}
public static double Distance((double Lat, double Lon) point1, (double Lat, double Lon) point2)
{
double φ1 = point1.Lat * (Math.PI / 180.0);
double φ2 = point2.Lat * (Math.PI / 180.0);
double Δφ = (point2.Lat - point1.Lat) * (Math.PI / 180.0);
double Δλ = (point2.Lon - point1.Lon) * (Math.PI / 180.0);
double a = Math.Sin(Δφ / 2) * Math.Sin(Δφ / 2) + Math.Cos(φ1) * Math.Cos(φ2) * Math.Sin(Δλ / 2) * Math.Sin(Δλ / 2);
double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
return radius * c;
}
radius is a constant representing the Earth's radius in meters.

c# How to get XYZ coordinates from horizontal and vertical degrees

I've been trying to get this code to work properly for the past hour and I almost got it complete. Everything works, but the float verticalDegrees.
In Detail Question: How do I get this code working so it returns XYZ from horizontal degrees, vertical degrees, radius and origin?
This link helped me, but it's missing Z coordinate
This is what I have so far:
private float[] DegreesToXYZ(float horizonalDegrees, float verticalDegrees, float radius, float[] origin)
{
float[] xyz = new float[3];
double radiansH = horizonalDegrees * Math.PI / 180.0;
double radiansV = verticalDegrees * Math.PI / 180.0;
xyz[1] = (float)Math.Cos(radiansH) * radius + origin[1];
xyz[0] = (float)Math.Sin(-radiansH) * radius + origin[0];
double deltaXY = Math.Sqrt(origin[0] * origin[0] + origin[1] * origin[1]);
xyz[2] = (float)Math.Atan2(origin[2], deltaXY);
return xyz;
}
This method converts spherical coordinates into cartesian coordinates:
private static double[] DegreesToXYZ(double radius, double theta, double phi, double[] originXYZ)
{
theta *= Math.PI / 180;//converting degress into radians
phi *= Math.PI / 180;//converting degress into radians
double[] xyz = new double[3];
xyz[0] = originXYZ[0] + radius * Math.Cos(theta) * Math.Sin(phi);//x
xyz[1] = originXYZ[1] + radius * Math.Sin(theta) * Math.Sin(phi);//y
xyz[2] = originXYZ[2] + radius * Math.Cos(phi);//z
return xyz;
}
Where theta is the 'horizontal' or 'azimuth' angle (angle from the x-axis in the x-y plane), and phi is the 'inclination' (angle from the positive
z axis) or 'vertical' angle.The radius is the distance to a given point (x,y,z) in cartesian coordinates.
Seems you have spherical coordinates and want to get Cartesian coordinates. In this case
x = x0 + r * Cos(fi) * Sin(theta)
y = y0 + r * Sin(fi) * Sin(theta)
z = z0 + r * Cos(theta)
Here fi is your "horizontal angle", theta is "vertical angle", x0..z0 are origin coordinates

Calculating a coordinate in an angle and distance from a coordinate

I wrote this extension method for an IPoint.
public static IPoint Offset(this IPoint point, double angle, double distanceInMeters)
{
var radians = Math.PI * angle / 180;
var distanceX = distanceInMeters * Math.Cos(radians);
var distanceY = distanceInMeters * Math.Sin(radians);
var earthRadius = 6371000;
var y = point.Y + ((distanceY / earthRadius) * 180 / Math.PI);
var x = point.X + ((distanceX / (earthRadius * Math.Cos(y * 180 / Math.PI))) * 180 / Math.PI);
return new Point(x, y);
}
It works fine when I am putting in an angle of 0, 90, 180 and 270, then it return a coordinate at the given distance away from the starting point. But when I am starting to go in an angle that do not point exactly North, East etc. Iam getting wrong distances.
Where do I go wrong ?
Alternative is there some libraries to use?
Try this formula. As I consider you should transfer latitude and longitude to radians and then back to degrees.
public static Point Offset(this Point point, double angle, double distanceInMeters)
{
double rad = Math.PI * angle / 180;
double xRad = Math.PI * point.X / 180; // convert to radians
double yRad = Math.PI * point.Y / 180;
double R = 6378100; //Radius of the Earth in meters
double x = Math.Asin(Math.Sin(xRad) * Math.Cos(distanceInMeters/ R)
+ Math.Cos(xRad) * Math.Sin(distanceInMeters/ R) * Math.Cos(rad));
double y = yRad + Math.Atan2(Math.Sin(rad) * Math.Sin(distanceInMeters/ R) * Math.Cos(xRad), Math.Cos(distanceInMeters/ R) - Math.Sin(xRad) * Math.Sin(x));
x = x * 180 / Math.PI; // convert back to degrees
y = y * 180 / Math.PI;
return new Point(x, y);
}

C# Rotate 2 controls around a center point at the defaul angle in WinForms

I was trying to rotate 2 windows form button as in the following image:
During their rotation, the distance between them should be 0 and when you click a label, they should "rotate" 90 degree, as like:
if (red is up and black is down)
{
red will be down and black will be up;
}
else
{
red will be up and black will be down;
}
I used this method to return the desired point "location", but i couldn't obtain the desired rotation "effect":
public static Point Rotate(Point point, Point pivot, double angleDegree)
{
double angle = angleDegree * Math.PI / 180;
double cos = Math.Cos(angle);
double sin = Math.Sin(angle);
int dx = point.X - pivot.X;
int dy = point.Y - pivot.Y;
double x = cos * dx - sin * dy + pivot.X;
double y = sin * dx + cos * dy + pivot.X;
Point rotated = new Point((int)Math.Round(x), (int)Math.Round(y));
return rotated;
}
like in my comment it has to look like this:
private Point calculateCircumferencePoint(double radoffset, Point center, double radius)
{
Point res = new Point();
double x = center.X + radius * Math.Cos(radoffset);
double y = center.Y + radius * Math.Sin(radoffset);
res.X = (int)x;
res.Y = (int)y;
return res;
}
here is also a test application: https://github.com/hrkrx/TestAppCircularRotation
EDIT: for a second button you just need to set the initial offset to Math.PI;
EDIT2: To rotate the buttons like they cross (like the path of an 8) you need to set the radius to Sin(radoffset) or Cos(radoffset)

calculate Point by point, angle and distance on a map

I have a mission to calculate point on a Map. I have the start point, the angle and the distance from the point. How can I do it ? I search a lot I found something but it doesn't work good - I mean it it doesn't calculate the correct point. Thank's all.
My try :
public Point MesPoint(double x1, double x2, double y1, double y2, double distance, double x) // X is the angle
{
double xEndP, yEndP;
var angularDistance = distance / c_EarthRadiusInKilometers; // angular distance in radians
var lat = ToRadian(y2);
var lon = ToRadian(x2);
var angel = ToRadian(x);
double latRadians = Math.Asin((Math.Sin(lat) * Math.Cos(angularDistance)) + (Math.Cos(lat) * Math.Sin(angularDistance) * Math.Cos(angel)));
double lngRadians = Math.Atan2(
Math.Sin(angel) * Math.Sin(angularDistance) * Math.Cos(lat),
Math.Cos(angularDistance) - (Math.Sin(lat) * Math.Sin(latRadians)));
double lon1 = (lon + lngRadians + Math.PI) % (2 * Math.PI) - Math.PI; // normalise to -180..+180º
yEndP = ToDegrees(latRadians);
xEndP = ToDegrees(lon1);
return (new Point(xEndP, yEndP));
}

Categories