华科机卓实验 平面截三角形拟合的立体图形

本文介绍了如何使用三维空间的三角形拟合任意形状的物体,并通过输入平面来求解截取的截面图形。针对给定的三角形集合和截取平面,计算各边的交点,处理无交点、交点不在线段上以及平行不包含的情况。文章涉及点的坐标、三角形数量和交点坐标的相关计算。
摘要由CSDN通过智能技术生成

朋友给我的一个题目,让我写写看。
具体的题目可以见代码后附,这里简单描述一下。

就跟PS里可以用画多边形来抠曲线图形一样,三维的任意形状的物体也可以用很多个三维空间的三角形来拟合,只要拟合的单位足够多,最后的效果会不错。
用拟合的图形代替原图形,再用一个给定的平面去截,截到三角形的边上时会得到很多交点,全部连起来就可以得到截面图形。

给出一系列三角形,再输入一个平面,求该平面与每个三角形每条边的交点。如果无交点或者交点不在线段上,都算作没有。
至于重合的情况,暂时算作不计,但是后期要修改的话依然可以改。

输入格式
第一行:点的数量
第二行开始:点的 X Y Z坐标
在这里插入图片描述
点的坐标最后一行之后:三角形的数量
下一行开始:三角形三个顶点的编号,编号按照上面的顺序(从零开始计数)
在这里插入图片描述
输出格式
他没跟我讲,我就随便输出了。
根据线段和平面的关系,有四种输出。
相交->交点坐标
平行但不包含->Paraell
包含->Included
相交但交点不在线段上->Exceed

编辑器为UTF-8格式,如果用devcpp等打开乱码,请先用记事本打开后,存储为ANSI。

#include <stdio.h>
typedef struct _coor
{
	double x,y,z;
}Coor;//单个点坐标
typedef Coor Vector;//向量和点的存储形式是一样的,但是还是区分一下
typedef struct _triangle
{
	int pid1,pid2,pid3;
}Triangle;//由于单个点已经存入了,为了减少存储负担,这里只存储点的序号

Coor* cList;int coorCnt;
//点的数组,由于输入数据可能非常大,采用手动在堆里申请的策略防止爆栈
Triangle* tList;int triangleCnt;
//三角形的数组
double A,B,C,D;
//最后输入的平面的参数
Vector normalVec;
//平面的法向量
int isCommandOutput=1;//命令行输出开关
int isFileOutput=1;//文件输出开关

double innerProduct(Vector a,Vector b);
//计算两向量的内积
Vector calVector(Coor from,Coor to);
//返回从from指向to的向量
void TSintersect(Triangle t);
//Triangle and Surface Intersect
//处理单个三角形
int LSintersect(Coor p1,Coor p2,Coor *r);
//Line and Surface Intersect
//处理单条线段
int isBetween(double n1,double n2,double candi);
//检测数candi是否在n1和n2之间,配合isOnTheLine使用来检测交点是否在线段上
int isOnTheLine(Coor p1,Coor p2,Coor c);
//检测点c是否在线段p1p2上

int main(int argc, char const *argv[])
{
	//测试数据从当前目录的Res01.txt读入
	//结果将同时在命令行和文件output.txt输出,可以自行修改
	FILE *f=fopen("Res01.txt","r");int i;
	if(!f) {
		printf("File cannot open!Program will exit.\n");
		return 0;
	}

	//将点和三角形读入动态数组
	fscanf(f,"%d",&coorCnt);
	cList=(Coor*)malloc(sizeof(Coor)*coorCnt);
	for(i=0;i<coorCnt;++i)
		fscanf(f,"%lf%lf%lf",&cList[i].x,&cList[i].y,&cList[i].z);

	fscanf(f,"%d",&triangleCnt);
	tList=(Triangle*)malloc(sizeof(Triangle)*triangleCnt);
	for(i=0;i<coorCnt;++i)
		fscanf(f,"%d%d%d",&tList[i].pid1,&tList[i].pid2,&tList[i].pid3);
	fclose(f);

	//读入给定的平面
	printf("Key in the formula of a surface, that is, key in A,B,C,D of Ax+by+Cz+D=0\n");
	scanf("%lf%lf%lf%lf",&A,&B,&C,&D);
	normalVec.x=A;normalVec.y=B;normalVec.z=C;

	//处理每个三角形,策略在TSintersect内
	for(i=0;i<triangleCnt;++i)
		TSintersect(tList[i]);

	free(cList);
	free(tList);
	return 0;
}

