Rotate a point by another point in 2D - c#

I want to know how to work out the new co-ordinates for a point when rotated by an angle relative to another point.
I have a block arrow and want to rotate it by an angle theta relative to a point in the middle of the base of the arrow.
This is required to allow me to draw a polygon between 2 onscreen controls. I can't use and rotate an image.
From what I have considered so far what complicates the matter further is that the origin of a screen is in the top left hand corner.

If you rotate point (px, py) around point (ox, oy) by angle theta you'll get:
p'x = cos(theta) * (px-ox) - sin(theta) * (py-oy) + ox
p'y = sin(theta) * (px-ox) + cos(theta) * (py-oy) + oy

If you are using GDI+ to do that, you can use Transform methods of the Graphics object:
graphics.TranslateTransform(point of origin);
graphics.RotateTransform(rotation angle);
Then draw the actual stuff.

If you have the System.Windows.Media namespace available, then you can use the built in transformations:
using System.Windows.Media;
var transform = new RotateTransform() {Angle = angleInDegrees, CenterX = center.X, CenterY = center.Y};
var transformedPoint = transform.Transform(point);

This takes a layout transform command on your image in the WPF, and rotates it the degree you want.
progress_image.LayoutTransform = new RotateTransform(90);

Related

Rotating a shape around its center using mouse position

I am trying to create a library which allows user to edit shapes on a canvas, primarily moving, resizing, and rotating the shapes.
I have a problem with my rotating code in that the degree of rotation seems to be off by -90 degrees.
This is my code that does the rotation, in the mouseMove event:
var mousePos = e.GetPosition(this.Parent as FrameworkElement);
//gridPos is the center point of the shape object (contained within a grid control for reasons
var gridPos = new Point(Canvas.GetLeft(this) + this.ActualWidth / 2, Canvas.GetTop(this) + this.ActualHeight / 2);
//Get the angle in radians
double radians = Math.Atan2(mousePos.Y - gridPos.Y, mousePos.X - gridPos.X);
//Convert to degrees
double angle = radians * (180 / Math.PI);
//Apply rotation from centre
RenderTransformOrigin = new Point(0.5, 0.5);
//This is applied initially to my shape control object which has the shape as child
RenderTransform = new RotateTransform(degrees);
This is what I'm seeing:
As you can see, the shape immediately rotates about -90. The red marks are drawn at mousePos and gridPos.
If I put some Debug.WriteLine in that, this is what results:
MouseX: 440.14, MouseY: 148
GridX: 443.14, GridY: 197
MouseX - GridX: -3
MouseY - GridY: -49
Radians: -1.631944489444198
Degrees: -93.50353164478446
I can't work out what's wrong with my logic here, although I'm pretty sure Math.Atan2(mousePos.Y - gridPos.Y, mousePos.X - gridPos.X); isn't giving me what I think it is...
Using atan2(y, x) only works if your anchor point is to the _right of the rotation point. Code for each is as follows:
double radians = Math.Atan2(gridPos.Y - mousePos.Y, gridPos.X - mousePos.X); // left
double radians = Math.Atan2(mousePos.X - gridPos.X, gridPos.Y - mousePos.Y); // top
double radians = Math.Atan2(gridPos.X - mousePos.X, mousePos.Y - gridPos.Y); // bottom
double radians = Math.Atan2(mousePos.Y - gridPos.Y, mousePos.X - gridPos.X); // right
Ideally though, what you should be doing is calculating the angle of the point where you initially click down, then calculate the new angle for your mousemove events, setting the rotation to be whatever the difference is between them. That's essentially what each of the 4 lines above is doing, they're just hard-coding the initial mouse down point.

Getting the position of the the tip of a sprite, while rotated

I want to get the position of the sprite while its rotated,
Example
The bigger dot is the location i want to get (while rotated), and the sprite is rotated so its quite hard to get that, and im clueless of how to get it, the origin is (0,0) for anyone asking, is there any math that needs to be done to get this?
What you need to do is create a Vector2 from the origin to the rotated point before it's rotated and then rotate that vector.
For example, let's say we have a sprite with the origin point in the center and we want to know where the front point will be when the sprite is rotated.
First, create a vector from the origin to the point you want rotated on the unrotated sprite. In this case it's probably going to be something like 20 pixels to the right of the center:
var vector = new Vector2(20, 0);
Now we can rotate our vector with this simple function (borrowed from MonoGame.Extended)
public static Vector2 Rotate(Vector2 value, float radians)
{
var cos = (float) Math.Cos(radians);
var sin = (float) Math.Sin(radians);
return new Vector2(value.X*cos - value.Y*sin, value.X*sin + value.Y*cos);
}.
Now we can get our rotated vector like so:
var radians = MathHelper.ToRadians(degrees: -33);
var rotatedVector = Rotate(vector, radians);
To get this vector back into "sprite" space we can add it back to our origin point:
var point = origin + rotatedVector;
Or alternately if you want it in "world" space you can also add it to your sprites position.
var worldPoint = position + origin + rotatedVector;
Happy coding!

