How Can I rotate a triangle's vertices in 2d space?

here’s my rotation matrix, I’ve tried to follow some examples but my results are weird and obviously incorrect, I should also note that this object rotates by following the players position and can therefore rotate clockwise and anticlockwise.

public void rotateVertices(){
		double cos = Math.cos(angleRot);
		double sin = Math.sin(angleRot);
		
		double centerX = x + 32;
		double centerY = y + 32;
		
		vertices[0] = new Vector2(((centerX + (cos * (x + 25) - centerX) + sin * ((y + 13) - centerY))), (centerY + (sin * (y + 13 - centerY) + cos * ((y + 13) - centerY))));
		vertices[1] = new Vector2(((centerX + (cos * (x + 64) - centerX) + sin * ((y + 33) - centerY))), (centerY + (sin * (y + 33 - centerY) + cos * ((y + 33) - centerY))));
		vertices[2] = new Vector2(((centerX + (cos * (x + 25) - centerX) + sin * ((y + 53) - centerY))), (centerY + (sin * (y + 53 - centerY) + cos * ((y + 53) - centerY))));
		 
	}
	

This just needs a little bit of linear algebra. You did not specify exactly what it means for the object to be rotated towards the player. I am assuming you want its local +X axis to point towards the player. If so, then the following is a working solution requiring no angles or sin/cos:


/**
 * @param vertices the vertices of an object O to rotate/transform
 * @param cX the x coordinate of the local center of the given vertices of the object O (in your example 32)
 * @param cY the y coordinate of the local center of the given vertices of the object O (in your example 32)
 * @param oX the x coordinate of the object O whose vertices to rotate
 * @param oY the y coordinate of the object O whose vertices to rotate
 * @param pX the x coordinate of the player to rotate towards
 * @param pY the y coordinate of the player to rotate towards
 */
public static void rotateVertices(Vector2f[] vertices, float cX, float cY, float oX, float oY, float pX, float pY) {
	// compute direction vector from O -> P
	float dX = pX - oX, dY = pY - oY;
	// normalize direction vector
	float invlen = 1.0f / (float) Math.sqrt(dX*dX + dY*dY);
	float ndX = dX * invlen, ndY = dY * invlen;
	// compute rotation matrix M such that +X will be oriented along (P - O)
	// i.e. the local X axis of the object will point at the player (pX, pY)
	// (this is just a form of: https://en.wikipedia.org/wiki/Rotation_matrix#In_two_dimensions)
	float m00 = ndX, m10 = -ndY;
	float m01 = ndY, m11 =  ndX;
	// rotate a bunch of vertices using pivot/center of rotation (cX, cY)
	// by multiplying T * M * T^-1 * v (for each v)
	// where T is translation by (cX, cY) and T^-1 its inverse
	for (int i = 0; i < vertices.length; i++) {
		Vector2f v = vertices[i];
		float vX = (v.x - cX) * m00 + (v.y - cY) * m10 + cX;
		float vY = (v.x - cX) * m01 + (v.y - cY) * m11 + cY;
		v.x = vX;
		v.y = vY;
	}
}

Hi, thanks for the response,

I should specified further about the rotation, ideally, I would like the second vertex (point of the triangle [1]) to point towards the player,
if you could be an even bigger help with this that would be great

One possible direct way that’s a bit more involved would be:

  1. compute everything like above (that means assuming you wanted the local +X axis of the object to point towards the player)
  2. compute the rotation matrix which would rotate the local +X axis to point to the second vertex (this just uses another direction vector computed from the second vertex and (cX, cY))
  3. invert that matrix you computed in 2. (this is simply the transpose of the 2x2 matrix) - this is to counter the rotation, since we want its opposite
  4. multiply the matrix M computed above (in step 1) with that inverted matrix computed in step 3
  5. use that combined matrix to transform your vertices (i.e. this now becomes your (m00 m01, m10 m11))

Hi there, I’ve implemented the code you provided in your first comment however my result’s just seem to show my the objects vertices spinning wildly around in circles very rapidly, any idea why this is?

The method I posted above modifies the provided vertices array in-place.
That means, when you call that method over and over again, the same vertices are being rotated further and further around, because the amount/angle to rotate stays constant since it is only computed/derived from the player’s position and the object’s position.
So, you should rather modify that method in order to store the modified vertices in another array.
Or you indeed incorporate the object-local position/rotation of the vertex you want to point to the player into the calculation.

