如图所示,两个三角形重合存在很多种情况,上图举出其中4个例子,本文要讲的是已知两个三角形三个顶点坐标,求重叠部分最大三角形的顶点坐标;
虽然已知顶点坐标,位置关系已经确定,但是编程解决的是一类问题,所以各种情况还是要考虑到。
定义变量保存结果
double resultx[3];
double resulty[3];
两个三角形的坐标变量
double coordinate-X[3];
double coordinate-Y[3];
double coordinate-XX[3];
double coordinate-YY[3];
coordinate-X[0]=x1;//
coordinate-Y[0]=y1;
coordinate-X[1]=x2;
coordinate-Y[1]=y2;
coordinate-X[2]=x3;
coordinate-Y[2]=y3;
coordinate-XX[0]=PPx1;
coordinate-YY[0]=PPy1;
coordinate-XX[1]=PPx2;
coordinate-YY[1]=PPy2;
coordinate-XX[2]=PPx3;
coordinate-YY[2]=PPy3;
第一步做的是判断有没有三角形的一个顶角是否在另一个三角形内部,如果有那么这个顶角一定是内部最大三角形的一个顶点
std::vector<double> Nodeposy;
std::vector<double> Nodeposx;
//判断有没有一个三角形的顶点在另一个三角形的内部的情况(根据分析在三角形内部的顶点一定是重叠部分三角形的一个顶点)
//面积法判断
//S=(1/2)*|(x1y2+x2y3+x3y1-x1y3-x2y1-x3y2)| //S=1/2|x1(y3-y2)+x2(y1-y3)+x3(y2-y1)|
double curs=abs(x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2));//计算三角形的面积,用的是向量
double pps=abs(PPx1*(PPy2-PPy3)+PPx2*(PPy3-PPy1)+PPx3*(PPy1-PPy2));//计算三角形的面积,用的是向量法
double sall=0.0f;
//当前三角是有有顶点在匹配色域空间中
for (int i=0;i<3;i++)
{
for (int n=0;n<3;n++)
{
for(int m=n+1;m<3;m++)
{
sall+=abs(coordinate-XX[n]*(coordinate-YY[m]-coordinate-Y[i])+coordinate-X[i]*(coordinate-YY[n]-coordinate-YY[m])+coordinate-XX[m]*(coordinate-Y[i]-coordinate-YY[n]));
}
}
if(abs(sall-pps)<0.01f)//面积相等说明在内
{
Nodeposy.push_back(coordinate-Y[i]);
Nodeposx.push_back(coordinate-X[i]);
}
sall=0.0f;
}
//两个三角形重合
if (Nodeposy.size()==3)
{
goto LLL;
}//当前三角是否有顶点在另一个三角中
sall=0.0f;
for (int j=0;j<3;j++)
{
for (int n=0;n<3;n++)
{
for(int m=n+1;m<3;m++)
{
sall+=abs(coordinate-X[n]*(coordinate-Y[m]-coordinate-YY[j])+coordinate-XX[j]*(coordinate-Y[n]-coordinate-Y[m])+coordinate-X[m]*(coordinate-YY[j]-coordinate-Y[n]));
}
}
if(abs(sall-curs)<0.01f)//面积相等说明在内
{
Nodeposy.push_back(coordinate-YY[j]);
Nodeposx.push_back(coordinate-XX[j]);
}
sall=0.0f;
}
if (Nodeposy.size()>=3)//有三个点在内部的时候,直接认为是公共三角形(不在计算交点)
{
for(int i=0;i<Nodeposx.size();i++)//先清除重合的点
{
for(int j=0;j<Nodeposx.size();j++)
{
if (Nodeposx[i]==Nodeposx[j])
{
Nodeposx.erase(Nodeposx.begin()+j);
Nodeposy.erase(Nodeposy.begin()+j);
}
}
}
for(int m=0;m<3;m++)
{
resultx[i]=Nodeposx[i];
resulty[i]=Nodeposy[i];
}
return true;
}
第二步计算两个三角形所有的交点
for(int i=0;i<3;i++)//计算所有直线方程
{
if (i<2)
{
k[i]=(coordinate-Y[i+1]-coordinate-Y[i])/(coordinate-X[i+1]-coordinate-X[i]);
b[i]=coordinate-Y[i]-k[i]*coordinate-X[i];
pk[i]=(coordinate-YY[i+1]-coordinate-YY[i])/(coordinate-XX[i+1]-coordinate-XX[i]);
pb[i]=coordinate-YY[i]-k[i]*coordinate-XX[i];
}
else
{
k[i]=(coordinate-Y[i]-coordinate-Y[0])/(coordinate-X[i]-coordinate-X[0]);
b[i]=coordinate-Y[i]-k[i]*coordinate-X[i];
pk[i]=(coordinate-YY[i]-coordinate-YY[0])/(coordinate-XX[i]-coordinate-XX[0]);
pb[i]=coordinate-YY[i]-k[i]*coordinate-XX[i];
}
}
double curposy=0.0f;
double curposx=0.0f;
for(int i=0;i<3;i++)
{
for (int j=0;j<3;j++)
{
if (abs(k[i]-pk[j])>0.0f)//判断是否平行或重合
{
curposy=(b[i]-(k[i]*pb[j]/pk[j]))/(1.0f-(k[i]/pk[j]));
curposx=(pb[j]-b[i])/(k[i]-pk[j]);
//求线段坐标范围
int m,n;
if(i<2)m=i+1;
else m=0;
if(j<2)n=j+1;
else n=0;
double cux1min=coordinate-X[i]<coordinate-X[m]?coordinate-X[i]:coordinate-X[m]-0.5f;
double cux1max=coordinate-X[i]>coordinate-X[m]?coordinate-X[i]:coordinate-X[m]+0.5f;
double cuy1min=coordinate-Y[i]<coordinate-Y[m]?coordinate-Y[i]:coordinate-Y[m]-0.5f;
double cuy1max=coordinate-Y[i]>coordinate-Y[m]?coordinate-Y[i]:coordinate-Y[m]+0.5f;
double ppxmin=coordinate-XX[j]<coordinate-XX[n]?coordinate-XX[j]:coordinate-XX[n]-0.5f;
double ppxmax=coordinate-XX[j]>coordinate-XX[n]?coordinate-XX[j]:coordinate-XX[n]+0.5f;
double ppymin=coordinate-YY[j]<coordinate-YY[n]?coordinate-YY[j]:coordinate-YY[n]-0.5f;
double ppymax=coordinate-YY[j]>coordinate-YY[n]?coordinate-YY[j]:coordinate-YY[n]+0.5f;
//这里要取两根线最小的范围即为两根线的共有范围,所以小的里面取大的,大的里面取小的
double xmin=cux1min<ppxmin?ppxmin:cux1min;
double xmax=cux1max>ppxmax?ppxmax:cux1max;
double ymin=cuy1min<ppymin?ppymin:cuy1min;
double ymax=cuy1max>ppymax?ppymax:cuy1max;;
if(curposx>=xmin&&curposx<=xmax&&curposy>=ymin&&curposy<=ymax)
{
//将符合条件的交点记录
Nodeposx.push_back(curposx);
Nodeposy.push_back(curposy);
}
}
}
}
if (Nodeposx.size()<3)//计算到这仍然不到三个点说明计算错误返回false
{
return false;
}
第三步.找出面积最大的三角形
std::vector<double> area;
std::vector<CString> index;
double s;
CString str;
for(int i=0;i<Nodeposx.size();i++)
{
for (int j=i+1;j<Nodeposx.size();j++)
{
for (int m=j+1;m<Nodeposx.size();m++)
{
s=abs(Nodeposx[i]*(Nodeposy[j]-Nodeposy[m])+Nodeposx[m]*(Nodeposy[i]-Nodeposy[j])+Nodeposx[j]*(Nodeposy[m]-Nodeposy[i]));
area.push_back(s);
str.Format("%i%i%i",i,j,m);
index.push_back(str);
}
}
}
double ss=0;
int num=0;
for (int n=0;n<area.size();n++)
{
if (area[n]>ss)
{
ss=area[n];
num=n;
}
}
int idx=atof(index[num]);
int anglenum[3];
anglenum[0]=idx/100;
anglenum[1]=idx%100/10;
anglenum[2]=idx%10;
for(int m=0;m<3;m++)
{
resultx[i]=Nodeposx[anglenum[i]];
resulty[i]=Nodeposy[anglenum[i]];
}
index.clear();
area.clear();
Nodeposx.clear();
Nodeposy.clear();
return true;
至此最大重叠部分三角形的三个顶点就计算出来了