So I am building a project in order to build a tetris style game, and I want to be able to test whether the shape will be able to be added to a 5 x 5 grid. The shape is modelled by a 2D array, where a 1 is considered to be a single block of the shape (the shapes are made of a few blocks). The shapes are modelled with a 3 x 3 grid. The thing I must do is check the grid for whether the shape will be able to fit on top of it. Take for example placing a line shape at the top square of the grid, the line will go out of bounds and should not work, or another example is that the grid may already have a shape on it and so the line should not be able to be put on top of it.
This is the code that I've got thus far, and it is not working, I'm just really having a tough time conceptualising what to do. Thank you in advance.
Please note that cols is the number of columns in the grid (5) and rows is the same (5). Game piece is the shape, and the co-ordinates is where the user has clicked on the 5x5 grid.
Also: The anchor point of the shape is 1,1 of the 3x3 grid (so the anchor point is right in the middle of the grid). And get(int x, int y) method is getting the value stored in the 5x5 grid.
Sorry if this was not made clear in the beginning but I am trying to basically see whether the shape stored in the 3x3 grid (made up of blocks) can be placed on top of the 5x5 grid. The 3x3 grid that contains the block has a centre anchor point, so it would be 1,1 (since arrays start with 0). If the 5x5 grid has other blocks that are at the same co-ordinate of the new shape being added, then I want it to return false or if the shape becomes out of bounds when being placed on the 5x5 grid, but if it can be added successfully then it will return true.
public boolean canPlayPiece (GamePiece piece, int x, int y) {
logger.info("canPlayPiece - Block clicked coordinates: " + x + "," + y);
// Piece co-ordinates are 3 x 3, each element that is 1 means there is a block there
int[][] pieceCoordinates = piece.getBlocks();
// For loop to iterate through the grid
// first looping through x values
for (int i = x - 1; i < cols; i++) {
System.out.println("i= " + i);
// nested for loop to find the y values stored inside the x
for (int j = y - 1; j < rows; j++) {
System.out.println("j: " + j);
if (pieceCoordinates[x][y] == 1 && get(i,j) != 0) {
logger.info("canPlayPiece: FALSE");
return false;
}
}
}
logger.info("canPlayPiece: TRUE");
return true;
}
Ok i made the following for you:
public boolean canPlayPiece(GamePiece piece, int x, int y) {
int[][] pc = piece.getBlocks();
final int w = 3, h = 3, e = w - 1;
final int offX = -1, offY = -1; // The offset of the left top corner from 'x' and 'y'
int i, si, ei, ax, ay, rx, ry;
for (ei = w * h - 1; ei >= 0 && pc[ei / w][ei % w] == 0; ei--);
for (si = 0; si <= ei && pc[si / w][si % w] == 0; si++);
for (i = si + 1, ax = si % w; ax > 0 && i <= ei; i++) if (pc[i / w][rx = i % w] != 0) { si += Math.min(rx - ax, 0); ax = rx; }
for (i = ei - 1, ax = ei % w; ax < e && i >= si; i--) if (pc[i / w][rx = i % w] != 0) { ei += Math.max(rx - ax, 0); ax = rx; }
if (si > ei) return true; // There is no block in the piece's grid
int sx = si % w, sy = si / w, ex = ei % w, ey = ei / w; // The bounds of the shape inside of pc
int asx = x + offX + sx, asy = y + offY + sy, aex = asx + ex - sx, aey = asy + ey - sy;
if ((asx | asy | aex | aey | cols - 1 - aex | rows - 1 - aey) < 0) return false; // Would be out of bounds
for (rx = sx, ax = asx; rx <= ex; rx++, ax++) {
for (ry = sy, ay = asy; ry <= ey; ry++, ay++) {
// if (grid[ay][ax] != 0 && pc[ry][rx] != 0) return false; // Block overlaps another block
if (get(ax, ay) != 0 && pc[ry][rx] != 0) return false; // Block overlaps another block
}
}
return true;
}
First it figues out the bounds of the shape inside of 'pc' grid (the grid returned by 'piece.getBlocks()')
If there is no shape inside of 'pc' it will return true, since an empty shape can be placed anywhere (change the return value to false, if you want to return false in that case)
If the inner shape would go out of bounds, when being inserted, it will return false
In the end it will walk through both the grid (using your 'get(x: int, y: int) function) and 'pc' to check whether the shape in 'pc' overlaps with any preexisting blocks inside the grid. And if it doesn't it returns true.
I really hope that this works for you. I tested it out and it worked at least for me.
I have an XML - list of xy-coordinates (vertices) that define the edge of a polygon. I read this file and save the vertices in an ArrayList. Now I would like to iterate over the finished ArrayList and compare two vertices with each other to decide whether the edge connecting both vertices is a north, west, south, or east edge of the simple polygon.
This is the code I can use to test whether the edge that makes up two points is a north, west, east, or south edge.
enum EdgeType {TOP, BOTTOM, LEFT, RIGHT, EMPTY}
public EdgeType orthoEdgeTypeCCW(double x0, double y0, double x1, double y1)
{
if(x0 == x1) // vertical
{
return (y0 < y1) ? EdgeType.RIGHT :
(y0 > y1) ? EdgeType.LEFT :
EdgeType.EMPTY;
}
else if(y0 == y1) // horizontal
{
return (x0 < x1) ? EdgeType.BOTTOM :
(x0 > x1) ? EdgeType.TOP :
EdgeType.EMPTY;
}
else
{
throw new IllegalArgumentException("Edge not orthogonal");
}
}
I have two concerns for which I don't find a solution:
First I would like to test whether the vertices are sorted clockwise or counterclockwise. Accordingly, I would have to change the code for the edge types.
Second I don't know how I can iterate over the ArrayList of vertices in order to compare two of the vertices at each step.
For example in the first step v1 with v2, in the second v2 with v3, in the third v3 with v4 and so on.. Can I perhaps address the vertices in the ArrayList with their indices?
For a simple orthogonal polygon with no self-intersections you can determine its orientation (CW|CCW) by finding the lower left corner point and determining if the y value of the next point is equal to (CCW) or greater (CW).
enum Orientation {CW, CCW}
public Orientation orientation(List<Point2D> points)
{
int minIdx = 0;
for(int i=1; i<points.size(); i++)
if(pointOrder(points.get(i), points.get(minIdx)) <= 0) minIdx = i;
int nextIdx = (minIdx+1) % points.size();
if(points.get(nextIdx).getY() == points.get(minIdx).getY())
return Orientation.CCW;
else
return Orientation.CW;
}
public int pointOrder(Point2D p1, Point2D p2)
{
if(p1.getY() < p2.getY()) return -1;
else if(p1.getY() > p2.getY()) return 1;
else if(p1.getX() < p2.getX()) return -1;
else if(p1.getX() > p2.getX()) return 1;
else return 0;
}
Once you have the orientation you can iterate through the edges to determine their type.
for(int i=0, j=points.size()-1; i<points.size(); j=i++)
{
EdgeType edgeType = orthoEdgeTypeCCW(points.get(j), points.get(i));
System.out.format("%s -> %s : %s%n", points.get(j), points.get(i), edgeType);
}
With
public EdgeType orthoEdgeTypeCCW(Point2D p1, Point2D p2)
{
if(p1.getX() == p2.getX()) // vertical
{
return (p1.getY() < p2.getY()) ? EdgeType.RIGHT :
(p1.getY() > p2.getY()) ? EdgeType.LEFT :
EdgeType.EMPTY;
}
else if(p1.getY() == p2.getY()) // horizontal
{
return (p1.getX() < p2.getX()) ? EdgeType.BOTTOM :
(p1.getX() > p2.getX()) ? EdgeType.TOP :
EdgeType.EMPTY;
}
else
{
throw new IllegalArgumentException("Edge not orthogonal");
}
}
Obviously the type for CW polygons is reversed.
Regarding your first question, there are a number of ways to find the orientation of a polygon. See the discussion on SO here.
As for comparing the points in a polygon, you can do something like the below:
List<Point2D.Float> points = new ArrayList<>(); //your initial set of points
for (int i = 0; i < points.size(); i++) {
Point2D.Float current = points.get(i);
Point2D.Float next = points.get((i + 1) % points.size());
//do your comparison between the two points here
}
This will compare each point with the next, including comparing the last point with the first to 'close the loop'. If this isn't needed, you can do a small change to stop as soon as the last point is reached:
List<Point2D.Float> points = new ArrayList<>(); //your initial set of points
for (int i = 0; i < points.size() - 1; i++) {
Point2D.Float current = points.get(i);
Point2D.Float next = points.get((i + 1));
}
I have a program where an entity moves around in two-dimensional space. To move one step, the entity picks its next point, and then sets it as his current point.
Sometimes, however, the entity's next point lies in an Area (java.awt.geom.Area) that is forbidden (the "forbidden area" is actually a velocity obstacle).
How can the entity pick the point outside the Area which is closest to the entity's preferred point?
The Area is composed of different shapes (sometimes, the shapes are not touching).
My initial plan was to simply draw a line to the preferred point. Wherever the line intersected the Area first, this would be the next-best point. However, finding the intersection between a line and an Area turns out to be quite complex.
EDIT: This wouldn't necessarily find the closest point. This would just find the closet point on the same trajectory. I'm looking for the closest possible point.
Perhaps Area isn't the best class to use. All I require is something that can add multiple shapes, even when the shapes aren't touching.
I've solved the problem:
First, find all the line segments that constrain the Area. I've written code to do that on a different answer.
Then, it's just a matter of iterating through each line segment, and recording the point on the segment that's closest to the entity's desired point. Store these in the data structure of your choice (e.g., an ArrayList).
See: Shortest distance between a point and a line segment
Lastly, determine which of the points is closest to the desired point. VoilĂ !
Here's a demonstration:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
public class AreaTest extends JFrame{
private static final long serialVersionUID = -2221432546854106311L;
Area area = new Area();
ArrayList<Line2D.Double> areaSegments = new ArrayList<Line2D.Double>();
Point2D.Double insidePoint = new Point2D.Double(225, 225);
Point2D.Double closestPoint = new Point2D.Double(-1, -1);
Point2D.Double bestPoint = new Point2D.Double(-1, -1);
ArrayList<Point2D.Double> closestPointList = new ArrayList<Point2D.Double>();
AreaTest() {
Path2D.Double triangle = new Path2D.Double();
Random random = new Random();
// Draw three random triangles
for (int i = 0; i < 3; i++) {
triangle.moveTo(random.nextInt(400) + 50, random.nextInt(400) + 50);
triangle.lineTo(random.nextInt(400) + 50, random.nextInt(400) + 50);
triangle.lineTo(random.nextInt(400) + 50, random.nextInt(400) + 50);
triangle.closePath();
area.add(new Area(triangle));
triangle.reset();
}
// Place a point inside the area
if (!area.contains(insidePoint)); {
while (!area.contains(insidePoint)) {
insidePoint.setLocation(random.nextInt(400) + 50, random.nextInt(400) + 50);
}
}
// Note: we're storing double[] and not Point2D.Double
ArrayList<double[]> areaPoints = new ArrayList<double[]>();
double[] coords = new double[6];
for (PathIterator pi = area.getPathIterator(null); !pi.isDone(); pi.next()) {
// Because the Area is composed of straight lines
int type = pi.currentSegment(coords);
// We record a double array of {segment type, x coord, y coord}
double[] pathIteratorCoords = {type, coords[0], coords[1]};
areaPoints.add(pathIteratorCoords);
}
double[] start = new double[3]; // To record where each polygon starts
for (int i = 0; i < areaPoints.size(); i++) {
// If we're not on the last point, return a line from this point to the next
double[] currentElement = areaPoints.get(i);
// We need a default value in case we've reached the end of the ArrayList
double[] nextElement = {-1, -1, -1};
if (i < areaPoints.size() - 1) {
nextElement = areaPoints.get(i + 1);
}
// Make the lines
if (currentElement[0] == PathIterator.SEG_MOVETO) {
start = currentElement; // Record where the polygon started to close it later
}
if (nextElement[0] == PathIterator.SEG_LINETO) {
areaSegments.add(
new Line2D.Double(
currentElement[1], currentElement[2],
nextElement[1], nextElement[2]
)
);
} else if (nextElement[0] == PathIterator.SEG_CLOSE) {
areaSegments.add(
new Line2D.Double(
currentElement[1], currentElement[2],
start[1], start[2]
)
);
}
}
// Calculate the nearest point on the edge
for (Line2D.Double line : areaSegments) {
// From: https://stackoverflow.com/questions/6176227
double u =
((insidePoint.getX() - line.x1) * (line.x2 - line.x1) + (insidePoint.getY() - line.y1) * (line.y2 - line.y1))
/ ((line.x2 - line.x1) * (line.x2 - line.x1) + (line.y2 - line.y1) * (line.y2 - line.y1));
double xu = line.x1 + u * (line.x2 - line.x1);
double yu = line.y1 + u * (line.y2 - line.y1);
if (u < 0) {
closestPoint.setLocation(line.getP1());
} else if (u > 1) {
closestPoint.setLocation(line.getP2());
} else {
closestPoint.setLocation(xu, yu);
}
closestPointList.add((Point2D.Double) closestPoint.clone());
if (closestPoint.distance(insidePoint) < bestPoint.distance(insidePoint)) {
bestPoint.setLocation(closestPoint);
}
}
setSize(new Dimension(500, 500));
setLocationRelativeTo(null); // To center the JFrame on screen
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);
}
public void paint(Graphics g) {
// Fill the area
Graphics2D g2d = (Graphics2D) g;
g.setColor(Color.lightGray);
g2d.fill(area);
// Draw the border line by line
g.setColor(Color.black);
for (Line2D.Double line : areaSegments) {
g2d.draw(line);
}
// Draw the inside point
g.setColor(Color.red);
g2d.fill(
new Ellipse2D.Double(
insidePoint.getX() - 3,
insidePoint.getY() - 3,
6,
6
)
);
// Draw the other close points
for (Point2D.Double point : closestPointList) {
g.setColor(Color.black);
g2d.fill(
new Ellipse2D.Double(
point.getX() - 3,
point.getY() - 3,
6,
6
)
);
}
// Draw the outside point
g.setColor(Color.green);
g2d.fill(
new Ellipse2D.Double(
bestPoint.getX() - 3,
bestPoint.getY() - 3,
6,
6
)
);
}
public static void main(String[] args) {
new AreaTest();
}
}
Here's the result:
And again:
View my answer on this post
You can get the closest point outside of a polygon with a simple and lightweight approach:
Simply find the closest line segment, and find the perpendicular angle to that segment that intercepts the input point.
Example Code:
Vector2 is 2 doubles, x and y (Like Unity)
public class PolyCollisions {
// Call this function...
public static Vector2 doCollisions (Vector2[] polygon, Vector2 point) {
if(!pointIsInPoly(polygon, point)) {
// The point is not colliding with the polygon, so it does not need to change location
return point;
}
// Get the closest point off the polygon
return closestPointOutsidePolygon(polygon, point);
}
// Check if the given point is within the given polygon (Vertexes)
//
// If so, call on collision if required, and move the point to the
// closest point outside of the polygon
public static boolean pointIsInPoly(Vector2[] verts, Vector2 p) {
int nvert = verts.length;
double[] vertx = new double[nvert];
double[] verty = new double[nvert];
for(int i = 0; i < nvert; i++) {
Vector2 vert = verts[i];
vertx[i] = vert.x;
verty[i] = vert.y;
}
double testx = p.x;
double testy = p.y;
int i, j;
boolean c = false;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
// Gets the closed point that isn't inside the polygon...
public static Vector2 closestPointOutsidePolygon (Vector2[] poly, Vector2 point) {
return getClosestPointInSegment(closestSegment(poly, point), point);
}
public static Vector2 getClosestPointInSegment (Vector2[] segment, Vector2 point) {
return newPointFromCollision(segment[0], segment[1], point);
}
public static Vector2 newPointFromCollision (Vector2 aLine, Vector2 bLine, Vector2 p) {
return nearestPointOnLine(aLine.x, aLine.y, bLine.x, bLine.y, p.x, p.y);
}
public static Vector2 nearestPointOnLine(double ax, double ay, double bx, double by, double px, double py) {
// https://stackoverflow.com/questions/1459368/snap-point-to-a-line-java
double apx = px - ax;
double apy = py - ay;
double abx = bx - ax;
double aby = by - ay;
double ab2 = abx * abx + aby * aby;
double ap_ab = apx * abx + apy * aby;
double t = ap_ab / ab2;
if (t < 0) {
t = 0;
} else if (t > 1) {
t = 1;
}
return new Vector2(ax + abx * t, ay + aby * t);
}
public static Vector2[] closestSegment (Vector2[] points, Vector2 point) {
Vector2[] returns = new Vector2[2];
int index = closestPointIndex(points, point);
returns[0] = points[index];
Vector2[] neighbors = new Vector2[] {
points[(index+1+points.length)%points.length],
points[(index-1+points.length)%points.length]
};
double[] neighborAngles = new double[] {
getAngle(new Vector2[] {point, returns[0], neighbors[0]}),
getAngle(new Vector2[] {point, returns[0], neighbors[1]})
};
if(neighborAngles[0] < neighborAngles[1]) {
returns[1] = neighbors[0];
} else {
returns[1] = neighbors[0];
}
return returns;
}
public static double getAngle (Vector2[] abc) {
// https://stackoverflow.com/questions/1211212/how-to-calculate-an-angle-from-three-points
// atan2(P2.y - P1.y, P2.x - P1.x) - atan2(P3.y - P1.y, P3.x - P1.x)
return Math.atan2(abc[2].y - abc[0].y, abc[2].x - abc[0].x) - Math.atan2(abc[1].y - abc[0].y, abc[1].x - abc[0].x);
}
//public static Vector2 lerp (Vector2 a, Vector2 b, double c) {
//
// return new Vector2(c*(a.x-b.x)+b.x, c*(a.y-b.y)+b.y);
//
//}
/*public static Vector2 closestPoint (Vector2[] points, Vector2 point) {
int leastDistanceIndex = 0;
double leastDistance = Double.MAX_VALUE;
for(int i = 0; i < points.length; i++) {
double dist = distance(points[i], point);
if(dist < leastDistance) {
leastDistanceIndex = i;
leastDistance = dist;
}
}
return points[leastDistanceIndex];
}*/
public static int closestPointIndex (Vector2[] points, Vector2 point) {
int leastDistanceIndex = 0;
double leastDistance = Double.MAX_VALUE;
for(int i = 0; i < points.length; i++) {
double dist = distance(points[i], point);
if(dist < leastDistance) {
leastDistanceIndex = i;
leastDistance = dist;
}
}
return leastDistanceIndex;
}
public static double distance (Vector2 a, Vector2 b) {
return Math.sqrt(Math.pow(Math.abs(a.x-b.x), 2)+Math.pow(Math.abs(a.y-b.y), 2));
}
}
Useful Links / Answers
Snap Point to Line
How to calculate an angle from 3 points
The most easy (and most inefficient) approach would be a brute force.
You have a preferred point inside an area. to find the closest point to it: hold two variables, one for minimal distance and one for current closest point. now simply step over every other point in your two dimensional space: if that point is not inside the forbidden area (or any forbidden area if there are many), then calculate the distance between it and the preferred point. If that distance is less than the current minimal distance, then make it become the current minimal distance and make the point become the current closest point.
when you finish, you will have the closest point outside the area and if none was found, you stay on your original point.
I am not specialist in geometry algorithms, but if the two dimensional space is very big and the calculation is not finishing fast enough, maybe you can try to improve it with the following: the Area class has a contains method that "tests if the interior of the Shape entirely contains the specified rectangular area". therefore, start creating rectangles(or squares) around the preferred point. you start with the minimal rectangle surrounding the point and on every loop you increase it by one point in each direction. for every rectangle that you create, check if it is contained in the area. you stop calculating rectangles when you hit the first rectangle that is not entirely contained in the area. then, you use the above algorithm (the brute force) but only on points contained in this rectangle and that are not inside the area.
The formula for distance between two points is (javascript):
var xDiff = ( point1x - point2x ),
yDiff = ( point1y - point2y ),
distance = Math.sqrt( ( xDiff * xDiff ) + ( yDiff * yDiff ) );
Loop around your "proposed new point", starting at one x-1, y-1 to x+1, y+1. At each point check to see that it's not a forbidden point, not the point you just came from, and not off the boundaries of the map. If it meets all those criteria, use the above formula to measure the distance and add it to an array. At the end of your "1-point out" loop, check if there are any distances in that array. If so, take the smallest one and you're done. If there aren't any, move onto x-2, y-2 to x+2, y+2 (2 points out).
This will be extremely fast for the small area you are referring to.
Demo: http://jsfiddle.net/ThinkingStiff/V7Bqm/
var X = 0,
Y = 1,
currentPoint = [5,5],
proposedPoint = [5,6],
forbiddenPoints = [[5,6],[6,6],[4,7],[5,7],[6,7],[4,8],[5,8]],
map = { left:1, top:1, right:10, bottom:10 };
function closestSafePoint( point ) {
var x = point[X], y = point[Y], safePoints = [];
for( var left = x - 1, top = y - 1, right = x + 1, bottom = y + 1;
left <= map.left || top <= map.top || right <= map.right || bottom <= map.bottom;
left--, top--, right++, bottom++) {
checkHorizontalPoints( safePoints, point, left, right, top );
checkHorizontalPoints( safePoints, point, left, right, bottom );
checkVerticalPoints( safePoints, point, top + 1, bottom - 1, left );
checkVerticalPoints( safePoints, point, top + 1, bottom - 1, right );
safePoints.sort( function( a, b ){ return a[1] - b[1] } );
return safePoints.length ? safePoints[0] : point;
};
};
function checkHorizontalPoints( points, fromPoint, startX, endX, y ) {
for( var x = startX; x <= endX ; x++ ) {
var toPoint = [x, y];
if( !isForbidden( toPoint ) && !isCurrent( toPoint) && onMap( toPoint ) ) {
points.push( [toPoint, distance( fromPoint, toPoint )] );
};
};
};
function checkVerticalPoints( points, fromPoint, startY, endY, x ) {
for( var y = startY; y <= endY ; y++ ) {
var toPoint = [x, y];
if( !isForbidden( toPoint ) && !isCurrent( toPoint) && onMap( toPoint ) ) {
points.push( [toPoint, distance( fromPoint, toPoint )] );
};
};
};
function isForbidden( point ) {
for( var index = 0; index < forbiddenPoints.length; index++ ) {
if( forbiddenPoints[index].toString() == point.toString() ) return true;
};
};
function isCurrent( point ) {
return currentPoint.toString() == point.toString() ? true : false;
};
function onMap( point ) {
var x = point[X], y = point[Y];
return x >= map.left && y >= map.top && x <= map.right && y <= map.bottom;
};
function distance( pointA, pointB ) {
var xDiff = ( pointA[X] - pointB[X] ),
yDiff = ( pointA[Y] - pointB[Y] );
return Math.sqrt( ( xDiff * xDiff ) + ( yDiff * yDiff ) );
};
console.log(
'current: ' + currentPoint + ', '
+ 'proposed: ' + proposedPoint + ', '
+ 'closest: ' + closestSafePoint( proposedPoint )[0]
);
One optimization you could make to this, if you're fairly sure most of your safe spots will be one or two points away is to break out as soon as you get to a point thats distance is the same as the level you're on. So if you're on loop one, and you get a point that is distance = 1, stop, since you'll never get closer than that.
UPDATE: I noticed you added "same trajectory" to your question. But in one of the comments, you also say it can't jump over the forbidden area. Those statements seem to conflict.
Same trajectory is a little more tricky and requires some trig. Check out my demo of circular divs at http://jsfiddle.net/ThinkingStiff/uLu7v/. There is a "point on ray" function halfway down at:
$this.siblings( ".circle" ).each( function()
This calculates the distance to move the surrounding circles on a ray away from the selected circle. This could be used to calculate a point on your trajectory. But, I think my original function is actually what you're looking for and you didn't mean same trajectory.
I need to find an algorithm which determines a relationship between a square and rectangle. It must be able to determine if:
The square is completely inside the rectangle
The square is partially inside (overlaps) the rectangle
Square's corner only touches a rectangle's corner
Square's edge is on the rectangle's edge
And here are the inputs (given values) that will help us to extract a mathematical formula for each case:
x coordinate of the center of the square = squareX
y coordinate of the center of the square = squareY
width of the square = squareW
x coordinate of the center of the rectangle = recX
y coordinate of the center of the rectangle = recY
width of the rectangle = recW
length of the rectangle = recL
P.S: Rectangle's sizes are always bigger than the square's width.
I will write the code in Java once we can extract an algorithm using mathematical operations.
Edit:
For the case of corners in touch, here is the code I wrote, and it works (Math.abs means the absolute value):
((Math.abs(Math.abs(recX-squareX)-(recW+squareW)/2))<=0.001) && ((Math.abs(Math.abs(recY-squareY)-(recL+squareW)/2))<=0.001)
updated for doubles
double dx = Math.abs(rectX - squareX);
double dy = Math.abs(rectY - squarey);
double dw2 = (rectW + squareW) / 2;
double dh2 = (rectL + squareW) / 2;
if (Double.compare(dx, dw2) == 0 && Double.compare(dy, dh2) == 0)
return CORNER_TOUCH;
else if (Double.compare(dx, dw2) > 0 || Double.compare(dy, dh2) > 0)
return OUTSIDE;
else if (Double.compare(dx, dw2) == 0 || Double.compare(dy, dh2) == 0)
return EDGE_TOUCH;
else if (Double.compare(dx, rectW - dw2) <= 0 &&
Double.compare(dy, rectL - dh2) <= 0)
return INSIDE;
else
return OVERLAPS;
squareX1 = squareX - squareW/2
squareY1 = squareY - squareW/2
squareX2 = squareX + squareW/2
squareY2 = squareY + squareW/2
recX1 = recX - recW/2
recY1 = recY - recL/2
recX2 = recX + recW/2
recY2 = recY + recL/2
inside = squareX1 > recX1 && squareX2 < recX2 && squareY1 > recY1 && squareY2 < recY2
overlaps = squareX1 < recX2 && squareX2 > recX1 && squareY1 < recY2 && squareY2 > recY1
the last two one should be trivial