Bug with rotation in 2D

I’m trying to make some quads in 2D (orthographic projection) rotate around a central origin. This is something I’ve done several times before in other graphics engines, but for some reason in Unity I’m not getting correct results. Look at this image:

rotation issue

You can see as the quad rotates through 360 degrees, it stretches and compresses in incorrect ways. The code that handles this is:

public static void createRotatedQuadVectorsInPos(float x, float y, float w, float h, float angle, UILayer layer, int vpos)
	{
		angle = 360f - angle; // make positive changes rotate clockwise on screen
		float cosine = math.cosine(angle);
		float sine = math.sine(angle); // use lookup tables for speed

		// get an offset to add once we have rotated the corners
		Vector2 offset = new Vector2(x * ratioX, Screen.height - Mathf.Abs(h) - y);
		offset.x /= Screen.width; offset.y /= Screen.height; // normalize position offset

		// for now, we'll rotate around a central origin, so get four corner
 vectors as if origin was zero
		Vector2 tl = new Vector2(-w * 0.5f, -h * 0.5f);
		Vector2 tr = new Vector2(w * 0.5f, -h * 0.5f);
		Vector2 br = new Vector2(w * 0.5f, h * 0.5f);
		Vector2 bl = new Vector2(-w * 0.5f, h * 0.5f);

		// rotate around zero
		tl.x = tl.x * cosine - tl.y * sine;
		tl.y = tl.x * sine + tl.y * cosine;
		tr.x = tr.x * cosine - tr.y * sine;
		tr.y = tr.x * sine + tr.y * cosine;
		br.x = br.x * cosine - br.y * sine;
		br.y = br.x * sine + br.y * cosine;
		bl.x = bl.x * cosine - bl.y * sine;
		bl.y = bl.x * sine + bl.y * cosine;

		// mul by screen ratio, so when we scale by screen width/height the 
normalized  coordinates are correct for screen size
		tl.x *= ratioX;
		tr.x *= ratioX;
		br.x *= ratioX;
		bl.x *= ratioX;

		// normalize to screen coords (for orthographic display)
		tl.x /= Screen.width; tl.y /= Screen.height;
		tr.x /= Screen.width; tr.y /= Screen.height;
		br.x /= Screen.width; br.y /= Screen.height;
		bl.x /= Screen.width; bl.y /= Screen.height;

		// offset from zero to actual on-screen position
		tl += offset;
		tr += offset;
		bl += offset;
		br += offset;

		// get pointer to the mesh data
		List<Vector3> v = layer.vertices;

		// set corners in mesh data
		v[vpos] = new Vector3(tl.x, tl.y, 0);
		v[vpos + 1] = new Vector3(tr.x, tr.y, 0);
		v[vpos + 2] = new Vector3(br.x, br.y, 0);
		v[vpos + 3] = new Vector3(bl.x, bl.y, 0);

		// NB updating the on-screen mesh is handled outside this method
	}

Everything looks normal, and all my tests have shown the rotation maths to be correct, but somewhere along the line, the positions of each corner of the quad are getting screwed up.

Has anyone else done this in Unity and have an idea what the problem is?

Okay, I figured it out. Turns out I’m a moron of the Nth degree.

This code:

       tl.x = tl.x * cosine - tl.y * sine;
       tl.y = tl.x * sine + tl.y * cosine;
       tr.x = tr.x * cosine - tr.y * sine;
       tr.y = tr.x * sine + tr.y * cosine;
       br.x = br.x * cosine - br.y * sine;
       br.y = br.x * sine + br.y * cosine;
       bl.x = bl.x * cosine - bl.y * sine;
       bl.y = bl.x * sine + bl.y * cosine;

Needs to be:

        Vector2 tempTL = Vector2.zero, tempTR = Vector2.zero, 
                tempBL = Vector2.zero, tempBR = Vector2.zero;
		tempTL.x = tl.x * cosine - tl.y * sine;
		tempTL.y = tl.x * sine + tl.y * cosine;
		tempTR.x = tr.x * cosine - tr.y * sine;
		tempTR.y = tr.x * sine + tr.y * cosine;
		tempBR.x = br.x * cosine - br.y * sine;
		tempBR.y = br.x * sine + br.y * cosine;
		tempBL.x = bl.x * cosine - bl.y * sine;
		tempBL.y = bl.x * sine + bl.y * cosine;
		tl = tempTL;
		tr = tempTR;
		br = tempBR;
		bl = tempBL;

The problem was that when I came to rotate the y axis of each vector, I had already rotated the x axis, and this was messing up the y equation.

The real kick in the nuts? I had this exact same problem about four years ago, with the exact same solution, and I completely forgot about it. So much for learning from my mistakes :frowning: