Need help fixing a function for drawing hexagons - java

I've got a program that can hexagonal tiles using images that are loaded into it. It creates these tiles images by replacing any pixels outside the hexagon with transparent pixels using a function called inHex(). This works.
Now I want to create a border on the inner edge of the hexagon. So I modified a copy of inHex(), changing the &&s to ||s, and adding two lines for the flat edges. The problem is that only the upper borders get drawn.
I've tried changing the order of the statements, and replacing all of the ors with separate if statements, no dice. Using System.out.print line in the loop I know hexEdge() doesn't return true when it should except for the upper lines.
public boolean hexEdge(int x, int y)
{
/**
* returns true if the coordinates are inside the hexagon bounded by the width and height of the tile
*/
double slope = (tileHeight/2.0)/(tileWidth);
boolean inside=false;
//check in acordance to sides
if (x<(tileWidth/2 +1) )
{
inside=
( y == (int)(0.25*tileHeight-slope*x) ) ||//this works
( y == (int)(0.75*tileHeight+slope*x) ) ||
(x==0 && y>(int)(0.25*tileHeight) && y<=(int)(0.25*tileHeight) );
}else {
int x2=x-tileWidth/2;
inside =
(y == (int)(0+slope*x2) )||//this works
(y == (int)(tileHeight -slope*x2 ) )||
(x==tileWidth-1 && y>(int)(0.25*tileHeight) && y<=(int)(0.25*tileHeight) );
}
return inside;
}

Related

[JAVA]Recursively removing empty cell in minesweeper

I am working on a minesweeper assignment right now. And I used recursion to implement the function that removes an empty area. However my program always runs into eroor. The error message states:
a Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
And this is my code, I know it looks messy, apologize in advance. I would appreciate any help!
public void removeEmptyRegion(int x, int y){ //note: uses recursive decomposition
if (x < 0 || x > width-1 || y < 0 || y > length-1) {
return; // check for bounds
}else if(tiles[y][x].getClicked()){ //first time activated this method
//checks the tiles surround it
removeEmptyRegion(x,y+1);//up
removeEmptyRegion(x,y-1);//down
removeEmptyRegion(x+1,y);//left
removeEmptyRegion(x-1,y);//right
removeEmptyRegion(x-1, y+1); //up-left
removeEmptyRegion(x+1, y+1); //up-right
removeEmptyRegion(x-1,y-1); //down-left
removeEmptyRegion(x+1,y-1); //down-right
}
else if(!(tiles[y][x].getValue() == -1) && tiles[y][x].getClicked() == false ) {
//check: -1 indicates it is a bomb
if(tiles[y][x].getValue() == 0) {
tiles[y][x].clickTile();
//chain reaction
removeEmptyRegion(x,y+1);//up
removeEmptyRegion(x,y-1);//down
removeEmptyRegion(x+1,y);//left
removeEmptyRegion(x-1,y);//right
removeEmptyRegion(x-1, y+1); //up-left
removeEmptyRegion(x+1, y+1); //up-right
removeEmptyRegion(x-1,y-1); //down-left
removeEmptyRegion(x+1,y-1); //down-right
return;
}else { //stops if the tile is a numbered tile
tiles[y][x].clickTile();
return;
}
} else {
return;
}
}
You check each possible direction from each tile recursively.
Say your code is at 0,0 and now it checks the tile above. Now it's at 0,1. Then, from 0,1 your code checks a few directions, including down. Now it's back at 0,0. This repeats infinitely, causing a stack overflow.
I suggest using something called memoization.
Create a boolean[][] with the same dimensions as your minesweeper grid. When you check a square, mark boolean[y][x]=true.
At the top of your method where you check if you are out of bounds, use if (boolean[y][x]) to check if you've already checked there.

Transformation of objects to different coordinate sets

