Комбинированная область перекрывающихся кругов

Недавно я столкнулся с проблемой, когда у меня было четыре круга (середина и радиус), и мне пришлось вычислять площадь объединения этих кругов.

Пример изображения:

LxEIF.png

Для двух кругов это довольно просто,

L9WCg.png

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

Но есть ли умный алгоритм, который я могу использовать, когда есть более двух кругов?

Ответ 1

Найдите все пересечения окружностей по внешнему периметру (например, B, D, F, H на следующей диаграмме). Соедините их вместе с центрами соответствующих кругов, чтобы сформировать многоугольник. Площадь объединения окружностей - это площадь многоугольника + площадь срезов круга, определяемая последовательными точками пересечения, и центр круга между ними. Вам также понадобятся все отверстия.

circle overlap

Ответ 2

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

  • установите ограничивающий прямоугольник вокруг кругов;
  • генерирует случайные точки в ограничивающей рамке;
  • выяснить, находится ли случайная точка внутри одного из кругов;
  • вычислить область с помощью некоторого простого сложения и деления (пропорция_о__по_определения_индекса * area_of_bounding_box).

Уверен, он немой, но:

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

Ответ 3

Для другого решения из предыдущего вы можете произвести оценку с произвольной точностью с использованием квадранта.

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

Каждая ячейка имеет одно из состояний: пустое, полное, частичное

Алгоритм состоит в "рисовании" кругов в квадранте, начиная с низкого разрешения (4 ячейки, например, помечены как пустые). Каждая ячейка либо:

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

Когда это будет сделано, вы можете вычислить оценку области: полные ячейки дают нижнюю границу, пустые ячейки дают более высокую оценку, частичные ячейки дают максимальную ошибку области.

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

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

Ответ 4

Ответ Ants Aasma дал основную идею, но я хотел сделать это немного более конкретным. Взгляните на пять кругов внизу и то, как они были разложены.

Example

  • Синие точки - это центры кругов.
  • Красные точки - это пересечения границы круга.
  • Красные точки с белым интерьером - это пересечения границы круга, которые не содержатся ни в каких других кругах.

Идентификация этих трех типов точек проста. Теперь построим структуру данных графа, где узлы представляют собой синие точки и красные точки с белым интерьером. Для каждого круга поместите грань между серединой круга (синяя точка) и каждым ее пересечением (красные точки с белым интерьером) на ее границе.

Это разлагает круговой союз на множество полигонов (заштрихованных синих) и круглых кусочков пирога (зеленого цвета), которые попарно не пересекаются и покрывают исходный союз (т.е. раздел). Так как каждая часть здесь - это то, что легко вычислить в области, вы можете вычислить площадь объединения, суммируя области частей.

Ответ 5

Мне нравится подход к случаю 2 пересекающихся кругов - вот как я бы использовал небольшую вариацию того же подхода для более сложного примера.

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

Разница здесь в том, что я начинаю со связывания центров (так что есть вершина между центром окружностей, а не между местами, где пересекаются окружности). Я думаю, что это позволяет лучше обобщать.

(на практике, может быть, стоит метод Монте-Карло)

alt text
(источник: secretGeek.net)

Ответ 6

Если вам нужен дискретный (в отличие от непрерывного) ответ, вы можете сделать что-то подобное алгоритму рисования пикселей.

Нарисуйте круги на сетке, а затем покрасьте каждую ячейку сетки, если она в основном содержится внутри cirle (то есть, по крайней мере, 50% ее области находится внутри одного из кругов). Сделайте это для всей сетки (где сетка охватывает всю область, охватываемую кругами), а затем подсчитайте количество цветных ячеек в сетке.

Ответ 7

