Rotate point along sphere X axis - c#

I have this formula to rotate around a sphere
double naX = o.Node.Angle.X;
double naY = o.Node.Angle.Y;
double x = o.DrawingPosition.X - 4.0 * Math.Cos(naX) * Math.Sin(naY);
double y = o.DrawingPosition.Y - 4.0 * Math.Sin(naX) * Math.Sin(naY);
double z = o.DrawingPosition.Z - 4.0 * Math.Cos(naY);
Where 4.0 is the radius to follow and o.DrawingPosition is the center
I want it to rotate along the transform x axis (I have a quaternion and a unit vector normalized for calculated for the Z -1 normal) but if I add offsets the angles won't match
naX += _rotationTicks;
naY += _rotationTicks;
For example, it will follow a infinite shaped trajectory, how can I calculate the correct rotation so it behaves like a perfect circle?
Edit:
I found this answer on Rotating body from spherical coordinates
But the main core difference is that both the XY rotation angles and the origins are arbitrary values, there is a forward vector calculated with a quaternion to determine facing like this:
var quat = System.Numerics.Quaternion.CreateFromYawPitchRoll((float)o.Node.Angle.X, (float)o.Node.Angle.Y, 0);
var dirVec = new Vector3(0, -1, 0).ToNumerics();
var downwards = quat.Multiply(dirVec); // it can be backwards, left, right, etc, changing the unit vector from dirVec
Thanks in advance.

Related

Finding points on a cylinder in 3d room c#

Example Image here
I am trying to find a way to calculate points on my cylinders top circle surface. My situation looks like this, I have a vector which is defining my cylinders direction in 3d room. Then I already calculated me a perpendicular vector with
Vector3.Cross(vector1, vector2)
Now I use the diameter/2 to calculate the point which is lying on the edge of the circular top surface of my cylinder. Now I want to rotate my vector always 90 degrees in order to get 4 points on the edge of the surface. All the 4 vectors defining them should be perpendicular to the cylinders direction. Can you help me how I can rotate the first perpendicular to achieve this?
I already tried:
Matrix4x4.CreateFromAxisAngle(vectorcylinderdirection, radiant)
Then I calculated again cross product but it doesnt work like I want to.
Edit:
public static void calculatePontsOnCylinder()
{
//Calculate Orthogonal Vector to Direction
Vector3 tCylinderDirection = new Vector3(1, 0, 0);
Vector3 tOrthogonal = Vector3.Cross(tCylinderDirection, new Vector3(-tCylinderDirection.Z,tCylinderDirection.X,tCylinderDirection.Y));
Vector3 tNormOrthogonal = Vector3.Normalize(tOrthogonal);
//Calculate point on surface circle of cylinder
//10mm radius
int tRadius = 10;
Vector3 tPointFinder = tNormOrthogonal * tRadius;
//tPointFinder add the cylinder start point
//not yet implemented
//now i need to rotate the vector always 90 degrees to find the 3 other points on the circular top surface of the cylinder
//don't know how to do this
// I thought this should do it
Matrix4x4.CreateFromAxisAngle(tCylinderDirection, (float)DegreeToRadian(90));
}
private static double DegreeToRadian(double angle)
{
return Math.PI * angle / 180.0;
}
In the picture you can see a example, the vector1 is what I need, always rotated 90 degrees and vector2 would be my cylinder direction vector
I possibly have found the correct formula:
Vector3 tFinal = Vector3.Multiply((float)Math.Cos(DegreeToRadian(90)), tPointFinder) + Vector3.Multiply((float)Math.Sin(DegreeToRadian(90)), Vector3.Cross(tCylinderDirection, tPointFinder));
Vector3 tFinal180 = Vector3.Multiply((float)Math.Cos(DegreeToRadian(180)), tPointFinder) + Vector3.Multiply((float)Math.Sin(DegreeToRadian(180)), Vector3.Cross(tCylinderDirection, tPointFinder));
Vector3 tFinal270= Vector3.Multiply((float)Math.Cos(DegreeToRadian(270)), tPointFinder) + Vector3.Multiply((float)Math.Sin(DegreeToRadian(270)), Vector3.Cross(tCylinderDirection, tPointFinder));
Interesting is that if I try it with (1,1,0) as cylinder direction it gives me correct directions but the length is different for 90 degrees and 270.
Here is the code that should solve your problem assuming that the input requirements are satisfied.
float zCutPlaneLocation = 20; // should not get bigger than cylinder length
float cylinderRadius = 100;
Vector3 cylinderCenter = new Vector3(0, 0, 0); // or whatever you got as cylinder center point, given as Vector3 since Point type is not defined
// will return 360 points on cylinder edge, corresponding to this z section (cut plane),
// another z section will give another 360 points and so on
List<Vector3> cylinderRotatedPointsIn3D = new List<Vector3>();
for (int angleToRotate = 0; angleToRotate < 360; angleToRotate++)
{
cylinderRotatedPointsIn3D.Add(GetRotatedPoint(zCutPlaneLocation, angleToRotate, cylinderRadius, cylinderCenter));
}
....
private static Vector3 GetRotatedPoint(
float zLocation, double rotationAngleInRadian, float cylinderRadius, Vector3 cylinderCenter)
{
Vector2 cylinderCenterInSection = new Vector2(cylinderCenter.X, cylinderCenter.Y);
float xOfRotatedPoint = cylinderRadius * (float)Math.Cos(rotationAngleInRadian);
float yOfRotatedPoint = cylinderRadius * (float)Math.Sin(rotationAngleInRadian);
Vector2 rotatedVector = new Vector2(xOfRotatedPoint, yOfRotatedPoint);
Vector2 rotatedSectionPointOnCylinder = rotatedVector + cylinderCenterInSection;
Vector3 rotatedPointOnCylinderIn3D = new Vector3(
rotatedSectionPointOnCylinder.X,
rotatedSectionPointOnCylinder.Y,
zLocation + cylinderCenter.Z);
return rotatedPointOnCylinderIn3D;
}
I just created a console app for this. First part of code should be added in main method.
Working with those matrices seems is not that easy. Also I am not sure if your solution works ok for any kind of angle.
Here the idea is that the rotated points from cylinder are calculated in a section of the cylinder so in 2D than the result is moved in 3D by just adding the z where the Z section was made on cylinder. I suppose that world axis and cylinder axis are on the same directions. Also if your cylinder gets along (increases) on the X axis, instead of Z axis as in example just switch in code the Z with X.
I attached also a picture for more details. This should work if you have the cylinder center, radius, rotation angle and you know the length of the cylinder so that you create valid Z sections on cylinder. This could get tricky for clockwise/counter clock wise cases but lets see how it works for you.
If you want to handle this with matrices or whatever else I think that you will end up having this kind of result. So I think that you cannot have "all" the rotated points in just a list for the entire cylinder surface, they would depend on something like the rotated points of a Z section on the cylinder.

