[GIS算法] TIN文件的组织方式 - C语言实现

版权声明:本文为博主原创文章,若有错误之处望大家批评指正!转载需附上原文链接,谢谢! https://blog.csdn.net/summer_dew/article/details/84955128

文章目录

理论

【TIN例子】
在这里插入图片描述

TIN基础:https://blog.csdn.net/summer_dew/article/details/84349500#TIN_13

【PLT】点、线、三角形组织方式

7
0 -1.000000 4.000000 100.000000
1 4.000000 5.000000 100.000000
2 1.000000 2.000000 100.000000
3 0.000000 0.000000 100.000000
4 2.000000 0.000000 100.000000
5 0.000000 3.000000 100.000000
6 2.000000 -1.000000 100.000000
13
0 0 1 0 -1
1 1 2 0 2
2 2 0 0 1
3 2 3 1 4
4 3 0 1 -1
5 2 4 2 4
6 4 1 2 3
7 4 5 3 6
8 5 1 3 -1
9 3 4 4 5
10 4 6 5 6
11 6 3 5 -1
12 5 6 6 -1
7
0 0 1 2
1 2 3 4
2 1 5 6
3 6 7 8
4 3 9 5
5 9 10 11
6 7 12 10

【PT】点、三角形组织方式

7
0 -1 4 100
1 4 5 100
2 1 2 100
3 0 0 100
4 2 0 100
5 0 3 100
6 2 -1 100
7
0 0 1 2
1 0 2 3
2 1 2 4
3 1 4 5
4 2 3 4
5 3 4 6
6 4 5 6

代码内容

  1. 从文件(点、三角形组织方式)中读取TINint ReadTIN_PTFile(char *filename, TIN_PT *tin)
  2. 从文件(点线三角形组织方式)中读取ITNint ReadTIN_PLTFile(char *filename, TIN_PLT *tin)
  3. 保存PLT至文件 int SaveTIN_PLT(TIN_PLT tin, char *filename)
  4. TIN_PT转TIN_PLTint LocateLineID(TIN_PLT tin, int A, int B)
  5. 创建线int CreateLine(TIN_PLT *pTin,int tri, int A, int B)
  6. PT组织方式转PLT组织方式int TIN_PTtoPLT(TIN_PT oldTin, TIN_PLT *pTin)
  7. 得到TIN的边界int GetTinOutLine_PLT(TIN_PLT tin)

【助理解】得到TIN边界时的过程
用一个循环的静态链表的方式来表示边界

在这里插入图片描述

代码

#include<stdio.h>
#include<stdlib.h>
// 使用动态数组来管理
// 链表方式:可参照https://blog.csdn.net/summer_dew/article/details/84726286

#define EXP 10e-6

// 点
typedef struct point{
	int ID;			//点的ID
	double x,y,z;	//点的x,y,z
}Point;

/* TIN - 点三角形组织方式 */
typedef struct triangle_PT{
	int ID;		//三角形的ID
	int A,B,C;	//三角形的三个顶点
}Triangle_PT;
typedef struct{
	Point *points;		//点集
	Triangle_PT *tris;	//边集
	int pointNum;		//点数
	int triNum;			//三角形个数
}TIN_PT; //点、三角形组织方式


/* 从文件(点、三角形组织方式)中读取TIN
【说明】文本文件格式
点个数
点ID x y z
[点ID x y z]
三角形个数
三角形ID A点的ID号 B点的ID号 C点的ID号
[三角形ID A点的ID号 B点的ID号 C点的ID号]
*/
int ReadTIN_PTFile(char *filename, TIN_PT *tin) {
	FILE *fp;
	int i;

	fp = fopen(filename, "r");
	if (!fp) exit(0);
	
	// 读取点集
	fscanf(fp, "%d", &tin->pointNum);
	tin->points = (Point *)malloc(sizeof(Point) * tin->pointNum);
	if (!tin->points) exit(0);
	for (i=0; i<tin->pointNum; i++) {
		fscanf(fp, "%d%lf%lf%lf", &tin->points[i].ID, &tin->points[i].x, &tin->points[i].y, &tin->points[i].z);
	}
	// 读取三角形
	fscanf(fp, "%d", &tin->triNum);
	tin->tris = (Triangle_PT *)malloc(sizeof(Triangle_PT) * tin->triNum);
	if (!tin->tris) exit(0);
	for (i=0; i<tin->triNum; i++) {
		fscanf(fp, "%d%d%d%d", &tin->tris[i].ID, &tin->tris[i].A, &tin->tris[i].B, &tin->tris[i].C);
	}

	fclose(fp);
	return 1;
}

