Задача.
Треугольник и точка. Лежит ли точка [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]. Если условие выполнено, точка лежит внутри треугольника. В противном случае точка внутри треугольника не лежит.
 
						
Можно рассуждать чуть проще. Через каждые две вершины проходит прямая уравнение которой легко построить. Если мы в это уравнение подставим координаты третьей вершины и потом координаты искомой точки, то уравнение превратится в неравенство. Если обе проверяемые точки лежат с одной стороны, то знаки обоих неравенств совпадут. Останется проверить для всех трёх прямых (на сторонах треугольника).
Опечатка в «типах» треугольников , а так вполне пристойно вышло.
Очепятка устранена.