//================================================================================================= void Terrain::FillGeometryPart(vector<Tri>& tris, vector<Vec3>& verts, int px, int pz, const Vec3& offset) const { assert(px >= 0 && pz >= 0 && uint(px) < n_parts && uint(pz) < n_parts); verts.reserve((tiles_per_part + 1)*(tiles_per_part + 1)); for(uint z = pz*tiles_per_part; z <= (pz + 1)*tiles_per_part; ++z) { for(uint x = px*tiles_per_part; x <= (px + 1)*tiles_per_part; ++x) { verts.push_back(Vec3(x*tile_size + offset.x, h[x + z*hszer] + offset.y, z*tile_size + offset.z)); } } tris.reserve(tiles_per_part * tiles_per_part * 3); #define XZ(xx,zz) (x+(xx)+(z+(zz))*(tiles_per_part+1)) for(uint z = 0; z < tiles_per_part; ++z) { for(uint x = 0; x < tiles_per_part; ++x) { tris.push_back(Tri(XZ(0, 0), XZ(0, 1), XZ(1, 0))); tris.push_back(Tri(XZ(1, 0), XZ(0, 1), XZ(1, 1))); } } #undef XZ }
//================================================================================================= void Terrain::FillGeometry(vector<Tri>& tris, vector<Vec3>& verts) { uint vcount = (n_tiles + 1)*(n_tiles + 1); verts.reserve(vcount); for(uint z = 0; z <= (n_tiles + 1); ++z) { for(uint x = 0; x <= (n_tiles + 1); ++x) { verts.push_back(Vec3(x*tile_size, h[x + z*hszer], z*tile_size)); } } tris.reserve(n_tiles * n_tiles * 3); #define XZ(xx,zz) (x+(xx)+(z+(zz))*(n_tiles+1)) for(uint z = 0; z < n_tiles; ++z) { for(uint x = 0; x < n_tiles; ++x) { tris.push_back(Tri(XZ(0, 0), XZ(0, 1), XZ(1, 0))); tris.push_back(Tri(XZ(1, 0), XZ(0, 1), XZ(1, 1))); } } #undef XZ }
QVector<Tri> subdivide(){ QVector<Tri> faces; Vec d=((a+b)/2.0).normalized(), e=((b+c)/2.0).normalized(), f=((c+a)/2.0).normalized(); faces.push_back(Tri(a,d,f,1)); faces.push_back(Tri(d,b,e,2)); faces.push_back(Tri(f,e,c,3)); faces.push_back(Tri(d,e,f,4)); return faces; }
QString TetraGPSEncoder::generate(TGPSReal lat, TGPSReal lon, TGPSReal precMeters){ const Vec coord(cos(lat)*cos(lon), cos(lat)*sin(lon), sin(lat)); qDebug()<<"COORD:"<<coord<<coord.length()<<coord.latlon(); QVector<Tri> faces; const TGPSReal ma=(M_PI*2.0)/3.0; const Vec north( +0.0, +1.0, +0.0); const Vec prime( +0.0, +sin(-ma), +cos(-ma)); const Vec meridian2(prime.x()*cos(+ma) - prime.z()*sin(+ma), prime.y(), prime.z()*cos(+ma) + prime.x()*sin(+ma)); const Vec meridian3(prime.x()*cos(-ma) - prime.z()*sin(-ma), prime.y(), prime.z()*cos(-ma) + prime.x()*sin(-ma)); qDebug()<<"north= "<<north<<north.length(); qDebug()<<"prime= "<<prime<<prime.length(); qDebug()<<"meridian2="<<meridian2<<meridian2.length(); qDebug()<<"meridian3="<<meridian3<<meridian3.length(); faces.push_back(Tri(north,prime,meridian2, 1)); faces.push_back(Tri(north,prime,meridian3, 2)); faces.push_back(Tri(north,meridian2,meridian3, 3)); faces.push_back(Tri(prime,meridian2,meridian3, 4)); TGPSReal score=1000.0; QStringList ret; int sub=0; Tri best,second; while((score*planetRadiusMeters)>precMeters && sub++<9){ //qDebug()<<"----ROUND "<<sub<< score; TGPSReal eps=1000.0; for(auto tri:faces) { TGPSReal delta=(tri.center-coord).length(); //qDebug()<<"DELTA: "<<delta<<tri.center<<tri.center.length(); if(delta<eps){ if(delta<score){ score=delta; } eps=delta; best=tri; qDebug()<<"NEW BEST: "<<best<<"!"; } } QString name=best.name(); //if("0"==name){ break; } ret<<name; faces=best.subdivide(); if(best!=second){ second=best; } else{ break; } } TGPSReal d=(coord-best.center).length()/best.reach(); qDebug()<<"BEST: "<<best<<" with "<< d<<" normalized distance from center and " << (score*planetRadiusMeters)<<" meters after "<<sub<<" iterations"; return ret.join("."); }
main(){ //int i; liste l=NULL; liste p; l=ajouttete3(l,(double)(1),63); printf("%f,%d\n",l->duree,l->note); l=ajouttete3(l,(double)(3),62); printf("%f,%d\n",l->duree,l->note); l=ajouttete3(l,(double)(2),61); printf("%f,%d\n",l->duree,l->note); l=ajouttete3(l,(double)(24),46); printf("%f,%d\n",l->duree,l->note); l=ajouttete3(l,(double)(0),78); printf("%f,%d\n",l->duree,l->note); l=ajouttete3(l,(double)(3),61); printf("%f,%d\n",l->duree,l->note); l=ajouttete3(l,(double)(3),61); printf("%f,%d\n",l->duree,l->note); l=ajouttete3(l,(double)(3),61); printf("%f,%d\n",l->duree,l->note); l=Tri(&l); for(p=l;p;p=p->suiv){ printf("t %f,%d\n",p->duree,p->note); } }
U0 DrawQuail(CTask *,CDC *dc) { I64 i; U8 *inter; F64 tt,t1=tT-t0; SpritePlot3(dc,0,SKY_HEIGHT,0,$IB,"<4>",4$); for (i=0;i<NUM_QUAIL;i++) { tt=Tri(t1+q[i].phase,1.0); if (q[i].dead) { q[i].x+=(t1-t_last)*q[i].dx; q[i].y+=50*(t1-t_last); if (q[i].y>SKY_HEIGHT) { q[i].y=SKY_HEIGHT; q[i].dx=0; } SpritePlot3(dc,q[i].x,q[i].y,0,$IB,"<3>",3$); } else { q[i].x+=(t1-t_last)*q[i].dx; q[i].y+=(t1-t_last)*q[i].dy; if (!(0<q[i].y<SKY_HEIGHT-20)) { q[i].dy=-q[i].dy; q[i].y+=(t1-t_last)*q[i].dy; } inter=SpriteInterpolate($IB,"<1>",1$,$IB,"<2>",2$,tt); SpritePlot3(dc,q[i].x,q[i].y,0,inter); Free(inter); if (q[i].x>0 && t1-t_last>10*Rand) q[i].dead=TRUE; } } t_last=t1; }
U0 DrawIt(CTask *,CDC *dc) { I64 i; F64 dt=tMBeat%8.0,z,w,x1,y1,z1,x2,y2,z2; Bool first=TRUE; DCAllocDepthBuf(dc); dc->flags|=DCF_TRANSFORMATION; dc->x=30*dt+20.0*Sin(dt)+25; dc->y=10*dt-15; dc->z=GR_Z_ALL; GrRotXEqu(dc->r,0.75*dt); GrRotYEqu(dc->r,0.45*dt); GrRotZEqu(dc->r,0.50*dt); GrScaleMatEqu(dc->r,0.5); for (i=-50;i<40;i+=2) { if (i&2) dc->color=LTGRAY; else dc->color=DKGRAY; z=10*Cos(i/10.0*ã/8.0)*Cos(dt); w=Tri(100+i,200); x1=i-3;y1=0;z1=z; if (-30<=i<=40) { GrLine3(dc,i,-10*w,z,i-3,0,z); GrLine3(dc,i,+10*w,z,i-3,0,z); } if (!first) { dc->color=DKGRAY; GrLine3(dc,x1,y1,z1,x2,y2,z2); } x2=x1;y2=y1;z2=z1; first=FALSE; } }
void EEMS::calc_between(const VectorXi &mColors, const VectorXd &mEffcts, const double mrateMu, MatrixXd &Binv) const { // d is the number of demes in the graph (observed or not) if (Binv.rows()!=d||Binv.cols()!=d) { Binv.resize(d,d); } // A sparse matrix of migration rates will be constructed on the fly // First a triplet (a,b,m) is added for each edge (a,b) // I have decided to construct the sparse matrix rather than update it // because a single change to the migration Voronoi tessellation can // change the migration rate of many edges simultaneously vector<Tri> coefficients; int alpha, beta; // For every edge in the graph -- it does not matter whether demes are observed or not // as the resistance distance takes into consideration all paths between a and b // to produces the effective resistance B(a,b) for ( int edge = 0 ; edge < graph.get_num_edges() ; edge++ ) { graph.get_edge(edge,alpha,beta); // On the log10 scale, log10(m_alpha) = mrateMu + m_alpha = mrateMu + m_tile(tile_alpha) // On the log10 scale, log10(m_beta) = mrateMu + m_beta = mrateMu + m_tile(tile_beta) double log10m_alpha = mrateMu + mEffcts(mColors(alpha)); double log10m_beta = mrateMu + mEffcts(mColors(beta)); // Then on the original scale, m(alpha,beta) = (10^m_alpha + 10^m_beta)/2 double m_ab = 0.5 * pow(10.0,log10m_alpha) + 0.5 * pow(10.0,log10m_beta); // The graph is undirected, so m(alpha->beta) = m(beta->alpha) coefficients.push_back(Tri(alpha,beta,m_ab)); coefficients.push_back(Tri(beta,alpha,m_ab)); } SpMat sparseM(d,d); // Actually construct and fill in the sparse matrix sparseM.setFromTriplets(coefficients.begin(),coefficients.end()); // Initialize a dense matrix from the sparse matrix MatrixXd M = MatrixXd(sparseM); // Read S1.4 Computing the resistance distances in the Supplementary // This computation is specific to the resistance distance metric // but the point is that we have a method to compute the between // demes component of the expected genetic dissimilarities from // the sparse matrix of migration rates // Here instead of B, we compute its inverse Binv MatrixXd Hinv = - M; Hinv.diagonal() += M.rowwise().sum(); Hinv.array() += 1.0; if (o==d) { Binv = -0.5 * Hinv; // If all the demes are observed, it is quite easy to compute Binv } else { Binv = -0.5 * Hinv.topLeftCorner(o,o); Binv += 0.5 * Hinv.topRightCorner(o,d-o) * Hinv.bottomRightCorner(d-o,d-o).selfadjointView<Lower>().llt().solve(Hinv.bottomLeftCorner(d-o,o)); } // The constant is slightly different for haploid and diploid species Binv *= Binvconst; }
void ATO::Integrator<T>::trisFromPoly( std::vector< Vector3D >& points, std::vector< Tri >& tris, Teuchos::RCP<MiniPoly> poly) /******************************************************************************/ { std::vector<Vector3D>& polyPoints = poly->points; uint nPoints = polyPoints.size(); if(nPoints < 3) return; // find centerpoint Vector3D center(polyPoints[0]); for(uint i=1; i<nPoints; i++) center += polyPoints[i]; center /= nPoints; // sort by counterclockwise angle about surface normal T pi = acos(-1.0); Vector3D X(polyPoints[0]-center); T xnorm = Intrepid::norm(X); X /= xnorm; Vector3D X1(polyPoints[1]-center); Vector3D Z = Intrepid::cross(X, X1); T znorm = Intrepid::norm(Z); Z /= znorm; Vector3D Y = Intrepid::cross(Z, X); std::map<T, uint> angles; angles.insert( std::pair<T, uint>(0.0,0) ); for(int i=1; i<nPoints; i++){ Vector3D comp = polyPoints[i] - center; T compnorm = Intrepid::norm(comp); comp /= compnorm; T prod = X*comp; T angle = acos((float)prod); if( Y * comp < 0.0 ) angle = 2.0*pi - angle; angles.insert( std::pair<T, uint>(angle,i) ); } // append points int offset = points.size(); for(int pt=0; pt<nPoints; pt++){ points.push_back(polyPoints[pt]); } // create tris if( angles.size() > 2 ){ typename std::map<T,uint>::iterator it=angles.begin(); typename std::map<T,uint>::iterator last=angles.end(); std::advance(last,-1); // skip last point int iP = it->second; it++; while(it != last){ int i1 = it->second; it++; int i2 = it->second; tris.push_back(Tri(iP+offset,i1+offset,i2+offset)); } } }
int main(int argc, char ** argv){ Triangle Tri(1, 1, 3, 5, 6); Square Sq(1, 2, 5); Circle Cir(1, 3, 2); Sphere Sph(1, 4, 2); Cube Cub(1, 5, 5); Tetrahedron Tetra(1, 6, 10, 10, 10, 10, 10, 10); Cube Cub2(1, 7, 100); Square Sq2(1, 8, 100); Circle Cir2(1, 9, 25); Circle Cir3(1, 10, 45.2); Square Sq3(1, 11, 11.11); Shape * arr; arr = new Shape[11]; arr[0] = Tri; arr[1] = Sq; arr[2] = Cir; arr[3] = Sph; arr[4] = Cub; arr[5] = Tetra; arr[6] = Cub2; arr[7] = Sq2; arr[8] = Cir2; arr[9] = Cir3; arr[10] = Sq3; for(int i = 0; i < 11; ++i){ cout << endl; if(arr[i].getVolume() == -1){ cout << "2-D Shape Found" << endl; cout << "The Shape is: " << arr[i].getName() << endl; cout << "Points are: (" << arr[i].getX() << ", " << arr[i].getY() << ")" << endl; cout << "The Area is: " << arr[i].getArea() << endl; } else{ cout << "3-D Shape Found" << endl; cout << "The Shape is: " << arr[i].getName() << endl; cout << "Points are: (" << arr[i].getX() << ", " << arr[i].getY() << ")" << endl; cout << "The Surface Area is: " << arr[i].getArea() << endl; cout << "The Volume is: " << arr[i].getVolume() << endl; } cout << endl << endl; } delete[] arr; return 0; }
int main() { int i; while (scanf("%d%d%d",&n,&m,&q)!=EOF) { memset(count,0,sizeof(count)); makeset(n,m); for (i=1;i<=q;i++) { char name[10]; scanf("%s%d%d",name,&opt[i].x,&opt[i].y); opt[i].s=name[0]; switch (opt[i].s) { case 'C':scanf("%d%d",&opt[i].l,&opt[i].c); break; case 'D':scanf("%d%d",&opt[i].l,&opt[i].c); break; case 'R':scanf("%d%d%d",&opt[i].l,&opt[i].w,&opt[i].c); break; case 'T':scanf("%d%d",&opt[i].w,&opt[i].c); break; } } for (i=q;i>0;i--) { switch (opt[i].s) { case 'C':Cir(opt[i].x,opt[i].y,opt[i].l,opt[i].c); break; case 'D':Dia(opt[i].x,opt[i].y,opt[i].l,opt[i].c); break; case 'R':Rec(opt[i].x,opt[i].y,opt[i].l,opt[i].w,opt[i].c); break; case 'T':Tri(opt[i].x,opt[i].y,opt[i].w,opt[i].c); break; } } for (i=1;i<=9;i++) if (i==9) printf("%d\n",count[i]); else printf("%d ",count[i]); } return 0; }
void LR(int *M, int m, int n, TypeCellule **U, TypeCellule** PI,int l, int d) { int i,j; int picked=0; // le numero du job que on selecte apairtir du U int k=0,it=0,at=0,xi=INT_MAX; //k est le nb des jobs qui est dans PI, it est idletime, at=C_m+C_lamda, xi est le resultat de la fonction d'index int K[m]; //initiale du K, K est une tableau de 3 , K[i] pour machine i int J[m]; // pour calculer le Cm pour le job courant float Lamda[m],moyenne; //Lamda est un tableau du 3, pour calculer le Cm pour le job lamda (qui est le moyenne des job U-{j}) TypeCellule * L=NULL; //U est une liste pour les jobs dont l'ordre est pas encore déterminé TypeCellule * p=NULL,* pp=NULL, *ppp=NULL; //pointeurs servent à l'itération for(i=0;i<m;i++)K[i]=0; k=0; for(i=0;i<n;i++)*U=Append(*U,i,1000); p=*U; while(p!=NULL) //pour chaque element dans U { j=p->job[0]; //job[0] est le numero du job courant, job[1] est Cm du job courant it=0; at=0; for(i=0;i<m;i++) //initiation du tableau J { J[i]=*(M+i*n+j); Lamda[i]=0; } pp=*U; moyenne=0; //nb des jobs (sauf job j) dans U /*l'initiation du tableau Lamda*/ while(pp!=NULL) { if(pp->job[0]==j)pp=pp->suivant; else { moyenne++; for(i=0;i<m;i++) { Lamda[i]+=(int)(*(M+i*n+pp->job[0])); } pp=pp->suivant; } } if(moyenne>0) { for(i=0;i<m;i++) { Lamda[i]=Lamda[i]/moyenne; } } /* Fin de l'initiation du tableau Lamda*/ /*Mis a jour du tableau J et tableau Lamda*/ J[0]+=K[0]; Lamda[0]+=J[0]; for(i=1;i<m;i++) { if(K[i]<J[i-1]) { it+=(m*(J[i-1]-K[i]))/((i+1)+k*(m-i-1)/(n-2)); //on calcule le idle time for job j J[i]+=J[i-1]; //mis a jour le temps de finir pour le job j dans la machine i } else { it+=(m*0)/((i+1)+k*(m-i-1)/(n-2)); J[i]=K[i]+J[i]; } if(J[i]<Lamda[i-1])Lamda[i]+=Lamda[i-1]; else Lamda[i]+=J[i]; } at=J[m-1]+Lamda[m-1]; ////mis a jour le temps de finir pour le job lamda dans la machine i p->job[1]=(n-k-2)*it+at; p=p->suivant; } L = Tri(*U); ppp=L; for(i=0;i<l;i++) { if(ppp->suivant!=NULL) ppp=ppp->suivant; } picked=ppp->job[0]; Liveration(&L); L = NULL; /*mis a jour du tableau K*/ K[0]=(int)*(M+0*n+picked); //tableau K conserve le Ci de les k jobs (dont l'ordre est determine) for(i=1;i<m;i++) { if(K[i]<K[i-1])K[i]=K[i-1]+(int)(*(M+i*n+picked)); else K[i]=(int)(*(M+i*n+picked)); } *U=Supprime(*U,picked); //on supprime le job selecté dans U *PI=Append(*PI,picked,K[m-1]); //on ajoute le job seletcé dans PI k++; // l'algo commence while(k<d) { xi=INT_MAX; p=*U; while(p!=NULL) //pour chaque element dans U { j=p->job[0]; //job[0] est le numero du job courant, job[1] est Cm du job courant it=0; at=0; for(i=0;i<m;i++) //initiation du tableau J { J[i]=*(M+i*n+j); Lamda[i]=0; } pp=*U; moyenne=0; //nb des jobs (sauf job j) dans U /*l'initiation du tableau Lamda*/ while(pp!=NULL) { if(pp->job[0]==j)pp=pp->suivant; else { moyenne++; for(i=0;i<m;i++) { Lamda[i]+=(int)(*(M+i*n+pp->job[0]));//M[i][pp->job[0]]; } pp=pp->suivant; } } if(moyenne>0) { for(i=0;i<m;i++) { Lamda[i]=Lamda[i]/moyenne; } } /* Fin de l'initiation du tableau Lamda*/ /*Mis a jour du tableau J et tableau Lamda*/ J[0]+=K[0]; Lamda[0]+=J[0]; for(i=1;i<m;i++) { if(K[i]<J[i-1]) { it+=(m*(J[i-1]-K[i]))/((i+1)+k*(m-i-1)/(n-2)); //on calcule le idle time for job j J[i]+=J[i-1]; //mis a jour le temps de finir pour le job j dans la machine i } else { it+=(m*0)/((i+1)+k*(m-i-1)/(n-2)); J[i]=K[i]+J[i]; } if(J[i]<Lamda[i-1])Lamda[i]+=Lamda[i-1]; else Lamda[i]+=J[i]; } at=J[m-1]+Lamda[m-1]; ////mis a jour le temps de finir pour le job lamda dans la machine i p->job[1]=(n-k-2)*it+at; if(p->job[1]<xi) { xi=p->job[1]; //on calcule le resultat de la fonction d'index picked=j; // on prend le job qui a le plus petite valeur du xi } p=p->suivant; //on passe à la job suivant qui est dans U } /*mis a jour du tableau K*/ /*Modif Comme LR.c OK*/ K[0]+=(int)(*(M+0*n+picked)); //tableau K conserve le Ci de les k jobs (dont l'ordre est determine) /*fin comme lr.c*/ for(i=1;i<m;i++) { if(K[i]<K[i-1]) { K[i]=K[i-1]+(int)(*(M+i*n+picked)); } else K[i]=K[i]+(int)(*(M+i*n+picked)); } *U=Supprime(*U,picked); //on supprime le job selecté dans U *PI=Append(*PI,picked,K[m-1]); //on ajoute le job seletcé dans PI k++; } }
//-***************************************************************************** void MeshDrwHelper::update( P3fArraySamplePtr iP, V3fArraySamplePtr iN, Int32ArraySamplePtr iIndices, Int32ArraySamplePtr iCounts, Abc::Box3d iBounds ) { // Before doing a ton, just have a quick look. if ( m_meshP && iP && ( m_meshP->size() == iP->size() ) && m_meshIndices && ( m_meshIndices == iIndices ) && m_meshCounts && ( m_meshCounts == iCounts ) ) { if ( m_meshP == iP ) { updateNormals( iN ); } else { update( iP, iN ); } return; } // Okay, if we're here, the indices are not equal or the counts // are not equal or the P-array size changed. // So we can clobber those three, but leave N alone for now. m_meshP = iP; m_meshIndices = iIndices; m_meshCounts = iCounts; m_triangles.clear (); // Check stuff. if ( !m_meshP || !m_meshIndices || !m_meshCounts ) { std::cerr << "Mesh update quitting because no input data" << std::endl; makeInvalid(); return; } // Get the number of each thing. size_t numFaces = m_meshCounts->size(); size_t numIndices = m_meshIndices->size(); size_t numPoints = m_meshP->size(); if ( numFaces < 1 || numIndices < 1 || numPoints < 1 ) { // Invalid. std::cerr << "Mesh update quitting because bad arrays" << ", numFaces = " << numFaces << ", numIndices = " << numIndices << ", numPoints = " << numPoints << std::endl; makeInvalid(); return; } // Make triangles. size_t faceIndexBegin = 0; size_t faceIndexEnd = 0; for ( size_t face = 0; face < numFaces; ++face ) { faceIndexBegin = faceIndexEnd; size_t count = (*m_meshCounts)[face]; faceIndexEnd = faceIndexBegin + count; // Check this face is valid if ( faceIndexEnd > numIndices || faceIndexEnd < faceIndexBegin ) { std::cerr << "Mesh update quitting on face: " << face << " because of wonky numbers" << ", faceIndexBegin = " << faceIndexBegin << ", faceIndexEnd = " << faceIndexEnd << ", numIndices = " << numIndices << ", count = " << count << std::endl; // Just get out, make no more triangles. break; } // Checking indices are valid. bool goodFace = true; for ( size_t fidx = faceIndexBegin; fidx < faceIndexEnd; ++fidx ) { if ( ( size_t ) ( (*m_meshIndices)[fidx] ) >= numPoints ) { std::cout << "Mesh update quitting on face: " << face << " because of bad indices" << ", indexIndex = " << fidx << ", vertexIndex = " << (*m_meshIndices)[fidx] << ", numPoints = " << numPoints << std::endl; goodFace = false; break; } } // Make triangles to fill this face. if ( goodFace && count > 2 ) { m_triangles.push_back( Tri( ( unsigned int )(*m_meshIndices)[faceIndexBegin+0], ( unsigned int )(*m_meshIndices)[faceIndexBegin+1], ( unsigned int )(*m_meshIndices)[faceIndexBegin+2] ) ); for ( size_t c = 3; c < count; ++c ) { m_triangles.push_back( Tri( ( unsigned int )(*m_meshIndices)[faceIndexBegin+0], ( unsigned int )(*m_meshIndices)[faceIndexBegin+c-1], ( unsigned int )(*m_meshIndices)[faceIndexBegin+c] ) ); } } } // Cool, we made triangles. // Pretend the mesh is made... m_valid = true; // And now update just the P and N, which will update bounds // and calculate new normals if necessary. if ( iBounds.isEmpty() ) { computeBounds(); } else { m_bounds = iBounds; } updateNormals( iN ); // And that's it. }
stetmesh::Tri stetmesh::Tet::getTri(uint i) const { assert (i<=3); uint triidx = pTetmesh->_getTetTriNeighb(pTidx)[i]; return (Tri(pTetmesh, triidx)); }