版权声明:本文为博主原创文章,若有错误之处望大家批评指正!转载需附上原文链接,谢谢! 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
代码内容
- 从文件(点、三角形组织方式)中读取TIN
int ReadTIN_PTFile(char *filename, TIN_PT *tin)
- 从文件(点线三角形组织方式)中读取ITN
int ReadTIN_PLTFile(char *filename, TIN_PLT *tin)
- 保存PLT至文件
int SaveTIN_PLT(TIN_PLT tin, char *filename)
- TIN_PT转TIN_PLT
int LocateLineID(TIN_PLT tin, int A, int B)
- 创建线
int CreateLine(TIN_PLT *pTin,int tri, int A, int B)
- PT组织方式转PLT组织方式
int TIN_PTtoPLT(TIN_PT oldTin, TIN_PLT *pTin)
- 得到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;
}