/*****************************************************************************1*2* Elmer, A Finite Element Software for Multiphysical Problems3*4* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland5*6* This program is free software; you can redistribute it and/or7* modify it under the terms of the GNU General Public License8* as published by the Free Software Foundation; either version 29* of the License, or (at your option) any later version.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program (in file fem/GPL-2); if not, write to the18* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,19* Boston, MA 02110-1301, USA.20*21*****************************************************************************/2223/*******************************************************************************24*25* Definition of three node triangle element.26*27*******************************************************************************28*29* Author: Juha Ruokolainen30*31* Address: CSC - IT Center for Science Ltd.32* Keilaranta 14, P.O. BOX 40533* 02101 Espoo, Finland34* Tel. +358 0 457 272335* Telefax: +358 0 457 230236* EMail: [email protected]37*38* Date: 20 Sep 199539*40*41* Modification history:42*43* 28 Sep 1995, changed call to elm_triangle_normal to geo_triangle normal44* routine elm_... doesn't exist anymore45*46******************************************************************************/4748#include "../elmerpost.h"49#include <elements.h>5051/*52* Three node triangular surface element53*54* 2 v=155* / \56* / \57* / \58* 0-------1 u=159*60*/61static double N[3][3] =62{63{ 1.0,-1.0,-1.0 },64{ 0.0, 1.0, 0.0 },65{ 0.0, 0.0, 1.0 }66};6768static double NodeU[3] = { 0.0, 1.0, 0.0 };69static double NodeV[3] = { 0.0, 0.0, 1.0 };7071/*******************************************************************************72*73* Name: elm_3node_triangle_triangulate( geometry_t *,element_t * )74*75* Purpose: Triangulate an element. The process also builds up an edge76* table and adds new nodes to node table. The triangulation77* and edge table is stored in geometry_t *geom-structure.78*79* Parameters:80*81* Input: (geometry_t *) pointer to structure holding triangulation82* (element_t *) element to triangulate83*84* Output: (geometry_t *) structure is modified85*86* Return value: FALSE if malloc() fails, TRUE otherwise87*88******************************************************************************/89int elm_3node_triangle_triangulate( geometry_t *geom, element_t *Elm, element_t *Parent)90{91double u,v,w,s;9293int i,j;9495triangle_t triangle;9697triangle.Element = Parent;98for( i=0; i<3; i++ )99{100triangle.v[i] = Elm->Topology[i];101triangle.Edge[i] = TRUE;102}103geo_triangle_normal( geom,&triangle );104105return geo_add_triangle( geom, &triangle );106}107108/*******************************************************************************109*110* Name: elm_3node_triangle_point_inside(111* double *nx,double *ny,double *nz,112* double px, double py, double pz,113* double *u,double *v,double *w )114*115* Purpose: Find if point (px,py,pz) is inside the element, and return116* element coordinates of the point.117*118* Parameters:119*120* Input: (double *) nx,ny,nz node coordinates121* (double) px,py,pz point to consider122*123* Output: (double *) u,v,w point in element coordinates if inside124*125* Return value: in/out status126*127* NOTES: the goal here can be hard for more involved element types. kind of128* trivial for this one... (TODO: this is for xy-plane tri only)129*130******************************************************************************/131int elm_3node_triangle_point_inside132(133double *nx, double *ny, double *nz,134double px, double py, double pz, double *u,double *v,double *w135)136{137double A00,A01,A10,A11,B00,B01,B10,B11,detA;138139if ( px > MAX(MAX( nx[0],nx[1] ),nx[2] ) ) return FALSE;140if ( px < MIN(MIN( nx[0],nx[1] ),nx[2] ) ) return FALSE;141142if ( py > MAX(MAX( ny[0],ny[1] ),ny[2] ) ) return FALSE;143if ( py < MIN(MIN( ny[0],ny[1] ),ny[2] ) ) return FALSE;144145#if 0146if ( pz > MAX(MAX( nz[0],nz[1] ),nz[2] ) ) return FALSE;147if ( pz < MIN(MIN( nz[0],nz[1] ),nz[2] ) ) return FALSE;148#endif149150A00 = nx[1] - nx[0];151A01 = nx[2] - nx[0];152A10 = ny[1] - ny[0];153A11 = ny[2] - ny[0];154155detA = A00*A11 - A01*A10;156if ( ABS(detA) < AEPS )157{158fprintf( stderr, "3node_triangle_inside: SINGULAR, HUH? \n" );159return FALSE;160}161162detA = 1/detA;163164B00 = A11*detA;165B10 = -A10*detA;166B01 = -A01*detA;167B11 = A00*detA;168169px -= nx[0];170py -= ny[0];171*u = *v = *w = 0.0;172173*u = B00*px + B01*py;174if ( *u < 0.0 || *u > 1.0 ) return FALSE;175176*v = B10*px + B11*py;177if ( *v < 0.0 || *v > 1.0 ) return FALSE;178179return (*u + *v) <= 1.0;180}181182/*******************************************************************************183*184* Name: elm_3node_triangle_fvalue( double *,double,double )185*186* Purpose: return value of a quantity given on nodes at point (u,v)187*188*189* Parameters:190*191* Input: (double *) quantity values at nodes192* (double u,double v) point where value is evaluated193*194* Output: none195*196* Return value: quantity value197*198******************************************************************************/199static double elm_3node_triangle_fvalue(double *F,double u,double v)200{201return F[0]*(1-u-v) + F[1]*u + F[2]*v;202}203204/*******************************************************************************205*206* Name: elm_3node_triangle_dndu_fvalue( double *,double,double )207*208* Purpose: return value of a first partial derivate in (u) of a209* quantity given on nodes at point (u,v)210*211*212* Parameters:213*214* Input: (double *) quantity values at nodes215* (double u,double v) point where value is evaluated216*217* Output: none218*219* Return value: quantity value220*221******************************************************************************/222static double elm_3node_triangle_dndu_fvalue(double *F,double u,double v)223{224return -F[0] + F[1];225}226227/*******************************************************************************228*229* Name: elm_3node_triangle_dndv_fvalue( double *,double,double )230*231* Purpose: return value of a first partial derivate in (v) of a232* quantity given on nodes at point (u,v)233*234*235* Parameters:236*237* Input: (double *) quantity values at nodes238* (double u,double v) point where value is evaluated239*240* Output: none241*242* Return value: quantity value243*244******************************************************************************/245static double elm_3node_triangle_dndv_fvalue(double *F,double u,double v)246{247return -F[0] + F[2];248}249250#define FEPS 1.0E-9251252/*******************************************************************************253*254* Name: elm_3node_triangle_isoline255*256* Purpose: Extract a iso line from triangle with given threshold257*258* Parameters:259*260* Input: (double) K, contour threshold261* (double *) F, contour quantity262* (double *) C, color quantity263* (double *) X,Y,Z vertex coords.264*265* Output: (line_t *) place to store the line266*267* Return value: number of lines generated (0 or 1)268*269*******************************************************************************/270int elm_3node_triangle_isoline271(272double K, double *F, double *C,double *X,double *Y,double *Z,line_t *Line273)274{275double F0=F[0],F1=F[1],F2=F[2],t;276int i,n=0;277278int S0 = (F0 > K);279int S1 = (F1 > K);280int S2 = (F2 > K);281int S = S0 + S1 + S2;282283if ( S==0 || S==3 ) return 0;284285if (S0 ^ S1)286{287if ( ABS(F1-F0) < FEPS ) return 0;288t = (K-F0)/(F1-F0);289290Line->x[n] = t*(X[1] - X[0]) + X[0];291Line->y[n] = t*(Y[1] - Y[0]) + Y[0];292Line->z[n] = t*(Z[1] - Z[0]) + Z[0];293Line->f[n] = K;294if ( C ) Line->c[n] = t*(C[1] - C[0]) + C[0];295n++;296}297298if (S0 ^ S2)299{300if ( ABS(F2-F0) < FEPS ) return 0;301t = (K-F0)/(F2-F0);302303Line->x[n] = t*(X[2] - X[0]) + X[0];304Line->y[n] = t*(Y[2] - Y[0]) + Y[0];305Line->z[n] = t*(Z[2] - Z[0]) + Z[0];306Line->f[n] = K;307if ( C ) Line->c[n] = t*(C[2] - C[0]) + C[0];308n++;309}310311if (S1 ^ S2)312{313if ( ABS(F2-F1) < FEPS ) return 0;314t = (K-F1)/(F2-F1);315316Line->x[n] = t*(X[2] - X[1]) + X[1];317Line->y[n] = t*(Y[2] - Y[1]) + Y[1];318Line->z[n] = t*(Z[2] - Z[1]) + Z[1];319Line->f[n] = K;320if ( C ) Line->c[n] = t*(C[2] - C[1]) + C[1];321n++;322}323324return (n>=2);325}326327328/*******************************************************************************329*330* Name: elm_3node_triangle_initialize()331*332* Purpose: Register the element type333*334* Parameters:335*336* Input: (char *) description of the element337* (int) numeric code for the element338*339* Output: Global list of element types is modified340*341* Return value: malloc() success342*343******************************************************************************/344int elm_3node_triangle_initialize()345{346static char *Name = "ELM_3NODE_TRIANGLE";347348element_type_t ElementDef;349int elm_add_element_type();350351ElementDef.ElementName = Name;352ElementDef.ElementCode = 303;353354ElementDef.NumberOfNodes = 3;355356ElementDef.NodeU = NodeU;357ElementDef.NodeV = NodeV;358ElementDef.NodeW = NULL;359360ElementDef.PartialU = (double (*)())elm_3node_triangle_dndu_fvalue;361ElementDef.PartialV = (double (*)())elm_3node_triangle_dndv_fvalue;362ElementDef.PartialW = (double (*)())NULL;363364ElementDef.FunctionValue = (double (*)())elm_3node_triangle_fvalue;365ElementDef.Triangulate = (int (*)())elm_3node_triangle_triangulate;366ElementDef.IsoLine = (int (*)())elm_3node_triangle_isoline;367ElementDef.PointInside = (int (*)())elm_3node_triangle_point_inside;368ElementDef.IsoSurface = (int (*)())NULL;369370return elm_add_element_type( &ElementDef ) ;371}372373374