I would like to group/merge/union rectangles that are close (similar) to each other. There is no particular reason why I tried this recursively but it seemed appropriate.
However I am missing something here. The output is not correct and I did not consider the fact that rectangles that are merged later down the road might be close now to rectangles that I considered "un-mergeable" and put into the finalList
The merging and the check closeness method are working properly.
public static ArrayList<Rect> mergeCloseRects(ArrayList<Rect> sourceList, ArrayList<Rect> finalList) {
Rect rect = sourceList.get(0).clone();
sourceList.remove(0);
for (int i = 0; i < sourceList.size(); i++) {
if (rectsAreClose(rect, sourceList.get(i)) {
// put merged rectangle on top of the list
sourceList.add(0, getMergeRect(rect, sourceList.get(i)));
// remove rectangle that was merged with rect
sourceList.remove(i + 1);
mergeCloseRects(sourceList, finalList);
}
}
// if rect has no close neighbours
finalList.add(rect);
return finalList;
}
Input
Output
As you can see the rectangles are not really merged. The lower rectangle stayed in the list. The green outline tells where the new rectangle(s) will be.
This seems to me to be a better fit for iteration than recursion: you can naturally keep going until there is nothing left to merge. I would think your code should look something like:
while(!getListCloseRectangles(sourceList).isEmpty()) {
List<Rect> rectanglesToMerge = getListCloseRectangles(sourceList);
sourceList.removeAll(rectanglesToMerge);
sourceList.add(createMergedRect(rectanglesToMerge));
}
This also allows for the situation in which getListCloseRectangles can return more than two rectangles at a time. But it will still work fine if it only ever returns two items in the list.
Related
I'm working on a collision system for my game, however I can't get it to work, if I add more than one wall (which is the object I'm rendering) the collision system doesn't work and I can get through the block.
However if I leave only one wall the collision works correctly, or if at the end of the loop I add a break;
the collision works but only on the first wall of the map, the others don't get the collision.
Would anyone know how to solve this? I've been trying to solve it for 2 days and I couldn't.
public boolean checkCollisionWall(int xnext, int ynext){
int[] xpoints1 = {xnext+3,xnext+3,xnext+4,xnext+3,xnext+3,xnext+4,xnext+10,xnext+11,xnext+11,xnext+10,xnext+11,xnext+11};
int[] ypoints1 = {ynext+0,ynext+8,ynext+9,ynext+11,ynext+12,ynext+15,ynext+15,ynext+12,ynext+11,ynext+9,ynext+8,ynext+0};
int npoints1 = 12;
Polygon player = new Polygon(xpoints1,ypoints1,npoints1);
Area area = new Area(player);
for(int i = 0; i < Game.walls.size(); i++){
Wall atual = Game.walls.get(i);
int[] xpoints2 = {atual.getX(),atual.getX(),atual.getX()+16,atual.getX()+16};
int[] ypoints2 = {atual.getY(),atual.getY()+16,atual.getY()+16,atual.getY()};
int npoints2 = 4;
Polygon Wall = new Polygon(xpoints2,ypoints2,npoints2);
area.intersect(new Area(Wall));
if(area.isEmpty()){
return true;
}
}
return false;
}
I'm pretty sure the problem is this call:
area.intersect(new Area(Wall));
Here's the JavaDoc for that method:
public void intersect(Area rhs)
Sets the shape of this Area to the intersection of its current shape
and the shape of the specified Area. The resulting shape of this Area
will include only areas that were contained in both this Area and also
in the specified Area.
So area, which represents the shape of your player, is going to be modified by each test with a wall, which is why it's only working with one wall.
You could fix the issue by simply making the player Area the argument of the call, as in:
Area wallArea = new Area(Wall);
wallArea.intersect(area);
if(wallArea.isEmpty()){
return true;
}
By the way, this logic is reversed isn't it. Don't you want to check that the resulting area is not empty, i.e. there was an overlap between the player and the wall?
The other option, if each Wall is actually a rectangle, would be to use the this Area method instead:
public boolean intersects(double x,
double y,
double w,
double h)
Tests if the interior of the Shape intersects the interior of a
specified rectangular area. The rectangular area is considered to
intersect the Shape if any point is contained in both the interior of
the Shape and the specified rectangular area.
Something like this:
if(area.intersects(atual.getX(), atual.getY(), 16, 16)) {
return true;
}
As this avoids the creation of an Area object for each wall, and the intersection test is going to be much simpler, and faster.
My question does not refer to what operators I need to use to manipulate matrices, but rather what is actually being sought by doing this procedure.
I have, for example, an image in matrix form on which I need to perform several operations (this filter is one of them). After converting said image to grayscale, I need to apply the following filter
float[][] smoothKernel = {
{0.1f,0.1f,0.1f},
{0.1f,0.2f,0.1f},
{0.1f,0.1f,0.1f}
};
on it.
The assignment file gives this example , so I assumed that when asked to "smooth" the image, I had to replace every individual pixel with an average of its neighbors (while also making sure special cases such as corners or side were handled properly).
The basic idea is this:
public static float[][] filter(float[][] gray, float[][] kernel) {
// gray is the image matrix, and kernel is the array I specifed above
float current = 0.0f;
float around = 0.0f;
float[][] smooth = new float[gray.length][gray[0].length];
for (int col = 0; col < gray.length; col++) {
for (int row = 0; row < gray[0].length; row++) {
//first two for loops are used to do this procedure on every single pixel
//the next two call upon the respective pixels around the one in question
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
around = at(gray, i + col, j + row); //This calls a method which checks for the
//pixels around the one being modified
current += around * kernel[i+1][j+1];
//after the application of the filter these are then added to the new value
}
}
smooth[col][row] = current;
current = 0.0f;
//The new value is now set into the smooth matrix
}
}
return smooth;
}
My dilemma lies in if I have to create this new array float[][] smooth; so as to avoid overriding the values of the original (the image outputted is all white in this case...). From the end product in the example I linked above I just cannot understand what is going on.
What is the correct way of applying the filter? Is this a universal method or does it vary for different filters?
Thank you for taking the time to clarify this.
EDIT: I have found the two errors which I detailed in the comments below, implemented back into the code, everything is working fine now.
I have also been able to verify that some of the values in the example are calculated incorrectly (thus contributing to my confusion), so I will be sure to point it out in my next class.
Question has been solved by ulterior methods, I am however not deleting it in hopes other people can benefit from it. The original code can be found in the edits.
A more advanced colleague of mine helped me to note that I was missing two things: one was the issue with resetting the current variable after computing the "smoothed" variables in the new array (resulting in a white image because this value would get increasingly larger thus surpassing the binary color limit, so it was set to the max). The second issue was that I was continuously iterating on the same pixel, which caused the whole image to have the same color (I was iterating the new array). So I added these specifications in, and all works fine since.
I am working on a game that uses several HashMap<Point, Integer> to store values assigned to coordinates. In order to make it more simple and reduce duplication, I extended the Point class with an own class, called GamePoint. It has an equals() method that compares only x and y, which works with Point as well. As I don't need the key-value relation from the HashMap anymore, I simply put it into an ArrayList.
With the HashMap I had this:
HashMap<Point, Tile> tileMap; //already built at that stage
public static Tile getTile(int x, int y) {
Point p = new Point(x,y);
if(matrix.containsKey(p)){
return tileMap.get(p);
} else return Tile.BOUNDS;
}
From that Tile (which is an enum) I would get the image Index.
Now I do this to get my value from the ArrayList:
ArrayList<GameTile> gameTiles; //already built at that stage
public static int getGameTileIndex(int x, int y) {
Point p = new Point(x,y); //only for finding the coordinates
for(GameTile gt : gameTiles){
if (p.equals(gt)){
return gt.getImageIndex();
}
}
return 0; //empty tile
}
Unfortunately there is no direct method that can return the GameTile. Iterating is really, really slow, as I have 1.000.000 entries and there will be more in the final game.
Here's what I need to know:
Is iterating the ArrayList the right way for retrieving the GameTile? Should I stay with the HashMap and use something like HashMap<Point, GameTile> ?
Or could I somehow use the get(int index) method, knowing that the array is filled with a nested loop similiar to this:
List<Point> referencePoints;
for (int x; x<width; x++){
for (int y; y<height; y++){
Point p = new Point(x,y);
height = calculateHeight(x,y);
tileMap.put(p, height);
referencePoints.add(p);
}
}
for (Point p: referencePoints){
GameTile tile;
if (float height = getHeight(p) > THRESHOLD){
tile= new GameTile.GrassTile(p.x,p.y);
}
else {
tile= new GameTile.WaterTile(p.x,p.y);
}
gameTiles.add(tile);
}
Note: I really feel that there is a very logical way to use the x,y variables for index retrieval, but I can't get my mind together right now.
Edit:
I went with a HashMap which works as a charm right now. The answers, while giving me a new perspective, couldn't help me solve the problem and it still stands as it is. I found a workaround that works for my case and will be using that for now.
Is iterating the ArrayList the right way for retrieving the GameTile?
No way. Your HashMap implementation was far superior to iterating.
Should I stay with the HashMap and use something like HashMap ?
No. Indexing into an ArrayList is going to be much faster than using a HashMap.
Or could I somehow use the get(int index) method?
Yes. Honestly it would probably be easier to follow if you used a two-dimensional array , x by y. But it will work the way you laid it out in that bit of pseudocode. This will be your most efficient solution.
If you have a fixed number of points and you know that each one will have a tile, one option is to make 2-dimensional array and store your tiles in there, like this:
GameTile tiles[][] = new GameTile[n][n];
In this way, you can quickly access the tile at (i, j) by doing
GameTile tile = tiles[i][j];
Of course, the memory complexity for this is O(n2).
If you have a small number of tiles compared to n2 then I think the HashMap is indeed your best option.
I am using Java's Rectangle class in a program.
I have two Rectangle objects:
Rectangle big = new Rectangle(...);
Rectangle small = new Rectangle(...);
The specific sizes of the rectangles are not important. However, big will always be larger than small (in both width and height).
Usually, small is entirely contained within big. I can use Rectangle#contains to verify this. However, when this is not the case, I would like to move small to be entirely contained within big. The dimensions of neither rectangle should change.
For example:
I know could use four conditionals with Math.max and Math.min, but is there a more elegant way of doing this?
You could do it with only Math.max and Math.min. Try something like this:
small.setLocation(
Math.max(Math.min(small.getX(),big.getX() - small.getWidth()),big.getX()),
Math.max(Math.min(small.getY(),big.getY() - small.getHeight()),big.getY())
);
You'd have to consider readability though.
You need a stronger design. If you extend upon the Rectangle class, you can add the exact functionality you're looking for. Apparently the "big rectangle" should act as a container, containing the smaller rectangle:
class BigRectangle extends Rectangle {
//reference to or list of rectangle(s) here
private boolean isAlignedWith(Rectangle rect) {
return /* bounds logic */;
}
private void align(Rectangle rect) {
//move rectangle to proper position
}
public void add(Rectangle rect) {
if(!isAlignedWith(rect)) {
align(rect);
}
//store in reference or add to list
}
}
Now, you can simply add the smaller rectangle to the bigger one:
Rectangle smallRectangle = new Rectangle();
BigRectangle bigRectangle = new BigRectangle();
bigRectangle.add(smallRectangle); //automatically aligns if needed
You are now hiding the (needed) logic, keeping your central unit of code clean. This is my opinion of the most elegant way to handle this. (I would also probably create an interface RectangleContainer or ShapeContainer, having BigRectangle implement that. The interface would contain a method add(Rectangle) or add(SmallShape))
I currently have a program that draws overlapping rectangles and was wondering if there is an easy way to determine which shape is on the top (most visible). This has me stumped as there is no z axis to use like in when dealing in 3D.
I have tried looping through the rectangles and using the .contains method but it returns all rectangles under a specific point and not the highest level one.
I have also searched around but perhaps I'm using the wrong keywords?
Normally when people do painting code they do something like:
List rectangles = ....
for (int i = 0; i < rectangles.size(); i++)
//paint the rectangle
So if you want to search for a Point to determine what Rectanle it is in then you should use:
for (int i = rectangles.size() - 1; i >= 0; i--)
{
if (rectangles.get(i).contains(yourPoint))
{
// do something
break;
}
}
Starting from the end will give you the last rectangle painted which means it is on top of all aother rectangles.