Разделение площади на заданное количество квадратов

У меня есть элемент DIV, размер которого может быть изменен пользователем. В этом DIV я хочу нарисовать заданное количество квадратов. Теперь мне нужно выяснить, какой должна быть идеальная длина стороны квадрата, чтобы все поместилось в DIV без переполнения.

Это то, что я получил до сих пор:

function CalcSize (){
    var number = 23; // Example-Number
    var area = jQuery('#container').height() * jQuery('#container').width();
    var elementArea = parseInt(area / number);
    var sideLength = parseInt(Math.sqrt(elementArea));
    return sideLength;
}

Это делает квадраты слишком большими, поскольку не «выбрасывает» пространство, которое не может быть заполнено квадратами. При поиске этой проблемы я нашел проблему с упаковкой и отображение дерева, но ни то, ни другое не помогло мне с моим проблема, так как, честно говоря, мне не хватает математических навыков, и, насколько я понимаю, решения допускают такие вещи, как неквадраты и повороты.

Спасибо!

Обновление:

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

Ссылка на скриншот


person Fjonan    schedule 03.12.2013    source источник
comment
Равны ли ширина и высота вашего родительского div...?   -  person Prasath K    schedule 03.12.2013
comment
Нет, пользователь может свободно определять размер DIV, за исключением минимальной высоты/ширины и максимальной высоты/ширины, контролируемых CSS. Скрипт будет запущен, когда пользователь прекратит изменять размер или когда будут добавлены или удалены новые элементы.   -  person Fjonan    schedule 03.12.2013
comment
что именно вы подразумеваете под не выбрасывать? можете ли вы предоставить фотографии, пожалуйста?   -  person ile    schedule 03.12.2013
comment
Тогда квадратов не добиться...   -  person Prasath K    schedule 03.12.2013
comment
@Prasath: Он может, если он может оставить часть области незаполненной.   -  person Klas Lindbäck    schedule 03.12.2013
comment
и что вы подразумеваете под идеальной длиной стороны? это максимально возможная длина? Вы понимаете, что это не всегда возможно, т.е. когда число = 5, вы не сможете заполнить прямоугольник двумя рядами квадратов?   -  person ile    schedule 03.12.2013
comment
Что, если jQuery('#container').height() возвращает простое число, например 997   -  person Tom Chung    schedule 03.12.2013
comment
Тогда «идеальная» длина стороны будет 1px?   -  person Tom Chung    schedule 03.12.2013
comment
Обновил пост ссылкой на скриншот. Под выбрасыванием я имел в виду, что мое в настоящее время не работающее решение, похоже, не учитывает наличие незаполненного пространства. Что касается простых чисел: могу ли я учесть простые числа, уменьшив число высоты/с на единицу в своих расчетах?   -  person Fjonan    schedule 03.12.2013
comment
то, что у вас есть, на самом деле довольно хорошо. Представьте, если бы мы немного увеличили размер квадратов. Тогда последний столбец должен уйти, и всего у вас будет только 4 столбца. Но некуда поставить эти 4 квадрата, так как нельзя увеличить количество рядов. Верно?   -  person ile    schedule 03.12.2013
comment
Правильно, именно поэтому нынешний метод грубой силы тут же остановился. Я надеялся, что смогу найти решение, которое не полагается на циклы для вычисления правильного размера.   -  person Fjonan    schedule 03.12.2013
comment
Я чувствую, что вам все равно понадобится цикл, хотя определенно лучше, чем грубая сила.   -  person ile    schedule 03.12.2013


Ответы (2)


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

Обратите внимание, что цикл while обычно не должен проходить более одной или двух итераций.

function CalcSize (){
    var number = 23; // Example-Number
    var width = jQuery('#container').width();
    var height = jQuery('#container').height();
    var area = height * width;
    var elementArea = parseInt(area / number);

    // Calculate side length if there is no "spill":
    var sideLength = parseInt(Math.sqrt(elementArea));

    // We now need to fit the squares. Let's reduce the square size 
    // so an integer number fits the width.
    var numX = ceil(width/sideLength);
    sideLength = width/numX;
    while (numX <= number) {
        // With a bit of luck, we are done.
        if (floor(height/sideLength) * numX >= number) {
            // They all fit! We are done!
            return sideLength;
        }
        // They don't fit. Make room for one more square i each row.
        numX++;
        sideLength = width/numX;
    }
    // Still doesn't fit? The window must be very wide
    // and low.
    sideLength = height;
    return sideLength;
}
person Klas Lindbäck    schedule 03.12.2013
comment
Очень хорошо работает! Неиспользуемое пространство внизу фактически соответствует моему (в вопросе, который явно не указан) варианту использования, когда элементы добавляются во время выполнения довольно хорошо. Большое спасибо всем, кто помогает мне в этом. :) - person Fjonan; 03.12.2013

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

По сути, это задача линейного программирования (на самом деле это задача целочисленного программирования). У нас есть следующие неравенства, и мы хотим максимизировать длину.

строки, столбцы и длина неизвестны; и n, ширина и высота даны:

rows >= 1
cols >= 1
rows*cols >= n
rows*length <= height
cols*length <= width
maximize length

Из последних 3 уравнений вы получили правильную оценку: длина ‹ = sqrt (высота * ширина / n). Однако вам все равно нужно будет перебрать возможный диапазон, чтобы получить целочисленные значения. Вы можете сделать это намного быстрее с помощью Двоичный поиск.

person ile    schedule 03.12.2013
comment
Я должен возиться с идеей. Ответ Класа довольно близок к тому, что я хочу. Теперь все сводится к тому, чего человек хочет. В приведенном выше ответе используется не так много циклов, и он визуально соответствует квадратам по ширине. Я придерживаюсь этого сейчас, но ваш ответ близок к моему используемому в настоящее время методу. Большое спасибо за ваш отзыв! - person Fjonan; 03.12.2013