[LibGDX]Get points of rotated rectangle?

I have a rectangle like this:

http://s12.postimg.org/6snvkhuw9/square.png

I then rotate it by 45 degrees and want to calculate the coordinates of the four white points.

The x/y position of an entity is the top left corner, where x is increasing moving rightwards and y downwards.

I don’t know if you are looking for something like this, but here:

This is a collision detection for rotating rectangle collision.

public class RotatingRegion {
	
	private Line2D.Float[] lines = new Line2D.Float[4];
	
	public float cx, cy;
	private float angle;
	private float x, y, width, height;
	
@@	public RotatingRegion(float x, float y, float width, float height){
		this(x, y, width, height, 0);
	}
@@	public RotatingRegion(float x, float y, float width, float height, float angle){
		cx = x + (width / 2);
		cy = y + (height / 2);
		this.angle = angle;
		this.x = x;
		this.y = y;
        	this.width = width;
		this.height = height;
		build();
       }
	
	public float angle(){
		return (float)Math.toDegrees(angle);
	}
	
	public void setCenter(float cx, float cy){
		this.cx = cx;
		this.cy = cy;
		x = cx - (width / 2);
		y = cy - (height / 2);
		build();
	}
	
@@	public void angle(float angle){
  		this.angle = angle;
  		build();
  	}
	
	public void build(){
		float[] point1 = rotateAroundCenter(x, y, angle);
		float[] point2 = rotateAroundCenter(x + width, y, angle);
		float[] point3 = rotateAroundCenter(x + width, y + height, angle);
		float[] point4 = rotateAroundCenter(x, y + height, angle);
		lines[0] = new Line2D.Float(point1[0], point1[1], point2[0], point2[1]);
		lines[1] = new Line2D.Float(point2[0], point2[1], point3[0], point3[1]);
		lines[2] = new Line2D.Float(point3[0], point3[1], point4[0], point4[1]);
		lines[3] = new Line2D.Float(point4[0], point4[1], point1[0], point1[1]);
	}
	
	public float[] rotateAroundCenter(float x, float y, float angle){
		float dx = x - cx;
		float dy = y - cy;
		float distance = (float) Math.sqrt(dx * dx + dy * dy);
		float originalAngle = getAngle(cx, cy, x, y);
		float newangle = originalAngle + angle;
		float ndx = distance * (float)Math.sin(newangle);
		float ndy = distance * (float)Math.cos(newangle);
		float nx = cx + ndx;
		float ny = cy + ndy;
		return new float[]{nx, ny};
	}
	
	public boolean intersects(float x, float y){
		for(int index = 0; index < lines.length; index++){
			if(lines[index].contains(x, y)){
				return true;
			}
		}
		return false;
	}
	
	public boolean contains(float x, float y){
		int intersections = 0;
		Line2D.Float test = new Line2D.Float(x - 1000, y - 1000, x, y);
		for(int index = 0; index < lines.length; index++){
			if(lines[index].intersectsLine(test)){
				intersections++;
			}
		}
		return intersections > 0 && intersections % 2 == 1;
	}
	
@@	public boolean contains(RotatingRegion region){
		for(int index1 = 0; index1 < region.lines.length; index1++){
			for(int index = 0; index < lines.length; index++){
				if(lines[index].intersectsLine(region.lines[index1])){
					return true;
				}
			}
		}		
		return false;
	}
	
	public static float getAngle(float mousex, float mousey, float playerx, float playery){
		float deltax = mousex - playerx;
		float deltay = mousey - playery;
		double rawangle = Math.atan2(deltay, deltax);
		float degrees = (float) Math.toDegrees(rawangle);
		degrees += 90.0f; // add 90 so opengl can use it
		if(degrees < 0){
			degrees += 360.0f; // fix all angles less than 0
		}
		if(degrees > 360.0f){
			degrees -= 360.0f; // fix all angles more than 360
		}
		degrees %= 360.0f;
		return (float) Math.toRadians(degrees);
	}

}

CopyableCougar4

