Rotated Rectangle collision

So I have a custom Shape object with intersection for points, but I want to test the shapes for collision with a rotated rectangle. I have looked all over, including AffineTransform, Path2D, etc. but I couldn’t find a solution to my problem.

Here is the Shape class. create() finalizes the shape:


package game.util;

import java.awt.geom.Line2D;
import java.util.ArrayList;

import static org.lwjgl.opengl.GL11.*;

public class Shape {
	
	private ArrayList<Coordinate> points = new ArrayList<Coordinate>();
	private ArrayList<Line2D.Float> intersectionTest = new ArrayList<Line2D.Float>(); 
	
	public Shape(){
	}
	
	public void addPoint(float x, float y){
		points.add(new Coordinate(x, y));
		if(points.size() >= 2){
			Coordinate last = points.get(points.size() - 2);
			intersectionTest.add(new Line2D.Float(last.x, last.y, x, y));
		}
	}
	public void create(){
		// last point
		Coordinate last = points.get(points.size() - 1);
		Coordinate first = points.get(0);
		intersectionTest.add(new Line2D.Float(last.x, last.y, first.x, first.y));
	}
	
	public boolean intersects(float x, float y){
		int intersections = 0;
		Line2D.Float original = new Line2D.Float(x - 1000, y - 1000, x, y);
		for(Line2D.Float intersectionTestLine : intersectionTest){
			if(original.intersectsLine(intersectionTestLine)){
				intersections++;
			}
		}
		return intersections > 0 && intersections % 2 == 1;
	}
	public boolean intersects(Shape shape){
		for(Line2D.Float intersectionTestLine : intersectionTest){
			for(Line2D.Float intersectionOtherLine : shape.intersectionTest){
				if(intersectionOtherLine.intersectsLine(intersectionTestLine)){
					return true;
				}
			}
		}
		return false;
	}
	
	private static class Coordinate {
		private float x, y;
		public Coordinate(float x, float y){
			this.x = x;
			this.y = y;
		}
	}
	
	public void debug(){
		glColor3f(0.0f, 0.0f, 1.0f);
		glBegin(GL_LINE_STRIP);
		for(int index = 0; index < intersectionTest.size(); index++){
			Line2D.Float line = intersectionTest.get(index);
			drawLine(line);
		}
		glEnd();
		glColor3f(1.0f, 1.0f, 1.0f);
	}
	private void drawLine(Line2D.Float line){
		glVertex2f(line.x1, line.y1);
		glVertex2f(line.x2, line.y2);
	}

}

And here is what I have so far for my rotated rectangle, however it doesn’t seem to work…


package game.util;

import java.awt.geom.Line2D;

import static org.lwjgl.opengl.GL11.*;

public class RotatingRectangle {
	
	private float x1, x2, x3, x4, y1, y2, y3, y4, x, y, width, height;
	private Line2D.Float line1, line2, line3, line4;
	private Shape shape;
	
	public RotatingRectangle(float x, float y, float width, float height){
		x1 = x;
		x2 = x + width;
		x3 = x + width;
		x4 = x;
		y1 = y;
		y2 = y;
		y3 = y + height;
		y4 = y + height;
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}
	
	public void setCenterX(float cx){
		x = cx - (width / 2);
	}
	public void setCenterY(float cy){
		y = cy - (height / 2);
	}
	
	public void debug(){
		glColor3f(1.0f, 0.0f, 0.0f);
		glBegin(GL_LINE_STRIP);
		glVertex2f(x1, y1);
		glVertex2f(x2, y2);
		glVertex2f(x3, y3);
		glVertex2f(x4, y4);
		glVertex2f(x1, y1);
		glEnd();
		glColor3f(1.0f, 1.0f, 1.0f);
	}
	
	public RotatingRectangle rotate(float radians){
		// rotate each point
		Point p1 = rotate(radians, x, y);
		x1 = p1.x;
		y1 = p1.y;
		Point p2 = rotate(radians, x + width, y);
		x2 = p2.x;
		y2 = p2.y;
		Point p3 = rotate(radians, x + width, y + height);
		x3 = p3.x;
		y3 = p3.y;
		Point p4 = rotate(radians, x, y + height);
		x4 = p4.x;
		y4 = p4.y;	
		createShape();
		return this;
	}
	
	public void createShape(){
		shape = new Shape();
		shape.addPoint(x1, y1);
		shape.addPoint(x2, y2);
		shape.addPoint(x3, y3);
		shape.addPoint(x4, y4);
		shape.create();
	}
	
	public boolean intersects(Shape shape_){
		return shape.intersects(shape_);
	}
	
