Path: blob/devel/ElmerGUI/Application/src/meshutils.cpp
3203 views
/*****************************************************************************1* *2* Elmer, A Finite Element Software for Multiphysical Problems *3* *4* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland *5* *6* This program is free software; you can redistribute it and/or *7* modify it under the terms of the GNU General Public License *8* as published by the Free Software Foundation; either version 2 *9* 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 of *13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *14* GNU General Public License for more details. *15* *16* You should have received a copy of the GNU General Public License *17* along with this program (in file fem/GPL-2); if not, write to the *18* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *19* Boston, MA 02110-1301, USA. *20* *21*****************************************************************************/2223/*****************************************************************************24* *25* ElmerGUI meshutils *26* *27*****************************************************************************28* *29* Authors: Mikko Lyly, Juha Ruokolainen and Peter RÃ¥back *30* Email: [email protected] *31* Web: http://www.csc.fi/elmer *32* Address: CSC - IT Center for Science Ltd. *33* Keilaranta 14 *34* 02101 Espoo, Finland *35* *36* Original Date: 15 Mar 2008 *37* *38*****************************************************************************/3940#include <QtCore>41#include <iostream>42#include <stdlib.h>43#include <cmath>44#include "meshutils.h"45using namespace std;4647template <typename T>48T **AllocateDynamicArray(int nRows, int nCols) {49T **dynamicArray;50dynamicArray = new T*[nRows];51for( int i = 0 ; i < nRows ; i++ )52dynamicArray[i] = new T [nCols];53return dynamicArray;54}5556template <typename T>57void FreeDynamicArray(T** dArray) {58delete [] *dArray;59delete [] dArray;60}6162template <typename T>63T *AllocateDynamicVector(int nRows) {64T *dynamicArray;65dynamicArray = new T[nRows];66return dynamicArray;67}6869template <typename T>70void FreeDynamicVector(T* dArray) {71delete [] dArray;72}7374Meshutils::Meshutils()75{76}777879Meshutils::~Meshutils()80{81}828384// Clear mesh...85//-----------------------------------------------------------------------------86void Meshutils::clearMesh(mesh_t *mesh)87{88if(mesh == NULL)89return;9091mesh->clear();92delete mesh;9394cout << "Old mesh cleared" << endl;95cout.flush();96}979899100// Find surface elements for 3D elements when they are not provided101//----------------------------------------------------------------------------102void Meshutils::findSurfaceElements(mesh_t *mesh)103{104#define RESETENTRY1 \105h->node[0] = UNKNOWN; \106h->node[1] = UNKNOWN; \107h->element[0] = UNKNOWN; \108h->element[1] = UNKNOWN; \109h->index[0] = UNKNOWN; \110h->index[1] = UNKNOWN; \111h->next = NULL;112113class hashEntry {114public:115int node[2];116int element[2];117int index[2];118int face;119hashEntry *next;120};121122123if(mesh->getElements() == 0) return;124125int keys = mesh->getNodes();126hashEntry *hash = new hashEntry[keys];127128bool found;129hashEntry *h;130131for(int i=0; i<keys; i++) {132h = &hash[i];133RESETENTRY1;134}135136// TODO: only 1st and 2nd order elements137138static int familyfaces[9] = {0, 0, 0, 0, 0, 4, 5, 5, 6};139140static int faceedges8[] = {4, 4, 4, 4, 4, 4};141static int facemap8[][8] = {{0,1,2,3,8,9,10,11}, {4,5,6,7,16,17,18,19}, {0,1,5,4,8,13,16,12}, {1,2,6,5,9,14,17,13}, {2,3,7,6,10,15,18,14}, {3,0,4,7,11,12,19,15}};142143static int faceedges7[] = {3, 3, 4, 4, 4};144static int facemap7[][8] = {{0,1,2,6,7,8}, {3,4,5,12,13,14}, {0,1,4,3,6,10,12,9}, {1,2,5,4,7,11,13,10}, {2,0,3,5,8,9,14,11}};145146static int faceedges6[] = {4, 3, 3, 3, 3};147static int facemap6[][8] = {{0,1,2,3,5,6,7,8}, {0,1,4,5,10,9}, {1,2,4,6,11,10}, {2,3,4,7,12,11}, {3,0,4,8,9,12}};148149static int faceedges5[4] = {3, 3, 3, 3};150static int facemap5[][6] = {{0,1,2,4,5,6}, {0,1,3,4,8,7}, {1,2,3,5,9,8}, {2,0,3,6,7,9}};151152153for(int i=0; i < mesh->getElements(); i++) {154element_t *e = mesh->getElement(i);155156int facenodes = 0;157int *facemap = NULL;158int n[4];159160int family = e->getCode() / 100;161int faces = familyfaces[family];162163for(int f=0; f<faces; f++) {164if(family == 5) {165facenodes = faceedges5[f];166facemap = &facemap5[f][0];167}168else if(family == 6) {169facenodes = faceedges6[f];170facemap = &facemap6[f][0];171}172else if(family == 7) {173facenodes = faceedges7[f];174facemap = &facemap7[f][0];175}176else if(family == 8) {177facenodes = faceedges8[f];178facemap = &facemap8[f][0];179}180181for(int j=0; j < facenodes; j++)182n[j] = e->getNodeIndex(facemap[j]);183184// Order indexes in an increasing order185for(int k=facenodes-1;k>0;k--) {186for(int j=0;j<k;j++) {187if(n[j] > n[j+1]) {188int tmp = n[j+1];189n[j+1] = n[j];190n[j] = tmp;191}192}193}194195// three nodes define a face uniquely also for rectangles196h = &hash[n[0]];197found = false;198while(h->next) {199if((h->node[0] == n[1]) && (h->node[1] == n[2])) {200found = true;201break;202}203h = h->next;204}205206if(!found) {207h->node[0] = n[1];208h->node[1] = n[2];209h->element[0] = i;210h->index[0] = e->getIndex();211h->face = f;212213h->next = new hashEntry;214h = h->next;215RESETENTRY1;216} else {217h->index[1] = e->getIndex();218h->element[1] = i;219}220}221}222223// count faces that have different materials at either sides:224int allsurfaces = 0;225int surfaces = 0;226int maxindex1 = 0;227int maxindex2 = 0;228for(int i=0; i<keys; i++) {229h = &hash[i];230while(h->next){231if(h->element[0] > UNKNOWN) allsurfaces++;232if(h->index[0] != h->index[1]) surfaces++;233if(h->index[0] > maxindex1) maxindex1 = h->index[0];234if(h->index[1] > maxindex2) maxindex2 = h->index[1];235h = h->next;236}237}238cout << "Found " << surfaces << " interface faces of " << allsurfaces << endl;239240241// Create a index table such that all combinations of materials242// get different BC index243//int indextable[maxindex1+1][maxindex2+1];244int **indextable = AllocateDynamicArray<int>(maxindex1+1, maxindex2+1);245int index1,index2;246for(int i=0;i<=maxindex1;i++)247for(int j=0;j<=maxindex2;j++)248indextable[i][j] = 0;249250for(int i=0; i<keys; i++) {251h = &hash[i];252while(h->next){253if(h->index[0] != h->index[1]) {254index1 = h->index[0];255index2 = h->index[1];256if(index2 == -1) index2 = 0;257indextable[index1][index2] = 1;258}259h = h->next;260}261}262index1=0;263for(int i=0;i<=maxindex1;i++)264for(int j=0;j<=maxindex2;j++)265if(indextable[i][j]) indextable[i][j] = ++index1;266267cout << "Boundaries were numbered up to index " << index1 << endl;268269// Finally set the surfaces:270mesh->setSurfaces(surfaces);271mesh->newSurfaceArray(mesh->getSurfaces());272273surfaces = 0;274for(int i=0; i<keys; i++) {275h = &hash[i];276277while(h->next) {278if(h->index[0] != h->index[1]) {279surface_t *s = mesh->getSurface(surfaces);280281s->setElements(1);282s->newElementIndexes(2);283s->setElementIndex(0, h->element[0]);284s->setElementIndex(1, h->element[1]);285if(s->getElementIndex(1) >= 0) s->setElements(2); // ?????286287element_t *e = mesh->getElement(h->element[0]);288int code = e->getCode();289int family = code / 100;290int f = h->face;291292int faceedges = 0;293int *facemap = NULL;294int degree = 1;295296if(family == 5) {297faceedges = faceedges5[f];298if( code == 510) degree = 2;299facemap = &facemap5[f][0];300}301else if(family == 6) {302faceedges = faceedges6[f];303if( code == 613) degree = 2;304facemap = &facemap6[f][0];305}306else if(family == 7) {307faceedges = faceedges7[f];308if( code == 715) degree = 2;309facemap = &facemap7[f][0];310}311else if(family == 8) {312faceedges = faceedges8[f];313if( code == 820 ) degree = 2;314facemap = &facemap8[f][0];315}316317int facenodes = degree * faceedges;318if (code == 827) facenodes = 9;319320s->setNodes(facenodes);321s->setCode(100 * faceedges + facenodes);322s->newNodeIndexes(s->getNodes());323for(int j=0; j < s->getNodes(); j++)324s->setNodeIndex(j, e->getNodeIndex(facemap[j]));325326index1 = h->index[0];327index2 = h->index[1];328if(index2 < 0) index2 = 0;329330s->setIndex(indextable[index1][index2]);331332s->setEdges(s->getNodes());333s->newEdgeIndexes(s->getEdges());334for(int j=0; j < s->getEdges(); j++)335s->setEdgeIndex(j, UNKNOWN);336337s->setNature(PDE_BOUNDARY);338surfaces++;339}340h = h->next;341}342}343344delete [] hash;345}346347348349// Find parent elements for existing surfaces...350//----------------------------------------------------------------------------351void Meshutils::findEdgeElementParents(mesh_t *mesh)352{353#define RESETENTRY0 \354h->node[0] = UNKNOWN; \355h->node[1] = UNKNOWN; \356h->element[0] = UNKNOWN; \357h->element[1] = UNKNOWN; \358h->next = NULL;359360class hashEntry {361public:362int node[2];363int element[2];364hashEntry *next;365};366367int keys = mesh->getNodes();368hashEntry *hash = new hashEntry[keys];369370bool found;371hashEntry *h;372373for(int i=0; i<keys; i++) {374h = &hash[i];375RESETENTRY0;376}377378// TODO: only tetrahedron at the moment379380static int edgemap[][2] = {{0,1}, {1,2}, {2,0}};381382for(int i = 0; i < mesh->getSurfaces(); i++) {383surface_t *s = mesh->getSurface(i);384385for(int f = 0; f < 3; f++) {386int n0 = s->getNodeIndex(edgemap[f][0]);387int n1 = s->getNodeIndex(edgemap[f][1]);388389if(n1 < n0) {390int tmp = n1;391n1 = n0;392n0 = tmp;393}394395h = &hash[n0];396found = false;397while(h->next) {398if(h->node[0] == n1) {399found = true;400break;401}402h = h->next;403}404405if(!found) {406h->node[0] = n1;407h->element[0] = i;408h->next = new hashEntry;409h = h->next;410RESETENTRY0;411} else {412h->element[1] = i;413}414}415}416417// count faces:418int edges = 0;419for(int i = 0; i < keys; i++) {420h = &hash[i];421while((h = h->next) != NULL)422edges++;423}424425cout << "Found total of " << edges << " edges" << endl;426427// Finally find parents:428for(int i = 0; i < mesh->getEdges(); i++) {429edge_t *e = mesh->getEdge(i);430431int n0 = e->getNodeIndex(0);432int n1 = e->getNodeIndex(1);433434if(n1 < n0) {435int tmp = n1;436n1 = n0;437n0 = tmp;438}439440h = &hash[n0];441while(h->next) {442if(h->node[0] == n1) {443444// should we deallocate s->element if it exists?445e->setSurfaces(2);446e->newSurfaceIndexes(2);447448e->setSurfaceIndex(0, h->element[0]);449e->setSurfaceIndex(1, h->element[1]);450}451h = h->next;452}453}454455delete [] hash;456}457458459// Find parent elements for existing surfaces...460//----------------------------------------------------------------------------461void Meshutils::findSurfaceElementParents(mesh_t *mesh)462{463#define RESETENTRY0 \464h->node[0] = UNKNOWN; \465h->node[1] = UNKNOWN; \466h->element[0] = UNKNOWN; \467h->element[1] = UNKNOWN; \468h->next = NULL;469470class hashEntry {471public:472int node[2];473int element[2];474hashEntry *next;475};476477int keys = mesh->getNodes();478hashEntry *hash = new hashEntry[keys];479480bool found;481hashEntry *h;482483for(int i=0; i<keys; i++) {484h = &hash[i];485RESETENTRY0;486}487488// TODO: only tetrahedron at the moment489490static int facemap[][3] = {{0,1,2}, {0,1,3}, {0,2,3}, {1,2,3}};491492for(int i=0; i < mesh->getElements(); i++) {493element_t *e = mesh->getElement(i);494495for(int f=0; f<4; f++) {496int n0 = e->getNodeIndex(facemap[f][0]);497int n1 = e->getNodeIndex(facemap[f][1]);498int n2 = e->getNodeIndex(facemap[f][2]);499500if(n2 < n1) {501int tmp = n2;502n2 = n1;503n1 = tmp;504}505506if(n2 < n0) {507int tmp = n2;508n2 = n0;509n0 = tmp;510}511512if(n1 < n0) {513int tmp = n1;514n1 = n0;515n0 = tmp;516}517518h = &hash[n0];519found = false;520while(h->next) {521if((h->node[0] == n1) && (h->node[1] == n2)) {522found = true;523break;524}525h = h->next;526}527528if(!found) {529h->node[0] = n1;530h->node[1] = n2;531h->element[0] = i;532h->next = new hashEntry;533h = h->next;534RESETENTRY0;535} else {536h->element[1] = i;537}538}539}540541// count faces:542int faces = 0;543for(int i=0; i<keys; i++) {544h = &hash[i];545while((h = h->next) != NULL)546faces++;547}548549cout << "Found total of " << faces << " faces" << endl;550551// Finally find parents:552for(int i=0; i < mesh->getSurfaces(); i++) {553surface_t *s = mesh->getSurface(i);554555int n0 = s->getNodeIndex(0);556int n1 = s->getNodeIndex(1);557int n2 = s->getNodeIndex(2);558559if(n2 < n1) {560int tmp = n2;561n2 = n1;562n1 = tmp;563}564565if(n2 < n0) {566int tmp = n2;567n2 = n0;568n0 = tmp;569}570571if(n1 < n0) {572int tmp = n1;573n1 = n0;574n0 = tmp;575}576577h = &hash[n0];578while(h->next) {579if((h->node[0] == n1) && (h->node[1] == n2)) {580581// should we deallocate s->element if it exists?582s->setElements(2);583s->newElementIndexes(2);584585s->setElementIndex(0, h->element[0]);586s->setElementIndex(1, h->element[1]);587}588h = h->next;589}590}591592delete [] hash;593}594595596597// Find points for edge elements...598//-----------------------------------------------------------------------------599void Meshutils::findEdgeElementPoints(mesh_t *mesh)600{601class hashEntry {602public:603int edges;604int *edge;605};606607int keys = mesh->getNodes();608609hashEntry *hash = new hashEntry[keys];610611for(int i = 0; i < keys; i++) {612hashEntry *h = &hash[i];613h->edges = 0;614h->edge = NULL;615}616617for(int i = 0; i < mesh->getEdges(); i++) {618edge_t *e = mesh->getEdge(i);619620if(e->getNature() == PDE_BOUNDARY) {621for(int k = 0; k < 2; k++) {622int n = e->getNodeIndex(k);623624hashEntry *h = &hash[n];625626bool found = false;627for(int j = 0; j < h->edges; j++) {628if(h->edge[j] == i) {629found = true;630break;631}632}633634if(!found) {635int *tmp = new int[h->edges+1];636for(int j = 0; j < h->edges; j++)637tmp[j] = h->edge[j];638tmp[h->edges] = i;639delete [] h->edge;640641h->edges++;642h->edge = tmp;643}644}645}646}647648// count points:649int count = 0;650for(int i = 0; i < keys; i++) {651hashEntry *h = &hash[i];652if(h->edges > 0)653count++;654}655656cout << "Found " << count << " points on boundary edges" << endl;657cout.flush();658659// delete old points, if any:660if(mesh->getPoints() > 0) {661cout << "Deleting old points and creating new" << endl;662cout.flush();663for(int i = 0; i < mesh->getPoints(); i++) {664mesh->getPoint(i)->deleteNodeIndexes();665mesh->getPoint(i)->deleteEdgeIndexes();666}667mesh->deletePointArray();668}669670mesh->setPoints(count);671mesh->newPointArray(mesh->getPoints());672673count = 0;674for(int i = 0; i < keys; i++) {675hashEntry *h = &hash[i];676677if(h->edges > 0) {678point_t *p = mesh->getPoint(count++);679p->setNodes(1);680p->newNodeIndexes(1);681p->setNodeIndex(0, i);682p->setEdges(h->edges);683p->newEdgeIndexes(p->getEdges());684for(int j = 0; j < p->getEdges(); j++) {685p->setEdgeIndex(j, h->edge[j]);686}687p->setSharp(false);688}689}690691// delete temp stuff692for(int i = 0; i < keys; i++) {693hashEntry *h = &hash[i];694if(h->edges > 0)695delete [] h->edge;696}697698delete [] hash;699700// Inverse map701cout << "Constructing inverse map from edges to points" << endl;702cout.flush();703704for(int i=0; i < mesh->getPoints(); i++) {705point_t *p = mesh->getPoint(i);706707for(int j=0; j < p->getEdges(); j++) {708int k = p->getEdgeIndex(j);709if ( k<0 ) continue;710711edge_t *e = mesh->getEdge(k);712713// allocate space for two points, if not yet done:714if(e->getPoints() < 2) {715e->setPoints(2);716e->newPointIndexes(2);717e->setPointIndex(0, -1);718e->setPointIndex(1, -1);719}720721for(int r=0; r < e->getPoints(); r++) {722if(e->getPointIndex(r) < 0) {723e->setPointIndex(r, i);724break;725}726}727}728}729}730731732733// Find edges for surface elements...734//-----------------------------------------------------------------------------735void Meshutils::findSurfaceElementEdges(mesh_t *mesh)736{737#define RESETENTRY \738h->surfaces = 0; \739h->surface = NULL; \740h->parentindex[0] = UNKNOWN; \741h->parentindex[1] = UNKNOWN; \742h->next = NULL;743744int keys = mesh->getNodes();745746class hashEntry {747public:748int nodes;749int *node;750int nature;751int index;752int surfaces;753int *surface;754int parentindex[2];755hashEntry *next;756};757758hashEntry *hash = new hashEntry[keys];759760bool found;761hashEntry *h;762763for(int i=0; i<keys; i++) {764h = &hash[i];765RESETENTRY;766}767768bool createindexes = ((!mesh->getEdges()) && (!mesh->getElements()));769770// ????? should we test for mesh->edges ?????771// if ( mesh->edge && (mesh->getEdges() > 0) ) {772if ( mesh->getEdges() > 0 ) {773// add existing edges first:774for( int i=0; i<mesh->getEdges(); i++ )775{776edge_t *edge = mesh->getEdge(i);777int n0 = edge->getNodeIndex(0);778int n1 = edge->getNodeIndex(1);779780int m = (n0<n1) ? n0 : n1;781int n = (n0<n1) ? n1 : n0;782783h = &hash[m];784found = false;785while(h->next) {786if(h->node[0] == n) {787found = true;788break;789}790h = h->next;791}792793if(!found) {794h->nodes = edge->getNodes() - 1;795h->node = new int[h->nodes];796h->node[0] = n;797for( int j=1; j<h->nodes; j++ )798{799h->node[j] = edge->getNodeIndex(j+1);800}801h->surfaces = edge->getSurfaces();802h->surface = new int[edge->getSurfaces()];803for( int j=0; j < edge->getSurfaces(); j++ ) {804h->surface[j] = edge->getSurfaceIndex(j);805}806h->index = edge->getIndex();807h->nature = edge->getNature();808h->next = new hashEntry;809h = h->next;810RESETENTRY;811}812}813814mesh->setEdges(0);815mesh->deleteEdgeArray(); // delete [] mesh->edge;816}817818819static int triedgemap[][4] = { {0,1,3,6}, {1,2,4,7}, {2,0,5,8} };820static int quadedgemap[][4] = {{0,1,4,8}, {1,2,5,9}, {2,3,6,10}, {3,0,7,11}};821822823for(int i=0; i < mesh->getSurfaces(); i++) {824surface_t *s = mesh->getSurface(i);825826// loop over edges827for(int e=0; e < s->getEdges(); e++) {828int n0, n1,nrest[2] = { -1,-1 };829if((int)(s->getCode() / 100) == 3) {830n0 = s->getNodeIndex(triedgemap[e][0]);831n1 = s->getNodeIndex(triedgemap[e][1]);832if ( s->getCode() >= 306) nrest[0] = s->getNodeIndex(triedgemap[e][2]);833if ( s->getCode() >= 309) nrest[1] = s->getNodeIndex(triedgemap[e][3]);834} else if((int)(s->getCode() / 100) == 4) {835n0 = s->getNodeIndex(quadedgemap[e][0]);836n1 = s->getNodeIndex(quadedgemap[e][1]);837// corrected 4.11.2008:838if ( s->getCode() >= 408) nrest[0] = s->getNodeIndex(quadedgemap[e][2]);839if ( s->getCode() >= 412) nrest[1] = s->getNodeIndex(quadedgemap[e][3]);840} else {841cout << "findBoundaryElementEdges: error: unknown element code" << endl;842exit(0);843}844845int m = (n0<n1) ? n0 : n1;846int n = (n0<n1) ? n1 : n0;847848h = &hash[m];849found = false;850while(h->next) {851if(h->node[0] == n) {852found = true;853break;854}855h = h->next;856}857858if(!found) {859h->nodes = 1;860h->nodes += nrest[0] >=0 ? 1:0;861h->nodes += nrest[1] >=0 ? 1:0;862h->node = new int[h->nodes];863h->node[0] = n;864for( int j=1; j<h->nodes; j++ )865h->node[j] = nrest[j-1];866867h->surfaces = 1;868h->surface = new int[1];869h->surface[0] = i;870h->parentindex[0] = s->getIndex();871h->index = UNKNOWN;872h->nature = PDE_UNKNOWN;873h->next = new hashEntry;874h = h->next;875RESETENTRY;876} else {877int *tmp = new int[h->surfaces];878879found = false;880for(int j=0; j<h->surfaces; j++)881{882tmp[j] = h->surface[j];883if ( tmp[j] == i ) found = true;884}885if ( found ) {886delete [] tmp;887} else {888delete [] h->surface;889h->surface = new int[h->surfaces+1];890for(int j=0; j<h->surfaces; j++)891h->surface[j] = tmp[j];892h->surface[h->surfaces++] = i;893if( s->getIndex() < h->parentindex[0]) {894h->parentindex[1] = h->parentindex[0];895h->parentindex[0] = s->getIndex();896}897else {898h->parentindex[1] = s->getIndex();899}900delete [] tmp;901}902}903}904}905906// count edges:907int edges = 0;908for(int i=0; i<keys; i++) {909h = &hash[i];910while((h = h->next) != NULL)911edges++;912}913914915916cout << "Found " << edges << " edges on boundary" << endl;917918mesh->setEdges(edges);919mesh->newEdgeArray(edges); // edge = new edge_t[edges];920921if(createindexes) {922cout << "Creating edge indexes " << endl;923924int maxindex1 = UNKNOWN;925int maxindex2 = UNKNOWN;926927for(int i=0; i<keys; i++) {928h = &hash[i];929while(h->next){930if(h->parentindex[0] > maxindex1) maxindex1 = h->parentindex[0];931if(h->parentindex[1] > maxindex2) maxindex2 = h->parentindex[1];932h = h->next;933}934}935936// Create a index table such that all combinations of materials937// get different BC index938//int indextable[maxindex1+2][maxindex2+2];939int **indextable = AllocateDynamicArray<int>(maxindex1+2, maxindex2+2);940int index1,index2;941for(int i=-1;i<=maxindex1;i++)942for(int j=-1;j<=maxindex2;j++)943indextable[i+1][j+1] = 0;944945int edgebcs=0;946for(int i=0; i<keys; i++) {947h = &hash[i];948while(h->next){949if(h->parentindex[0] != h->parentindex[1]) {950index1 = h->parentindex[0];951index2 = h->parentindex[1];952indextable[index1+1][index2+1] = 1;953edgebcs += 1;954}955h = h->next;956}957}958959index1=0;960for(int i=-1;i<=maxindex1;i++)961for(int j=-1;j<=maxindex2;j++)962if(indextable[i+1][j+1]) indextable[i+1][j+1] = ++index1;963964cout << edgebcs << " boundary edges were numbered up to index " << index1 << endl;965966for(int i=0; i<keys; i++) {967h = &hash[i];968while(h->next){969if(h->parentindex[0] != h->parentindex[1]) {970index1 = h->parentindex[0];971index2 = h->parentindex[1];972h->index = indextable[index1+1][index2+1];973h->nature = PDE_BOUNDARY;974}975h = h->next;976}977}978}979980981// Create edges:982edges = 0;983for(int i=0; i<keys; i++) {984h = &hash[i];985while(h->next) {986edge_t *e = mesh->getEdge(edges++);987988e->setNature(h->nature);989e->setNodes(h->nodes + 1);990e->newNodeIndexes(e->getNodes());991e->setNodeIndex(0, i); // ?????992for( int j=1; j < e->getNodes(); j++ )993e->setNodeIndex(j, h->node[j-1]);994995e->setCode(200 + e->getNodes());996997e->setSurfaces(h->surfaces);998e->newSurfaceIndexes(max(e->getSurfaces(), 2));999e->setSurfaceIndex(0, -1);1000e->setSurfaceIndex(1, -1);10011002for(int j=0; j < e->getSurfaces(); j++)1003e->setSurfaceIndex(j, h->surface[j]);10041005e->setSharp(false);10061007e->setIndex(h->index);1008e->setPoints(0);1009h = h->next;1010}1011}10121013delete [] hash;10141015// Inverse map1016for(int i=0; i < mesh->getEdges(); i++) {1017edge_t *e = mesh->getEdge(i);10181019for(int j=0; j < e->getSurfaces(); j++) {1020int k = e->getSurfaceIndex(j);1021if ( k< 0 ) continue;10221023surface_t *s = mesh->getSurface(k);10241025for(int r=0; r < s->getEdges(); r++) {1026if(s->getEdgeIndex(r) < 0) {1027s->setEdgeIndex(r, i);1028break;1029}1030}1031}1032}10331034#if 01035cout << "*********************" << endl;1036for(int i=0; i<mesh->getEdges(); i++)1037cout << "Edge " << i << " nodes " << mesh->edge[i].node[0] << " "<< mesh->edge[i].node[0] << endl;10381039for(int i=0; i < mesh->getSurfaces(); i++)1040cout << "Surface " << i << " nodes "1041<< mesh->surface[i].node[0] << " "1042<< mesh->surface[i].node[1] << " "1043<< mesh->surface[i].node[2] << " "1044<< " Edges "1045<< mesh->surface[i].edge[0] << " "1046<< mesh->surface[i].edge[1] << " "1047<< mesh->surface[i].edge[2] << " "1048<< " Parents "1049<< mesh->surface[i].element[0] << " "1050<< mesh->surface[i].element[1] << " "1051<< endl;10521053cout.flush();1054#endif10551056}10571058105910601061// Find sharp points for edge elements...1062//-----------------------------------------------------------------------------1063void Meshutils::findSharpPoints(mesh_t *mesh, double limit)1064{1065QREAL_OR_FLOAT t0[3], t1[3];10661067cout << "Limit: " << limit << " degrees" << endl;1068cout.flush();10691070double angle;1071int count = 0;1072point_t *point = NULL;1073edge_t *edge = NULL;1074Helpers *helpers = new Helpers;10751076for(int i=0; i < mesh->getPoints(); i++) {1077point = mesh->getPoint(i);10781079if(point->getEdges() == 2) {1080int n = point->getNodeIndex(0);10811082int e0 = point->getEdgeIndex(0);1083int e1 = point->getEdgeIndex(1);10841085edge = mesh->getEdge(e0);1086int n0 = edge->getNodeIndex(0);1087if(edge->getNodeIndex(1) != n)1088n0 = edge->getNodeIndex(1);10891090edge = mesh->getEdge(e1);1091int n1 = edge->getNodeIndex(0);1092if(edge->getNodeIndex(1) != n)1093n1 = edge->getNodeIndex(1);10941095// unit tangent from node to node01096t0[0] = mesh->getNode(n0)->getX(0) - mesh->getNode(n)->getX(0);1097t0[1] = mesh->getNode(n0)->getX(1) - mesh->getNode(n)->getX(1);1098t0[2] = mesh->getNode(n0)->getX(2) - mesh->getNode(n)->getX(2);10991100// unit tangent from node to node11101t1[0] = mesh->getNode(n1)->getX(0) - mesh->getNode(n)->getX(0);1102t1[1] = mesh->getNode(n1)->getX(1) - mesh->getNode(n)->getX(1);1103t1[2] = mesh->getNode(n1)->getX(2) - mesh->getNode(n)->getX(2);11041105helpers->normalize(t0);1106helpers->normalize(t1);11071108double cosofangle = t0[0]*t1[0] + t0[1]*t1[1] + t0[2]*t1[2];1109angle = acos(cosofangle) / MYPI * 180.0;1110} else {1111angle = 0.0;1112}11131114point->setSharp(false);1115if(sqrt(angle*angle) < (180.0-limit) ) {1116point->setSharp(true);1117count++;1118}1119}11201121cout << "Found " << count << " sharp points" << endl;1122delete helpers;1123}1124112511261127// Find sharp edges for surface elements...1128//-----------------------------------------------------------------------------1129void Meshutils::findSharpEdges(mesh_t *mesh, double limit)1130{11311132cout << "Limit: " << limit << " degrees" << endl;1133cout.flush();11341135double angle;1136int count = 0;11371138for(int i=0; i<mesh->getEdges(); i++) {1139edge_t *edge = mesh->getEdge(i);11401141if(edge->getSurfaces() == 2) {1142int s0 = edge->getSurfaceIndex(0);1143int s1 = edge->getSurfaceIndex(1);1144double *n0 = mesh->getSurface(s0)->getNormalVec();1145double *n1 = mesh->getSurface(s1)->getNormalVec();1146double cosofangle = n0[0]*n1[0] + n0[1]*n1[1] + n0[2]*n1[2];1147cosofangle = std::abs(cosofangle);1148angle = acos(cosofangle) / MYPI * 180.0;1149} else {1150angle = 180.0;1151}11521153edge->setSharp(false);1154if(sqrt(angle*angle) > limit) {1155edge->setSharp(true);1156count++;1157}1158}11591160cout << "Found " << count << " sharp edges" << endl;1161}1162116311641165// Divide edge by sharp points...1166//-----------------------------------------------------------------------------1167int Meshutils::divideEdgeBySharpPoints(mesh_t *mesh)1168{1169class Bc {1170public:1171void propagateIndex(mesh_t* mesh, int index, int i) {1172edge_t *edge = mesh->getEdge(i);11731174// index is ok1175if(!edge->getSelected() || (edge->getIndex() != UNKNOWN)1176|| (edge->getNature() != PDE_BOUNDARY)) return;11771178// set index1179edge->setIndex(index);11801181// propagate index1182for(int j=0; j < edge->getPoints(); j++) {1183int k = edge->getPointIndex(j);1184point_t *point = mesh->getPoint(k);11851186// skip sharp points1187if(!point->isSharp()) {1188for(int m = 0; m < point->getEdges(); m++) {1189int n = point->getEdgeIndex(m);1190propagateIndex(mesh, index, n);1191}1192}11931194}1195}1196};119711981199// reset bc-indices on edges:1200int index = 0;1201int count = 0;12021203for(int i=0; i < mesh->getEdges(); i++)1204{1205edge_t *edge = mesh->getEdge(i);1206if((edge->getNature() == PDE_BOUNDARY) && !edge->getSelected())1207index = max(index, edge->getIndex());1208}1209index++;12101211// int edge_index[index];1212int *edge_index = new int[index];12131214for( int i=0; i<index; i++ )1215edge_index[i] = UNKNOWN;12161217index = 0;1218for(int i=0; i < mesh->getEdges(); i++)1219{1220edge_t *edge = mesh->getEdge(i);1221if (edge->getNature() == PDE_BOUNDARY)1222{1223if ( edge->getSelected() ) {1224count++;1225edge->setIndex(UNKNOWN);1226} else {1227if ( edge_index[edge->getIndex()] == UNKNOWN )1228edge_index[edge->getIndex()] = ++index;1229edge->setIndex(edge_index[edge->getIndex()]);1230}1231}1232}12331234if ( count==0 ) {1235cout << "No boundary edges to divide." << endl;1236return 0;1237}12381239Bc *bc = new Bc;12401241// recursively determine boundary parts:1242for(int i=0; i < mesh->getEdges(); i++)1243{1244edge_t *edge = mesh->getEdge(i);1245if(edge->getSelected() && (edge->getIndex() == UNKNOWN) && (edge->getNature() == PDE_BOUNDARY))1246bc->propagateIndex(mesh, ++index, i);1247}1248index++;12491250// Create a hopefully mesh independent indexing of groupings to enable1251// reapplying merge/division operations after remeshing. The indices1252// are given based on group bounding box corner distances from a given1253// point. Fails if two groups have same bbox, which should not happen1254// often though (?)12551256//double xmin[index], ymin[index], zmin[index];1257//double xmax[index], ymax[index], zmax[index];1258//double xc = 0, yc = 0, zc = 0, dist[index];1259//int cc[index], order[index], sorder[index];1260//double g_xmin,g_xmax,g_ymin,g_ymax,g_zmin,g_zmax;12611262double *xmin = new double[index];1263double *ymin = new double[index];1264double *zmin = new double[index];1265double *xmax = new double[index];1266double *ymax = new double[index];1267double *zmax = new double[index];1268double xc = 0, yc = 0, zc = 0;1269double *dist = new double[index];1270int *cc = new int[index];1271int *order = new int[index];1272int *sorder = new int[index];1273double g_xmin,g_xmax,g_ymin,g_ymax,g_zmin,g_zmax;12741275for( int i=0; i<index; i++ )1276{1277cc[i] = 0;1278order[i] = i;1279xmin[i] = ymin[i] = zmin[i] = 1e20;1280xmax[i] = ymax[i] = zmax[i] = -1e20;1281}12821283for( int i=0; i<mesh->getEdges(); i++ )1284{1285edge_t *edge = mesh->getEdge(i);1286if (edge->getNature() == PDE_BOUNDARY) {1287int k = edge->getIndex();1288for( int j=0; j < edge->getNodes(); j++ ) {1289int n = edge->getNodeIndex(j);1290cc[k]++;1291xmin[k] = min(xmin[k], mesh->getNode(n)->getX(0));1292ymin[k] = min(ymin[k], mesh->getNode(n)->getX(1));1293zmin[k] = min(zmin[k], mesh->getNode(n)->getX(2));12941295xmax[k] = max(xmax[k], mesh->getNode(n)->getX(0));1296ymax[k] = max(ymax[k], mesh->getNode(n)->getX(1));1297zmax[k] = max(zmax[k], mesh->getNode(n)->getX(2));1298}1299}1300}13011302g_xmin = g_ymin = g_zmin = 1e20;1303g_xmax = g_ymax = g_zmax = -1e20;1304for( int i=0; i<index; i++)1305{1306g_xmin = min(xmin[i],g_xmin);1307g_ymin = min(ymin[i],g_ymin);1308g_zmin = min(zmin[i],g_zmin);13091310g_xmax = max(xmax[i],g_xmax);1311g_ymax = max(ymax[i],g_ymax);1312g_zmax = max(zmax[i],g_zmax);1313}13141315double g_scale = max(max(g_xmax-g_xmin,g_ymax-g_ymin),g_zmax-g_zmin);1316double g_xp = g_xmax + 32.1345 * g_scale;1317double g_yp = g_ymin - 5.3*MYPI * g_scale;1318double g_zp = g_zmax + 8.1234 * g_scale;13191320for( int i=0; i<index; i++ )1321{1322dist[i] = 0;1323if ( cc[i]>0 ) {1324for( int j=0; j<8; j++ ) {1325switch(j) {1326case 0: xc=xmin[i]; yc=ymin[i]; zc=zmin[i]; break;1327case 1: xc=xmax[i]; break;1328case 2: yc=xmax[i]; break;1329case 3: xc=xmin[i]; break;1330case 4: zc=zmax[i]; break;1331case 5: yc=ymin[i]; break;1332case 6: xc=xmax[i]; break;1333case 7: yc=ymax[i]; break;1334}1335dist[i] += (xc-g_xp)*(xc-g_xp);1336dist[i] += (yc-g_yp)*(yc-g_yp);1337dist[i] += (zc-g_zp)*(zc-g_zp);1338}1339}1340}13411342sort_index( index, dist, order );1343for( int i=0; i<index; i++ )1344sorder[order[i]] = i;13451346for( int i=0; i<mesh->getEdges(); i++ )1347if ( mesh->getEdge(i)->getNature() == PDE_BOUNDARY )1348mesh->getEdge(i)->setIndex(sorder[mesh->getEdge(i)->getIndex()]);13491350--index;1351cout << "Edge divided into " << index << " parts" << endl;13521353delete bc;13541355return index;1356}135713581359void Meshutils::sort_index(int n, double *a, int *b)1360{1361#if WITH_QT61362vector<QPair<double, int>> list;13631364for(int i = 0; i < n; i++)1365list.push_back(qMakePair(a[i], b[i]));13661367sort(list.begin(), list.end());1368#else1369QList<QPair<double, int> > list;13701371for(int i = 0; i < n; i++)1372list << qMakePair(a[i], b[i]);13731374qSort(list);1375#endif1376for(int i = 0; i < n; i++) {1377a[i] = list[i].first;1378b[i] = list[i].second;1379}1380}138113821383// Divide surface by sharp edges...1384//-----------------------------------------------------------------------------1385int Meshutils::divideSurfaceBySharpEdges(mesh_t *mesh)1386{1387class Bc {1388public:1389void propagateIndex(mesh_t* mesh, int index, int i) {1390surface_t *surf = mesh->getSurface(i);13911392// index is ok1393if(!surf->getSelected() || (surf->getIndex() != UNKNOWN)1394|| (surf->getNature() != PDE_BOUNDARY) ) return;13951396// set index1397surf->setIndex(index);13981399// propagate index1400for(int j=0; j < surf->getEdges(); j++) {1401int k = surf->getEdgeIndex(j);1402edge_t *edge = mesh->getEdge(k);14031404// skip sharp edges1405if(!edge->isSharp()) {1406for(int m=0; m < edge->getSurfaces(); m++) {1407int n = edge->getSurfaceIndex(m);1408propagateIndex(mesh, index, n);1409}1410}1411}1412}1413};14141415// reset bc-indices:1416int count = 0;1417int index = 0;14181419for( int i=0; i<mesh->getSurfaces(); i++ )1420{1421surface_t *surf = mesh->getSurface(i);1422if( (surf->getNature() == PDE_BOUNDARY) && !surf->getSelected() )1423index = max(index, surf->getIndex());1424}1425index++;14261427// int surf_index[index];1428int *surf_index = new int[index];14291430for( int i=0; i<index; i++ )1431surf_index[i] = UNKNOWN;14321433index = 0;1434for(int i=0; i < mesh->getSurfaces(); i++)1435{1436surface_t *surf = mesh->getSurface(i);1437if (surf->getNature() == PDE_BOUNDARY) {1438if ( surf->getSelected() ) {1439count++;1440surf->setIndex(UNKNOWN);1441} else {1442if ( surf_index[surf->getIndex()] == UNKNOWN )1443surf_index[surf->getIndex()] = ++index;1444surf->setIndex(surf_index[surf->getIndex()]);1445}1446}1447}14481449if ( count==0 ) {1450cout << "No boundary surfaces to divide." << endl;1451return 0;1452}145314541455// recursively determine boundary parts:1456Bc *bc = new Bc;14571458for(int i=0; i < mesh->getSurfaces(); i++)1459{1460surface_t *surf = mesh->getSurface(i);1461if(surf->getSelected() && (surf->getIndex() == UNKNOWN) && (surf->getNature() == PDE_BOUNDARY))1462bc->propagateIndex(mesh, ++index, i);1463}1464index++;14651466// Create a hopefully mesh independent indexing of groupings to enable1467// reapplying merge/division operations after remeshing. The indices1468// are given based on group bounding box corner distances from a given1469// point. Fails if two groups have same bbox, which should not happen1470// often though (?)14711472//double xmin[index], ymin[index], zmin[index];1473//double xmax[index], ymax[index], zmax[index];1474//double xc = 0, yc = 0, zc = 0, dist[index];1475//int cc[index], order[index], sorder[index];1476//double g_xmin,g_xmax,g_ymin,g_ymax,g_zmin,g_zmax;14771478double *xmin = new double[index];1479double *ymin = new double[index];1480double *zmin = new double[index];1481double *xmax = new double[index];1482double *ymax = new double[index];1483double *zmax = new double[index];1484double xc = 0, yc = 0, zc = 0;1485double *dist = new double[index];1486int *cc = new int[index];1487int *order = new int[index];1488int *sorder = new int[index];1489double g_xmin,g_xmax,g_ymin,g_ymax,g_zmin,g_zmax;14901491for( int i=0; i<index; i++ )1492{1493cc[i] = 0;1494order[i] = i;1495xmin[i] = ymin[i] = zmin[i] = 1e20;1496xmax[i] = ymax[i] = zmax[i] = -1e20;1497}14981499for( int i=0; i < mesh->getSurfaces(); i++ )1500{1501surface_t *surf = mesh->getSurface(i);1502if ( mesh->getSurface(i)->getNature() == PDE_BOUNDARY ) {1503int k = surf->getIndex();1504for( int j=0; j < surf->getNodes(); j++ ) {1505int n = surf->getNodeIndex(j);1506cc[k]++;1507xmin[k] = min( xmin[k], mesh->getNode(n)->getX(0) );1508ymin[k] = min( ymin[k], mesh->getNode(n)->getX(1) );1509zmin[k] = min( zmin[k], mesh->getNode(n)->getX(2) );15101511xmax[k] = max( xmax[k], mesh->getNode(n)->getX(0) );1512ymax[k] = max( ymax[k], mesh->getNode(n)->getX(1) );1513zmax[k] = max( zmax[k], mesh->getNode(n)->getX(2) );1514}1515}1516}15171518g_xmin = g_ymin = g_zmin = 1e20;1519g_xmax = g_ymax = g_zmax = -1e20;1520for( int i=0; i<index; i++)1521{1522g_xmin = min(xmin[i],g_xmin);1523g_ymin = min(ymin[i],g_ymin);1524g_zmin = min(zmin[i],g_zmin);15251526g_xmax = max(xmax[i],g_xmax);1527g_ymax = max(ymax[i],g_ymax);1528g_zmax = max(zmax[i],g_zmax);1529}15301531double g_scale = max(max(g_xmax-g_xmin,g_ymax-g_ymin),g_zmax-g_zmin);1532double g_xp = g_xmax + 32.1345 * g_scale;1533double g_yp = g_ymin - 5.3*MYPI * g_scale;1534double g_zp = g_zmax + 8.1234 * g_scale;15351536for( int i=0; i<index; i++ )1537{1538dist[i] = 0;1539if ( cc[i]>0 ) {1540for( int j=0; j<8; j++ ) {1541switch(j) {1542case 0: xc=xmin[i]; yc=ymin[i]; zc=zmin[i]; break;1543case 1: xc=xmax[i]; break;1544case 2: yc=xmax[i]; break;1545case 3: xc=xmin[i]; break;1546case 4: zc=zmax[i]; break;1547case 5: yc=ymin[i]; break;1548case 6: xc=xmax[i]; break;1549case 7: yc=ymax[i]; break;1550}1551dist[i] += (xc-g_xp)*(xc-g_xp);1552dist[i] += (yc-g_yp)*(yc-g_yp);1553dist[i] += (zc-g_zp)*(zc-g_zp);1554}1555}1556}15571558sort_index( index, dist, order );1559for( int i=0; i<index; i++ )1560sorder[order[i]] = i;15611562for( int i=0; i < mesh->getSurfaces(); i++ )1563if ( mesh->getSurface(i)->getNature() == PDE_BOUNDARY )1564mesh->getSurface(i)->setIndex(sorder[mesh->getSurface(i)->getIndex()]);1565--index;15661567cout << "Surface divided into " << index << " parts" << endl;15681569delete bc;15701571return index;1572}1573157415751576// Find surface element normals...1577//-----------------------------------------------------------------------------1578void Meshutils::findSurfaceElementNormals(mesh_t *mesh)1579{1580static QREAL_OR_FLOAT a[3], b[3], c[3];1581double center_surface[3], center_element[3], center_difference[3];1582Helpers *helpers = new Helpers;1583int u, v, w, e0, e1, i0, i1, bigger;15841585for(int i=0; i < mesh->getSurfaces(); i++) {1586surface_t *surface = mesh->getSurface(i);15871588u = surface->getNodeIndex(0);1589v = surface->getNodeIndex(1);15901591if((int)(surface->getCode() / 100) == 3) {1592w = surface->getNodeIndex(2);1593} else if((int)(surface->getCode() / 100) == 4) {1594w = surface->getNodeIndex(3);1595} else {1596cout << "findBoundaryElementNormals: error: unknown code" << endl;1597cout.flush();1598exit(0);1599}16001601// Calculate normal (modulo sign):1602a[0] = mesh->getNode(v)->getX(0) - mesh->getNode(u)->getX(0);1603a[1] = mesh->getNode(v)->getX(1) - mesh->getNode(u)->getX(1);1604a[2] = mesh->getNode(v)->getX(2) - mesh->getNode(u)->getX(2);16051606b[0] = mesh->getNode(w)->getX(0) - mesh->getNode(u)->getX(0);1607b[1] = mesh->getNode(w)->getX(1) - mesh->getNode(u)->getX(1);1608b[2] = mesh->getNode(w)->getX(2) - mesh->getNode(u)->getX(2);16091610helpers->crossProduct(a,b,c);1611helpers->normalize(c);16121613surface->setNormal(0, -c[0]);1614surface->setNormal(1, -c[1]);1615surface->setNormal(2, -c[2]);16161617// Determine sign:1618//----------------16191620// a) which parent element has bigger index?16211622e0 = surface->getElementIndex(0);1623e1 = surface->getElementIndex(1);16241625if( (e0<0) && (e1<0) ) {1626// both parents unknown1627bigger = -1;1628} else if(e1<0) {1629// e0 known, e1 unknown1630bigger = e0;1631} else if (e0<0) {1632// e0 unknown, e1 known1633bigger = e1;1634} else {1635// both parents known1636bigger = e0;1637i0 = mesh->getElement(e0)->getIndex();1638i1 = mesh->getElement(e1)->getIndex();1639if(i1 > i0)1640bigger = e1;1641}16421643// b) normal should point to the parent with smaller index:16441645if(bigger > -1) {16461647// Compute center point of the surface element:1648center_surface[0] = 0.0;1649center_surface[1] = 0.0;1650center_surface[2] = 0.0;16511652for(int i=0; i < surface->getNodes(); i++) {1653int j = surface->getNodeIndex(i);1654node_t *n = mesh->getNode(j);1655center_surface[0] += n->getX(0);1656center_surface[1] += n->getX(1);1657center_surface[2] += n->getX(2);1658}16591660center_surface[0] /= (double)(surface->getNodes());1661center_surface[1] /= (double)(surface->getNodes());1662center_surface[2] /= (double)(surface->getNodes());16631664element_t *e = mesh->getElement(bigger);16651666// compute center point of the parent element:1667center_element[0] = 0.0;1668center_element[1] = 0.0;1669center_element[2] = 0.0;16701671for(int i=0; i < e->getNodes(); i++) {1672int j = e->getNodeIndex(i);1673node_t *n = mesh->getNode(j);1674center_element[0] += n->getX(0);1675center_element[1] += n->getX(1);1676center_element[2] += n->getX(2);1677}16781679center_element[0] /= (double)(e->getNodes());1680center_element[1] /= (double)(e->getNodes());1681center_element[2] /= (double)(e->getNodes());16821683// difference of the centers:1684center_difference[0] = center_element[0] - center_surface[0];1685center_difference[1] = center_element[1] - center_surface[1];1686center_difference[2] = center_element[2] - center_surface[2];16871688// dot product must be negative1689double dp = center_difference[0]*c[0]1690+ center_difference[1]*c[1]1691+ center_difference[2]*c[2];16921693if(dp > 0.0) {1694surface->setNormal(0, -surface->getNormal(0));1695surface->setNormal(1, -surface->getNormal(1));1696surface->setNormal(2, -surface->getNormal(2));16971698// change orientation of the surface element:1699if(surface->getCode() == 303) {1700int tmp = surface->getNodeIndex(1);1701surface->setNodeIndex(1, surface->getNodeIndex(2));1702surface->setNodeIndex(2, tmp);17031704} else if(surface->getCode() == 404) {1705int tmp = surface->getNodeIndex(1);1706surface->setNodeIndex(1, surface->getNodeIndex(3));1707surface->setNodeIndex(3, tmp);17081709} else if(surface->getCode() == 306) {1710int tmp = surface->getNodeIndex(1);1711surface->setNodeIndex(1, surface->getNodeIndex(2));1712surface->setNodeIndex(2, tmp);1713tmp = surface->getNodeIndex(3);1714surface->setNodeIndex(3, surface->getNodeIndex(5));1715surface->setNodeIndex(5, tmp);17161717} else if(surface->getCode() == 408) {1718int tmp = surface->getNodeIndex(1);1719surface->setNodeIndex(1, surface->getNodeIndex(3));1720surface->setNodeIndex(3, tmp);1721tmp = surface->getNodeIndex(4);1722surface->setNodeIndex(4, surface->getNodeIndex(7));1723surface->setNodeIndex(7, tmp);1724tmp = surface->getNodeIndex(5);1725surface->setNodeIndex(5, surface->getNodeIndex(6));1726surface->setNodeIndex(6, tmp);17271728} else if(surface->getCode() == 409) {1729int tmp = surface->getNodeIndex(1);1730surface->setNodeIndex(1, surface->getNodeIndex(3));1731surface->setNodeIndex(3, tmp);1732tmp = surface->getNodeIndex(4);1733surface->setNodeIndex(4, surface->getNodeIndex(7));1734surface->setNodeIndex(7, tmp);1735tmp = surface->getNodeIndex(5);1736surface->setNodeIndex(5, surface->getNodeIndex(6));1737surface->setNodeIndex(6, tmp);17381739} else {1740cout << "findSurfaceElementNormals: error: unable to change element orientation" << endl;1741cout.flush();1742exit(0);1743}1744}1745}1746}17471748for( int i=0; i < mesh->getSurfaces(); i++ )1749{1750surface_t *surface = mesh->getSurface(i);1751int n = surface->getCode() / 100;1752for(int j=0; j<n; j++ )1753{1754surface->setVertexNormalVec(j, surface->getNormalVec());1755}1756}175717581759// List surfaces connected to nodes1760//class n_s_t {1761//public:1762//int index;1763//n_s_t *next;1764//} n_s[mesh->getNodes()];17651766class n_s_t {1767public:1768int index;1769n_s_t *next;1770};17711772n_s_t *n_s = new n_s_t[mesh->getNodes()];17731774for( int i=0; i<mesh->getNodes(); i++ )1775{1776n_s[i].index = -1;1777n_s[i].next = NULL;1778}17791780for( int i=0; i < mesh->getSurfaces(); i++ )1781{1782surface_t *surface = mesh->getSurface(i);1783int n = surface->getCode() / 100;17841785for( int j=0; j<n; j++ )1786{1787n_s_t *p = &n_s[surface->getNodeIndex(j)];1788if ( p->index >= 0 ) {1789n_s_t *q = new n_s_t;1790q->next = p->next;1791p->next = q;1792q->index = i;1793} else p->index = i;1794}1795}17961797// average normals over surfaces connected to vertices if1798// normals within the limit_angle:1799double limit_angle = cos(50.*3.14159/180.);18001801for( int i=0; i < mesh->getSurfaces(); i++ )1802{1803surface_t *surf1 = mesh->getSurface(i);1804int n = surf1->getCode() / 100;18051806for( int j=0; j<n; j++ )1807{1808n_s_t *p = &n_s[surf1->getNodeIndex(j)];1809for( ; p && p->index>=0; p=p->next )1810{1811if ( p->index == i ) continue;18121813surface_t *surf2 = mesh->getSurface(p->index);1814double s = 0.;18151816s += surf1->getNormal(0) * surf2->getNormal(0);1817s += surf1->getNormal(1) * surf2->getNormal(1);1818s += surf1->getNormal(2) * surf2->getNormal(2);1819if ( fabs(s) > limit_angle )1820{1821if ( s > 0 ) {1822surf1->addVertexNormalVec(j, surf2->getNormalVec());1823} else {1824surf1->subVertexNormalVec(j, surf2->getNormalVec());1825}1826}1827}1828}1829}18301831// delete lists:1832for( int i=0; i<mesh->getNodes(); i++ )1833{1834n_s_t *p=&n_s[i], *q;1835p = p->next;1836while( p )1837{1838q = p->next;1839delete p;1840p = q;1841}1842}18431844// And finally normalize:1845for( int i=0; i < mesh->getSurfaces(); i++ )1846{1847surface_t *surface = mesh->getSurface(i);1848int n = surface->getCode() / 100;18491850for(int j=0; j<n; j++ )1851{1852double* v = surface->getVertexNormalVec(j);1853double s = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];1854if ( s != 0 ) {1855s = sqrt(s);1856v[0] /= s;1857v[1] /= s;1858v[2] /= s;1859}1860}1861}186218631864delete helpers;1865}1866186718681869// Increase elementorder from 1 to 21870//----------------------------------------------------------------------------1871void Meshutils::increaseElementOrder(mesh_t *mesh)1872{1873class hashEntry {1874public:1875int node1;1876int noedge;1877hashEntry *next;1878};18791880if((mesh->getElements() == 0) && (mesh->getSurfaces() == 0)) return;18811882int keys = mesh->getNodes();1883hashEntry *hash = new hashEntry[keys];1884hashEntry *h;18851886for(int i=0; i<keys; i++) {1887h = &hash[i];1888h->node1 = UNKNOWN;1889h->noedge = UNKNOWN;1890h->next = NULL;1891}18921893static int familylinnodes[9] = {0, 1, 2, 3, 4, 4, 5, 6, 8};1894static int familyedges[9] = {0, 0, 1, 3, 4, 6, 8, 9, 12};18951896static int edgemap8[][2] = {{0,1}, {1,2}, {2,3}, {3,0}, {0,4}, {1,5}, {2,6}, {3,7}, {4,5}, {5,6}, {6,7}, {7,4}};1897static int edgemap7[][2] = {{0,1}, {1,2}, {2,0}, {0,3}, {1,4}, {2,5}, {3,4}, {4,5}, {5,6}};1898static int edgemap6[][2] = {{0,1}, {1,2}, {2,3}, {3,0}, {0,4}, {1,4}, {2,4}, {3,4}};1899static int edgemap5[][2] = {{0,1}, {1,2}, {2,0}, {0,3}, {1,3}, {2,3}};1900static int edgemap4[][2] = {{0,1}, {1,2}, {2,3}, {3,0}};1901static int edgemap3[][2] = {{0,1}, {1,2}, {2,0}};1902static int edgemap2[][2] = {{0,1}};190319041905// First go through elements and find all new edges introduced by the 2nd order1906int noedges = 0;1907for(int i=0; i < mesh->getElements() + mesh->getSurfaces(); i++) {19081909element_t *e;1910if(i < mesh->getElements())1911e = mesh->getElement(i);1912else1913e = mesh->getSurface(i - mesh->getElements());19141915int *edgemap = NULL;1916int family = e->getCode() / 100;1917int edges = familyedges[family];19181919// Skip undetermined and nonlinear element1920if((e->getNodes() < 2) || (e->getNodes() > familylinnodes[family])) continue;19211922for(int f=0; f<edges; f++) {1923if(family == 3)1924edgemap = &edgemap3[f][0];1925else if(family == 4)1926edgemap = &edgemap4[f][0];1927if(family == 5)1928edgemap = &edgemap5[f][0];1929else if(family == 6)1930edgemap = &edgemap6[f][0];1931else if(family == 7)1932edgemap = &edgemap7[f][0];1933else if(family == 8)1934edgemap = &edgemap8[f][0];19351936int n0 = e->getNodeIndex(edgemap[0]);1937int n1 = e->getNodeIndex(edgemap[1]);19381939if(n0 < 0 || n1 < 0) continue;19401941// Order indexes in an increasing order1942if(n0 > n1) {1943int tmp = n0;1944n0 = n1;1945n1 = tmp;1946}19471948h = &hash[n0];1949bool found = false;1950while(h->next) {1951if(h->node1 == n1) {1952found = true;1953break;1954}1955h = h->next;1956}19571958if(!found) {1959h->node1 = n1;1960h->noedge = noedges;19611962h->next = new hashEntry;1963h = h->next;1964h->node1 = UNKNOWN;1965h->noedge = UNKNOWN;1966h->next = NULL;1967noedges++;1968}1969}1970}19711972cout << "Found " << noedges << " edges in the mesh " << endl;19731974if(noedges == 0) {1975return;1976delete [] hash;1977}19781979// Then redefine the mesh using the additional nodes1980int quadnodes = mesh->getNodes() + noedges;1981node_t *quadnode = new node_t[quadnodes];19821983// Copy linear nodes1984for(int i = 0; i < mesh->getNodes(); i++) {1985quadnode[i].setX(0, mesh->getNode(i)->getX(0));1986quadnode[i].setX(1, mesh->getNode(i)->getX(1));1987quadnode[i].setX(2, mesh->getNode(i)->getX(2));1988quadnode[i].setIndex(mesh->getNode(i)->getIndex());1989}19901991// Quadratic nodes are taken to be means of the linear nodes1992for(int i=0; i<keys; i++) {1993int j = 0;1994h = &hash[i];1995while(h->next){1996if(h->noedge > UNKNOWN) {1997j++;1998int n0 = i;1999int n1 = h->node1;2000int j = mesh->getNodes() + h->noedge;2001quadnode[j].setX(0, 0.5*(quadnode[n0].getX(0) + quadnode[n1].getX(0)));2002quadnode[j].setX(1, 0.5*(quadnode[n0].getX(1) + quadnode[n1].getX(1)));2003quadnode[j].setX(2, 0.5*(quadnode[n0].getX(2) + quadnode[n1].getX(2)));2004quadnode[j].setIndex(UNKNOWN);2005}2006h = h->next;2007}2008}2009mesh->deleteNodeArray();2010mesh->setNodeArray(quadnode);20112012cout << "Set " << quadnodes << " additional nodes" << endl;201320142015int tmpnode[27];20162017for(int i=0; i < mesh->getElements() + mesh->getSurfaces() + mesh->getEdges(); i++) {20182019element_t *e;2020if(i < mesh->getElements())2021e = mesh->getElement(i);2022else if (i < mesh->getElements() + mesh->getSurfaces())2023e = mesh->getSurface(i - mesh->getElements());2024else2025e = mesh->getEdge(i - mesh->getElements() - mesh->getSurfaces());20262027int *edgemap = NULL;2028int family = e->getCode() / 100;2029int edges = familyedges[family];20302031/* Not a linear element */2032if((e->getNodes() < 2) || (e->getNodes() > familylinnodes[family])) continue;20332034int linnodes = e->getNodes();2035for(int j=0;j<linnodes;j++)2036tmpnode[j] = e->getNodeIndex(j);20372038e->deleteNodeIndexes();2039e->setCode(e->getCode() + edges);2040e->setNodes(e->getNodes() + edges);2041e->newNodeIndexes(e->getNodes());2042for(int j=0;j<linnodes;j++)2043e->setNodeIndex(j, tmpnode[j]);204420452046for(int f=0; f<edges; f++) {20472048if(family == 2)2049edgemap = &edgemap2[f][0];2050if(family == 3)2051edgemap = &edgemap3[f][0];2052else if(family == 4)2053edgemap = &edgemap4[f][0];2054if(family == 5)2055edgemap = &edgemap5[f][0];2056else if(family == 6)2057edgemap = &edgemap6[f][0];2058else if(family == 7)2059edgemap = &edgemap7[f][0];2060else if(family == 8)2061edgemap = &edgemap8[f][0];20622063int n0 = e->getNodeIndex(edgemap[0]);2064int n1 = e->getNodeIndex(edgemap[1]);2065if((n0 < 0) || (n1 < 0)) continue;20662067// Order indexes in an increasing order2068if(n0 > n1) {2069int tmp = n0;2070n0 = n1;2071n1 = tmp;2072}20732074h = &hash[n0];2075bool found = false;2076while(h->next) {2077if(h->node1 == n1) {2078found = true;2079e->setNodeIndex(linnodes+f, h->noedge + mesh->getNodes());2080break;2081}2082h = h->next;2083}2084if(!found) {2085cout << "All edges should be found!? " << endl;2086}2087}2088}2089mesh->setNodes(quadnodes);20902091delete [] hash;2092}2093209420952096// Decrease elementorder from >1 to 12097//----------------------------------------------------------------------------2098void Meshutils::decreaseElementOrder(mesh_t *mesh)2099{2100if((mesh->getElements() == 0) && (mesh->getSurfaces() == 0)) return;21012102static int familylinnodes[9] = {0, 1, 2, 3, 4, 4, 5, 6, 8};21032104int *activenodes = new int[mesh->getNodes()];2105for(int i=0; i < mesh->getNodes(); i++)2106activenodes[i] = -1;21072108// int noedges = 0;2109for(int i=0; i < mesh->getElements() + mesh->getSurfaces(); i++) {21102111element_t *e;2112if(i < mesh->getElements())2113e = mesh->getElement(i);2114else2115e = mesh->getSurface(i - mesh->getElements());21162117int family = e->getCode() / 100;2118int linnodes = familylinnodes[family];21192120for(int j=0;j<linnodes;j++)2121activenodes[e->getNodeIndex(j)] = 0;2122}21232124int linnodes = 0;2125for(int i=0; i < mesh->getNodes(); i++)2126if(activenodes[i] > -1) activenodes[i] = linnodes++;21272128cout << "Setting " << linnodes << " linear nodes of the total " << mesh->getNodes() << " nodes" << endl;2129if(linnodes == mesh->getNodes()) return;213021312132// Copy linear nodes2133node_t *linnode = new node_t[linnodes];2134for(int i=0; i < mesh->getNodes(); i++) {2135int j = activenodes[i];2136if(j > -1) {2137linnode[j].setX(0, mesh->getNode(i)->getX(0));2138linnode[j].setX(1, mesh->getNode(i)->getX(1));2139linnode[j].setX(2, mesh->getNode(i)->getX(2));2140}2141}2142mesh->deleteNodeArray();2143mesh->setNodeArray(linnode);2144mesh->setNodes(linnodes);21452146int tmpnode[8];21472148for(int i=0; i < mesh->getElements() + mesh->getSurfaces() + mesh->getEdges(); i++) {21492150element_t *e;2151if(i < mesh->getElements())2152e = mesh->getElement(i);2153else if (i < mesh->getElements() + mesh->getSurfaces())2154e = mesh->getSurface(i - mesh->getElements());2155else2156e = mesh->getEdge(i - mesh->getElements() - mesh->getSurfaces());21572158int family = e->getCode() / 100;2159int linnodes = familylinnodes[family];21602161for(int j=0;j<linnodes;j++)2162tmpnode[j] = e->getNodeIndex(j);21632164e->deleteNodeIndexes();2165e->setCode(100*family + linnodes);2166e->setNodes(linnodes);2167e->newNodeIndexes(e->getNodes());21682169for(int j=0;j<linnodes;j++)2170e->setNodeIndex(j, activenodes[tmpnode[j]]);2171}2172}21732174// Clean up hanging sharp edges (for visualization)...2175//----------------------------------------------------------------------------2176int Meshutils::cleanHangingSharpEdges(mesh_t *mesh)2177{2178int count_total = 0;2179int count_removed = 0;21802181if(mesh->getEdges() == 0)2182return 0;21832184for(int i = 0; i < mesh->getEdges(); i++) {2185edge_t *edge = mesh->getEdge(i);2186if(edge->isSharp()) {2187count_total++;2188if(edge->getSurfaces() == 2) {2189// has two parents2190int i0 = edge->getSurfaceIndex(0);2191int i1 = edge->getSurfaceIndex(1);2192surface_t *s0 = NULL;2193surface_t *s1 = NULL;2194if(i0 >= 0)2195s0 = mesh->getSurface(i0);2196if(i1 >= 0)2197s1 = mesh->getSurface(i1);2198if((s0 != NULL) && (s1 != NULL)) {2199int index0 = s0->getIndex();2200int index1 = s1->getIndex();2201if(index0 == index1) {2202// remove2203count_removed++;2204edge->setSharp(false);2205}2206}2207}2208}2209}22102211return count_removed;2212}221322142215