Разделение поверхности Java на маленькие квадраты

Я хотел бы знать, есть ли какой-либо алгоритм, который делает что-то вроде этого:

Учитывая конкретную поверхность, он делит ее на меньшие прямоугольники того же размера.

Что-то вроде этого примера рисунка:

введите здесь описание изображения

Серая область — это поверхность, а красные квадраты — сама перегородка.

Я думаю, есть ли оптимизированный способ сделать это.

Очень плохим подходом будет цикл for во всех пикселях и проверка, есть ли прямоугольник для этого конкретного места, если нет, будет создан прямоугольник и так далее.

Может кто знает алгоритм уже сделанный? или лучшее решение?

Заранее большое спасибо ;)


person TiagoM    schedule 19.03.2014    source источник


Ответы (2)


Вот один из способов сделать это.

  1. Создайте маску изображения. (Я просто использовал фотошоп)

    введите здесь описание изображениявведите здесь описание изображения

  2. Украдите код Эндрю Томпсона для Создание области из изображения и используйте его для создания Area изображения.

    Area imageArea = getOutline(Color.BLACK, imageMask);
    
  3. Создайте сетку из Rectangle2D объектов для всего изображения.

    Rectangle2D[][] grid = new Rectangle2D[rows][cols];
    for (int i = 0; i < grid.length; i++) {
        int y = i * CELL_SIZE;
        for (int j = 0; j < grid[i].length; j++) {
            int x = j * CELL_SIZE;
            grid[i][j] = new Rectangle2D.Double(x, y, cellSize, cellSize);
        }
    }
    
  4. Когда у вас есть сетка, вы можете просто пройтись по Rectangle2D объектам и проверить, есть ли Area.contains каждый отдельный Rectangle2D в сетке, и вы можете просто добавить его в List<Rectangle2D>. Будут добавлены только прямоугольники, содержащиеся в области, что даст вам окончательную сетку прямоугольников для рисования. В приведенном ниже примере я просто нарисовал прямоугольники в качестве визуального элемента.

    for (Rectangle2D[] rects : imageGrid) {
        for (Rectangle2D rect : rects) {
            if (imageArea.contains(rect)) {
                g2.drawRect((int) rect.getX(), (int) rect.getY(),
                        (int) rect.getWidth(), (int) rect.getHeight());
            }
        }
    }
    

Полный пример

введите здесь описание изображения

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class SquaresInArea extends JPanel {

    private static final int CELL_SIZE = 30;

    BufferedImage image;
    BufferedImage imageMask;
    Area imageArea;
    Rectangle2D[][] imageGrid;

    public SquaresInArea() {
        try {
            image = ImageIO.read(getClass().getResource("/resources/floorplan.png"));
            imageMask = ImageIO.read(getClass().getResource("/resources/floorplan-black.png"));
        } catch (IOException ex) {
            Logger.getLogger(SquaresInArea.class.getName()).log(Level.SEVERE, null, ex);
        }
        imageArea = getOutline(Color.BLACK, imageMask);
        imageGrid = createGrid();
    }

    private Rectangle2D[][] createGrid() {
        int width = image.getWidth();
        int height = image.getHeight();
        int rows = height / CELL_SIZE;
        int cols = width / CELL_SIZE;
        Rectangle2D[][] grid = new Rectangle2D[rows][cols];
        for (int i = 0; i < grid.length; i++) {
            int y = i * CELL_SIZE;
            for (int j = 0; j < grid[i].length; j++) {
                int x = j * CELL_SIZE;
                grid[i][j] = new Rectangle2D.Double(x, y, CELL_SIZE, CELL_SIZE);
            }
        }
        return grid;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.drawImage(image, 0, 0, this);
        g2.setColor(Color.YELLOW);
        g2.setStroke(new BasicStroke(3f));
        for (Rectangle2D[] rects : imageGrid) {
            for (Rectangle2D rect : rects) {
                if (imageArea.contains(rect)) {
                    g2.drawRect((int) rect.getX(), (int) rect.getY(),
                            (int) rect.getWidth(), (int) rect.getHeight());
                }
            }
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return image == null ? new Dimension(300, 300)
                : new Dimension(image.getWidth(), image.getHeight());

    }

    private Area getOutline(Color target, BufferedImage bi) {
        // construct the GeneralPath
        GeneralPath gp = new GeneralPath();

        boolean cont = false;
        int targetRGB = target.getRGB();
        for (int xx = 0; xx < bi.getWidth(); xx++) {
            for (int yy = 0; yy < bi.getHeight(); yy++) {
                if (bi.getRGB(xx, yy) == targetRGB) {
                    if (cont) {
                        gp.lineTo(xx, yy);
                        gp.lineTo(xx, yy + 1);
                        gp.lineTo(xx + 1, yy + 1);
                        gp.lineTo(xx + 1, yy);
                        gp.lineTo(xx, yy);
                    } else {
                        gp.moveTo(xx, yy);
                    }
                    cont = true;
                } else {
                    cont = false;
                }
            }
            cont = false;
        }
        gp.closePath();

        // construct the Area from the GP & return it
        return new Area(gp);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new SquaresInArea());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

вот еще один вид для ясности

введите здесь описание изображения

private final BasicStroke thin = new BasicStroke(1f);
private final BasicStroke thick = new BasicStroke(4f);

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    g2.drawImage(image, 0, 0, this);
    for (Rectangle2D[] rects : imageGrid) {
        for (Rectangle2D rect : rects) {
            if (imageArea.contains(rect)) {
                g2.setStroke(thick);
                g2.setColor(Color.GREEN);
                g2.draw(rect);
            } else {
                g2.setStroke(thin);
                g2.setColor(Color.RED);
                g2.draw(rect);
            }
        }
    }
}
person Paul Samsotha    schedule 19.03.2014
comment
Большое спасибо за ваш ответ, это поможет мне ;) - person TiagoM; 19.03.2014

Вы просто хотите заполнить его квадратами - или вы хотите заполнить его оптимальным количеством квадратов?

Алгоритм для второго сложнее.

Для начала просто пройдитесь по изображению квадратным размером за раз. Если пиксель в этой точке заполнен, отсканируйте весь квадрат, если он весь заполнен, нарисуйте квадрат. Если нет, то перейдите к следующему пункту.

то есть, если квадраты 10 * 10 пикселей:

for (int x=0;x<width;x+=SQUARE_SIZE) {
    for (int y=0;y<height;y+=SQUARE_SIZE) {
       // Now check if you can put a valid square here, if so draw it
    }
}
person Tim B    schedule 19.03.2014
comment
спасибо за ваш ответ, что вы подразумеваете под оптимальным количеством квадратов? Я хочу разделить поверхность на максимально возможное количество квадратов, учитывая определенную ширину и высоту квадрата. - person TiagoM; 19.03.2014
comment
Правильное размещение квадратов может означать, что вы вписываете в него разные числа. Например, если пространство имеет ширину 11 единиц, то вы можете разместить два квадрата шириной 5 единиц, если вы начнете с 0 или с 1, но если вы начнете с 2, вы сможете разместить только один квадрат. - person Tim B; 19.03.2014