Общей площадью пересекающихся кругов

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

изображение:

для двух кругов это довольно легко,

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

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

13 ответов


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

circle overlap


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

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

конечно, это глупо, но:

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

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

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

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

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

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

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

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

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


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

Example

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

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

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


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

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

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

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

alt текст http://secretGeek.net/image/triangles_1667310.png


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

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


Хм, очень интересная проблема. Мой подход, вероятно, будет примерно таким:--10-->

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

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

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

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

  • теперь продолжайте добавлять круги и продолжайте работать над областью, добавленной как сумма / вычитание областей кругов и областей пересечений между кругами. Например, для 3 кругов (назовем дополнительный круг 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 из этих кругов, которые могут быть вычислены точно (не знаю, как это сделать, однако).

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


Я работал над проблемой моделирования перекрывающихся звездных полей, пытаясь оценить истинное количество звезд из фактических областей диска в плотных полях,где большие яркие звезды могут маскировать более слабые. Я тоже надеялся, что смогу сделать это с помощью строгого формального анализа, но не смог найти алгоритм для этой задачи. Я решил его, создав Звездные поля на синем фоне в виде зеленых дисков, диаметр которых определялся вероятностным алгоритмом. Простая процедура может соедините их, чтобы увидеть, есть ли перекрытие (поворачивая звездную пару желтым); затем количество пикселей цветов генерирует наблюдаемую область для сравнения с теоретической областью. Это затем генерирует кривую вероятности для истинных подсчетов. Грубая сила может быть, но, кажется, работает нормально.
http://www.2from.com/images/simulated_star_field.gif


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

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


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


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

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


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

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

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

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


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

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

одним недостатком пиксельной живописи является конечная точность решения. Но это настраивается просто путем рендеринга на большие или меньшие полотна, как того требует ситуация. Заметьте также, что анти-алиасинг в 2D-коде рендеринга (часто включенном по умолчанию) даст точность лучше, чем на уровне пикселей. Так, например, рендеринг фигуры 100x100 в холст тех же размеров должен, я думаю, давать точность порядка 1 / (100 x 100 x 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);