stt/archived/QdTree_Icosa.h

2196 lines
79 KiB
C
Raw Normal View History

2024-09-10 16:01:52 +08:00
#ifndef _QDTREE_ICOSA_H
#define _QDTREE_ICOSA_H
#include "dataStruct.h"
#include "progressBar_imp.h"
class QdTree_Icosa
{
public:
QdTree_Icosa(){
refradius = refRadius = defaultR;
strcpy(referSystem,"NULL");
strcpy(orientPara,"NULL");
strcpy(pointFile,"NULL");
strcpy(lineFile,"NULL");
strcpy(polyFile,"NULL");
strcpy(circleFile,"NULL");
strcpy(outlineFile,"NULL");
strcpy(holeFile,"NULL");
strcpy(mshFile,"NULL");
strcpy(sphFile,"NULL");
strcpy(locFile,"NULL");
strcpy(locOutFile,"NULL");
}
~QdTree_Icosa(){}
void runtine(char*);
int init_refer(char*);
int set_orient(char*);
void init_para(double,vertex); //初始化参数
void create_branch(int,int,int,int,int,int,Qdtree_node**); //创建分枝
void create_tree(int,int,int,Qdtree*);//创建树
void delete_tree(Qdtree_node**);//清空整颗树
void return_leaf(Qdtree_node**);//返回叶子
void cut_outline(Qdtree_node**);//切割模型范围 为了保证后续处理中树形结构的完整性 我们只添加node的属性值来控制是否输出改节点
void cut_holes(Qdtree_node**);
void add_vertex(int,Qdtree_node**); //按照规则添加个额外顶点
void close_surface(int,Qdtree_node**); //闭合模型表面
void locating_triangle(vertex,_1iArray&,Qdtree_node**); //判断包含着球坐标位置的最小三角形
//转到球坐标之后事情变得麻烦了一点点 策略 对于每一个三角平面建立一个新的坐标系 将待测试的点投影到新的坐标系然后判断 呵呵呵呵呵
//int inTriangleDot_old(Qdtree_node*);//判断插入点是否在节点三角形内 直角坐标系默认使用x y坐标 球坐标默认使用坐标投影
int inTriangleSpoint(vertex,Qdtree_node*); //判断一个单独点与节点三角形的关系
int inTriangleDot(Qdtree_node*);//在球面上判断点和三角形关系的一种方法 直接使用矢量运算确定包含关系 更直接更简单
//注意因为球面上的特殊关系 两个点之间的夹角不能大于等于180度 因为球面上总是沿着最短路径走 而且通常我们指的也是最短路径
int inTriangleLine(Qdtree_node*);//判断插入线是否穿过节点三角形 使用的是球面下的方法 直接矢量计算
int inTrianglePoly(Qdtree_node*);//判断多边形与三角形的关系
int inTriangleCircle(Qdtree_node*);//判断圆与三角形的关系
int outPolyOutline(Qdtree_node*);//判断多边形与三角形的关系 用于切割模型边界
int inPolyOutline(Qdtree_node*);//判断多边形与三角形的关系 用于切割模型边界 挖洞
int out_msh(char*,double,double);
int out_sph(char*,double,double);
int out_loc(char*);
int get_extrapoint(char*); //读取额外的点
int get_extraline(char*); //读取额外的线段
int get_extrapoly(char*); //读取额外的多边形
int get_extracircle(char*); //读取额外的圆
int get_outline(char*); //读取模型范围文件
int get_hole(char*); //读取模型范围文件
int get_loc(char*); //读入一组位置 判断包含着一组位置的最小三角形
//辅助函数
void init_icosa(double,vertex); //初始化一个二十面体实例 需要给定一个默认半径值 二十面体顶点的经纬坐标 在init_para函数中调用
void extract_vertex();//按return_*函数返回的三角形索引 提取顶点向量的子集 在outmsh函数中调用
double mean_edgeDegree(Qdtree_node*,double);//计算节点三角形的平均边长相对于半径的角度 会使用点的x y z坐标
private:
int tree_depth; //树深度
int max_depth; //最大深度
double refradius,refRadius;
vertexArray vArray; //顶点向量与映射
idMap mapId;
idMap::iterator ivd;
strMap mapStr;
strMap::iterator ivm;
outIdMap mapOutId;
outIdMap::iterator ioim;
Icosa ICOSA;
Qdtree* FOREST[20]; //四叉树集合,每一个二十面体的三角面都确定为一个树根
vertex orient; //二十面的顶点的朝向 由经纬度坐标给出 半径长度为defaultR 默认的二十面体顶点 第一个顶点 在地理北极点
_1iArray out_iArray; //输出顶点向量索引
triangleArray out_tArray; //输出三角形索引向量
pointArray extrapArray; //额外顶点向量
lineArray extralArray; //额外折线向量
polygonArray extrapolyArray; //额外的多边形
circleArray extracirArray; //额外的圆圈
//模型范围多边形 我们使用一个多边形来规定需要保留的模型范围
//如果outlineArray为空的话直接输出整个球面模型
//而如果模型范围存在的话则删除位于模型范围之外的三角形节点
//如果一个节点三角形的三个顶点均位于范围多边形之外 则删除之
polygonArray outlineArray; //模型范围多边形 位于该多边形之外的三角形单元将被删去 从深到浅执行
polygonArray holeArray; //挖洞多边形
//输入的球坐标位置
vertexArray sphLocations; //输入的球坐标位置
_2iArray locTriangles; //输入球坐标位置所在的最小三角形的列表 一个位置可能被多个三角形包含 即在三角形的边 或 顶点上
char referSystem[1024];
char orientPara[1024];
char pointFile[1024];
char lineFile[1024];
char polyFile[1024];
char circleFile[1024];
char outlineFile[1024];
char holeFile[1024];
char mshFile[1024];
char sphFile[1024];
char locFile[1024];
char locOutFile[1024];
};
void QdTree_Icosa::runtine(char* paras)
{
if (!strcmp(paras,"NULL"))
{
cout << "set reference ellipsoid for output (input NULL to use defaults 1e+5/1e+5). use 0/0 to disable the function" << endl << "==> ";
cin >> referSystem;
cout << "set basic quad-tree depth. this is the depth all quad-tree nodes can achieve" << endl << "==> ";
cin >> tree_depth;
cout << "set maximal quad-tree depth. this is the depth no quad-tree node can surpass" << endl << "==> ";
cin >> max_depth;
cout << "set oriention of the basic icosahedron (lon/lat,input NULL to use defaults which are 0/90)" << endl << "==> ";
cin >> orientPara;
cout << "outline polygons locaiton file (input NULL if no)" << endl << "==> ";
cin >> outlineFile;
cout << "hole polygons locaiton file (input NULL if no)" << endl << "==> ";
cin >> holeFile;
cout << "extral points locaiton file (input NULL if no)" << endl << "==> ";
cin >> pointFile;
cout << "extral lines locaiton file (input NULL if no)" << endl << "==> ";
cin >> lineFile;
cout << "extral polygons locaiton file (input NULL if no)" << endl << "==> ";
cin >> polyFile;
cout << "extral circles locaiton file (input NULL if no)" << endl << "==> ";
cin >> circleFile;
cout << "extral spherical coordinates file (input NULL if no)" << endl << "==> ";
cin >> locFile;
cout << "set output Gmsh (.msh) file name (input NULL if no)" << endl << "==> ";
cin >> mshFile;
cout << "set output xyz (lon lat radius) file name (input NULL if no)" << endl << "==> ";
cin >> sphFile;
cout << "set output locations (lon lat radius triangles) file name (input NULL if no)" << endl << "==> ";
cin >> locOutFile;
}
else
{
string temp_str;
ifstream infile;
if (open_infile(infile,paras)) return;
while (getline(infile,temp_str))
{
if (*(temp_str.begin()) == '#') continue;
else
{
if (1==sscanf(temp_str.c_str(),"basic-depth=%d",&tree_depth)) cout << "basic tree depth:\t" << tree_depth << endl;
else if (1==sscanf(temp_str.c_str(),"refer-system=%s",referSystem)) cout << "reference system:\t" << referSystem << endl;
else if (1==sscanf(temp_str.c_str(),"max-depth=%d",&max_depth)) cout << "maximal tree depth:\t" << max_depth << endl;
else if (1==sscanf(temp_str.c_str(),"orientation=%s",orientPara)) cout << "icosahedron orientation:\t" << orientPara << endl;
else if (1==sscanf(temp_str.c_str(),"extra-points=%s",pointFile)) cout << "extral points:\t" << pointFile << endl;
else if (1==sscanf(temp_str.c_str(),"extra-lines=%s",lineFile)) cout << "extral lines:\t" << lineFile << endl;
else if (1==sscanf(temp_str.c_str(),"extra-polys=%s",polyFile)) cout << "extral polys:\t" << polyFile << endl;
else if (1==sscanf(temp_str.c_str(),"extra-circles=%s",circleFile)) cout << "extral circles:\t" << circleFile << endl;
else if (1==sscanf(temp_str.c_str(),"outline-polys=%s",outlineFile)) cout << "outline polys:\t" << outlineFile << endl;
else if (1==sscanf(temp_str.c_str(),"hole-polys=%s",holeFile)) cout << "hole polys:\t" << holeFile << endl;
else if (1==sscanf(temp_str.c_str(),"sph-locations=%s",locFile)) cout << "spherical locations:\t" << locFile << endl;
else if (1==sscanf(temp_str.c_str(),"msh-save=%s",mshFile)) cout << "Gmsh save:\t" << mshFile << endl;
else if (1==sscanf(temp_str.c_str(),"sph-save=%s",sphFile)) cout << "Xyz save:\t" << sphFile << endl;
else if (1==sscanf(temp_str.c_str(),"loc-save=%s",locOutFile)) cout << "Xyz save:\t" << locOutFile << endl;
else
{
cout << "Unknown parameter:\t" << temp_str << endl;
return;
}
}
}
}
if(init_refer(referSystem)) return;
if(!get_outline(outlineFile))
cout << "reading " << outlineFile << " ... done" << endl;
if(!get_hole(holeFile))
cout << "reading " << holeFile << " ... done" << endl;
if(!get_extrapoint(pointFile))
cout << "reading " << pointFile << " ... done" << endl;
if(!get_extraline(lineFile))
cout << "reading " << lineFile << " ... done" << endl;
if (!get_extrapoly(polyFile))
cout << "reading " << polyFile << " ... done" << endl;
if (!get_extracircle(circleFile))
cout << "reading " << circleFile << " ... done" << endl;
if (!get_loc(locFile))
cout << "reading " << locFile << " ... done" << endl;
for (int i = 0; i < 20; i++)
{
FOREST[i] = new Qdtree;
FOREST[i]->root = new Qdtree_node;
FOREST[i]->root->tri = new triangle;
}
if (set_orient(orientPara)) return;
init_para(defaultR,orient);
ProgressBar *bar = new ProgressBar(20,"create model");
for (int i = 0; i < 20; i++)
{
bar->Progressed(i);
create_tree(ICOSA.tri[i].ids[0],ICOSA.tri[i].ids[1],ICOSA.tri[i].ids[2],FOREST[i]);
}
//如果没有额外的点 线 多边形 则跳过新增节点和封闭表面的操作
if (strcmp(pointFile,"NULL") || strcmp(lineFile,"NULL") || strcmp(polyFile,"NULL") || strcmp(circleFile,"NULL"))
{
ProgressBar *bar2 = new ProgressBar(max_depth-tree_depth+1,"refine model");
int curr_depth = tree_depth;
while(curr_depth <= max_depth)
{
bar2->Progressed(curr_depth-tree_depth);
for (int i = 0; i < 20; i++)
{
add_vertex(curr_depth,&(FOREST[i]->root));
}
for (int i = 0; i < 20; i++)
{
close_surface(curr_depth,&(FOREST[i]->root));
}
curr_depth++;
}
}
//执行模型范围的剪切 在极点处有bug
if (strcmp(outlineFile,"NULL")) //如果outlineFile存在 则执行剪裁流程
{
ProgressBar *bar3 = new ProgressBar(20,"cut model");
for (int i = 0; i < 20; i++)
{
bar3->Progressed(i);
cut_outline(&(FOREST[i]->root));
}
}
//执行挖洞 在极点处有bug
if (strcmp(holeFile,"NULL")) //如果outlineFile存在 则执行剪裁流程
{
ProgressBar *bar4 = new ProgressBar(20,"cut holes");
for (int i = 0; i < 20; i++)
{
bar4->Progressed(i);
cut_holes(&(FOREST[i]->root));
}
}
for (int i = 0; i < 20; i++)
{
return_leaf(&(FOREST[i]->root));
}
//在确定节点三角形的输出id之后 我们再来确定输入位置所在的最小三角形
if (strcmp(locFile,"NULL"))
{
//初始化locTriangles
locTriangles.resize(sphLocations.size());
ProgressBar *bar5 = new ProgressBar(sphLocations.size(),"locating");
for (int i = 0; i < sphLocations.size(); i++)
{
bar5->Progressed(i);
for (int j = 0; j < 20; j++)
{
locating_triangle(sphLocations[i],locTriangles[i],&(FOREST[j]->root));
}
}
}
if (!out_msh(mshFile,refradius,refRadius))
cout << "file saved: " << mshFile << endl;
if (!out_sph(sphFile,refradius,refRadius))
cout << "file saved: " << sphFile << endl;
if (!out_loc(locOutFile))
cout << "file saved: " << locOutFile << endl;
for (int i = 0; i < 20; i++)
{
delete_tree(&(FOREST[i]->root));
if (FOREST[i] != NULL) delete FOREST[i];
}
}
int QdTree_Icosa::init_refer(char* para)
{
if (!strcmp(para,"NULL")) return 0;
if (2 != sscanf(para,"%lf/%lf",&refradius,&refRadius))
{
cout << "reference system initialzation fail " << para << endl;
return 1;
}
return 0;
}
int QdTree_Icosa::set_orient(char* para)
{
if (!strcmp(para,"NULL"))
{
orient.posis.lon = 0;
orient.posis.lat = 90;
orient.posis.rad = defaultR;
orient.set(orient.posis);
return 0;
}
else
{
if (2!=sscanf(para,"%lf/%lf",&orient.posis.lon,&orient.posis.lat))
{
cout << "oriention initialzation fail " << para << endl;
return 1;
}
else return 0;
}
}
void QdTree_Icosa::init_para(double R,vertex ori)
{
stringstream sstemp;
string vert_id,mid_id;
//初始化二十面体实例
init_icosa(R,ori);
for (int i = 0; i < 12; i++)
{
vArray.push_back(ICOSA.vert[i]); //添加二十面体顶点到顶点向量
mapId[ICOSA.vert[i].id] = ICOSA.vert[i]; //保存顶点id映射
//插入以坐标位置的字符串为键值的映射
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<ICOSA.vert[i].posic.x;
sstemp>>vert_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<ICOSA.vert[i].posic.y;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<ICOSA.vert[i].posic.z;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
mapStr[vert_id] = ICOSA.vert[i];
}
}
void QdTree_Icosa::create_branch(int upper_id,int order_id,int depth,int t_ids0,int t_ids1,int t_ids2,Qdtree_node** node)
{
stringstream sstemp;
string vert_id,mid_id;
vertex localVert[6];
Qdtree_node* currNode;
*node = new Qdtree_node; //初始化一个新的四叉树节点
currNode = *node;
currNode->tri->ids[0] = t_ids0;//将上一节点的三角形顶点索引赋值给currNode内的triangle.ids,因此每一层节点实际上都保存了其本身的三角形顶点索引
currNode->tri->ids[1] = t_ids1;
currNode->tri->ids[2] = t_ids2;
currNode->id = upper_id*10+order_id;//写入四叉树节点编号
currNode->depth = depth;//记录四叉树深度
//额外生长条件 满足其一即可生长 在局部加密模型的过程中 不同物理组的赋值顺序前后顺序为圈 多边形 线 点
if ((depth < tree_depth //基本生长条件 所有节点都能达到的深度
|| inTriangleCircle(currNode)
|| inTrianglePoly(currNode)
|| inTriangleLine(currNode)
|| inTriangleDot(currNode))
&& depth < max_depth) //最大深度限制 所有节点不能超过的深度
{
ivd = mapId.find(t_ids0);//利用map_ID映射找到四叉树节点的前三个点这三个节点是上一层四叉树产生的必然存在
localVert[0] = ivd->second;
ivd = mapId.find(t_ids1);
localVert[1] = ivd->second;
ivd = mapId.find(t_ids2);
localVert[2] = ivd->second;
for(int i = 0; i < 3; i++)//循环产生三个新的顶点,位于节点三角形的三条边的中点,给每一个新产生的节点赋索引值与坐标,并保存到顶点链表中
{
localVert[i+3].posic = middle_cpoint(localVert[i%3].posic,localVert[(i+1)%3].posic);//计算新顶点坐标,这里需要注意,如果顶点已经存在则需要将顶点索引重置,不增加顶点计数
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<localVert[i+3].posic.x;
sstemp>>vert_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<localVert[i+3].posic.y;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<localVert[i+3].posic.z;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
ivm = mapStr.find(vert_id);
if(ivm != mapStr.end())//利用map_vert查到当前顶点是否存在,这里需要注意,如果顶点已经存在则只需要将顶点索引置为已存在顶点的索引,不增加顶点计数
{
localVert[i+3].id = ivm->second.id;
}
else//若为新的顶点则将其增加到两个映射和一个链表中
{
localVert[i+3].set(vArray.size());//新的顶点索引等于顶点集的数量
localVert[i+3].set(localVert[i+3].posic);
vArray.push_back(localVert[i+3]);//将新产生的顶点保存到顶点链表中
mapId[localVert[i+3].id] = localVert[i+3];//将新产生的顶点保存到顶点索引映射中
mapStr[vert_id] = localVert[i+3];//将新产生的顶点保存到顶点位置映射中
}
}
create_branch(currNode->id,1,depth+1,localVert[0].id,localVert[3].id,localVert[5].id,&(currNode->children[0]));
create_branch(currNode->id,2,depth+1,localVert[1].id,localVert[4].id,localVert[3].id,&(currNode->children[1]));
create_branch(currNode->id,3,depth+1,localVert[2].id,localVert[5].id,localVert[4].id,&(currNode->children[2]));
create_branch(currNode->id,4,depth+1,localVert[3].id,localVert[4].id,localVert[5].id,&(currNode->children[3]));
}
return;
}
void QdTree_Icosa::create_tree(int t_ids0,int t_ids1,int t_ids2,Qdtree* pTree)
{
if (tree_depth == 0)
{
pTree->root->id = 0;
pTree->root->depth = 0;
pTree->root->tri->ids[0] = t_ids0;//将上一节点的三角形顶点索引赋值给currNode内的triangle.ids,因此每一层节点实际上都保存了其本身的三角形顶点索引
pTree->root->tri->ids[1] = t_ids1;
pTree->root->tri->ids[2] = t_ids2;
for(int i=0;i<4;i++)
{
pTree->root->children[i] = NULL;
}
}
else
{
create_branch(0,0,0,t_ids0,t_ids1,t_ids2,&(pTree->root));//以根节点开始创建四叉树
}
}
void QdTree_Icosa::delete_tree(Qdtree_node** pTree)
{
Qdtree_node* currNode = *pTree;
if (currNode == NULL)
{
return;
}
else
{
for (int i = 0; i < 4; i++)
{
delete_tree(&(currNode->children[i]));
}
delete currNode->tri; //构造函数初始化 一定存在
delete currNode; //上面已经判断证否 一定存在
currNode = NULL;
return;
}
}
void QdTree_Icosa::return_leaf(Qdtree_node** pTree)
{
triangle temp_tri;
Qdtree_node* currNode = *pTree;
if (currNode->children[0]==NULL &&
currNode->children[1]==NULL &&
currNode->children[2]==NULL &&
currNode->children[3]==NULL &&
currNode->outOK==true)
{
for (int i = 0; i < 3; i++)
{
temp_tri.ids[i] = currNode->tri->ids[i];
temp_tri.physic = currNode->tri->physic;
}
currNode->outId = out_tArray.size(); //为outId赋值
out_tArray.push_back(temp_tri);
return;
}
else
{
for (int i = 0; i < 4; i++)
{
if (currNode->children[i]!=NULL)
return_leaf(&(currNode->children[i]));
}
return;
}
}
void QdTree_Icosa::cut_outline(Qdtree_node** pTree)
{
//切割范围多边形之外的四叉树节点 从深到浅执行
Qdtree_node* currNode = *pTree;
//当前节点是叶子节点 进行判断
if (currNode->children[0]==NULL &&
currNode->children[1]==NULL &&
currNode->children[2]==NULL &&
currNode->children[3]==NULL)
{
if (outPolyOutline(currNode)) //如果节点三角形在范围多边形之外 删除节点三角形 同时初始化指针
{
currNode->outOK = false;
return;
}
else return;
}
else
{
for (int i = 0; i < 4; i++)
{
//顺序访问当前节点的四个子节点 先处理子节点的情况 当然前提是节点存在
if (currNode->children[i] != NULL)
{
cut_outline(&(currNode->children[i]));
}
else continue;
}
}
return;
}
void QdTree_Icosa::cut_holes(Qdtree_node** pTree)
{
//切割范围多边形之外的四叉树节点 从深到浅执行
Qdtree_node* currNode = *pTree;
//当前节点是叶子节点 进行判断
if (currNode->children[0]==NULL &&
currNode->children[1]==NULL &&
currNode->children[2]==NULL &&
currNode->children[3]==NULL)
{
if (inPolyOutline(currNode)) //如果节点三角形在范围多边形之外 删除节点三角形 同时初始化指针
{
currNode->outOK = false;
return;
}
else return;
}
else
{
for (int i = 0; i < 4; i++)
{
//顺序访问当前节点的四个子节点 先处理子节点的情况 当然前提是节点存在
if (currNode->children[i] != NULL)
{
cut_holes(&(currNode->children[i]));
}
else continue;
}
}
return;
}
void QdTree_Icosa::add_vertex(int vist_depth,Qdtree_node** pTree)
{
cpoint middle_p;
cpoint temp_p,temp_p2;
vertex temp_v;
stringstream sstemp;
string vert_id,mid_id;
Qdtree_node* currNode = *pTree;
//访问深度为vist_depth的节点 节点深度不足 深入
if (currNode->depth < vist_depth)
{
//访问存在的子节点
for (int i = 0; i < 4; i++)
{
if (currNode->children[i] != NULL)
add_vertex(vist_depth,&(currNode->children[i]));
else continue;
}
}
/*来到了目标节点 检查在当前节点三角形每条边的1/4和3/4位置上是否有已知顶点
*/
else if (currNode->depth == vist_depth)
{
for (int i = 0; i < 3; i++)
{
middle_p = middle_cpoint(vArray.at(currNode->tri->ids[i%3]).posic,vArray.at(currNode->tri->ids[(i+1)%3]).posic);
//检查1/4 3/4位置
for (int n = 0; n < 2; n++)
{
temp_p = middle_cpoint(vArray.at(currNode->tri->ids[(i+n)%3]).posic,middle_p);
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.x;
sstemp>>vert_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.y;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.z;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
ivm = mapStr.find(vert_id);
if(ivm!=mapStr.end())//利用map_vert查到1/4 3/4位置点存在 检查对边中点是否存在
{
temp_p2 = middle_cpoint(vArray.at(currNode->tri->ids[i%3]).posic,vArray.at(currNode->tri->ids[(i+2)%3]).posic);
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p2.x;
sstemp>>vert_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p2.y;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p2.z;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
ivm = mapStr.find(vert_id);
if(ivm==mapStr.end())//利用map_vert查到对边中点不存在 添加一个新的顶点到顶点向量
{
temp_v.set(vArray.size());//新的顶点索引等于顶点集的数量
temp_v.set(temp_p2);
vArray.push_back(temp_v);//将新产生的顶点保存到顶点链表中
mapId[temp_v.id] = temp_v;//将新产生的顶点保存到顶点索引映射中
mapStr[vert_id] = temp_v;//将新产生的顶点保存到顶点位置映射中
}
temp_p2 = middle_cpoint(vArray.at(currNode->tri->ids[(i+1)%3]).posic,vArray.at(currNode->tri->ids[(i+2)%3]).posic);
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p2.x;
sstemp>>vert_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p2.y;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p2.z;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
ivm = mapStr.find(vert_id);
if(ivm==mapStr.end())//利用map_vert查到对边中点不存在 添加一个新的顶点到顶点向量
{
temp_v.set(vArray.size());//新的顶点索引等于顶点集的数量
temp_v.set(temp_p2);
vArray.push_back(temp_v);//将新产生的顶点保存到顶点链表中
mapId[temp_v.id] = temp_v;//将新产生的顶点保存到顶点索引映射中
mapStr[vert_id] = temp_v;//将新产生的顶点保存到顶点位置映射中
}
break;
}
}
}
}
}
void QdTree_Icosa::close_surface(int vist_depth,Qdtree_node** pTree)
{
int pointNum;
cpoint temp_p;
stringstream sstemp;
string vert_id,mid_id;
vertex localVert[6];
int newids[4][3] = {{0,3,5},{1,4,3},{2,5,4},{3,4,5}};
Qdtree_node* currNode = *pTree;
//访问深度为vist_depth的节点 节点深度不足 深入
if (currNode->depth < vist_depth)
{
//访问存在的子节点
for (int i = 0; i < 4; i++)
{
if (currNode->children[i] != NULL)
close_surface(vist_depth,&(currNode->children[i]));
else continue;
}
}
/*来到了目标节点 首先检查在当前节点三角形第四个子节点是否存在 若存在则则前三个也存在 不用做操作*/
else if (currNode->depth == vist_depth)
{
if (currNode->children[3] == NULL)
{
//循环确定有几个新顶点
pointNum = 0;
for (int j = 0; j < 3; j++)
{
temp_p = middle_cpoint(vArray.at(currNode->tri->ids[j%3]).posic,vArray.at(currNode->tri->ids[(j+1)%3]).posic);
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.x;
sstemp>>vert_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.y;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.z;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
ivm = mapStr.find(vert_id);
if(ivm!=mapStr.end())//利用map_vert查到1/4 3/4位置点存在 检查对边中点是否存在
{
pointNum++;
}
}
//按不同情况生成新的三角形
if (pointNum == 1)
{
for (int j = 0; j < 3; j++)
{
temp_p = middle_cpoint(vArray.at(currNode->tri->ids[j%3]).posic,vArray.at(currNode->tri->ids[(j+1)%3]).posic);
//计算点的位置ID
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.x;
sstemp>>vert_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.y;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.z;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
ivm = mapStr.find(vert_id);
if(ivm!=mapStr.end())//利用map_vert查到当前顶点是否存在
{
//增加第一个三角形
currNode->children[0] = new Qdtree_node;
currNode->children[0]->id = 10*(currNode->id) + 1;
currNode->children[0]->depth = currNode->depth + 1;
currNode->children[0]->tri->ids[0] = currNode->tri->ids[j%3];
currNode->children[0]->tri->ids[1] = ivm->second.id;
currNode->children[0]->tri->ids[2] = currNode->tri->ids[(j+2)%3];
//增加第二个三角形
currNode->children[1] = new Qdtree_node;
currNode->children[1]->id = 10*(currNode->id) + 2;
currNode->children[1]->depth = currNode->depth + 1;
currNode->children[1]->tri->ids[0] = currNode->tri->ids[(j+1)%3];
currNode->children[1]->tri->ids[1] = currNode->tri->ids[(j+2)%3];
currNode->children[1]->tri->ids[2] = ivm->second.id;
}
}
}
else if (pointNum == 2)
{
for (int i = 0; i < 3; i++)
{
temp_p = middle_cpoint(vArray.at(currNode->tri->ids[i%3]).posic,vArray.at(currNode->tri->ids[(i+1)%3]).posic);
//计算点的位置ID
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.x;
sstemp>>vert_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.y;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<temp_p.z;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
ivm = mapStr.find(vert_id);
if(ivm==mapStr.end())//利用map_vert查到当前顶点是否存在
{
for(int k = 0; k < 2; k++)//循环产生三个新的顶点,位于节点三角形的三条边的中点,给每一个新产生的节点赋索引值与坐标,并保存到顶点链表中
{
localVert[k].posic = middle_cpoint(vArray.at(currNode->tri->ids[(i+k)%3]).posic,vArray.at(currNode->tri->ids[(i+2)%3]).posic);//计算新顶点坐标,这里需要注意,如果顶点已经存在则需要将顶点索引重置,不增加顶点计数
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<localVert[k].posic.x;
sstemp>>vert_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<localVert[k].posic.y;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<localVert[k].posic.z;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
ivm = mapStr.find(vert_id);
localVert[k].id = ivm->second.id;
}
currNode->children[0] = new Qdtree_node;
currNode->children[0]->id = 10*(currNode->id) + 1;
currNode->children[0]->depth = currNode->depth + 1;
currNode->children[0]->tri->ids[0] = currNode->tri->ids[i%3];
currNode->children[0]->tri->ids[1] = currNode->tri->ids[(i+1)%3];
currNode->children[0]->tri->ids[2] = localVert[1].id;
currNode->children[1] = new Qdtree_node;
currNode->children[1]->id = 10*(currNode->id) + 2;
currNode->children[1]->depth = currNode->depth + 1;
currNode->children[1]->tri->ids[0] = currNode->tri->ids[i%3];
currNode->children[1]->tri->ids[1] = localVert[1].id;
currNode->children[1]->tri->ids[2] = localVert[0].id;
currNode->children[2] = new Qdtree_node;
currNode->children[2]->id = 10*(currNode->id) + 3;
currNode->children[2]->depth = currNode->depth + 1;
currNode->children[2]->tri->ids[0] = localVert[0].id;
currNode->children[2]->tri->ids[1] = localVert[1].id;
currNode->children[2]->tri->ids[2] = currNode->tri->ids[(i+2)%3];
}
}
}
else if (pointNum == 3)
{
for (int k = 0; k < 3; k++)
{
ivd = mapId.find(currNode->tri->ids[k]);//利用map_ID映射找到四叉树节点的前三个点这三个节点是上一层四叉树产生的必然存在
localVert[k] = ivd->second;
}
for(int k = 0; k < 3; k++)//循环产生三个新的顶点,位于节点三角形的三条边的中点,给每一个新产生的节点赋索引值与坐标,并保存到顶点链表中
{
localVert[k+3].posic = middle_cpoint(localVert[k%3].posic,localVert[(k+1)%3].posic);//计算新顶点坐标,这里需要注意,如果顶点已经存在则需要将顶点索引重置,不增加顶点计数
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<localVert[k+3].posic.x;
sstemp>>vert_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<localVert[k+3].posic.y;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
sstemp.str("");
sstemp.clear();
sstemp<<setprecision(16)<<localVert[k+3].posic.z;
sstemp>>mid_id;
vert_id = vert_id + " " + mid_id;
ivm = mapStr.find(vert_id);
localVert[k+3].id = ivm->second.id;
}
for (int i = 0; i < 4; i++)
{
currNode->children[i] = new Qdtree_node;
currNode->children[i]->id = 10*(currNode->id) + 1 + i;
currNode->children[i]->depth = currNode->depth + 1;
currNode->children[i]->tri->ids[0] = localVert[newids[i][0]].id;
currNode->children[i]->tri->ids[1] = localVert[newids[i][1]].id;
currNode->children[i]->tri->ids[2] = localVert[newids[i][2]].id;
}
}
}
}
}
void QdTree_Icosa::locating_triangle(vertex sp,_1iArray& belongs,Qdtree_node** pTree)
{
Qdtree_node* currNode = *pTree;
//首先判断输入点是否在当前节点三角形内 如果不在则返回
if (inTriangleSpoint(sp,currNode))
{
//如果节点三角形是叶子 则将其outId添加到belongs内 注意outOk应该也为真
if (currNode->children[0]==NULL &&
currNode->children[1]==NULL &&
currNode->children[2]==NULL &&
currNode->children[3]==NULL &&
currNode->outOK==true)
{
belongs.push_back(currNode->outId);
return;
}
else
{
for (int i = 0; i < 4; i++)
{
//顺序访问当前节点的四个子节点 先处理子节点的情况 当然前提是节点存在
if (currNode->children[i] != NULL)
{
locating_triangle(sp,belongs,&(currNode->children[i]));
}
else continue;
}
}
}
else return;
}
int QdTree_Icosa::inTriangleSpoint(vertex sp,Qdtree_node* node)
{
int count;
cpoint tri_nor;
cpoint cross_point;
cpoint edge_nor,edge_nor2;
triangle temp_tri;
for (int j = 0; j < 3; j++)
{
temp_tri.ids[j] = node->tri->ids[j];
}
//计算三角面元外法线矢量
tri_nor = cross(vArray.at(temp_tri.ids[1]).posic-vArray.at(temp_tri.ids[0]).posic , vArray.at(temp_tri.ids[2]).posic-vArray.at(temp_tri.ids[0]).posic);
if (dot(tri_nor,sp.posic) > 0)
{
//如果sp等于三角形顶点中的一个返回真
for (int j = 0; j < 3; j++)
{
if (cpoint_angle(vArray.at(temp_tri.ids[j]).posic,sp.posic)<ZERO)
return 1;
}
//我们需要判断点是否刚好落在三角形的一条边上
for (int j = 0; j < 3; j++)
{
edge_nor = cross(sp.posic,vArray.at(temp_tri.ids[j]).posic);
edge_nor2 = cross(vArray.at(temp_tri.ids[(j+1)%3]).posic,sp.posic);
if (cpoint_angle(edge_nor,edge_nor2)<ZERO)
return 1;
}
count = 0;
for (int j = 0; j < 3; j++)
{
cross_point = lineOnPlane(vArray.at(temp_tri.ids[j]).posic,tri_nor,sp.posic);
//依次判断前后两条边与待检测点的外法线是否同向 注意排除从球体背面穿射的情况 全为真则返回真
if (dot(tri_nor,cross(vArray.at(temp_tri.ids[(j+1)%3]).posic-vArray.at(temp_tri.ids[j]).posic , cross_point-vArray.at(temp_tri.ids[j]).posic)) >= 0)
count++;
}
if (count == 3) return 1;
}
return 0;
}
int QdTree_Icosa::inTriangleDot(Qdtree_node* node)
{
if (extrapArray.empty()) //没有插入的点位 直接返回否
{
return 0;
}
else
{
int tempDepth;
double tempDeg;
int count;
cpoint tri_nor;
cpoint cross_point;
triangle temp_tri;
for (int j = 0; j < 3; j++)
{
temp_tri.ids[j] = node->tri->ids[j];
}
tempDepth = node->depth;
tempDeg = 0;
for (int i = 0; i < 3; i++)
{
tempDeg += acos(dot(vArray.at(temp_tri.ids[i]).posic,vArray.at(temp_tri.ids[(i+1)%3]).posic)
/(length_cpoint(vArray.at(temp_tri.ids[i]).posic)*length_cpoint(vArray.at(temp_tri.ids[(i+1)%3]).posic)));
}
tempDeg = tempDeg*60/pi;
//计算三角面元外法线矢量
tri_nor = cross(vArray.at(temp_tri.ids[1]).posic-vArray.at(temp_tri.ids[0]).posic , vArray.at(temp_tri.ids[2]).posic-vArray.at(temp_tri.ids[0]).posic);
for (int i = 0; i < extrapArray.size(); i++)
{
if (dot(tri_nor,extrapArray.at(i).vert.posic) > 0)
{
count = 0;
for (int j = 0; j < 3; j++)
{
cross_point = lineOnPlane(vArray.at(temp_tri.ids[j]).posic,tri_nor,extrapArray.at(i).vert.posic);
//依次判断前后两条边与待检测点的外法线是否同向 注意排除从球体背面穿射的情况 全为真则返回真
if (dot(tri_nor,
cross(vArray.at(temp_tri.ids[(j+1)%3]).posic-vArray.at(temp_tri.ids[j%3]).posic , cross_point-vArray.at(temp_tri.ids[j%3]).posic)) > 0)
{
count++;
}
}
//全为真 当前节点深度小于允许的最大值 当前节点三角形角度大于允许的最小值 都为真则返回真
if (count == 3)
{
node->tri->physic = extrapArray.at(i).physic;
if (extrapArray.at(i).maxDepth >= tempDepth && tempDeg >= extrapArray.at(i).minDeg) return 1;
}
}
}
return 0;
}
}
int QdTree_Icosa::inTriangleLine(Qdtree_node* node)
{
if (extralArray.empty())
{
return 0;
}
else
{
int tempDepth;
double tempDeg;
int count;
cpoint tri_nor;
cpoint lineface_nor, edgeface_nor;
cpoint intersect[2];
cpoint angle_mid;
cpoint edge_mid;
cpoint cross_point;
triangle temp_tri;
for (int i = 0; i < 3; i++)
{
temp_tri.ids[i] = node->tri->ids[i];
}
tempDepth = node->depth;
tempDeg = 0;
for (int i = 0; i < 3; i++)
{
tempDeg += acos(dot(vArray.at(temp_tri.ids[i]).posic,vArray.at(temp_tri.ids[(i+1)%3]).posic)
/(length_cpoint(vArray.at(temp_tri.ids[i]).posic)*length_cpoint(vArray.at(temp_tri.ids[(i+1)%3]).posic)));
}
tempDeg = tempDeg*60/pi;
//计算三角面元外法线矢量
tri_nor = cross(vArray.at(temp_tri.ids[1]).posic-vArray.at(temp_tri.ids[0]).posic , vArray.at(temp_tri.ids[2]).posic-vArray.at(temp_tri.ids[0]).posic);
//遍历所有线段
//判断线段端点是否在三角形内 如果是 返回真
for (int i = 0; i < extralArray.size(); i++)
{
for (int j = 0; j < extralArray.at(i).vert.size(); j++)
{
//判断线段端点是否在三角形内 如果是 返回真
if (dot(tri_nor,extralArray.at(i).vert.at(j).posic) > 0)
{
count = 0;
for (int k = 0; k < 3; k++)
{
cross_point = lineOnPlane(vArray.at(temp_tri.ids[k%3]).posic,tri_nor,extralArray.at(i).vert.at(j).posic);
//依次判断前后两条边与待检测点的外法线是否同向 注意排除从球体背面穿射的情况 全为真则返回真
if (dot(tri_nor,
cross(vArray.at(temp_tri.ids[(k+1)%3]).posic-vArray.at(temp_tri.ids[k%3]).posic , cross_point-vArray.at(temp_tri.ids[k%3]).posic)) > 0)
{
count++;
}
}
//全部在左侧 返回真
if (count == 3)
{
node->tri->physic = extralArray.at(i).physic;
if (extralArray.at(i).maxDepth >= tempDepth && tempDeg >= extralArray.at(i).minDeg) return 1;
}
}
}
}
//无端点在三角形内 判断球面大圆弧是否与三角形相交 三角形内任意一条边与大圆弧相交则两者相交
//先计算线段球心扇面的法线矢量 因为点序不确定所以具体方向不确定 不过没关系 哈哈
for (int i = 0; i < extralArray.size(); i++)
{
for (int j = 0; j < extralArray.at(i).vert.size()-1; j++)
{
lineface_nor = cross(extralArray.at(i).vert.at(j).posic,extralArray.at(i).vert.at(j+1).posic);
angle_mid = middle_cpoint(extralArray.at(i).vert.at(j).posic,extralArray.at(i).vert.at(j+1).posic);
for (int n = 0; n < 3; n++)
{
edgeface_nor = cross(vArray.at(temp_tri.ids[n%3]).posic,vArray.at(temp_tri.ids[(n+1)%3]).posic);
edge_mid = middle_cpoint(vArray.at(temp_tri.ids[n%3]).posic,vArray.at(temp_tri.ids[(n+1)%3]).posic);
//排除两个扇面在同一个平面的情况
if (fabs(dot(lineface_nor,edgeface_nor))/(length_cpoint(lineface_nor)*length_cpoint(edgeface_nor)) != 1.0)
{
//两个扇面可能的交点矢量垂直于两个扇面的外法线矢量 正反两个矢量
intersect[0] = cross(lineface_nor,edgeface_nor);
intersect[1] = cross(edgeface_nor,lineface_nor);
for (int k = 0; k < 2; k++)
{
//交点矢量在两个线段端点矢量之间 注意端点先后顺序决定了大圆弧在球面上的范围 注意这里同样有从背面穿透的可能 因为我们不确定intersect中哪一个是我们想要的
//注意计算叉乘的时候 我们总是会走一个角度小于180的方向
//排除与angle_mid相反的半球上所有的三角形
if (dot(angle_mid,tri_nor) > 0
&& dot(cross(intersect[k],vArray.at(temp_tri.ids[n%3]).posic),cross(intersect[k],vArray.at(temp_tri.ids[(n+1)%3]).posic)) < 0
&& dot(cross(intersect[k],extralArray.at(i).vert.at(j).posic),cross(intersect[k],extralArray.at(i).vert.at(j+1).posic)) < 0
&& dot(intersect[k],angle_mid) > 0
&& dot(intersect[k],edge_mid) > 0)
{
node->tri->physic = extralArray.at(i).physic;
if (extralArray.at(i).maxDepth >= tempDepth && tempDeg >= extralArray.at(i).minDeg) return 1;
}
}
}
}
}
}
return 0;
}
}
int QdTree_Icosa::inTrianglePoly(Qdtree_node* node)
{
if (extrapolyArray.empty())
{
return 0;
}
else
{
int tempDepth;
double tempDeg;
int count;
int pnum;
cpoint tri_nor;
cpoint lineface_nor, edgeface_nor;
cpoint intersect[2];
cpoint angle_mid;
cpoint polygon_mid;
cpoint cross_point;
triangle temp_tri;
for (int j = 0; j < 3; j++)
{
temp_tri.ids[j] = node->tri->ids[j];
}
tempDepth = node->depth;
tempDeg = 0;
for (int i = 0; i < 3; i++)
{
tempDeg += acos(dot(vArray.at(temp_tri.ids[i]).posic,vArray.at(temp_tri.ids[(i+1)%3]).posic)
/(length_cpoint(vArray.at(temp_tri.ids[i]).posic)*length_cpoint(vArray.at(temp_tri.ids[(i+1)%3]).posic)));
}
tempDeg = tempDeg*60/pi;
//计算三角面元外法线矢量
tri_nor = cross(vArray.at(temp_tri.ids[1]).posic-vArray.at(temp_tri.ids[0]).posic , vArray.at(temp_tri.ids[2]).posic-vArray.at(temp_tri.ids[0]).posic);
//首先判断多边形的顶点是否在当前节点三角形内 或者多边形的边是否与当前节点三角形相交 这些条件可以判断多边形边上的三角形
for (int i = 0; i < extrapolyArray.size(); i++)
{
pnum = extrapolyArray.at(i).vert.size();
for (int j = 0; j < extrapolyArray.at(i).vert.size(); j++)
{
if (dot(tri_nor,extrapolyArray.at(i).vert.at(j).posic) > 0)
{
//多边形节点在当前节点三角形内
count = 0;
for (int k = 0; k < 3; k++)
{
cross_point = lineOnPlane(vArray.at(temp_tri.ids[k%3]).posic,tri_nor,extrapolyArray.at(i).vert.at(j).posic);
//依次判断前后两条边与待检测点的外法线是否同向 注意排除从球体背面穿射的情况 全为真则返回真
if (dot(tri_nor,
cross(vArray.at(temp_tri.ids[(k+1)%3]).posic-vArray.at(temp_tri.ids[k%3]).posic , cross_point-vArray.at(temp_tri.ids[k%3]).posic)) > 0)
{
count++;
}
}
//全部在左侧 返回真
if (count == 3)
{
node->tri->physic = extrapolyArray.at(i).physic;
if (extrapolyArray.at(i).maxDepth >= tempDepth && tempDeg >= extrapolyArray.at(i).minDeg) return 1;
}
}
//多边形边与当前节点三角形相交
lineface_nor = cross(extrapolyArray.at(i).vert.at(j%pnum).posic,extrapolyArray.at(i).vert.at((j+1)%pnum).posic);
angle_mid = middle_cpoint(extrapolyArray.at(i).vert.at(j%pnum).posic,extrapolyArray.at(i).vert.at((j+1)%pnum).posic);
for (int n = 0; n < 3; n++)
{
edgeface_nor = cross(vArray.at(temp_tri.ids[n%3]).posic,vArray.at(temp_tri.ids[(n+1)%3]).posic);
//排除两个扇面在同一个平面的情况
if (fabs(dot(lineface_nor,edgeface_nor))/(length_cpoint(lineface_nor)*length_cpoint(edgeface_nor)) != 1.0)
{
//两个扇面可能的交点矢量垂直于两个扇面的外法线矢量 正反两个矢量
intersect[0] = cross(lineface_nor,edgeface_nor);
intersect[1] = cross(edgeface_nor,lineface_nor);
for (int k = 0; k < 2; k++)
{
//交点矢量在两个线段端点矢量之间 注意端点先后顺序决定了大圆弧在球面上的范围 注意这里同样有从背面穿透的可能 因为我们不确定intersect中哪一个是我们想要的
//注意计算叉乘的时候 我们总是会走一个角度小于180的方向
//排除与angle_mid相反的半球上所有的三角形
if (dot(cross(intersect[k],vArray.at(temp_tri.ids[n%3]).posic),cross(intersect[k],vArray.at(temp_tri.ids[(n+1)%3]).posic)) < 0
&& dot(cross(intersect[k],extrapolyArray.at(i).vert.at(j%pnum).posic),cross(intersect[k],extrapolyArray.at(i).vert.at((j+1)%pnum).posic)) < 0
&& dot(angle_mid,tri_nor) > 0)
{
node->tri->physic = extrapolyArray.at(i).physic;
if (extrapolyArray.at(i).maxDepth >= tempDepth && tempDeg >= extrapolyArray.at(i).minDeg) return 1;
}
}
}
}
}
}
//多边形的顶点和边与当前节点三角形不相交或者包含 判断三角形是否在多边形内
for (int i = 0; i < extrapolyArray.size(); i++)
{
pnum = extrapolyArray.at(i).vert.size();
polygon_mid = middle_vertex(extrapolyArray.at(i).vert);
//依次判断节点三角形的三条边与多边形边的交点个数
for (int k = 0; k < 3; k++)
{
count = 0;
//计算三角形边与球心的平面的法线矢量 只要任意一条边在多边形内 则三角形在多边形内
edgeface_nor = cross(vArray.at(temp_tri.ids[(k)%3]).posic,vArray.at(temp_tri.ids[(k+1)%3]).posic);
for (int j = 0; j < extrapolyArray.at(i).vert.size(); j++)
{
//多边形边与当前节点三角形相交
lineface_nor = cross(extrapolyArray.at(i).vert.at(j%pnum).posic,extrapolyArray.at(i).vert.at((j+1)%pnum).posic);
angle_mid = middle_cpoint(extrapolyArray.at(i).vert.at(j%pnum).posic,extrapolyArray.at(i).vert.at((j+1)%pnum).posic);
//排除两个扇面在同一个平面的情况
if (fabs(dot(lineface_nor,edgeface_nor))/(length_cpoint(lineface_nor)*length_cpoint(edgeface_nor)) != 1.0)
{
//两个扇面可能的交点矢量垂直于两个扇面的外法线矢量 正反两个矢量
intersect[0] = cross(lineface_nor,edgeface_nor);
intersect[1] = cross(edgeface_nor,lineface_nor);
for (int n = 0; n < 2; n++)
{
/*注意 这里我们只判断交点是否在线段之间 或者一个点上 这里选择第一个点也可以选择第二点 但只能包含一个 不判断是不是在边之间
180*/
//交点矢量在两个线段端点矢量之间 注意端点先后顺序决定了大圆弧在球面上的范围 注意这里同样有从背面穿透的可能 因为我们不确定intersect中哪一个是我们想要的
//注意计算叉乘的时候 我们总是会走一个角度小于180的方向
//排除与angle_mid相反的半球上所有的三角形
if (dot(polygon_mid,tri_nor) > 0 //排除位于球背面的三角形
&& (dot(cross(intersect[k],extrapolyArray.at(i).vert.at(j%pnum).posic),cross(intersect[k],extrapolyArray.at(i).vert.at((j+1)%pnum).posic)) < 0
|| extrapolyArray.at(i).vert.at(j).posic == intersect[n]) //排除与多边形的边不相交的三角形边的延长线 这里包含了一个等于条件 即交点刚好在多边形的顶点上
&& dot(angle_mid,intersect[n]) > 0 //排除位于球背面的多边形边与三角形边延长线的交点
&& dot(edgeface_nor,cross(vArray.at(temp_tri.ids[k%3]).posic,intersect[n])) > 0) //只取三角形边其中一则的延长线
{
count++;
}
}
}
}
//交点个数为奇数 边在多边形内
if (pow(-1,count) < 0)
{
node->tri->physic = extrapolyArray.at(i).physic;
if (extrapolyArray.at(i).maxDepth >= tempDepth && tempDeg >= extrapolyArray.at(i).minDeg) return 1;
}
}
}
//全不为真 返回假
return 0;
}
}
int QdTree_Icosa::inTriangleCircle(Qdtree_node* node)
{
if (extracirArray.empty()) //没有插入的圆圈 直接返回否
{
return 0;
}
else
{
int tempDepth;
double tempDeg;
double cenDeg;
triangle temp_tri;
for (int j = 0; j < 3; j++)
{
temp_tri.ids[j] = node->tri->ids[j];
}
tempDepth = node->depth;
tempDeg = 0;
for (int i = 0; i < 3; i++)
{
tempDeg += acos(dot(vArray.at(temp_tri.ids[i]).posic,vArray.at(temp_tri.ids[(i+1)%3]).posic)
/(length_cpoint(vArray.at(temp_tri.ids[i]).posic)*length_cpoint(vArray.at(temp_tri.ids[(i+1)%3]).posic)));
}
tempDeg = tempDeg*60/pi;
//计算节点三角形顶点与圆圈中心点的球心夹角
for (int i = 0; i < extracirArray.size(); i++)
{
for (int j = 0; j < 3; j++)
{
cenDeg = acos(dot(extracirArray.at(i).cen.posic,vArray.at(temp_tri.ids[j]).posic)
/(length_cpoint(extracirArray.at(i).cen.posic)*length_cpoint(vArray.at(temp_tri.ids[j]).posic)))*180/pi;
if (cenDeg <= extracirArray.at(i).radDeg)
{
node->tri->physic = extracirArray.at(i).physic;
if (extracirArray.at(i).maxDepth >= tempDepth && tempDeg >= extracirArray.at(i).minDeg) return 1;
}
}
}
return 0;
}
}
int QdTree_Icosa::outPolyOutline(Qdtree_node* node)
{
if (outlineArray.empty()) //没有范围多边形 直接返回否
{
return 0;
}
else
{
int count;
int pnum;
cpoint tri_nor;
cpoint lineface_nor, edgeface_nor;
cpoint intersect[2];
cpoint angle_mid;
cpoint polygon_mid;
cpoint cross_point;
triangle temp_tri;
for (int j = 0; j < 3; j++)
{
temp_tri.ids[j] = node->tri->ids[j];
}
//计算三角面元外法线矢量
tri_nor = cross(vArray.at(temp_tri.ids[1]).posic-vArray.at(temp_tri.ids[0]).posic , vArray.at(temp_tri.ids[2]).posic-vArray.at(temp_tri.ids[0]).posic);
//首先判断多边形的顶点是否在当前节点三角形内 或者多边形的边是否与当前节点三角形相交 这些条件可以判断多边形边上的三角形
for (int i = 0; i < outlineArray.size(); i++)
{
pnum = outlineArray.at(i).vert.size();
for (int j = 0; j < outlineArray.at(i).vert.size(); j++)
{
if (dot(tri_nor,outlineArray.at(i).vert.at(j).posic) > 0) //排除球形背面的点
{
//多边形节点在当前节点三角形内
count = 0;
for (int k = 0; k < 3; k++)
{
cross_point = lineOnPlane(vArray.at(temp_tri.ids[k%3]).posic,tri_nor,outlineArray.at(i).vert.at(j).posic);
//依次判断前后两条边与待检测点的外法线是否同向 注意排除从球体背面穿射的情况 全为真则返回真
if (dot(tri_nor,
cross(vArray.at(temp_tri.ids[(k+1)%3]).posic-vArray.at(temp_tri.ids[k%3]).posic , cross_point-vArray.at(temp_tri.ids[k%3]).posic)) > 0)
{
count++;
}
}
//全部在左侧 多边形顶点至少有一个在节点三角形内 即节点三角形至少有一个顶点在多边形内 返回假
if (count == 3) return 0;
}
//多边形边与当前节点三角形相交
lineface_nor = cross(outlineArray.at(i).vert.at(j%pnum).posic,outlineArray.at(i).vert.at((j+1)%pnum).posic);
angle_mid = middle_cpoint(outlineArray.at(i).vert.at(j%pnum).posic,outlineArray.at(i).vert.at((j+1)%pnum).posic);
for (int n = 0; n < 3; n++)
{
edgeface_nor = cross(vArray.at(temp_tri.ids[n%3]).posic,vArray.at(temp_tri.ids[(n+1)%3]).posic);
//排除两个扇面在同一个平面的情况
if (fabs(dot(lineface_nor,edgeface_nor))/(length_cpoint(lineface_nor)*length_cpoint(edgeface_nor)) != 1.0)
{
//两个扇面可能的交点矢量垂直于两个扇面的外法线矢量 正反两个矢量
intersect[0] = cross(lineface_nor,edgeface_nor);
intersect[1] = cross(edgeface_nor,lineface_nor);
for (int k = 0; k < 2; k++)
{
//交点矢量在两个线段端点矢量之间 注意端点先后顺序决定了大圆弧在球面上的范围 注意这里同样有从背面穿透的可能 因为我们不确定intersect中哪一个是我们想要的
//注意计算叉乘的时候 我们总是会走一个角度小于180的方向
//排除与angle_mid相反的半球上所有的三角形
if (dot(cross(intersect[k],vArray.at(temp_tri.ids[n%3]).posic),cross(intersect[k],vArray.at(temp_tri.ids[(n+1)%3]).posic)) < 0
&& dot(cross(intersect[k],outlineArray.at(i).vert.at(j%pnum).posic),cross(intersect[k],outlineArray.at(i).vert.at((j+1)%pnum).posic)) < 0
&& dot(angle_mid,tri_nor) > 0)
{
//多边形边与节点三角形相交 即节点三角形至少有一个顶点在多边形内 返回假
return 0;
}
}
}
}
}
}
//多边形的顶点和边与当前节点三角形不相交或者包含 判断三角形是否在多边形内
for (int i = 0; i < outlineArray.size(); i++)
{
pnum = outlineArray.at(i).vert.size();
polygon_mid = middle_vertex(outlineArray.at(i).vert);
//依次判断节点三角形的三条边与多边形边的交点个数
for (int k = 0; k < 3; k++)
{
count = 0;
//计算三角形边与球心的平面的法线矢量 只要任意一条边在多边形内 则三角形在多边形内
edgeface_nor = cross(vArray.at(temp_tri.ids[(k)%3]).posic,vArray.at(temp_tri.ids[(k+1)%3]).posic);
for (int j = 0; j < outlineArray.at(i).vert.size(); j++)
{
//多边形边与当前节点三角形相交
lineface_nor = cross(outlineArray.at(i).vert.at(j%pnum).posic,outlineArray.at(i).vert.at((j+1)%pnum).posic);
angle_mid = middle_cpoint(outlineArray.at(i).vert.at(j%pnum).posic,outlineArray.at(i).vert.at((j+1)%pnum).posic);
//排除两个扇面在同一个平面的情况
if (fabs(dot(lineface_nor,edgeface_nor))/(length_cpoint(lineface_nor)*length_cpoint(edgeface_nor)) != 1.0)
{
//两个扇面可能的交点矢量垂直于两个扇面的外法线矢量 正反两个矢量
intersect[0] = cross(lineface_nor,edgeface_nor);
intersect[1] = cross(edgeface_nor,lineface_nor);
for (int n = 0; n < 2; n++)
{
/*注意 这里我们只判断交点是否在线段之间 或者一个点上 这里选择第一个点也可以选择第二点 但只能包含一个 不判断是不是在边之间
180*/
//交点矢量在两个线段端点矢量之间 注意端点先后顺序决定了大圆弧在球面上的范围 注意这里同样有从背面穿透的可能 因为我们不确定intersect中哪一个是我们想要的
//注意计算叉乘的时候 我们总是会走一个角度小于180的方向
//排除与angle_mid相反的半球上所有的三角形
if (dot(polygon_mid,tri_nor) > 0 //排除位于球背面的三角形
&& (dot(cross(intersect[k],outlineArray.at(i).vert.at(j%pnum).posic),cross(intersect[k],outlineArray.at(i).vert.at((j+1)%pnum).posic)) < 0
|| outlineArray.at(i).vert.at(j).posic == intersect[n]) //排除与多边形的边不相交的三角形边的延长线 这里包含了一个等于条件 即交点刚好在多边形的顶点上
&& dot(angle_mid,intersect[n]) > 0 //排除位于球背面的多边形边与三角形边延长线的交点
&& dot(edgeface_nor,cross(vArray.at(temp_tri.ids[k%3]).posic,intersect[n])) > 0) //只取三角形边其中一则的延长线
{
count++;
}
}
}
}
//交点个数为奇数 边在多边形内 返回假
if (pow(-1,count) < 0) return 0;
}
}
//全不为假 返回真
return 1;
}
}
int QdTree_Icosa::inPolyOutline(Qdtree_node* node)
{
if (holeArray.empty()) //没有范围多边形 直接返回否
{
return 0;
}
else
{
int count;
int pnum;
cpoint tri_nor;
cpoint lineface_nor, edgeface_nor;
cpoint intersect[2];
cpoint angle_mid;
cpoint polygon_mid;
cpoint cross_point;
triangle temp_tri;
for (int j = 0; j < 3; j++)
{
temp_tri.ids[j] = node->tri->ids[j];
}
//计算三角面元外法线矢量
tri_nor = cross(vArray.at(temp_tri.ids[1]).posic-vArray.at(temp_tri.ids[0]).posic , vArray.at(temp_tri.ids[2]).posic-vArray.at(temp_tri.ids[0]).posic);
//首先判断多边形的顶点是否在当前节点三角形内 或者多边形的边是否与当前节点三角形相交 这些条件可以判断多边形边上的三角形
for (int i = 0; i < holeArray.size(); i++)
{
pnum = holeArray.at(i).vert.size();
for (int j = 0; j < holeArray.at(i).vert.size(); j++)
{
if (dot(tri_nor,holeArray.at(i).vert.at(j).posic) > 0) //排除球形背面的点
{
//多边形节点在当前节点三角形内
count = 0;
for (int k = 0; k < 3; k++)
{
cross_point = lineOnPlane(vArray.at(temp_tri.ids[k%3]).posic,tri_nor,holeArray.at(i).vert.at(j).posic);
//依次判断前后两条边与待检测点的外法线是否同向 注意排除从球体背面穿射的情况 全为真则返回真
if (dot(tri_nor,
cross(vArray.at(temp_tri.ids[(k+1)%3]).posic-vArray.at(temp_tri.ids[k%3]).posic , cross_point-vArray.at(temp_tri.ids[k%3]).posic)) > 0)
{
count++;
}
}
//全部在左侧 多边形顶点至少有一个在节点三角形内 即节点三角形至少有一个顶点在多边形内 返回真
if (count == 3) return 1;
}
//多边形边与当前节点三角形相交
lineface_nor = cross(holeArray.at(i).vert.at(j%pnum).posic,holeArray.at(i).vert.at((j+1)%pnum).posic);
angle_mid = middle_cpoint(holeArray.at(i).vert.at(j%pnum).posic,holeArray.at(i).vert.at((j+1)%pnum).posic);
for (int n = 0; n < 3; n++)
{
edgeface_nor = cross(vArray.at(temp_tri.ids[n%3]).posic,vArray.at(temp_tri.ids[(n+1)%3]).posic);
//排除两个扇面在同一个平面的情况
if (fabs(dot(lineface_nor,edgeface_nor))/(length_cpoint(lineface_nor)*length_cpoint(edgeface_nor)) != 1.0)
{
//两个扇面可能的交点矢量垂直于两个扇面的外法线矢量 正反两个矢量
intersect[0] = cross(lineface_nor,edgeface_nor);
intersect[1] = cross(edgeface_nor,lineface_nor);
for (int k = 0; k < 2; k++)
{
//交点矢量在两个线段端点矢量之间 注意端点先后顺序决定了大圆弧在球面上的范围 注意这里同样有从背面穿透的可能 因为我们不确定intersect中哪一个是我们想要的
//注意计算叉乘的时候 我们总是会走一个角度小于180的方向
//排除与angle_mid相反的半球上所有的三角形
if (dot(cross(intersect[k],vArray.at(temp_tri.ids[n%3]).posic),cross(intersect[k],vArray.at(temp_tri.ids[(n+1)%3]).posic)) < 0
&& dot(cross(intersect[k],holeArray.at(i).vert.at(j%pnum).posic),cross(intersect[k],holeArray.at(i).vert.at((j+1)%pnum).posic)) < 0
&& dot(angle_mid,tri_nor) > 0)
{
//多边形边与节点三角形相交 即节点三角形至少有一个顶点在多边形内 返回真
return 1;
}
}
}
}
}
}
//多边形的顶点和边与当前节点三角形不相交或者包含 判断三角形是否在多边形内
for (int i = 0; i < holeArray.size(); i++)
{
pnum = holeArray.at(i).vert.size();
polygon_mid = middle_vertex(holeArray.at(i).vert);
//依次判断节点三角形的三条边与多边形边的交点个数
for (int k = 0; k < 3; k++)
{
count = 0;
//计算三角形边与球心的平面的法线矢量 只要任意一条边在多边形内 则三角形在多边形内
edgeface_nor = cross(vArray.at(temp_tri.ids[(k)%3]).posic,vArray.at(temp_tri.ids[(k+1)%3]).posic);
for (int j = 0; j < holeArray.at(i).vert.size(); j++)
{
//多边形边与当前节点三角形相交
lineface_nor = cross(holeArray.at(i).vert.at(j%pnum).posic,holeArray.at(i).vert.at((j+1)%pnum).posic);
angle_mid = middle_cpoint(holeArray.at(i).vert.at(j%pnum).posic,holeArray.at(i).vert.at((j+1)%pnum).posic);
//排除两个扇面在同一个平面的情况
if (fabs(dot(lineface_nor,edgeface_nor))/(length_cpoint(lineface_nor)*length_cpoint(edgeface_nor)) != 1.0)
{
//两个扇面可能的交点矢量垂直于两个扇面的外法线矢量 正反两个矢量
intersect[0] = cross(lineface_nor,edgeface_nor);
intersect[1] = cross(edgeface_nor,lineface_nor);
for (int n = 0; n < 2; n++)
{
/*注意 这里我们只判断交点是否在线段之间 或者一个点上 这里选择第一个点也可以选择第二点 但只能包含一个 不判断是不是在边之间
180*/
//交点矢量在两个线段端点矢量之间 注意端点先后顺序决定了大圆弧在球面上的范围 注意这里同样有从背面穿透的可能 因为我们不确定intersect中哪一个是我们想要的
//注意计算叉乘的时候 我们总是会走一个角度小于180的方向
//排除与angle_mid相反的半球上所有的三角形
if (dot(polygon_mid,tri_nor) > 0 //排除位于球背面的三角形
&& (dot(cross(intersect[k],holeArray.at(i).vert.at(j%pnum).posic),cross(intersect[k],holeArray.at(i).vert.at((j+1)%pnum).posic)) < 0
|| holeArray.at(i).vert.at(j).posic == intersect[n]) //排除与多边形的边不相交的三角形边的延长线 这里包含了一个等于条件 即交点刚好在多边形的顶点上
&& dot(angle_mid,intersect[n]) > 0 //排除位于球背面的多边形边与三角形边延长线的交点
&& dot(edgeface_nor,cross(vArray.at(temp_tri.ids[k%3]).posic,intersect[n])) > 0) //只取三角形边其中一则的延长线
{
count++;
}
}
}
}
//交点个数为奇数 边在多边形内 返回真
if (pow(-1,count) < 0) return 1;
}
}
//全不为真 返回假
return 0;
}
}
int QdTree_Icosa::out_msh(char* filename,double refr,double refR)
{
time_t now = time(0);
char* dt = ctime(&now);
vertex v;
ofstream outfile;
if (!strcmp(filename,"NULL"))
{
return -1;
}
if(open_outfile(outfile,filename)) return -1;
extract_vertex();
outfile << "$Comments" << endl << "this file is created by Qdtree_icosa.ex on " << dt;
outfile << "basic quad-tree depth: " << tree_depth << endl;
outfile << "maximal quad-tree depth: " << max_depth << endl;
outfile << "outline: " << outlineFile << endl;
outfile << "hole:" << holeFile << endl;
outfile << "extral points: " << pointFile << endl;
outfile << "extral lines: " << lineFile << endl;
outfile << "extral polygons: " << polyFile << endl;
outfile << "extral circles: " << circleFile << endl << "$EndComments" << endl;
outfile<<"$MeshFormat"<<endl<<"2.2 0 8"<<endl<<"$EndMeshFormat"<<endl<<"$Nodes"<<endl<<out_iArray.size()<<endl;
for (int i = 0; i < out_iArray.size(); i++)
{
if (refr == 0 && refR == 0)
{
outfile << i << " " << setprecision(16) << vArray.at(out_iArray.at(i)).posic.x << " " << vArray.at(out_iArray.at(i)).posic.y << " " << vArray.at(out_iArray.at(i)).posic.z << endl;
}
else if (refr != 0 && refR != 0)
{
v = vArray.at(out_iArray.at(i));
v.posic = rescale_cpoint(vArray.at(out_iArray.at(i)).posic, REF_r(v.posis.lat,refr,refR));
v.set(v.posic);
outfile << i << " " << setprecision(16) << v.posic.x << " " << v.posic.y << " " << v.posic.z << endl;
}
else
{
cout << "error ==> reference system fail" << endl;
return -1;
}
}
outfile<<"$EndNodes"<<endl<<"$Elements"<<endl<<out_tArray.size()<<endl;
for (int i = 0; i < out_tArray.size(); i++)
{
outfile<< i <<" 2 1 " << out_tArray.at(i).physic << " " << mapOutId[out_tArray.at(i).ids[0]] << " " << mapOutId[out_tArray.at(i).ids[1]] << " " << mapOutId[out_tArray.at(i).ids[2]] << endl;
}
outfile<<"$EndElements"<<endl;
outfile.close();
return 0;
}
int QdTree_Icosa::out_sph(char* filename,double refr,double refR)
{
time_t now = time(0);
char* dt = ctime(&now);
vertex v;
ofstream outfile;
if (!strcmp(filename,"NULL"))
{
return -1;
}
if(open_outfile(outfile,filename)) return -1;
extract_vertex();
outfile << "# this file is created by Qdtree_icosa.ex on " << dt;
outfile << "# basic quad-tree depth: " << tree_depth << endl;
outfile << "# maximal quad-tree depth: " << max_depth << endl;
outfile << "# outline: " << outlineFile << endl;
outfile << "# hole: " << holeFile << endl;
outfile << "# extral points: " << pointFile << endl;
outfile << "# extral lines: " << lineFile << endl;
outfile << "# extral polygons: " << polyFile << endl;
outfile << "# extral circles: " << circleFile << endl;
//outfile << "# lon(deg) lat(deg) rad(m)" << endl;
outfile << "# node position lon(deg) lat(deg)" << endl;
for (int i = 0; i < out_iArray.size(); i++)
{
if (refr == 0 && refR == 0) //not used
{
outfile << setprecision(16) << vArray.at(out_iArray.at(i)).posis.lon << " " << vArray.at(out_iArray.at(i)).posis.lat << " " << vArray.at(out_iArray.at(i)).posis.rad << endl;
}
else if (refr != 0 && refR != 0)
{
v = vArray.at(out_iArray.at(i));
v.posic = rescale_cpoint(vArray.at(out_iArray.at(i)).posic, REF_r(v.posis.lat,refr,refR));
v.set(v.posic);
outfile << setprecision(16) << v.posis.lon << " " << v.posis.lat << " " << v.posis.rad << endl;
//outfile << setprecision(16) << v.posis.lon << " " << v.posis.lat << endl;
}
else
{
cout << "error ==> reference system fail" << endl;
return -1;
}
}
outfile.close();
return 0;
}
int QdTree_Icosa::out_loc(char* filename)
{
time_t now = time(0);
char* dt = ctime(&now);
ofstream outfile;
if (!strcmp(filename,"NULL"))
{
return -1;
}
if(open_outfile(outfile,filename)) return -1;
outfile << "# this file is created by Qdtree_icosa.ex on " << dt;
outfile << "# basic quad-tree depth: " << tree_depth << endl;
outfile << "# maximal quad-tree depth: " << max_depth << endl;
outfile << "# outline: " << outlineFile << endl;
outfile << "# hole: " << holeFile << endl;
outfile << "# extral points: " << pointFile << endl;
outfile << "# extral lines: " << lineFile << endl;
outfile << "# extral polygons: " << polyFile << endl;
outfile << "# extral circles: " << circleFile << endl;
outfile << "# node position lon(deg) lat(deg) Triangle-ids" << endl;
for (int i = 0; i < sphLocations.size(); i++)
{
outfile << setprecision(16);
outfile << sphLocations[i].posis.lon << " " << sphLocations[i].posis.lat << " ";
if (locTriangles[i].empty())
{
outfile << "nan" << endl; //对于没有所属三角形的情况 输出-1
}
else
{
for (int j = 0; j < locTriangles[i].size(); j++)
{
outfile << locTriangles[i][j] << " ";
}
outfile << endl;
}
}
outfile.close();
return 0;
}
int QdTree_Icosa::get_extrapoint(char* filename)
{
double node_eleva;
stringstream temp_ss;
string temp_str;
point temp_v;
ifstream infile;
if (!strcmp(filename,"NULL"))
{
return 0;
}
if (open_infile(infile,filename)) return -1;
else
{
while (getline(infile,temp_str))
{
if (*(temp_str.begin()) == '#' || temp_str == "") continue;
else
{
temp_ss.str("");
temp_ss.clear();
temp_ss << temp_str;
if (temp_ss >> temp_v.maxDepth >> temp_v.minDeg >> temp_v.physic >> temp_v.vert.posis.lon >> temp_v.vert.posis.lat >> node_eleva)
{
if (temp_v.maxDepth < 0) temp_v.maxDepth = 1e+3; //这里直接给一个很大的深度值 节点深度一定小于这个值
if (temp_v.minDeg < 0) temp_v.minDeg = -1; //这里直接给成-1
temp_v.vert.posis.rad = defaultR + node_eleva;
temp_v.vert.set(extrapArray.size());
temp_v.vert.set(temp_v.vert.posis);
extrapArray.push_back(temp_v);
}
}
}
infile.close();
}
return 0;
}
int QdTree_Icosa::get_extraline(char* filename) //点个数跟点列表
{
int count;
double node_eleva;
stringstream temp_ss;
string temp_str;
vertex temp_v;
line l;
ifstream infile;
if (!strcmp(filename,"NULL"))
{
return 0;
}
if (open_infile(infile,filename)) return -1;
else
{
while (getline(infile,temp_str))
{
if (*(temp_str.begin()) == '#' || temp_str == "") continue;
else
{
if (!l.vert.empty()) l.vert.clear();
temp_ss.str("");
temp_ss.clear();
temp_ss << temp_str;
temp_ss >> count >> l.maxDepth >> l.minDeg >> l.physic;
if (l.maxDepth < 0) l.maxDepth = 1e+3; //这里直接给一个很大的深度值 节点深度一定小于这个值
if (l.minDeg < 0) l.minDeg = -1; //这里直接给成-1
for (int i = 0; i < count; i++)
{
getline(infile,temp_str);
temp_ss.str("");
temp_ss.clear();
temp_ss << temp_str;
if (temp_ss >> temp_v.posis.lon >> temp_v.posis.lat >> node_eleva)
{
temp_v.posis.rad = defaultR + node_eleva;
temp_v.set(l.vert.size());
temp_v.set(temp_v.posis);
l.vert.push_back(temp_v);
}
}
l.id = extralArray.size();
extralArray.push_back(l);
}
}
infile.close();
}
return 0;
}
int QdTree_Icosa::get_extrapoly(char* filename)
{
int count;
double node_eleva;
stringstream temp_ss;
string temp_str;
vertex temp_v;
polygon p;
ifstream infile;
if (!strcmp(filename,"NULL"))
{
return 0;
}
if (open_infile(infile,filename)) return -1;
else
{
while (getline(infile,temp_str))
{
if (*(temp_str.begin()) == '#' || temp_str == "") continue;
else
{
if (!p.vert.empty()) p.vert.clear();
temp_ss.str("");
temp_ss.clear();
temp_ss << temp_str;
temp_ss >> count >> p.maxDepth >> p.minDeg >> p.physic;
if (p.maxDepth < 0) p.maxDepth = 100; //这里直接给一个很大的深度值 节点深度一定小于这个值
if (p.minDeg < 0) p.minDeg = -1.0; //这里直接给成-1
for (int i = 0; i < count; i++)
{
getline(infile,temp_str);
temp_ss.str("");
temp_ss.clear();
temp_ss << temp_str;
if (temp_ss >> temp_v.posis.lon >> temp_v.posis.lat >> node_eleva)
{
temp_v.posis.rad = defaultR + node_eleva;
temp_v.set(p.vert.size());
temp_v.set(temp_v.posis);
p.vert.push_back(temp_v);
}
}
p.id = extrapolyArray.size();
extrapolyArray.push_back(p);
}
}
infile.close();
}
return 0;
}
int QdTree_Icosa::get_extracircle(char* filename)
{
double node_eleva;
stringstream temp_ss;
string temp_str;
circle temp_v;
ifstream infile;
if (!strcmp(filename,"NULL"))
{
return 0;
}
if (open_infile(infile,filename)) return -1;
else
{
while (getline(infile,temp_str))
{
if (*(temp_str.begin()) == '#' || temp_str == "") continue;
else
{
temp_ss.str("");
temp_ss.clear();
temp_ss << temp_str;
if (temp_ss >> temp_v.maxDepth >> temp_v.minDeg >> temp_v.physic >> temp_v.radDeg >> temp_v.cen.posis.lon >> temp_v.cen.posis.lat >> node_eleva)
{
if (temp_v.maxDepth < 0) temp_v.maxDepth = 1e+3; //这里直接给一个很大的深度值 节点深度一定小于这个值
if (temp_v.minDeg < 0) temp_v.minDeg = -1; //这里直接给成-1
temp_v.cen.posis.rad = defaultR + node_eleva;
temp_v.cen.set(extracirArray.size());
temp_v.cen.set(temp_v.cen.posis);
extracirArray.push_back(temp_v);
}
}
}
infile.close();
}
return 0;
}
int QdTree_Icosa::get_outline(char* filename)
{
int count;
double node_eleva;
stringstream temp_ss;
string temp_str;
vertex temp_v;
polygon p;
ifstream infile;
if (!strcmp(filename,"NULL"))
{
return 0;
}
if (open_infile(infile,filename)) return -1;
else
{
while (getline(infile,temp_str))
{
if (*(temp_str.begin()) == '#' || temp_str == "") continue;
else
{
if (!p.vert.empty()) p.vert.clear();
temp_ss.str("");
temp_ss.clear();
temp_ss << temp_str;
//由于范围多边形对模型生成范围作出的是绝对性的约束 因此并不需要制定每个范围多边形的最大深度和最小尺寸等信息
//这里暂时保留这两个参数 只是他们在后续的过程中并不起任何作用
temp_ss >> count >> p.maxDepth >> p.minDeg >> p.physic; //后面三个没用
if (p.maxDepth < 0) p.maxDepth = 1e+3; //这里直接给一个很大的深度值 节点深度一定小于这个值
if (p.minDeg < 0) p.minDeg = -1; //这里直接给成-1
for (int i = 0; i < count; i++)
{
getline(infile,temp_str);
temp_ss.str("");
temp_ss.clear();
temp_ss << temp_str;
if (temp_ss >> temp_v.posis.lon >> temp_v.posis.lat >> node_eleva)
{
temp_v.posis.rad = defaultR + node_eleva;
temp_v.set(p.vert.size());
temp_v.set(temp_v.posis);
p.vert.push_back(temp_v);
}
}
p.id = outlineArray.size();
outlineArray.push_back(p);
}
}
infile.close();
}
return 0;
}
int QdTree_Icosa::get_hole(char* filename)
{
int count;
double node_eleva;
stringstream temp_ss;
string temp_str;
vertex temp_v;
polygon p;
ifstream infile;
if (!strcmp(filename,"NULL"))
{
return 0;
}
if (open_infile(infile,filename)) return -1;
else
{
while (getline(infile,temp_str))
{
if (*(temp_str.begin()) == '#' || temp_str == "") continue;
else
{
if (!p.vert.empty()) p.vert.clear();
temp_ss.str("");
temp_ss.clear();
temp_ss << temp_str;
//由于范围多边形对模型生成范围作出的是绝对性的约束 因此并不需要制定每个范围多边形的最大深度和最小尺寸等信息
//这里暂时保留这两个参数 只是他们在后续的过程中并不起任何作用
temp_ss >> count >> p.maxDepth >> p.minDeg >> p.physic; //后面三个没用
if (p.maxDepth < 0) p.maxDepth = 1e+3; //这里直接给一个很大的深度值 节点深度一定小于这个值
if (p.minDeg < 0) p.minDeg = -1; //这里直接给成-1
for (int i = 0; i < count; i++)
{
getline(infile,temp_str);
temp_ss.str("");
temp_ss.clear();
temp_ss << temp_str;
if (temp_ss >> temp_v.posis.lon >> temp_v.posis.lat >> node_eleva)
{
temp_v.posis.rad = defaultR + node_eleva;
temp_v.set(p.vert.size());
temp_v.set(temp_v.posis);
p.vert.push_back(temp_v);
}
}
p.id = holeArray.size();
holeArray.push_back(p);
}
}
infile.close();
}
return 0;
}
int QdTree_Icosa::get_loc(char* filename)
{
stringstream temp_ss;
string temp_str;
vertex temp_vert;
ifstream infile;
if (!strcmp(filename,"NULL"))
{
return 0;
}
if (open_infile(infile,filename)) return -1;
else
{
while (getline(infile,temp_str))
{
if (*(temp_str.begin()) == '#' || temp_str == "") continue;
else
{
temp_ss.str("");
temp_ss.clear();
temp_ss << temp_str;
temp_ss >> temp_vert.posis.lon >> temp_vert.posis.lat;
temp_vert.posis.rad = defaultR;
temp_vert.set(temp_vert.posis);
sphLocations.push_back(temp_vert);
}
}
infile.close();
}
return 0;
}
/*辅助函数*/
void QdTree_Icosa::init_icosa(double R,vertex ori)
{
double constL,constZ;
//计算二十面的十二个顶点位置 首先将顶点位置固定在地理北极点
ICOSA.vert[0].id = 0;
ICOSA.vert[0].posic.x = 0.0;
ICOSA.vert[0].posic.y = 0.0;
ICOSA.vert[0].posic.z = R;
ICOSA.vert[0].set(ICOSA.vert[0].posic);
ICOSA.vert[11].id = 11;
ICOSA.vert[11].posic.x = 0.0;
ICOSA.vert[11].posic.y = 0.0;
ICOSA.vert[11].posic.z = -R;
ICOSA.vert[11].set(ICOSA.vert[11].posic);
constZ = R*(golden_mean*golden_mean - 1.0)/(golden_mean*golden_mean + 1.0);
constL = R*sqrt(1.0 - pow((golden_mean*golden_mean - 1.0)/(golden_mean*golden_mean + 1.0),2));
for(int i=1;i<=5;i++)
{
ICOSA.vert[i].id = i;
ICOSA.vert[i].posic.x = cos(72.0*(i-1)*pi/180.0)*constL;
ICOSA.vert[i].posic.y = sin(72.0*(i-1)*pi/180.0)*constL;
ICOSA.vert[i].posic.z = constZ;
ICOSA.vert[i].set(ICOSA.vert[i].posic);
ICOSA.vert[i+5].id = i+5;
ICOSA.vert[i+5].posic.x = cos((72.0*(i-1)+36.0)*pi/180.0)*constL;
ICOSA.vert[i+5].posic.y = sin((72.0*(i-1)+36.0)*pi/180.0)*constL;
ICOSA.vert[i+5].posic.z = -constZ;
ICOSA.vert[i+5].set(ICOSA.vert[i+5].posic);
}
//给定二十面的面顶点索引,各个三角面顶点索引按逆时针排序
ICOSA.tri[0].ids[0] = 0; ICOSA.tri[0].ids[1] = 1; ICOSA.tri[0].ids[2] = 2;
ICOSA.tri[1].ids[0] = 0; ICOSA.tri[1].ids[1] = 2; ICOSA.tri[1].ids[2] = 3;
ICOSA.tri[2].ids[0] = 0; ICOSA.tri[2].ids[1] = 3; ICOSA.tri[2].ids[2] = 4;
ICOSA.tri[3].ids[0] = 0; ICOSA.tri[3].ids[1] = 4; ICOSA.tri[3].ids[2] = 5;
ICOSA.tri[4].ids[0] = 0; ICOSA.tri[4].ids[1] = 5; ICOSA.tri[4].ids[2] = 1;
ICOSA.tri[5].ids[0] = 1; ICOSA.tri[5].ids[1] = 6; ICOSA.tri[5].ids[2] = 2;
ICOSA.tri[6].ids[0] = 2; ICOSA.tri[6].ids[1] = 6; ICOSA.tri[6].ids[2] = 7;
ICOSA.tri[7].ids[0] = 2; ICOSA.tri[7].ids[1] = 7; ICOSA.tri[7].ids[2] = 3;
ICOSA.tri[8].ids[0] = 3; ICOSA.tri[8].ids[1] = 7; ICOSA.tri[8].ids[2] = 8;
ICOSA.tri[9].ids[0] = 3; ICOSA.tri[9].ids[1] = 8; ICOSA.tri[9].ids[2] = 4;
ICOSA.tri[10].ids[0] = 4; ICOSA.tri[10].ids[1] = 8; ICOSA.tri[10].ids[2] = 9;
ICOSA.tri[11].ids[0] = 4; ICOSA.tri[11].ids[1] = 9; ICOSA.tri[11].ids[2] = 5;
ICOSA.tri[12].ids[0] = 5; ICOSA.tri[12].ids[1] = 9; ICOSA.tri[12].ids[2] = 10;
ICOSA.tri[13].ids[0] = 5; ICOSA.tri[13].ids[1] = 10; ICOSA.tri[13].ids[2] = 1;
ICOSA.tri[14].ids[0] = 1; ICOSA.tri[14].ids[1] = 10; ICOSA.tri[14].ids[2] = 6;
ICOSA.tri[15].ids[0] = 6; ICOSA.tri[15].ids[1] = 11; ICOSA.tri[15].ids[2] = 7;
ICOSA.tri[16].ids[0] = 7; ICOSA.tri[16].ids[1] = 11; ICOSA.tri[16].ids[2] = 8;
ICOSA.tri[17].ids[0] = 8; ICOSA.tri[17].ids[1] = 11; ICOSA.tri[17].ids[2] = 9;
ICOSA.tri[18].ids[0] = 9; ICOSA.tri[18].ids[1] = 11; ICOSA.tri[18].ids[2] = 10;
ICOSA.tri[19].ids[0] = 10; ICOSA.tri[19].ids[1] = 11; ICOSA.tri[19].ids[2] = 6;
//旋转二十面顶点的位置
vertex ref_vert = ICOSA.vert[0]; //注意我们选取的参考点为z轴正方向
for (int i = 0; i < 12; i++)
{
ICOSA.vert[i] = rotate_vertex(ref_vert,ori,ICOSA.vert[i]);
}
return;
}
void QdTree_Icosa::extract_vertex()
{
vector<int>::iterator pos;
for (int i = 0; i < out_tArray.size(); i++)
{
for (int j = 0; j < 3; j++)
{
out_iArray.push_back(out_tArray.at(i).ids[j]);
}
}
sort(out_iArray.begin(),out_iArray.end()); //对顶点序列由小到大排序
pos = unique(out_iArray.begin(), out_iArray.end()); //获取重复序列开始的位置
out_iArray.erase(pos, out_iArray.end()); //删除重复顶点序列
//初始化mapOutId;
for (int i = 0; i < out_iArray.size(); i++)
{
mapOutId[out_iArray.at(i)] = i;
}
}
double QdTree_Icosa::mean_edgeDegree(Qdtree_node* node,double refR)
{
double l = 0;
triangle temp_tri;
for (int j = 0; j < 3; j++)
{
temp_tri.ids[j] = node->tri->ids[j];
}
for (int i = 0; i < 3; i++)
{
l += distance_cpoint(vArray.at(temp_tri.ids[i%3]).posic,vArray.at(temp_tri.ids[(i+1)%3]).posic);
}
return l*60.0/(pi*refR);
}
//判断点是否在三角形内 使用投影方法的函数 如要使用需要取消dataStruct.h中的相应部分
/*
int QdTree_Icosa::inTriangleDot_old(Qdtree_node* node)
{
int count;
planePara currPlane;
point2d currTri[3];
point2d currP2d;
cpoint dir_v012;
double xmin,xmax,ymin,ymax; //用于判断点是否在外接矩形外
if (extrapArray.empty()) //没有插入的点位 直接返回否
{
return 0;
}
else
{
triangle temp_tri;
for (int j = 0; j < 3; j++)
{
temp_tri.ids[j] = node->tri->ids[j];
}
//计算一样三角形的外法线矢量
dir_v012 = cross(vArray.at(temp_tri.ids[1]).posic - vArray.at(temp_tri.ids[0]).posic,vArray.at(temp_tri.ids[2]).posic - vArray.at(temp_tri.ids[0]).posic);
//计算三角面平面
currPlane = get_planePara(vArray.at(temp_tri.ids[0]).posic,vArray.at(temp_tri.ids[1]).posic,vArray.at(temp_tri.ids[2]).posic);
//计算三角形三个顶点在新坐标系中的坐标
currTri[0].x = 0.0; currTri[0].y = 0.0; //新坐标系的原点
currTri[1].x = distance_cpoint(vArray.at(temp_tri.ids[0]).posic,vArray.at(temp_tri.ids[1]).posic); currTri[1].y = 0.0; //新坐标系的x轴
currTri[2] = newXY(vArray.at(temp_tri.ids[0]),vArray.at(temp_tri.ids[1]),vArray.at(temp_tri.ids[2]),vArray.at(temp_tri.ids[2]));
//确定外接矩形
xmin = MAX_DBL; ymin = MAX_DBL;
xmax = MIN_BDL; ymax = MIN_BDL;
for (int j = 0; j < 3; j++)
{
if (currTri[j].x < xmin) xmin = currTri[j].x;
if (currTri[j].x > xmax) xmax = currTri[j].x;
if (currTri[j].y < ymin) ymin = currTri[j].y;
if (currTri[j].y > ymax) ymax = currTri[j].y;
}
for (int i = 0; i < extrapArray.size(); i++)
{
//首先要计算三角形外法线矢量与待检测点矢量的方向是否基本一致 需要排除反向穿越的情况
if (dot(dir_v012,extrapArray.at(i).vert.posic) > 0)
{
//计算带监测点在新坐标系中的位置
currP2d = newXY(vArray.at(temp_tri.ids[0]),vArray.at(temp_tri.ids[1]),vArray.at(temp_tri.ids[2]),dotOnPlane(currPlane,extrapArray.at(i).vert));
//满足点在外接矩形内
if (currP2d.x > xmin && currP2d.x < xmax && currP2d.y > ymin && currP2d.y < ymax)
{
//向右做射线 计算与线段的交点 待检验点横坐标如果小于交点横坐标 则表示射线穿过
//如果穿过次数为奇数 则在多边形内
count = 0;
for (int j = 0; j < 3; j++)
{
//注意现在使用的条件不包含位于多边形的边和顶点上的点
//前两组条件表示待检测点y坐标在线段内 单侧包含
//后一组条件表示交点横坐标大于待检测点横坐标
//注意这里线段两个端点的y值相同时分母为零的情况在前叙的if条件中已经规避了
if (((currP2d.y < currTri[j%3].y && currP2d.y >= currTri[(j+1)%3].y) ||
(currP2d.y > currTri[j%3].y && currP2d.y <= currTri[(j+1)%3].y)) &&
currP2d.x < ((currP2d.y - currTri[j%3].y)*(currTri[(j+1)%3].x - currTri[j%3].x)/(currTri[(j+1)%3].y - currTri[j%3].y) + currTri[j%3].x))
{
count++;
}
}
//至少有一个点在当前多边形内 直接返回真
if (pow(-1,count) < 0) return 1;
}
}
}
//没有点在当前多边形内 返回假
return 0;
}
}
*/
#endif