Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
hash.c
Go to the documentation of this file.
1/* =============================================================================
2** This file is part of the mmg software package for the tetrahedral
3** mesh modification.
4** Copyright (c) Bx INP/CNRS/Inria/UBordeaux/UPMC, 2004-
5**
6** mmg is free software: you can redistribute it and/or modify it
7** under the terms of the GNU Lesser General Public License as published
8** by the Free Software Foundation, either version 3 of the License, or
9** (at your option) any later version.
10**
11** mmg is distributed in the hope that it will be useful, but WITHOUT
12** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13** FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14** License for more details.
15**
16** You should have received a copy of the GNU Lesser General Public
17** License and of the GNU General Public License along with mmg (in
18** files COPYING.LESSER and COPYING). If not, see
19** <http://www.gnu.org/licenses/>. Please read their terms carefully and
20** use this copy of the mmg distribution only if you accept them.
21** =============================================================================
22*/
23
35#include "mmgcommon_private.h"
36
58int MMG5_mmgHashTria(MMG5_pMesh mesh, MMG5_int *adjt, MMG5_Hash *hash, int chkISO) {
59 MMG5_pTria pt,pt1,pt2;
60 MMG5_hedge *ph;
61 MMG5_int kk;
62 MMG5_int *adja,hmax,k,ia,ib,jel,lel,dup,nmf;
63 int8_t i,i1,i2,j,l;
64 MMG5_int key;
65
66 /* adjust hash table params */
67 hmax =(MMG5_int)(3.71*mesh->np);
68 hash->siz = mesh->np;
69 hash->max = hmax + 1;
70 hash->nxt = hash->siz;
71 MMG5_ADD_MEM(mesh,(hash->max+1)*sizeof(MMG5_hedge),"hash table",return 0);
72 MMG5_SAFE_CALLOC(hash->item,hash->max+1,MMG5_hedge,return 0);
73
74 for (k=hash->siz; k<hash->max; k++)
75 hash->item[k].nxt = k+1;
76
77 if ( mesh->info.ddebug ) fprintf(stdout," h- stage 1: init\n");
78
79 /* hash triangles */
80 ++mesh->base;
81 dup = nmf = 0;
82 for (k=1; k<=mesh->nt; k++) {
83 pt = &mesh->tria[k];
84 if ( !MG_EOK(pt) ) continue;
85
86 pt->flag = 0;
87 // base field of triangles has to be setted because it is used in setadj (mmgs
88 // and mmg3d) to detect moebius strip and to flip tria orientation
89 pt->base = mesh->base;
90
91 adja = &adjt[3*(k-1)+1];
92 for (i=0; i<3; i++) {
93
94 if ( !MG_EOK(pt) ) continue;
95
96 /* Skip parallel edges */
97 if( (pt->tag[i] & MG_PARBDY) && !(pt->tag[i] & MG_PARBDYBDY) ) continue;
98
99 i1 = MMG5_inxt2[i];
100 i2 = MMG5_iprv2[i];
101
102 /* compute key */
103 ia = MG_MIN(pt->v[i1],pt->v[i2]);
104 ib = MG_MAX(pt->v[i1],pt->v[i2]);
105 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
106 ph = &hash->item[key];
107
108 /* store edge */
109 if ( ph->a == 0 ) {
110 ph->a = ia;
111 ph->b = ib;
112 ph->k = 3*k + i;
113 ph->nxt = 0;
114 ++ph->s;
115 continue;
116 }
117 /* update info about adjacent */
118#ifndef NDEBUG
119 int8_t ok = 0;
120#endif
121 while ( ph->a ) {
122 if ( ph->a == ia && ph->b == ib ) {
123 jel = ph->k / 3;
124 j = ph->k % 3;
125 pt1 = &mesh->tria[jel];
126 /* discard duplicate face */
127 if ( pt1->v[j] == pt->v[i] ) {
128 pt->v[0] = 0;
129 dup++;
130 }
131 /* update adjacent */
132 else if ( !adjt[3*(jel-1)+1+j] ) {
133 adja[i] = 3*jel + j;
134 adjt[3*(jel-1)+1+j] = 3*k + i;
135 ++ph->s;
136 }
137 /* non-manifold case */
138 else if ( adja[i] != 3*jel+j ) {
139 lel = adjt[3*(jel-1)+1+j]/3;
140 l = adjt[3*(jel-1)+1+j]%3;
141 pt2 = &mesh->tria[lel];
142
143 if ( chkISO && ( (pt->ref == mesh->info.isoref) || (pt->ref < 0)) ) {
144 adjt[3*(lel-1)+1+l] = 0;
145 adja[i] = 3*jel+j;
146 adjt[3*(jel-1)+1+j] = 3*k + i;
147 }
148 pt->tag[i] |= MG_NOM;
149 pt1->tag[j] |= MG_NOM;
150 pt2->tag[l] |= MG_NOM;
151 nmf++;
152 ++ph->s;
153 }
154#ifndef NDEBUG
155 ok = 1;
156#endif
157 break;
158 }
159 else if ( !ph->nxt ) {
160 ph->nxt = hash->nxt;
161 ph = &hash->item[ph->nxt];
162 assert(ph);
163
164 if ( hash->nxt >= hash->max-1 ) {
165 if ( mesh->info.ddebug ) {
166 fprintf(stderr,"\n ## Warning: %s: memory alloc problem (edge):"
167 " %" MMG5_PRId "\n",__func__,hash->max);
168 }
170 "MMG5_edge",
171 MMG5_DEL_MEM(mesh,hash->item);
172 return 0);
173
174 ph = &hash->item[hash->nxt];
175
176 for (kk=ph->nxt; kk<hash->max; kk++)
177 hash->item[kk].nxt = kk+1;
178 }
179
180 hash->nxt = ph->nxt;
181 ph->a = ia;
182 ph->b = ib;
183 ph->k = 3*k + i;
184 ph->nxt = 0;
185 ++ph->s;
186#ifndef NDEBUG
187 ok = 1;
188#endif
189 break;
190 }
191 else
192 ph = &hash->item[ph->nxt];
193 }
194 assert(ok);
195 }
196 }
197
198 /* Now loop on "only" parallel edges in order to add a MG_BDY tag on those
199 * that are found in the hash table and their adjacents (if manifold; in the
200 * non-manifold case the MG_NOM tag suffices).
201 *
202 * Rationale:
203 * - put MG_BDY tags on edges that are contact edges between a "true"
204 * geometrical boundary (!MG_PARBDY || (MG_PARBDY && MG_PARBDYBDY) and a
205 * purele parallel (non-geometrical) one (MG_PARBDY && !MG_PARBDYBDY);
206 * - add also a MG_PARBDYBDY tag on those edges (as it cannot be inherited
207 * from any triangle there) and their extremities.
208 */
209 for (k=1; k<=mesh->nt; k++) {
210 pt = &mesh->tria[k];
211 if ( !MG_EOK(pt) ) continue;
212 for (i=0; i<3; i++) {
213 if( !(pt->tag[i] & MG_PARBDY) || (pt->tag[i] & MG_PARBDYBDY) ) continue;
214 i1 = MMG5_inxt2[i];
215 i2 = MMG5_iprv2[i];
216
217 /* compute key */
218 ia = MG_MIN(pt->v[i1],pt->v[i2]);
219 ib = MG_MAX(pt->v[i1],pt->v[i2]);
220 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
221 ph = &hash->item[key];
222
223 if ( ph->a == 0 ) continue;
224 while( ph->a ) {
225 if ( ph->a == ia && ph->b == ib ) {
226 jel = ph->k / 3;
227 j = ph->k % 3;
228 pt1 = &mesh->tria[jel];
229 pt1->tag[j] |= MG_BDY + MG_PARBDYBDY;
230 mesh->point[ia].tag |= MG_PARBDYBDY;
231 mesh->point[ib].tag |= MG_PARBDYBDY;
232 /* update adjacent */
233 lel = adjt[3*(jel-1)+1+j]/3;
234 l = adjt[3*(jel-1)+1+j]%3;
235 if( lel ) {
236 pt2 = &mesh->tria[lel];
237 pt2->tag[l] |= MG_BDY + MG_PARBDYBDY;
238 mesh->point[ia].tag |= MG_PARBDYBDY;
239 mesh->point[ib].tag |= MG_PARBDYBDY;
240 }
241 break;
242 } else if ( !ph->nxt ) {
243 break;
244 } else {
245 ph = &hash->item[ph->nxt];
246 }
247 }
248 }
249 }
250
251 /* set tag */
252 for (k=1; k<=mesh->nt; k++) {
253 pt = &mesh->tria[k];
254 for (i=0; i<3; i++) {
255 if ( pt->tag[i] & MG_NOM ) {
256 mesh->point[pt->v[MMG5_inxt2[i]]].tag |= MG_NOM;
257 mesh->point[pt->v[MMG5_iprv2[i]]].tag |= MG_NOM;
258 }
259 }
260 }
261
262 if ( abs(mesh->info.imprim) > 5 && dup+nmf > 0 ) {
263 fprintf(stdout," ## "); fflush(stdout);
264 if ( nmf > 0 ) fprintf(stdout,"[non-manifold model] ");
265 if ( dup > 0 ) fprintf(stdout," %" MMG5_PRId " duplicate removed",dup);
266 fprintf(stdout,"\n");
267 }
268 if ( mesh->info.ddebug ) fprintf(stdout," h- completed.\n");
269
270 return 1;
271}
272
286MMG5_int MMG5_hashFace(MMG5_pMesh mesh,MMG5_Hash *hash,MMG5_int ia,MMG5_int ib,MMG5_int ic,MMG5_int k) {
287 MMG5_hedge *ph;
288 MMG5_int key;
289 MMG5_int mins,maxs,sum,j;
290
291 mins = MG_MIN(ia,MG_MIN(ib,ic));
292 maxs = MG_MAX(ia,MG_MAX(ib,ic));
293
294 /* compute key */
295 sum = ia + ib + ic;
296 key = (MMG5_KA*(int64_t)mins + MMG5_KB*(int64_t)maxs) % hash->siz;
297 ph = &hash->item[key];
298
299 if ( ph->a ) {
300 if ( ph->a == mins && ph->b == maxs && ph->s == sum )
301 return ph->k;
302 else {
303 while ( ph->nxt && ph->nxt < hash->max ) {
304 ph = &hash->item[ph->nxt];
305 if ( ph->a == mins && ph->b == maxs && ph->s == sum ) return ph->k;
306 }
307 }
308 ph->nxt = hash->nxt;
309 ph = &hash->item[hash->nxt];
310 ph->a = mins;
311 ph->b = maxs;
312 ph->s = sum;
313 ph->k = k;
314 hash->nxt = ph->nxt;
315 ph->nxt = 0;
316
317 if ( hash->nxt >= hash->max ) {
318 MMG5_TAB_RECALLOC(mesh,hash->item,hash->max,MMG5_GAP,MMG5_hedge,"face",return 0;);
319 for (j=hash->nxt; j<hash->max; j++) hash->item[j].nxt = j+1;
320 }
321 return -1;
322 }
323
324 /* insert new face */
325 ph->a = mins;
326 ph->b = maxs;
327 ph->s = sum;
328 ph->k = k;
329 ph->nxt = 0;
330
331 return -1;
332}
333
345int MMG5_hashEdge(MMG5_pMesh mesh,MMG5_Hash *hash, MMG5_int a,MMG5_int b,MMG5_int k) {
346 MMG5_hedge *ph;
347 MMG5_int key;
348 MMG5_int ia,ib,j;
349
350 ia = MG_MIN(a,b);
351 ib = MG_MAX(a,b);
352 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
353 ph = &hash->item[key];
354
355 if ( ph->a == ia && ph->b == ib )
356 return 1;
357 else if ( ph->a ) {
358 while ( ph->nxt && ph->nxt < hash->max ) {
359 ph = &hash->item[ph->nxt];
360 if ( ph->a == ia && ph->b == ib ) return 1;
361 }
362 ph->nxt = hash->nxt;
363 ph = &hash->item[hash->nxt];
364
365 if ( hash->nxt >= hash->max-1 ) {
366 if ( mesh->info.ddebug )
367 fprintf(stderr,"\n ## Warning: %s: memory alloc problem (edge):"
368 " %" MMG5_PRId "\n",__func__,hash->max);
369
371 "MMG5_edge",return 0);
372 /* ph pointer may be false after realloc */
373 ph = &hash->item[hash->nxt];
374
375 for (j=ph->nxt; j<hash->max; j++) hash->item[j].nxt = j+1;
376 }
377 hash->nxt = ph->nxt;
378 }
379
380 /* insert new edge */
381 ph->a = ia;
382 ph->b = ib;
383 ph->k = k;
384 ph->nxt = 0;
385
386 return 1;
387}
388
400int MMG5_hashUpdate(MMG5_Hash *hash, MMG5_int a,MMG5_int b,MMG5_int k) {
401 MMG5_hedge *ph;
402 MMG5_int key;
403 MMG5_int ia,ib;
404
405 ia = MG_MIN(a,b);
406 ib = MG_MAX(a,b);
407 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
408 ph = &hash->item[key];
409
410 while ( ph->a ) {
411 if ( ph->a == ia && ph->b == ib ) {
412 ph->k = k;
413 return 1;
414 }
415
416 if ( !ph->nxt ) return 0;
417
418 ph = &hash->item[ph->nxt];
419
420 }
421
422 return 0;
423}
424
437int MMG5_hashEdgeTag(MMG5_pMesh mesh,MMG5_Hash *hash, MMG5_int a,MMG5_int b,int16_t tag) {
438 MMG5_hedge *ph;
439 MMG5_int key;
440 MMG5_int ia,ib,j;
441
442 ia = MG_MIN(a,b);
443 ib = MG_MAX(a,b);
444 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
445 ph = &hash->item[key];
446
447 if ( ph->a ) {
448 if ( ph->a == ia && ph->b == ib ) {
449 ph->k |= tag;
450 return ph->k;
451 }
452 else {
453 while ( ph->nxt && ph->nxt < hash->max ) {
454 ph = &hash->item[ph->nxt];
455 if ( ph->a == ia && ph->b == ib ) {
456 ph->k |= tag;
457 return ph->k;
458 }
459 }
460 }
461 ph->nxt = hash->nxt;
462 ph = &hash->item[hash->nxt];
463 ph->a = ia;
464 ph->b = ib;
465 ph->k = tag;
466 hash->nxt = ph->nxt;
467 ph->nxt = 0;
468
469 if ( hash->nxt >= hash->max ) {
471 "edge hash table",return 0);
472 for (j=hash->nxt; j<hash->max; j++) hash->item[j].nxt = j+1;
473 }
474 return tag;
475 }
476
477 /* insert new edge */
478 ph->a = ia;
479 ph->b = ib;
480 ph->k = tag;
481 ph->nxt = 0;
482
483 return tag;
484}
485
495MMG5_int MMG5_hashGet(MMG5_Hash *hash,MMG5_int a,MMG5_int b) {
496 MMG5_hedge *ph;
497 MMG5_int key;
498 MMG5_int ia,ib;
499
500 if ( !hash->item ) return 0;
501
502 ia = MG_MIN(a,b);
503 ib = MG_MAX(a,b);
504 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
505 ph = &hash->item[key];
506
507 if ( !ph->a ) return 0;
508 if ( ph->a == ia && ph->b == ib ) return ph->k;
509 while ( ph->nxt ) {
510 ph = &hash->item[ph->nxt];
511 if ( ph->a == ia && ph->b == ib ) return ph->k;
512 }
513 return 0;
514}
515
526int MMG5_hashNew(MMG5_pMesh mesh,MMG5_Hash *hash,MMG5_int hsiz,MMG5_int hmax) {
527 MMG5_int k;
528
529 /* adjust hash table params */
530 hash->siz = hsiz+1;
531 hash->max = hmax + 2;
532 hash->nxt = hash->siz;
533
534 MMG5_ADD_MEM(mesh,(hash->max+1)*sizeof(MMG5_hedge),"hash table",
535 return 0);
536 MMG5_SAFE_CALLOC(hash->item,(hash->max+1),MMG5_hedge,return 0);
537
538 for (k=hash->siz; k<hash->max; k++)
539 hash->item[k].nxt = k+1;
540
541 return 1;
542}
if(!ier) exit(EXIT_FAILURE)
MMG5_pMesh * mesh
MMG5_int MMG5_hashFace(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int ia, MMG5_int ib, MMG5_int ic, MMG5_int k)
Definition: hash.c:286
int MMG5_hashEdgeTag(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int a, MMG5_int b, int16_t tag)
Definition: hash.c:437
int MMG5_mmgHashTria(MMG5_pMesh mesh, MMG5_int *adjt, MMG5_Hash *hash, int chkISO)
Definition: hash.c:58
int MMG5_hashUpdate(MMG5_Hash *hash, MMG5_int a, MMG5_int b, MMG5_int k)
Definition: hash.c:400
int MMG5_hashNew(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int hsiz, MMG5_int hmax)
Definition: hash.c:526
MMG5_int MMG5_hashGet(MMG5_Hash *hash, MMG5_int a, MMG5_int b)
Definition: hash.c:495
int MMG5_hashEdge(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int a, MMG5_int b, MMG5_int k)
Definition: hash.c:345
#define MMG5_SAFE_CALLOC(ptr, size, type, law)
#define MG_EOK(pt)
#define MG_PARBDY
#define MG_MIN(a, b)
#define MG_MAX(a, b)
#define MMG5_GAP
#define MMG5_ADD_MEM(mesh, size, message, law)
static const uint8_t MMG5_iprv2[3]
#define MMG5_KB
#define MMG5_TAB_RECALLOC(mesh, ptr, initSize, wantedGap, type, message, law)
static const uint8_t MMG5_inxt2[6]
#define MG_BDY
#define MG_NOM
#define MMG5_KA
#define MG_PARBDYBDY
#define MMG5_DEL_MEM(mesh, ptr)
Identic as MMG5_HGeom but use MMG5_hedge to store edges instead of MMG5_hgeom (memory economy).
Definition: libmmgtypes.h:595
MMG5_int max
Definition: libmmgtypes.h:596
MMG5_int nxt
Definition: libmmgtypes.h:596
MMG5_hedge * item
Definition: libmmgtypes.h:597
MMG5_int siz
Definition: libmmgtypes.h:596
int8_t ddebug
Definition: libmmgtypes.h:532
MMG5_int isoref
Definition: libmmgtypes.h:521
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_Info info
Definition: libmmgtypes.h:651
MMG5_pPoint point
Definition: libmmgtypes.h:641
double gap
Definition: libmmgtypes.h:608
MMG5_int base
Definition: libmmgtypes.h:616
MMG5_int nt
Definition: libmmgtypes.h:612
MMG5_pTria tria
Definition: libmmgtypes.h:647
MMG5_int np
Definition: libmmgtypes.h:612
int16_t tag
Definition: libmmgtypes.h:284
int16_t tag[3]
Definition: libmmgtypes.h:342
MMG5_int ref
Definition: libmmgtypes.h:335
MMG5_int flag
Definition: libmmgtypes.h:341
MMG5_int base
Definition: libmmgtypes.h:336
MMG5_int v[3]
Definition: libmmgtypes.h:334
Used to hash edges (memory economy compared to MMG5_hgeom).
Definition: libmmgtypes.h:584
MMG5_int s
Definition: libmmgtypes.h:587
MMG5_int b
Definition: libmmgtypes.h:585
MMG5_int a
Definition: libmmgtypes.h:585
MMG5_int k
Definition: libmmgtypes.h:586
MMG5_int nxt
Definition: libmmgtypes.h:585