#ifndef GROUP_H #define GROUP_H #include "vtr.h" #include #include #include #include using namespace std; template class Basis { private: int ID; int nTri; T **triPtr; int cnt; public: // set procedures Basis(){ ID = -1; nTri = 0; triPtr = NULL; cnt = 0; } void setID(int id) { ID = id; } void InitialtriPtr(int n){ if (triPtr != NULL) delete [] triPtr; triPtr = new T* [n]; } void AddTriPtr(T *tt) { int i; for (i = 0; i < cnt; i ++){ if (triPtr[i] == tt) return; } triPtr[cnt] = tt; cnt ++; } void AddnTri() { nTri ++; } // Get procedures int getID() { return ID; } int getnTri() { return nTri; } int getCnt() { return cnt; } T* getTriPtr(int i) { return triPtr[i]; } }; typedef struct box{ float xmin, ymin, zmin; float xmax, ymax, zmax; vtr center; } box; // element: tri3d or face or tetra // In this subroutine, I used data struture of tri3d template class group { private: box BoundBox; group *children[2]; group *mother; element **elemArray; int nElement, nBasis, nChild; int *bArray, counter; int IdMax, IdMin; double radius; bool basisBuilt; bool PointInBox(double, double, double); void EqualPartition(int, double, double, double &); void AddnElement(); public: group(); void MakeChildren(); void FormBox(); void FormBoundary(double, double, double, double, double, double); void Initialize(); void InsertElement(element *); void ComputeGroupRadius(); void PartitionMultiLevelSVD(int, int&); void BuildGroupBarray(); void BuildMotherBarray(); void findGroup(group **); void findGroupHelper(int &, group **, group *); // set functions void SetnBasis(int n ) { nBasis = n; } void SetbArray(int *array) { bArray = array; } void SetnElement(int n) { nElement = n; } void SetMother(group *grp) { mother = grp; } void SetMaxId(int n) { IdMax = n; } void SetMinId(int n) { IdMin = n; } void SetBasisBuilt() { basisBuilt = true; } //get functions box GetBox() { return BoundBox; } group *GetMother() { return mother; } group **GetChildren() { return children; } group *GetChildren(int i) { return children[i]; } vtr GetGroupCenter() { return BoundBox.center; } element* GetElemArray(int i) { return elemArray[i]; } int GetnElement() { return nElement; } int GetnChild() { return nChild; } int GetnBasis() { return nBasis; } int* GetbArray() { return bArray; } double GetRadius() { return radius; } int GetMaxId() { return IdMax; } int GetMinId() { return IdMin; } bool IsBasisBuilt() { return basisBuilt; } }; template group::group() { basisBuilt = false; nElement = 0; counter = 0; nBasis = 0; IdMin = int (1.0e6); IdMax = -1; elemArray = 0; nChild = 2; mother = 0; for (int i = 0; i < nChild; i ++) children[i] = 0; } template void group::FormBoundary(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) { BoundBox.xmin = x_min; BoundBox.xmax = x_max; BoundBox.ymin = y_min; BoundBox.ymax = y_max; BoundBox.zmin = z_min; BoundBox.zmax = z_max; } template void group::FormBox() { double x, y, z; BoundBox.xmin = 1.0e10; BoundBox.ymin = 1.0e10; BoundBox.zmin = 1.0e10; BoundBox.xmax = -1.0e10; BoundBox.ymax = -1.0e10; BoundBox.zmax = -1.0e10; int i, j; for (i = 0; i < nElement; i ++){ element *elem = elemArray[i]; for (j = 0 ; j < 3; j ++){ x = elem->GetNodePtr(j)->GetX(); y = elem->GetNodePtr(j)->GetY(); z = elem->GetNodePtr(j)->GetZ(); if (x < BoundBox.xmin) BoundBox.xmin = x; if (y < BoundBox.ymin) BoundBox.ymin = y; if (z < BoundBox.zmin) BoundBox.zmin = z; if (x > BoundBox.xmax) BoundBox.xmax = x; if (y > BoundBox.ymax) BoundBox.ymax = y; if (z > BoundBox.zmax) BoundBox.zmax = z; } } x = (BoundBox.xmin + BoundBox.xmax) / 2.0; y = (BoundBox.ymin + BoundBox.ymax) / 2.0; z = (BoundBox.zmin + BoundBox.zmax) / 2.0; BoundBox.center.setvtr(x, y, z); // compute group radius vtr Gc = BoundBox.center; vtr point[8]; radius = 0.0; double xmax, xmin, ymax, ymin, zmax, zmin; xmax = BoundBox.xmax; ymax = BoundBox.ymax; zmax = BoundBox.zmax; xmin = BoundBox.xmin; ymin = BoundBox.ymin; zmin = BoundBox.zmin; point[0].setvtr(xmin, ymin, zmin); point[1].setvtr(xmin, ymax, zmin); point[2].setvtr(xmax, ymin, zmin); point[3].setvtr(xmax, ymax, zmin); point[4].setvtr(xmin, ymin, zmax); point[5].setvtr(xmin, ymax, zmax); point[6].setvtr(xmax, ymin, zmax); point[7].setvtr(xmax, ymax, zmax); for (i = 0 ; i < 8 ; i ++) { double length = Length(point[i] - Gc); if (length > radius) radius = length; } } /* // update the coordinate for the bounding box, */ /* // as well as the center of the box */ /* template */ /* void group::FormBox() */ /* { */ /* double x, y, z; */ /* BoundBox.xmin = 1.0e10; */ /* BoundBox.ymin = 1.0e10; */ /* BoundBox.zmin = 1.0e10; */ /* BoundBox.xmax = -1.0e10; */ /* BoundBox.ymax = -1.0e10; */ /* BoundBox.zmax = -1.0e10; */ /* int i; */ /* for (i = 0; i < nElement; i ++){ */ /* element *elem = elemArray[i]; */ /* elem->GetCenter(x, y, z); */ /* if (x < BoundBox.xmin) BoundBox.xmin = x; */ /* if (y < BoundBox.ymin) BoundBox.ymin = y; */ /* if (z < BoundBox.zmin) BoundBox.zmin = z; */ /* if (x > BoundBox.xmax) BoundBox.xmax = x; */ /* if (y > BoundBox.ymax) BoundBox.ymax = y; */ /* if (z > BoundBox.zmax) BoundBox.zmax = z; */ /* } */ /* x = (BoundBox.xmin + BoundBox.xmax) / 2.0; */ /* y = (BoundBox.ymin + BoundBox.ymax) / 2.0; */ /* z = (BoundBox.zmin + BoundBox.zmax) / 2.0; */ /* BoundBox.center.setvtr(x, y, z); */ /* // compute group radius */ /* vtr Gc = BoundBox.center; */ /* vtr point[8]; */ /* radius = 0.0; */ /* double xmax, xmin, ymax, ymin, zmax, zmin; */ /* xmax = BoundBox.xmax; */ /* ymax = BoundBox.ymax; */ /* zmax = BoundBox.zmax; */ /* xmin = BoundBox.xmin; */ /* ymin = BoundBox.ymin; */ /* zmin = BoundBox.zmin; */ /* point[0].setvtr(xmin, ymin, zmin); */ /* point[1].setvtr(xmin, ymax, zmin); */ /* point[2].setvtr(xmax, ymin, zmin); */ /* point[3].setvtr(xmax, ymax, zmin); */ /* point[4].setvtr(xmin, ymin, zmax); */ /* point[5].setvtr(xmin, ymax, zmax); */ /* point[6].setvtr(xmax, ymin, zmax); */ /* point[7].setvtr(xmax, ymax, zmax); */ /* for (i = 0 ; i < 8 ; i ++) { */ /* double length = Length(point[i] - Gc); */ /* if (length > radius) */ /* radius = length; */ /* } */ /* } */ // initialize the elemArray template void group::Initialize() { if (elemArray != 0) delete [] elemArray; elemArray = new element* [nElement]; } // increment the number of element template void group::AddnElement() { nElement ++; } // insert an element to elemArray template void group::InsertElement(element *T) { /* int i; for (i = 0; i < nElement; i ++) { if (elemArray[i] == T) return; } */ elemArray[counter ++] = T; } // Compute the radius of bounding box template void group::ComputeGroupRadius() { vtr Gc = BoundBox.center; vtr point[8]; radius = 0.0; double xmax, xmin, ymax, ymin, zmax, zmin; xmax = BoundBox.xmax; ymax = BoundBox.ymax; zmax = BoundBox.zmax; xmin = BoundBox.xmin; ymin = BoundBox.ymin; zmin = BoundBox.zmin; point[0].setvtr(xmin, ymin, zmin); point[1].setvtr(xmin, ymax, zmin); point[2].setvtr(xmax, ymin, zmin); point[3].setvtr(xmax, ymax, zmin); point[4].setvtr(xmin, ymin, zmax); point[5].setvtr(xmin, ymax, zmax); point[6].setvtr(xmax, ymin, zmax); point[7].setvtr(xmax, ymax, zmax); int i; for (i = 0 ; i < 8 ; i ++) { double length = Length(point[i] - Gc); if (length > radius) radius = length; } } // determine if a point inside the bounding box template bool group::PointInBox(double x, double y, double z) { double xmax, xmin, ymax, ymin, zmax, zmin; xmax = BoundBox.xmax; ymax = BoundBox.ymax; zmax = BoundBox.zmax; xmin = BoundBox.xmin; ymin = BoundBox.ymin; zmin = BoundBox.zmin; bool In = true, Out = false; if (xmin <= x && xmax >= x && ymin <= y && ymax >= y && zmin <= z && zmax >= z) return In; return Out; } // this subroutine determines where to cut the box into half template void group::EqualPartition(int index, double min, double max, double &mid) { int i; double center, xc, yc, zc; int check = 0; int leftcnt; bool found = true; float range_min = 0.45; float range_max = 0.55; double midMax = max; double midMin = min; while (found) { if (check == 1) break; leftcnt = 0; for (i = 0; i < nElement; i ++) { element *elem = elemArray[i]; elem->GetCenter(xc, yc, zc); if (index == 0) center = xc; if (index == 1) center = yc; if (index == 2) center = zc; if (check == 0) mid = 0.5 * (max + min); if ((min <= center) && (mid >= center)) { leftcnt ++; } } double Cnt = leftcnt; if ((Cnt >= range_min * nElement) && (Cnt <= range_max * nElement)) break; if (Cnt <= range_min * nElement) { midMin = mid; mid = 0.5 * (midMax + mid); } if (Cnt >= range_max * nElement) { midMax = mid; mid = 0.5 * (mid + midMin); } check ++; } } template void group::MakeChildren() { int i, j; for (i = 0; i < nChild; i ++) children[i] = new group [1]; double xmax, xmin, ymax, ymin, zmax, zmin; xmax = BoundBox.xmax; ymax = BoundBox.ymax; zmax = BoundBox.zmax; xmin = BoundBox.xmin; ymin = BoundBox.ymin; zmin = BoundBox.zmin; double xmid, ymid, zmid; double dmax = xmax - xmin; int optCASE = 0; if ((ymax - ymin) > dmax) { optCASE = 1; dmax = ymax - ymin; } if ((zmax - zmin) > dmax) { optCASE = 2; dmax = zmax - zmin; } if (dmax < 1.0e-8) return; if (optCASE == 0) { EqualPartition(0, xmin, xmax, xmid); children[0]->FormBoundary(xmin, xmid, ymin, ymax, zmin, zmax); children[1]->FormBoundary(xmid, xmax, ymin, ymax, zmin, zmax); } else if (optCASE == 1) { EqualPartition(1, ymin, ymax, ymid); children[0]->FormBoundary(xmin, xmax, ymin, ymid, zmin, zmax); children[1]->FormBoundary(xmin, xmax, ymid, ymax, zmin, zmax); } else { EqualPartition(2, zmin, zmax, zmid); children[0]->FormBoundary(xmin, xmax, ymin, ymax, zmin, zmid); children[1]->FormBoundary(xmin, xmax, ymin, ymax, zmid, zmax); } double xc, yc, zc; for (i = 0; i < nElement; i ++) { element *elem = elemArray[i]; elem->GetCenter(xc, yc, zc); if (fabs(xmin - xmax) < 1.0e-8) xc = xmin; if (fabs(ymin - ymax) < 1.0e-8) yc = ymin; if (fabs(zmin - zmax) < 1.0e-8) zc = zmin; bool InBox; InBox = children[0]->PointInBox(xc, yc, zc); if (InBox) { children[0]->AddnElement(); } else { children[1]->AddnElement(); } } int nElem = 0; for (i = 0; i < nChild; i ++) { int elem = children[i]->GetnElement(); if (elem == 0) { /* cout << "one of children is empty\n"; */ for (j = 0; j < nChild; j ++) children[j] = 0; return; } nElem += elem; } if (nElem != nElement) { cout << "Error : Mother is not splitted into children" << endl; cout << nElem << " " << nElement << endl; exit(1); } for (i = 0; i < nChild; i ++) { children[i]->SetMother(this); children[i]->Initialize(); } set child0; child0.clear(); set child1; child1.clear(); for (i = 0; i < nElement; i ++) { element *elem = elemArray[i]; elem->GetCenter(xc, yc, zc); if (fabs(xmin - xmax) < 1.0e-8) xc = xmin; if (fabs(ymin - ymax) < 1.0e-8) yc = ymin; if (fabs(zmin - zmax) < 1.0e-8) zc = zmin; bool InBox; InBox = children[0]->PointInBox(xc, yc, zc); if (InBox) { // children[0]->InsertElement(elem); child0.insert(elem); } else { // children[1]->InsertElement(elem); child1.insert(elem); } } int cntt=0; for( typename set::iterator it= child0.begin() ; it!=child0.end(); it++){ children[0]->elemArray[cntt]= *it; cntt++; } cntt=0; for(typename set::iterator it=child1.begin();it!=child1.end();it++){ children[1]->elemArray[cntt]= *it; cntt++; } child0.clear(); child1.clear(); } template void group::PartitionMultiLevelSVD(int grpsize, int &numGrp) { int i; if (nElement <= grpsize){ if (nElement != 0) { FormBox(); numGrp ++; } return; } FormBox(); MakeChildren(); int noChild = 0; for (i = 0; i < nChild; i ++) { if (children[i] != 0) children[i]->PartitionMultiLevelSVD(grpsize, numGrp); else noChild = 1; } if (noChild && nElement != 0) { FormBox(); numGrp ++; return; } } template void group::BuildGroupBarray() { int i, j; for (i = 0; i < nElement; i ++) { element *elem = elemArray[i]; int edgeNum = 3; for (j = 0; j < edgeNum; j ++) { int id = elem->GetEdgePtr(j)->GetId(); int VALID = elem->GetEdgePtr(j)->GetNegativeId(); if (id < 0 || VALID != -1) continue; elem->GetEdgePtr(j)->SetNegativeId(-2); nBasis ++; if (id < IdMin) IdMin = id; if (id > IdMax) IdMax = id; } } bArray = new int [nBasis]; int cnt = 0; for (i = 0; i < nElement; i ++) { element *elem = elemArray[i]; int edgeNum = 3; for (j = 0; j < edgeNum; j ++) { int id = elem->GetEdgePtr(j)->GetId(); int VALID = elem->GetEdgePtr(j)->GetNegativeId(); if (id < 0 || VALID != -2) continue; elem->GetEdgePtr(j)->SetNegativeId(1); bArray[id - IdMin] = id; cnt ++; } } basisBuilt = true; } // Combine the children unknown IDs into mother template void group::BuildMotherBarray() { if (mother == 0) return; bool built = mother->IsBasisBuilt(); if ( built ) return; group **grp = mother->GetChildren(); int n1 = grp[0]->GetnBasis(); int n2 = grp[1]->GetnBasis(); if (n1 == 0 || n2 == 0) return; int *ID1 = grp[0]->GetbArray(); int *ID2 = grp[1]->GetbArray(); int n = n1 + n2; mother->SetnBasis(n); int *array = new int [n]; int min1 = grp[0]->GetMinId(); int min2 = grp[1]->GetMinId(); int min = (min1 < min2) ? min1 : min2; int max1 = grp[0]->GetMaxId(); int max2 = grp[1]->GetMaxId(); int max = (max1 > max2) ? max1 : max2; int i; for (i = 0; i < n1; i ++) array[ID1[i] - min] = ID1[i]; for (i = 0; i < n2; i ++) array[ID2[i] - min] = ID2[i]; mother->SetbArray(array); mother->SetBasisBuilt(); mother->SetMinId(min); mother->SetMaxId(max); mother->BuildMotherBarray(); } template void group::findGroup(group **grp) { int cnt = 0; findGroupHelper(cnt, grp, this); } template void group::findGroupHelper(int &cnt, group **grp, group *mgp) { int flag = 0; if (mgp->children[0] == 0) flag = 1; else findGroupHelper(cnt, grp, mgp->children[0]); if (mgp->children[1] == 0) { if (flag == 1 && mgp->GetnElement() != 0) grp[cnt++] = mgp; } else findGroupHelper(cnt, grp, mgp->children[1]); } #endif