What are 2D quaternions called (what should I search for more information)?

I stumbled on a working concept for a fast rotation & orientation system today, based on a two-term quaternion that represents either a rotation about the X axis (1,0,0) in the form w + ix, a rotation about the Y axis (0,1,0) in the form w + jy, or a rotation about the Z axis (0,0,1) in the form w + kz.
They're similar to complex numbers, but a) are half-angled and double-sided like all quaternions (they're simply quaternions with two of three imaginary terms zeroed out), and b) represent rotations about one of three 3D axes specifically.
My problem and question is...I can't find any representation of such a system online and have no idea what to search for. What are these complex numbers called? Who else has done something like this before? Where can I find more information on the path I'm headed down? It seems too good to be true and I want to find the other shoe before it drops on me.
Practical example I worked out (an orientation quaternion from Tait-Bryan angles):
ZQuat Y, YQuat P, XQuat R; // yaw, pitch, roll
float w = Y.W * P.W;
float x = -Y.Z * P.Y;
float y = Y.W * P.Y;
float z = Y.Z * P.W;
Quaternion O; // orientation
O.W = x * R.W + w * R.X;
O.X = y * R.W + z * R.X;
O.Y = z * R.W - y * R.X;
O.Z = w * R.W - x * R.X;
Quaternions in 2D would degenerate to just being a single component being no diferrent than an rotation angle. That's propably why you do not find anything. With quaternions you do f.e. not have the problem of gimbal lock, appearing when two rotation axes align because of rotation order. In normal 2D space you do not have more than a single rotation axis, so it has neither order (how do you sort a single element) and there are no axes to align. The lack of rotation axes in 2D is because you get a rotation axis when being perpendicular to two other axes.
This gives 3 axes for 3D:
X&Y=>Z
X&Z=>Y
Y&Z=>X
But only one for 2D:
X&Y=>Z

Find the point on a circle with given center point, radius, and degree

It's been 10 years since I did any math like this... I am programming a game in 2D and moving a player around. As I move the player around I am trying to calculate the point on a circle 200 pixels away from the player position given a positive OR negative angle(degree) between -360 to 360. The screen is 1280x720 with 0,0 being the center point of the screen. The player moves around this entire Cartesian coordinate system. The point I am trying trying to find can be off screen.
I tried the formulas on article Find the point with radius and angle but I don't believe I am understanding what "Angle" is because I am getting weird results when I pass Angle as -360 to 360 into a Cos(angle) or Sin(angle).
So for example I have...
1280x720 on a Cartesian plane
Center Point (the position of player):
let x = a number between minimum -640 to maximum 640
let y = a number between minimum -360 to maximum 360
Radius of Circle around the player: let r always = 200
Angle: let a = a number given between -360 to 360 (allow negative to point downward or positive to point upward so -10 and 350 would give same answer)
What is the formula to return X on the circle?
What is the formula to return Y on the circle?
The simple equations from your link give the X and Y coordinates of the point on the circle relative to the center of the circle.
X = r * cosine(angle)
Y = r * sine(angle)
This tells you how far the point is offset from the center of the circle. Since you have the coordinates of the center (Cx, Cy), simply add the calculated offset.
The coordinates of the point on the circle are:
X = Cx + (r * cosine(angle))
Y = Cy + (r * sine(angle))
You should post the code you are using. That would help identify the problem exactly.
However, since you mentioned measuring your angle in terms of -360 to 360, you are probably using the incorrect units for your math library. Most implementations of trigonometry functions use radians for their input. And if you use degrees instead...your answers will be weirdly wrong.
x_oncircle = x_origin + 200 * cos (degrees * pi / 180)
y_oncircle = y_origin + 200 * sin (degrees * pi / 180)
Note that you might also run into circumstance where the quadrant is not what you'd expect. This can fixed by carefully selecting where angle zero is, or by manually checking the quadrant you expect and applying your own signs to the result values.
I highly suggest using matrices for this type of manipulations. It is the most generic approach, see example below:
// The center point of rotation
var centerPoint = new Point(0, 0);
// Factory method creating the matrix
var matrix = new RotateTransform(angleInDegrees, centerPoint.X, centerPoint.Y).Value;
// The point to rotate
var point = new Point(100, 0);
// Applying the transform that results in a rotated point
Point rotated = Point.Multiply(point, matrix);
Side note, the convention is to measure the angle counter clockwise starting form (positive) X-axis
I am getting weird results when I pass Angle as -360 to 360 into a Cos(angle) or Sin(angle).
I think the reason your attempt did not work is that you were passing angles in degrees. The sin and cos trigonometric functions expect angles expressed in radians, so the numbers should be from 0 to 2*M_PI. For d degrees you pass M_PI*d/180.0. M_PI is a constant defined in math.h header.
I also needed this to form the movement of the hands of a clock in code. I tried several formulas but they didn't work, so this is what I came up with:
motion - clockwise
points - every 6 degrees (because 360 degrees divided by 60 minuites is 6 degrees)
hand length - 65 pixels
center - x=75,y=75
So the formula would be
x=Cx+(r*cos(d/(180/PI))
y=Cy+(r*sin(d/(180/PI))
where x and y are the points on the circumference of a circle, Cx and Cy are the x,y coordinates of the center, r is the radius, and d is the amount of degrees.
Here is the c# implementation. The method will return the circular points which takes radius, center and angle interval as parameter. Angle is passed as Radian.
public static List<PointF> getCircularPoints(double radius, PointF center, double angleInterval)
{
List<PointF> points = new List<PointF>();
for (double interval = angleInterval; interval < 2 * Math.PI; interval += angleInterval)
{
double X = center.X + (radius * Math.Cos(interval));
double Y = center.Y + (radius * Math.Sin(interval));
points.Add(new PointF((float)X, (float)Y));
}
return points;
}
and the calling example:
List<PointF> LEPoints = getCircularPoints(10.0f, new PointF(100.0f, 100.0f), Math.PI / 6.0f);
The answer should be exactly opposite.
X = Xc + rSin(angle)
Y = Yc + rCos(angle)
where Xc and Yc are circle's center coordinates and r is the radius.
Recommend:
public static Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles)
{
return Quaternion.Euler(angles) * (point - pivot) + pivot;
}
You can use this:
Equation of circle
where
(x-k)2+(y-v)2=R2
where k and v is constant and R is radius

import elliptical arc from dxf

I have a problem that made me pull my last hair of my head.
I'm struggling to reproduce an angled elliptical arc in
my c# winform application using data extracted from DXF.
Data as follows:
Centerpoint at X : 597,5;
Centerpoint at Y : 185;
Endpoint of major axis, relative to the center (X): 35,9651502358374;
Endpoint of major axis, relative to the center (Y): 60,0542085828599;
Ratio of minor axis to major axis : 0,35714285714286;
Start parameter : 4,78575772944812;
End parameter : 7,78061288491105;
The code:
float ex = 597,5; //Centerpoint at X
float ey = 185; //Centerpoint at Y
float exb = 35,9651502358374; //Endpoint of major axis (X)
float eyb = 60,0542085828599; //Endpoint of major axis (Y)
float EllipseRatio = 0,35714285714286;
double sa = 4,78575772944812; //Start parameter
double ea = 7,78061288491105; //End parameter
sa = double.Parse(exb.ToString()) * Math.Cos(sa) + //Now it's a Start angle
double.Parse(eyb.ToString()) * Math.Sin(sa);
ea = 2 * double.Parse(exb.ToString()) * Math.Cos(ea) + //Now it's a sweep angle
double.Parse(eyb.ToString()) * Math.Sin(ea);
double angle = Math.Atan(exb / eyb); //Rotation angle
Graphics ellipse = this.CreateGraphics();
ellipse.TranslateTransform(ex, ey); //So I can rotate at center
ellipse.RotateTransform(float.Parse(angle.ToString()));
ellipse.DrawArc(PreviewPen, (0 - exb), eyb, 2 * exb, 2 * eyb * EllipseRatio,
float.Parse(sa.ToString()), float.Parse(ea.ToString()));
It should look like this;
Instead it looks like this:
As You can see, all the shapes are ok, except the ellipse.
I just can't get it right. Eider the position is wrong, or the
orientation is wrong, size, shape, angle...
At some point i got close, but then my thinking engine just blew up.
I'm not using e.graphics.
Please help in details if you can.

How do I find rotation transformed 2D coordinates in XNA?

I'm making an XNA game and have run into a small problem figuring out a bit of vector math.
I have a class representing a 2D object with X and Y integer coordinates and a Rotation float. What I need is to have a Vector2 property for Position that gets and sets X and Y as a Vector2 that has been transformed using the Rotation float. This way I can just do something like;
Position += new Vector2((thumbstick.X * scrollSpeed), -(thumbstick.Y * scrollSpeed));
and the object will move in it's own upward direction, rather than the View's upward direction.
So far this is what I have...I think the set is right, but for += changes it needs a get as well and the answer just isn't coming to me right now... >.>
public Vector2 Position
{
get
{
// What goes here? :S
}
set
{
X = value.X * (int)Math.Cos(this.Rotation);
Y = value.Y * (int)Math.Cos(this.Rotation);
}
}
No, both are incorrect.
A 2D vector transforms like this:
x' = x*cos(angle) - y*sin(angle)
y' = x*sin(angle) + y*cos(angle)
where the angle is measured in radians, zero angle is along the positive x-axis, and increases in the counterclockwise direction as you rotate around the z-axis out of plane. The center of rotation is at the end of the vector being transformed, so imagine the vector with origin at (0,0), end at (x,y) rotation through an angle until it becomes a vector with origin at (0,0) and end at (x', y').
You can also use the Matrix helper methods to create a Z rotation matrix then multiply your vector by this to rotate it. Something like this:
Vector v1;
Matrix rot = Matrix.CreateRotationZ(angle);
Vector v2 = v1 * rot;
I think this is a bad idea. Keep all of your objects' X and Y co-ordinates in the same planes instead of each having their own axes. By all means have a Position and Heading properties and consider having a Move method which takes your input vector and does the maths to update position and heading.

Categories