/* TIN - 点线三角形组织方式 */
typedef struct line_PLT{
	int ID;		//线ID
	int A,B;	//线的顶点ID
	int T1,T2;	//两侧的三角形ID
}Line_PLT;
typedef struct triangle_PLT{
	int ID;			//三角形ID
	int e1,e2,e3;	//线集
}Triangle_PLT;
typedef struct{
	Point *points;		//点集
	Line_PLT *lines;	//边集
	Triangle_PLT *tris;	//三角形集
	int pointNum;
	int lineNum;
	int triNum;
}TIN_PLT; //点、边、三角形组织方式

/* 从文件(点线三角形组织方式)中读取ITN
【说明】文本文件格式
点个数
点ID x y z
[点ID x y z]
边个数
边ID 顶点A 顶点B 左边三角形ID 右边三角形ID
[边ID 顶点A 顶点B 左边三角形ID 右边三角形ID]
三角形个数
三角形ID 边1 边2 边3
[三角形ID 边1 边2 边3]
*/
int ReadTIN_PLTFile(char *filename, TIN_PLT *tin) {
	FILE *fp;
	int i;

	fp = fopen(filename, "r");
	if (!fp) exit(0);

	// 读取点集
	fscanf(fp, "%d", &tin->pointNum);
	tin->points = (Point *)malloc(sizeof(Point) * tin->pointNum);
	if (!tin->points) exit(0);
	for (i=0; i<tin->pointNum; i++) {
		fscanf(fp, "%d%lf%lf%lf", &tin->points[i].ID, &tin->points[i].x, &tin->points[i].y, &tin->points[i].z);
	}
	// 读取边集
	fscanf(fp, "%d", &tin->lineNum);
	tin->lines = (Line_PLT *)malloc(sizeof(Line_PLT) * tin->lineNum);
	if (!tin->lines) exit(0);
	for (i=0; i<tin->lineNum; i++) {
		fscanf(fp, "%d%d%d%d%d", &tin->lines[i].ID, &tin->lines[i].A, &tin->lines[i].B, &tin->lines[i].T1, &tin->lines[i].T2);
	}
	// 读取三角形集
	fscanf(fp, "%d", &tin->triNum);
	tin->tris = (Triangle_PLT *)malloc(sizeof(Triangle_PLT) * tin->triNum);
	if (!tin->tris) exit(0);
	for (i=0; i<tin->triNum; i++) {
		fscanf(fp, "%d%d%d%d", &tin->tris[i].ID, &tin->tris[i].e1, &tin->tris[i].e2, &tin->tris[i].e3);
	}

	fclose(fp);
	return 1;
}
int SaveTIN_PLT(TIN_PLT tin, char *filename) {
	FILE *fp;
	int i;
	fp = fopen(filename, "w+");
	
	// 存储点集
	fprintf(fp, "%d\n", tin.pointNum);
	for (i=0; i<tin.pointNum; i++) {
		fprintf(fp, "%d %lf %lf %lf\n", tin.points[i].ID, tin.points[i].x, tin.points[i].y, tin.points[i].z);
	}
	// 存储边集
	fprintf(fp, "%d\n", tin.lineNum);
	for (i=0; i<tin.lineNum; i++) {
		fprintf(fp, "%d %d %d %d %d\n", tin.lines[i].ID, tin.lines[i].A, tin.lines[i].B, tin.lines[i].T1, tin.lines[i].T2);
	}
	// 存储三角形集
	fprintf(fp, "%d\n", tin.triNum);
	for (i=0; i<tin.triNum; i++) {
		fprintf(fp, "%d %d %d %d\n", tin.tris[i].ID, tin.tris[i].e1, tin.tris[i].e2, tin.tris[i].e3);
	}

	fclose(fp);
	return 1;
}

/* TIN_PT转TIN_PLT */
int LocateLineID(TIN_PLT tin, int A, int B) { //定位线AB
	int i;
	for (i=0; i<tin.lineNum; i++) {
		if (tin.lines[i].A == A && tin.lines[i].B == B) { //找到了线AB
			return i;
		}
		if (tin.lines[i].A == B && tin.lines[i].B == A) { //找到了线BA
			return i;
		}
	}
	return -1; //当前没有存AB
}
int CreateLine(TIN_PLT *pTin,int tri, int A, int B) {
	//tri:AB所属三角形的ID
	//A.B顶点
	int eId;

	eId = LocateLineID(*pTin, A, B);
	if (eId == -1) { //没有存在该条边
		eId = pTin->lineNum;
		pTin->lines[eId].A = A;
		pTin->lines[eId].B = B;
		pTin->lines[eId].ID = pTin->lineNum;
		pTin->lines[eId].T1 = tri; //添加上AB属于三角形tri
		pTin->lines[eId].T2 = -1; //现在还没有
		pTin->lineNum++; //增加完了一条边
	} else { //存在该条边
		pTin->lines[eId].T2 = tri; //添加上AB属于三角形tri
	}
	return eId;
}
int TIN_PTtoPLT(TIN_PT oldTin, TIN_PLT *pTin) {
	int i;
	int ID;
	int A,B,C;

	// 复制点集表
	pTin->pointNum = oldTin.pointNum;
	pTin->points = (Point *)malloc(sizeof(Point) * pTin->pointNum);
	if (!pTin->points) exit(0);
	for (i=0; i<pTin->pointNum; i++) {
		pTin->points[i] = oldTin.points[i];
	}
	// 计算三角形表
	pTin->triNum = oldTin.triNum;
	pTin->tris = (Triangle_PLT *)malloc(sizeof(Triangle_PLT) * pTin->triNum);
	// 创建边表
	pTin->lineNum = 0;
	pTin->lines = (Line_PLT *)malloc(sizeof(Line_PLT) * pTin->triNum*3); //至少有 triNum*3 个边(我们创大一点,然后从头到尾存放,不影响上面的存储)
	for (i=0; i<pTin->triNum; i++) { // 处理第i个三角形
		// 添加第i个三角形的信息
		ID = oldTin.tris[i].ID;
		pTin->tris[i].ID = ID; //ID
		// 取出这个三角形的顶点
		A = oldTin.tris[i].A;
		B = oldTin.tris[i].B;
		C = oldTin.tris[i].C;
		// 三角形的边
		pTin->tris[i].e1 = CreateLine(pTin, ID, A, B);
		pTin->tris[i].e2 = CreateLine(pTin, ID, B, C);
		pTin->tris[i].e3 = CreateLine(pTin, ID, C, A);
	}
	return 1;
}
// 函数功能:得到TIN的边界
// 实际考察:由边构造出多边形
// 说明:前提是提供的边一定是个闭合的,本函数没有对边进行验证!
int GetTinOutLine_PLT(TIN_PLT tin) {
	// 多边形的边是一个循环的点集
	// 所以,可用一个循环的静态链表的方式来表示边界
	int i,j,flag,start;
	int pointNum;
	int *points; //下标表示结点的ID
	int A,B;

	pointNum = tin.pointNum;
	points = (int *)malloc(sizeof(int) * pointNum);
	if (!points) exit(0);
	for (i=0; i<pointNum; i++) points[i] = -1;
	// 遍历边
	printf("该TIN的边界的边有:\n");
	for (i=0; i<tin.lineNum; i++) {
		if (tin.lines[i].T2 == -1) { //是否为边界
			// 取出两点
			A = tin.lines[i].A;
			B = tin.lines[i].B;
			printf("边ID=%d:%d-%d\n", tin.lines[i].ID, A, B); //debug
			// 连接边AB(两种情况需要考虑:A->B,B->A)
			if (points[A] == -1) { // 判断是不是可以A->B
				// 找一下是不是已经有一个点j->B了?
				flag = 1; 
				for (j=0; j<pointNum; j++) {
					if (points[j] == B) { //已经存在j->B
						flag = 0;		//A->B已经不行了
						points[B] = A;	//那么只能是B->A
						break;
					}
				}
				if (flag == 1) { //A->B可以
					points[A] = B;	//A->B可以
				}
			} else { //A->B不可以,A已经有下一个点了
				points[B] = A; //B->A
			}
		}
	}

	// 遍历这个静态的循环链表
	printf("由TIN的边界线创建的边界为:");
	// 找到循环链表的第一个结点
	for (i=0; i<pointNum; i++) {
		if (points[i]!=-1) {
			start = i;
			break;
		}
	}
	// 从第一个结点开始遍历下去
	i = start;
	do {
		printf("%d->", i);
		i = points[i];
	} while (i!=start);
	printf("%d\n", start);
	return 1;
}

int main() {
	// 测试
	TIN_PT tin1;
	TIN_PLT tin2;

	ReadTIN_PTFile("2018-8 TINByPT.txt", &tin1); //从文件读入 点三角形表示 的文件
	TIN_PTtoPLT(tin1, &tin2); //转换成 点线三角形表示方法
	GetTinOutLine_PLT(tin2); //得到边界
	SaveTIN_PLT(tin2, "2018-8 TINByPLT.txt"); //存储PLT
	ReadTIN_PLTFile("2018-8 TINByPLT.txt", &tin2);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/summer_dew/article/details/84955128