Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/post/src/geometry.c
3196 views
1
/*****************************************************************************
2
*
3
* Elmer, A Finite Element Software for Multiphysical Problems
4
*
5
* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland
6
*
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version 2
10
* of the License, or (at your option) any later version.
11
*
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
16
*
17
* You should have received a copy of the GNU General Public License
18
* along with this program (in file fem/GPL-2); if not, write to the
19
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20
* Boston, MA 02110-1301, USA.
21
*
22
*****************************************************************************/
23
24
/*******************************************************************************
25
*
26
* Geometry manipulation utilities.
27
*
28
*******************************************************************************
29
*
30
* Author: Juha Ruokolainen
31
*
32
* Address: Keilaranta 14, P.O. BOX 405
33
* 02101 Espoo, Finland
34
* Tel. +358 0 457 2723
35
* Telefax: +358 0 457 2302
36
* EMail: [email protected]
37
*
38
* Date: 26 Sep 1995
39
*
40
* Modification history:
41
*
42
* 27 Sep 1995: added geo_add_edge - routine, see below, Juha Ruokolainen
43
*
44
******************************************************************************/
45
46
#define MODULE_GEOMETRY
47
48
#include <elmerpost.h>
49
50
#include <tcl.h>
51
extern Tcl_Interp *TCLInterp;
52
53
void geo_free_groups( group_t *groups )
54
{
55
group_t *grp;
56
int gid = 0;
57
char str[64];
58
59
for( ; groups != NULL; gid++ )
60
{
61
grp = groups->Next;
62
63
sprintf( str, "GroupStatus(%d)", gid );
64
Tcl_UnlinkVar( TCLInterp, str );
65
66
free( groups );
67
groups = grp;
68
}
69
Tcl_SetVar( TCLInterp, "NumberOfGroups", "0", TCL_GLOBAL_ONLY );
70
}
71
72
int geo_group_id( element_model_t *model, char *name,int open )
73
{
74
group_t *group,*prevgroup;
75
int groupid = 0;
76
77
static char str[128];
78
79
prevgroup = model->Groups;
80
for( group = model->Groups; group!=NULL; group=group->Next )
81
{
82
if ( strcmp(group->Name, name) == 0 ) break;
83
groupid++;
84
prevgroup = group;
85
}
86
87
if ( !group )
88
{
89
if ( !prevgroup )
90
group = model->Groups = (group_t *)malloc(sizeof(group_t));
91
else
92
group = prevgroup->Next = (group_t *)malloc(sizeof(group_t));
93
94
sprintf( str, "GroupStatus(%d)", groupid );
95
Tcl_LinkVar( TCLInterp,str,(char *)&group->status,TCL_LINK_INT );
96
97
group->status = 1;
98
group->Next = NULL;
99
group->Name = (char *)malloc(strlen(name)+1);
100
strcpy(group->Name,name);
101
}
102
103
group->Open = open;
104
105
return groupid;
106
}
107
108
/*******************************************************************************
109
*
110
* Name: geo_add_vertex( geometry_t *, vertex_t * )
111
*
112
* Purpose: Add a vertex to triangulation description
113
*
114
* Parameters:
115
*
116
* Input: (geometry_t *) pointer to geometry structure to modify
117
* (vertex_t *) pointer to vertex to add
118
*
119
* Output: (geometry_t *) is modified
120
*
121
* Return value: TRUE if success, FALSE if malloc() fails
122
*
123
******************************************************************************/
124
int geo_add_vertex( geometry_t *geometry, vertex_t *vertex )
125
{
126
vertex_t *ptr;
127
128
if ( geometry->VertexCount >= geometry->MaxVertexCount )
129
{
130
geometry->MaxVertexCount += GEO_VERTEX_BLOCK_SIZE;
131
ptr = (vertex_t *)realloc(geometry->Vertices,geometry->MaxVertexCount*sizeof(vertex_t));
132
133
if ( !ptr )
134
{
135
fprintf( stderr, "FATAL: geo_add_vertex: Can't allocate memory.\n" );
136
return -1;
137
}
138
139
geometry->Vertices = ptr;
140
}
141
142
vertex->Faces = NULL;
143
geometry->Vertices[geometry->VertexCount++] = *vertex;
144
145
return (geometry->VertexCount-1);
146
}
147
148
/*******************************************************************************
149
*
150
* Name: geo_add_edge( geometry_t *, edge_t *,element_t * )
151
*
152
* Purpose: Add an edge to edge table
153
*
154
* Parameters:
155
* Input: (geometry_t *) pointer to geometry structure to modify
156
* (edge_t *) pointer to edge to add
157
* (element_t *) pointer to parent element
158
*
159
* Output: (geometry_t *) is modified
160
*
161
* Return value: TRUE if success, FALSE if malloc() fails
162
*
163
******************************************************************************/
164
int geo_add_edge( geometry_t *geometry,int v0,int v1,element_t *elm )
165
{
166
int swap;
167
edge_list_t *ptr;
168
169
if ( !GlobalOptions.VolumeEdges && elm->ElementType->ElementCode>=500 ) return TRUE;
170
171
if ( v0 > v1 ) { swap = v0; v0 = v1; v1 = swap; }
172
173
if ( v0 >= geometry->VertexCount || v1 >= geometry->VertexCount )
174
{
175
fprintf( stderr, "geo_add_edge: vertex number [%d,%d] out of range\n", v0,v1);
176
return FALSE;
177
}
178
179
180
for( ptr=geometry->Edges[v0].EdgeList; ptr != NULL; ptr=ptr->Next )
181
{
182
if ( v1 == ptr->Entry ) break;
183
}
184
185
if ( ptr != NULL )
186
{
187
if ( elm->ElementType->ElementCode < 300 )
188
{
189
ptr->Count = -1;
190
ptr->Element = elm;
191
} else if ( ptr->Count > 0 ) ptr->Count++;
192
} else
193
{
194
ptr = (edge_list_t *)malloc( sizeof(edge_list_t) );
195
if ( !ptr )
196
{
197
fprintf( stderr, "geo_add_edge: FATAL: can't alloc memory.\n" );
198
return FALSE;
199
}
200
if ( elm->ElementType->ElementCode < 300 )
201
ptr->Count = -1;
202
else
203
ptr->Count = 1;
204
ptr->Entry = v1;
205
ptr->Element = elm;
206
ptr->Next = geometry->Edges[v0].EdgeList;
207
208
geometry->Edges[v0].EdgeList = ptr;
209
}
210
211
return TRUE;
212
}
213
214
/*******************************************************************************
215
*
216
* Name: geo_free_edge_tables( geometry_t * )
217
*
218
* Purpose: free geometry edge tables
219
*
220
* Parameters:
221
* Input: (geometry_t *) pointer to geometry structure to modify
222
*
223
* Output: (geometry_t *) is modified
224
*
225
* Return value: void
226
*
227
******************************************************************************/
228
void geo_free_edge_tables( geometry_t *geometry )
229
{
230
edge_list_t *ptr,*ptr1;
231
int i;
232
233
if ( geometry->Edges )
234
{
235
for( i=0; i<geometry->VertexCount; i++ )
236
{
237
for( ptr=geometry->Edges[i].EdgeList; ptr != NULL; )
238
{
239
ptr1 = ptr->Next;
240
free( ptr );
241
ptr = ptr1;
242
}
243
geometry->Edges[i].EdgeList = NULL;
244
}
245
free( geometry->Edges );
246
geometry->Edges = NULL;
247
}
248
}
249
250
/*******************************************************************************
251
*
252
* Name: geo_free_vertex_face_tables( geometry_t * )
253
*
254
* Purpose: free geometry vertex face tables
255
*
256
* Parameters:
257
* Input: (geometry_t *) pointer to geometry structure to modify
258
*
259
* Output: (geometry_t *) is modified
260
*
261
* Return value: void
262
*
263
******************************************************************************/
264
void geo_free_vertex_face_tables( geometry_t *geometry )
265
{
266
vertex_face_t *face,*face1;
267
vertex_t *vertex;
268
int i;
269
270
for( i=0; i<geometry->VertexCount; i++ )
271
{
272
vertex = &geometry->Vertices[i];
273
for( face=vertex->Faces; face != NULL; )
274
{
275
face1 = face->Next;
276
free( face );
277
face = face1;
278
}
279
vertex->Faces = NULL;
280
}
281
}
282
283
/*******************************************************************************
284
*
285
* Name: geo_add_triangle( geometry_t *, triangle_t * )
286
*
287
* Purpose: Add a triangle to triangulation description. The vertices
288
* to which (triangle_t *) points must exist before this routine
289
* is called.
290
*
291
* Parameters:
292
*
293
* Input: (geometry_t *) pointer to geometry structure to modify
294
* (triangle_t *) pointer to triangle ito add
295
*
296
* Output: (geometry_t *) is modified
297
*
298
* Return value: TRUE if success, FALSE if malloc() fails
299
*
300
******************************************************************************/
301
int geo_add_triangle( geometry_t *geometry, triangle_t *triangle )
302
{
303
triangle_t *ptr,*tri;
304
vertex_t *vertex;
305
vertex_face_t *face;
306
307
int i,j,v0=triangle->v[0],v1=triangle->v[1],v2=triangle->v[2],swap,w0,w1,w2;
308
309
if ( v0 >= geometry->VertexCount || v1 >= geometry->VertexCount || v2 >= geometry->VertexCount)
310
{
311
fprintf( stderr, "geo_add_triangle: vertex number [%d,%d,%d] out of range\n", v0,v1,v2);
312
return FALSE;
313
}
314
315
if ( v0 > v1 ) { swap=v0; v0=v1; v1=swap; }
316
if ( v1 > v2 ) { swap=v1; v1=v2; v2=swap; }
317
if ( v0 > v1 ) { swap=v0; v0=v1; v1=swap; }
318
319
vertex = &geometry->Vertices[v0];
320
for( face=vertex->Faces; face != NULL; face=face->Next )
321
{
322
tri = &geometry->Triangles[face->Face];
323
324
if ( v0 == tri->v[0] )
325
if ( v1 == tri->v[1] )
326
if ( v2 == tri->v[2] )
327
{
328
if ( triangle->Element->ElementType->ElementCode < 500 )
329
{
330
tri->Count = - 1;
331
tri->Element = triangle->Element;
332
} else if ( tri->Count > 0 ) tri->Count++;
333
return TRUE;
334
}
335
}
336
337
if ( geometry->TriangleCount >= geometry->MaxTriangleCount )
338
{
339
geometry->MaxTriangleCount += GEO_TRIANGLE_BLOCK_SIZE;
340
ptr = (triangle_t *)realloc( geometry->Triangles,geometry->MaxTriangleCount*sizeof(triangle_t) );
341
if ( !ptr )
342
{
343
fprintf( stderr, "FATAL: geo_add_triangle: Can't allocate memory.\n" );
344
return FALSE;
345
}
346
347
geometry->Triangles = ptr;
348
}
349
350
if ( GlobalOptions.SurfaceSides ) {
351
if ( triangle->Edge[0] ) geo_add_edge( geometry,triangle->v[0],triangle->v[1],triangle->Element );
352
if ( triangle->Edge[1] ) geo_add_edge( geometry,triangle->v[1],triangle->v[2],triangle->Element );
353
if ( triangle->Edge[2] ) geo_add_edge( geometry,triangle->v[2],triangle->v[0],triangle->Element );
354
}
355
356
triangle->v[0] = v0;
357
triangle->v[1] = v1;
358
triangle->v[2] = v2;
359
360
for( j=0; j<3; j++ )
361
{
362
vertex = &geometry->Vertices[triangle->v[j]];
363
364
face = (vertex_face_t *)malloc( sizeof(vertex_face_t) );
365
if ( !face )
366
{
367
fprintf( stderr, "geo_add_triangle: FATAL: malloc() failed.\n" );
368
return FALSE;
369
}
370
371
face->Face = geometry->TriangleCount;
372
face->Next = vertex->Faces;
373
vertex->Faces = face;
374
}
375
376
if ( triangle->Element->ElementType->ElementCode < 500 )
377
triangle->Count = -1;
378
else
379
triangle->Count = 1;
380
geometry->Triangles[geometry->TriangleCount++] = *triangle;
381
382
return TRUE;
383
}
384
385
/*******************************************************************************
386
*
387
* Name: geo_triangle_normal
388
*
389
* Purpose: generate triangle face normal by cross product
390
*
391
* Parameters:
392
*
393
* Input: (geometry_t *) holding triangulation information
394
* (triangle_t *) the triangle for which the normal
395
* is computed
396
* (this could be index to geometry,hmm)
397
*
398
* Output: (triangle_t *) is modified
399
*
400
* Return value: void
401
*
402
******************************************************************************/
403
void geo_triangle_normal( geometry_t *geom,triangle_t *triangle )
404
{
405
int i;
406
407
double ax,ay,az,bx,by,bz,u,v,w,s,uu,vv,ww;
408
409
vertex_t *Vert = geom->Vertices;
410
411
int v0 = triangle->v[0];
412
int v1 = triangle->v[1];
413
int v2 = triangle->v[2];
414
415
if ( v0 >= geom->VertexCount || v1 >= geom->VertexCount || v2 >= geom->VertexCount)
416
{
417
fprintf( stderr, "geo_triangle_normal: vertex number [%d,%d,%d] out of range\n", v0,v1,v2);
418
return;
419
}
420
421
ax = Vert[triangle->v[1]].x[0] - Vert[triangle->v[0]].x[0];
422
ay = Vert[triangle->v[1]].x[1] - Vert[triangle->v[0]].x[1];
423
az = Vert[triangle->v[1]].x[2] - Vert[triangle->v[0]].x[2];
424
425
bx = Vert[triangle->v[2]].x[0] - Vert[triangle->v[0]].x[0];
426
by = Vert[triangle->v[2]].x[1] - Vert[triangle->v[0]].x[1];
427
bz = Vert[triangle->v[2]].x[2] - Vert[triangle->v[0]].x[2];
428
429
u = ay*bz - az*by;
430
v = az*bx - ax*bz;
431
w = ax*by - ay*bx;
432
s = 1.0 / sqrt(u*u + v*v + w*w);
433
434
u = u * s;
435
v = v * s;
436
w = w * s;
437
438
for( i=0; i<3; i++ )
439
{
440
triangle->u[i][0] = u;
441
triangle->u[i][1] = v;
442
triangle->u[i][2] = w;
443
}
444
445
triangle->Fu[0] = u;
446
triangle->Fu[1] = v;
447
triangle->Fu[2] = w;
448
}
449
450
451
/*******************************************************************************
452
*
453
* Name: geo_vertex_normals( geometry_t *, double )
454
*
455
* Purpose: Generete triangle vertex normals from face normals,
456
* by averaging face normals connected to same vertex
457
* and within a given angle.
458
*
459
* Parameters:
460
*
461
* Input: (geometry_t *) pointer to geometry structure to modify
462
* (double) threshold angle
463
*
464
* Output: (geometry_t *) is modified
465
*
466
* Return value: void
467
*
468
******************************************************************************/
469
void geo_vertex_normals( geometry_t *geometry, double Ang )
470
{
471
vertex_t *vertex,*p = geometry->Vertices;
472
473
vertex_face_t *Faces;
474
475
triangle_t *t = geometry->Triangles;
476
477
double CU,CV,CW,u,v,w,s,A;
478
479
int i,j,k;
480
481
A = cos( M_PI*Ang / 180.0 );
482
483
for( i=0; i<geometry->TriangleCount; i++ ) geo_triangle_normal( geometry,&t[i] );
484
485
for( i=0; i<geometry->TriangleCount; i++ ) /* loop through faces */
486
{
487
u = t[i].Fu[0];
488
v = t[i].Fu[1];
489
w = t[i].Fu[2];
490
491
for( j=0; j<3; j++ ) /* through face vertices */
492
{
493
t[i].u[j][0] = u;
494
t[i].u[j][1] = v;
495
t[i].u[j][2] = w;
496
497
vertex = &p[t[i].v[j]];
498
499
/*
500
* loop through faces connected to a vertex
501
*/
502
for( Faces=vertex->Faces; Faces != NULL; Faces=Faces->Next )
503
{
504
if ( Faces->Face == i ) continue;
505
506
CU = t[Faces->Face].Fu[0];
507
CV = t[Faces->Face].Fu[1];
508
CW = t[Faces->Face].Fu[2];
509
510
s = u*CU + v*CV + w*CW;
511
512
if ( ABS(s) >= A )
513
{
514
if ( s < 0.0 )
515
{
516
t[i].u[j][0] -= CU;
517
t[i].u[j][1] -= CV;
518
t[i].u[j][2] -= CW;
519
} else
520
{
521
t[i].u[j][0] += CU;
522
t[i].u[j][1] += CV;
523
t[i].u[j][2] += CW;
524
}
525
}
526
}
527
}
528
}
529
530
/*
531
* normalize
532
*/
533
for( i=0; i<geometry->TriangleCount; i++ )
534
for( j=0; j<3; j++ )
535
{
536
u = t[i].u[j][0];
537
v = t[i].u[j][1];
538
w = t[i].u[j][2];
539
s = sqrt( u*u + v*v + w*w );
540
541
if ( s > 1.0E-10 )
542
{
543
t[i].u[j][0] /= s;
544
t[i].u[j][1] /= s;
545
t[i].u[j][2] /= s;
546
}
547
}
548
}
549
550