#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<>vert_id; sstemp.str(""); sstemp.clear(); sstemp<>mid_id; vert_id = vert_id + " " + mid_id; sstemp.str(""); sstemp.clear(); 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<>vert_id; sstemp.str(""); sstemp.clear(); sstemp<>mid_id; vert_id = vert_id + " " + mid_id; sstemp.str(""); sstemp.clear(); 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<>vert_id; sstemp.str(""); sstemp.clear(); sstemp<>mid_id; vert_id = vert_id + " " + mid_id; sstemp.str(""); sstemp.clear(); 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<>vert_id; sstemp.str(""); sstemp.clear(); sstemp<>mid_id; vert_id = vert_id + " " + mid_id; sstemp.str(""); sstemp.clear(); 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<>vert_id; sstemp.str(""); sstemp.clear(); sstemp<>mid_id; vert_id = vert_id + " " + mid_id; sstemp.str(""); sstemp.clear(); 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<>vert_id; sstemp.str(""); sstemp.clear(); sstemp<>mid_id; vert_id = vert_id + " " + mid_id; sstemp.str(""); sstemp.clear(); 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<>vert_id; sstemp.str(""); sstemp.clear(); sstemp<>mid_id; vert_id = vert_id + " " + mid_id; sstemp.str(""); sstemp.clear(); 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<>vert_id; sstemp.str(""); sstemp.clear(); sstemp<>mid_id; vert_id = vert_id + " " + mid_id; sstemp.str(""); sstemp.clear(); 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<>vert_id; sstemp.str(""); sstemp.clear(); sstemp<>mid_id; vert_id = vert_id + " " + mid_id; sstemp.str(""); sstemp.clear(); 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<>vert_id; sstemp.str(""); sstemp.clear(); sstemp<>mid_id; vert_id = vert_id + " " + mid_id; sstemp.str(""); sstemp.clear(); 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)= 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"< reference system fail" << endl; return -1; } } outfile<<"$EndNodes"< 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::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