	// You can only rotate a shape once
	public Point rotate(float radians, float x, float y){
		float cx = this.x + (width / 2);
		float cy = this.y + (height / 2);
		float dx = cx - x;
		float dy = cy - y;
		float hypotenuse = (float) StrictMath.sqrt(dx * dx + dy * dy);
		float oldAngle = (float) Math.tan(dx / dy);
		float ndx = hypotenuse * (float) Math.sin(oldAngle + radians);
		float ndy = hypotenuse * (float) Math.cos(oldAngle + radians);
		float nx = ndx + cx;
		float ny = ndy + cy;
		return new Point(nx, ny);
	}
	
	private static class Point {
		
		private float x, y;
		public Point(float x, float y){
			this.x = x;
			this.y = y;
		}
		
	}

}

Sorry that the code is so all over the place. Any help with the collision would be appreciated. (Also, the Shape object collision seems to work 100% correctly, rotated rectangle seems to be where the problem lies)

CopyableCougar4

i didn’t read the code yet but usually you could just unrotate the square and apply axis aligned bounding square (aabb) tests.

I don’t want to unrotate the the square I want to keep it rotated and check that collision.

CopyableCougar4

Lets say you have a Rectangle called R. You also have a point called P. You rotate R by 35 degrees. To check if P collides with R, you rotate P around the point you rotated R (center of R probably) by 35 degrees and check for collision like you would normally.

That’s what I did but I seem to get the collision way off. If you want to see it see the function [icode]Point rotate(radians, x, y)[/icode]

CopyableCougar4

I would suggest you get rid off all abstractions at first and work on getting the basics down first. Its really much harder to fix bugs on lower level when you have abstractions.

What do you mean abstractions? The Shape object and RotatedRectangle object is about as simple as it can get. And the Shape object collision works just fine.

CopyableCougar4

Search.

This is a trimmed down code that just shows the only possible location for the problem:


public RotatingRectangle rotate(float radians){
		// rotate each point
		Point p1 = rotate(radians, x, y);
		x1 = p1.x;
		y1 = p1.y;
		Point p2 = rotate(radians, x + width, y);
		x2 = p2.x;
		y2 = p2.y;
		Point p3 = rotate(radians, x + width, y + height);
		x3 = p3.x;
		y3 = p3.y;
		Point p4 = rotate(radians, x, y + height);
		x4 = p4.x;
		y4 = p4.y;	
		createShape(); // just takes the four corners and makes four lines for intersection testing
		return this;
	}
public Point rotate(float radians, float x, float y){
		float cx = this.x + (width / 2);
		float cy = this.y + (height / 2);
		float dx = cx - x;
		float dy = cy - y;
		float hypotenuse = (float) StrictMath.sqrt(dx * dx + dy * dy);
		float oldAngle = (float) Math.tan(dx / dy);
		float ndx = hypotenuse * (float) Math.sin(oldAngle + radians);
		float ndy = hypotenuse * (float) Math.cos(oldAngle + radians);
		float nx = ndx + cx;
		float ny = ndy + cy;
		return new Point(nx, ny);
	}

CopyableCougar4

I may just have to put my “wonderful” rotating collision detection on hold, as I am unsure whether I have the brainpower to solve this problem…

CopyableCougar4

more coffee!

:slight_smile:

Hi CopyableCougar4 :stuck_out_tongue:

I didnt read your code, but since you say that your AABB algorithm is working fine, I can refer to the two best(in my opinion), and well, ‘not so simple’ tutorials for SAT (Separated Axis Theorem) collision detection, which is fairly easy once you get into it.

The first is: http://gamedevelopment.tutsplus.com/tutorials/collision-detection-using-the-separating-axis-theorem--gamedev-169

The other: is very informative as-well, but very different. Here you can also play around with a few flash demos, which visualize the math/problem:http://www.metanetsoftware.com/technique/tutorialA.html

I’m sorry, I cannot read your code now, too much stuff to do.
But even if you are advanced, maybe redo it, print out every step in your console BEFORE moving on to the next step, and keep going, if anything breaks, stop and check.

I dont want to sound like: ‘DELETE -> DO IT AGAIN’, but for me, when i get ahead of myself, i grab a piece of paper, draw out the math, and test, then get to java, and print my math to the console, then apply to actual shapes etc.
One time, in the collision geometry calculations i had a simple ‘casting problem’, but actually everything was calculated the right way, and finally i narrowed it down to a set of parenthesis, i printed it to the console, and the result was completely alien… a simple set of parenthesis ^^

I usually get ahead of myself, and then i have to redo it again.

Greetings and all the best, i hope the links help you somewhat.

Empty your cup, then fill it again with a fresh attitude :stuck_out_tongue: