Llewv
Llewv

Reputation: 133

Drawing graphics into an Array

Suppose that I have the given array:

int[] array = {
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0
    };

Would there be a way to draw graphics into that array? For example assume that we have a way to access the data in this array by an x and y coordinate could we make a method that would put a line through this array dependant on 2 coordinates. The code would look something like this:

public void drawLine(int x1, int y1, int x2, int y2) {
    ...     
}

And would transfer something like this:

int[] array = {
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0
    };

Into this:

int[] array = {
        1, 0, 0, 0, 0,
        0, 1, 0, 0, 0,
        0, 0, 1, 0, 0,
        0, 0, 0, 1, 0,
        0, 0, 0, 0, 1
    };

You would have to be able to pass in any set of coordinates and have a calculated line placed through the array. How would I implement this?

Calling drawLine(1,0,3,4) would create something like:

int[] array = {
    0, 1, 0, 0, 0,
    0, 0, 1, 0, 0,
    0, 0, 1, 0, 0,
    0, 0, 0, 1, 0,
    0, 0, 0, 1, 0
};

Also if your up to it is there a way I could specify any number of points and have them all connected and then filled in? (No I don't want to use any libraries).

Upvotes: 1

Views: 1777

Answers (1)

MatheM
MatheM

Reputation: 811

Very cheaty way to do it (without implementing the drawing logic yourself) would be to use BufferedImage with the dimensions of your array and draw on that. After drawing the line you want you would iterate over the pixels of the BufferedImage and check which pixels are painted.

private static void drawToArray(int[][] array2d, int x1, int y1, int x2, int y2) {
    int width = array2d[0].length; // width is columns and columns are second
    int height = array2d.length; // height is rows and rows are first

    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2d = image.createGraphics();
    g2d.setBackground(Color.WHITE);
    g2d.fillRect(0, 0, width, height);  // paint background white
    g2d.setColor(Color.BLACK);
    BasicStroke bs = new BasicStroke(1); // set black brush to size 1 (1 pixel)
    g2d.setStroke(bs);

    g2d.drawLine(x1, y1, x2, y2); // paint line on image

    // fill array with values, check entire image
    for (int row = 0; row < height; row++) {
        for (int column = 0; column < width; column++) {
            int clr = image.getRGB(row,column); // get color of pixel at position
            if (clr == Color.WHITE.getRGB()) { // white is -1
                array2d[row][column] = 0;
            } else {
                array2d[row][column] = 1;
            }
        }
    }
    g2d.dispose();
    // returning array is not necesery I am editing the array2d variable passed in
}

Usage

int[][] arr = new int[5][5];
drawToArray(arr, 0, 0, 2, 5);

This example assumes that your array is two dimensional and that each row is of same length. If you want to use one dimensional array, you will have to define its width and height yourself. Also instead of

array2d[row][column] = 0;

you would have

array1d[row*width + column] = 0;

Edit 1: edited my answer to be more general

Edit 2: Considering performance

I doubt that I can improve the drawLine method so only place for improvement is conversion to 2d array. It is possible to get the array of pixels represented as integer values from Image and convert that to 2d array. I updated the draw ToArray method and left commented out lines there as explanation.

private static void drawToArray(int[][] array2d, int x1, int y1, int x2, int y2) {
    int width = array2d[0].length; // width is columns and columns are second
    int height = array2d.length; // height is rows and rows are first

    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2d = image.createGraphics();   // default color of image is 0 no need to paint background, just draw with color diferent than 0
    //g2d.setColor(Color.WHITE);               // default brush color is different than 0, expicitly setting is unnecesery
    //BasicStroke bs = new BasicStroke(1);
    //g2d.setStroke(bs);                       // default is 1 pixel expicitly setting is unnecesery

    g2d.drawLine(x1, y1, x2, y2); // paint line on image

    int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
    for (int i = 0, row = 0, col = 0; i < pixels.length; i++) {
        array2d[row][col] = pixels[i] == 0 ? 0 : 1; // no performance difference vs if/else just readability
        //array2d[row][col] = pixels[i]; // if you write it like this you will be "painting" with '-1's instead of '1's and save one if/else
        col++;
        // if is more readable here no performance difference vs ternary
        if (col == width) {
            col = 0;
            row++;
        }
    }
    g2d.dispose();
}

Only other place where to improve performance is to not convert it to 2d array at all and access the values like I mentioned before. But if you want to "paint" with number 1 instead of default -1 you will have to loop trough the array of pixels anyway to replace the -1s with 1s.

Upvotes: 2

Related Questions