题目链接:FZU-2273 Triangles
题意
给出两个三角形各顶点在直角坐标系上的坐标,问这两个三角形的位置关系是相离、相交还是包含?(共边或共点算相交)
思路
先判断是否相交(因为共边和共点算相交,先判断相交会方便一些),再判断是否包含,两种都不是则为相离。
判断三角形相交
两个三角形各拿出一条边,共有9种组合,判断每种组合的两条边是否相交,出现一对边相交则两个三角形相交,问题转换为如何判断线段相交。
考虑向量叉积,首先要知道一个定理,若$\overrightarrow {a}\times \overrightarrow {b}$的结果小于0,表示$\overrightarrow {b}$在$\overrightarrow {a}$的顺时针方向;若结果大于0,表示$\overrightarrow {b}$在$\overrightarrow {a}$的逆时针方向;若结果等于0,说明$\overrightarrow {a}$和$\overrightarrow {b}$平行。(顺逆时针是指两向量平移至起点相连,从某个方向旋转到另一个向量小于180度)
线段AB与线段CD相交的充要条件是直线AB与线段CD相交,并且直线CD与线段AB相交。判断直线AB与线段CD相交只需要判断C、D两点分别在直线AB的两边,即$\overrightarrow{AB}\times \overrightarrow{AC}$与$\overrightarrow{AB}\times \overrightarrow{AD}$异号,判断直线CD与线段AB相交同理。
判断三角形包含
$\Delta ABC$被$\Delta DEF$包含的充要条件是A、B、C三个点都在$\Delta DEF$内部。一个点$X$在$\Delta DEF$内部的充要条件是$S_{\Delta DEF}=S_{\Delta DEX}+S_{\Delta DFX}+S_{\Delta EFX}$。计算三角形面积可用向量叉积,$S_{\Delta ABC}=|\overrightarrow{AB}\times \overrightarrow{AC}|/2$。
代码实现
#include <cstdio> #include <cmath> const double eps = 1e-8; struct Point { double x, y; } P[2][4]; double xmult(Point a, Point b, Point c) { // 向量ab与向量ac的叉积 return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); } int main() { int T; scanf("%d", &T); while (T--) { for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { scanf("%lf %lf", &P[i][j].x, &P[i][j].y); } } P[0][3] = P[0][0], P[1][3] = P[1][0]; bool ints = false; for (int i = 0; i < 3 && !ints; i++) { for (int j = 0; j < 3 && !ints; j++) { // 第0个三角形的第i条边与第1个三角形的第j条边是否相交 if (xmult(P[0][i], P[0][i+1], P[1][j]) * xmult(P[0][i], P[0][i+1], P[1][j+1]) < eps && xmult(P[1][j], P[1][j+1], P[0][i]) * xmult(P[1][j], P[1][j+1], P[0][i+1]) < eps) { ints = true; } } } if (ints) { puts("intersect"); continue; } bool in = false; for (int i = 0; i < 2; i++) { double area = fabs(xmult(P[i][0], P[i][1], P[i][2])); for (int j = 0; j < 3; j++) { double area2 = 0; for (int k = 0; k < 3; k++) { area2 += fabs(xmult(P[i^1][j], P[i][k], P[i][k+1])); } // 三角形i^1的第j个点是否在三角形i里面 if (fabs(area - area2) < eps) in = true; else { in = false; break; } } if (in) break; } if (in) puts("contain"); else puts("disjoint"); } return 0; }