Slightly shorter answer, if you would like to rotate a point around the origin (x = 0, y = 0) using degrees, you could use code like the following:

float sin = (float)Math.sin(Math.toRadians(angle));
float cos = (float)Math.cos(Math.toRadians(angle));

float rotatedX = x * cos - y * sin;
float rotatedY = x * sin + y * cos;

e.g. if the rectangle had a width and height of 10 and the centre of the rectangle is the origin (0, 0). Then the x, y values for top white point would be (0, -5), bottom (0, 5), left (-5, 0) and right (5, 0). Set angle as the rotation in degrees and rotatedX and rotatedY will give you the rotated result.

Also, with my previous code you can rotate points around the center by using my function [icode]rotateAroundCenter(float x, float y, float angle)[/icode] and just adding cx and cy as parameters :slight_smile:

CopyableCougar4

Room for some optimisation in your rotateAroundCenter() method by avoiding the expensive Math.sqrt() call, see method in my previous post.

What’s wrong with using AffineTransform? :persecutioncomplex:

how do I apply that to my coordinate system?

You’d have to translate all your points to put the centre of the rectangle at the origin, rotate, then translate back.

eg. x = x - midX; x = rotate(x); x = x + midX;

I stick by my question / suggestion above. Why not use AffineTransform? You set up the transform to rotate around the centre of your rectangle then pass in an array (float or double) of your points as a series [x1, y1, x2, y2, …] and get back an array of transformed points in the same configuration. Internally IIRC it’s pretty much doing what @kappa is suggesting, though caching various values.

Notes: AffineTransform is a pile of junk. Avoiding a sqrt is fine, but sqrt is only expensive compared to add/mul. It’s faster than division and much faster than trig. If you care about speed for something then don’t use angles.

Care to elaborate? :wink: I’ve no doubt you have a valid reason, but an example of how you’d solve the OP’s question would be good! :stuck_out_tongue:

The reason I suggested AffineTransform is that internally it’s doing @kappa’s suggestion, but could also handle the OP’s question around translation to his coordinate system, and it should perform just as well (possibly better if you naively implement and don’t cache the trig calls), and definitely faster than the other code posted above. It’s also simpler! Unless it’s actually a bottleneck, sometimes simpler is better.

Its not really clear from Op’s post whether he is using Java2D, another library or if he’s implementing his own 2d renderer, therefore I suggested a generic answer rather than pointing him to a specific API like AffineTransform.

It’s written to be reasonable on machines prior to the Pentium 3. On newer machines than that…it’s doing it complete wrong.

WRT: OP’s question. What is it? As is it only mentions a single rotation.

Care to elaborate more? ;D Now you’ve got me really intrigued and confused. What exactly is “wrong”, and what would be the correct approach?

It’s a pity it’s under awt, along with all the geometry classes, as they’re pretty toolkit agnostic really (assuming JDK and not Android).

Assumptions made: memory is fast, branches and jumps are fast and FP multiples are slow. zero for three. What it’s attempted to do is eliminate multiplies by zero and +/-1 by tracking or inspecting if the matrix is in a special case. Exponentially slower than performing the computation. You have:

x’ = m00x + m01y + m02
y’ = m10x + m11y + m12

stage 1: | t00= m00x | t01=m01y | t02=m10x | t3=m11y |
stage 2: | t11=t01+t02 | t12=t03+t04 |
stage 3: | t21=t11+m02 | t22=t03+m12 |

So if you had a CPU that could issue 4 multiples or 2 adds per clock, this computation takes three cycles to issue (ignoring loading and storing). Moving that to a more realistic 2 multiples issued per clock then this take 4 cycles to issue. Calling a multiply 5 cycles to complete, then the latency is about 10 cycles (too lazy to think it through).

Reading in the variable that specifies “what special case” from L1 cache to register takes 5 cycles of latency and everything goes massively downhill from there. So that 4000 line class would be much faster if it were probably less than 200.

@Roquen - thanks, always good when people back up their “pile of junk” statements with the logical argument behind it. :wink:

Bear in mind, though, that if you’re transforming a series of points, that special case is only checked once, whether you’re doing 1 point or 1000’s. I wonder how many it takes to actually be worth it!? :slight_smile:

The type tracking stuff is borderline useful at times too.

My code is not working. Can someone look at it? Btw using LibGDX.

	private Point2D.Float getSpawnPos(int rotation)
	{
		/*
		 * 0 degrees is facing west in my engine. Increasing this value is rotating clockwise.
		 */
		final double rot = Math.toRadians(rotation);
		final float midX = getCenterX(); //The center position of the entity in the world
		final float midY = getCenterY(); //The center position of the entity in the world
		final float sin = (float)Math.sin(rot);
		final float cos = (float)Math.cos(rot);

		//currX respective currY is the absolute position of the entity in the world(top-left corner of the entity)
		float x = currX - midX;
		float y = currY - midY;
		
		float rotatedX = x * cos - y * sin;
		float rotatedY = x * sin + y * cos;
		
		rotatedX += midX;
		rotatedY += midY;
		
		return new Point2D.Float(rotatedX, rotatedY);
	}

The returned point contains absurd values.

Well, the most obvious thing is that you’ve taken me slightly too literally :wink: - you need to translate your midY coordinates in the same way so that you’re rotating around 0,0!

That didnt work either. But I do not get it. What do you mean rotate around (0,0)? How am I suppose to calculate the position of the rotated point if I rotate around 0,0 instead of the entity´s position?

I know my code isn’t as efficient, but it works and is easier to see how to get each point.

 public Point2D.Float rotateAroundCenter(float x, float y, float angle, float cx, float cy) {
      float dx = x - cx;
      float dy = y - cy;
      float distance = (float) Math.sqrt(dx * dx + dy * dy);
      float originalAngle = getAngle(cx, cy, x, y);
      float newangle = originalAngle + angle;
      float ndx = distance * (float)Math.sin(newangle);
      float ndy = distance * (float)Math.cos(newangle);
      float nx = cx + ndx;
      float ny = cy + ndy;
      return new Point2D.Float(nx, ny);
   }

Returns the degree in radians.

public static float getAngle(float mousex, float mousey, float playerx, float playery) {
		float deltax = mousex - playerx;
		float deltay = mousey - playery;
		double rawangle = Math.atan2(deltay, deltax);
		float degrees = (float) Math.toDegrees(rawangle);
		degrees += 90.0f; // add 90 so opengl can use it
		if (degrees < 0) {
			degrees += 360.0f; // fix all angles less than 0
		}
		if (degrees > 360.0f) {
			degrees -= 360.0f; // fix all angles more than 360
		}
		degrees %= 360.0f;
		if (degrees > 180.0f) {
			degrees -= 360.0f;
		}
		return (float) Math.toRadians(degrees);
	}

:slight_smile:

CopyableCougar4

Thanks all. Solved it like this:

	 /**
	 * Rotates this entity and returns the updated {@code x} and {@code y} coordinates.
	 * @param x The relative x position we want after a rotation.
	 * @param y The relative y position we want after a rotation.
	 * @param rotation The angle in degrees.
	 * @return The point that contains the absolute coordinates.
	 */
	public Point2D.Float getRotatedPoint(float x, float y, int rotation)
	{
		if(width != height)
			throw new IllegalArgumentException("Width and height mismatch. The GameObject must use a square image!");
		
		final double rot = Math.toRadians(rotation);
		final float halfWidth = getWidth() / 2;
		
		y -= x;
		x -= x;
		
		y = -y;
		
		float rotX = (float) (x * Math.cos(rot) - y * Math.sin(rot));
		float rotY = (float) (y * Math.cos(rot) + x * Math.sin(rot));
		
		rotY = -rotY;
		
		rotX += halfWidth;
		rotY += halfWidth;
		
		return new Point2D.Float(rotX + currX, rotY + currY);
	}

Can probably be improved to work with rectangular shapes and not just squares.