// MAUS WARNING: THIS IS LEGACY CODE. #include "Interface/TriangularMesh.hh" #include "Utils/Exception.hh" #include #include #include //////////// TriangularMesh /////////////// TriangularMesh::TriangularMesh(std::string qHullFileName, std::string qHullFileType) { if(qHullFileType == "points") ReadPointsFromQHull(qHullFileName); if(qHullFileType == "mesh") ReadPointsFromQHull(qHullFileName); if(qHullFileType == "tesselation") ReadPointsFromQHull(qHullFileName); } TriangularMesh::TriangularMesh(int numberOfPoints, int numberOfDimensions, double ** thePoints, double* min, double* max) : nDims(numberOfDimensions), points(), simplices() {///nd if(numberOfDimensions==2) { AddCorners(min, max); for(int i=0; i0) delete allSimplices[0]; for(unsigned int i=0; icoords; delete points[i]; } } void TriangularMesh::ReadPointsFromQHull(std::string fileName) { std::ifstream fin(fileName.c_str()); int nPoints; std::string line; std::stringstream in(""); getline(fin, line); in << line; in >> nDims; fin >> nPoints; points = std::vector(nPoints); for(int i=0; icoords = new double[nDims]; for(int j=0; j> points[i]->coords[j]; } if(!fin) throw(MAUS::Exceptions::Exception(MAUS::Exceptions::recoverable, "Error reading file", "QHullIO::ReadQHullInputFile")); fin.close(); } void TriangularMesh::ReadMeshFromQHull(std::string fileName) { std::ifstream fin(fileName.c_str()); int nSimplices; std::string line; std::stringstream in(""); getline(fin, line); in << line; in >> nSimplices; int nVertices = nDims+1; for(int i=0; i> pointIndex; simplexPoints[j] = points[pointIndex]; } simplices.push_back(new Simplex(this, simplexPoints)); } if(!fin) throw(MAUS::Exceptions::Exception(MAUS::Exceptions::recoverable, "Error reading file", "QHullIO::ReadQHullInputFile")); fin.close(); } void TriangularMesh::WriteQHullInput(std::string fileName) { std::ofstream fout(fileName.c_str()); int nPoints = points.size(); fout << nDims << " #QHull Input by G4MICE\n" << nPoints << "\n"; for(int i=0; icoords[j] << " "; fout << "\n"; } if(!fout) throw(MAUS::Exceptions::Exception(MAUS::Exceptions::recoverable, "Error writing file", "TriangularMesh::WriteQHullInput")); fout.close(); } void TriangularMesh::ReadTessFromQHull(std::string fileName) { std::ifstream fin(fileName.c_str()); int nHulls, nSites, dummy; std::string line; std::stringstream in(""); getline(fin, line); in << line; in >> nDims; fin >> nSites >> nHulls >> dummy; hullPoints = std::vector(nSites); hulls = std::vector(nHulls); for(int i=0; icoords = new double[nDims]; for(int j=0; j> hullPoints[i]->coords[j]; } for(int i=0; i> nPoints; std::vector myHullPoints(nPoints); std::cout << "Reading hull " << i << " ** "; for(int j=0; j> pointIndex; myHullPoints[j] = hullPoints[pointIndex]; std:: cout << pointIndex << " "; } std::cout << std::endl; hulls[i] = new Hull(this, myHullPoints, NULL); } if(!fin) throw(MAUS::Exceptions::Exception(MAUS::Exceptions::recoverable, "Error reading file", "QHullIO::ReadQHullInputFile")); fin.close(); } void TriangularMesh::Position(const Mesh::Iterator& it, double * position) const { position = points[it._state[0]]->coords; } void TriangularMesh::AddCorners(double* min, double* max) { for(int i=0; i<4; i++) { points.push_back(new Point(nDims)); points[i]->coords = new double[2]; } points[0]->coords[0] = min[0]; points[0]->coords[1] = min[1]; points[1]->coords[0] = min[0]; points[1]->coords[1] = max[1]; points[2]->coords[0] = max[0]; points[2]->coords[1] = max[1]; points[3]->coords[0] = max[0]; points[3]->coords[1] = min[1]; //what about the boundaries that only have one adjacent? Point* pointsSimp1[3] = {points[0], points[1], points[2]}; simplices.push_back( new Simplex(this, pointsSimp1 ) ); Point* pointsSimp2[3] = {points[0], points[3], points[2]}; simplices.push_back( new Simplex(this, pointsSimp2 ) ); } std::vector TriangularMesh::ConnectedPoints(TriangularMesh::Point* point) { std::vector nn; for(size_t i=0; isimplices.size(); i++) {//loop over points that are nearest neighbours of this point TriangularMesh::Simplex* s = point->simplices[i]; for(int j=0; j<3; j++) { if(&s->MyPoint(j) != point) nn.push_back(point); } } return nn; } void TriangularMesh::AddPoint_Delaunay(double * point) { points.push_back(new Point(nDims)); points.back()->coords = point; //Find bounding edges surrounding point for(std::list::iterator it = simplices.begin(); it!=simplices.end(); ++it) if( (*it)->IsInside(*points.back()) ) (*it)->AddPoint(*points.back()); } void TriangularMesh::AddPoint_NoChecking(double * point) { points.push_back(new Point(nDims)); points.back()->coords = point; //Find bounding edges surrounding point for(std::list::iterator it = simplices.begin(); it!=simplices.end(); ++it) if( (*it)->IsInside(*points.back()) ) (*it)->AddPointNoChecking(*points.back()); } void TriangularMesh::AddPoint_NoTriangulation(double * point) { points.push_back(new Point(nDims)); points.back()->coords = point; } void TriangularMesh::BarycentricCoordinates(const Point& test, const Point& apex, const Point& end0, const Point& end1, double baryCoords[2]) { Point vec0 = end0 - apex; Point vec1 = end1 - apex; Point vecT = test - apex; double dot00 = vec0.dot(vec0); double dot01 = vec0.dot(vec1); double dot0T = vec0.dot(vecT); double dot11 = vec1.dot(vec1); double dot1T = vec1.dot(vecT); double inverse = 1 / (dot00 * dot11 - dot01 * dot01); baryCoords[0] = (dot11 * dot0T - dot01 * dot1T) * inverse; baryCoords[1] = (dot00 * dot1T - dot01 * dot0T) * inverse; delete [] vec0.coords; delete [] vec1.coords; delete [] vecT.coords; } std::list TriangularMesh::GetSimplices() const { std::list leaves; for(std::list::const_iterator it = simplices.begin(); it!=simplices.end(); ++it) { std::list childTris = (*it)->GetLeaves(); leaves.insert(leaves.begin(), childTris.begin(), childTris.end()); } return leaves; } void TriangularMesh::RemoveSimplex(Simplex* tri) { for(std::vector::iterator it = allSimplices.begin(); itsimplices.push_back(&Simplex); } void TriangularMesh::Point::RemoveSimplex(Simplex& aSimplex) { for(std::vector::iterator it=simplices.begin(); itPositionDimension()) { f_parent = parent; f_point = new Point*[nDims+1]; f_parent->AddSimplex(this); for(int i=0; iInsertSimplex(*this); CalcCircleCoords(); } TriangularMesh::Simplex::~Simplex() { f_parent->RemoveSimplex(this); for(int i=0; iRemoveSimplex(*this); delete [] f_point; delete [] circleX; } TriangularMesh::Point& TriangularMesh::Simplex::MyPointCyclic(int i) const { i -= (nDims+1)*( i/(nDims+1) ); return *f_point[i]; } TriangularMesh::Simplex& TriangularMesh::Simplex::FindLeaf(Point& test) { if(IsLeaf()) return *this; for(std::list::const_iterator it = f_children.begin(); it!=f_children.end(); ++it) if( (*it)->IsInside(test) ) return (*it)->FindLeaf(test); throw(MAUS::Exceptions::Exception(MAUS::Exceptions::recoverable, "Failed to find test point", "Simplex::FindLeaf")); } bool TriangularMesh::Simplex::IsInside(Point& test) const { double barys[2] = {0,0}; BarycentricCoordinates(test, MyPoint(0), barys); if(barys[0]>0 && barys[0]<1 && barys[1]>0 && barys[1]<1 && barys[0]+barys[1]<1) return true; return false; } bool TriangularMesh::Simplex::IsInsideCircumCircle(Point& test) const { double myRSq = 0; for(int i=0; inDims; i++) myRSq += (test.coords[i] - circleX[i])*(test.coords[i] - circleX[i]); if( myRSq > circleRSq ) return false; return true; } void TriangularMesh::Simplex::CalcCircleCoords() { double x1 = f_point[0]->coords[0]; double x2 = f_point[1]->coords[0]; double x3 = f_point[2]->coords[0]; double y1 = f_point[0]->coords[1]; double y2 = f_point[1]->coords[1]; double y3 = f_point[2]->coords[1]; double a = 2.*(+x1*(y2-y3) -x2*(y1-y3) +x3*(y1-y2) ); double bx = -(x1*x1+y1*y1)*(y2-y3) +(x2*x2+y2*y2)*(y1-y3) -(x3*x3+y3*y3)*(y1-y2); double by = +(x1*x1+y1*y1)*(x2-x3) -(x2*x2+y2*y2)*(x1-x3) +(x3*x3+y3*y3)*(x1-x2); circleX = new double[nDims]; circleX[0] = -bx/a; circleX[1] = -by/a; circleRSq = (x1-circleX[0])*(x1-circleX[0])+(y1-circleX[1])*(y1-circleX[1]); } void TriangularMesh::Simplex::BarycentricCoordinates(Point& test, Point& apex, double barys[]) const { int apexInt=0; Point *end0, *end1; while(&apex != f_point[apexInt] && apexInt < 3) apexInt++; if (apexInt == 0) {end0 = f_point[1]; end1 = f_point[2];} else if(apexInt == 1) {end0 = f_point[0]; end1 = f_point[2];} else if(apexInt == 2) {end0 = f_point[0]; end1 = f_point[1];} else throw(MAUS::Exceptions::Exception(MAUS::Exceptions::recoverable, "Trying to find BarycentricCoordinates with point not in Simplex", "Simplex::BarycentricCoordinates")); TriangularMesh::BarycentricCoordinates(test, apex, *end0, *end1, barys); } void TriangularMesh::Simplex::AddPointNoChecking(Point& newPoint) { if(IsLeaf()) { std::vector point (nDims+1); std::vector simple(nDims+1); for(int i=0; i::iterator it = f_children.begin(); it!=f_children.end(); ++it) if( (*it)->IsInside(newPoint) ) (*it)->AddPoint(newPoint); } void TriangularMesh::Simplex::AddPoint(Point& newPoint) { if(IsLeaf()) { std::vector point (nDims+1); std::vector simple(nDims+1); for(int i=0; iCheckEdge(newPoint); return; } for(std::list::iterator it = f_children.begin(); it!=f_children.end(); ++it) if( (*it)->IsInside(newPoint) ) (*it)->AddPoint(newPoint); } bool TriangularMesh::Simplex::IsVertex(Point& test) const { for(int i=0; i TriangularMesh::Simplex::GetLeaves() { if(IsLeaf()) return std::list(1, this); std::list simplices; for(std::list::const_iterator it = f_children.begin(); it!=f_children.end(); ++it) { std::list childTris = (*it)->GetLeaves(); simplices.insert(simplices.begin(), childTris.begin(), childTris.end()); } return simplices; } TriangularMesh::Simplex& TriangularMesh::Simplex::GetAdjacentSimplex(Point& opposite) { std::vector commonPoints; //shouldn't do it like this - memory reallocation is slow for(int i=0; i::iterator it=commonPoints[0]->simplices.begin(); it!=commonPoints[0]->simplices.end(); it++) { bool isCommon = true; for(unsigned int i=1; iIsVertex(*commonPoints[i]) && (*it)->IsLeaf(); if(isCommon && (*it)!=this) return *(*it); } return *this; } TriangularMesh::Point& TriangularMesh::Simplex::GetAdjacentPoint (Point& opposite) { Simplex& tri = GetAdjacentSimplex(opposite); for(int i=0; iCheckEdge(newPoint); tri2->CheckEdge(newPoint); delete [] edge; } /* Simplex& oppSimp = GetAdjacentSimplex(opposite); Point* opp[2] = {&opposite, &GetAdjacentPoint(opposite)}; //points opposite shared edge Point** point1 = new Point*[nDims+1]; Point** point2 = new Point*[nDims+1]; Simplex* tri1 = new Simplex(f_parent, point1); Simplex* tri2 = new Simplex(f_parent, point2); this-> f_children.push_back(tri1); this-> f_children.push_back(tri2); oppSimp.f_children.push_back(tri1); oppSimp.f_children.push_back(tri2); Point* oldOpp; if(opp[0] == &newPoint) oldOpp = opp[1]; else oldOpp = opp[0]; tri1->CheckEdge(newPoint); tri2->CheckEdge(newPoint); delete [] edge; */ bool TriangularMesh::Simplex::OnBoundary() { bool onBoundary = false; //GetAdjacentPoint returns test point if it can't find an adjacent point //If any points don't have an adjacent point then I am on a boundary for(int i=0; i