题意:三维空间有两个三角形,问两者是否有公共点。
题解:如果相交,三角形的某条边一定经过另一个三角形的内部,边上,或者顶点。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const double eps = 1e-8;
const double PI = acos(-1);
struct Point3 {
double x, y, z;
Point3(double x = 0, double y = 0, double z = 0):x(x), y(y), z(z) {}
};
typedef Point3 Vector3;
int dcmp(double x) {
if (fabs(x) < eps)
return 0;
return x < 0 ? -1 : 1;
}
Vector3 operator + (Vector3 A, Vector3 B) {
return Vector3(A.x + B.x, A.y + B.y, A.z + B.z);
}
Vector3 operator - (Vector3 A, Vector3 B) {
return Vector3(A.x - B.x, A.y - B.y, A.z - B.z);
}
Vector3 operator * (Vector3 A, double b) {
return Vector3(A.x * b, A.y * b, A.z * b);
}
Vector3 operator / (Vector3 A, double b) {
return Vector3(A.x / b, A.y / b, A.z / b);
}
double Dot (Vector3 A, Vector3 B) {
return A.x * B.x + A.y * B.y + A.z * B.z;
}
double Length(Vector3 A) {
return sqrt(Dot(A, A));
}
double Angle(Vector3 A, Vector3 B) {
return acos(Dot(A, B) / Length(A) / Length(B));
}
//点p到平面p0 - n的距离,n必须为单位法向量
double DistanceToPlane(const Point3& p, const Point3& p0, const Vector3& n) {
return fabs(Dot(p - p0, n));
}
//点p在平面上的投影i,n必须为单位法向量
Point3 GetPlaneProjection(const Point3& p, const Point3& p0, const Vector3& n) {
return p - n * Dot(p - p0, n);
}
//直线p1p2到平面p0-n的交点
Point3 LinePlaneIntersection(Point3 p1, Point3 p2, Point3 p0, Vector3 n) {
Vector3 v = p2 - p1;
double t = Dot(n, p0 - p1) / Dot(n, p2 - p1);//判断分母是否为0
return p1 + v * t; //如果是线段,判断t是不是在0和1之间
}
Vector3 Cross(Vector3 A, Vector3 B) {
return Vector3(A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x);
}
double Area2(Point3 A, Point3 B, Point3 C) {
return Length(Cross(B - A, C - A));
}
//点p是否在三角形P0P1P2中,假定p在三角形所在平面内
bool PointInTri(Point3 P, Point3 P0, Point3 P1, Point3 P2) {
double area1 = Area2(P, P0, P1);
double area2 = Area2(P, P1, P2);
double area3 = Area2(P, P2, P0);
return dcmp(area1 + area2 + area3 - Area2(P0, P1, P2)) == 0;
}
//判断线段和三角形是否相交
//三角形p0p1p2和线段ab
bool TriSegmentIntersection(Point3 P0, Point3 P1, Point3 P2, Point3 A, Point3 B, Point3& P) {
Vector3 n = Cross(P1 - P0, P2 - P0);
if (dcmp(Dot(n, B - A)) == 0)
return false; // 平行或共面
double t = Dot(n, P0 - A) / Dot(n, B - A);
if (dcmp(t) < 0 || dcmp(t - 1) > 0)
return false; //交点不在线段AB上
P = A + (B - A) * t;
return PointInTri(P, P0, P1, P2); //判断交点是否在三角形内
}
//点p到直线AB的距离,面积法
double DistanceToLine(Point3 P, Point3 A, Point3 B) {
Vector3 v1 = B - A, v2 = P - A;
return Length(Cross(v1, v2)) / Length(v1);
}
//点到线段AB的距离
double DistanceToSegment(Point3 P, Point3 A, Point3 B) {
Vector3 v1 = B - A, v2 = P - A, v3 = P - B;
if (dcmp(Dot(v1, v2)) < 0)
return Length(v2);
if (dcmp(Dot(v1, v3)) > 0)
return Length(v3);
return Length(Cross(v1, v2)) / Length(v1);
}
//四面体体积
double Volume6(Point3 A, Point3 B, Point3 C, Point3 D) {
return Dot(D - A, Cross(B - A, C - A));
}
bool TriTriIntersection(Point3* Tri1, Point3* Tri2) {
Point3 P;
for (int i = 0; i < 3; i++) {
if (TriSegmentIntersection(Tri1[0], Tri1[1], Tri1[2], Tri2[i], Tri2[(i + 1) % 3], P))
return true;
if (TriSegmentIntersection(Tri2[0], Tri2[1], Tri2[2], Tri1[i], Tri1[(i + 1) % 3], P))
return true;
}
return false;
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
Point3 Tri1[3], Tri2[3];
for (int i = 0; i < 3; i++)
scanf("%lf%lf%lf", &Tri1[i].x, &Tri1[i].y, &Tri1[i].z);
for (int i = 0; i < 3; i++)
scanf("%lf%lf%lf", &Tri2[i].x, &Tri2[i].y, &Tri2[i].z);
printf("%d\n", TriTriIntersection(Tri1, Tri2) ? 1 : 0);
}
return 0;
}