Данные n квадраты с граничной длиной l, как я могу определить минимальный радиус r круга так, чтобы я мог распределить все квадраты равномерно вдоль периметра круга без них наложение? (Ограничение: первый квадрат будет всегда располагаться в 12 часов.)
Последующий вопрос: как я могу поместить n идентичные прямоугольники с высотой h и шириной w?
(источник: n3rd.org)
Может существовать математически хитрый способ сделать это, но я бы не знал.
Я думаю, что это немного усложняется тем фактом, что геометрия различается для каждого количества квадратов; для 4 это ромб, для 5 это пятиугольник и так далее.
Я бы поместил эти квадраты на круг размером 1 единицу (слишком маленький, я знаю, несите меня), распределенный на нем поровну. Это достаточно просто, просто разделите (разделите) ваши 360 градусов на количество квадратов. Затем просто проверьте все свои квадраты на перекрытие со своими соседями; если они перекрываются, увеличьте радиус.
Вы можете сделать эту процедуру менее глупой, чем кажется, используя интеллектуальный алгоритм для достижения нужного размера. Я думаю о чем-то вроде алгоритма Ньютона: учитывая два последовательных предположения, одно из которых слишком мало, а другое слишком велико, ваше следующее предположение должно быть средним из этих двух.
Вы можете выполнять итерацию с любой точностью. Остановитесь, когда расстояние между предположениями меньше некоторой произвольной небольшой погрешности.
РЕДАКТИРОВАТЬ У меня есть решение получше:
Я думал о том, что сказать вам, если вы спросите: «Как я узнаю, перекрываются ли квадраты?» Это дало мне представление о том, как точно рассчитать размер круга за один шаг:
Поместите квадраты на слишком маленький круг. Вы знаете, как: вычислите точки на окружности, в которых ваши углы 360 / n пересекают ее, и поместите туда центр квадрата. На самом деле, вам пока не нужно размещать квадраты, для следующих шагов нужны только средние точки.
Чтобы вычислить минимальное расстояние квадрата до его соседа: Вычислите разность по X и разность по Y средних точек и возьмите их минимум. X и Y на самом деле просто косинусы и синусы на окружности.
Вам понадобится минимум любой квадрат против своего соседа (скажем, по часовой стрелке). Поэтому вам нужно обойти круг, чтобы найти самый маленький.
Минимальное (X или Y) расстояние между квадратами должно быть 1,0. Так что просто возьмите величину, обратную минимальному расстоянию, и умножьте на это размер круга. Престо, твой круг правильного размера.
РЕДАКТИРОВАТЬ
Не теряя общности, я думаю, что можно немного усовершенствовать свое решение, чтобы оно было близко к кодированию. Вот уточнение:
Избавьтесь от крайних случаев:
if (n <2) throw new IllegalArgumentException ();
если (n == 2) вернуть 0,5; // 2 квадрата точно уместятся на окружности радиуса 0.5
Начните с круга размером r
0,5, который наверняка будет слишком маленьким для любого количества квадратов> 2.
r = 0,5;
dmin = 1,0; // начинаем предполагать, что минимальное расстояние в порядке
a = 2 * PI / n;
for (p1 = 0.0; p1 <= PI; p1 + = a) {// начиная с угла 0, пробуем все точки до середины
// (да, мы начинаем восток, а не север. не имеет значения)
р2 = р1 + а; // следующая точка на окружности
dx = abs (r * cos (p2) - r * cos (p1))
dy = abs (r * sin (p2) - r * sin (p1))
dmin = min (dmin, dx, dy)
}
r = r / dmin;
РЕДАКТИРОВАТЬ
Я превратил это в настоящий Java-код и получил для запуска нечто очень похожее на это. Код и результаты здесь: http://ideone.com/r9aiu
Я создал графический вывод с помощью GnuPlot. Мне удалось создать простые диаграммы прямоугольников, расположенных по кругу, путем вырезания и вставки наборов точек из вывода в файл данных, а затем запуска
plot '5.dat' with boxxyerrorbars
.5
в файле serve размер ящиков ... ленивое, но рабочее решение. 0,5 применяется к обеим сторонам от центра, поэтому коробки в конечном итоге имеют размер 1,0.
Увы, мой алгоритм не работает . Это делает радиусы слишком большими, поэтому коробки располагаются намного дальше друг от друга, чем необходимо. Даже уменьшение в 2 раза (в некоторых местах могло быть ошибкой использование 0,5) не помогло.
Простите, я сдаюсь. Может быть, мой подход можно спасти, но он работает не так, как я, хотя мог бы. : (
РЕДАКТИРОВАТЬ
Ненавижу сдаваться.Я собирался оставить свой компьютер, когда подумал о способе спасти свой алгоритм:
Алгоритм регулировал меньшее расстояний X или Y, чтобы оно было не менее 1. Это легко продемонстрировать. просто глупо.Когда у вас много ящиков, то на восточном и западном краях круга у вас есть ящики, уложенные почти прямо друг на друга, причем их X очень близко друг к другу, но они защищены от соприкосновения за счет наличия достаточного расстояния Y между их.
Итак ... чтобы выполнить эту работу, вы должны масштабировать максимум dx и dy так, чтобы (для всех случаев) как минимум радиус (или это был двойной радиус?).
Исправленный код находится здесь: http://ideone.com/EQ03g http://ideone.com/VRyyo
Повторно протестирован в GnuPlot, он создает красивые маленькие кружочки прямоугольников, где иногда просто 1 или 2 коробки ровно соприкасаются. Проблема решена! :)
(Эти изображения шире, чем высокие, потому что GnuPlot не знал, что мне нужен пропорциональный макет. Только представьте, что все работы сжаты в квадратную форму :))
Я бы вычислил верхнюю границу минимального радиуса, работая с кругами, охватывающими квадраты, вместо самих квадратов.
Мои результаты вычислений:
Rmin <= X / (sqrt (2) * sin (180 / N))
Где: X - длина стороны квадрата, а N - необходимое количество квадратов.
Я предполагаю, что круги расположены так, что их центры попадают на окружность большого круга.
- РЕДАКТИРОВАТЬ -
Используя идею Дэйва в комментарии ниже, мы также можем вычислить хорошую нижнюю границу, считая, что круги находятся внутри квадратов (таким образом, имея радиус X / 2). Эта граница:
Rmin> = X / (2 * sin (180 / N))
Как уже отмечалось, проблема расположения n точек на равном расстоянии друг от друга по окружности круга является тривиальной. Не самая сложная часть проблемы заключается в том, чтобы определить радиус окружности, необходимый для приятного расположения квадратов. Я предлагаю вам последовать одному из других ответов и представить, что квадраты находятся внутри круглого "буфера", достаточно большого, чтобы вместить квадрат и достаточно пространства, чтобы удовлетворить ваши эстетические требования. Затем проверьте формулу для длины хорды между центрами соседних квадратов. Теперь у вас есть угол в центре круга, вычитаемый хордой между центрами квадратов, и вы можете легко вычислить радиус круга из тригонометрии треугольника.
И, что касается вашего последующего вопроса: Я предлагаю вам решить задачу для квадратов с длиной стороны min(h,w)
на окружности, затем преобразовать квадраты в прямоугольники, а окружность в эллипс с эксцентриситетом h/w (или w/h).
Я бы решил ее так:
Чтобы найти связь между радиусом r и длиной l, давайте проанализируем безразмерное представление
Это оптимальное решение, которое можно решить в терминах r = f(l). Решение может быть адаптировано к прямоугольникам путем корректировки формул для xLR[i] и yUL[i+1].
Постараюсь дать некоторый псевдокод.
EDIT:
.
В процедуре есть ошибка, нижний правый и верхний левый не являются необходимыми ближайшими точками для двух соседних квадратов/прямоугольников.
Предположим, вы решили задачу для 3 или 4 квадратов.
Если у вас есть n > = 5 квадратов, и вы поместите один квадрат вверху круга, у вас будет другой квадрат, который попадет в первый квадрант декартовой плоскости, концентричной с вашим кругом.
Задача состоит в том, чтобы найти такой радиус r для круга, чтобы левая сторона круга рядом с верхним кругом и правая сторона верхнего круга не пересекались друг с другом. .
Координата x правой стороны верхнего круга равна x1 = L / 2, где L - сторона квадрата.Координата x левой стороны окружности рядом с верхней составляет x2 = r cos a - L / 2, где r - радиус, а a - угол между каждой парой квадратных центров ( a = 360 / n градусов).
Итак, нам нужно решить x1 <= x2 , что приводит к
r > = L / cos a .
L и a известны, так что мы закончили: -)
Вы начинаете с произвольного круга (например, с диаметром (* n l)
) и равномерно размещаете квадраты по окружности.Затем вы проходите через каждую пару соседних квадратов и:
вычисляете пересечение этой линии со сторонами промежуточных квадратов (M1 и M2 - средние точки, S1 и S2 - соответствующие пересечения со стороной квадрата:
S2 S1
M1 -------------- * ---------- * --------------- M2
------------------------
| |
| |
| |
| |
| M1 |
| \ |
| \ |
| ------- * ------- + --------
| | \ | |
| | \ | |
------- + --------- * ------ |
| \ |
| M2 |
| |
| |
| |
| |
-------------------------
вычислите масштабный коэффициент, необходимый для того, чтобы S1 и S2 упали вместе (просто отношение суммы M1-S1 и S2-M2 к M1-M2), и
, наконец, масштабируйте круг на максимум найденные масштабные коэффициенты.
Редактировать: Это точное решение. Тем не менее, немного подумав, можно еще оптимизировать это для скорости: