Question

I wanted to make a fill bucket tool for my program using a lines class that I have. My fill bucket would record all the lines it would need to draw in order to fill an area for example:

http://i.imgur.com/Cywh8xU.png - In this image, my clicked point was the red circle and than it would find 2 points for each line (the start and end points). I obviously did not draw all the lines, but that's the basic concept of what I have.

The problem I am running into is that images end up looking like this and I cannot figure out why. http://i.imgur.com/IXHgEf2.jpg

Here is my code for finding all the lines so far:

public class FillBucket{

private BufferedImage image;
private Fill currentFill;
private Line currentLine;

private Queue<Point> pointsToVisit;

@Override
public void mousePressed(Point point) {
    super.mousePressed(point);

    if(pointIsOnCanvas(point)) {
        image = new BufferedImage(getCanvas().getPreferredSize().width, getCanvas().getPreferredSize().height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) image.getGraphics();
        getCanvas().paint(g2);

        currentFill = new Fill(getColor());
        pointsToVisit = new LinkedList<>();
        createPoints(point, image.getRGB(point.x, point.y));

        getCanvas().addDrawable(currentFill);
        getCanvas().repaint();
    }
}

private void createPoints(Point clickedPoint, int clickedColor) {
    pointsToVisit.add(clickedPoint);

    while(!pointsToVisit.isEmpty()) {
        Point testPoint = pointsToVisit.poll();

        if(testPoint.x > 0 && testPoint.x < image.getWidth() && testPoint.y > 0 && testPoint.y < image.getHeight() 
                && image.getRGB(testPoint.x, testPoint.y) == clickedColor) {
            while(testPoint.x > 0 && image.getRGB(testPoint.x, testPoint.y) == clickedColor) {
                testPoint.x--;
            }
            currentLine = new Line(getColor(), 5);
            currentLine.addPoint(new Point(testPoint));
            while(testPoint.x < image.getWidth() && image.getRGB(testPoint.x, testPoint.y) == clickedColor) {
                pointsToVisit.add(new Point(testPoint.x, testPoint.y+1));
                pointsToVisit.add(new Point(testPoint.x, testPoint.y-1));

                image.setRGB(testPoint.x, testPoint.y, getColor().getRGB());
                testPoint.x++;
            }
            currentLine.addPoint(new Point(testPoint));
            currentFill.addLine(currentLine);
        }
    }
}

}

Here is the basics of my line class:

public class Line {
private List<Point> points;
private int width;

/**
 * Create a Line
 * @param color - The color of the line
 * @param width - The width of the line
 */
public Line(Color color, int width){
    points = new LinkedList<>();
    setColor(color);
    setWidth(width);
}

/**
 * Add a Point to the Line
 * @param p - The Point to add to the Line 
 */
public void addPoint(Point p) {
    points.add(p);
}

@Override
public void draw(Graphics2D g2) {
    super.draw(g2);
    g2.setStroke(new BasicStroke(getWidth(), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
    for(int i=1; i<points.size(); i++)
        g2.drawLine(points.get(i-1).x, points.get(i-1).y, points.get(i).x, points.get(i).y);
}

}

And here is my Fill class:

public class Fill{

List<Line> lines;

/**
 * Create a Fill
 * @param color - The Color of the Fill
 */
public Fill(Color color){
    lines = new LinkedList<>();
    setColor(color);
}

/**
 * Add a Line to the Fill
 * @param l - The Line to add
 */
public void addLine(Line l) {
    lines.add(l);
}

@Override
public void draw(Graphics2D g2) {
    super.draw(g2);
    for(Line l: lines) {
        l.draw(g2);
    }
}

Any help would be appreciated, Thanks.

Was it helpful?

Solution

You need to change your createPoints(...) function to look like this:

private void createPoints(Point clickedPoint, int clickedColor) {
    pointsToVisit.add(clickedPoint);

    while(!pointsToVisit.isEmpty()) {
        Point testPoint = pointsToVisit.poll();

        if(testPoint.x >= 0 && testPoint.x < image.getWidth() && testPoint.y >= 0 && testPoint.y < image.getHeight() 
            && image.getRGB(testPoint.x, testPoint.y) == clickedColor) {
            while(testPoint.x > 0 && image.getRGB(testPoint.x-1, testPoint.y) == clickedColor) {
                testPoint.x--;
            }
            currentLine = new Line(getColor(), 5);
            currentLine.addPoint(new Point(testPoint));

            pointsToVisit.add(new Point(testPoint.x, testPoint.y+1));
            pointsToVisit.add(new Point(testPoint.x, testPoint.y-1));

            image.setRGB(testPoint.x, testPoint.y, getColor().getRGB());

            while(testPoint.x < image.getWidth()-1 && image.getRGB(testPoint.x+1, testPoint.y) == clickedColor) {
                pointsToVisit.add(new Point(testPoint.x, testPoint.y+1));
                pointsToVisit.add(new Point(testPoint.x, testPoint.y-1));

                image.setRGB(testPoint.x, testPoint.y, getColor().getRGB());
                testPoint.x++;
            }
            currentLine.addPoint(new Point(testPoint));
            currentFill.addLine(currentLine);
        }
    }
}

(I sprinkled a couple of =-signs into your if condition to allow you to click into the top left corner of the image also, and a couple of +1s and -1s into you while conditions to fix the bug described next)

Basically, what happens is after your first while loop you are either at the left edge of the image, in which case everything works fine, or your testPoint is pointing at the first pixel that is NOT equal to clickedColor any more, in which case your second while loop terminates immediately.

BTW: Your code will probably lock up if you click on a point that is already set to your fill color (i.e. if clickedColor == getColor()).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top