But quite frankly, that’ll only complicate things unnecessarily.
I’d first “normalize” your object’s vertices by letting the “tip” vertex, which you want to have pointed towards the player, be either directed along the local +X or +Y axis of the object. Also you should make the center of rotation be the local origin (0, 0) of your object and not having a weird (32, 32) offset to take care of all the time.

And then, since you are seemingly using libGDX with its Vector2 class, you should also use libGDX’s own transformation mechanisms instead of manually modifying/transforming the object’s vertices.

Thanks for the reply, I misunderstood before as my second vertex is already aligned on the X axis so I should not have to do any additional transformations, I should also note that the Vector class is my own, I also would prefer to understand the maths behind games programming myself.

I also don’t understand how storing the vertices in a separate array will stop the rotations as I will need to constantly update the vertices array regardless as the object is rotating

[quote]I also don’t understand how storing the vertices in a separate array will stop the rotations as I will need to constantly update the vertices array regardless as the object is rotating
[/quote]
Look, when you constantly apply the same rotation to the set of positions that you rotated the previous frame, then of course it’ll rotate like crazy since you keep on rotating forever.
You must store your initial set of (unrotated) vertices separately from your rotated set of vertices, because then, you can recompute and apply the necessary amount of rotation each frame and it will not continue rotating since it is not applying the rotation over and over again to the already rotated vertices.
So you start with an unrotated set of vertices each frame and each frame you apply the necessary rotation and store the resulting rotated vertices in a separate array.

EDIT: To explain a little bit more:
The rotation that the method is computing and applying to the provided vertices is saying “Hey, I have this set of vertices with an assumed local +X axis which is aligned with the world’s +X axis and I want that local +X axis to point along the world’s direction towards the player.”
The important piece here is that we assume that our vertices do not already point to the player and hence we have to rotate them.
Therefore, when you give that method a set of vertices that are already rotated/transformed, the method does not know about that and it’ll assume that you gave it a set of unrotated vertices and will still apply the rotation.
So, in the second frame you will have twice as much rotation as necessary, in the third frame three times as much, in the fourth frame four times as much, etc. since all the rotations are accumulating.

To add to what KaiHH said and maybe explain what he’s trying to convey in a slightly simpler way…
Think of it like this. If you want to rotate something 10 degrees per frame, there are two ways to do so.
Option A:
Store a variable that gets incremented once per frame like this:


float x = 0.0f;
public void update() {
     object.rotate(x); // rotate x degrees relative to zero (x - 0)
     x += 10.0f;
}

Option B:
Rotate the actual vertices:


public void update() {
     object.rotate(10.0f); // rotate another 10 degrees relative to the previous state of rotation
}

Now, both of these can do the same thing, except in Option B, you’ve lost your original vertex data.
Can you see what the difference is?
In Option A, it’s the rotation float variable that’s getting incremented to make the object rotate more and more from the original 0 degrees every frame. (the variable is the ‘previous state of rotation’)
In Option B, it’s the vertex positions and rotation transformations themselves that get concatenated/incremented so they basically act like the ‘previous state of rotation’

I hope this makes sense

I did understand what KaiHH was saying after the second explanation however after passing through the positions of the original vertices instead of the already rotated vertices, these new vertices still rotate just as before.

In my Mind it makes sense that I can update my vertices like so:

for (int i = 0; i < verts.length; i++) {
		      Vector2 v = verts[i];
		      double vX = (v.x - cX) * m00 + (v.y - cY) * m10 + cX;
		      double vY = (v.x - cX) * m01 + (v.y - cY) * m11 + cY;
		      v.x = vX;
		      v.y = vY;
		      
		      vertices[i] = v;
		   }

Well, no. This is not how it is going to work, since [icode]verts[i][/icode] and [icode]vertices[i][/icode] will then point to the exact same modified Vector2 instance.
Please read up on the Java programming language and its semantics, probably by googling for “Java object references”.

You can create a static copy() method to get a new vector instead of assigning it like

verts[i] = vertices[i];

The static method will look like this

public static Vector2 copy(Vector2 v){
    return new Vector2(v.x,v.y);
}

And use it like this

verts[i] = Vector2.copy(vertices[i]);

for (int i = 0; i < verts.length; i++) {
  Vector2 v = verts[i];

  // FWIW:  this is do more work than needed and the compiler can't remove it
  double vX = (v.x - cX) * m00 + (v.y - cY) * m10 + cX;
  double vY = (v.x - cX) * m01 + (v.y - cY) * m11 + cY;
  
   vertices[i].set(vX,vY);
}