/** * \param mesh pointer toward the mesh structure. * \param list pointer toward the ball of the point to collapse. * \return 1. * * Collapse edge \f$list[0]%3\f$ in tet \f$list[0]/3\f$ (\f$ ip->i1\f$ ) for a * ball of the collapsed point of size 3: the collapsed point is removed. * */ int colver3(MMG5_pMesh mesh,int* list) { MMG5_pTria pt,pt1,pt2; int *adja,iel,jel,kel,mel,ip; char i,i1,j,j1,j2,k,m; /* update of new point for triangle list[0] */ iel = list[0] / 3; i = list[0] % 3; i1 = _MMG5_inxt2[i]; pt = &mesh->tria[iel]; ip = pt->v[i]; jel = list[1] / 3; j = list[1] % 3; j1 = _MMG5_inxt2[j]; j2 = _MMG5_iprv2[j]; pt1 = &mesh->tria[jel]; kel = list[2] / 3; k = list[2] % 3; pt2 = &mesh->tria[kel]; /* update info */ pt1->v[j] = pt->v[i1]; pt1->tag[j1] |= pt2->tag[k]; pt1->edg[j1] = MG_MAX(pt1->edg[j1],pt2->edg[k]); pt1->tag[j2] |= pt->tag[i]; pt1->edg[j2] = MG_MAX(pt1->edg[j2],pt->edg[i]); pt1->base = mesh->base; /* update neighbours of new triangle */ adja = &mesh->adja[3*(jel-1)+1]; adja[j1] = mesh->adja[3*(kel-1)+1+k]; adja[j2] = mesh->adja[3*(iel-1)+1+i]; mel = adja[j2] / 3; if ( mel ) { m = adja[j2] % 3; pt = &mesh->tria[mel]; pt->tag[m] = pt1->tag[j2]; pt->edg[m] = pt1->edg[j2]; mesh->adja[3*(mel-1)+1+m] = 3*jel + j2; } mel = adja[j1] / 3; if ( mel ) { m = adja[j1] % 3; pt = &mesh->tria[mel]; pt->tag[m] = pt1->tag[j1]; pt->edg[m] = pt1->edg[j1]; mesh->adja[3*(mel-1)+1+m] = 3*jel + j1; } /* remove vertex + elements */ _MMG5_delPt(mesh,ip); _MMG5_delElt(mesh,iel); _MMG5_delElt(mesh,kel); return(1); }
/** * \param mesh pointer toward the mesh structure. * \param np number of vertices. * \param nt number of triangles. * \param na number of edges. * \return 0 if failed, 1 otherwise. * * Set the number of vertices, triangles and edges of the * mesh and allocate the associated tables. If call twice, reset the * whole mesh to realloc it at the new size * */ int MMGS_Set_meshSize(MMG5_pMesh mesh, int np, int nt, int na) { int k; if ( ( (mesh->info.imprim > 5) || mesh->info.ddebug ) && ( mesh->point || mesh->tria || mesh->edge) ) fprintf(stdout," ## Warning: new mesh\n"); mesh->np = np; mesh->nt = nt; mesh->na = na; mesh->npi = mesh->np; mesh->nti = mesh->nt; mesh->nai = mesh->na; if ( mesh->point ) _MMG5_DEL_MEM(mesh,mesh->point,(mesh->npmax+1)*sizeof(MMG5_Point)); if ( mesh->tria ) _MMG5_DEL_MEM(mesh,mesh->tria,(mesh->nt+1)*sizeof(MMG5_Tria)); if ( mesh->edge ) _MMG5_DEL_MEM(mesh,mesh->edge,(mesh->na+1)*sizeof(MMG5_Edge)); /*tester si -m defini : renvoie 0 si pas ok et met la taille min dans info.mem */ if( mesh->info.mem > 0) { if ( mesh->npmax < mesh->np || mesh->ntmax < mesh->nt) { _MMGS_memOption(mesh); // printf("pas de pbs ? %d %d %d %d %d %d -- %d\n",mesh->npmax,mesh->np, // mesh->ntmax,mesh->nt,mesh->nemax,mesh->ne,mesh->info.mem); if ( mesh->npmax < mesh->np || mesh->ntmax < mesh->nt) { fprintf(stdout,"not enough memory: np : %d %d nt : %d %d \n" ,mesh->npmax,mesh->np, mesh->ntmax,mesh->nt); return(0); } } else if(mesh->info.mem < 39) { printf("not enough memory %d\n",mesh->info.mem); return(0); } } else { mesh->npmax = MG_MAX(1.5*mesh->np,_MMG5_NPMAX); mesh->ntmax = MG_MAX(1.5*mesh->nt,_MMG5_NTMAX); } _MMG5_ADD_MEM(mesh,(mesh->npmax+1)*sizeof(MMG5_Point),"initial vertices", printf(" Exit program.\n"); exit(EXIT_FAILURE)); _MMG5_SAFE_CALLOC(mesh->point,mesh->npmax+1,MMG5_Point); _MMG5_ADD_MEM(mesh,(mesh->ntmax+1)*sizeof(MMG5_Tria),"initial triangles",return(0)); _MMG5_SAFE_CALLOC(mesh->tria,mesh->ntmax+1,MMG5_Tria); mesh->namax = mesh->na; if ( mesh->na ) { _MMG5_ADD_MEM(mesh,(mesh->na+1)*sizeof(MMG5_Edge),"initial edges",return(0)); _MMG5_SAFE_CALLOC(mesh->edge,(mesh->na+1),MMG5_Edge); }
/** compute iso size map */ int _MMG5_DoSol(MMG5_pMesh mesh,MMG5_pSol met) { MMG5_pTetra pt; MMG5_pPoint p1,p2; double ux,uy,uz,dd; int i,k,ia,ib,ipa,ipb; int *mark; _MMG5_SAFE_CALLOC(mark,mesh->np+1,int); /* Memory alloc */ met->np = mesh->np; met->npmax = mesh->npmax; met->size = 1; met->dim = mesh->dim; _MMG5_ADD_MEM(mesh,(met->npmax*met->size+1)*sizeof(double),"solution",return(0)); _MMG5_SAFE_CALLOC(met->m,met->npmax*met->size+1,double); /* internal edges */ for (k=1; k<=mesh->ne; k++) { pt = &mesh->tetra[k]; if ( !pt->v[0] ) continue; /* internal edges */ for (i=0; i<6; i++) { ia = _MMG5_iare[i][0]; ib = _MMG5_iare[i][1]; ipa = pt->v[ia]; ipb = pt->v[ib]; p1 = &mesh->point[ipa]; p2 = &mesh->point[ipb]; ux = p1->c[0] - p2->c[0]; uy = p1->c[1] - p2->c[1]; uz = p1->c[2] - p2->c[2]; dd = sqrt(ux*ux + uy*uy + uz*uz); met->m[ipa] += dd; mark[ipa]++; met->m[ipb] += dd; mark[ipb]++; } } /* vertex size */ for (k=1; k<=mesh->np; k++) { p1 = &mesh->point[k]; if ( !mark[k] ) { met->m[k] = mesh->info.hmax; continue; } else met->m[k] = MG_MIN(mesh->info.hmax,MG_MAX(mesh->info.hmin,met->m[k] / (double)mark[k])); } _MMG5_SAFE_FREE(mark); return(1); }
/* Compute the intersected (2 x 2) metric between metrics m and n, PRESERVING the directions of m. Result is stored in mr*/ int intmetsavedir(MMG5_pMesh mesh, double *m,double *n,double *mr) { int i; double lambda[2],vp[2][2],siz,isqhmin; isqhmin = 1.0 / (mesh->info.hmin * mesh->info.hmin); _MMG5_eigensym(m,lambda,vp); for (i=0; i<2; i++) { siz = n[0]*vp[i][0]*vp[i][0] + 2.0*n[1]*vp[i][0]*vp[i][1] + n[2]*vp[i][1]*vp[i][1]; lambda[i] = MG_MAX(lambda[i],siz); lambda[i] = MG_MIN(lambda[i],isqhmin); } mr[0] = lambda[0]*vp[0][0]*vp[0][0] + lambda[1]*vp[1][0]*vp[1][0]; mr[1] = lambda[0]*vp[0][0]*vp[0][1] + lambda[1]*vp[1][0]*vp[1][1]; mr[2] = lambda[0]*vp[0][1]*vp[0][1] + lambda[1]*vp[1][1]*vp[1][1]; return(1); }
/** * \param mesh pointer toward the mesh structure. * \param met pointer toward the metric structure. * \param nump index of point in which the size must be computed. * \param lists pointer toward the surfacic ball of \a nump. * \param ilists size of surfacic ball of \a nump. * \param hmin minimal edge size. * \param hmax maximal edge size. * \param hausd hausdorff value. * \return the isotropic size at the point. * * Define isotropic size at regular point nump, whose surfacic ball is provided. * */ static double _MMG5_defsizreg(MMG5_pMesh mesh,MMG5_pSol met,int nump,int *lists, int ilists, double hmin,double hmax,double hausd) { MMG5_pTetra pt; MMG5_pxTetra pxt; MMG5_pPoint p0,p1; MMG5_Tria tt; _MMG5_Bezier b; double ux,uy,uz,det2d,h,isqhmin,isqhmax,ll,lmin,lmax,hnm,s; double *n,*t,r[3][3],lispoi[3*MMG3D_LMAX+1],intm[3],b0[3],b1[3],c[3],tAA[6],tAb[3],d[3]; double kappa[2],vp[2][2]; int k,na,nb,ntempa,ntempb,iel,ip0; char iface,i,j,i0; p0 = &mesh->point[nump]; if ( !p0->xp || MG_EDG(p0->tag) || (p0->tag & MG_NOM) || (p0->tag & MG_REQ)) { fprintf(stdout," ## Func. _MMG5_defsizreg : wrong point qualification : xp ? %d\n",p0->xp); return(0); } isqhmin = 1.0 / (hmin*hmin); isqhmax = 1.0 / (hmax*hmax); n = &mesh->xpoint[p0->xp].n1[0]; /* Step 1 : rotation matrix that sends normal n to the third coordinate vector of R^3 */ if ( !_MMG5_rotmatrix(n,r) ) { fprintf(stdout,"%s:%d: Error: function _MMG5_rotmatrix return 0\n", __FILE__,__LINE__); exit(EXIT_FAILURE); } /* Step 2 : rotation of the oriented surfacic ball with r : lispoi[k] is the common edge between faces lists[k-1] and lists[k] */ iel = lists[0] / 4; iface = lists[0] % 4; pt = &mesh->tetra[iel]; lmin = MAXLEN; lmax = 0.0; na = nb = 0; for (i=0; i<3; i++) { if ( pt->v[_MMG5_idir[iface][i]] != nump ) { if ( !na ) na = pt->v[_MMG5_idir[iface][i]]; else nb = pt->v[_MMG5_idir[iface][i]]; } } for (k=1; k<ilists; k++) { iel = lists[k] / 4; iface = lists[k] % 4; pt = &mesh->tetra[iel]; ntempa = ntempb = 0; for (i=0; i<3; i++) { if ( pt->v[_MMG5_idir[iface][i]] != nump ) { if ( !ntempa ) ntempa = pt->v[_MMG5_idir[iface][i]]; else ntempb = pt->v[_MMG5_idir[iface][i]]; } } if ( ntempa == na ) p1 = &mesh->point[na]; else if ( ntempa == nb ) p1 = &mesh->point[nb]; else if ( ntempb == na ) p1 = &mesh->point[na]; else { assert(ntempb == nb); p1 = &mesh->point[nb]; } ux = p1->c[0] - p0->c[0]; uy = p1->c[1] - p0->c[1]; uz = p1->c[2] - p0->c[2]; lispoi[3*k+1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz; lispoi[3*k+2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz; lispoi[3*k+3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz; ll = lispoi[3*k+1]*lispoi[3*k+1] + lispoi[3*k+2]*lispoi[3*k+2] + lispoi[3*k+3]*lispoi[3*k+3]; lmin = MG_MIN(lmin,ll); lmax = MG_MAX(lmax,ll); na = ntempa; nb = ntempb; } /* Finish with point 0 */ iel = lists[0] / 4; iface = lists[0] % 4; pt = &mesh->tetra[iel]; ntempa = ntempb = 0; for (i=0; i<3; i++) { if ( pt->v[_MMG5_idir[iface][i]] != nump ) { if ( !ntempa ) ntempa = pt->v[_MMG5_idir[iface][i]]; else ntempb = pt->v[_MMG5_idir[iface][i]]; } } if ( ntempa == na ) p1 = &mesh->point[na]; else if ( ntempa == nb ) p1 = &mesh->point[nb]; else if ( ntempb == na ) p1 = &mesh->point[na]; else { assert(ntempb == nb); p1 = &mesh->point[nb]; } ux = p1->c[0] - p0->c[0]; uy = p1->c[1] - p0->c[1]; uz = p1->c[2] - p0->c[2]; lispoi[1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz; lispoi[2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz; lispoi[3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz; ll = lispoi[1]*lispoi[1] + lispoi[2]*lispoi[2] + lispoi[3]*lispoi[3]; lmin = MG_MIN(lmin,ll); lmax = MG_MAX(lmax,ll); /* list goes modulo ilist */ lispoi[3*ilists+1] = lispoi[1]; lispoi[3*ilists+2] = lispoi[2]; lispoi[3*ilists+3] = lispoi[3]; /* At this point, lispoi contains the oriented surface ball of point p0, that has been rotated through r, with the convention that triangle l has edges lispoi[l]; lispoi[l+1] */ if ( lmax/lmin > 4.0*hmax*hmax/ (hmin*hmin) ) return(hmax); /* Check all projections over tangent plane. */ for (k=0; k<ilists-1; k++) { det2d = lispoi[3*k+1]*lispoi[3*(k+1)+2] - lispoi[3*k+2]*lispoi[3*(k+1)+1]; if ( det2d < 0.0 ) return(hmax); } det2d = lispoi[3*(ilists-1)+1]*lispoi[3*0+2] - lispoi[3*(ilists-1)+2]*lispoi[3*0+1]; if ( det2d < 0.0 ) return(hmax); /* Reconstitution of the curvature tensor at p0 in the tangent plane, with a quadric fitting approach */ memset(intm,0.0,3*sizeof(double)); memset(tAA,0.0,6*sizeof(double)); memset(tAb,0.0,3*sizeof(double)); for (k=0; k<ilists; k++) { iel = lists[k] / 4; iface = lists[k] % 4; _MMG5_tet2tri(mesh,iel,iface,&tt); pxt = &mesh->xtetra[mesh->tetra[iel].xt]; if ( !_MMG5_bezierCP(mesh,&tt,&b,MG_GET(pxt->ori,iface)) ) { fprintf(stdout,"%s:%d: Error: function _MMG5_bezierCP return 0\n", __FILE__,__LINE__); exit(EXIT_FAILURE); } for (i0=0; i0<3; i0++) { if ( tt.v[i0] == nump ) break; } assert(i0 < 3); for (j=0; j<10; j++) { c[0] = b.b[j][0] - p0->c[0]; c[1] = b.b[j][1] - p0->c[1]; c[2] = b.b[j][2] - p0->c[2]; b.b[j][0] = r[0][0]*c[0] + r[0][1]*c[1] + r[0][2]*c[2]; b.b[j][1] = r[1][0]*c[0] + r[1][1]*c[1] + r[1][2]*c[2]; b.b[j][2] = r[2][0]*c[0] + r[2][1]*c[1] + r[2][2]*c[2]; } /* Mid-point along left edge and endpoint in the rotated frame */ if ( i0 == 0 ) { memcpy(b0,&(b.b[7][0]),3*sizeof(double)); memcpy(b1,&(b.b[8][0]),3*sizeof(double)); } else if ( i0 == 1 ) { memcpy(b0,&(b.b[3][0]),3*sizeof(double)); memcpy(b1,&(b.b[4][0]),3*sizeof(double)); } else { memcpy(b0,&(b.b[5][0]),3*sizeof(double)); memcpy(b1,&(b.b[6][0]),3*sizeof(double)); } s = 0.5; /* At this point, the two control points are expressed in the rotated frame */ c[0] = 3.0*s*(1.0-s)*(1.0-s)*b0[0] + 3.0*s*s*(1.0-s)*b1[0] + s*s*s*lispoi[3*k+1]; c[1] = 3.0*s*(1.0-s)*(1.0-s)*b0[1] + 3.0*s*s*(1.0-s)*b1[1] + s*s*s*lispoi[3*k+2]; c[2] = 3.0*s*(1.0-s)*(1.0-s)*b0[2] + 3.0*s*s*(1.0-s)*b1[2] + s*s*s*lispoi[3*k+3]; /* Fill matric tAA and second member tAb*/ tAA[0] += c[0]*c[0]*c[0]*c[0]; tAA[1] += c[0]*c[0]*c[1]*c[1]; tAA[2] += c[0]*c[0]*c[0]*c[1]; tAA[3] += c[1]*c[1]*c[1]*c[1]; tAA[4] += c[0]*c[1]*c[1]*c[1]; tAA[5] += c[0]*c[0]*c[1]*c[1]; tAb[0] += c[0]*c[0]*c[2]; tAb[1] += c[1]*c[1]*c[2]; tAb[2] += c[0]*c[1]*c[2]; s = 1.0; /* At this point, the two control points are expressed in the rotated frame */ c[0] = 3.0*s*(1.0-s)*(1.0-s)*b0[0] + 3.0*s*s*(1.0-s)*b1[0] + s*s*s*lispoi[3*k+1]; c[1] = 3.0*s*(1.0-s)*(1.0-s)*b0[1] + 3.0*s*s*(1.0-s)*b1[1] + s*s*s*lispoi[3*k+2]; c[2] = 3.0*s*(1.0-s)*(1.0-s)*b0[2] + 3.0*s*s*(1.0-s)*b1[2] + s*s*s*lispoi[3*k+3]; /* Fill matric tAA and second member tAb*/ tAA[0] += c[0]*c[0]*c[0]*c[0]; tAA[1] += c[0]*c[0]*c[1]*c[1]; tAA[2] += c[0]*c[0]*c[0]*c[1]; tAA[3] += c[1]*c[1]*c[1]*c[1]; tAA[4] += c[0]*c[1]*c[1]*c[1]; tAA[5] += c[0]*c[0]*c[1]*c[1]; tAb[0] += c[0]*c[0]*c[2]; tAb[1] += c[1]*c[1]*c[2]; tAb[2] += c[0]*c[1]*c[2]; /* Mid-point along median edge and endpoint in the rotated frame */ if ( i0 == 0 ) { c[0] = A64TH*(b.b[1][0] + b.b[2][0] + 3.0*(b.b[3][0] + b.b[4][0])) \ + 3.0*A16TH*(b.b[6][0] + b.b[7][0] + b.b[9][0]) + A32TH*(b.b[5][0] + b.b[8][0]); c[1] = A64TH*(b.b[1][1] + b.b[2][1] + 3.0*(b.b[3][1] + b.b[4][1])) \ + 3.0*A16TH*(b.b[6][1] + b.b[7][1] + b.b[9][1]) + A32TH*(b.b[5][1] + b.b[8][1]); c[2] = A64TH*(b.b[1][2] + b.b[2][2] + 3.0*(b.b[3][2] + b.b[4][2])) \ + 3.0*A16TH*(b.b[6][2] + b.b[7][2] + b.b[9][2]) + A32TH*(b.b[5][2] + b.b[8][2]); d[0] = 0.125*b.b[1][0] + 0.375*(b.b[3][0] + b.b[4][0]) + 0.125*b.b[2][0]; d[1] = 0.125*b.b[1][1] + 0.375*(b.b[3][1] + b.b[4][1]) + 0.125*b.b[2][1]; d[2] = 0.125*b.b[1][2] + 0.375*(b.b[3][2] + b.b[4][2]) + 0.125*b.b[2][2]; } else if (i0 == 1) { c[0] = A64TH*(b.b[0][0] + b.b[2][0] + 3.0*(b.b[5][0] + b.b[6][0])) \ + 3.0*A16TH*(b.b[3][0] + b.b[8][0] + b.b[9][0]) + A32TH*(b.b[4][0] + b.b[7][0]); c[1] = A64TH*(b.b[0][1] + b.b[2][1] + 3.0*(b.b[5][1] + b.b[6][1])) \ + 3.0*A16TH*(b.b[3][1] + b.b[8][1] + b.b[9][1]) + A32TH*(b.b[4][1] + b.b[7][1]); c[2] = A64TH*(b.b[0][2] + b.b[2][2] + 3.0*(b.b[5][2] + b.b[6][2])) \ + 3.0*A16TH*(b.b[3][2] + b.b[8][2] + b.b[9][2]) + A32TH*(b.b[4][2] + b.b[7][2]); d[0] = 0.125*b.b[2][0] + 0.375*(b.b[5][0] + b.b[6][0]) + 0.125*b.b[0][0]; d[1] = 0.125*b.b[2][1] + 0.375*(b.b[5][1] + b.b[6][1]) + 0.125*b.b[0][1]; d[2] = 0.125*b.b[2][2] + 0.375*(b.b[5][2] + b.b[6][2]) + 0.125*b.b[0][2]; } else { c[0] = A64TH*(b.b[0][0] + b.b[1][0] + 3.0*(b.b[7][0] + b.b[8][0])) \ + 3.0*A16TH*(b.b[4][0] + b.b[5][0] + b.b[9][0]) + A32TH*(b.b[3][0] + b.b[6][0]); c[1] = A64TH*(b.b[0][1] + b.b[1][1] + 3.0*(b.b[7][1] + b.b[8][1])) \ + 3.0*A16TH*(b.b[4][1] + b.b[5][1] + b.b[9][1]) + A32TH*(b.b[3][1] + b.b[6][1]); c[2] = A64TH*(b.b[0][2] + b.b[1][2] + 3.0*(b.b[7][2] + b.b[8][2])) \ + 3.0*A16TH*(b.b[4][2] + b.b[5][2] + b.b[9][2]) + A32TH*(b.b[3][2] + b.b[6][2]); d[0] = 0.125*b.b[0][0] + 0.375*(b.b[7][0] + b.b[8][0]) + 0.125*b.b[1][0]; d[1] = 0.125*b.b[0][1] + 0.375*(b.b[7][1] + b.b[8][1]) + 0.125*b.b[1][1]; d[2] = 0.125*b.b[0][2] + 0.375*(b.b[7][2] + b.b[8][2]) + 0.125*b.b[1][2]; } /* Fill matric tAA and second member tAb*/ tAA[0] += c[0]*c[0]*c[0]*c[0]; tAA[1] += c[0]*c[0]*c[1]*c[1]; tAA[2] += c[0]*c[0]*c[0]*c[1]; tAA[3] += c[1]*c[1]*c[1]*c[1]; tAA[4] += c[0]*c[1]*c[1]*c[1]; tAA[5] += c[0]*c[0]*c[1]*c[1]; tAb[0] += c[0]*c[0]*c[2]; tAb[1] += c[1]*c[1]*c[2]; tAb[2] += c[0]*c[1]*c[2]; tAA[0] += d[0]*d[0]*d[0]*d[0]; tAA[1] += d[0]*d[0]*d[1]*d[1]; tAA[2] += d[0]*d[0]*d[0]*d[1]; tAA[3] += d[1]*d[1]*d[1]*d[1]; tAA[4] += d[0]*d[1]*d[1]*d[1]; tAA[5] += d[0]*d[0]*d[1]*d[1]; tAb[0] += d[0]*d[0]*d[2]; tAb[1] += d[1]*d[1]*d[2]; tAb[2] += d[0]*d[1]*d[2]; } /* solve now (a b c) = tAA^{-1} * tAb */ if ( !_MMG5_sys33sym(tAA,tAb,c) ) return(hmax); intm[0] = 2.0*c[0]; intm[1] = c[2]; intm[2] = 2.0*c[1]; /* At this point, intm stands for the integral matrix of Taubin's approach : vp[0] and vp[1] are the two pr. directions of curvature, and the two curvatures can be inferred from lambdas*/ if( !_MMG5_eigensym(intm,kappa,vp) ){ fprintf(stdout,"%s:%d: Error: function _MMG5_eigensym return 0\n", __FILE__,__LINE__); exit(EXIT_FAILURE); } /* h computation : h(x) = sqrt( 9*hausd / (2 * max(kappa1(x),kappa2(x)) ) */ kappa[0] = 2.0/9.0 * fabs(kappa[0]) / hausd; kappa[0] = MG_MIN(kappa[0],isqhmin); kappa[0] = MG_MAX(kappa[0],isqhmax); kappa[1] = 2.0/9.0 * fabs(kappa[1]) / hausd; kappa[1] = MG_MIN(kappa[1],isqhmin); kappa[1] = MG_MAX(kappa[1],isqhmax); kappa[0] = 1.0 / sqrt(kappa[0]); kappa[1] = 1.0 / sqrt(kappa[1]); h = MG_MIN(kappa[0],kappa[1]); /* Travel surfacic ball one last time and update non manifold point metric */ for (k=0; k<ilists; k++) { iel = lists[k] / 4; iface = lists[k] % 4; for (j=0; j<3; j++) { i0 = _MMG5_idir[iface][j]; ip0 = pt->v[i0]; p1 = &mesh->point[ip0]; if( !(p1->tag & MG_NOM) || MG_SIN(p1->tag) ) continue; assert(p1->xp); t = &p1->n[0]; memcpy(c,t,3*sizeof(double)); d[0] = r[0][0]*c[0] + r[0][1]*c[1] + r[0][2]*c[2]; d[1] = r[1][0]*c[0] + r[1][1]*c[1] + r[1][2]*c[2]; hnm = intm[0]*d[0]*d[0] + 2.0*intm[1]*d[0]*d[1] + intm[2]*d[1]*d[1]; hnm = 2.0/9.0 * fabs(hnm) / hausd; hnm = MG_MIN(hnm,isqhmin); hnm = MG_MAX(hnm,isqhmax); hnm = 1.0 / sqrt(hnm); met->m[ip0] = MG_MIN(met->m[ip0],hnm); } } return(h); }
/* check if geometry preserved by collapsing edge i */ int chkcol(MMG5_pMesh mesh,MMG5_pSol met,int k,char i,int *list,char typchk) { MMG5_pTria pt,pt0,pt1,pt2; MMG5_pPoint p1,p2; double len,lon,ps,cosnold,cosnnew,kal,n0old[3],n1old[3],n00old[3]; double n0new[3],n1new[3],n00new[3]; int *adja,jel,kel,ip1,ip2,l,ll,ilist; char i1,i2,j,jj,j2,lj,open,voy; pt0 = &mesh->tria[0]; pt = &mesh->tria[k]; i1 = _MMG5_inxt2[i]; i2 = _MMG5_iprv2[i]; ip1 = pt->v[i1]; ip2 = pt->v[i2]; if ( typchk == 2 && met->m ) { lon = _MMG5_lenedg(mesh,met,ip1,ip2,0); lon = MG_MIN(lon,LSHRT); lon = MG_MAX(1.0/lon,LLONG); } /* collect all triangles around vertex i1 */ ilist = boulechknm(mesh,k,i1,list); if ( ilist <= 0 ) return(0); /* check for open ball */ adja = &mesh->adja[3*(k-1)+1]; open = adja[i] == 0; if ( ilist > 3 ) { /* check references */ if ( MG_EDG(pt->tag[i2]) ) { jel = list[1] / 3; pt1 = &mesh->tria[jel]; if ( abs(pt->ref) != abs(pt1->ref) ) return(0); } /* analyze ball */ for (l=1; l<ilist-1+open; l++) { jel = list[l] / 3; j = list[l] % 3; jj = _MMG5_inxt2[j]; j2 = _MMG5_iprv2[j]; pt1 = &mesh->tria[jel]; /* check length */ if ( typchk == 2 && met->m && !MG_EDG(mesh->point[ip2].tag) ) { ip1 = pt1->v[j2]; len = _MMG5_lenedg(mesh,met,ip1,ip2,0); if ( len > lon ) return(0); } /* check normal flipping */ if ( !_MMG5_nortri(mesh,pt1,n1old) ) return(0); memcpy(pt0,pt1,sizeof(MMG5_Tria)); pt0->v[j] = ip2; if ( !_MMG5_nortri(mesh,pt0,n1new) ) return(0); ps = n1new[0]*n1old[0] + n1new[1]*n1old[1] + n1new[2]*n1old[2]; if ( ps < 0.0 ) return(0); /* keep normals at 1st triangles */ if ( l == 1 && !open ) { memcpy(n00old,n1old,3*sizeof(double)); memcpy(n00new,n1new,3*sizeof(double)); } /* check normals deviation */ if ( !(pt1->tag[j2] & MG_GEO) ) { if ( l > 1 ) { cosnold = n0old[0]*n1old[0] + n0old[1]*n1old[1] + n0old[2]*n1old[2]; cosnnew = n0new[0]*n1new[0] + n0new[1]*n1new[1] + n0new[2]*n1new[2]; if ( cosnold < _MMG5_ANGEDG ) { if ( cosnnew < cosnold ) return(0); } else if ( cosnnew < _MMG5_ANGEDG ) return(0); } } /* check geometric support */ if ( l == 1 ) { pt0->tag[j2] = MG_MAX(pt0->tag[j2],pt->tag[i1]); } else if ( l == ilist-2+open ) { ll = list[ilist-1+open] / 3; if ( ll > mesh->nt ) return(0); lj = list[ilist-1+open] % 3; pt0->tag[jj] = MG_MAX(pt0->tag[jj],mesh->tria[ll].tag[lj]); } if ( chkedg(mesh,0) ) return(0); /* check quality */ if ( typchk == 2 && met->m ) kal = ALPHAD*_MMG5_calelt(mesh,met,pt0); else kal = ALPHAD*_MMG5_caltri_iso(mesh,NULL,pt0); if ( kal < NULKAL ) return(0); memcpy(n0old,n1old,3*sizeof(double)); memcpy(n0new,n1new,3*sizeof(double)); } /* check angle between 1st and last triangles */ if ( !open && !(pt->tag[i] & MG_GEO) ) { cosnold = n00old[0]*n1old[0] + n00old[1]*n1old[1] + n00old[2]*n1old[2]; cosnnew = n00new[0]*n1new[0] + n00new[1]*n1new[1] + n00new[2]*n1new[2]; if ( cosnold < _MMG5_ANGEDG ) { if ( cosnnew < cosnold ) return(0); } else if ( cosnnew < _MMG5_ANGEDG ) return(0); /* other checks for reference collapse */ jel = list[ilist-1] / 3; j = list[ilist-1] % 3; j = _MMG5_iprv2[j]; pt = &mesh->tria[jel]; if ( MG_EDG(pt->tag[j]) ) { jel = list[ilist-2] / 3; pt1 = &mesh->tria[jel]; if ( abs(pt->ref) != abs(pt1->ref) ) return(0); } } } /* specific test: no collapse if any interior edge is EDG */ else if ( ilist == 3 ) { p1 = &mesh->point[pt->v[i1]]; if ( MS_SIN(p1->tag) ) return(0); else if ( MG_EDG(pt->tag[i2]) && !MG_EDG(pt->tag[i]) ) return(0); else if ( !MG_EDG(pt->tag[i2]) && MG_EDG(pt->tag[i]) ) return(0); else if ( MG_EDG(pt->tag[i2]) && MG_EDG(pt->tag[i]) && MG_EDG(pt->tag[i1]) ) return(0); /* Check geometric approximation */ jel = list[1] / 3; j = list[1] % 3; jj = _MMG5_inxt2[j]; j2 = _MMG5_iprv2[j]; pt0 = &mesh->tria[0]; pt1 = &mesh->tria[jel]; memcpy(pt0,pt1,sizeof(MMG5_Tria)); pt0->v[j] = ip2; jel = list[2] / 3; j = list[2] % 3; pt1 = &mesh->tria[jel]; pt0->tag[jj] |= pt1->tag[j]; pt0->tag[j2] |= pt1->tag[_MMG5_inxt2[j]]; if ( chkedg(mesh,0) ) return(0); } /* for specific configurations along open ridge */ else if ( ilist == 2 ) { if ( !open ) return(0); jel = list[1] / 3; j = list[1] % 3; /* Topological test */ adja = &mesh->adja[3*(jel-1)+1]; kel = adja[j] / 3; voy = adja[j] % 3; pt2 = &mesh->tria[kel]; if ( pt2->v[voy] == ip2) return(0); jj = _MMG5_inxt2[j]; pt1 = &mesh->tria[jel]; if ( abs(pt->ref) != abs(pt1->ref) ) return(0); else if ( !(pt1->tag[jj] & MG_GEO) ) return(0); p1 = &mesh->point[pt->v[i1]]; p2 = &mesh->point[pt1->v[jj]]; if ( p2->tag > p1->tag || p2->ref != p1->ref ) return(0); /* Check geometric approximation */ j2 = _MMG5_iprv2[j]; pt0 = &mesh->tria[0]; memcpy(pt0,pt,sizeof(MMG5_Tria)); pt0->v[i1] = pt1->v[j2]; if ( chkedg(mesh,0) ) return(0); } return(ilist); }
/* collapse edge i of k, i1->i2 */ int colver(MMG5_pMesh mesh,int *list,int ilist) { MMG5_pTria pt,pt1,pt2; int *adja,k,iel,jel,kel,ip1,ip2; char i,i1,i2,j,jj,open; iel = list[0] / 3; i1 = list[0] % 3; i = _MMG5_iprv2[i1]; i2 = _MMG5_inxt2[i1]; pt = &mesh->tria[iel]; ip1 = pt->v[i1]; ip2 = pt->v[i2]; /* check for open ball */ adja = &mesh->adja[3*(iel-1)+1]; open = adja[i] == 0; /* update vertex ip1 -> ip2 */ for (k=1; k<ilist-1+open; k++) { jel = list[k] / 3; jj = list[k] % 3; pt1 = &mesh->tria[jel]; pt1->v[jj] = ip2; pt1->base = mesh->base; } /* update adjacent with 1st elt */ jel = list[1] / 3; jj = list[1] % 3; j = _MMG5_iprv2[jj]; pt1 = &mesh->tria[jel]; pt1->tag[j] = MG_MAX(pt->tag[i1],pt1->tag[j]); pt1->edg[j] = MG_MAX(pt->edg[i1],pt1->edg[j]); if ( adja[i1] ) { kel = adja[i1] / 3; k = adja[i1] % 3; mesh->adja[3*(kel-1)+1+k] = 3*jel + j; mesh->adja[3*(jel-1)+1+j] = 3*kel + k; pt2 = &mesh->tria[kel]; pt2->tag[k] = MG_MAX(pt1->tag[j],pt2->tag[k]); pt2->edg[k] = MG_MAX(pt1->edg[j],pt2->edg[k]); } else mesh->adja[3*(jel-1)+1+j] = 0; /* adjacent with last elt */ if ( !open ) { iel = list[ilist-1] / 3; i1 = list[ilist-1] % 3; pt = &mesh->tria[iel]; jel = list[ilist-2] / 3; jj = list[ilist-2] % 3; j = _MMG5_inxt2[jj]; pt1 = &mesh->tria[jel]; pt1->tag[j] = MG_MAX(pt->tag[i1],pt1->tag[j]); pt1->edg[j] = MG_MAX(pt->edg[i1],pt1->edg[j]); adja = &mesh->adja[3*(iel-1)+1]; if ( adja[i1] ) { kel = adja[i1] / 3; k = adja[i1] % 3; mesh->adja[3*(kel-1)+1+k] = 3*jel + j; mesh->adja[3*(jel-1)+1+j] = 3*kel + k; pt2 = &mesh->tria[kel]; pt2->tag[k] = MG_MAX(pt1->tag[j],pt2->tag[k]); pt2->edg[k] = MG_MAX(pt1->edg[j],pt2->edg[k]); } else mesh->adja[3*(jel-1)+1+j] = 0; } _MMG5_delPt(mesh,ip1); _MMG5_delElt(mesh,list[0] / 3); if ( !open ) _MMG5_delElt(mesh,list[ilist-1] / 3); return(1); }
/** compute normals at C1 vertices, for C0: tangents */ static int _MMG5_norver(MMG5_pMesh mesh) { MMG5_pTria pt; MMG5_pPoint ppt; MMG5_xPoint *pxp; double n[3],dd; int *adja,k,kk,ng,nn,nt,nf; char i,ii,i1; /* recomputation of normals only if mesh->xpoint has been freed */ if ( mesh->xpoint ) { if ( abs(mesh->info.imprim) > 3 || mesh->info.ddebug ) { fprintf(stdout," ## Warning: no research of boundary points"); fprintf(stdout," and normals of mesh. "); fprintf(stdout,"mesh->xpoint must be freed to enforce analysis.\n"); } return(1); } /* identify boundary points */ ++mesh->base; mesh->xp = 0; for (k=1; k<=mesh->nt; k++) { pt = &mesh->tria[k]; if ( !MG_EOK(pt) ) continue; for (i=0; i<3; i++) { ppt = &mesh->point[pt->v[i]]; if ( ppt->flag == mesh->base ) continue; else { ++mesh->xp; ppt->flag = mesh->base; } } } /* memory to store normals for boundary points */ mesh->xpmax = MG_MAX( (long long)(1.5*mesh->xp),mesh->npmax); _MMG5_ADD_MEM(mesh,(mesh->xpmax+1)*sizeof(MMG5_xPoint),"boundary points",return(0)); _MMG5_SAFE_CALLOC(mesh->xpoint,mesh->xpmax+1,MMG5_xPoint); /* compute normals + tangents */ nn = ng = nt = nf = 0; mesh->xp = 0; ++mesh->base; for (k=1; k<=mesh->nt; k++) { pt = &mesh->tria[k]; if ( !MG_EOK(pt) ) continue; adja = &mesh->adjt[3*(k-1)+1]; for (i=0; i<3; i++) { ppt = &mesh->point[pt->v[i]]; if ( ppt->tag & MG_CRN || ppt->tag & MG_NOM || ppt->flag == mesh->base ) continue; /* C1 point */ if ( !MG_EDG(ppt->tag) ) { if ( !_MMG5_boulen(mesh,k,i,n) ) { ++nf; continue; } else { ++mesh->xp; if(mesh->xp > mesh->xpmax){ _MMG5_TAB_RECALLOC(mesh,mesh->xpoint,mesh->xpmax,0.2,MMG5_xPoint, "larger xpoint table", mesh->xp--; return(0)); } ppt->xp = mesh->xp; pxp = &mesh->xpoint[ppt->xp]; memcpy(pxp->n1,n,3*sizeof(double)); ppt->flag = mesh->base; nn++; } } /* along ridge-curve */ i1 = _MMG5_inxt2[i]; if ( !MG_EDG(pt->tag[i1]) ) continue; else if ( !_MMG5_boulen(mesh,k,i,n) ) { ++nf; continue; } ++mesh->xp; if(mesh->xp > mesh->xpmax){ _MMG5_TAB_RECALLOC(mesh,mesh->xpoint,mesh->xpmax,0.2,MMG5_xPoint, "larger xpoint table", mesh->xp--; return(0)); } ppt->xp = mesh->xp; pxp = &mesh->xpoint[ppt->xp]; memcpy(pxp->n1,n,3*sizeof(double)); if ( pt->tag[i1] & MG_GEO && adja[i1] > 0 ) { kk = adja[i1] / 3; ii = adja[i1] % 3; ii = _MMG5_inxt2[ii]; if ( !_MMG5_boulen(mesh,kk,ii,n) ) { ++nf; continue; } memcpy(pxp->n2,n,3*sizeof(double)); /* compute tangent as intersection of n1 + n2 */ pxp->t[0] = pxp->n1[1]*pxp->n2[2] - pxp->n1[2]*pxp->n2[1]; pxp->t[1] = pxp->n1[2]*pxp->n2[0] - pxp->n1[0]*pxp->n2[2]; pxp->t[2] = pxp->n1[0]*pxp->n2[1] - pxp->n1[1]*pxp->n2[0]; dd = pxp->t[0]*pxp->t[0] + pxp->t[1]*pxp->t[1] + pxp->t[2]*pxp->t[2]; if ( dd > _MMG5_EPSD2 ) { dd = 1.0 / sqrt(dd); pxp->t[0] *= dd; pxp->t[1] *= dd; pxp->t[2] *= dd; } ppt->flag = mesh->base; ++nt; continue; } /* compute tgte */ ppt->flag = mesh->base; ++nt; if ( !_MMG5_boulec(mesh,k,i,pxp->t) ) { ++nf; continue; } dd = pxp->n1[0]*pxp->t[0] + pxp->n1[1]*pxp->t[1] + pxp->n1[2]*pxp->t[2]; pxp->t[0] -= dd*pxp->n1[0]; pxp->t[1] -= dd*pxp->n1[1]; pxp->t[2] -= dd*pxp->n1[2]; dd = pxp->t[0]*pxp->t[0] + pxp->t[1]*pxp->t[1] + pxp->t[2]*pxp->t[2]; if ( dd > _MMG5_EPSD2 ) { dd = 1.0 / sqrt(dd); pxp->t[0] *= dd; pxp->t[1] *= dd; pxp->t[2] *= dd; } }