stt/archived/dataStruct.h
2024-09-10 16:01:52 +08:00

476 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef _DATASTRUCT_H
#define _DATASTRUCT_H
#include "sysDefine.h"
//直角坐标系下的一个点
struct cpoint
{
double x,y,z;
cpoint() //初始化坐标值
{
x = y = z = MAX_DBL;
}
};
typedef vector<cpoint> cpointArray;
//直角坐标点的一些数学运算
cpoint operator -(cpoint a, cpoint b)
{
cpoint m;
m.x=a.x-b.x;
m.y=a.y-b.y;
m.z=a.z-b.z;
return m;
}
cpoint operator +(cpoint a, cpoint b) //矢量加法
{
cpoint m;
m.x=a.x+b.x;
m.y=a.y+b.y;
m.z=a.z+b.z;
return m;
}
cpoint operator *(double sign,cpoint b) //矢量乘法
{
cpoint m;
m.x=sign*b.x;
m.y=sign*b.y;
m.z=sign*b.z;
return m;
}
//重载逻辑等操作符作用于矢量,判断两个直角点是否相等
bool operator ==(cpoint a, cpoint b)
{
if(fabs(a.x-b.x)<ZERO&&fabs(a.y-b.y)<ZERO&&fabs(a.z-b.z)<ZERO)
{
return 1;
}
else return 0;
}
double dot(cpoint a, cpoint b) //矢量点乘
{
return a.x*b.x+a.y*b.y+a.z*b.z;
}
cpoint cross(cpoint a,cpoint b) //矢量叉乘
{
cpoint v;
v.x = a.y*b.z-a.z*b.y;
v.y = a.z*b.x-a.x*b.z;
v.z = a.x*b.y-a.y*b.x;
return v;
}
//返回两个直角坐标点的中点位置
cpoint middle_cpoint(cpoint a,cpoint b)
{
cpoint c;
c.x = 0.5*(a.x + b.x);
c.y = 0.5*(a.y + b.y);
c.z = 0.5*(a.z + b.z);
return c;
}
//返回两点之间的一个点 以第一个点为参考点 第三个参数为相对于原线段的比例
cpoint scale_cpoint(cpoint a,cpoint b,double scale)
{
cpoint c;
c.x = a.x + (b.x - a.x)*scale;
c.y = a.y + (b.y - a.y)*scale;
c.z = a.z + (b.z - a.z)*scale;
return c;
}
cpoint rescale_cpoint(cpoint a,double refr)
{
cpoint c;
double m = sqrt(a.x*a.x+a.y*a.y+a.z*a.z);
c.x = a.x*refr/m;
c.y = a.y*refr/m;
c.z = a.z*refr/m;
return c;
}
double length_cpoint(cpoint v) //矢量模
{
return sqrt(v.x*v.x+v.y*v.y+v.z*v.z);
}
double distance_cpoint(cpoint a, cpoint b)
{
cpoint m;
double d;
m.x=a.x-b.x;
m.y=a.y-b.y;
m.z=a.z-b.z;
d = sqrt(m.x*m.x + m.y*m.y + m.z*m.z);
return d;
}
//计算两个向量的夹角
double cpoint_angle(cpoint a,cpoint b)
{
return acos((a.x*b.x+a.y*b.y+a.z*b.z)/(sqrt(a.x*a.x+a.y*a.y+a.z*a.z)*sqrt(b.x*b.x+b.y*b.y+b.z*b.z)))*180.0/pi;
}
//求三角形中心坐标
cpoint Tri_center(cpoint vec1,cpoint vec2,cpoint vec3)
{
cpoint c;
c.x = (vec1.x+vec2.x+vec3.x)/3.0;
c.y = (vec1.y+vec2.y+vec3.y)/3.0;
c.z = (vec1.z+vec2.z+vec3.z)/3.0;
return c;
}
//球坐标系下的一个点
struct spoint
{
double lon,lat,rad;
spoint() //初始化坐标值
{
lon = lat = rad = MAX_DBL;
}
};
typedef vector<spoint> spointArray;
/*直角坐标与球坐标相互转换函数 注意这里使用的球坐标是地理坐标范围 即经度为-180~180 纬度为-90~90*/
cpoint s2c(spoint s)
{
cpoint c;
c.x = s.rad*sin((0.5 - s.lat/180.0)*pi)*cos((2.0 + s.lon/180.0)*pi);
c.y = s.rad*sin((0.5 - s.lat/180.0)*pi)*sin((2.0 + s.lon/180.0)*pi);
c.z = s.rad*cos((0.5 - s.lat/180.0)*pi);
return c;
}
spoint c2s(cpoint c)
{
spoint s;
s.rad = sqrt(pow(c.x,2)+pow(c.y,2)+pow(c.z,2));
if (fabs(s.rad)<ZERO) //点距离原点极近 将点置于原点
{
s.lat = s.lon = s.rad = 0.0;
}
else
{
s.lat = 90.0 - acos(c.z/s.rad)*180.0/pi;
s.lon = atan2(c.y,c.x)*180.0/pi;
}
return s;
}
//顶点
struct vertex
{
int id; //索引
cpoint posic; //直角坐标系位置
spoint posis; //球坐标系位置
vertex()
{
id = -1; //初始化顶点索引值为-1 这里不需要初始化坐标位置 因为已经由相应的初始化函数完成了初始化
}
void set(int i) //设置索引值
{
id = i;
}
void set(cpoint c) //从直角坐标位置初始化
{
posic.x = c.x; posic.y = c.y; posic.z = c.z;
posis = c2s(posic);
}
void set(spoint s) //从球坐标位置初始化
{
posis.lon = s.lon; posis.lat = s.lat; posis.rad = s.rad;
posic = s2c(posis);
}
void info() //显示顶点信息
{
cout << id << " " << setprecision(16) << posic.x << " " << posic.y << " " << posic.z << " " << posis.lon << " " << posis.lat << " " << posis.rad << endl;
}
};
typedef vector<vertex> vertexArray;
typedef map<int,vertex> idMap; //顶点索引值映射 用于通过索引值寻找相应顶点
typedef map<string,vertex> strMap; //顶点位置映射 用于通过顶点位置寻找相应顶点
typedef map<int,int> outIdMap; //输出msh文件时重新索引三角形顶点集
//计算一个顶点向量的中点
cpoint middle_vertex(vertexArray vert)
{
cpoint c;
c.x = 0; c.y = 0; c.z = 0;
if (!vert.empty())
{
for (int i = 0; i < vert.size(); i++)
{
c.x += vert.at(i).posic.x;
c.y += vert.at(i).posic.y;
c.z += vert.at(i).posic.z;
}
c.x /= vert.size();
c.y /= vert.size();
c.z /= vert.size();
}
return c;
}
/*旋转顶点的方位
旋转的方式为首先绕着x轴旋转 然后绕着z轴旋转
给出参考点的原位置olda与新位置newa以获取旋转参数 然后求取输入点oldb做相同旋转后的新坐标newb
*/
vertex rotate_vertex(vertex olda,vertex newa,vertex oldb)
{
vertex newb;
vertex temp_ref,temp_b;
double yz_angle = (newa.posis.lat - olda.posis.lat)*pi/180.0;
//首先绕olda.lon即x轴旋转oldb
temp_b.posic.x = oldb.posic.x;
temp_b.posic.y = oldb.posic.y*cos(-1.0*yz_angle)+oldb.posic.z*sin(-1.0*yz_angle);
temp_b.posic.z = oldb.posic.z*cos(-1.0*yz_angle)-oldb.posic.y*sin(-1.0*yz_angle);
temp_b.set(temp_b.posic);
//计算绕x轴旋转后olda的位置 这是后一步旋转需要的参考值
temp_ref.posic.x = olda.posic.x;
temp_ref.posic.y = olda.posic.y*cos(-1.0*yz_angle)+olda.posic.z*sin(-1.0*yz_angle);
temp_ref.posic.z = olda.posic.z*cos(-1.0*yz_angle)-olda.posic.y*sin(-1.0*yz_angle);
temp_ref.set(temp_ref.posic);
//注意绕z轴旋转的经度参考位置为olda绕x轴旋转后的经度值
double xy_angle = (newa.posis.lon - temp_ref.posis.lon)*pi/180.0;
//绕z轴旋转temp_b z值不变
newb.id = oldb.id;
newb.posic.x = temp_b.posic.x*cos(-1.0*xy_angle)+temp_b.posic.y*sin(-1.0*xy_angle);
newb.posic.y = temp_b.posic.y*cos(-1.0*xy_angle)-temp_b.posic.x*sin(-1.0*xy_angle);
newb.posic.z = temp_b.posic.z;
newb.set(newb.posic);
return newb;
}
//点 点包含索引和一个顶点
struct point
{
int id;
int maxDepth;
double minDeg;
int physic;
vertex vert;
point()
{
id = -1;
maxDepth = -1;
minDeg = -1.0;
}
void info()
{
cout << id << " " << maxDepth << " " << minDeg << endl;
vert.info();
}
};
typedef vector<point> pointArray;
//折线 折线包含索引和一个顶点向量 顶点从前向后连成折线
struct line
{
int id;
int maxDepth;
double minDeg;
int physic;
vertexArray vert;
line()
{
id = -1;
maxDepth = -1;
minDeg = -1.0;
}
void info()
{
cout << id << " " << maxDepth << " " << minDeg << endl;
for (int i = 0; i < vert.size(); i++)
{
vert.at(i).info();
}
}
void clear_vert()
{
if (!vert.empty()) vert.clear();
}
};
typedef vector<line> lineArray;
//多边形 多边形包含索引和一个顶点向量 顶点逆时针连成多边形 注意多边形第一个点和最后一个点应该一致
struct polygon
{
int id;
int maxDepth;
double minDeg;
int physic;
vertexArray vert;
polygon()
{
id = -1;
maxDepth = -1;
minDeg = -1.0;
}
void info()
{
cout << id << " " << maxDepth << " " << minDeg << endl;
for (int i = 0; i < vert.size(); i++)
{
vert.at(i).info();
}
}
void clear_vert()
{
if (!vert.empty()) vert.clear();
}
};
typedef vector<polygon> polygonArray;
//圆形
struct circle
{
int id;
int maxDepth;
double minDeg;
double radDeg;
int physic;
vertex cen;
};
typedef vector<circle> circleArray;
//三角形信息结构体,包含三角形的三个顶点索引,逆时针排序
struct triangle
{
int ids[3];//三角形顶点
int physic; //三角形的物理属性组
triangle() //初始化顶点索引
{
physic = 0; //默认的物理属性组为0
ids[0] = ids[1] = ids[2] = -1;
}
};
typedef vector<triangle> triangleArray;
//平面参数结构体
struct planePara
{
double A,B,C,D;
planePara()
{
A = B = C = D = MAX_DBL;
}
};
//矢量与平面的交点
cpoint lineOnPlane(cpoint c,cpoint normal,cpoint p)
{
cpoint m;
m.x = 0; m.y = 0; m.z = 0;
double t;
if (dot(normal,p) != 0) //平面与矢量平行
{
t = dot(normal,c)/dot(normal,p);
m.x += p.x*t;
m.y += p.y*t;
m.z += p.z*t;
}
return m;
}
//正二十面体结构体,包含正二十面体的十二个顶点和二十个面的顶点索引,三角面索引按逆时针排序
struct Icosa
{
vertex vert[12];
triangle tri[20];
};
//四叉树节点结构体,这是整个算法中最重要的结构体包含一个指向triangle的指针和指向四个子节点的指针
struct Qdtree_node
{
int id;//节点的编号
int outId;//节点在文件输出时候的id 这个id会在return_leaf函数中确定
int depth;//节点深度
bool outOK; //节点是否可以被输出
triangle* tri;//节点三角形顶点索引 逆时针
Qdtree_node* children[4];//四个子节点指针
Qdtree_node() //初始化变量值
{
id = -1;
depth = -1;
outOK = true;
children[0] = children[1] = children[2] = children[3] = NULL;
tri = new triangle;
}
void info()
{
cout << id << endl;
cout << depth << endl;
cout << outOK << endl;
cout << tri->ids[0] << " " << tri->ids[1] << " " << tri->ids[2] << endl;
}
};
//四叉树结构
struct Qdtree
{
Qdtree_node *root;//根节点
};
/*
// 在现行的代码中 我们不再使用平面投影算法 因此不再需要使用以下的数据类型与函数
struct point2d
{
double x,y;
point2d()
{
x = y = MAX_DBL;
}
};
//由三个顶点计算平面参数
planePara get_planePara(cpoint v1,cpoint v2,cpoint v3)
{
planePara pl;
pl.A = (v2.y - v1.y)*(v3.z - v1.z) - (v3.y - v1.y)*(v2.z - v1.z);
pl.B = (v2.z - v1.z)*(v3.x - v1.x) - (v3.z - v1.z)*(v2.x - v1.x);
pl.C = (v2.x - v1.x)*(v3.y - v1.y) - (v3.x - v1.x)*(v2.y - v1.y);
pl.D = -1.0*(pl.A*v1.x + pl.B*v1.y + pl.C*v1.z);
return pl;
}
//点在平面上的投影
vertex dotOnPlane(planePara pl,vertex v)
{
vertex m;
double t = (pl.A*v.posic.x + pl.B*v.posic.y + pl.C*v.posic.z + pl.D)/(pl.A*pl.A + pl.B*pl.B + pl.C*pl.C);
m.posic.x = v.posic.x - pl.A*t;
m.posic.y = v.posic.y - pl.B*t;
m.posic.z = v.posic.z - pl.C*t;
m.set(m.posic);
return m;
}
//以平面内一条直线为x轴 起点为原点 计算另一个点到新的坐标系内的坐标值
point2d newXY(vertex v1,vertex v2,vertex v3,vertex p)
{
point2d p2d;
vertex m,ap;
cpoint dir_map,dir_v123;
m.posic = v2.posic - v1.posic;
ap.posic = p.posic - v1.posic;
//因为cos函数在这种情况下自动可以区分正负情况 所以x值的计算比较简单
p2d.x = dot(ap.posic,m.posic)/length_cpoint(m.posic);
//下面我们来计算y值 相对比较麻烦 首先计算一下距离
p2d.y = sqrt(pow(length_cpoint(ap.posic),2) - p2d.x*p2d.x);
//计算一下三角形的外向法矢量 m与ap的法矢量
dir_v123 = cross(v2.posic-v1.posic,v3.posic-v1.posic);
dir_map = cross(v2.posic-v1.posic,ap.posic);
//如果两个向量同向则y值为正 否则为负
if (dot(dir_v123,dir_map) < 0) p2d.y *= -1.0;
return p2d;
}
*/
#endif