I've been stuck with rotating an asset with an offset.
Sstart = e.GetPosition(dial);
if (dial.IsStylusCaptured)
{
AngleRot = Math.Atan2((Y - Sstart.Y) , (X - Sstart.X));
radAngle = AngleRot / Math.PI * 180 + 180;
radAngle = radAngle - AthetaD;
di.RenderTransform = new RotateTransform(radAngle + 90);
}
Using this I was able to rotate my object from 0° with an offset of x to angle theta. But when I make a second rotation, instead of it rotating from angle theta with an offset x it resets the object back to 0°. How can I make it so the offset is always from theta and not 0°?
Here I Rotate with an offset angle
Here my angle resets back to 0° instead of moving from -56°
Let current direction vector is (cx, cy).
In the beginning set it into (1,0) or another needed value.
When you rotated dial, you have new direction
nx = X - Sstart.X
ny = Y - Sstart.Y
To rotate current direction vector to new one, you need to calculate relative angle. This approach uses cross product and dot product of vectors. Perhaps you'll need to change sign of the first expression
Angle = Math.Atan2(nx * cy - ny * cx, cx * nx + cy * ny)
..apply rotation by Angle
After rotation remember current direction to use it later
cx = nx
cy = ny
Related
I have a hemisphere with radius 250.
Located on the edge of the hemisphere (15 degrees above the base/horizon), I have 7 equally spaced points (i.e., 1 point every 360/7 degrees).
Using Unity3D, I want to place camera at each of those 7 points such that their FoV is perpendicular/orthogonal to the surface of the sphere.
Given camera number (1,2,3...7) and the radius of the hemisphere (250), what function will place the cameras in the correct position and facing the correct direction?
pointCount = 7;
tilt = 15;
radius = 250;
void PositionCamera(int pointCount, int pointId, float radius, float tilt, Transform camera){
Vector3 temp = Vector3.forward * radius;
temp = Quaternion.Euler(tilt, 0, 0) * temp;
temp = Quaternion.Euler(0, 360/pointCount*pointId, 0) * temp;
camera.position = temp + camera.parent.position;
camera.rotation = Quaternion.LookRotation(temp);
}
Assuming that the center of the hemisphere is at origin and the first point on the z axis.
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 have a c# program where I need to draw some simple 2D objects on the canvas.
One of these involves drawing a rectangle and lines where I know the start point, the length and I have to calculate the end position. So I have the following code;
private void CalculateEndPoint()
{
double angle = Helper.deg2rad((double)this.StartAngle);
int x = this.StartPoint.X + (int)(Math.Cos(angle) * this.Length * -1);
int y = this.StartPoint.Y + (int)(Math.Sin(angle) * this.Length);
this.EndPoint = new Point(x, y);
}
Now this seems to work OK to calculate the end points. The issue I have is with the angle (this.StartAngle), the value I specify seems not to be how it is drawn and I seem to have the following;
Where as I'm expecting 0 at the top, 90 on the right, 180 at the bottom etc.
So to get a shape to draw straight down the canvas I have to specify 90 degrees, where as I would expect to specify 180.
Have I done something wrong? Or is it just a lack of understanding?
You should change your CalculateEndPoint function to have that:
private static void CalculateEndPoint(double dec)
{
double angle = (Math.PI / 180) * (this.StartAngle + 90); // add PI / 2
int x = StartPoint.X + (int)(Math.Cos(angle) * Length * -1);
double angle2 = (Math.PI / 180) * (this.StartAngle - 90); // minus PI / 2
int y = StartPoint.Y + (int)(Math.Sin(angle2) * Length);
EndPoint = new Point(x, y);
}
Actually, 0 should be on the right. You are multiplying the x-coordinate by -1, so you're moving it to the left.
Just remember these 2 rules:
- The cosine of the angle is the x-coordinate of the unit circle.
- The sine of the angle is the y-coordinate of the unit circle.
Since cos(0) = 1 and sin(0) = 0, the coordinate corresponding to angle 0 is (1, 0).
Whether 90 is on top or on the bottom depends on the canvas.
Some applications/frameworks consider y-coordinate 0 to be at the top of the canvas. That means you go clockwise around the circle and 90 will be at the bottom.
If y-coordinate 0 is at the bottom of the canvas, you go counter-clockwise and 90 will be at the top.
I am working on an application for the past few weeks which involves some trigonometry and am currently stuck. As shown in the diagram below, I have a circular item (green circle at position #1) which I know the center point (let's call that X1,Y1). The circle has another point (orange circle) that is off-centered a bit - midway between two other marks (blue circles). These marks can move around. The coordinates of the orange point are calculated (let's call it X2, Y2) and the angle of the blue line is calculated (call it Angle) in relation to the horizontal of the circle.
I can calculate the difference between the center of the circle and the point by:
deltaX = X2-X1
deltaY = Y2-Y1
I need to move and rotate the green circle (either CW or CCW - whichever is shorter) from it's start location (position 1) over to position 2. This means the angle could be negative or positive. The blue line must end up vertical and the orange dot at the center of position 2 (red square). I know the coordinates for the center of position 2 (let's call this point X3,Y3). Position #1 and position #2 are exactly 90 degrees from each other.
I thought I could use some trig identity formulas that calculate the rotation of a point, as such:
offsetX = deltaX * cos(90-Angle) - deltaY * sin(90-Angle)
offsetY = deltaX * sin(90-Angle) + deltaY * cos(90-Angle)
I was hoping these offsets would be what I need to adjust the circle to it's new center when it moves/rotates over to position 2.
X3 = X3 + offsetX
Y3 = Y3 + offsetY
However, when I try use this math, it's not placing the orange mark of the circle in the center of the square. Not sure if my equations and calculations are correct based on the angle of rotation (positive or negative, CW or CCW) or if I'm using the angle correctly (where I subtract the known angle from 90 degrees). How do I correctly calculate the final point/position? Any help and examples would be greatly appreciated!
Thank you very much for your time!
So you need to rotate your circle by 90 - Angle and then move orange point to (X3, Y3)?
First you need to find orange point coordinate after rotation:
newX = X2 * cos(90 - Angle) - Y2 * sin(90 - Angle);
newY = X2 * sin(90 - Angle) + Y2 * cos(90 - Angle);
newX and newY are orange point coordinates after rotation. To find move transformation simply substract:
moveX = X3 - newX;
moveY = Y3 - newY;
Now if you rotate circle by 90 - Angle and move it by (moveX, moveY) orange point will move to (X3, Y3). That is if you rotate circle around (0, 0) point. If you rotating around some (X, Y) point, you first need to substract X from X2, Y from Y2 and then add X to newX, Y to newY. That substraction 'moves' your rotation base point to (0, 0), so after rotation you need to move it back:
newX = (X2 - X) * cos(90 - Angle) - (Y2 - Y) * sin(90 - Angle) + X;
newY = (X2 - X) * sin(90 - Angle) + (Y2 - Y) * cos(90 - Angle) + Y;
Be aware that your code is using a counter clockwise rotation, (conventionally angles are measured counter clockwise) which may be why you're not getting the results you expect. if you want a clockwise rotation try:
offsetX = deltaX * cos(angle) + deltaY * sin(angle)
offsetY = -deltaX * sin(angle) + deltaY * cos(angle)
Ensure your angles are in radians not degrees.
Drawing some lines may help you debug things too.
I am writing a program in which I need to draw polygons of an arbitrary number of sides, each one being translated by a given formula which changes dynamically. There is some rather interesting mathematics involved but I am stuck on this probelm.
How can I calculate the coordinates of the vertices of a regular polygon (one in which all angles are equal), given only the number of sides, and ideally (but not neccessarily) having the origin at the centre?
For example: a hexagon might have the following points (all are floats):
( 1.5 , 0.5 *Math.Sqrt(3) )
( 0 , 1 *Math.Sqrt(3) )
(-1.5 , 0.5 *Math.Sqrt(3) )
(-1.5 , -0.5 *Math.Sqrt(3) )
( 0 , -1 *Math.Sqrt(3) )
( 1.5 , -0.5 *Math.Sqrt(3) )
My method looks like this:
void InitPolygonVertexCoords(RegularPolygon poly)
and the coordinates need to be added to this (or something similar, like a list):
Point[] _polygonVertexPoints;
I'm interested mainly in the algorithm here but examples in C# would be useful. I don't even know where to start. How should I implement it? Is it even possible?!
Thank you.
for (i = 0; i < n; i++) {
printf("%f %f\n",r * Math.cos(2 * Math.PI * i / n), r * Math.sin(2 * Math.PI * i / n));
}
where r is the radius of the circumsribing circle. Sorry for the wrong language No Habla C#.
Basically the angle between any two vertices is 2 pi / n and all the vertices are at distance r from the origin.
EDIT:
If you want to have the center somewher other than the origin, say at (x,y)
for (i = 0; i < n; i++) {
printf("%f %f\n",x + r * Math.cos(2 * Math.PI * i / n), y + r * Math.sin(2 * Math.PI * i / n));
}
The number of points equals the number of sides.
The angle you need is angle = 2 * pi / numPoints.
Then starting vertically above the origin with the size of the polygon being given by radius:
for (int i = 0; i < numPoints; i++)
{
x = centreX + radius * sin(i * angle);
y = centreY + radius * cos(i * angle);
}
If your centre is the origin then simply ignore the centreX and centreY terms as they'll be 0,0.
Swapping the cos and sin over will point the first point horizontally to the right of the origin.
Sorry, I dont have a full solution at hand right now, but you should try looking for 2D-Rendering of Circles. All classic implementations of circle(x,y,r) use a polygon like you described for drawing (but with 50+ sides).
Say the distance of the vertices to the origin is 1. And say (1, 0) is always a coordinate of the polygon.
Given the number of vertices (say n), the rotation angle required to position the (1, 0) to the next coordinate would be (360/n).
The computation required here is to rotate the coordinates. Here is what it is; Rotation Matrix.
Say theta = 360/n;
[cos(theta) -sin(theta)]
[sin(theta) cos(theta)]
would be your rotation matrix.
If you know linear algebra you already know what i mean. If dont just have a look at Matrix Multiplication
One possible implementation to generate a set of coordinates for regular polygon is to:
Define polygon center, radius and first vertex1. Rotate the vertex n-times2 at an angle of: 360/n.
In this implementation I use a vector to store the generated coordinates and a recursive function to generate them:
void generateRegularPolygon(vector<Point>& v, Point& center, int sidesNumber, int radius){
// converted to radians
double angRads = 2 * PI / double(sidesNumber);
// first vertex
Point initial(center.x, center.y - radius);
rotateCoordinate(v, center, initial, angRads, sidesNumber);
}
where:
void rotateCoordinate(vector<Point>& v, Point& axisOfRotation, Point& initial, double angRads, int numberOfRotations){
// base case: number of transformations < 0
if(numberOfRotations <= 0) return;
else{
// apply rotation to: initial, around pivot point: axisOfRotation
double x = cos(angRads) * (initial.x - axisOfRotation.x) - sin(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.x;
double y = sin(angRads) * (initial.x - axisOfRotation.x) + cos(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.y;
// store the result
v.push_back(Point(x, y));
rotateCoordinate(v, axisOfRotation, Point(x,y), angRads, --numberOfRotations);
}
}
Note:
Point is a simple class to wrap the coordinate into single data structure:
class Point{
public:
Point(): x(0), y(0){ }
Point(int xx, int yy): x(xx), y(yy) { }
private:
int x;
int y;
};
1 in terms of (relative to) the center, radius. In my case the first vertex is translated from the centre up horizontally by the radius lenght.
2 n-regular polygon has n vertices.
The simple method is:
Let's take N-gone(number of sides) and length of side L. The angle will be T = 360/N.
Let's say one vertices is located on origin.
* First vertex = (0,0)
* Second vertex = (LcosT,LsinT)
* Third vertex = (LcosT+Lcos2T, LsinT+Lsin2T)
* Fourth vertex = (LcosT+Lcos2T+Lcos3T, LsinT+Lsin2T+Lsin3T)
You can do in for loop
hmm if you test all the versions that are listed here you'll see that the implementation is not good. you can check the distance from the center to each generated point of the polygon with : http://www.movable-type.co.uk/scripts/latlong.html
Now i have searched a lot and i could not find any good implementation for calculating a polyogon using the center and the radius...so i went back to the math book and tried to implement it myself. In the end i came up with this...wich is 100% good:
List<double[]> coordinates = new List<double[]>();
#region create Polygon Coordinates
if (!string.IsNullOrWhiteSpace(bus.Latitude) && !string.IsNullOrWhiteSpace(bus.Longitude) && !string.IsNullOrWhiteSpace(bus.ListingRadius))
{
double lat = DegreeToRadian(Double.Parse(bus.Latitude));
double lon = DegreeToRadian(Double.Parse(bus.Longitude));
double dist = Double.Parse(bus.ListingRadius);
double angle = 36;
for (double i = 0; i <= 360; i += angle)
{
var bearing = DegreeToRadian(i);
var lat2 = Math.Asin(Math.Sin(lat) * Math.Cos(dist / earthRadius) + Math.Cos(lat) * Math.Sin(dist / earthRadius) * Math.Cos(bearing));
var lon2 = lon + Math.Atan2(Math.Sin(bearing) * Math.Sin(dist / earthRadius) * Math.Cos(lat),Math.Cos(dist / earthRadius) - Math.Sin(lat) * Math.Sin(lat2));
coordinates.Add(new double[] { RadianToDegree(lat2), RadianToDegree(lon2) });
}
poly.Coordinates = new[] { coordinates.ToArray() };
}
#endregion
If you test this you'll see that all the points are at the exact distance that you give ( radius ). Also don't forget to declare the earthRadius.
private const double earthRadius = 6371.01;
This calculates the coordinates of a decagon. You see the angle used is 36 degrees. You can split 360 degrees to any number of sides that you want and put the result in the angle variable.
Anyway .. i hope this helps you #rmx!