I am having trouble figuring out how to remove the 0's in this table. I've attempted looking it up online and have had little success figuring it out that way (probably not searching it correctly). I am attempting to get Figure #1 to appear like Figure #2 besides a few stylistic changes.
I'd appreciate any help.
Code: (http://www.buildingjavaprograms.com/DrawingPanel.java) Drawing Panel Used
import java.awt.*;
public class IfGridFor {
public static void main(String[] args) {
DrawingPanel panel = new DrawingPanel(400, 520);
panel.setBackground(Color.blue);
Graphics g = panel.getGraphics();
int sizeX = 40;
int sizeY = 40;
for (int x = 0; x < 10; x++) {
for (int y = 0; y <= 12; y++) {
int cornerX = x*sizeX;
int cornerY = y*sizeY;
if ((x + y) % 2 == 0)
g.setColor(Color.green);
else
g.setColor(Color.yellow);
g.fillRect(cornerX+1, cornerY+1, sizeX-2, sizeY-2);
g.setColor(Color.black);
g.drawString(x + " * " + y, cornerX + 5, cornerY + 15); // text is
g.drawString("= " + x * y, cornerX + 5, cornerY + 33); // offsets
}
}
}
}
Figure #1:
Figure #2:
You are almost done - all you need is changing what gets shown from x, y, x*y to (x+1), (y+1), (x+1)*(y+1), and reducing the height of the panel by one row:
DrawingPanel panel = new DrawingPanel(400, 480); // 12 rows, not 13
...
for (int x = 0; x < 10; x++) {
for (int y = 0; y < 12; y++) { // < instead of <=
...
g.drawString((x+1) + " * " + (y+1), cornerX + 5, cornerY + 15); // text is
g.drawString("" + (x+1) * (y+1), cornerX + 5, cornerY + 33); // offsets
}
}
The rest of your code (i.e. the ... parts) remain the same.
If I'm understanding your question correctly, you want to remove the top row and the left column? If so, start your for loops at one instead of zero. Also your outer loop should have the condition x <= 10 if you want the figure to include the square labelled '10'.
Then change the lines:
int cornerX = x*sizeX;
int cornerY = y*sizeY;
to:
int cornerX = (x-1)*sizeX;
int cornerY = (y-1)*sizeY;
Related
I'm having problems with completing the algorithm based on this link.
After building a wall I choose the upper or left part of the maze and it seems to create itself only to the point where it needs to break the recursion and enter another divide method call. I'm not sure if I understand the values needed to be passed to the last call of the divide method correctly.
public void divide(int x, int y, int width, int hight) {
if (width< 2 || hight< 2) ;
else {
boolean horizontal = chooseOrientation(width,hight);
if (horizontal) {
int randomNumber = r.nextInt(hight - 1);
wallY = randomNumber + y;
for (int i = x; i < width; i++) {
fields[wallY][i].setHorizontalWall();
}
fields[wallY][r.nextInt(width- 1)].deleteHorizontalWall();
hight = wallY - y + 1;
divide(x, y, width, hight);
}
else {
int randomNumber = r.nextInt(width- 1);
WallX = randomNumber + x;
for (int i = y; i < hight; i++) {
fields[i][WallX].setVerticalWall();
}
fields[r.nextInt(hight - 1) + y][WallX].deleteVerticalWall();
width = WallX - x + 1;
}
if(horizontal){
hight = y + hight + WallY-1;
y = WallY + 1;
}
else {
width = WallX - 1 + width + x;
x = WallX + 1;
}
divide(x, y, width, hight);
}
}
In the "recursive-division" algorithm you start with a full 2-dimensional grid graph and you then start removing edges (= building "walls") alternating in horizontal and vertical "stripes". In every "stripe" only a single edge ("door") is left.
A graph-based version of this algorithm can be found here:
https://github.com/armin-reichert/mazes
https://github.com/armin-reichert/mazes/blob/master/mazes-algorithms/src/main/java/de/amr/maze/alg/others/RecursiveDivision.java
What would be the easiest and simplest way to keep the fill() the same after clicking (that's when it changes) and then unclicking, and leaving hover?
In this project, I simply made a grid. When the mouse hovers over a specific rect (at x,y) it changes color based on the state it is in. fill(50) is the default, fill(75) is when the mouse is hovering, and fill(100) is when the mouse clicks. But here when the mouse is unclicked it returns to hover fill until the mouse leaves the rectangle. Thanks.
int cols, rows;
int scl = 20;
void setup() {
size(400, 400);
int w = 400;
int h = 400;
cols = w / scl;
rows = h / scl;
}
void draw() {
background(255);
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
int xpos = x*scl;
int ypos = y*scl;
stroke(55);
if((mouseX >= xpos && mouseX <= xpos+scl) &&
(mouseY >= ypos && mouseY <= ypos+scl)){
fill(75);
if (mousePressed == true){
println("Clicked at: " + xpos + " and " + ypos);
fill(100);
//here is the desired location for the fill to remain constant even
//after unclicking and leaving hover
}
println("Mouse at: " + xpos + " and " + ypos);
}else{
fill(50);
}
rect(xpos, ypos, scl, scl);
}
}
}
Stack Overflow isn't really designed for general "how do I do this" type questions. It's for specific "I tried X, expected Y, but got Z instead" type questions. But I'll try to help in a general sense:
You need to store the state of each cell in a data structure, and then use that data structure to draw your scene.
You could do this with a 2D array, where each cell in the array represents a cell in the grid. You could store the state of the cell, or the color directly.
As Kevin said, you should keep the state of your application in a matrix.
boolean[][] matrix = new boolean[21][21];
When you click on a cell, toggle it
if(!matrix[xpos/scl][ypos/scl]) {
matrix[xpos/scl][ypos/scl] = true;
} else {
matrix[xpos/scl][ypos/scl] = false;
}
Inside this loop, check if your current position can be drawn or not
if(matrix[x][y]) {
fill(204, 102, 0); // an orange color
rect(xpos, ypos, scl, scl);
}
So your draw() method should look like this
void draw() {
background(255);
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
int xpos = x*scl;
int ypos = y*scl;
stroke(55);
if((mouseX >= xpos && mouseX <= xpos+scl) &&
(mouseY >= ypos && mouseY <= ypos+scl)){
fill(75);
if (mousePressed == true){
println("Clicked at: " + xpos + " and " + ypos);
if(!matrix[xpos/scl][ypos/scl]) {
matrix[xpos/scl][ypos/scl] = true;
} else {
matrix[xpos/scl][ypos/scl] = false;
}
fill(100);
//here is the desired location for the fill to remain constant even
//after unclicking and leaving hover
}
println("Mouse at: " + xpos + " and " + ypos);
}else{
fill(50);
}
if(matrix[x][y]) {
fill(204, 102, 0);
rect(xpos, ypos, scl, scl);
}
rect(xpos, ypos, scl, scl);
}
}
}
I appear to have hit a wall in my most recent project involving wave/ripple generation over an image. I made one that works with basic colors on a grid that works perfectly; heck, I even added shades to the colors depending on the height of the wave.
However, my overall goal was to make this effect work over an image like you would see here. I was following an algorithm that people are calling the Hugo Elias method (though idk if he truly came up with the design). His tutorial can be found here!
When following that tutorial I found his pseudo code challenging to follow. I mean the concept for the most part makes sense until I hit the height map portion over an image. The problem being the x and y offsets throw an ArrayIndexOutOfBoundsException due to him adding the offset to the corresponding x or y. If the wave is too big (i.e. in my case 512) it throws an error; yet, if it is too small you can't see it.
Any ideas or fixes to my attempted implementation of his algorithm?
So I can't really make a compile-able version that is small and shows the issue, but I will give the three methods I'm using in the algorithm. Also keep in mind that the buffer1 and buffer2 are the height maps for the wave (current and previous) and imgArray is a bufferedImage represented by a int[img.getWidth() * img.getHeight()] full of ARGB values.
Anyways here you go:
public class WaveRippleAlgorithmOnImage extends JPanel implements Runnable, MouseListener, MouseMotionListener
{
private int[] buffer1;
private int[] buffer2;
private int[] imgArray;
private int[] movedImgArray;
private static double dampening = 0.96;
private BufferedImage img;
public WaveRippleAlgorithmOnImage(BufferedImage img)
{
this.img = img;
imgArray = new int[img.getHeight()*img.getWidth()];
movedImgArray = new int[img.getHeight()*img.getWidth()];
imgArray = img.getRGB(0, 0,
img.getWidth(), img.getHeight(),
null, 0, img.getWidth());
//OLD CODE
/*for(int y = 0; y < img.getHeight(); y++)
{
for(int x = 0; x < img.getWidth(); x++)
{
imgArray[y][x] = temp[0 + (y-0)*img.getWidth() + (x-0)];
}
}*/
buffer1 = new int[img.getHeight()*img.getWidth()];
buffer2 = new int[img.getHeight()*img.getWidth()];
buffer1[buffer1.length/2] = (img.getWidth() <= img.getHeight() ? img.getWidth() / 3 : img.getHeight() / 3);
//buffer1[25][25] = 10;
back = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
//<editor-fold defaultstate="collapsed" desc="Used Methods">
#Override
public void run()
{
while(true)
{
this.update();
this.repaint();
this.swap();
}
}
//Called from Thread to update movedImgArray prior to being drawn.
private void update()
{
//This is my attempt of trying to convert his code to java.
for (int i=img.getWidth(); i < imgArray.length - 1; i++)
{
if(i % img.getWidth() == 0 || i >= imgArray.length - img.getWidth())
continue;
buffer2[i] = (
((buffer1[i-1]+
buffer1[i+1]+
buffer1[i-img.getWidth()]+
buffer1[i+img.getWidth()]) >> 1)) - buffer2[i];
buffer2[i] -= (buffer2[i] >> 5);
}
//Still my version of his code, because of the int[] instead of int[][].
for (int y = 1; y < img.getHeight() - 2; y++)
{
for(int x = 1; x < img.getWidth() - 2; x++)
{
int xOffset = buffer1[((y)*img.getWidth()) + (x-1)] - buffer1[((y)*img.getWidth()) + (x+1)];
int yOffset = buffer1[((y-1)*img.getWidth()) + (x)] - buffer1[((y+1)*img.getWidth()) + (x)];
int shading = xOffset;
//Here is where the error occurs (after a click or wave started), because yOffset becomes -512; which in turn gets
//multiplied by y... Not good... -_-
movedImgArray[(y*img.getWidth()) + x] = imgArray[((y+yOffset)*img.getWidth()) + (x+xOffset)] + shading;
}
}
//This is my OLD code that kidna worked...
//I threw in here to show you how I was doing it before I switched to images.
/*
for(int y = 1; y < img.getHeight() - 1; y++)
{
for(int x = 1; x < img.getWidth() - 1; x++)
{
//buffer2[y][x] = ((buffer1[y][x-1] +
//buffer1[y][x+1] +
//buffer1[y+1][x] +
//buffer1[y-1][x]) / 4) - buffer2[y][x];
buffer2[y][x] = ((buffer1[y][x-1] +
buffer1[y][x+1] +
buffer1[y+1][x] +
buffer1[y-1][x] +
buffer1[y + 1][x-1] +
buffer1[y + 1][x+1] +
buffer1[y - 1][x - 1] +
buffer1[y - 1][x + 1]) / 4) - buffer2[y][x];
buffer2[y][x] = (int)(buffer2[y][x] * dampening);
}
}*/
}
//Swaps buffers
private void swap()
{
int[] temp;
temp = buffer2;
buffer2 = buffer1;
buffer1 = temp;
}
//This creates a wave upon clicking. It also is where that 512 is coming from.
//512 was about right in my OLD code shown above, but helps to cause the Exeception now.
#Override
public void mouseClicked(MouseEvent e)
{
if(e.getX() > 0 && e.getY() > 0 && e.getX() < img.getWidth() && e.getY() < img.getHeight())
buffer2[((e.getY())*img.getWidth()) + (e.getX())] = 512;
}
private BufferedImage back;
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
back.setRGB(0, 0, img.getWidth(), img.getHeight(), movedImgArray, 0, img.getWidth());
g.drawImage(back, 0, 0, null);
}
}
P.S. Here are two images of the old code working.
Looking at my original pseudocode, I assume the Array Out Of Bounds error is happening when you try to look up the texture based on the offset. The problem happens because the refraction in the water is allowing us to see outside of the texture.
for every pixel (x,y) in the buffer
Xoffset = buffer(x-1, y) - buffer(x+1, y)
Yoffset = buffer(x, y-1) - buffer(x, y+1)
Shading = Xoffset
t = texture(x+Xoffset, y+Yoffset) // Array out of bounds?
p = t + Shading
plot pixel at (x,y) with colour p
end loop
The way to fix this is simply to either clamp the texture coordinates, or let them wrap. Also, if you find that the amount of refraction is too much, you can reduce it by bit-shifting the Xoffset and Yoffset values a little bit.
int clamp(int x, int min, int max)
{
if (x < min) return min;
if (x > max) return max;
return x;
}
int wrap(int x, int min, int max)
{
while (x<min)
x += (1+max-min);
while (x>max)
x -= (1+max-min);
return x;
}
for every pixel (x,y) in the buffer
Xoffset = buffer(x-1, y) - buffer(x+1, y)
Yoffset = buffer(x, y-1) - buffer(x, y+1)
Shading = Xoffset
Xoffset >>= 1 // Halve the amount of refraction
Yoffset >>= 1 // if you want.
Xcoordinate = clamp(x+Xoffset, 0, Xmax) // Use clamp() or wrap() here
Ycoordinate = clamp(y+Yoffset, 0, Ymax) //
t = texture(Xcoordinate, Ycoordinate)
p = t + Shading
plot pixel at (x,y) with colour p
end loop
I'm trying to find a white rectangle in an image. The rectangle size is fixed. This is what I've come up as of yet:
BufferedImage bImage = bufferedImage;
int height = bufferedImage.getHeight(); //~1100px
int width = bufferedImage.getWidth(); //~1600px
int neededWidth = width / 2;
int neededHeight = 150;
int x = 0;
int y = 0;
boolean breaker = false;
boolean found = false;
int rgb = 0xFF00FF00;
int fx, fy;
fx = fy = 0;
JavaLogger.log.info("width, height: " + w + ", " + h);
while ((x != (width / 2) || y != (height - neededHeight)) && found == false) {
for (int i = y; i - y < neededHeight + 1; i++) {
for (int j = x; j - x < neededWidth + 1; j++) { //Vareetu buut, ka +1 vajadziigs
//JavaLogger.log.info("x,y: " + j + ", " + i);
long pixel = bImage.getRGB(j, i);
if (pixel != colorWhite && pixel != -1) {
//bImage.setRGB(j, i, rgb);
//JavaLogger.log.info("x,y: " + (j+x) + ", " + (i+y));
breaker = true;
break;
} else {
//bImage.setRGB(j, i, 0xFFFFFF00);
}
//printPixelARGB(pixel);
if ((i - y == neededHeight-10) && j - x == neededWidth-10) {
JavaLogger.log.info("width, height: " + x + ", " + y + "," + j + ", " + i);
fx = j;
fy = i;
found = true;
breaker = true;
break;
}
}
if (breaker) {
breaker = false;
break;
}
}
if (x < (width / 2)) {
x++;
} else {
if (y < (height - neededHeight)) {
y++;
x = 0;
} else {
break;
}
}
//JavaLogger.log.info("width, height: " + x + ", " + y);
}
if (found == true) {
for (int i = y; i < fy; i++) {
for (int j = x; j < fx; j++) {
bImage.setRGB(j, i, 0xFF00FF3F);
}
}
}
JavaLogger.log.info("width, height: " + w + ", " + h);
This works ok, if the rectangle I need is close to the begining of (0;0), but as it get further away, the performance degrades quite severely. I'm wondering, if there's something that can be done?
For example, this search took nearly 8s, which is quite a lot.
I'm thinking, that this can deffinitely be done more effectively. Maybe some blob finding? Read about it, but I've no idea how to apply it.
Also, I'm new to both Java and Image processing, so any help is appreciated.
This is very rough, but successfully finds all the white pixels in the image, more checking can be done to ensure it is the size you want and everything is there but the basics are there.
PS: I have not tested with your image. r and this.rc is picture size and p and this.px is the inner rectangle size
public static void main(String[] args) {
JFrame frame = new JFrame();
final int r = 100;
final int p = 10;
NewJPanel pan = new NewJPanel(r, p, new A() {
#Override
public void doImage(BufferedImage i) {
int o = 0;
for (int j = 0; j < i.getWidth() - p; j++) {
for (int k = 0; k < i.getHeight() - p; k++) {
PixelGrabber pix2 = new PixelGrabber(
i, j, k, p, p, false);
try {
pix2.grabPixels();
} catch (InterruptedException ex) {}
int pixelColor = pix2.getColorModel()
.getRGB(pix2.getPixels());
Color c = new Color(pixelColor);
if (c.equals(Color.WHITE)) {
System.out.println("Found at : x:" + j + ",y:" + k);
}
}
}
}
});
frame.getContentPane().add(pan);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private interface A {
void doImage(BufferedImage i);
}
private static class NewJPanel extends JPanel {
private static final long serialVersionUID = -5348356640373105209L;
private BufferedImage image = null;
private int px;
private int rc;
private A a;
public NewJPanel(int r, int p, A a) {
this.px = p;
this.rc = r;
this.a = a;
}
public BufferedImage getImage() {
return image;
}
#Override public void paint(Graphics g) {
super.paint(g);
image = new BufferedImage(this.rc, this.rc,
BufferedImage.TYPE_INT_ARGB);
java.awt.Graphics2D g2 = image.createGraphics();
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, this.rc, this.rc);
g2.setColor(Color.WHITE);
g2.fillRect(
new Random().nextInt(this.rc - this.px),
new Random().nextInt(this.rc - this.px),
this.px, this.px);
g.drawImage(image, this.rc, this.rc, this);
this.a.doImage(this.image);
}
}
I'm no expert but I don't think the code is the problem - you need to change your algorithm. I would start by recursively searching for a single white pixel on the 2d plane, something like:
findWhitePixel(square){
look at pixel in the middle of 'square' - if it's white return it, otherwise:
findWhitePixel(top-right-quarter of 'square')
findWhitePixel(top-left-quarter of 'square')
findWhitePixel(bottom-right-quarter of 'square')
findWhitePixel(bottom-left-quarter of 'square')
}
after you find a white pixel try travesing up, down, left and right from it to find the borders on you shape. if it's a given that there can only be rectangles - your done. if there might be other shapes (triangles, circles, etc.) you'll need some verification here.
What you are asking can be solved by the operation known as "erosion". The erosion replaces every pixel by the darkest of all pixels in the rectangle of the requested size at that location (top-left corner). Here, darkest means that non-white supersedes white.
The output of erosion is an image with W-1 columns and H-1 rows less. Any white pixel in it corresponds to a solution.
In the lucky case of a rectangle shape, erosion is a separable operation. This means that you can erode first using an horizontal segment shape, then a vertical segment shape on the output of the first erosion. For a W x H restangle size, this replaces W * H operations by W + H, a significant saving.
In the also lucky case of a binary image (non-white or white), erosion by a segment can be done extremely efficiently: in every row independently, find all contiguous runs of white pixels, and turn the W-1 rightmost ones to non-white. Do the same to all columns, shortening the white runs by H-1 pixels.
Example: find all 3x2 rectangles:
####....####
##.....#..##
#..######...
.....###....
After 3x1 erosion:
####..####
##...#####
#########.
...#####..
After 1x2 erosion:
####.#####
##########
#########.
This algorithms takes constant time per pixel (regardless the rectangle size). Properly implemented, should take a handful of milliseconds.
I am having a bit of trouble making this grid be drawn 10 pixels from the top and 10 pixels from the left of the Frame.
I can make it do it by increasing this.getY() + 10 to a higher number, just wondering why if is remove the + 10 it getting drawn off screen.
Ignore the variable names and any formatting I just threw this together
package griddrawing;
import java.awt.*;
import javax.swing.*;
public class Grid extends JFrame
{
private int TILEWIDTH;
private int TILEHEIGHT;
private int COLS;
private int ROWS;
private int defaultX;
private int defaultY;
private int currentX;
private int currentY;
public Grid()
{
setSize(800,400);
TILEWIDTH = 30;
TILEHEIGHT = 30;
COLS = 10;
ROWS = 10;
defaultX = this.getX() + 10;
defaultY = this.getY() + 10;
currentX = 0;
currentY = 0;
}
#Override
public void paint(Graphics g)
{
super.paint(g);
currentX = defaultX;
currentY = defaultY;
g.setColor(Color.black);
for(int i = 0; i < COLS; i++)
{
for(int k = 0 ; k < ROWS; k++)
{
g.drawRect(currentX - (TILEWIDTH / 2), currentY - (TILEHEIGHT / 2), TILEWIDTH, TILEHEIGHT);
g.drawString("" + k, currentX, currentY);
currentY += TILEWIDTH;
System.out.println("COL: " + i + " ROW: " + k + " Current X: " + currentX + " Current Y: " + currentY);
}
currentY = defaultY;
currentX += TILEHEIGHT;
}
}
}
Don't set the size of the frame.
Don't paint directly to the frame either.
Instead of both:
Override the paintComponent(Graphics) method of a JComponent or JPanel.
Either call theComponent.setPreferredSize(Dimension) or override that same method.
Add the custom component to the frame and call pack().
That lot should mean you no longer need to account for any offset (which might change by platform or PLAF).