Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combine smaller rectangles into larger ones

Tags:

algorithm

I have a problem where I need to merge small squares into larger rectangles. Say I have a 2D grid, filled with random 1's and 0's:

1 0 1 1 0
1 0 1 1 1
0 1 0 1 1
0 1 0 1 1
0 0 1 0 0

The 1's represent areas that are filled, and I draw them to screen way down the line as squares. However, for this problem, I need to match them up into rectangles first. In the example show, the 1's in the top left corner ->

1
1

can be joined into a rectangle.

I think that should be sufficient to explain what I need. It is preferable, however, that a particular square not be used in more than one rectangle. Also, it does not have to be the best case with the least number of rectangles, just a better case with fewer rectangles. 1x1 rectangles are also allowed were it would make things easier.

Any insight into where I could start, or even a solution will be appreciated.

If you want to know the reason behind this problem, I am working on a level builder for a game I am working on, and I want to reduce my vertex count. I thought I'd start with squares because they would be simple, but even this is boggling my mind.

Thank you for taking time to read!

like image 303
Denzil Avatar asked Nov 07 '11 11:11

Denzil


People also ask

How do you work out how many squares fit in a rectangle?

In a 2 \times 3 rectangle, squares of side 1 unit and squares of side 2 units can be formed. Number of squares of side 1 unit is 2 \times 3 = 6. Number of squares of side 2 units is 1 \times 2 = 2. Therefore the total number of squares in a 2 \times 3 rectangle is 6 + 2 = 8.

How many rectangles are in a rectangle?

As we know that a rectangular prism is also a cuboid. Thus, it has six rectangles in a net of a rectangular prism because rectangular prism is a prism in which all the faces are rectangles.

How many rectangles are there in A4?

36 Rectangle Labels per A4 sheet 57 mm x 20 mm.


2 Answers

I'm using 2 steps to reduce the numbers of colliders in my game. Merging horizontally consecutive types, then merging vertically types that have the same width.

steps

The code is a work in progress, but it seems to be working~

public class Tiles
{
    public char Type { get; set; }
    public int X { get; set; }
    public int Y { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }

    public override string ToString()
    {
        return $@"({X}, {Y}, {Width}, {Height}) '{Type}'";
    }
}

public class TilesFromStrings
{
    private List<Tiles> Result = new List<Tiles>();

    public IEnumerable<Tiles> Create(params string[] lines)
    {
        Result.Clear();

        CreateMergedHorizontalTiles(lines);
        MergeVerticallyTilesWithSameWidth();

        return Result.Where(f => f.Height > 0);
    }

    private void MergeVerticallyTilesWithSameWidth()
    {
        foreach (var current in Result)
        {
            foreach (var other in Result)
            {
                if (other.Y + other.Height == current.Y
                        && other.X == current.X
                        && other.Height > 0
                        && current.Height > 0)
                {
                    if (other.Type == current.Type)
                    {
                        if (other.Width == current.Width)
                        {
                            current.Height--;
                            current.Y++;
                            other.Height++;
                            break;
                        }
                    }
                }
            }
        }
    }

    private void CreateMergedHorizontalTiles(string[] tiles)
    {
        Tiles currentRect = null;
        var lastColumnIndex = tiles[0].Length - 1;
        for (int rowIndex = 0; rowIndex < tiles.Length; rowIndex++)
        {
            for (int columnIndex = 0; columnIndex < tiles[rowIndex].Length; columnIndex++)
            {
                var currentType = tiles[rowIndex][columnIndex];

                if (columnIndex == 0)
                {
                    currentRect = new Tiles
                    {
                        X = columnIndex + 1,
                        Y = rowIndex + 1,
                        Width = 1,
                        Height = 1,
                        Type = currentType
                    };

                    continue;
                }

                if (columnIndex == lastColumnIndex)
                {
                    if (currentRect.Type == currentType)
                    {
                        Result.Add(currentRect);
                        currentRect.Width++;
                    }
                    else
                    {
                        Result.Add(currentRect);
                        currentRect = new Tiles
                        {
                            X = columnIndex + 1,
                            Y = rowIndex + 1,
                            Width = 1,
                            Height = 1,
                            Type = currentType
                        };
                        Result.Add(currentRect);
                    }

                    continue;
                }

                if (currentRect.Type == currentType)
                {
                    currentRect.Width++;
                }
                else
                {
                    Result.Add(currentRect);
                    currentRect = new Tiles
                    {
                        X = columnIndex + 1,
                        Y = rowIndex + 1,
                        Width = 1,
                        Height = 1,
                        Type = currentType
                    };
                }
            }
        }
    }
}
like image 72
Ricardo Valente Avatar answered Oct 31 '22 18:10

Ricardo Valente


A simple approach would be to look for adjacent squares and turn them into rectangles. To do this first go horizontally through the grid and join together horizontally adjacent squares, then go through the grid vertically and join vertically adjacent squares.

Consider:

H = piece of horizontal rectangle

V = piece of vertical rectangle

Your original example of:

 1 0 1 1 0
 1 0 1 1 1
 0 1 0 1 1
 0 1 0 1 1
 0 0 1 0 0

would turn into:

V 0 H H 0
V 0 H H H
0 V 0 H H
0 V 0 H H
0 0 1 0 0

This approach is not optimal, but it will turn squares into rectangles if it is possible to do so given the 2D grid.

like image 2
Ojen Avatar answered Oct 31 '22 17:10

Ojen