double innerProduct(Vector a,Vector b)
//计算向量内积
{
	return a.x*b.x+a.y*b.y+a.z*b.z;
}

Vector calVector(Coor from,Coor to)
//输入两点,计算由from到to的向量
{
	Vector v;
	v.x=to.x-from.x;
	v.y=to.y-from.y;
	v.z=to.z-from.z;
	return v;
}

enum LS_RELATIONSHIP{
	INTERSECT,PARALLEL,INCLUDE,EXCEED
};//线段和平面的关系,依次为相交、平行、包含、交点不在线段上
//只有INTERSECT是有效的

void TSintersect(Triangle t)
//Triangle and Surface Intersect
//处理每个三角形和平面的关系
{
	static triangle_id;
	//给三角形编号
	int times=0;
	Coor p1,p2,r;
	FILE *f; 
	if(isFileOutput) f=fopen("output.txt","a+");

	if(isCommandOutput) printf("Triangle %d: ",triangle_id );
	if(isFileOutput) fprintf(f,"Triangle %d: ",triangle_id );
	while(times<3)
	{
		//三边轮换
		switch(times)
		{
			case 0:p1=cList[t.pid1],p2=cList[t.pid2];break;
			case 1:p1=cList[t.pid1],p2=cList[t.pid3];break;
			case 2:p1=cList[t.pid2],p2=cList[t.pid3];break;		}

		switch(LSintersect(p1,p2,&r))
		{
			case INTERSECT:
				if(isCommandOutput) printf("(%lf,%lf,%lf) ",r.x,r.y,r.z );
				if(isFileOutput) fprintf(f,"(%lf,%lf,%lf) ",r.x,r.y,r.z );
				break;
			case PARALLEL:
				if(isCommandOutput) printf("Parallel but not included ");
				if(isFileOutput) fprintf(f,"Parallel but not included " );
				break;
			case INCLUDE:
				if(isCommandOutput) printf("Included ");
				if(isFileOutput) fprintf(f, "Included ");
				break;
			case EXCEED:
				if(isCommandOutput) printf("Cross but exceed the line ");
				if(isFileOutput) fprintf(f, "Cross but exceed the line " );
				break;
		}
 		times++;
	}
	if(isCommandOutput) putchar('\n');
	if(isFileOutput) fputc('\n',f);
	triangle_id++;
	if(isFileOutput) fclose(f);
}

int LSintersect(Coor p1,Coor p2,Coor *r)
//Line and Surface Intersect
//计算由p1和p2确定的线段与平面的交点
//int返回状态代码,交点由r返回
{
	//方向向量与法向量垂直,直线平行平面,无交点
	Vector p1p2=calVector(p1,p2);
	double p1v=innerProduct(p1,normalVec)+D;//p1到平面的距离,省略掉了分母
	double p2v=innerProduct(p2,normalVec)+D;//p2到平面的距离,省略掉了分母
	if(p1v==p2v)//如果两点到平面的距离相等,那么为平行或者包含
	{
		if(p1v==0)//包含
			return INCLUDE;
		return PARALLEL;//平行,也没有交点
	}
	if(p2v==0)//如果p2在平面上,由于n要除以p2v,这里是要单独考虑的相交
	{
		*r=p2;
		return INTERSECT;
	}
	double n=p1v/p2v;
	double ratio=1+1/(n-1);
	r->x=ratio*p1p2.x;;
	r->y=ratio*p1p2.y;
	r->z=ratio*p1p2.z;
	//r此时为平面与直线的交点
	if(isOnTheLine(p1,p2,*r))//如果在线段上
		return INTERSECT;
	return EXCEED;//不在线段上也不算
}

int isOnTheLine(Coor p1,Coor p2,Coor c)
{
	if(isBetween(p1.x,p2.x,c.x) &&
		isBetween(p1.y,p2.y,c.y) &&
		isBetween(p1.z,p2.z,c.z))
		return 1;
	return 0;
}
int isBetween(double n1,double n2,double candi)
{
	if( (n1<=candi&&candi<=n2) || (n2<=candi&&candi<=n1))
		return 1;
	return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值