I am using a tree structure of objects to control my 2D world of objects. The root element or camera contains a list of sub objects, in this case a simple "hand" object. The hand object contains a list of sub objects which are 5 card objects.
Now the hand object is rotated 90 degrees. The Card objects' x position is increasing. So the result when you view it on the screen is that the cards appear to be building downwards (because the hand object is rotated)
Eventually I will need a card object to transfer to another hand object and I want to do that with smooth animation, so I need to map the card object to the camera's world, but so that it doesn't look like it moved.
For example, let's say one of the card objects has an X position of 100 with a y position of 0. When I rotate the hand object 90 degrees, it appears as if the card object is 0 in the x dimension and 100 in the y position.
If I simply remove the card from the hand and add it to the camera, then the card rotates back and moves in the x position appearing at 100,0.
For all rotations and positions (and scalings) how can I transfer the card object to the camera object and keep it's position on the screen?
In the code below, if the 'g' is pressed, I attempt to remove a card from the hand and add it to the camera. I call a method called 'transformObjectToTheseCoords' but I don't think my math is right...
public void update(LinkedList<Object> messages)
{
super.update(messages);
if(messages.size() > 0 && messages.get(0) instanceof KeyEvent)
{
KeyEvent ke = (KeyEvent)messages.get(0);
if(ke.getKeyChar() == 'g')
{
if(super.getSubObjects().size() > 0)
{
GameObject o = super.getSubObjects().remove(0);
GameObject parent = o.getParentObject();
while(parent != camera)
{
parent.transformObjectToTheseCoords(o);
parent = parent.getParentObject();
}
camera.addSubObject(o);
}
}
}
}
public void transformObjectToTheseCoords(GameObject o)
{
o.xPos += xPos;
o.yPos += yPos;
o.rPos += rPos;
}
If anyone has another technique to use, I would appreciate it.
The solution was to work with AffineTransform matrices... this appropriately handles the x and y transformations between different coordinate sets.
#Override
public void update(LinkedList<Object> messages)
{
super.update(messages);
if(messages.size() > 0 && messages.get(0) instanceof KeyEvent)
{
KeyEvent ke = (KeyEvent)messages.get(0);
if(ke.getKeyChar() == 'g')
{
if(super.getSubObjects().size() > 0)
{
GameObject o = super.getSubObjects().remove(0);
//We are inside the position layout, so first let's transform the object to these coordinates...
o.setRotationPosition(this.rPos);
//It's x,y position are relative to this already, so don't need to change that...
//Now the next layer up is the camera, so let's calculate the new X and Y
float x = (float) ((Math.cos(this.rPos)*o.getXPosition())-(Math.sin(this.rPos)*o.getYPosition())+this.xPos);
float y = (float) ((Math.sin(this.rPos)*o.getXPosition())+(Math.cos(this.rPos)*o.getYPosition())+this.yPos);
o.setPosition(x, y);
camera.addSubObject(o);
}
}
}
}

How to check if the values lie within the rectangular bound using java

I have a set of values say
LatLong1=(lon=74.663085,lat=22.67578)
LatLong2=(lon=80.663085,lat=28.67578)
These are the latitude and longitude values of a rectangular bounded region. LatLong1 is the left and bottom boundary values and LatLong2 is the right and top boundary values.
Now I need to check if some object lies within this boundary at current time.
If I have the object's position with 75.67 and 26.89 as latitude longitude respectively. How do I check whether these values lies within the above mentioned LatLong1 , LatLong2 values?
I've to guess your objects for which pertenency you need to check is a rentangle too, with values:
LatLong1=(lon=x0,lat=y0)
LatLong2=(lon=x1,lat=y1)
If this is the case, and both graphical structures are tied to the same origin of coordenates, the conditions to check is:
if( (x0>=lon0 && x1<=lon1 ) && (y0>=lat0 && y1<=lat1 ) )
return true;
else return false;
If you need to check if a point is inside a rectangle, being the coordinates of the point (x0,y0):
if( (x0>=lon0 && x0<=lon1 ) && (y0>=lat0 && y0<=lat1 ) )
return true;
else return false;
I don't know openlayer. But isn't it like finding whether a point (x,y) is in a rectangle whose lower left is (x1,y1) and top right is (x2, y2)?
In that case (x,y) is in the rectangle, if (x>x1 && x<x2 && y>y1 && y<y2)
You could create a rectangle. With your two points you can compute the upper left corner and the dimension.
Rectangle rect = new Rectangle(upperLeftCorner, dimension);
You want to check if a point (x,y) lies in the rectangle:
Point p = new Point(x,y);
rect.contains(p);

Java Image Connective Component

