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.
Related
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.
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 have a function to draw Bezier Curve through three points. I have already 2 points (start and end) - A and B. How do I calculate middle point between those two points as middle point would be always a little higher or lower than linear function of those two points.
Example:
Any formulas, ideas would be great!
I think this is what you're looking for:
http://blog.sklambert.com/finding-the-control-points-of-a-bezier-curve/
It goes into detail on calculating the various points on a Bezier curve.
You may also be interested in this more specific example for your application:
http://www.codeproject.com/Articles/223159/Midpoint-Algorithm-Divide-and-Conquer-Method-for-D
If you really want to get into it, then I suggest this Primer:
http://pomax.github.io/bezierinfo/
Bezier curves are a bit more complicated than simple arcs. For an arc, you can just use this formula:
R = H/2 + W^2/8H
...which definitely won't work for a Bezier curve. On a Quadratic Bezier curve, for example, to calculate a point, you must use:
Sources: http://en.wikipedia.org/wiki/B%C3%A9zier_curve, Quadratic Bezier Curve: Calculate Point
Below is what I use to get the control point of a quad bezier curve. It should work for your problem where the control point is on the curve. It's in Swift but you should be able to convert it to another language easily. Basically at the midpoint of the line (whose points are point1 and point2) I work out a perpendicular line with the given length. Clockwise parameter determines which side of the line the point should fall on.
func getControlPointWithPoint1(point1:CGPoint, point2:CGPoint, length:CGFloat, clockwise:Bool) -> CGPoint {
let angle = getAngleWithPoint1(point1, point2:point2)
let direction = clockwise ? 1 : -1
let perpendicularAngle = angle + (CGFloat(direction) * CGFloat((M_PI / 2)))
let midPoint = getMidPointWithPoint1(point1, point2:point2)
return CGPointMake(midPoint.x + (cos(perpendicularAngle) * length), midPoint.y + (sin(perpendicularAngle) * length))
}
func getAngleWithPoint1(point1:CGPoint, point2:CGPoint) -> CGFloat {
return atan2((point2.y - point1.y), (point2.x - point1.x))
}
func getMidPointWithPoint1(point1:CGPoint, point2:CGPoint) -> CGPoint {
return CGPointMake((point1.x + point2.x) / 2, (point1.y + point2.y) / 2)
}
Below is how it would map to your diagram letters:
c = getControlPointWithPoint1(a, point2:b, length:h, clockwise:true)
following Mark's answer, here is the snippet in C#
public static Path DrawBezeireUsingTwoPoints(Point startPoint, Point endPoint)
{
Path path = new Path();
PathFigure pathFigure = new PathFigure();
// Set up the Path to insert the segments
PathGeometry pathGeometry = new PathGeometry();
BezierSegment bezeireSeg;
// Draw an ellipse passing by the 2 points and let the path cross it
Point beziereMidPoint = CalculateBezierePoint(startPoint, endPoint, true);
bezeireSeg = new BezierSegment(startPoint, beziereMidPoint, endPoint, true);
pathFigure.StartPoint = startPoint;
pathFigure.IsClosed = false;
pathFigure.Segments.Add(bezeireSeg);
pathGeometry.Figures.Add(pathFigure);
path.Data = pathGeometry;
path.Stroke = Brushes.Brown;
path.StrokeThickness = 2;
return path;
}
I would be happy if help you.
It is my solution.
Vector2 posA = sphereA.transform.position;
Vector2 posB = sphereB.transform.position;
Gizmos.color = Color.blue;
Gizmos.DrawLine(posA, posB);
float distance = Vector2.Distance(posA, posB);
Vector2 direction = (posB - posA).normalized;
Vector2 v2 = end - start;
var angle = Mathf.Atan2(v2.y, v2.x) * Mathf.Rad2Deg;
var midStartPos = posA + direction * (distance / 2f);
Gizmos.color = Color.red;
Gizmos.DrawSphere(midStartPos, 0.02f);
var height = 0.3f;
height = Mathf.Clamp(height, 0f, Vector2.Distance(posA, posB) * 0.5f);
angle = 90f + angle;
var goalDirection = new Vector2(Mathf.Cos(angle * Mathf.Deg2Rad), Mathf.Sin(angle * Mathf.Deg2Rad));
if (goalDirection.y < 0f)
{
goalDirection.x = -goalDirection.x;
goalDirection.y = Mathf.Abs(goalDirection.y);
}
var midEndPos = midStartPos + goalDirection * height;
Gizmos.color = Color.blue;
Gizmos.DrawLine(midStartPos, midEndPos);
Gizmos.color = Color.red;
Gizmos.DrawSphere(midEndPos, 0.02f);
Here is my code. It works, except for when I do it at first It jumps far away from where it started, and as it's rotating its twitching and sort of flipping rapidly...
float rotAmount = 0;
Vector2 pivot = CenterSelection();
if (keyboardState.IsKeyDown(Keys.OemPlus)) rotAmount = 0.01f;
if (keyboardState.IsKeyDown(Keys.OemMinus)) rotAmount = -0.01f;
map.DoForSelected(delegate(GameObject mod)
{
Vector2 vDif = pivot - mod.position;
float vDist = (float)Math.Sqrt(Math.Pow(vDif.X, 2) + Math.Pow(vDif.Y, 2));
float vRot = rotAmount + (float)Math.Atan2(vDif.Y, vDif.X);
mod.position = pivot + new Vector2(
(float)Math.Cos(vRot),
(float)Math.Sin(vRot)
) * vDist;
mod.rotation += rotAmount;
});
I am trying to figure out what's wrong!
Your help is greatly appreciated!
Your difference vector points in the wrong direction:
Vector2 vDif = pivot - mod.position;
This is a vector from position to pivot.
Then you assign
mod.position = pivot + newDif;
expecting that newDif is a vector from pivot to position. But it's actually reversed.
So just reverse your difference vector:
Vector2 vDif = mod.position - pivot;