/* 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); }
/* 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); }