I have this program to detect objects in a binarized BufferedImage, which the image is a multiple choice answer sheet.
I'm trying to use 4-Connectivity as in to detect each object (answer on the sheet).
So far what I have in hand as source is these:
http://en.wikipedia.org/wiki/Connected-component_labeling
http://homepages.inf.ed.ac.uk/rbf/HIPR2/label.htm
and I have came up with this, following instructions from Wikipedia:
if(getPixel(image, x, y) != 0){
if(getPixel(image, x-1, y) !=0){
System.out.println("we are in the same region");
region[x][y] = region[x-1][y];
}
else if(getPixel(image, x-1, y) !=0 && getPixel(image, x, y-1) !=0){
System.out.println("North and West pixels belong to the same region and must be merged");
region[x][y] = Math.min(region[x-1][y], region[x][y-1]);
}
else if( getPixel(image, x-1, y) ==0 && getPixel(image, x, y-1) !=0){
System.out.println("Assign the label of the North pixel to the current pixel");
region[x][y] = region[x][y-1];
}
else if(getPixel(image, x-1, y) ==0 && getPixel(image, x, y-1) ==0){
System.out.println("Create a new label id and assign it to the current pixel");
cpt++;
region[x][y] = cpt;
}
But the problem is it creates 51 regions! and it only prints a couple of top pixels of each object (not all pixels).
Can anyone please help me to find what the problem is and how can I detect my objects?
I would appreciate any help.
You probably get a lot of regions because you do not seem to merge equal labels. There is no code for storing equal labels in your code snippet. The algorithm is a two-pass algorithm where the first pass assigns labels and the second pass merges equal labels.
Here are the condition checks quoted from the Wikipedia page:
Conditions to check:
Does the pixel to the left (West) have the same value as the current pixel?
Yes – We are in the same region. Assign the same label to the current pixel
No – Check next condition
Do both pixels to the North and West of the current pixel have the same value as the current pixel but not the same label?
Yes – We know that the North and West pixels belong to the same region and must be merged. Assign the current pixel the minimum of the North and West labels, and record their equivalence relationship
No – Check next condition
Does the pixel to the left (West) have a different value and the one to the North the same value as the current pixel?
Yes – Assign the label of the North pixel to the current pixel
No – Check next condition
Do the pixel's North and West neighbors have different pixel values than current pixel?
Yes – Create a new label id and assign it to the current pixel
Your second condition check,
else if(getPixel(image, x-1, y) !=0 && getPixel(image, x, y-1) !=0)
does not check if the left pixel and up pixel have different labels.
Furthermore, just like supersam654 mentions in the comment, the first else if will never be called. It seems like condition check (1) and (2) on the Wikipedia page should be in the opposite order. That is, first check if the left and up pixel have the same value as the current pixel but not the same label. Then, if that check fails, check if the left pixel has the same value as the current.
So try the following:
Add the label condition to your second condition check.
Switch the order of your first two condition checks.
Keep track of equal labels (i.e., which labels represent the same region).
Do a second pass over the image and merge equal labels.
I hope this helps.
While I'm not entirely sure that this answers your question, I would modify your code to look like this:
if(getPixel(image, x, y) != 0){
if(getPixel(image, x-1, y) !=0){
if(getPixel(image, x, y-1) !=0) {
System.out.println("North and West pixels belong to the same region and must be merged");
region[x][y] = Math.min(region[x-1][y], region[x][y-1]);
} else {
System.out.println("we are in the same region");
region[x][y] = region[x-1][y];
}
} else if(getPixel(image, x-1, y) ==0) {
if(getPixel(image, x, y-1) !=0) {
System.out.println("Assign the label of the North pixel to the current pixel");
region[x][y] = region[x][y-1];
} else if (getPixel(image, x, y-1) ==0) {
System.out.println("Create a new label id and assign it to the current pixel");
cpt++;
region[x][y] = cpt;
}
}

FloodFill - Minesweeper, Explanation needed

I'm trying to make a Minesweeper-like game in Java and I've got most of it to work. Something I need help with is FloodFill - http://en.wikipedia.org/wiki/Flood_fill.
Can someone explain how it works? I've looked online but I don't really understand the explanation so I thought it would be easier to ask here.
In my Minesweeper I have:
JButton[] btn = new JButton[100]//buttons being clicked and displaying the values/bombs
int[] mines = new int[100];//int array holding the values for each button.
The grid is a 10x10 grid so say the button you clicked was btn[14],
btn[4] // north of btn[14](14-10)
btn[24] // south of btn[14](14+10)
btn[13] // west of btn[14](14-1)
btn[15] // east of btn[14](14+1)
So back to the question, could someone explain it to me?
EDIT:
I changed my code to be 2D so instead of the above one it is now
btn[1][4]//row one, column 4
When the button is clicked, i want it to check a variable called mines[][] which has the values and if the value is equal to 0(around the initial clicked) it changes the BG
btn[x][y].setBackground(Color.GRAY);
Its a recursive algorithm. You start at some start position in a 2D Grid [x,y], then look in all directions and fill them if you can. If (x,y) can't be filled, return.
void floodFill( int x, int y ) {
if ( btn( x, y ) isFillable ) {
fillBtn(x,y);
floodFill( x+1, y );
floodFill( x-1, y );
floodFill( x, y-1 );
floodFill( x, y+1 );
} else {
return;
}
}
(ommited check for boundaries of grid)
I guess you are mainly asking about floodfill.
Actually it is a simple and common recursive algorithm. It can solve whatever your data structure is 1D or 2D.
For 2D version, #RMoeller has given the answer.
For your previous 1D declaration, it is also similar like this:
void floodFill( int pos ) {
if ( btn( pos ) isFillable ) {
fillBtn(pos);
floodFill( pos+1 );
floodFill( pos-1 );
floodFill( pos+10 );
floodFill( pos-10 );
} else {
return;
}
}
One thing you should remember is that floodfill, and almost all recursive algorithms, need to check boundaries. Otherwise you may get into an infinite loop or get a wrong result.
In above example (1D version), you should check whether:
pos >= 1 && pos <= 100
Similar to 2D version which is to check:
x >= 1 && x <= 10 && y>=1 && y <=10
Hope this helps.

Categories

Resources