Хм, очень интересная проблема. Мой подход, вероятно, был бы следующим:

  • Разработайте способ определения того, какие области пересечения между произвольным числом окружностей, т.е. если у меня есть 3 круга, мне нужно иметь возможность определить, что такое пересечение между этими кругами. Метод "Монте-Карло" был бы хорошим способом аппроксимировать это (http://local.wasp.uwa.edu.au/~pbourke/geometry/circlearea/).
  • Устраните любые круги, которые полностью содержатся в другом круге (посмотрите на радиус и модуль расстояния между центром двух окружностей). Я не думаю, что это обязательно.
  • Выберите 2 круга (назовите их A и B) и выработайте общую область, используя следующую формулу:

(это верно для любой формы, будь то круг или иначе)

area(A∪B) = area(A) + area(B) - area(A∩B)

Где A ∪ B означает A объединение B и A ∩ B означает, что A пересекает B (вы можете это сделать с первого шага.

  • Теперь продолжайте добавлять круги и продолжайте разрабатывать область, добавленную как сумму/вычитание областей кругов и областей пересечений между кругами. Например, для трех кругов (вызов дополнительной окружности C) мы определяем область, используя эту формулу:

(Это то же самое, что и выше, где A было заменено на A∪B)

area((A∪B)∪C) = area(A∪B) + area(C) - area((A∪B)∩C)

Где area(A∪B) мы только что разработали, и area((A∪B)∩C) можно найти:

area((A∪B)nC) = area((A∩C)∪(B∩C)) = area(A∩C) + area(A∩B) - area((A∩C)∩(B∩C)) = area(A∩C) + area(A∩B) - area(A∩B∩C)

Снова вы можете найти область (A∩B∩C) сверху.

Трудный бит - последний шаг - чем больше кругов добавляется, тем сложнее становится. Я считаю, что есть расширение для разработки области пересечения с конечным объединением, или, альтернативно, вы можете рекурсивно выработать ее.

Кроме того, что касается использования Монте-Карло для аппроксимации области итерации, я считаю возможным уменьшить пересечение произвольного числа окружностей до пересечения 4 этих кругов, которые можно точно вычислить (не знаю, как для этого, однако).

Вероятно, лучший способ сделать это btw - сложность значительно возрастает (возможно, экспоненциально, но я не уверен) для каждого добавленного дополнительного круга.

Ответ 8

Я работал над проблемой моделирования перекрывающихся звездных полей, пытаясь оценить истинное количество звезд по фактическим областям диска в плотных полях, где более крупные яркие звезды могут маскировать более слабые. Я тоже надеялся, что смогу сделать это с помощью строгого формального анализа, но не смог найти алгоритм для этой задачи. Я решил это, создав звездные поля на синем фоне в виде зеленых дисков, диаметр которых был определен вероятностным алгоритмом. Простая процедура может спарить их, чтобы увидеть, нет ли наложения (превращая звездную пару в желтый цвет); затем количество пикселей цветов создает наблюдаемую область для сравнения с теоретической областью. Затем генерируется кривая вероятности для истинных отсчетов. Грубая сила может быть, но, похоже, работает хорошо.

(источник: 2from.com)

Ответ 9

Существуют эффективные решения этой проблемы с использованием так называемых силовых диаграмм. Это действительно тяжелая математика, хотя и не то, что я хотел бы решить. Для "простого" решения найдите алгоритмы линейной развертки. Основной принцип заключается в том, что вы делите фигуру на полосы, где вычисление площади в каждой полосе относительно просто.

Итак, на фигуре, содержащей все круги, которые ничего не вытереть, нарисуйте горизонтальную линию в каждом положении, которое является либо вершиной круга, либо нижней частью круга, либо пересечением двух кругов. Обратите внимание, что внутри этих полос все области, которые вам нужно вычислить, выглядят одинаково: "трапеция" с двумя сторонами заменена круговыми сегментами. Поэтому, если вы можете решить, как вычислить такую ​​форму, вы просто делаете это для всех отдельных фигур и добавляете их вместе. Сложность этого наивного подхода - O (N ^ 3), где N - количество кругов на рисунке. Используя некоторую умную структуру данных, вы можете улучшить этот метод линейной развертки до O (N ^ 2 * log (N)), но если вам это действительно нужно, это, вероятно, не стоит проблем.

Ответ 10

Я нашел эту ссылку, которая может быть полезна. Однако, похоже, нет окончательного ответа. ответы Google. Еще одна ссылка для трех кругов - теорема Харуки. Там есть бумага.

Ответ 11

В зависимости от того, какую проблему вы пытаетесь решить, этого может быть достаточно, чтобы получить верхнюю и нижнюю границы. Верхняя граница проста, просто сумма всех кругов. Для нижней границы вы можете выбрать один радиус, чтобы ни один из кругов не перекрывался. Чтобы лучше найти наибольший радиус (до фактического радиуса) для каждого круга, чтобы он не перекрывался. Также должно быть довольно тривиально удалить любые полностью перекрывающиеся круги (все такие круги удовлетворяют | P_a - P_b | <= r_a), где P_a - центр круга A, P_b - центр круга B, а r_a - радиус A), и это повышает как верхнюю, так и нижнюю границу. Вы также можете получить лучшую верхнюю границу, если вы используете формулу пары для произвольных пар вместо суммы всех кругов. Может быть хороший способ выбрать "лучшие" пары (пары, которые приводят к минимальной общей площади.

Учитывая верхнюю и нижнюю границу, вы можете улучшить настройку подхода Монте-Карло, но ничего особенного не приходит на ум. Другой вариант (опять же в зависимости от вашего приложения) - растеризация кругов и подсчет пикселей. Это в основном подход Монте-Карло с фиксированным распределением.

Ответ 12

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

  • Приближает каждый круг регулярным многоугольником, центрированным в той же точке
  • Вычислить многоугольник, являющийся объединением аппроксимированных окружностей
  • Вычислить область объединенного многоугольника

Шаги 2 и 3 могут быть выполнены с использованием стандартных, легкодоступных алгоритмов из вычислительной геометрии.

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

Ответ 13

Это может быть решено с помощью теоремы Грина со сложностью n ^ 2log (n). Если вы не знакомы с теоремой Грина и хотите узнать больше, вот видео и заметки из Академии Хана. Но ради нашей проблемы, думаю, моего описания будет достаточно.

Извините за ссылки на фотографии, так как я не могу публиковать изображения. (Недостаточно очков репутации)

Общее уравнение теоремы Грина

Если я поставлю L и M так, что

Состояние

тогда RHS - это просто область Региона R, и ее можно получить, решив замкнутый интеграл или LHS, и это именно то, что мы собираемся сделать.

Все союзы можно разбить на такие непересекающиеся множества окружностей, которые пересекаются

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

AreaOfUnion= (Интеграция вдоль красных дуг в направлении против часовой стрелки + Интеграция вдоль синих дуг в направлении по часовой стрелке)

Но классный трюк в том, что для каждого круга, если мы интегрируем дуги, которые не находятся внутри какого-либо другого круга, мы получаем требуемую площадь, т.е. получаем интеграцию в направлении против часовой стрелки вдоль всех красных дуг и интеграцию вдоль всех синих дуг в направлении по часовой стрелке. РАБОТА ВЫПОЛНЕНА!!!

Даже случаи, когда круг не пересекается ни с каким другим, рассматриваются.

Вот ссылка GitHub на мой код C++

Ответ 14

Подход пиксельной живописи (как предложено @Loadmaster) превосходит математическое решение различными способами:

  • Реализация намного проще. Вышеупомянутая проблема может быть решена менее чем в 100 строках кода как показано в этом решении JSFiddle (главным образом потому, что его концептуально намного проще и не имеет края случаях или исключениях).
  • Он легко адаптируется к более общим проблемам. Он работает с любой формой, независимо от морфологии, до тех пор, пока ее рендерируемый с помощью двухмерных библиотек чертежей (т.е. "Все из них!" ) - круги, эллипсы, сплайны, многоугольники, вы называете это. Heck, даже растровые изображения.
  • Сложность решения для пиксельной живописи ~ O [n] по сравнению с ~ O [n * n] для математического решения. Это означает, что он будет работать лучше по мере увеличения числа фигур.
  • И, говоря о производительности, вы часто получаете аппаратное ускорение бесплатно, так как большинство современных 2D-библиотек (например, холст HTML5), я считаю, разгружает работу рендеринга на графические ускорители.

Единственным недостатком для рисования пикселей является конечная точность решения. Но это настраивается путем простого рендеринга на большие или мелкие полотна, как того требует ситуация. Обратите также внимание на то, что anti-aliasing в коде 2D-рендеринга (часто включается по умолчанию) обеспечит точность более высокого уровня. Так, например, рендеринг фигуры 100х100 в холст с одинаковыми размерами должен, я думаю, давать точность порядка 1/(100 х 100 х 255) =.000039%... что, вероятно, "достаточно хорошо", для всех, кроме самых сложных проблем.

<p>Area computation of arbitrary figures as done thru pixel-painting, in which a complex shape is drawn into an HTML5 canvas and the area determined by comparing the number of white pixels found in the resulting bitmap.  See javascript source for details.</p>

<canvas id="canvas" width="80" height="100"></canvas>

<p>Area = <span id="result"></span></p>
// Get HTML canvas element (and context) to draw into
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

// Lil' circle drawing utility
function circle(x,y,r) {
  ctx.beginPath();
  ctx.arc(x, y, r, 0, Math.PI*2);
  ctx.fill();
}

// Clear canvas (to black)
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);

// Fill shape (in white)
ctx.fillStyle = 'white';
circle(40, 50, 40);
circle(40, 10, 10);
circle(25, 15, 12);
circle(35, 90, 10);

// Get bitmap data
var id = ctx.getImageData(0, 0, canvas.width, canvas.height);
var pixels = id.data; // Flat array of RGBA bytes

// Determine area by counting the white pixels
for (var i = 0, area = 0; i < pixels.length; i += 4) {
  area += pixels[i]; // Red channel (same as green and blue channels)
}

// Normalize by the max white value of 255
area /= 255;

// Output result
document.getElementById('result').innerHTML = area.toFixed(2);