What is the Goal?:
I want to know the new Coordinates of a point after rotating the 3D-Object (Cuboid), around the anchorpoint (x,y & z) on the opposite side.
What i did:
I tried to calculate the position with the following function. I had to convert doubles to floats , because of the Autodesk Inventor API. Note: Vector is the difference from the origin /anchorpoint to the designated point.
Vector3 coordinateTransformation(Vector3 vector, float r_x, float r_y, float r_z, Vector3 origin)
{
vector.X = vector.X; //Just for demonstration
vector.Y = vector.Y * Convert.ToSingle(Math.Cos(DegreesToRadians(r_x))) - vector.Z * Convert.ToSingle(Math.Sin(DegreesToRadians(r_x)));
vector.Z = vector.Y * Convert.ToSingle(Math.Sin(DegreesToRadians(r_x))) + vector.Z * Convert.ToSingle(Math.Cos(DegreesToRadians(r_x)));
vector.X = vector.X * Convert.ToSingle(Math.Cos(DegreesToRadians(r_y))) + vector.Z * Convert.ToSingle(Math.Sin(DegreesToRadians(r_y)));
vector.Y = vector.Y; //Just for demonstration
vector.Z = vector.Z * Convert.ToSingle(Math.Cos(DegreesToRadians(r_y))) - vector.X * Convert.ToSingle(Math.Sin(DegreesToRadians(r_y)));
vector.X = vector.X * Convert.ToSingle(Math.Cos(DegreesToRadians(r_z))) - vector.Y * Convert.ToSingle(Math.Sin(DegreesToRadians(r_z)));
vector.Y = vector.X * Convert.ToSingle(Math.Sin(DegreesToRadians(r_z))) + vector.Y * Convert.ToSingle(Math.Cos(DegreesToRadians(r_z)));
vector.Z = vector.Z; //Just for demonstration
vector.X = Math.Abs(vector.X) + origin.X;
vector.Y = Math.Abs(vector.Y) + origin.Y;
vector.Z = Math.Abs(vector.Z) + origin.Z;
return vector;
}
Somehow the object does not get placed on the correct place.
Next step: On the internet i found a website which does the correct transformation.Casio Website
If i manually set vector to the calculated point on the website, everything else works fine. So i somehow have to get the exact same calculation into my code.
If you need further information, feel free to comment!
Edit:
1 : I want to place 2 Objects (e.g. Cuboids) within 1 Assembly Group in Inventor. Every Object as an anchorpoint (origin) and on the opposite side a connection point, which is described as the delta between the anchorpoint and the connection point itself. At first one Object is placed on the origin coordinates, followed by a rotation around the anchorpoint (degrees). After that the connection point coordinates of Object 1 have changed. In the next step i want to place Object 2 with its origin on the connection point of Object 1, while Object 2 has the same rotation as Object 1.
2 : Inventor uses a right-handed coordinate system
When you apply rotation to a vector manually, you'd need to update all the components (X, Y and Z) at once as follows.
Vector3 coordinateTransformation(Vector3 vector, float r_x, float r_y, float r_z, Vector3 origin)
{
// In the rotation around X axis below, `Y relies on Z` and `Z relies on Y`. So both must be updated simultaneously.
vector = new Vector3(
vector.X,
vector.Y * Convert.ToSingle(Math.Cos(DegreesToRadians(r_x))) - vector.Z * Convert.ToSingle(Math.Sin(DegreesToRadians(r_x))),
vector.Y * Convert.ToSingle(Math.Sin(DegreesToRadians(r_x))) + vector.Z * Convert.ToSingle(Math.Cos(DegreesToRadians(r_x)))
);
vector = new Vector3(
vector.X * Convert.ToSingle(Math.Cos(DegreesToRadians(r_y))) + vector.Z * Convert.ToSingle(Math.Sin(DegreesToRadians(r_y))),
vector.Y,
vector.Z * Convert.ToSingle(Math.Cos(DegreesToRadians(r_y))) - vector.X * Convert.ToSingle(Math.Sin(DegreesToRadians(r_y)))
);
vector = new Vector3(
vector.X * Convert.ToSingle(Math.Cos(DegreesToRadians(r_z))) - vector.Y * Convert.ToSingle(Math.Sin(DegreesToRadians(r_z))),
vector.X * Convert.ToSingle(Math.Sin(DegreesToRadians(r_z))) + vector.Y * Convert.ToSingle(Math.Cos(DegreesToRadians(r_z))),
vector.Z
);
vector.X = Math.Abs(vector.X) + origin.X;
vector.Y = Math.Abs(vector.Y) + origin.Y;
vector.Z = Math.Abs(vector.Z) + origin.Z;
return vector;
}
Appendix: Use of Matrix4x4
As #JonasH suggests, it's a good idea to use reliable libraries, if there are.
Since, row-vectors are used in the .NET world (while your implementation is based on column-vectors), X->Y->Z rotations can be written by straightforward matrices multiplications as follows.
Vector3 coordinateTransformation(Vector3 vector, float r_x, float r_y, float r_z, Vector3 origin)
{
var mat = Matrix4x4.CreateRotationX(DegreesToRadians(r_x))
* Matrix4x4.CreateRotationY(DegreesToRadians(r_y))
* Matrix4x4.CreateRotationZ(DegreesToRadians(r_z));
vector = Vector3.Transform(vector, mat);
vector.X = Math.Abs(vector.X) + origin.X;
vector.Y = Math.Abs(vector.Y) + origin.Y;
vector.Z = Math.Abs(vector.Z) + origin.Z;
return vector;
}
Do not mess around with vectors and angled by hand. Use some library for your vector functions and use matrices to do your transformations. For example System.Numerics or Math.Net.Numerics.
Assuming you have an euler angle to start with you can use CreateFromYawPitchRoll to create your rotation matrix. If you want to rotate around a specific point you just subtract your rotation center from all your points, apply the rotation and move the points back. This can all be done by just multiplying the transformation matrices:
var totalTransform = Matrix4x4.CreateTranslation(-rotationCenter) *
Matrix4x4.CreateFromYawPitchRoll(yawInRadians, pitchInRadians, rollInRadians) *
Matrix4x4.CreateTranslation(rotationCenter);
to apply the resulting transform you just call Vector3.Transform to produce a new, transformed vector.
This will all be a bit easier if you have some introduction to linear algebra. It is also common to do things like applying the transforms in the wrong order or something, and sometimes it is easiest to just try some different things until you get it right. I would also note that rotations are just hard to understand. I tend to prefer quaternions over eutler angles, not because the math is easier to understand, but since there are methods like CreateFromAxisAngle, that I can understand.
Related
The perimeter coordinates of the non-tilted circles, like the image above, were obtained with the following code.
//c=Center
//r=radius
//i=angle
Vector3 FindPoint(Vector3 c, float r, int i)
{
return c + Quaternion.AngleAxis(1.0f * i, Vector3.forward) * (Vector3.right * r);
}
//Example of securing coordinates
for(int i=0;i<360;i++)
{
point[i] = FindPoint(center, radius, i);
}
But, as in the image above, I need to get the circumference coordinates for the circles that are tilted in the x-axis.
How do you know the three-dimensional coordinates of the circumference of a tilted circle when you know the origin and radius and the tilted values along the x-axis?
From unity documentation:
Unlike Vector3.forward, Transform.forward moves the GameObject while also considering its rotation.
So, you can replace this line:
return c + Quaternion.AngleAxis(1.0f * i, Vector3.forward) * (Vector3.right * r);
with the following one:
return c + Quaternion.AngleAxis(1.0f * i, transform.forward) * (transform.right * r);
**I guessed your script is attached to the tilted object so used transform. Otherwise, you need to use it like tiltedObj.transform.
The .X3D format has an interesting rotation system. Unlike most formats containing rotation values around the X, Y and Z axis, .X3D gives a normalized direction vector and then gives a value in radians for rotation around that axis.
Example:
The axis to rotate around: 0.000000 0.465391 0.885105
Rotation around that axis (in radians): 3.141593
I have the conversion from radians to degrees, but I need the rotation values around XYZ from these values.
We can build a sequence for elementary matrix transformations to rotate about angle-axis. Let axis unit vector is w, angle Theta. Auxiliary values:
V = Sqrt(wx*wx + wz*wz)
W = Sqrt(wx*wx + wy*wy + wz*wz) //1 for unit dir vector
Cos(Alpha) = wz/V
Sin(Alpha) = wx/V
Cos(Beta) = V/W
Sin(Beta) = wy/W
Transformation sequence:
Ry(-Alpha) //rotation matrix about Y-axis by angle -Alpha
Rx(Beta)
Rz(Theta)
Rx(-Beta)
Ry(Alpha)
Note that for is axis is parallel to Y , one should use usual just rotation matrix about Y (accounting for direction sign), because V value is zero.
There is rather complex Rodrigues' rotation formula for computing the rotation matrix corresponding to a rotation by an angle Theta about a fixed axis specified by the unit vector w.
Explicit matrix here (weird formatted picture):
This Below C++ Function Rotates a Point Around A Provided Center and Uses Another Vector(Unit) as Axis to rotate Around.
This Code Below Was Made Thanks to Glenn Murray who provided the Formula Provided in Link. This is Tested and is Working Perfectly As intended.
Note: When Angle Is Positive And Unit Vector is {0,0,1} It Rotates To the Right Side, Basically Rotation Is On the Right Side, Axes are {x-forward,y-right,z-up}
void RotateVectorAroundPointAndAxis(Vector3D YourPoint, Vector3D PreferedCenter, Vector3D UnitDirection, float Angle, Vector3D& ReturnVector)
{
float SinVal = sin(Angle * 0.01745329251);
float CosVal = cos(Angle * 0.01745329251);
float OneMinSin = 1.0f - SinVal;
float OneMinCos = 1.0f - CosVal;
UnitDirection = GetUnitVector(UnitDirection, { 0,0,0 });// This Function Gets unit Vector From InputVector - DesiredCenter
float Temp = (UnitDirection.x * YourPoint.x) + (UnitDirection.y * YourPoint.y) + (UnitDirection.z * YourPoint.z);
ReturnVector.x = (PreferedCenter.x * (UnitDirection.y * UnitDirection.y)) - (UnitDirection.x * (((-PreferedCenter.y * UnitDirection.y) + (-PreferedCenter.z * UnitDirection.z)) - Temp));
ReturnVector.y = (PreferedCenter.y * (UnitDirection.x * UnitDirection.x)) - (UnitDirection.y * (((-PreferedCenter.x * UnitDirection.x) + (-PreferedCenter.z * UnitDirection.z)) - Temp));
ReturnVector.z = (PreferedCenter.z * (UnitDirection.x * UnitDirection.x)) - (UnitDirection.z * (((-PreferedCenter.x * UnitDirection.x) + (-PreferedCenter.y * UnitDirection.y)) - Temp));
ReturnVector.x = (ReturnVector.x * OneMinCos) + (YourPoint.x * CosVal);
ReturnVector.y = (ReturnVector.y * OneMinCos) + (YourPoint.y * CosVal);
ReturnVector.z = (ReturnVector.z * OneMinCos) + (YourPoint.z * CosVal);
ReturnVector.x += (-(PreferedCenter.z * UnitDirection.y) + (PreferedCenter.y * UnitDirection.z) - (UnitDirection.z * YourPoint.y) + (UnitDirection.y * YourPoint.z)) * SinVal;
ReturnVector.y += ( (PreferedCenter.z * UnitDirection.x) - (PreferedCenter.x * UnitDirection.z) + (UnitDirection.z * YourPoint.x) - (UnitDirection.x * YourPoint.z)) * SinVal;
ReturnVector.z += (-(PreferedCenter.y * UnitDirection.x) + (PreferedCenter.x * UnitDirection.y) - (UnitDirection.y * YourPoint.x) + (UnitDirection.x * YourPoint.y)) * SinVal;
}
I am making an application in Unity 3d where I want to code gravity and centripetal force myself but I am getting weird results, am I doing it right? This is my code:
public void Attract(MassObject[] _allMass)
{
Vector3 F = new Vector3();
Vector3 C = new Vector3();
foreach(MassObject i in _allMass)
{
// gravity pull
F.x = GV.gravity * ((mass * i.mass) / (obj.position.x - i.obj.position.x));
F.y = GV.gravity * ((mass * i.mass) / (obj.position.y - i.obj.position.y));
F.z = GV.gravity * ((mass * i.mass) / (obj.position.z - i.obj.position.z));
// centripital force
C.x = (mass * Mathf.Pow(vel.x,2)) / (obj.position.x - i.obj.position.x);
C.y = (mass * Mathf.Pow(vel.y,2)) / (obj.position.y - i.obj.position.y);
C.z = (mass * Mathf.Pow(vel.z,2)) / (obj.position.z - i.obj.position.z);
}
vel = F + C;
Debug.Log(F);
Debug.Log(C);
}
There are a few problems with this:
You are rewriting F and C with each foreach iteration, so you end up with the for for the last object in the list. You should add all the forces together using += instead of =.
You should be using vector operations rather than manually calculating x y and z. Doing so would make the third error more obvious:
The formula is wrong. For example, this line:
F.x = GV.gravity * ((mass * i.mass) / (obj.position.x - i.obj.position.x));
with just a few things substituted is
F.x = gravity coeff * (masses multiplied) / (distance **on the x axis** between objects.)
What you really need is distance between objects, not just on the x axis. You can get this with a vector operation:
float distanceSquared = (obj.position - i.obj.position).sqrMagnitude;
Then you can use the law of universal gravitation to get the magnitude of the force of gravity:
float forceMagnitude = GV.gravity * (mass * i.mass) / distanceSquared;
Finally, you need a direction. You can get that with vector subtraction and normalization, then multiplying by the desired magnitude:
Vector3 force = (i.obj.position - obj.position).normalized * forceMagnitude;
And now force is a vector pointing from obj to i.obj with the magnitude of gravity between the two objects. Add that to F to accumulate the force from each object and things should be good.
Your understanding of physics might be off. If vel is velocity, it is wrong to set it to the sum of two forces. I think you're better off learning about this from somewhere else, though. Understanding Newton's laws is a good start.
I've been trying to combine these two samples from David Amador:
http://www.david-amador.com/2010/03/xna-2d-independent-resolution-rendering/
http://www.david-amador.com/2009/10/xna-camera-2d-with-zoom-and-rotation/
Everything is working fine except I'm having some difficulty getting the mouse coordinates. I was able to get them for each individual sample, but my math for taking both into account seems to be wrong.
The mouse coordinates ARE correct if my virtual resolution and normal resolution are the same. It's when I do something like Resolution.SetVirtualResolution(1920, 1080)
and Resolution.SetResolution(1280, 720, false) when the coordinates slowly get out of sync as I move the camera.
Here is the code:
public static Vector2 MousePositionCamera(Camera camera)
{
float MouseWorldX = (Mouse.GetState().X - Resolution.VirtualWidth * 0.5f + (camera.position.X) * (float)Math.Pow(camera.Zoom, 1)) /
(float)Math.Pow(camera.Zoom, 1);
float MouseWorldY = ((Mouse.GetState().Y - Resolution.VirtualHeight * 0.5f + (camera.position.Y) * (float)Math.Pow(camera.Zoom, 1))) /
(float)Math.Pow(camera.Zoom, 1);
Vector2 mousePosition = new Vector2(MouseWorldX, MouseWorldY);
Vector2 virtualViewport = new Vector2(Resolution.VirtualViewportX, Resolution.VirtualViewportY);
mousePosition = Vector2.Transform(mousePosition - virtualViewport, Matrix.Invert(Resolution.getTransformationMatrix()));
return mousePosition;
}
In resolution I added this:
virtualViewportX = (_Device.PreferredBackBufferWidth / 2) - (width / 2);
virtualViewportY = (_Device.PreferredBackBufferHeight / 2) - (height / 2);
Everything else is the same as the sample code. Thanks in advance!
Thanks to David Gouveia I was able to identify the problem... My camera matrix was using the wrong math.
I'm going to post all of my code with the hopes of helping someone who is trying to do something similar.
Camera transformation matrix:
public Matrix GetTransformMatrix()
{
transform = Matrix.CreateTranslation(new Vector3(-position.X, -position.Y, 0)) * Matrix.CreateRotationZ(rotation) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) * Matrix.CreateTranslation(new Vector3(Resolution.VirtualWidth
* 0.5f, Resolution.VirtualHeight * 0.5f, 0));
return transform;
}
That will also center the camera. Here's how you get the mouse coordinates combining both the Resolution class and camera class:
public static Vector2 MousePositionCamera(Camera camera)
{
Vector2 mousePosition;
mousePosition.X = Mouse.GetState().X;
mousePosition.Y = Mouse.GetState().Y;
//Adjust for resolutions like 800 x 600 that are letter boxed on the Y:
mousePosition.Y -= Resolution.VirtualViewportY;
Vector2 screenPosition = Vector2.Transform(mousePosition, Matrix.Invert(Resolution.getTransformationMatrix()));
Vector2 worldPosition = Vector2.Transform(screenPosition, Matrix.Invert(camera.GetTransformMatrix()));
return worldPosition;
}
Combined with all of the other code I posted/mentioned this should be all you need to achieve resolution independence and an awesome camera!
I'm trying to rotate a Vector2 but nothing work.
I've tried the following -> didn't work:
x' = cos(angle)*x - sin(angle)*y & y' = sin(angle)*x + cos(angle)*y
I've tried using a rotation matrix -> didn't work
What am I doing wrong ? :/
angle = MathHelper.Pi;
direction.X = (int)((direction.X) * Math.Cos(angle) - direction.Y * Math.Sin(angle));
direction.Y = (int)((direction.X) * Math.Sin(angle) + direction.Y * Math.Cos(angle));
float angle = MathHelper.PiOver2;
Vector2 dir = new Vector2(direction.X, direction.Y);
Vector2.Transform(dir, Matrix.CreateRotationX(angle));
direction = new Point((int)dir.X, (int)dir.Y);
Vector2.Transform() returns a result rather than applying the changes in-place.
var transformed = Vector2.Transform(dir, Matrix.CreateRotationX(angle));
direction = new Point((int) dir.X, (int) dir.Y);
The first method you have written should work, as it's showed here also: http://www.oocities.org/davidvwilliamson/rotpoint.jpg
Remember to store the original values, and use those to determine the new values, and do not use the new x value to calculate y. Or store the products in separate variables.