Getting a vector from an angle and length?

I'm working on a monster's sight(cone-shaped) and need a way to draw it. The vector I get from the angle/distance will be centered around a position(the monster's position).
Using C#/Xna, how can I get a vector if I have an angle and distance(length from position)?
The answer helped lead me in the right direction. Code now looks like:
Vector2 vector = new Vector2((float)Math.Cos(angle) * distance + position.X, (float)Math.Sin(angle) * distance + position.Y);
You'd use some trigonometry.
Like so, assuming that angle is your angle, in radians:
new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
However, if you want an angle in degrees, then you'd use MathHelper.ToRadians, like this:
float angleInRadians = MathHelper.ToRadians(angle);
new Vector2((float)Math.Cos(angleInRadians), (float)Math.Sin(angleInRadians));

Determine screen coordinates from point in DirectX world

I have a point in space represented by a 4x4 matrix. I'd like to get the screen coordinates for the point. Picking appears to be the exact opposite fo what I need. I'm using the screen coordinate to determine where to draw text.
Currently the text I draw is floating in space far in front of the points. I've attached a screenshot of zoomed-in and zoomed-out to better explain. As you can see in the screenshot, the distance between each point is the same when zoomed in, when it should be smaller.
Am I missing a transformation? World coordinates consider 0,0,0 to be the center of the grid. I'm using SlimDX.
var viewProj = mMainCamera.View * mMainCamera.Projection;
//Convert 4x4 matrix for point to Vector4
var originalXyz = Vector3.Transform(Vector3.Zero, matrix);
//Vector4 to Vector3
Vector3 worldSpaceCoordinates = new Vector3(originalXyz.X, originalXyz.Y, originalXyz.Z);
//Transform point by view projection matrix
var transformedCoords = Vector3.Transform(worldSpaceCoordinates, viewProj);
Vector3 clipSpaceCoordinates = new Vector3(transformedCoords.X, transformedCoords.Y, transformedCoords.Z);
Vector2 pixelPosition = new Vector2((float)(0.5 * (clipSpaceCoordinates.X + 1) * ActualWidth), (float)(0.5 * (clipSpaceCoordinates.Y + 1) * ActualHeight));
Turns out I was way overthinking this. Just project the point to the screen by passing Vector3.Project your viewport information. It's a 3 line solution.
var viewProj = mMainCamera.View * mMainCamera.Projection;
var vp = mDevice.ImmediateContext.Rasterizer.GetViewports()[0];
var screenCoords = Vector3.Project(worldSpaceCoordinates, vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ, viewProj);

How to get coords inside a transformed sprite?

I am trying to the get the x and y coordinates inside a transformed sprite. I have a simple 200x200 sprite which rotates in the middle of the screen - with an origin of (0,0) to keep things simple.
I have written a piece of code that can transform the mouse coordinates but only with a specified x OR y value.
int ox = (int)(MousePos.X - Position.X);
int oy = (int)(MousePos.Y - Position.Y);
Relative.X = (float)((ox - (Math.Sin(Rotation) * Y /* problem here */)) / Math.Cos(Rotation));
Relative.Y = (float)((oy + (Math.Sin(Rotation) * X /* problem here */)) / Math.Cos(Rotation));
How can I achieve this? Or how can I fix my equation?
The most general way is to express the transformation as a matrix. This way, you can add any other transformation later, if you find you need it.
For the given transformation, the matrix is:
var mat = Matrix.CreateRotationZ(Rotation) * Matrix.CreateTranslation(Position);
This matrix can be interpreted as the system transformation from sprite space to world space. You want the inverse transformation - the system transformation from world space to sprite space.
var inv = Matrix.Invert(mat);
You can transform the mouse coordinates with this matrix:
var mouseInSpriteSpace = Vector2.Transform(MousePos, inv);
And you get the mouse position in the sprite's local system.
You can check if you have the correct matrix mat by using the overload of Spritebatch.Begin() that takes a matrix. If you pass the matrix, draw the sprite at (0, 0) with no rotation.

Categories

Resources