Пересечение двух треугольников


19

Учитывая 4 точки на 2D плоскостях A, B, C, D, рассчитать площадь области пересечения треугольников OABи OCD, где Oнаходится центр плоскости, имеющей координаты (0, 0).

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

правила

  • Каждая точка представлена ​​двумя действительными числами, обозначающими их координаты X и Y.
    • При желании, если ваш язык программирования (или некоторая библиотека вашего языка программирования) имеет встроенный Pointтип или эквивалентный, он может принимать Pointобъект в качестве входных данных.
  • Ввод дается в 4 балла, в форматах, включая, но не ограничиваясь:
    • Список из 8 координат.
    • Список из 4 точек, каждая точка может быть представлена ​​в любом удобном формате.
    • Два списка по 2 балла.
    • и т.п.
  • Вы не можете принять конкретный порядок точек (против часовой стрелки или по часовой стрелке)
  • Вы не можете предполагать, что точка Oпередается в качестве ввода. Другими словами, программа не должна принимать и использовать посторонний ввод.
  • Вы не можете предполагать, что все точки разные. Другими словами, треугольники могут быть вырожденными. Вы должны также обработать этот случай (см. Контрольные примеры ниже)
  • Абсолютная или относительная разница должна быть меньше, чем для тестовых примеров ниже.10-3

Критерии победы

Это , самый короткий ответ в байтах побеждает!

Примеры тестовых случаев

Ax Ay Bx By Cx Cy Dx Dy area

5 1 1 3 -1 0 0 -1 0
5 1 1 3 -1 0 0 0 0
5 1 1 3 0 0 0 0 0
5 1 1 3 3 4 4 -3 4.50418
5 1 1 3 1 2 2 1 1.5
5 1 1 3 -2 5 4 -2 1.74829
5 1 1 3 -2 5 5 4 2.96154
5 1 1 3 3 5 5 4 1.88462
5 1 1 3 3 5 3 1 3.92308
5 1 1 3 3 5 4 -1 5.26619
5 1 1 3 5 1 4 -1 0
5 1 1 3 5 1 1 3 7
1 3 1 3 5 1 1 3 0
1 3 1 3 1 3 1 3 0
4 8 4 -1 -2 6 -2 -3 0

1.2 3.4 -0.3 4.2 5 7.6 -1.1 2.4 2.6210759326188535
3.1 0.6 0.1 7.2 5.2 0.7 0.9 8 9.018496993987977

Если кто-то хочет, вот результаты для первой группы тестовых случаев в точной форме:

0
0
0
46375/10296
3/2
1792/1025
77/26
49/26
51/13
23345/4433
0
7
0
0
0

Иллюстративное изображение для тестового примера 5 1 1 3 3 4 4 -3(площадь зеленого четырехугольника - ожидаемый результат):

[ Образ]


Один из ваших тестовых примеров имеет 9 входов, а не 8. 1.2 3.4 -0.3 4.2 5 3 7.6 -1.1 2.4 0
Келли Лоудер

1
@KellyLowder Исправлено.
user202729

Ответы:


16

Wolfram Language (Mathematica) , 55 байтов

0&@@Area@BooleanRegion[And,Simplex[{0{,}}~Join~#]&/@#]&

Попробуйте онлайн!

Побрил несколько байтов от тривиального ответа.

%@{{{5, 1}, {1, 3}}, {{3, 4}, {4, -3}}} yields 46375/10296 or 4.504176379

Замена Areaна DiscretizeRegionпокажет пересечение.

введите описание изображения здесь

Кстати, это будет работать с любыми симплексами, а не только с треугольниками.

-1 байт благодаря JungHwan Min

Предложение @ user202729 добавило 4 байта, но дает 0 для вырожденных треугольников


1
Полигон также может заменить Симплекс
Келли Лоудер

1
Еще один байт: {{0,0}}to {0{,}}(это работает, потому что выражение оценивается как {Times[0, {Null, Null}]})
JungHwan Мин.

Сбой для этого теста , который указан в примере тестовых случаев.
user202729

Уже отмечалось, что это НЕ работает на TIO. Не уверен, что у них под капотом.
Келли Лоудер

1
Я вижу, что это не работает для пересечения двух линий. Мой плохой за пропуск этого теста. Технически это не треугольники. Я полагаю, если мы собираемся получить эту техническую информацию, возможно, вам следует изменить название поста, а также первое предложение. Мы также могли бы провести действительно эзотерическую дискуссию о том, определена ли область даже для одномерного объекта, но я бы предпочел этого не делать.
Келли Лоудер

5

Python 2 + PIL, 341 318 313 284 270 байт

Особая благодарность Деннису, который быстро добавил PIL на TIO
-23 байта благодаря Mr. Xcoder

import PIL.Image as I,PIL.ImageDraw as D
l=[i*1000for i in[0,0]+input()+[0,0]]
z=zip(*[[i-min(t)for i in t]for t in l[::2],l[1::2]])
print sum(map(int.__mul__,*map(lambda i,c:D.Draw(i).polygon(c,1)or i.getdata(),map(I.new,'11',[[max(l)-min(l)]*2]*2),[z[:3],z[3:]])))/1e6

Попробуйте онлайн! или попробуйте все тестовые случаи

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

объяснение

#the image/triangles are enlarged to increase the precision
#a pair of zeros are inserted in the start and at the end, this way "l" will have all 6 points to draw the triangles 
l=[i*1000for i in[0,0]+input()+[0,0]]
#split the input in x and y, where x=l[::2] and y=l[1::2]
#get the smallest number on each list, that will be "0" if there is no negative number, to be used as offset.
#this will be used to overcome the fact that PIL won't draw on negative coords
#zip "x" and "y" lists, to create a list containing the points
z=zip(*[[i-min(t)for i in t]for t in x,y])
#create 2 (B&W) blank images
#where the size is the difference between the smallest and the largest coord.
map(I.new,'11',[[max(l)-min(l)]*2]*2)
#draw both triangles and return the pixel list of each image
map(lambda i,c:D.Draw(i).polygon(c,1)or i.getdata(),<result of previous line>,[z[:3],z[3:]])
#count the amount of overlapping pixels by summing the color of each pixel, if the pixel is "1" in both images, then the triangles are overlapping, then the amount of pixels is divided by the initial enlarging factor squared (1e6)
print sum(map(int.__mul__,*<result of previous line>))/1e6
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.