Задача.
Треугольник и точка. Лежит ли точка [latex] M \left( x_{m}, y_{m} \right) [/latex] внутри треугольника, заданного координатами своих вершин [latex] \left( x_{A}, y_{A} \right) [/latex], [latex] \left( x_{A}, y_{A} \right) [/latex], [latex] \left( x_{A}, y_{A} \right) [/latex].
Комментарий.
Предполагаем, что треугольник невырожденный, т.е. точки [latex] A [/latex], [latex] B [/latex] и [latex] C [/latex] не лежат на одной прямой.
Слово «внутри» будем понимать следующим образом: точка «лежит внутри треугольника», если она принадлежит внутренности (в топологическом смысле) этого треугольника. Как следствие, если точка лежит на одной из сторон треугольника, внутри треугольника она НЕ лежит.
Тесты.
Ввод | Вывод |
0 0 1 0 1 1 0.5 0.25 | Да |
0 0 1 0 1 1 -1 -1.5 | Нет |
-1.5 -1.5 -1.5 4 1 0.5 -1 2 | Да |
-1.5 -1.5 -1.5 4 1 0.5 -1 0 | Нет |
0.3 0.2 1.3 0.2 0.3 0.8 0.7 0.4 | Да |
0.3 0.2 1.3 0.2 0.3 0.8 0.3 0.6 | Нет |
2 1 0.5 -2 -2 -0.5 0.5 -1 | Да |
2 1 0.5 -2 -2 -0.5 2 1 | Нет |
Рассмотрим четыре основных типа треугольников:
- ровно одна сторона параллельна оси абсцисс;
- ровно одна сторона параллельна оси ординат;
- две стороны параллельны координатным осям;
- ни одна из сторон не параллельна ни к одной из осей.
Для каждого типа рассмотрим два случая: точка принадлежит его внутренности и не принадлежит. При этом рассмотрим случай (восьмая строка таблицы), когда точка лежит на стороне и постараемся рассмотреть случаи, когда координатами являются нецелые и отрицательные числа.
По моим подсчётам есть 96 вариантов расположения треугольника и точки, с учётом параллельности/непараллельности сторон осям, расположения вершин по координатным четвертям и принадлежности/непринадлежности точки внутренности треугольника. Поэтому хочется верить, что выбранные тестовые примеры достаточно показательные.
Код.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include <iostream> #include <math.h> using namespace std; int main() { int i; double a1, a2, b1, b2, c1, c2, x, y, f, g; scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &a1, &a2, &b1, &b2, &c1, &c2, &x, &y); f = (y - a2)*(b1 - a1) - (x - a1)*(b2 - a2); g = (c2 - a2)*(b1 - a1) - (c1 - a1)*(b2 - a2); if (f*g > 0) { // Проверяем, лежат ли точки (x,y) и C по одну сторону от прямой AB f = (y - a2)*(c1 - a1) - (x - a1)*(c2 - a2); g = (b2 - a2)*(c1 - a1) - (b1 - a1)*(c2 - a2); if (f*g > 0) { // Проверяем, лежат ли точки (x,y) и B по одну сторону от прямой AC f = (y - b2)*(c1 - b1) - (x - b1)*(c2 - b2); g = (a2 - b2)*(c1 - b1) - (a1 - b1)*(c2 - b2); if (f*g > 0) { // Проверяем, лежат ли точки (x,y) и A по одну сторону от прямой BC printf("Да \n"); } else { printf("Нет \n"); } } else { printf("Нет \n"); } } else { printf("Нет \n"); } return 0; } |
Код (Java)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import java.util.*; import java.lang.*; import java.io.*; class Main { public static void main (String[] args) throws java.lang.Exception { Scanner in = new Scanner(System.in); double a1 = in. nextDouble(), a2 = in. nextDouble(); double b1 = in. nextDouble(), b2 = in. nextDouble(); double c1 = in. nextDouble(),c2 = in. nextDouble(); double x = in. nextDouble(), y = in. nextDouble(), f, g; f = (y - a2)*(b1 - a1) - (x - a1)*(b2 - a2); g = (c2 - a2)*(b1 - a1) - (c1 - a1)*(b2 - a2); if (f*g > 0) { f = (y - a2)*(c1 - a1) - (x - a1)*(c2 - a2); g = (b2 - a2)*(c1 - a1) - (b1 - a1)*(c2 - a2); if (f*g > 0) { f = (y - b2)*(c1 - b1) - (x - b1)*(c2 - b2); g = (a2 - b2)*(c1 - b1) - (a1 - b1)*(c2 - b2); if (f*g > 0) System.out.println("Yes\n"); else System.out.println("No\n"); } else System.out.println("No\n"); } else System.out.println("No\n"); } } |
Решение.
- Составим уравнения сторон треугольника. Как известно, в эвклидовой геометрии в прямоугольных декартовых координатах уравнение прямой, проходящей через две (различные!) точки [latex] \left( r1, r2 \right) [/latex] и [latex] \left( s1, s2 \right) [/latex] есть [latex] \left(y — r2 \right) \left( s1 — r1 \right) — \left( x — r1 \right) \left( s2 — r2 \right) = 0[/latex] . Эта прямая разбивает плоскость на три части: собственно прямую и две открытые полуплоскости, задаваемые неравенствами [latex] \left(y — r2 \right) \left( s1 — r1 \right) — \left( x — r1 \right) \left( s2 — r2 \right) < 0[/latex] и [latex] \left(y — r2 \right) \left( s1 — r1 \right) — \left( x — r1 \right) \left( s2 — r2 \right) > 0[/latex].
- Как известно, точка лежит внутри невырожденного треугольника, если и только если она лежит с каждой вершиной этого треугольника в одной полуплоскости относительно стороны, противоположной этой вершине.
- Из 1. заключаем, что точки с декартовыми координатами [latex] \left( x,y \right)[/latex] и [latex] \left( u,v \right)[/latex] лежат по одну сторону от прямой, проходящей через точки [latex] \left( r1,r2 \right)[/latex] и [latex] \left( s1,s2 \right)[/latex], если и только если числа [latex] \left(y — r2 \right) \left( s1 — r1 \right) — \left( x — r1 \right) \left( s2 — r2 \right)[/latex] и [latex] \left(v — r2 \right) \left( s1 — r1 \right) — \left( u- r1 \right) \left( s2 — r2 \right)[/latex] отличны от нуля и одного знака, т.е. если произведение этих чисел — строго положительное число.
- Проверяем условие из пункта 3. для вершины [latex] C [/latex] и стороны [latex] AB [/latex]. Если условие выполнено, переходим к пункту 5. В противном случае точка внутри треугольника не лежит.
- Проверяем условие из пункта 3. для вершины [latex] B [/latex] и стороны [latex] AC [/latex]. Если условие выполнено, переходим к пункту 5. В противном случае точка внутри треугольника не лежит.
- Проверяем условие из пункта 3. для вершины [latex] A [/latex] и стороны [latex] BC [/latex]. Если условие выполнено, точка лежит внутри треугольника. В противном случае точка внутри треугольника не лежит.
Можно рассуждать чуть проще. Через каждые две вершины проходит прямая уравнение которой легко построить. Если мы в это уравнение подставим координаты третьей вершины и потом координаты искомой точки, то уравнение превратится в неравенство. Если обе проверяемые точки лежат с одной стороны, то знаки обоих неравенств совпадут. Останется проверить для всех трёх прямых (на сторонах треугольника).
Опечатка в «типах» треугольников , а так вполне пристойно вышло.
Очепятка устранена.