/** check for ridges: dihedral angle */ static int _MMG5_setdhd(MMG5_pMesh mesh) { MMG5_pTria pt,pt1; double n1[3],n2[3],dhd; int *adja,k,kk,ne,nr; char i,ii,i1,i2; ne = nr = 0; for (k=1; k<=mesh->nt; k++) { pt = &mesh->tria[k]; if ( !MG_EOK(pt) ) continue; /* triangle normal */ _MMG5_nortri(mesh,pt,n1); adja = &mesh->adjt[3*(k-1)+1]; for (i=0; i<3; i++) { kk = adja[i] / 3; ii = adja[i] % 3; if ( !kk ) { pt->tag[i] |= MG_GEO; i1 = _MMG5_inxt2[i]; i2 = _MMG5_inxt2[i1]; mesh->point[pt->v[i1]].tag |= MG_GEO; mesh->point[pt->v[i2]].tag |= MG_GEO; nr++; } else if ( k < kk ) { pt1 = &mesh->tria[kk]; /* reference curve */ if ( pt1->ref != pt->ref ) { pt->tag[i] |= MG_REF; pt1->tag[ii] |= MG_REF; i1 = _MMG5_inxt2[i]; i2 = _MMG5_inxt2[i1]; mesh->point[pt->v[i1]].tag |= MG_REF; mesh->point[pt->v[i2]].tag |= MG_REF; ne++; } /* check angle w. neighbor */ _MMG5_nortri(mesh,pt1,n2); dhd = n1[0]*n2[0] + n1[1]*n2[1] + n1[2]*n2[2]; if ( dhd <= mesh->info.dhd ) { pt->tag[i] |= MG_GEO; pt1->tag[ii] |= MG_GEO; i1 = _MMG5_inxt2[i]; i2 = _MMG5_inxt2[i1]; mesh->point[pt->v[i1]].tag |= MG_GEO; mesh->point[pt->v[i2]].tag |= MG_GEO; nr++; } } } } if ( abs(mesh->info.imprim) > 3 && nr > 0 ) fprintf(stdout," %d ridges, %d edges updated\n",nr,ne); return(1); }
/** * \param mesh pointer toward the mesh structure. * \param met pointer toward the metric structure. * \param *warn \a warn is set to 1 if we don't have enough memory to complete mesh. * \return -1 if failed. * \return number of new points. * * Split edges of length bigger than _MMG5_LOPTL. * */ static int _MMG5_adpspl(MMG5_pMesh mesh,MMG5_pSol met, int* warn) { MMG5_pTetra pt; MMG5_pxTetra pxt; MMG5_Tria ptt; MMG5_pPoint p0,p1,ppt; MMG5_pxPoint pxp; double dd,len,lmax,o[3],to[3],ro[3],no1[3],no2[3],v[3]; int k,ip,ip1,ip2,list[_MMG5_LMAX+2],ilist,ns,ref,ier; char imax,tag,j,i,i1,i2,ifa0,ifa1; *warn=0; ns = 0; for (k=1; k<=mesh->ne; k++) { pt = &mesh->tetra[k]; if ( !MG_EOK(pt) || (pt->tag & MG_REQ) ) continue; pxt = pt->xt ? &mesh->xtetra[pt->xt] : 0; /* find longest edge */ imax = -1; lmax = 0.0; for (i=0; i<6; i++) { if ( pt->xt && (pxt->tag[i] & MG_REQ) ) continue; ip1 = _MMG5_iare[i][0]; ip2 = _MMG5_iare[i][1]; len = _MMG5_lenedg(mesh,met,pt->v[ip1],pt->v[ip2]); if ( len > lmax ) { lmax = len; imax = i; } } if ( imax==-1 ) fprintf(stdout,"%s:%d: Warning: all edges of tetra %d are required or of length null.\n", __FILE__,__LINE__,k); if ( lmax < _MMG5_LOPTL ) continue; /* proceed edges according to lengths */ ifa0 = _MMG5_ifar[imax][0]; ifa1 = _MMG5_ifar[imax][1]; i = (pt->xt && (pxt->ftag[ifa1] & MG_BDY)) ? ifa1 : ifa0; j = _MMG5_iarfinv[i][imax]; i1 = _MMG5_idir[i][_MMG5_inxt2[j]]; i2 = _MMG5_idir[i][_MMG5_iprv2[j]]; ip1 = pt->v[i1]; ip2 = pt->v[i2]; p0 = &mesh->point[ip1]; p1 = &mesh->point[ip2]; /* Case of a boundary face */ if ( pt->xt && (pxt->ftag[i] & MG_BDY) ) { if ( !(MG_GET(pxt->ori,i)) ) continue; ref = pxt->edg[_MMG5_iarf[i][j]]; tag = pxt->tag[_MMG5_iarf[i][j]]; if ( tag & MG_REQ ) continue; tag |= MG_BDY; ilist = _MMG5_coquil(mesh,k,imax,list); if ( !ilist ) continue; else if ( ilist < 0 ) return(-1); if ( tag & MG_NOM ){ if( !_MMG5_BezierNom(mesh,ip1,ip2,0.5,o,no1,to) ) continue; else if ( MG_SIN(p0->tag) && MG_SIN(p1->tag) ) { _MMG5_tet2tri(mesh,k,i,&ptt); _MMG5_nortri(mesh,&ptt,no1); if ( !MG_GET(pxt->ori,i) ) { no1[0] *= -1.0; no1[1] *= -1.0; no1[2] *= -1.0; } } } else if ( tag & MG_GEO ) { if ( !_MMG5_BezierRidge(mesh,ip1,ip2,0.5,o,no1,no2,to) ) continue; if ( MG_SIN(p0->tag) && MG_SIN(p1->tag) ) { _MMG5_tet2tri(mesh,k,i,&ptt); _MMG5_nortri(mesh,&ptt,no1); no2[0] = to[1]*no1[2] - to[2]*no1[1]; no2[1] = to[2]*no1[0] - to[0]*no1[2]; no2[2] = to[0]*no1[1] - to[1]*no1[0]; dd = no2[0]*no2[0] + no2[1]*no2[1] + no2[2]*no2[2]; if ( dd > _MMG5_EPSD2 ) { dd = 1.0 / sqrt(dd); no2[0] *= dd; no2[1] *= dd; no2[2] *= dd; } } } else if ( tag & MG_REF ) { if ( !_MMG5_BezierRef(mesh,ip1,ip2,0.5,o,no1,to) ) continue; } else { if ( !_MMG5_norface(mesh,k,i,v) ) continue; if ( !_MMG5_BezierReg(mesh,ip1,ip2,0.5,v,o,no1) ) continue; } ier = _MMG5_simbulgept(mesh,list,ilist,o); if ( !ier ) { ier = _MMG5_dichoto1b(mesh,list,ilist,o,ro); memcpy(o,ro,3*sizeof(double)); } ip = _MMG5_newPt(mesh,o,tag); if ( !ip ) { /* reallocation of point table */ _MMG5_POINT_REALLOC(mesh,met,ip,mesh->gap, *warn=1; break ,o,tag); } //CECILE if ( met->m ) met->m[ip] = 0.5 * (met->m[ip1]+met->m[ip2]); //CECILE ier = _MMG5_split1b(mesh,met,list,ilist,ip,1); /* if we realloc memory in _MMG5_split1b pt and pxt pointers are not valid */ pt = &mesh->tetra[k]; pxt = pt->xt ? &mesh->xtetra[pt->xt] : 0; if ( ier < 0 ) { fprintf(stdout," ## Error: unable to split.\n"); return(-1); } else if ( !ier ) { _MMG5_delPt(mesh,ip); continue; } ns++; ppt = &mesh->point[ip]; if ( MG_EDG(tag) || (tag & MG_NOM) ) ppt->ref = ref; else ppt->ref = pxt->ref[i]; if ( met->m ) met->m[ip] = 0.5 * (met->m[ip1]+met->m[ip2]); pxp = &mesh->xpoint[ppt->xp]; if ( tag & MG_NOM ){ memcpy(pxp->n1,no1,3*sizeof(double)); memcpy(pxp->t,to,3*sizeof(double)); } else if ( tag & MG_GEO ) { memcpy(pxp->n1,no1,3*sizeof(double)); memcpy(pxp->n2,no2,3*sizeof(double)); memcpy(pxp->t,to,3*sizeof(double)); } else if ( tag & MG_REF ) { memcpy(pxp->n1,no1,3*sizeof(double)); memcpy(pxp->t,to,3*sizeof(double)); } else memcpy(pxp->n1,no1,3*sizeof(double)); } /* Case of an internal face */ else { if ( (p0->tag & MG_BDY) && (p1->tag & MG_BDY) ) continue;
/** * \param mesh pointer toward the mesh structure. * \param pt pointer toward the triangle structure. * \param pb pointer toward the computed Bezier structure. * \param ori triangle orientation (unused but here for compatibility * with the _MMG5_bezierCP interface). * \return 1. * * Compute Bezier control points on triangle \a pt (cf. Vlachos) * * \todo merge with the _MMG5_mmg3dBeizerCP function and remove the pointer * toward this functions. * */ int _MMG5_mmgsBezierCP(MMG5_pMesh mesh,MMG5_Tria *pt,_MMG5_pBezier pb, char ori) { MMG5_pPoint p[3]; double *n1,*n2,nt[3],ps,ps2,dd,ux,uy,uz,ll; int ia,ib,ic; char i,i1,i2; ia = pt->v[0]; ib = pt->v[1]; ic = pt->v[2]; p[0] = &mesh->point[ia]; p[1] = &mesh->point[ib]; p[2] = &mesh->point[ic]; memset(pb,0,sizeof(_MMG5_Bezier)); /* first 3 CP = vertices, normals */ for (i=0; i<3; i++) { memcpy(&pb->b[i],p[i]->c,3*sizeof(double)); pb->p[i] = p[i]; if ( MS_SIN(p[i]->tag) ) { _MMG5_nortri(mesh,pt,pb->n[i]); } else if ( MG_EDG(p[i]->tag) ) { _MMG5_nortri(mesh,pt,nt); n1 = &mesh->xpoint[p[i]->ig].n1[0]; n2 = &mesh->xpoint[p[i]->ig].n2[0]; ps = n1[0]*nt[0] + n1[1]*nt[1] + n1[2]*nt[2]; ps2 = n2[0]*nt[0] + n2[1]*nt[1] + n2[2]*nt[2]; if ( fabs(ps) > fabs(ps2) ) memcpy(&pb->n[i],n1,3*sizeof(double)); else memcpy(&pb->n[i],n2,3*sizeof(double)); memcpy(&pb->t[i],p[i]->n,3*sizeof(double)); } else memcpy(&pb->n[i],p[i]->n,3*sizeof(double)); } /* compute control points along edges */ for (i=0; i<3; i++) { i1 = _MMG5_inxt2[i]; i2 = _MMG5_iprv2[i]; ux = p[i2]->c[0] - p[i1]->c[0]; uy = p[i2]->c[1] - p[i1]->c[1]; uz = p[i2]->c[2] - p[i1]->c[2]; ll = ux*ux + uy*uy + uz*uz; // A PROTEGER !!!! /* choose normals */ n1 = pb->n[i1]; n2 = pb->n[i2]; /* check for boundary curve */ if ( MG_EDG(pt->tag[i]) ) { if ( MS_SIN(p[i1]->tag) ) { dd = 1.0 / 3.0; pb->b[2*i+3][0] = p[i1]->c[0] + dd * ux; pb->b[2*i+3][1] = p[i1]->c[1] + dd * uy; pb->b[2*i+3][2] = p[i1]->c[2] + dd * uz; } else { dd = (ux*pb->t[i1][0] + uy*pb->t[i1][1] + uz*pb->t[i1][2]) / 3.0; pb->b[2*i+3][0] = p[i1]->c[0] + dd * pb->t[i1][0]; pb->b[2*i+3][1] = p[i1]->c[1] + dd * pb->t[i1][1]; pb->b[2*i+3][2] = p[i1]->c[2] + dd * pb->t[i1][2]; } if ( MS_SIN(p[i2]->tag) ) { dd = 1.0 / 3.0; pb->b[2*i+4][0] = p[i2]->c[0] - dd * ux; pb->b[2*i+4][1] = p[i2]->c[1] - dd * uy; pb->b[2*i+4][2] = p[i2]->c[2] - dd * uz; } else { dd = -(ux*pb->t[i2][0] + uy*pb->t[i2][1] + uz*pb->t[i2][2]) / 3.0; pb->b[2*i+4][0] = p[i2]->c[0] + dd * pb->t[i2][0]; pb->b[2*i+4][1] = p[i2]->c[1] + dd * pb->t[i2][1]; pb->b[2*i+4][2] = p[i2]->c[2] + dd * pb->t[i2][2]; } /* tangent evaluation */ ps = ux*(pb->t[i1][0]+pb->t[i2][0]) + uy*(pb->t[i1][1]+pb->t[i2][1]) + uz*(pb->t[i1][2]+pb->t[i2][2]); ps = 2.0 * ps / ll; pb->t[i+3][0] = pb->t[i1][0] + pb->t[i2][0] - ps*ux; pb->t[i+3][1] = pb->t[i1][1] + pb->t[i2][1] - ps*uy; pb->t[i+3][2] = pb->t[i1][2] + pb->t[i2][2] - ps*uz; dd = pb->t[i+3][0]*pb->t[i+3][0] + pb->t[i+3][1]*pb->t[i+3][1] + pb->t[i+3][2]*pb->t[i+3][2]; if ( dd > _MMG5_EPSD2 ) { dd = 1.0 / sqrt(dd); pb->t[i+3][0] *= dd; pb->t[i+3][1] *= dd; pb->t[i+3][2] *= dd; } } else { /* internal edge */ ps = ux*n1[0] + uy*n1[1] + uz*n1[2]; pb->b[2*i+3][0] = (2.0*p[i1]->c[0] + p[i2]->c[0] - ps*n1[0]) / 3.0; pb->b[2*i+3][1] = (2.0*p[i1]->c[1] + p[i2]->c[1] - ps*n1[1]) / 3.0; pb->b[2*i+3][2] = (2.0*p[i1]->c[2] + p[i2]->c[2] - ps*n1[2]) / 3.0; ps = -(ux*n2[0] + uy*n2[1] + uz*n2[2]); pb->b[2*i+4][0] = (2.0*p[i2]->c[0] + p[i1]->c[0] - ps*n2[0]) / 3.0; pb->b[2*i+4][1] = (2.0*p[i2]->c[1] + p[i1]->c[1] - ps*n2[1]) / 3.0; pb->b[2*i+4][2] = (2.0*p[i2]->c[2] + p[i1]->c[2] - ps*n2[2]) / 3.0; } /* normal evaluation */ ps = ux*(n1[0]+n2[0]) + uy*(n1[1]+n2[1]) + uz*(n1[2]+n2[2]); ps = 2.0*ps / ll; pb->n[i+3][0] = n1[0] + n2[0] - ps*ux; pb->n[i+3][1] = n1[1] + n2[1] - ps*uy; pb->n[i+3][2] = n1[2] + n2[2] - ps*uz; dd = pb->n[i+3][0]*pb->n[i+3][0] + pb->n[i+3][1]*pb->n[i+3][1] + pb->n[i+3][2]*pb->n[i+3][2]; if ( dd > _MMG5_EPSD2 ) { dd = 1.0 / sqrt(dd); pb->n[i+3][0] *= dd; pb->n[i+3][1] *= dd; pb->n[i+3][2] *= dd; } } /* Central Bezier coefficient */ for (i=0; i<3; i++) { dd = 0.5 / 3.0; pb->b[9][0] -= dd * pb->b[i][0]; pb->b[9][1] -= dd * pb->b[i][1]; pb->b[9][2] -= dd * pb->b[i][2]; } for (i=0; i<3; i++) { pb->b[9][0] += 0.25 * (pb->b[2*i+3][0] + pb->b[2*i+4][0]); pb->b[9][1] += 0.25 * (pb->b[2*i+3][1] + pb->b[2*i+4][1]); pb->b[9][2] += 0.25 * (pb->b[2*i+3][2] + pb->b[2*i+4][2]); } return(1); }
/* collapse edge i of k, i1->i2 */ int litcol(MMG5_pMesh mesh,int k,char i,double kali) { MMG5_pTria pt,pt0,pt1; MMG5_pPoint p1,p2; double kal,ps,cosnold,cosnnew,n0old[3],n0new[3],n1old[3],n1new[3],n00old[3],n00new[3]; int *adja,list[_MMG5_LMAX+2],jel,ip2,l,ilist; char i1,i2,j,jj,j2,open; pt0 = &mesh->tria[0]; pt = &mesh->tria[k]; i1 = _MMG5_inxt2[i]; i2 = _MMG5_iprv2[i]; ip2 = pt->v[i2]; /* collect all triangles around vertex i1 */ ilist = boulet(mesh,k,i1,list); /* check for open ball */ adja = &mesh->adja[3*(k-1)+1]; open = adja[i] == 0; if ( ilist > 3 ) { /* check references */ 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 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 < MG_MIN(0.0,cosnold) ) return(0); } else if ( cosnnew < _MMG5_ANGEDG ) return(0); } memcpy(n0old,n1old,3*sizeof(double)); memcpy(n0new,n1new,3*sizeof(double)); } /* check quality */ kal = ALPHAD*_MMG5_caltri_iso(mesh,NULL,pt0); if ( kal < NULKAL ) return(0); } /* check angle between 1st and last triangles */ if ( !open ) { 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 < MG_MIN(0.0,cosnold) ) return(0); } else if ( cosnnew < _MMG5_ANGEDG ) return(0); /* other reference checks */ jel = list[ilist-1] / 3; pt = &mesh->tria[jel]; jel = list[ilist-2] / 3; pt1 = &mesh->tria[jel]; if ( abs(pt->ref) != abs(pt1->ref) ) return(0); } return(colver(mesh,list,ilist)); } /* 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); return(colver3(mesh,list)); } /* for specific configurations along open ridge */ else if ( ilist == 2 ) { if ( !open ) return(0); jel = list[1] / 3; j = list[1] % 3; 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); return(colver2(mesh,list)); } return(0); }
/* 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); }