/* attempt to collapse small edges */ static int colelt(pMesh mesh,pSol met,char typchk) { pTria pt; pPoint p1,p2; double ll,ux,uy,uz; int ier,list[LMAX+2],ilist,k,nc; char i,i1,i2; nc = 0; for (k=1; k<=mesh->nt; k++) { pt = &mesh->tria[k]; if ( !MS_EOK(pt) || pt->ref < 0 ) continue; /* check edge length */ pt->flag = 0; ier = 0; for (i=0; i<3; i++) { if ( MS_SIN(pt->tag[i]) ) continue; i1 = inxt[i]; i2 = iprv[i]; p1 = &mesh->point[pt->v[i1]]; p2 = &mesh->point[pt->v[i2]]; if ( p1->tag & MS_NOM || p2->tag & MS_NOM ) continue; else if ( MS_SIN(p1->tag) ) continue; else if ( p1->tag > p2->tag || p1->tag > pt->tag[i] ) continue; /* check length */ if ( typchk == 1 ) { ux = p2->c[0] - p1->c[0]; uy = p2->c[1] - p1->c[1]; uz = p2->c[2] - p1->c[2]; ll = ux*ux + uy*uy + uz*uz; if ( ll > info.hmin*info.hmin ) continue; } else { ll = lenedg(mesh,met,pt->v[i1],pt->v[i2],0); if ( ll > LSHRT ) continue; } /* check if geometry preserved */ ilist = chkcol(mesh,met,k,i,list,typchk); if ( ilist > 3 ) { nc += colver(mesh,list,ilist); break; } else if ( ilist == 3 ) { nc += colver3(mesh,list); break; } else if ( ilist == 2 ) { nc += colver2(mesh,list); break; } } } if ( nc > 0 && (abs(info.imprim) > 5 || info.ddebug) ) fprintf(stdout," %8d vertices removed\n",nc); return(nc); }
/* check if splitting edge i of k is ok */ int chkspl(pMesh mesh,pSol met,int k,int i) { pTria pt,pt1; pPoint ppt; pGeom go; Bezier b; double s,uv[2],o[3],no[3],to[3]; int *adja,jel,ip,ier; char i1,i2,j,jj,j2; if ( mesh->ng > mesh->ngmax-2 ) return(0); pt = &mesh->tria[k]; i1 = inxt[i]; i2 = iprv[i]; if ( MS_SIN(pt->tag[i1]) || MS_SIN(pt->tag[i2]) ) return(0); adja = &mesh->adja[3*(k-1)+1]; jel = adja[i] / 3; if ( jel ) { j = adja[i] % 3; jj = inxt[j]; j2 = iprv[j]; pt1 = &mesh->tria[jel]; if ( MS_SIN(pt1->tag[jj]) || MS_SIN(pt1->tag[j2]) ) return(0); } ier = bezierCP(mesh,k,&b); assert(ier); /* create midedge point */ uv[0] = 0.5; uv[1] = 0.5; if (i == 1) uv[0] = 0.0; else if ( i == 2 ) uv[1] = 0.0; ier = bezierInt(&b,uv,o,no,to); assert(ier); ip = newPt(mesh,o,MS_EDG(pt->tag[i]) ? to : no); assert(ip); if ( MS_EDG(pt->tag[i]) ) { ++mesh->ng; ppt = &mesh->point[ip]; ppt->ig = mesh->ng; go = &mesh->geom[mesh->ng]; memcpy(go->n1,no,3*sizeof(double)); } s = 0.5; intmet(mesh,met,k,i,ip,s); return(ip); }
/* analyze triangles and split or collapse to match gradation */ static int adpcol(pMesh mesh,pSol met) { pTria pt; pPoint p1,p2; double len; int k,list[LMAX+2],ilist,nc; char i,i1,i2; nc = 0; for (k=1; k<=mesh->nt; k++) { pt = &mesh->tria[k]; if ( !MS_EOK(pt) || pt->ref < 0 ) continue; /* check edge length */ pt->flag = 0; for (i=0; i<3; i++) { if ( MS_SIN(pt->tag[i]) ) continue; /* check length */ i1 = inxt[i]; i2 = iprv[i]; p1 = &mesh->point[pt->v[i1]]; p2 = &mesh->point[pt->v[i2]]; if ( p1->tag & MS_NOM || p2->tag & MS_NOM ) continue; len = lenedg(mesh,met,pt->v[i1],pt->v[i2],0); if ( len > LOPTS ) continue; p1 = &mesh->point[pt->v[i1]]; p2 = &mesh->point[pt->v[i2]]; if ( MS_SIN(p1->tag) ) continue; else if ( p1->tag > p2->tag || p1->tag > pt->tag[i] ) continue; /* check if geometry preserved */ ilist = chkcol(mesh,met,k,i,list,2); if ( ilist > 3 ) { nc += colver(mesh,list,ilist); break; } else if ( ilist == 3 ) { nc += colver3(mesh,list); break; } else if ( ilist == 2 ) { nc += colver2(mesh,list); break; } } } return(nc); }
static int swpmsh(pMesh mesh,pSol met,char typchk) { pTria pt; int k,it,ns,nns,maxit; char i; it = nns = 0; maxit = 2; mesh->base++; do { ns = 0; for (k=1; k<=mesh->nt; k++) { pt = &mesh->tria[k]; if ( !MS_EOK(pt) || pt->ref < 0 ) continue; for (i=0; i<3; i++) { if ( MS_SIN(pt->tag[i]) || MS_EDG(pt->tag[i]) ) continue; else if ( chkswp(mesh,met,k,i,typchk) ) { ns += swapar(mesh,k,i); break; } } } nns += ns; } while ( ns > 0 && ++it < maxit ); if ( (abs(info.imprim) > 5 || info.ddebug) && nns > 0 ) fprintf(stdout," %8d edge swapped\n",nns); return(nns); }
/* Analyze triangles and move points to make mesh more uniform */ static int movtri(pMesh mesh,pSol met,int maxit) { pTria pt; pPoint ppt; int it,k,ier,base,nm,ns,nnm,list[LMAX+2],ilist; char i; if ( abs(info.imprim) > 5 || info.ddebug ) fprintf(stdout," ** OPTIMIZING MESH\n"); base = 1; for (k=1; k<=mesh->np; k++) mesh->point[k].flag = base; it = nnm = 0; do { base++; nm = ns = 0; for (k=1; k<=mesh->nt; k++) { pt = &mesh->tria[k]; if ( !MS_EOK(pt) || pt->ref < 0 ) continue; for (i=0; i<3; i++) { ppt = &mesh->point[pt->v[i]]; if ( ppt->flag == base || MS_SIN(ppt->tag) || ppt->tag & MS_NOM ) continue; ier = 0; ilist = boulet(mesh,k,i,list); if ( MS_EDG(ppt->tag) ) { ier = movridpt(mesh,met,list,ilist); if ( ier ) ns++; } else ier = movintpt(mesh,met,list,ilist); if ( ier ) { nm++; ppt->flag = base; } } } nnm += nm; if ( info.ddebug ) fprintf(stdout," %8d moved, %d geometry\n",nm,ns); } while ( ++it < maxit && nm > 0); if ( (abs(info.imprim) > 5 || info.ddebug) && nnm > 0 ) fprintf(stdout," %8d vertices moved, %d iter.\n",nnm,it); return(nnm); }
static int adpspl(pMesh mesh,pSol met) { pTria pt; pPoint p1,p2; double len,lmax; int ip,k,ns; char i,i1,i2,imax; ns = 0; for (k=1; k<=mesh->nt; k++) { pt = &mesh->tria[k]; if ( !MS_EOK(pt) || pt->ref < 0 ) continue; /* check edge length */ pt->flag = 0; imax = -1; lmax = -1.0; for (i=0; i<3; i++) { i1 = inxt[i]; i2 = iprv[i]; len = lenedg(mesh,met,pt->v[i1],pt->v[i2],0); if ( len > lmax ) { lmax = len; imax = i; } } if ( lmax < LOPTL ) continue; else if ( MS_SIN(pt->tag[imax]) ) continue; /* check length */ i1 = inxt[imax]; i2 = iprv[imax]; p1 = &mesh->point[pt->v[i1]]; p2 = &mesh->point[pt->v[i2]]; if ( p1->tag & MS_NOM || p2->tag & MS_NOM ) continue; ip = chkspl(mesh,met,k,imax); if ( ip > 0 ) ns += split1b(mesh,k,imax,ip); } return(ns); }
/* check if edge need to be split and return a binary coding the numbers of the edges of tria iel that should be split according to a hausdorff distance criterion */ int chkedg(pMesh mesh,int iel) { pTria pt; pPoint p[3]; double n[3][3],t[3][3],nt[3],c1[3],c2[3],*n1,*n2,t1[3],t2[3]; double ps,ps2,cosn,ux,uy,uz,ll,li,dd; char i,i1,i2; pt = &mesh->tria[iel]; p[0] = &mesh->point[pt->v[0]]; p[1] = &mesh->point[pt->v[1]]; p[2] = &mesh->point[pt->v[2]]; /* normal recovery */ for (i=0; i<3; i++) { if ( MS_SIN(p[i]->tag) ) { nortri(mesh,pt,n[i]); } else if ( MS_EDG(p[i]->tag) ) { nortri(mesh,pt,nt); n1 = &mesh->geom[p[i]->ig].n1[0]; n2 = &mesh->geom[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(&n[i],n1,3*sizeof(double)); else memcpy(&n[i],n2,3*sizeof(double)); memcpy(&t[i],p[i]->n,3*sizeof(double)); } else memcpy(&n[i],p[i]->n,3*sizeof(double)); } /* analyze edges */ for (i=0; i<3; i++) { i1 = inxt[i]; i2 = iprv[i]; /* check length */ 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; if ( ll > info.hmax*info.hmax ) { MS_SET(pt->flag,i); continue; } else if ( !MS_EDG(pt->tag[i]) && p[i1]->tag > MS_NOTAG && p[i2]->tag > MS_NOTAG ) { MS_SET(pt->flag,i); continue; } /* Hausdorff w/r tangent direction */ if ( MS_EDG(pt->tag[i]) ) { if ( MS_SIN(p[i1]->tag) ) { li = 1.0 / sqrt(ll); t1[0] = li*ux; t1[1] = li*uy; t1[2] = li*uz; } else{ memcpy(t1,t[i1],3*sizeof(double)); } if ( MS_SIN(p[i2]->tag) ) { li = 1.0 / sqrt(ll); t2[0] = li*ux; t2[1] = li*uy; t2[2] = li*uz; } else{ memcpy(t2,t[i2],3*sizeof(double)); } ps = t1[0]*ux + t1[1]*uy + t1[2]*uz; ps *= ps; cosn = ps/ll ; cosn *= (1.0-cosn); cosn *= (0.25*ll); if ( cosn > info.hausd*info.hausd ) { MS_SET(pt->flag,i); continue; } ps = -(t2[0]*ux + t2[1]*uy + t2[2]*uz); ps *= ps; cosn = ps/ll ; cosn *= (1.0-cosn); cosn *= (0.25*ll); if ( cosn > info.hausd*info.hausd ) { MS_SET(pt->flag,i); continue; } } else { n1 = n[i1]; n2 = n[i2]; ps = ux*n1[0] + uy*n1[1] + uz*n1[2]; c1[0] = (2.0*p[i1]->c[0] + p[i2]->c[0] - ps*n1[0]) / 3.0 - p[i1]->c[0]; c1[1] = (2.0*p[i1]->c[1] + p[i2]->c[1] - ps*n1[1]) / 3.0 - p[i1]->c[1]; c1[2] = (2.0*p[i1]->c[2] + p[i2]->c[2] - ps*n1[2]) / 3.0 - p[i1]->c[2]; ps = -(ux*n2[0] + uy*n2[1] + uz*n2[2]); c2[0] = (2.0*p[i2]->c[0] + p[i1]->c[0] - ps*n2[0]) / 3.0 - p[i2]->c[0]; c2[1] = (2.0*p[i2]->c[1] + p[i1]->c[1] - ps*n2[1]) / 3.0 - p[i2]->c[1]; c2[2] = (2.0*p[i2]->c[2] + p[i1]->c[2] - ps*n2[2]) / 3.0 - p[i2]->c[2]; /* squared cosines */ ps = c1[0]*ux + c1[1]*uy + c1[2]*uz; ps *= ps; dd = c1[0]*c1[0] + c1[1]*c1[1] + c1[2]*c1[2]; cosn = ps / (dd*ll); cosn *= (1.0-cosn); cosn *= (0.25*ll); if ( cosn > info.hausd*info.hausd ) { MS_SET(pt->flag,i); continue; } ps = -c2[0]*ux - c2[1]*uy - c2[2]*uz; ps *= ps; dd = c2[0]*c2[0]+c2[1]*c2[1]+c2[2]*c2[2]; cosn = ps / (dd*ll); cosn *= (1.0-cosn); cosn *= (0.25*ll); if ( cosn > info.hausd*info.hausd ) { MS_SET(pt->flag,i); continue; } } } return(pt->flag); }
/* analyze triangles and split if needed */ static int anaelt(pMesh mesh,pSol met,char typchk) { pTria pt; pPoint ppt,p1,p2; Hash hash; Bezier pb; pGeom go; double s,o[3],no[3],to[3],dd,len; int vx[3],i,j,ip,ip1,ip2,ier,k,ns,nc,nt; char i1,i2; static double uv[3][2] = { {0.5,0.5}, {0.,0.5}, {0.5,0.} }; hashNew(&hash,mesh->np); ns = 0; s = 0.5; for (k=1; k<=mesh->nt; k++) { pt = &mesh->tria[k]; if ( !MS_EOK(pt) || pt->ref < 0 ) continue; if ( MS_SIN(pt->tag[0]) || MS_SIN(pt->tag[1]) || MS_SIN(pt->tag[2]) ) continue; /* check element cut */ pt->flag = 0; if ( typchk == 1 ) { if ( !chkedg(mesh,k) ) continue; } else if ( typchk == 2 ) { for (i=0; i<3; i++) { i1 = inxt[i]; i2 = iprv[i]; len = lenedg(mesh,met,pt->v[i1],pt->v[i2],0); if ( len > LLONG ) MS_SET(pt->flag,i); } if ( !pt->flag ) continue; } ns++; /* geometric support */ ier = bezierCP(mesh,k,&pb); assert(ier); /* scan edges to split */ for (i=0; i<3; i++) { if ( !MS_GET(pt->flag,i) ) continue; i1 = inxt[i]; i2 = iprv[i]; ip1 = pt->v[i1]; ip2 = pt->v[i2]; ip = hashGet(&hash,ip1,ip2); if ( !MS_EDG(pt->tag[i]) && ip > 0 ) continue; /* new point along edge */ ier = bezierInt(&pb,uv[i],o,no,to); if ( !ip ) { ip = newPt(mesh,o,MS_EDG(pt->tag[i]) ? to : no); assert(ip); hashEdge(&hash,ip1,ip2,ip); p1 = &mesh->point[ip1]; p2 = &mesh->point[ip2]; ppt = &mesh->point[ip]; if ( MS_EDG(pt->tag[i]) ) { ++mesh->ng; assert(mesh->ng < mesh->ngmax); ppt->tag = pt->tag[i]; if ( p1->ref == pt->edg[i] || p2->ref == pt->edg[i] ) ppt->ref = pt->edg[i]; ppt->ig = mesh->ng; go = &mesh->geom[mesh->ng]; memcpy(go->n1,no,3*sizeof(double)); dd = go->n1[0]*ppt->n[0] + go->n1[1]*ppt->n[1] + go->n1[2]*ppt->n[2]; ppt->n[0] -= dd*go->n1[0]; ppt->n[1] -= dd*go->n1[1]; ppt->n[2] -= dd*go->n1[2]; dd = ppt->n[0]*ppt->n[0] + ppt->n[1]*ppt->n[1] + ppt->n[2]*ppt->n[2]; if ( dd > EPSD2 ) { dd = 1.0 / sqrt(dd); ppt->n[0] *= dd; ppt->n[1] *= dd; ppt->n[2] *= dd; } } if ( met->m ) { if ( typchk == 1 ) intmet33(mesh,met,ip1,ip2,ip,s); else intmet(mesh,met,k,i,ip,s); } } else if ( pt->tag[i] & MS_GEO ) { ppt = &mesh->point[ip]; go = &mesh->geom[ppt->ig]; memcpy(go->n2,no,3*sizeof(double)); /* a computation of the tangent with respect to these two normals is possible */ ppt->n[0] = go->n1[1]*go->n2[2] - go->n1[2]*go->n2[1]; ppt->n[1] = go->n1[2]*go->n2[0] - go->n1[0]*go->n2[2]; ppt->n[2] = go->n1[0]*go->n2[1] - go->n1[1]*go->n2[0]; dd = ppt->n[0]*ppt->n[0] + ppt->n[1]*ppt->n[1] + ppt->n[2]*ppt->n[2]; if ( dd > EPSD2 ) { dd = 1.0 / sqrt(dd); ppt->n[0] *= dd; ppt->n[1] *= dd; ppt->n[2] *= dd; } } } } if ( !ns ) { free(hash.item); return(ns); } /* step 2. checking if split by adjacent */ for (k=1; k<=mesh->nt; k++) { pt = &mesh->tria[k]; if ( !MS_EOK(pt) || pt->ref < 0 ) continue; else if ( pt->flag == 7 ) continue; /* geometric support */ ier = bezierCP(mesh,k,&pb); assert(ier); nc = 0; for (i=0; i<3; i++) { i1 = inxt[i]; i2 = inxt[i1]; if ( !MS_GET(pt->flag,i) && !MS_SIN(pt->tag[i]) ) { ip = hashGet(&hash,pt->v[i1],pt->v[i2]); if ( ip > 0 ) { MS_SET(pt->flag,i); nc++; if ( pt->tag[i] & MS_GEO ) { /* new point along edge */ ier = bezierInt(&pb,uv[i],o,no,to); assert(ier); ppt = &mesh->point[ip]; go = &mesh->geom[ppt->ig]; memcpy(go->n2,no,3*sizeof(double)); /* a computation of the tangent with respect to these two normals is possible */ ppt->n[0] = go->n1[1]*go->n2[2] - go->n1[2]*go->n2[1]; ppt->n[1] = go->n1[2]*go->n2[0] - go->n1[0]*go->n2[2]; ppt->n[2] = go->n1[0]*go->n2[1] - go->n1[1]*go->n2[0]; dd = ppt->n[0]*ppt->n[0] + ppt->n[1]*ppt->n[1] + ppt->n[2]*ppt->n[2]; if ( dd > EPSD2 ) { dd = 1.0 / sqrt(dd); ppt->n[0] *= dd; ppt->n[1] *= dd; ppt->n[2] *= dd; } } } } } if ( nc > 0 ) ++ns; } if ( info.ddebug && ns ) { fprintf(stdout," %d analyzed %d proposed\n",mesh->nt,ns); fflush(stdout); } /* step 3. splitting */ ns = 0; nt = mesh->nt; for (k=1; k<=nt; k++) { pt = &mesh->tria[k]; if ( !MS_EOK(pt) || pt->ref < 0 ) continue; else if ( pt->flag == 0 ) continue; j = -1; vx[0] = vx[1] = vx[2] = 0; for (i=0; i<3; i++) { i1 = inxt[i]; i2 = inxt[i1]; if ( MS_GET(pt->flag,i) ) { vx[i] = hashGet(&hash,pt->v[i1],pt->v[i2]); assert(vx[i]); j = i; } } if ( pt->flag == 1 || pt->flag == 2 || pt->flag == 4 ) { ier = split1(mesh,met,k,j,vx); assert(ier); ns++; } else if ( pt->flag == 7 ) { ier = split3(mesh,met,k,vx); assert(ier); ns++; } else { ier = split2(mesh,met,k,vx); assert(ier); ns++; } } if ( (info.ddebug || abs(info.imprim) > 5) && ns > 0 ) fprintf(stdout," %7d splitted\n",ns); free(hash.item); return(ns); }
/* Computes the Bezier coefficients associated to the underlying curve to [p0p1]. isrid = 0 if p0p1 is not a special edge, 1 otherwise */ inline void bezierEdge(MMG5_pMesh mesh,int i0,int i1,double b0[3],double b1[3],char isrid,double v[3]) { MMG5_pPoint p0,p1; double ux,uy,uz,*n1,*n2,*t,ps1,ps2; p0 = &mesh->point[i0]; p1 = &mesh->point[i1]; ux = p1->c[0] - p0->c[0]; uy = p1->c[1] - p0->c[1]; uz = p1->c[2] - p0->c[2]; if ( isrid ) { if ( MS_SIN(p0->tag) ) { b0[0] = p0->c[0] + _MMG5_ATHIRD*ux; b0[1] = p0->c[1] + _MMG5_ATHIRD*uy; b0[2] = p0->c[2] + _MMG5_ATHIRD*uz; } else { t = &p0->n[0]; ps1 = t[0]*ux + t[1]*uy + t[2]*uz; b0[0] = p0->c[0] + _MMG5_ATHIRD*ps1*t[0]; b0[1] = p0->c[1] + _MMG5_ATHIRD*ps1*t[1]; b0[2] = p0->c[2] + _MMG5_ATHIRD*ps1*t[2]; } if (MS_SIN(p1->tag) ) { b1[0] = p1->c[0] - _MMG5_ATHIRD*ux; b1[1] = p1->c[1] - _MMG5_ATHIRD*uy; b1[2] = p1->c[2] - _MMG5_ATHIRD*uz; } else { t = &p1->n[0]; ps1 = -(t[0]*ux + t[1]*uy + t[2]*uz); b1[0] = p1->c[0] + _MMG5_ATHIRD*ps1*t[0]; b1[1] = p1->c[1] + _MMG5_ATHIRD*ps1*t[1]; b1[2] = p1->c[2] + _MMG5_ATHIRD*ps1*t[2]; } } /* regular edge */ else { if ( MS_SIN(p0->tag) ) { b0[0] = p0->c[0] + _MMG5_ATHIRD*ux; b0[1] = p0->c[1] + _MMG5_ATHIRD*uy; b0[2] = p0->c[2] + _MMG5_ATHIRD*uz; } else { if ( MG_GEO & p0->tag ) { n1 = &mesh->xpoint[p0->ig].n1[0]; n2 = &mesh->xpoint[p0->ig].n2[0]; ps1 = v[0]*n1[0] + v[1]*n1[1] + v[2]*n1[2]; ps2 = v[0]*n2[0] + v[1]*n2[1] + v[2]*n2[2]; if ( ps1 < ps2 ) { n1 = &mesh->xpoint[p0->ig].n2[0]; ps1 = ps2; } } else if ( MG_REF & p0->tag ) { n1 = &mesh->xpoint[p0->ig].n1[0]; ps1 = ux*n1[0] + uy*n1[1] + uz*n1[2]; } else { n1 = &p0->n[0]; ps1 = ux*n1[0] + uy*n1[1] + uz*n1[2]; } b0[0] = _MMG5_ATHIRD*(2.0*p0->c[0] + p1->c[0] - ps1*n1[0]); b0[1] = _MMG5_ATHIRD*(2.0*p0->c[1] + p1->c[1] - ps1*n1[1]); b0[2] = _MMG5_ATHIRD*(2.0*p0->c[2] + p1->c[2] - ps1*n1[2]); } if ( MS_SIN(p1->tag) ) { b1[0] = p1->c[0] - _MMG5_ATHIRD*ux; b1[1] = p1->c[1] - _MMG5_ATHIRD*uy; b1[2] = p1->c[2] - _MMG5_ATHIRD*uz; } else { if ( MG_GEO & p1->tag ) { n1 = &mesh->xpoint[p1->ig].n1[0]; n2 = &mesh->xpoint[p1->ig].n2[0]; ps1 = -(v[0]*n1[0] + v[1]*n1[1] + v[2]*n1[2]); ps2 = -(v[0]*n2[0] + v[1]*n2[1] + v[2]*n2[2]); if ( fabs(ps2) < fabs(ps1) ) { n1 = &mesh->xpoint[p1->ig].n2[0]; ps1 = ps2; } } else if ( MG_REF & p1->tag ) { n1 = &mesh->xpoint[p1->ig].n1[0]; ps1 = -(ux*n1[0] + uy*n1[1] + uz*n1[2]); } else { n1 = &p1->n[0]; ps1 = -(ux*n1[0] + uy*n1[1] + uz*n1[2]); } b1[0] = _MMG5_ATHIRD*(2.0*p1->c[0] + p0->c[0] - ps1*n1[0]); b1[1] = _MMG5_ATHIRD*(2.0*p1->c[1] + p0->c[1] - ps1*n1[1]); b1[2] = _MMG5_ATHIRD*(2.0*p1->c[2] + p0->c[2] - ps1*n1[2]); } } }
/** * \param mesh pointer toward the mesh structure. * \param met pointer toward the sol structure. * \param np0 index of edge's extremity. * \param np1 index of edge's extremity. * \param isedg 1 if the edge is a ridge, 0 otherwise. * \return length of edge according to the prescribed metric. * * Compute length of edge \f$[i0;i1]\f$ according to the prescribed aniso. * metric. * */ double _MMG5_lenedg_ani(MMG5_pMesh mesh,MMG5_pSol met,int np0,int np1,char isedg) { MMG5_pPoint p0,p1; double gammaprim0[3],gammaprim1[3],t[3],*n1,*n2,ux,uy,uz,ps1,ps2,l0,l1; double *m0,*m1,met0[6],met1[6]; p0 = &mesh->point[np0]; p1 = &mesh->point[np1]; ux = p1->c[0] - p0->c[0]; uy = p1->c[1] - p0->c[1]; uz = p1->c[2] - p0->c[2]; /* computation of the two tangent vectors to the underlying curve of [i0i1] */ if ( MS_SIN(p0->tag) ) { gammaprim0[0] = ux; gammaprim0[1] = uy; gammaprim0[2] = uz; } else if ( isedg ) { memcpy(t,p0->n,3*sizeof(double)); ps1 = ux*t[0] + uy*t[1] + uz*t[2]; gammaprim0[0] = ps1*t[0]; gammaprim0[1] = ps1*t[1]; gammaprim0[2] = ps1*t[2]; } else { if ( MG_GEO & p0->tag ) { //assert(p0->ig); n1 = &mesh->xpoint[p0->ig].n1[0]; n2 = &mesh->xpoint[p0->ig].n2[0]; ps1 = ux*n1[0] + uy*n1[1] + uz*n1[2]; ps2 = ux*n2[0] + uy*n2[1] + uz*n2[2]; if ( fabs(ps2) < fabs(ps1) ) { n1 = &mesh->xpoint[p0->ig].n2[0]; ps1 = ps2; } } else if ( MG_REF & p0->tag ) { n1 = &mesh->xpoint[p0->ig].n1[0]; ps1 = ux*n1[0] + uy*n1[1] + uz*n1[2]; } else { n1 = &(p0->n[0]); ps1 = ux*n1[0] + uy*n1[1] + uz*n1[2]; } gammaprim0[0] = ux - ps1*n1[0]; gammaprim0[1] = uy - ps1*n1[1]; gammaprim0[2] = uz - ps1*n1[2]; } if ( MS_SIN(p1->tag) ) { gammaprim1[0] = -ux; gammaprim1[1] = -uy; gammaprim1[2] = -uz; } else if ( isedg ) { memcpy(t,p1->n,3*sizeof(double)); ps1 = -ux*t[0] - uy*t[1] - uz*t[2]; gammaprim1[0] = ps1*t[0]; gammaprim1[1] = ps1*t[1]; gammaprim1[2] = ps1*t[2]; } else { if ( MG_GEO & p1->tag ) { n1 = &mesh->xpoint[p1->ig].n1[0]; n2 = &mesh->xpoint[p1->ig].n2[0]; ps1 = -ux*n1[0] - uy*n1[1] - uz*n1[2]; ps2 = -ux*n2[0] - uy*n2[1] - uz*n2[2]; if ( fabs(ps2) < fabs(ps1) ) { n1 = &mesh->xpoint[p1->ig].n2[0]; ps1 = ps2; } } else if ( MG_REF & p1->tag ) { n1 = &mesh->xpoint[p1->ig].n1[0]; ps1 = - ux*n1[0] - uy*n1[1] - uz*n1[2]; } else { n1 = &(p1->n[0]); ps1 = -ux*n1[0] - uy*n1[1] - uz*n1[2]; } gammaprim1[0] = - ux - ps1*n1[0]; gammaprim1[1] = - uy - ps1*n1[1]; gammaprim1[2] = - uz - ps1*n1[2]; } /* Set metrics */ if ( MS_SIN(p0->tag) ) { m0 = &met->m[6*(np0)+1]; } else if ( MG_GEO & p0->tag ) { if ( !_MMG5_buildridmet(mesh,met,np0,ux,uy,uz,met0) ) return(-1.0); m0 = met0; } else { m0 = &met->m[6*(np0)+1]; } if ( MS_SIN(p1->tag) ) { m1 = &met->m[6*(np1)+1]; } else if ( MG_GEO & p1->tag ) { if ( !_MMG5_buildridmet(mesh,met,np1,ux,uy,uz,met1) ) return(-1.0); m1 = met1; } else { m1 = &met->m[6*(np1)+1]; } /* computation of the length of the two tangent vectors in their respective tangent plane */ l0 = m0[0]*gammaprim0[0]*gammaprim0[0] + m0[3]*gammaprim0[1]*gammaprim0[1] \ + m0[5]*gammaprim0[2]*gammaprim0[2] \ + 2.0*m0[1]*gammaprim0[0]*gammaprim0[1] + 2.0*m0[2]*gammaprim0[0]*gammaprim0[2] \ + 2.0*m0[4]*gammaprim0[1]*gammaprim0[2]; l1 = m1[0]*gammaprim1[0]*gammaprim1[0] + m1[3]*gammaprim1[1]*gammaprim1[1] \ + m1[5]*gammaprim1[2]*gammaprim1[2] \ +2.0*m1[1]*gammaprim1[0]*gammaprim1[1] + 2.0*m1[2]*gammaprim1[0]*gammaprim1[2] \ + 2.0*m1[4]*gammaprim1[1]*gammaprim1[2]; if(l0 < 0) { printf("neg %e\n",l0); l0 =1; } if(l1 < 0) { printf("neg1 %e\n",l1); l1 = 1; } l0 = 0.5*(sqrt(l0) + sqrt(l1)); return(l0); }
/** * \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); }
/** * \param mesh pointer toward the mesh structure. * \param met pointer toward the meric structure. * \param ptt pointer toward the triangle structure. * \return The computed area. * * Compute the area of the surface triangle \a ptt with respect to * the anisotropic metric \a met. * */ double _MMG5_surftri_ani(MMG5_pMesh mesh,MMG5_pSol met,MMG5_pTria ptt) { MMG5_pPoint p[3]; _MMG5_Bezier b; int np[3]; double surf,ux,uy,uz,dens,m[3][6],J[3][2],mJ[3][2],tJmJ[2][2]; char i,i1,i2; surf = 0.0; for (i=0; i<3; i++) { np[i] = ptt->v[i]; p[i] = &mesh->point[np[i]]; } if ( !_MMG5_bezierCP(mesh,ptt,&b,1) ) return(0.0); /* Set metric tensors at vertices of tria iel */ for(i=0; i<3; i++) { i1 = _MMG5_inxt2[i]; i2 = _MMG5_iprv2[i]; ux = 0.5*(p[i1]->c[0]+p[i2]->c[0]) - p[i]->c[0]; uy = 0.5*(p[i1]->c[1]+p[i2]->c[1]) - p[i]->c[1]; uz = 0.5*(p[i1]->c[2]+p[i2]->c[2]) - p[i]->c[2]; if ( MS_SIN(p[i]->tag) ) { memcpy(&m[i][0],&met->m[6*np[i]+1],6*sizeof(double)); } else if ( p[i]->tag & MG_GEO ) { if ( !_MMG5_buildridmet(mesh,met,np[i],ux,uy,uz,&m[i][0]) ) return(0.0); } else { memcpy(&m[i][0],&met->m[6*np[i]+1],6*sizeof(double)); } } /* Compute density integrand of volume at the 3 vertices of T */ for (i=0; i<3; i++) { if ( i == 0 ) { J[0][0] = 3.0*( b.b[7][0] - b.b[0][0] ) ; J[0][1] = 3.0*( b.b[6][0] - b.b[0][0] ); J[1][0] = 3.0*( b.b[7][1] - b.b[0][1] ) ; J[1][1] = 3.0*( b.b[6][1] - b.b[0][1] ); J[2][0] = 3.0*( b.b[7][2] - b.b[0][2] ) ; J[2][1] = 3.0*( b.b[6][2] - b.b[0][2] ); } else if ( i == 1 ) { J[0][0] = 3.0*( b.b[1][0] - b.b[8][0] ) ; J[0][1] = 3.0*( b.b[3][0] - b.b[8][0] ); J[1][0] = 3.0*( b.b[1][1] - b.b[8][1] ) ; J[1][1] = 3.0*( b.b[3][1] - b.b[8][1] ); J[2][0] = 3.0*( b.b[1][2] - b.b[8][2] ) ; J[2][1] = 3.0*( b.b[3][2] - b.b[8][2] ); } else { J[0][0] = 3.0*( b.b[4][0] - b.b[5][0] ) ; J[0][1] = 3.0*( b.b[2][0] - b.b[5][0] ); J[1][0] = 3.0*( b.b[4][1] - b.b[5][1] ) ; J[1][1] = 3.0*( b.b[2][1] - b.b[5][1] ); J[2][0] = 3.0*( b.b[4][2] - b.b[5][2] ) ; J[2][1] = 3.0*( b.b[2][2] - b.b[5][2] ); } mJ[0][0] = m[i][0]*J[0][0] + m[i][1]*J[1][0] + m[i][2]*J[2][0]; mJ[1][0] = m[i][1]*J[0][0] + m[i][3]*J[1][0] + m[i][4]*J[2][0]; mJ[2][0] = m[i][2]*J[0][0] + m[i][4]*J[1][0] + m[i][5]*J[2][0]; mJ[0][1] = m[i][0]*J[0][1] + m[i][1]*J[1][1] + m[i][2]*J[2][1]; mJ[1][1] = m[i][1]*J[0][1] + m[i][3]*J[1][1] + m[i][4]*J[2][1]; mJ[2][1] = m[i][2]*J[0][1] + m[i][4]*J[1][1] + m[i][5]*J[2][1]; /* dens = sqrt(tJacsigma * M * Jacsigma )*/ tJmJ[0][0] = J[0][0]*mJ[0][0] + J[1][0]*mJ[1][0] + J[2][0]*mJ[2][0]; tJmJ[0][1] = J[0][0]*mJ[0][1] + J[1][0]*mJ[1][1] + J[2][0]*mJ[2][1]; tJmJ[1][0] = J[0][1]*mJ[0][0] + J[1][1]*mJ[1][0] + J[2][1]*mJ[2][0]; tJmJ[1][1] = J[0][1]*mJ[0][1] + J[1][1]*mJ[1][1] + J[2][1]*mJ[2][1]; dens = tJmJ[0][0]*tJmJ[1][1] - tJmJ[1][0]*tJmJ[0][1]; if ( dens < 0.0 ) { //fprintf(stdout," ## Density should be positive : %E for elt %d %d %d \n",dens,ptt->v[0],ptt->v[1],ptt->v[2]); //return(0.0); } surf += sqrt(fabs(dens)); } surf *= _MMG5_ATHIRD; return(surf); }
/* 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); }
/* return Bezier control points on triangle iel (cf. Vlachos) */ int bezierCP(pMesh mesh,int iel,pBezier pb) { pTria pt; pPoint p[3]; double *n1,*n2,nt[3],ps,ps2,dd,ux,uy,uz; char i,i1,i2; pt = &mesh->tria[iel]; p[0] = &mesh->point[pt->v[0]]; p[1] = &mesh->point[pt->v[1]]; p[2] = &mesh->point[pt->v[2]]; memset(pb,0,sizeof(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) ) { nortri(mesh,pt,pb->n[i]); } else if ( MS_EDG(p[i]->tag) ) { nortri(mesh,pt,nt); n1 = &mesh->geom[p[i]->ig].n1[0]; n2 = &mesh->geom[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 = inxt[i]; i2 = inxt[i1]; 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]; /* choose normals */ n1 = pb->n[i1]; n2 = pb->n[i2]; /* check for boundary curve */ if ( MS_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 / (ux*ux + uy*uy + uz*uz); 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 > 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 / (ux*ux + uy*uy + uz*uz); 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 > 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++) { pb->b[9][0] -= (0.5*ATHIRD*pb->b[i][0]); pb->b[9][1] -= (0.5*ATHIRD*pb->b[i][1]); pb->b[9][2] -= (0.5*ATHIRD*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); }
/* return point o at (u,v) in Bezier patch and normal */ int bezierInt(pBezier pb,double uv[2],double o[3],double no[3],double to[3]) { double dd,u,v,w,ps,ux,uy,uz; char i; memset(to,0,3*sizeof(double)); u = uv[0]; v = uv[1]; w = 1 - u - v; /* coordinates + normals */ for (i=0; i<3; i++) { o[i] = pb->b[0][i]*w*w*w + pb->b[1][i]*u*u*u + pb->b[2][i]*v*v*v \ + 3.0 * (pb->b[3][i]*u*u*v + pb->b[4][i]*u*v*v + pb->b[5][i]*w*v*v \ + pb->b[6][i]*w*w*v + pb->b[7][i]*w*w*u + pb->b[8][i]*w*u*u)\ + 6.0 * pb->b[9][i]*u*v*w; /* quadratic interpolation of normals */ no[i] = pb->n[0][i]*w*w + pb->n[1][i]*u*u + pb->n[2][i]*v*v \ + 2.0*(pb->n[3][i]*u*v + pb->n[4][i]*v*w + pb->n[5][i]*u*w); /* linear interpolation, not used here no[i] = pb->n[0][i]*w + pb->n[1][i]*u + pb->n[2][i]*v; */ } /* tangent */ if ( w < EPSD2 ) { ux = pb->b[2][0] - pb->b[1][0]; uy = pb->b[2][1] - pb->b[1][1]; uz = pb->b[2][2] - pb->b[1][2]; dd = ux*ux + uy*uy + uz*uz; if ( dd > EPSD2 ) { dd = 1.0 / sqrt(dd); ux *= dd; uy *= dd; uz *= dd; } if ( MS_SIN(pb->p[1]->tag) ) { pb->t[1][0] = ux; pb->t[1][1] = uy; pb->t[1][2] = uz; } if ( MS_SIN(pb->p[2]->tag) ) { pb->t[2][0] = ux; pb->t[2][1] = uy; pb->t[2][2] = uz; } ps = pb->t[1][0]* pb->t[2][0] + pb->t[1][1]* pb->t[2][1] + pb->t[1][2]* pb->t[2][2]; if ( ps > 0.0 ) { to[0] = pb->t[1][0]*u + pb->t[2][0]*v; to[1] = pb->t[1][1]*u + pb->t[2][1]*v; to[2] = pb->t[1][2]*u + pb->t[2][2]*v; } else { to[0] = -pb->t[1][0]*u + pb->t[2][0]*v; to[1] = -pb->t[1][1]*u + pb->t[2][1]*v; to[2] = -pb->t[1][2]*u + pb->t[2][2]*v; } } if ( u < EPSD2 ) { ux = pb->b[2][0] - pb->b[0][0]; uy = pb->b[2][1] - pb->b[0][1]; uz = pb->b[2][2] - pb->b[0][2]; dd = ux*ux + uy*uy + uz*uz; if ( dd > EPSD2 ) { dd = 1.0 / sqrt(dd); ux *= dd; uy *= dd; uz *= dd; } if ( MS_SIN(pb->p[0]->tag) ) { pb->t[0][0] = ux; pb->t[0][1] = uy; pb->t[0][2] = uz; } if ( MS_SIN(pb->p[2]->tag) ) { pb->t[2][0] = ux; pb->t[2][1] = uy; pb->t[2][2] = uz; } ps = pb->t[0][0]* pb->t[2][0] + pb->t[0][1]* pb->t[2][1] + pb->t[0][2]* pb->t[2][2]; if ( ps > 0.0 ) { to[0] = pb->t[0][0]*w + pb->t[2][0]*v; to[1] = pb->t[0][1]*w + pb->t[2][1]*v; to[2] = pb->t[0][2]*w + pb->t[2][2]*v; } else { to[0] = -pb->t[0][0]*w + pb->t[2][0]*v; to[1] = -pb->t[0][1]*w + pb->t[2][1]*v; to[2] = -pb->t[0][2]*w + pb->t[2][2]*v; } } if ( v < EPSD2 ) { ux = pb->b[1][0] - pb->b[0][0]; uy = pb->b[1][1] - pb->b[0][1]; uz = pb->b[1][2] - pb->b[0][2]; dd = ux*ux + uy*uy + uz*uz; if ( dd > EPSD2 ) { dd = 1.0 / sqrt(dd); ux *= dd; uy *= dd; uz *= dd; } if ( MS_SIN(pb->p[0]->tag) ) { pb->t[0][0] = ux; pb->t[0][1] = uy; pb->t[0][2] = uz; } if ( MS_SIN(pb->p[1]->tag) ) { pb->t[1][0] = ux; pb->t[1][1] = uy; pb->t[1][2] = uz; } ps = pb->t[0][0]* pb->t[1][0] + pb->t[0][1]* pb->t[1][1] + pb->t[0][2]* pb->t[1][2]; if ( ps > 0.0 ) { to[0] = pb->t[0][0]*w + pb->t[1][0]*u; to[1] = pb->t[0][1]*w + pb->t[1][1]*u; to[2] = pb->t[0][2]*w + pb->t[1][2]*u; } else { to[0] = -pb->t[0][0]*w + pb->t[1][0]*u; to[1] = -pb->t[0][1]*w + pb->t[1][1]*u; to[2] = -pb->t[0][2]*w + pb->t[1][2]*u; } } dd = no[0]*no[0] + no[1]*no[1] + no[2]*no[2]; if ( dd > EPSD2 ) { dd = 1.0 / sqrt(dd); no[0] *= dd; no[1] *= dd; no[2] *= dd; } dd = to[0]*to[0] + to[1]*to[1] + to[2]*to[2]; if ( dd > EPSD2 ) { dd = 1.0 / sqrt(dd); to[0] *= dd; to[1] *= dd; to[2] *= dd; } return(1); }