Path: blob/devel/ElmerGUI/netgen/libsrc/meshing/meshclass.cpp
3206 views
#include <mystdlib.h>1#include "meshing.hpp"23#ifdef PARALLEL4#include <parallel.hpp>5#endif67namespace netgen8{910Mesh :: Mesh ()11{12volelements.SetName ("vol elements");13surfelements.SetName ("surf elements");14points.SetName ("meshpoints");1516boundaryedges = NULL;17surfelementht = NULL;18segmentht = NULL;1920lochfunc = NULL;21mglevels = 1;22elementsearchtree = NULL;23elementsearchtreets = NextTimeStamp();24majortimestamp = timestamp = NextTimeStamp();25hglob = 1e10;26hmin = 0;27numvertices = -1;28dimension = 3;2930topology = new MeshTopology (*this);31curvedelems = new CurvedElements (*this);32clusters = new AnisotropicClusters (*this);33ident = new Identifications (*this);3435hpelements = NULL;36coarsemesh = NULL;3738ps_startelement = 0;3940geomtype = NO_GEOM;4142bcnames.SetSize(0);43#ifdef PARALLEL44paralleltop = new ParallelMeshTopology (*this);45#endif46}474849Mesh :: ~Mesh()50{51delete lochfunc;52delete boundaryedges;53delete surfelementht;54delete segmentht;55delete curvedelems;56delete clusters;57delete topology;58delete ident;59delete elementsearchtree;6061delete coarsemesh;62delete hpelements;6364for (int i = 0; i < materials.Size(); i++)65delete [] materials[i];6667for(int i = 0; i < userdata_int.Size(); i++)68delete userdata_int[i];69for(int i = 0; i < userdata_double.Size(); i++)70delete userdata_double[i];7172for (int i = 0; i < bcnames.Size(); i++ )73if ( bcnames[i] ) delete bcnames[i];7475#ifdef PARALLEL76delete paralleltop;77#endif78}798081Mesh & Mesh :: operator= (const Mesh & mesh2)82{83points = mesh2.points;84// eltyps = mesh2.eltyps;85segments = mesh2.segments;86surfelements = mesh2.surfelements;87volelements = mesh2.volelements;88lockedpoints = mesh2.lockedpoints;89facedecoding = mesh2.facedecoding;90dimension = mesh2.dimension;9192bcnames.SetSize( mesh2.bcnames.Size() );93for ( int i = 0; i < mesh2.bcnames.Size(); i++ )94if ( mesh2.bcnames[i] ) bcnames[i] = new string ( *mesh2.bcnames[i] );95else bcnames[i] = 0;9697return *this;98}99100101void Mesh :: DeleteMesh()102{103points.SetSize(0);104segments.SetSize(0);105surfelements.SetSize(0);106volelements.SetSize(0);107lockedpoints.SetSize(0);108surfacesonnode.SetSize(0);109110delete boundaryedges;111boundaryedges = NULL;112113openelements.SetSize(0);114facedecoding.SetSize(0);115116delete ident;117ident = new Identifications (*this);118delete topology;119topology = new MeshTopology (*this);120delete curvedelems;121curvedelems = new CurvedElements (*this);122delete clusters;123clusters = new AnisotropicClusters (*this);124125for ( int i = 0; i < bcnames.Size(); i++ )126if ( bcnames[i] ) delete bcnames[i];127128#ifdef PARALLEL129delete paralleltop;130paralleltop = new ParallelMeshTopology (*this);131#endif132133134timestamp = NextTimeStamp();135}136137138139PointIndex Mesh :: AddPoint (const Point3d & p, int layer)140{141NgLock lock(mutex);142lock.Lock();143144timestamp = NextTimeStamp();145146PointIndex pi = points.Size() + PointIndex::BASE;147points.Append ( MeshPoint (p, layer, INNERPOINT) );148149#ifdef PARALLEL150points.Last().SetGhost(0);151#endif152153lock.UnLock();154155return pi;156}157158PointIndex Mesh :: AddPoint (const Point3d & p, int layer, POINTTYPE type)159{160NgLock lock(mutex);161lock.Lock();162163timestamp = NextTimeStamp();164165PointIndex pi = points.Size() + PointIndex::BASE;166points.Append ( MeshPoint (p, layer, type) );167168#ifdef PARALLEL169points.Last().SetGhost(0);170#endif171172lock.UnLock();173174return pi;175}176177178#ifdef PARALLEL179PointIndex Mesh :: AddPoint (const Point3d & p, bool isghost, int layer)180{181NgLock lock(mutex);182lock.Lock();183184timestamp = NextTimeStamp();185186PointIndex pi = points.Size() + PointIndex::BASE;187points.Append ( MeshPoint (p, layer, INNERPOINT) );188189points.Last().SetGhost(isghost);190191lock.UnLock();192193return pi;194}195196PointIndex Mesh :: AddPoint (const Point3d & p, bool isghost, int layer, POINTTYPE type)197{198NgLock lock(mutex);199lock.Lock();200201timestamp = NextTimeStamp();202203PointIndex pi = points.Size() + PointIndex::BASE;204points.Append ( MeshPoint (p, layer, type) );205206points.Last().SetGhost(isghost);207208lock.UnLock();209210return pi;211}212213#endif214215216217SegmentIndex Mesh :: AddSegment (const Segment & s)218{219NgLock lock(mutex);220lock.Lock();221timestamp = NextTimeStamp();222223int maxn = max2 (s.p1, s.p2);224maxn += 1-PointIndex::BASE;225226/*227if (maxn > ptyps.Size())228{229int maxo = ptyps.Size();230ptyps.SetSize (maxn);231for (int i = maxo; i < maxn; i++)232ptyps[i] = INNERPOINT;233}234235if (ptyps[s.p1] > EDGEPOINT) ptyps[s.p1] = EDGEPOINT;236if (ptyps[s.p2] > EDGEPOINT) ptyps[s.p2] = EDGEPOINT;237*/238239if (maxn <= points.Size())240{241if (points[s.p1].Type() > EDGEPOINT)242points[s.p1].SetType (EDGEPOINT);243if (points[s.p2].Type() > EDGEPOINT)244points[s.p2].SetType (EDGEPOINT);245}246/*247else248{249cerr << "edge points nrs > points.Size" << endl;250}251*/252253SegmentIndex si = segments.Size();254segments.Append (s);255256lock.UnLock();257return si;258}259260SurfaceElementIndex Mesh :: AddSurfaceElement (const Element2d & el)261{262NgLock lock(mutex);263lock.Lock();264timestamp = NextTimeStamp();265266int maxn = el[0];267for (int i = 1; i < el.GetNP(); i++)268if (el[i] > maxn) maxn = el[i];269270maxn += 1-PointIndex::BASE;271272/*273if (maxn > ptyps.Size())274{275int maxo = ptyps.Size();276ptyps.SetSize (maxn);277for (i = maxo+PointIndex::BASE;278i < maxn+PointIndex::BASE; i++)279ptyps[i] = INNERPOINT;280281}282*/283if (maxn <= points.Size())284{285for (int i = 0; i < el.GetNP(); i++)286if (points[el[i]].Type() > SURFACEPOINT)287points[el[i]].SetType(SURFACEPOINT);288}289/*290else291{292cerr << "surf points nrs > points.Size" << endl;293}294*/295296SurfaceElementIndex si = surfelements.Size();297surfelements.Append (el);298299if (el.index > facedecoding.Size())300cerr << "has no facedecoding: fd.size = " << facedecoding.Size() << ", ind = " << el.index << endl;301302surfelements.Last().next = facedecoding[el.index-1].firstelement;303facedecoding[el.index-1].firstelement = si;304305#ifdef PARALLEL306surfelements.Last().SetGhost ( el.IsGhost() );307#endif308309lock.UnLock();310return si;311}312313314ElementIndex Mesh :: AddVolumeElement (const Element & el)315{316NgLock lock(mutex);317lock.Lock();318319int maxn = el[0];320for (int i = 1; i < el.GetNP(); i++)321if (el[i] > maxn) maxn = el[i];322323maxn += 1-PointIndex::BASE;324325/*326if (maxn > ptyps.Size())327{328int maxo = ptyps.Size();329ptyps.SetSize (maxn);330for (i = maxo+PointIndex::BASE;331i < maxn+PointIndex::BASE; i++)332ptyps[i] = INNERPOINT;333}334*/335/*336if (maxn > points.Size())337{338cerr << "add vol element before point" << endl;339}340*/341342int ve = volelements.Size();343344volelements.Append (el);345volelements.Last().flags.illegal_valid = 0;346347#ifdef PARALLEL348volelements.Last().SetGhost ( el.IsGhost() );349#endif350351// while (volelements.Size() > eltyps.Size())352// eltyps.Append (FREEELEMENT);353354timestamp = NextTimeStamp();355356lock.UnLock();357return ve;358}359360361362363364365void Mesh :: Save (const string & filename) const366{367368ofstream outfile(filename.c_str());369370Save(outfile);371}372373374375void Mesh :: Save (ostream & outfile) const376{377int i, j;378379double scale = 1; // globflags.GetNumFlag ("scale", 1);380int inverttets = 0; // globflags.GetDefineFlag ("inverttets");381int invertsurf = 0; // globflags.GetDefineFlag ("invertsurfacemesh");382383384385outfile << "mesh3d" << "\n";386387outfile << "dimension\n" << GetDimension() << "\n";388389outfile << "geomtype\n" << int(geomtype) << "\n";390391392outfile << "\n";393outfile << "# surfnr bcnr domin domout np p1 p2 p3"394<< "\n";395396397switch (geomtype)398{399case GEOM_STL:400outfile << "surfaceelementsgi" << "\n";401break;402case GEOM_OCC: case GEOM_ACIS:403outfile << "surfaceelementsuv" << "\n";404break;405default:406outfile << "surfaceelements" << "\n";407}408409outfile << GetNSE() << "\n";410411SurfaceElementIndex sei;412for (sei = 0; sei < GetNSE(); sei++)413{414if ((*this)[sei].GetIndex())415{416outfile.width(8);417outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).SurfNr()+1;418outfile.width(8);419outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();420outfile.width(8);421outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainIn();422outfile.width(8);423outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainOut();424}425else426outfile << " 0 0 0";427428Element2d sel = (*this)[sei];429if (invertsurf)430sel.Invert();431432outfile.width(8);433outfile << sel.GetNP();434435for (j = 0; j < sel.GetNP(); j++)436{437outfile.width(8);438outfile << sel[j];439}440441442switch (geomtype)443{444case GEOM_STL:445for (j = 1; j <= sel.GetNP(); j++)446{447outfile.width(7);448outfile << " " << sel.GeomInfoPi(j).trignum;449}450break;451case GEOM_OCC: case GEOM_ACIS:452for (j = 1; j <= sel.GetNP(); j++)453{454outfile.width(7);455outfile << " " << sel.GeomInfoPi(j).u;456outfile << " " << sel.GeomInfoPi(j).v;457}458break;459default:460outfile << "\n";461}462463464outfile << endl;465}466467outfile << "\n" << "\n";468outfile << "# matnr np p1 p2 p3 p4" << "\n";469outfile << "volumeelements" << "\n";470outfile << GetNE() << "\n";471472for (ElementIndex ei = 0; ei < GetNE(); ei++)473{474outfile.width(8);475outfile << (*this)[ei].GetIndex();476outfile.width(8);477outfile << (*this)[ei].GetNP();478479Element el = (*this)[ei];480if (inverttets)481el.Invert();482483/*484for (j = 0; j < el.GetNP(); j++)485for (int k = 0; k < el.GetNP()-1; k++)486if (el[k] > el[k+1]) swap (el[k], el[k+1]);487*/488489for (j = 0; j < el.GetNP(); j++)490{491outfile.width(8);492outfile << el[j];493}494outfile << "\n";495}496497498outfile << "\n" << "\n";499// outfile << " surf1 surf2 p1 p2" << "\n";500outfile << "# surfid 0 p1 p2 trignum1 trignum2 domin/surfnr1 domout/surfnr2 ednr1 dist1 ednr2 dist2 \n";501outfile << "edgesegmentsgi2" << "\n";502outfile << GetNSeg() << "\n";503504for (i = 1; i <= GetNSeg(); i++)505{506const Segment & seg = LineSegment (i);507outfile.width(8);508outfile << seg.si; // 2D: bc number, 3D: wievielte Kante509outfile.width(8);510outfile << 0;511outfile.width(8);512outfile << seg.p1;513outfile.width(8);514outfile << seg.p2;515outfile << " ";516outfile.width(8);517outfile << seg.geominfo[0].trignum; // stl dreiecke518outfile << " ";519outfile.width(8);520outfile << seg.geominfo[1].trignum; // << endl; // stl dreieck521522if (dimension == 3)523{524outfile << " ";525outfile.width(8);526outfile << seg.surfnr1+1;527outfile << " ";528outfile.width(8);529outfile << seg.surfnr2+1;530}531else532{533outfile << " ";534outfile.width(8);535outfile << seg.domin;536outfile << " ";537outfile.width(8);538outfile << seg.domout;539}540541outfile << " ";542outfile.width(8);543outfile << seg.edgenr;544outfile << " ";545outfile.width(12);546outfile.precision(16);547outfile << seg.epgeominfo[0].dist; // splineparameter (2D)548outfile << " ";549outfile.width(8);550outfile.precision(16);551outfile << seg.epgeominfo[1].edgenr; // geometry dependent552outfile << " ";553outfile.width(12);554outfile << seg.epgeominfo[1].dist;555556outfile << "\n";557}558559560outfile << "\n" << "\n";561outfile << "# X Y Z" << "\n";562outfile << "points" << "\n";563outfile << GetNP() << "\n";564outfile.precision(16);565outfile.setf (ios::fixed, ios::floatfield);566outfile.setf (ios::showpoint);567568PointIndex pi;569for (pi = PointIndex::BASE;570pi < GetNP()+PointIndex::BASE; pi++)571{572outfile.width(22);573outfile << (*this)[pi](0)/scale << " ";574outfile.width(22);575outfile << (*this)[pi](1)/scale << " ";576outfile.width(22);577outfile << (*this)[pi](2)/scale << "\n";578}579580if (ident -> GetMaxNr() > 0)581{582outfile << "identifications\n";583ARRAY<INDEX_2> identpairs;584int cnt = 0;585for (i = 1; i <= ident -> GetMaxNr(); i++)586{587ident -> GetPairs (i, identpairs);588cnt += identpairs.Size();589}590outfile << cnt << "\n";591for (i = 1; i <= ident -> GetMaxNr(); i++)592{593ident -> GetPairs (i, identpairs);594for (j = 1; j <= identpairs.Size(); j++)595{596outfile.width (8);597outfile << identpairs.Get(j).I1();598outfile.width (8);599outfile << identpairs.Get(j).I2();600outfile.width (8);601outfile << i << "\n";602}603}604605outfile << "identificationtypes\n";606outfile << ident -> GetMaxNr() << "\n";607for (i = 1; i <= ident -> GetMaxNr(); i++)608{609int type = ident -> GetType(i);610outfile << " " << type;611}612outfile << "\n";613}614615int cntmat = 0;616for (i = 1; i <= materials.Size(); i++)617if (materials.Get(i) && strlen (materials.Get(i)))618cntmat++;619620if (cntmat)621{622outfile << "materials" << endl;623outfile << cntmat << endl;624for (i = 1; i <= materials.Size(); i++)625if (materials.Get(i) && strlen (materials.Get(i)))626outfile << i << " " << materials.Get(i) << endl;627}628629630int cntbcnames = 0;631for ( int ii = 0; ii < bcnames.Size(); ii++ )632if ( bcnames[ii] ) cntbcnames++;633634if ( cntbcnames )635{636outfile << "\n\nbcnames" << endl << bcnames.Size() << endl;637for ( i = 0; i < bcnames.Size(); i++ )638outfile << i+1 << "\t" << GetBCName(i) << endl;639outfile << endl << endl;640}641642/*643if ( GetDimension() == 2 )644{645for (i = 1; i <= GetNSeg(); i++)646{647const Segment & seg = LineSegment (i);648if ( ! bcprops.Contains(seg.si) && seg.GetBCName() != "" )649{650bcprops.Append(seg.si);651cntbcnames++;652}653}654}655else656{657for (sei = 0; sei < GetNSE(); sei++)658{659if ((*this)[sei].GetIndex())660{661int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();662string name = GetFaceDescriptor((*this)[sei].GetIndex ()).BCName();663if ( !bcprops.Contains(bcp) &&664name != "" )665{666bcprops.Append(bcp);667cntbcnames++;668}669}670}671}672673bcprops.SetSize(0);674if ( cntbcnames )675{676outfile << "\nbcnames" << endl << cntbcnames << endl;677if ( GetDimension() == 2 )678{679for (i = 1; i <= GetNSeg(); i++)680{681const Segment & seg = LineSegment (i);682if ( ! bcprops.Contains(seg.si) && seg.GetBCName() != "" )683{684bcprops.Append(seg.si);685outfile << seg.si << "\t" << seg.GetBCName() << endl;686}687}688}689else690{691for (sei = 0; sei < GetNSE(); sei++)692{693if ((*this)[sei].GetIndex())694{695int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();696string name = GetFaceDescriptor((*this)[sei].GetIndex ()).BCName();697if ( !bcprops.Contains(bcp) &&698name != "" )699{700bcprops.Append(bcp);701outfile << bcp << "\t" << name << endl;702}703}704}705}706outfile << endl << endl;707}708*/709710int cnt_sing = 0;711for (PointIndex pi = PointIndex::BASE; pi < GetNP()+PointIndex::BASE; pi++)712if ((*this)[pi].Singularity()>=1.) cnt_sing++;713714if (cnt_sing)715{716outfile << "singular_points" << endl << cnt_sing << endl;717for (PointIndex pi = PointIndex::BASE; pi < GetNP()+PointIndex::BASE; pi++)718if ((*this)[pi].Singularity()>=1.)719outfile << int(pi) << "\t" << (*this)[pi].Singularity() << endl;720}721722cnt_sing = 0;723for (SegmentIndex si = 0; si < GetNSeg(); si++)724if ( segments[si].singedge_left ) cnt_sing++;725if (cnt_sing)726{727outfile << "singular_edge_left" << endl << cnt_sing << endl;728for (SegmentIndex si = 0; si < GetNSeg(); si++)729if ( segments[si].singedge_left )730outfile << int(si) << "\t" << segments[si].singedge_left << endl;731}732733cnt_sing = 0;734for (SegmentIndex si = 0; si < GetNSeg(); si++)735if ( segments[si].singedge_right ) cnt_sing++;736if (cnt_sing)737{738outfile << "singular_edge_right" << endl << cnt_sing << endl;739for (SegmentIndex si = 0; si < GetNSeg(); si++)740if ( segments[si].singedge_right )741outfile << int(si) << "\t" << segments[si].singedge_right << endl;742}743744745cnt_sing = 0;746for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)747if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular)748cnt_sing++;749750if (cnt_sing)751{752outfile << "singular_face_inside" << endl << cnt_sing << endl;753for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)754if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular)755outfile << int(sei) << "\t" <<756GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular << endl;757}758759cnt_sing = 0;760for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)761if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular) cnt_sing++;762if (cnt_sing)763{764outfile << "singular_face_outside" << endl << cnt_sing << endl;765for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)766if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular)767outfile << int(sei) << "\t"768<< GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular << endl;769}770771772}773774775776void Mesh :: Load (const string & filename)777{778779ifstream infile(filename.c_str());780if (!infile.good())781throw NgException ("mesh file not found");782783Load(infile);784}785786787788789void Mesh :: Load (istream & infile)790{791792char str[100];793int i, n;794795double scale = 1; // globflags.GetNumFlag ("scale", 1);796int inverttets = 0; // globflags.GetDefineFlag ("inverttets");797int invertsurf = 0; // globflags.GetDefineFlag ("invertsurfacemesh");798799800facedecoding.SetSize(0);801802bool endmesh = false;803804while (infile.good() && !endmesh)805{806infile >> str;807808if (strcmp (str, "dimension") == 0)809{810infile >> dimension;811}812813if (strcmp (str, "geomtype") == 0)814{815int hi;816infile >> hi;817geomtype = GEOM_TYPE(hi);818}819820821if (strcmp (str, "surfaceelements") == 0 || strcmp (str, "surfaceelementsgi")==0 || strcmp (str, "surfaceelementsuv") == 0)822{823infile >> n;824PrintMessage (3, n, " surface elements");825for (i = 1; i <= n; i++)826{827int j;828int surfnr, bcp, domin, domout, nep, faceind = 0;829830infile >> surfnr >> bcp >> domin >> domout;831surfnr--;832833for (j = 1; j <= facedecoding.Size(); j++)834if (GetFaceDescriptor(j).SurfNr() == surfnr &&835GetFaceDescriptor(j).BCProperty() == bcp &&836GetFaceDescriptor(j).DomainIn() == domin &&837GetFaceDescriptor(j).DomainOut() == domout)838faceind = j;839840if (!faceind)841{842faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0));843GetFaceDescriptor(faceind).SetBCProperty (bcp);844}845846infile >> nep;847if (!nep) nep = 3;848849Element2d tri(nep);850tri.SetIndex(faceind);851852for (j = 1; j <= nep; j++)853infile >> tri.PNum(j);854855if (strcmp (str, "surfaceelementsgi") == 0)856for (j = 1; j <= nep; j++)857infile >> tri.GeomInfoPi(j).trignum;858859if (strcmp (str, "surfaceelementsuv") == 0)860for (j = 1; j <= nep; j++)861infile >> tri.GeomInfoPi(j).u >> tri.GeomInfoPi(j).v;862863if (invertsurf)864tri.Invert();865866AddSurfaceElement (tri);867}868}869870871if (strcmp (str, "volumeelements") == 0)872{873infile >> n;874PrintMessage (3, n, " volume elements");875for (i = 1; i <= n; i++)876{877Element el;878int hi, nep;879infile >> hi;880if (hi == 0) hi = 1;881el.SetIndex(hi);882infile >> nep;883el.SetNP(nep);884885for (int j = 0; j < nep; j++)886infile >> (int&)(el[j]);887888if (inverttets)889el.Invert();890891AddVolumeElement (el);892}893}894895896if (strcmp (str, "edgesegments") == 0)897{898infile >> n;899for (i = 1; i <= n; i++)900{901Segment seg;902int hi;903infile >> seg.si >> hi >> seg.p1 >> seg.p2;904AddSegment (seg);905}906}907908909910if (strcmp (str, "edgesegmentsgi") == 0)911{912infile >> n;913for (i = 1; i <= n; i++)914{915Segment seg;916int hi;917infile >> seg.si >> hi >> seg.p1 >> seg.p2918>> seg.geominfo[0].trignum919>> seg.geominfo[1].trignum;920AddSegment (seg);921}922}923924if (strcmp (str, "edgesegmentsgi2") == 0)925{926int a;927infile >> a;928n=a;929930PrintMessage (3, n, " curve elements");931932for (i = 1; i <= n; i++)933{934Segment seg;935int hi;936infile >> seg.si >> hi >> seg.p1 >> seg.p2937>> seg.geominfo[0].trignum938>> seg.geominfo[1].trignum939>> seg.surfnr1 >> seg.surfnr2940>> seg.edgenr941>> seg.epgeominfo[0].dist942>> seg.epgeominfo[1].edgenr943>> seg.epgeominfo[1].dist;944945seg.epgeominfo[0].edgenr = seg.epgeominfo[1].edgenr;946947seg.domin = seg.surfnr1;948seg.domout = seg.surfnr2;949950seg.surfnr1--;951seg.surfnr2--;952953AddSegment (seg);954}955}956957if (strcmp (str, "points") == 0)958{959infile >> n;960PrintMessage (3, n, " points");961for (i = 1; i <= n; i++)962{963Point3d p;964infile >> p.X() >> p.Y() >> p.Z();965p.X() *= scale;966p.Y() *= scale;967p.Z() *= scale;968AddPoint (p);969}970}971972if (strcmp (str, "identifications") == 0)973{974infile >> n;975for (i = 1; i <= n; i++)976{977PointIndex pi1, pi2;978int ind;979infile >> pi1 >> pi2 >> ind;980ident -> Add (pi1, pi2, ind);981}982}983984if (strcmp (str, "identificationtypes") == 0)985{986infile >> n;987for (i = 1; i <= n; i++)988{989int type;990infile >> type;991ident -> SetType(i,Identifications::ID_TYPE(type));992}993}994995if (strcmp (str, "materials") == 0)996{997infile >> n;998for (i = 1; i <= n; i++)999{1000int nr;1001string mat;1002infile >> nr >> mat;1003SetMaterial (nr, mat.c_str());1004}1005}10061007if ( strcmp (str, "bcnames" ) == 0 )1008{1009infile >> n;1010ARRAY<int,0> bcnrs(n);10111012SetNBCNames(n);1013for ( i = 1; i <= n; i++ )1014{1015string nextbcname;1016infile >> bcnrs[i-1] >> nextbcname;1017bcnames[bcnrs[i-1]-1] = new string(nextbcname);1018}10191020if ( GetDimension() == 2 )1021{1022for (i = 1; i <= GetNSeg(); i++)1023{1024Segment & seg = LineSegment (i);1025if ( seg.si <= n )1026seg.SetBCName (bcnames[seg.si-1]);1027else1028seg.SetBCName(0);1029}1030}1031else1032{1033for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)1034{1035if ((*this)[sei].GetIndex())1036{1037int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();1038if ( bcp <= n )1039GetFaceDescriptor((*this)[sei].GetIndex ()).SetBCName(bcnames[bcp-1]);1040else1041GetFaceDescriptor((*this)[sei].GetIndex ()).SetBCName(0);10421043}1044}10451046}104710481049}10501051if (strcmp (str, "singular_points") == 0)1052{1053infile >> n;1054for (i = 1; i <= n; i++)1055{1056PointIndex pi;1057double s;1058infile >> pi;1059infile >> s;1060(*this)[pi].Singularity (s);1061}1062}10631064if (strcmp (str, "singular_edge_left") == 0)1065{1066infile >> n;1067for (i = 1; i <= n; i++)1068{1069SegmentIndex si;1070double s;1071infile >> si;1072infile >> s;1073(*this)[si].singedge_left = s;1074}1075}1076if (strcmp (str, "singular_edge_right") == 0)1077{1078infile >> n;1079for (i = 1; i <= n; i++)1080{1081SegmentIndex si;1082double s;1083infile >> si;1084infile >> s;1085(*this)[si].singedge_right = s;1086}1087}10881089if (strcmp (str, "singular_face_inside") == 0)1090{1091infile >> n;1092for (i = 1; i <= n; i++)1093{1094SurfaceElementIndex sei;1095double s;1096infile >> sei;1097infile >> s;1098GetFaceDescriptor((*this)[sei].GetIndex()).domin_singular = s;1099}1100}11011102if (strcmp (str, "singular_face_outside") == 0)1103{1104infile >> n;1105for (i = 1; i <= n; i++)1106{1107SurfaceElementIndex sei;1108double s;1109infile >> sei;1110infile >> s;1111GetFaceDescriptor((*this)[sei].GetIndex()).domout_singular = s;1112}1113}11141115if (strcmp (str, "endmesh") == 0)1116endmesh = true;1117111811191120strcpy (str, "");1121}11221123CalcSurfacesOfNode ();1124// BuildConnectedNodes ();1125topology -> Update();1126clusters -> Update();11271128SetNextMajorTimeStamp();1129// PrintMemInfo (cout);113011311132#ifdef PARALLEL1133if ( ntasks > 1 )1134{1135// for parallel processing1136Distribute ();1137return;1138}1139#endif11401141}114211431144114511461147void Mesh :: Merge (const string & filename, const int surfindex_offset)1148{1149ifstream infile(filename.c_str());1150if (!infile.good())1151throw NgException ("mesh file not found");11521153Merge(infile,surfindex_offset);11541155}1156115711581159void Mesh :: Merge (istream & infile, const int surfindex_offset)1160{1161char str[100];1162int i, n;116311641165int inverttets = 0; // globflags.GetDefineFlag ("inverttets");11661167int oldnp = GetNP();1168int oldne = GetNSeg();1169int oldnd = GetNDomains();11701171for(SurfaceElementIndex si = 0; si < GetNSE(); si++)1172for(int j=1; j<=(*this)[si].GetNP(); j++) (*this)[si].GeomInfoPi(j).trignum = -1;11731174int max_surfnr = 0;1175for (i = 1; i <= GetNFD(); i++)1176max_surfnr = max2 (max_surfnr, GetFaceDescriptor(i).SurfNr());1177max_surfnr++;11781179if(max_surfnr < surfindex_offset) max_surfnr = surfindex_offset;118011811182bool endmesh = false;11831184while (infile.good() && !endmesh)1185{1186infile >> str;11871188if (strcmp (str, "surfaceelementsgi") == 0 || strcmp (str, "surfaceelements") == 0)1189{1190infile >> n;1191PrintMessage (3, n, " surface elements");1192for (i = 1; i <= n; i++)1193{1194int j;1195int surfnr, bcp, domin, domout, nep, faceind = 0;1196infile >> surfnr >> bcp >> domin >> domout;11971198surfnr--;11991200if(domin > 0) domin += oldnd;1201if(domout > 0) domout += oldnd;1202surfnr += max_surfnr;120312041205for (j = 1; j <= facedecoding.Size(); j++)1206if (GetFaceDescriptor(j).SurfNr() == surfnr &&1207GetFaceDescriptor(j).BCProperty() == bcp &&1208GetFaceDescriptor(j).DomainIn() == domin &&1209GetFaceDescriptor(j).DomainOut() == domout)1210faceind = j;12111212if (!faceind)1213{1214faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0));1215if(GetDimension() == 2) bcp++;1216GetFaceDescriptor(faceind).SetBCProperty (bcp);1217}12181219infile >> nep;1220if (!nep) nep = 3;12211222Element2d tri(nep);1223tri.SetIndex(faceind);12241225for (j = 1; j <= nep; j++)1226{1227infile >> tri.PNum(j);1228tri.PNum(j) = tri.PNum(j) + oldnp;1229}123012311232if (strcmp (str, "surfaceelementsgi") == 0)1233for (j = 1; j <= nep; j++)1234{1235infile >> tri.GeomInfoPi(j).trignum;1236tri.GeomInfoPi(j).trignum = -1;1237}12381239AddSurfaceElement (tri);1240}1241}124212431244if (strcmp (str, "edgesegments") == 0)1245{1246infile >> n;1247for (i = 1; i <= n; i++)1248{1249Segment seg;1250int hi;1251infile >> seg.si >> hi >> seg.p1 >> seg.p2;1252seg.p1 = seg.p1 + oldnp;1253seg.p2 = seg.p2 + oldnp;1254AddSegment (seg);1255}1256}1257125812591260if (strcmp (str, "edgesegmentsgi") == 0)1261{1262infile >> n;1263for (i = 1; i <= n; i++)1264{1265Segment seg;1266int hi;1267infile >> seg.si >> hi >> seg.p1 >> seg.p21268>> seg.geominfo[0].trignum1269>> seg.geominfo[1].trignum;1270seg.p1 = seg.p1 + oldnp;1271seg.p2 = seg.p2 + oldnp;1272AddSegment (seg);1273}1274}1275if (strcmp (str, "edgesegmentsgi2") == 0)1276{1277infile >> n;1278PrintMessage (3, n, " curve elements");12791280for (i = 1; i <= n; i++)1281{1282Segment seg;1283int hi;1284infile >> seg.si >> hi >> seg.p1 >> seg.p21285>> seg.geominfo[0].trignum1286>> seg.geominfo[1].trignum1287>> seg.surfnr1 >> seg.surfnr21288>> seg.edgenr1289>> seg.epgeominfo[0].dist1290>> seg.epgeominfo[1].edgenr1291>> seg.epgeominfo[1].dist;1292seg.epgeominfo[0].edgenr = seg.epgeominfo[1].edgenr;12931294seg.surfnr1--;1295seg.surfnr2--;12961297if(seg.surfnr1 >= 0) seg.surfnr1 = seg.surfnr1 + max_surfnr;1298if(seg.surfnr2 >= 0) seg.surfnr2 = seg.surfnr2 + max_surfnr;1299seg.p1 = seg.p1 +oldnp;1300seg.p2 = seg.p2 +oldnp;1301seg.edgenr = seg.edgenr + oldne;1302seg.epgeominfo[1].edgenr = seg.epgeominfo[1].edgenr + oldne;13031304AddSegment (seg);1305}1306}13071308if (strcmp (str, "volumeelements") == 0)1309{1310infile >> n;1311PrintMessage (3, n, " volume elements");1312for (i = 1; i <= n; i++)1313{1314Element el;1315int hi, nep;1316infile >> hi;1317if (hi == 0) hi = 1;1318el.SetIndex(hi+oldnd);1319infile >> nep;1320el.SetNP(nep);13211322for (int j = 0; j < nep; j++)1323{1324infile >> (int&)(el[j]);1325el[j] = el[j]+oldnp;1326}13271328if (inverttets)1329el.Invert();13301331AddVolumeElement (el);1332}1333}133413351336if (strcmp (str, "points") == 0)1337{1338infile >> n;1339PrintMessage (3, n, " points");1340for (i = 1; i <= n; i++)1341{1342Point3d p;1343infile >> p.X() >> p.Y() >> p.Z();1344AddPoint (p);1345}1346}134713481349if (strcmp (str, "endmesh") == 0)1350{1351endmesh = true;1352}135313541355if (strcmp (str, "materials") == 0)1356{1357infile >> n;1358for (i = 1; i <= n; i++)1359{1360int nr;1361string mat;1362infile >> nr >> mat;1363SetMaterial (nr+oldnd, mat.c_str());1364}1365}136613671368strcpy (str, "");1369}13701371CalcSurfacesOfNode ();13721373topology -> Update();1374clusters -> Update();13751376SetNextMajorTimeStamp();1377}13781379138013811382138313841385138613871388bool Mesh :: TestOk () const1389{1390for (ElementIndex ei = 0; ei < volelements.Size(); ei++)1391{1392for (int j = 0; j < 4; j++)1393if ( (*this)[ei][j] <= PointIndex::BASE-1)1394{1395(*testout) << "El " << ei << " has 0 nodes: ";1396for (int k = 0; k < 4; k++)1397(*testout) << (*this)[ei][k];1398break;1399}1400}1401CheckMesh3D (*this);1402return 1;1403}14041405void Mesh :: SetAllocSize(int nnodes, int nsegs, int nsel, int nel)1406{1407points.SetAllocSize(nnodes);1408segments.SetAllocSize(nsegs);1409surfelements.SetAllocSize(nsel);1410volelements.SetAllocSize(nel);1411}141214131414void Mesh :: BuildBoundaryEdges(void)1415{1416delete boundaryedges;14171418boundaryedges = new INDEX_2_CLOSED_HASHTABLE<int>1419(3 * (GetNSE() + GetNOpenElements()) + GetNSeg() + 1);142014211422for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)1423{1424const Element2d & sel = surfelements[sei];1425if (sel.IsDeleted()) continue;14261427int si = sel.GetIndex();14281429for (int j = 0; j < sel.GetNP(); j++)1430{1431INDEX_2 i2;1432i2.I1() = sel.PNumMod(j+1);1433i2.I2() = sel.PNumMod(j+2);1434i2.Sort();1435if (sel.GetNP() <= 4)1436boundaryedges->Set (i2, 1);1437}1438}143914401441for (int i = 0; i < openelements.Size(); i++)1442{1443const Element2d & sel = openelements[i];1444for (int j = 0; j < sel.GetNP(); j++)1445{1446INDEX_2 i2;1447i2.I1() = sel.PNumMod(j+1);1448i2.I2() = sel.PNumMod(j+2);1449i2.Sort();1450boundaryedges->Set (i2, 1);14511452points[sel[j]].SetType(FIXEDPOINT);1453}1454}14551456for (int i = 0; i < GetNSeg(); i++)1457{1458const Segment & seg = segments[i];1459INDEX_2 i2(seg.p1, seg.p2);1460i2.Sort();14611462boundaryedges -> Set (i2, 2);1463//segmentht -> Set (i2, i);1464}146514661467}14681469void Mesh :: CalcSurfacesOfNode ()1470{1471int i, j, k;1472SurfaceElementIndex sei;14731474surfacesonnode.SetSize (GetNP());14751476delete boundaryedges;1477boundaryedges = NULL;14781479delete surfelementht;1480delete segmentht;14811482/*1483surfelementht = new INDEX_3_HASHTABLE<int> (GetNSE()/4 + 1);1484segmentht = new INDEX_2_HASHTABLE<int> (GetNSeg() + 1);1485*/14861487surfelementht = new INDEX_3_CLOSED_HASHTABLE<int> (3*GetNSE() + 1);1488segmentht = new INDEX_2_CLOSED_HASHTABLE<int> (3*GetNSeg() + 1);14891490for (sei = 0; sei < GetNSE(); sei++)1491{1492const Element2d & sel = surfelements[sei];1493if (sel.IsDeleted()) continue;14941495int si = sel.GetIndex();14961497for (j = 0; j < sel.GetNP(); j++)1498{1499PointIndex pi = sel[j];1500bool found = 0;1501for (k = 0; k < surfacesonnode[pi].Size(); k++)1502if (surfacesonnode[pi][k] == si)1503{1504found = 1;1505break;1506}15071508if (!found)1509surfacesonnode.Add (pi, si);15101511}1512}1513/*1514for (sei = 0; sei < GetNSE(); sei++)1515{1516const Element2d & sel = surfelements[sei];1517if (sel.IsDeleted()) continue;15181519INDEX_3 i3;1520i3.I1() = sel.PNum(1);1521i3.I2() = sel.PNum(2);1522i3.I3() = sel.PNum(3);1523i3.Sort();1524surfelementht -> PrepareSet (i3);1525}15261527surfelementht -> AllocateElements();1528*/1529for (sei = 0; sei < GetNSE(); sei++)1530{1531const Element2d & sel = surfelements[sei];1532if (sel.IsDeleted()) continue;15331534INDEX_3 i3;1535i3.I1() = sel.PNum(1);1536i3.I2() = sel.PNum(2);1537i3.I3() = sel.PNum(3);1538i3.Sort();1539surfelementht -> Set (i3, sei); // war das wichtig ??? sel.GetIndex());1540}15411542int np = GetNP();15431544if (dimension == 3)1545{1546for (PointIndex pi = PointIndex::BASE;1547pi < np+PointIndex::BASE; pi++)1548points[pi].SetType (INNERPOINT);15491550if (GetNFD() == 0)1551{1552for (sei = 0; sei < GetNSE(); sei++)1553{1554const Element2d & sel = surfelements[sei];1555if (sel.IsDeleted()) continue;1556for (j = 0; j < sel.GetNP(); j++)1557{1558PointIndex pi = SurfaceElement(sei)[j];1559points[pi].SetType(FIXEDPOINT);1560}1561}1562}1563else1564{1565for (sei = 0; sei < GetNSE(); sei++)1566{1567const Element2d & sel = surfelements[sei];1568if (sel.IsDeleted()) continue;1569for (j = 0; j < sel.GetNP(); j++)1570{1571PointIndex pi = sel[j];1572int ns = surfacesonnode[pi].Size();1573if (ns == 1)1574points[pi].SetType(SURFACEPOINT);1575if (ns == 2)1576points[pi].SetType(EDGEPOINT);1577if (ns >= 3)1578points[pi].SetType(FIXEDPOINT);1579}1580}1581}15821583for (i = 0; i < segments.Size(); i++)1584{1585const Segment & seg = segments[i];1586for (j = 1; j <= 2; j++)1587{1588PointIndex hi = (j == 1) ? seg.p1 : seg.p2;15891590if (points[hi].Type() == INNERPOINT ||1591points[hi].Type() == SURFACEPOINT)1592points[hi].SetType(EDGEPOINT);1593}1594}159515961597for (i = 0; i < lockedpoints.Size(); i++)1598points[lockedpoints[i]].SetType(FIXEDPOINT);1599}160016011602/*1603for (i = 0; i < openelements.Size(); i++)1604{1605const Element2d & sel = openelements[i];1606for (j = 0; j < sel.GetNP(); j++)1607{1608INDEX_2 i2;1609i2.I1() = sel.PNumMod(j+1);1610i2.I2() = sel.PNumMod(j+2);1611i2.Sort();1612boundaryedges->Set (i2, 1);16131614points[sel[j]].SetType(FIXEDPOINT);1615}1616}1617*/16181619// eltyps.SetSize (GetNE());1620// eltyps = FREEELEMENT;16211622for (i = 0; i < GetNSeg(); i++)1623{1624const Segment & seg = segments[i];1625INDEX_2 i2(seg.p1, seg.p2);1626i2.Sort();16271628//boundaryedges -> Set (i2, 2);1629segmentht -> Set (i2, i);1630}1631}163216331634void Mesh :: FixPoints (const BitArray & fixpoints)1635{1636if (fixpoints.Size() != GetNP())1637{1638cerr << "Mesh::FixPoints: sizes don't fit" << endl;1639return;1640}1641int np = GetNP();1642for (int i = 1; i <= np; i++)1643if (fixpoints.Test(i))1644{1645points.Elem(i).SetType (FIXEDPOINT);1646}1647}164816491650void Mesh :: FindOpenElements (int dom)1651{1652static int timer = NgProfiler::CreateTimer ("Mesh::FindOpenElements");1653static int timera = NgProfiler::CreateTimer ("Mesh::FindOpenElements A");1654static int timerb = NgProfiler::CreateTimer ("Mesh::FindOpenElements B");1655static int timerc = NgProfiler::CreateTimer ("Mesh::FindOpenElements C");1656static int timerd = NgProfiler::CreateTimer ("Mesh::FindOpenElements D");1657static int timere = NgProfiler::CreateTimer ("Mesh::FindOpenElements E");16581659NgProfiler::RegionTimer reg (timer);16601661int np = GetNP();1662int ne = GetNE();1663int nse = GetNSE();16641665ARRAY<int,PointIndex::BASE> numonpoint(np);16661667numonpoint = 0;16681669NgProfiler::StartTimer (timera);1670for (ElementIndex ei = 0; ei < ne; ei++)1671{1672const Element & el = (*this)[ei];1673if (dom == 0 || dom == el.GetIndex())1674{1675if (el.GetNP() == 4)1676{1677INDEX_4 i4(el[0], el[1], el[2], el[3]);1678i4.Sort();1679numonpoint[i4.I1()]++;1680numonpoint[i4.I2()]++;1681}1682else1683for (int j = 0; j < el.GetNP(); j++)1684numonpoint[el[j]]++;1685}1686}16871688TABLE<ElementIndex,PointIndex::BASE> elsonpoint(numonpoint);1689for (ElementIndex ei = 0; ei < ne; ei++)1690{1691const Element & el = (*this)[ei];1692if (dom == 0 || dom == el.GetIndex())1693{1694if (el.GetNP() == 4)1695{1696INDEX_4 i4(el[0], el[1], el[2], el[3]);1697i4.Sort();1698elsonpoint.Add (i4.I1(), ei);1699elsonpoint.Add (i4.I2(), ei);1700}1701else1702for (int j = 0; j < el.GetNP(); j++)1703elsonpoint.Add (el[j], ei);1704}1705}1706NgProfiler::StopTimer (timera);17071708170917101711NgProfiler::StartTimer (timerb);1712171317141715ARRAY<char, 1> hasface(GetNFD());17161717int i;1718for (i = 1; i <= GetNFD(); i++)1719{1720int domin = GetFaceDescriptor(i).DomainIn();1721int domout = GetFaceDescriptor(i).DomainOut();1722hasface[i] =1723dom == 0 && (domin != 0 || domout != 0) ||1724dom != 0 && (domin == dom || domout == dom);1725}17261727numonpoint = 0;1728for (SurfaceElementIndex sii = 0; sii < nse; sii++)1729{1730int ind = surfelements[sii].GetIndex();1731/*1732if (1733GetFaceDescriptor(ind).DomainIn() &&1734(dom == 0 || dom == GetFaceDescriptor(ind).DomainIn())1735||1736GetFaceDescriptor(ind).DomainOut() &&1737(dom == 0 || dom == GetFaceDescriptor(ind).DomainOut())1738)1739*/1740if (hasface[ind])1741{1742/*1743Element2d hel = surfelements[i];1744hel.NormalizeNumbering();1745numonpoint[hel[0]]++;1746*/1747const Element2d & hel = surfelements[sii];1748int mini = 0;1749for (int j = 1; j < hel.GetNP(); j++)1750if (hel[j] < hel[mini])1751mini = j;1752numonpoint[hel[mini]]++;1753}1754}17551756TABLE<SurfaceElementIndex,PointIndex::BASE> selsonpoint(numonpoint);1757for (SurfaceElementIndex sii = 0; sii < nse; sii++)1758{1759int ind = surfelements[sii].GetIndex();17601761/*1762if (1763GetFaceDescriptor(ind).DomainIn() &&1764(dom == 0 || dom == GetFaceDescriptor(ind).DomainIn())1765||1766GetFaceDescriptor(ind).DomainOut() &&1767(dom == 0 || dom == GetFaceDescriptor(ind).DomainOut())1768)1769*/1770if (hasface[ind])1771{1772/*1773Element2d hel = surfelements[i];1774hel.NormalizeNumbering();1775selsonpoint.Add (hel[0], i);1776*/1777const Element2d & hel = surfelements[sii];1778int mini = 0;1779for (int j = 1; j < hel.GetNP(); j++)1780if (hel[j] < hel[mini])1781mini = j;1782selsonpoint.Add (hel[mini], sii);1783}1784}178517861787NgProfiler::StopTimer (timerb);17881789int ii, j, k, l;1790PointIndex pi;1791SurfaceElementIndex sei;1792Element2d hel;17931794NgProfiler::RegionTimer regc (timerc);179517961797INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht(100);1798openelements.SetSize(0);17991800for (pi = PointIndex::BASE; pi < np+PointIndex::BASE; pi++)1801if (selsonpoint[pi].Size()+elsonpoint[pi].Size())1802{1803faceht.SetSize (2 * selsonpoint[pi].Size() + 4 * elsonpoint[pi].Size());18041805FlatArray<SurfaceElementIndex> row = selsonpoint[pi];1806for (ii = 0; ii < row.Size(); ii++)1807{1808hel = SurfaceElement(row[ii]);1809int ind = hel.GetIndex();18101811if (GetFaceDescriptor(ind).DomainIn() &&1812(dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) )1813{1814hel.NormalizeNumbering();1815if (hel.PNum(1) == pi)1816{1817INDEX_3 i3(hel[0], hel[1], hel[2]);1818INDEX_2 i2 (GetFaceDescriptor(ind).DomainIn(),1819(hel.GetNP() == 3)1820? PointIndex (PointIndex::BASE-1)1821: hel.PNum(4));1822faceht.Set (i3, i2);1823}1824}1825if (GetFaceDescriptor(ind).DomainOut() &&1826(dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) )1827{1828hel.Invert();1829hel.NormalizeNumbering();1830if (hel.PNum(1) == pi)1831{1832INDEX_3 i3(hel[0], hel[1], hel[2]);1833INDEX_2 i2 (GetFaceDescriptor(ind).DomainOut(),1834(hel.GetNP() == 3)1835? PointIndex (PointIndex::BASE-1)1836: hel.PNum(4));1837faceht.Set (i3, i2);1838}1839}1840}184118421843FlatArray<ElementIndex> rowel = elsonpoint[pi];1844for (ii = 0; ii < rowel.Size(); ii++)1845{1846const Element & el = VolumeElement(rowel[ii]);18471848if (dom == 0 || el.GetIndex() == dom)1849{1850for (j = 1; j <= el.GetNFaces(); j++)1851{1852el.GetFace (j, hel);1853hel.Invert();1854hel.NormalizeNumbering();18551856if (hel[0] == pi)1857{1858INDEX_3 i3(hel[0], hel[1], hel[2]);18591860if (faceht.Used (i3))1861{1862INDEX_2 i2 = faceht.Get(i3);1863if (i2.I1() == el.GetIndex())1864{1865i2.I1() = PointIndex::BASE-1;1866faceht.Set (i3, i2);1867}1868else1869{1870if (i2.I1() == 0)1871{1872PrintSysError ("more elements on face");1873(*testout) << "more elements on face!!!" << endl;1874(*testout) << "el = " << el << endl;1875(*testout) << "hel = " << hel << endl;1876(*testout) << "face = " << i3 << endl;1877(*testout) << "points = " << endl;1878for (int jj = 1; jj <= 3; jj++)1879(*testout) << "p = " << Point(i3.I(jj)) << endl;1880}1881}1882}1883else1884{1885hel.Invert();1886hel.NormalizeNumbering();1887INDEX_3 i3(hel[0], hel[1], hel[2]);1888INDEX_2 i2(el.GetIndex(),1889(hel.GetNP() == 3)1890? PointIndex (PointIndex::BASE-1)1891: hel[3]);1892faceht.Set (i3, i2);1893}1894}1895}1896}1897}1898for (i = 0; i < faceht.Size(); i++)1899if (faceht.UsedPos (i))1900{1901INDEX_3 i3;1902INDEX_2 i2;1903faceht.GetData (i, i3, i2);1904if (i2.I1() != PointIndex::BASE-1)1905{1906Element2d tri;1907tri.SetType ( (i2.I2() == PointIndex::BASE-1) ? TRIG : QUAD);1908for (l = 0; l < 3; l++)1909tri[l] = i3.I(l+1);1910tri.PNum(4) = i2.I2();1911tri.SetIndex (i2.I1());19121913// tri.Invert();19141915openelements.Append (tri);1916}1917}1918}19191920int cnt3 = 0;1921for (i = 0; i < openelements.Size(); i++)1922if (openelements[i].GetNP() == 3)1923cnt3++;19241925int cnt4 = openelements.Size() - cnt3;192619271928MyStr treequad;1929if (cnt4)1930treequad = MyStr(" (") + MyStr(cnt3) + MyStr (" + ") +1931MyStr(cnt4) + MyStr(")");19321933PrintMessage (5, openelements.Size(), treequad, " open elements");19341935BuildBoundaryEdges();193619371938NgProfiler::RegionTimer regd (timerd);19391940for (i = 1; i <= openelements.Size(); i++)1941{1942const Element2d & sel = openelements.Get(i);19431944if (boundaryedges)1945for (j = 1; j <= sel.GetNP(); j++)1946{1947INDEX_2 i2;1948i2.I1() = sel.PNumMod(j);1949i2.I2() = sel.PNumMod(j+1);1950i2.Sort();1951boundaryedges->Set (i2, 1);1952}19531954for (j = 1; j <= 3; j++)1955{1956int pi = sel.PNum(j);1957if (pi < points.Size()+PointIndex::BASE)1958points[pi].SetType (FIXEDPOINT);1959}1960}196119621963NgProfiler::RegionTimer rege (timere);19641965/*1966for (i = 1; i <= GetNSeg(); i++)1967{1968const Segment & seg = LineSegment(i);1969INDEX_2 i2(seg.p1, seg.p2);1970i2.Sort();19711972if (!boundaryedges->Used (i2))1973cerr << "WARNING: no boundedge, but seg edge: " << i2 << endl;19741975boundaryedges -> Set (i2, 2);1976segmentht -> Set (i2, i-1);1977}1978*/1979}19801981bool Mesh :: HasOpenQuads () const1982{1983int no = GetNOpenElements();1984for (int i = 0; i < no; i++)1985if (openelements[i].GetNP() == 4)1986return true;1987return false;1988}198919901991199219931994void Mesh :: FindOpenSegments (int surfnr)1995{1996int i, j, k;19971998// new version, general elemetns1999// hash index: pnum1-22000// hash data : surfnr, surfel-nr (pos) or segment nr(neg)2001INDEX_2_HASHTABLE<INDEX_2> faceht(4 * GetNSE()+GetNSeg()+1);20022003PrintMessage (5, "Test Opensegments");2004for (i = 1; i <= GetNSeg(); i++)2005{2006const Segment & seg = LineSegment (i);20072008if (surfnr == 0 || seg.si == surfnr)2009{2010INDEX_2 key(seg.p1, seg.p2);2011INDEX_2 data(seg.si, -i);20122013if (faceht.Used (key))2014{2015cerr << "ERROR: Segment " << seg << " already used" << endl;2016(*testout) << "ERROR: Segment " << seg << " already used" << endl;2017}20182019faceht.Set (key, data);2020}2021}202220232024for (i = 1; i <= GetNSeg(); i++)2025{2026const Segment & seg = LineSegment (i);20272028if (surfnr == 0 || seg.si == surfnr)2029{2030INDEX_2 key(seg.p2, seg.p1);2031if (!faceht.Used(key))2032{2033cerr << "ERROR: Segment " << seg << " brother not used" << endl;2034(*testout) << "ERROR: Segment " << seg << " brother not used" << endl;2035}2036}2037}203820392040for (i = 1; i <= GetNSE(); i++)2041{2042const Element2d & el = SurfaceElement(i);2043if (el.IsDeleted()) continue;20442045if (surfnr == 0 || el.GetIndex() == surfnr)2046{2047for (j = 1; j <= el.GetNP(); j++)2048{2049INDEX_2 seg (el.PNumMod(j), el.PNumMod(j+1));2050INDEX_2 data;20512052if (seg.I1() <= 0 || seg.I2() <= 0)2053cerr << "seg = " << seg << endl;20542055if (faceht.Used(seg))2056{2057data = faceht.Get(seg);2058if (data.I1() == el.GetIndex())2059{2060data.I1() = 0;2061faceht.Set (seg, data);2062}2063else2064{2065PrintSysError ("hash table si not fitting for segment: ",2066seg.I1(), "-", seg.I2(), " other = ",2067data.I2());2068}2069}2070else2071{2072Swap (seg.I1(), seg.I2());2073data.I1() = el.GetIndex();2074data.I2() = i;20752076faceht.Set (seg, data);2077}2078}2079}2080}20812082(*testout) << "open segments: " << endl;2083opensegments.SetSize(0);2084for (i = 1; i <= faceht.GetNBags(); i++)2085for (j = 1; j <= faceht.GetBagSize(i); j++)2086{2087INDEX_2 i2;2088INDEX_2 data;2089faceht.GetData (i, j, i2, data);2090if (data.I1()) // surfnr2091{2092Segment seg;2093seg.p1 = i2.I1();2094seg.p2 = i2.I2();2095seg.si = data.I1();20962097// find geomdata:2098if (data.I2() > 0)2099{2100// segment due to triangle2101const Element2d & el = SurfaceElement (data.I2());2102for (k = 1; k <= el.GetNP(); k++)2103{2104if (seg.p1 == el.PNum(k))2105seg.geominfo[0] = el.GeomInfoPi(k);2106if (seg.p2 == el.PNum(k))2107seg.geominfo[1] = el.GeomInfoPi(k);2108}21092110(*testout) << "trig seg: ";2111}2112else2113{2114// segment due to line2115const Segment & lseg = LineSegment (-data.I2());2116seg.geominfo[0] = lseg.geominfo[0];2117seg.geominfo[1] = lseg.geominfo[1];21182119(*testout) << "line seg: ";2120}21212122(*testout) << seg.p1 << " - " << seg.p22123<< " len = " << Dist (Point(seg.p1), Point(seg.p2))2124<< endl;21252126opensegments.Append (seg);2127if (seg.geominfo[0].trignum <= 0 || seg.geominfo[1].trignum <= 0)2128{2129(*testout) << "Problem with open segment: " << seg << endl;2130}21312132}2133}21342135PrintMessage (3, opensegments.Size(), " open segments found");2136(*testout) << opensegments.Size() << " open segments found" << endl;21372138/*2139ptyps.SetSize (GetNP());2140for (i = 1; i <= ptyps.Size(); i++)2141ptyps.Elem(i) = SURFACEPOINT;21422143for (i = 1; i <= GetNSeg(); i++)2144{2145const Segment & seg = LineSegment (i);2146ptyps.Elem(seg.p1) = EDGEPOINT;2147ptyps.Elem(seg.p2) = EDGEPOINT;2148}2149for (i = 1; i <= GetNOpenSegments(); i++)2150{2151const Segment & seg = GetOpenSegment (i);2152ptyps.Elem(seg.p1) = EDGEPOINT;2153ptyps.Elem(seg.p2) = EDGEPOINT;2154}2155*/2156for (i = 1; i <= points.Size(); i++)2157points.Elem(i).SetType(SURFACEPOINT);21582159for (i = 1; i <= GetNSeg(); i++)2160{2161const Segment & seg = LineSegment (i);2162points[seg.p1].SetType(EDGEPOINT);2163points[seg.p2].SetType(EDGEPOINT);2164}2165for (i = 1; i <= GetNOpenSegments(); i++)2166{2167const Segment & seg = GetOpenSegment (i);2168points[seg.p1].SetType (EDGEPOINT);2169points[seg.p2].SetType (EDGEPOINT);2170}2171217221732174/*21752176for (i = 1; i <= openelements.Size(); i++)2177{2178const Element2d & sel = openelements.Get(i);21792180if (boundaryedges)2181for (j = 1; j <= sel.GetNP(); j++)2182{2183INDEX_2 i2;2184i2.I1() = sel.PNumMod(j);2185i2.I2() = sel.PNumMod(j+1);2186i2.Sort();2187boundaryedges->Set (i2, 1);2188}21892190for (j = 1; j <= 3; j++)2191{2192int pi = sel.PNum(j);2193if (pi <= ptyps.Size())2194ptyps.Elem(pi) = FIXEDPOINT;2195}2196}2197*/2198}219922002201void Mesh :: RemoveOneLayerSurfaceElements ()2202{2203int i, j;2204int np = GetNP();22052206FindOpenSegments();2207BitArray frontpoints(np);22082209frontpoints.Clear();2210for (i = 1; i <= GetNOpenSegments(); i++)2211{2212const Segment & seg = GetOpenSegment(i);2213frontpoints.Set (seg.p1);2214frontpoints.Set (seg.p2);2215}22162217for (i = 1; i <= GetNSE(); i++)2218{2219Element2d & sel = surfelements.Elem(i);2220int remove = 0;2221for (j = 1; j <= sel.GetNP(); j++)2222if (frontpoints.Test(sel.PNum(j)))2223remove = 1;2224if (remove)2225sel.PNum(1) = 0;2226}22272228for (i = surfelements.Size(); i >= 1; i--)2229{2230if (surfelements.Elem(i).PNum(1) == 0)2231{2232surfelements.Elem(i) = surfelements.Last();2233surfelements.DeleteLast();2234}2235}22362237for (int i = 0; i < facedecoding.Size(); i++)2238facedecoding[i].firstelement = -1;2239for (int i = surfelements.Size()-1; i >= 0; i--)2240{2241int ind = surfelements[i].GetIndex();2242surfelements[i].next = facedecoding[ind-1].firstelement;2243facedecoding[ind-1].firstelement = i;2244}224522462247timestamp = NextTimeStamp();2248// Compress();2249}225022512252225322542255void Mesh :: FreeOpenElementsEnvironment (int layers)2256{2257int i, j, k;2258PointIndex pi;2259const int large = 9999;2260ARRAY<int,PointIndex::BASE> dist(GetNP());22612262dist = large;22632264for (int i = 1; i <= GetNOpenElements(); i++)2265{2266const Element2d & face = OpenElement(i);2267for (j = 0; j < face.GetNP(); j++)2268dist[face[j]] = 1;2269}22702271for (k = 1; k <= layers; k++)2272for (i = 1; i <= GetNE(); i++)2273{2274const Element & el = VolumeElement(i);2275if (el[0] == -1 || el.IsDeleted()) continue;22762277int elmin = large;2278for (j = 0; j < el.GetNP(); j++)2279if (dist[el[j]] < elmin)2280elmin = dist[el[j]];22812282if (elmin < large)2283{2284for (j = 0; j < el.GetNP(); j++)2285if (dist[el[j]] > elmin+1)2286dist[el[j]] = elmin+1;2287}2288}22892290int cntfree = 0;2291for (i = 1; i <= GetNE(); i++)2292{2293Element & el = VolumeElement(i);2294if (el[0] == -1 || el.IsDeleted()) continue;22952296int elmin = large;2297for (j = 0; j < el.GetNP(); j++)2298if (dist[el[j]] < elmin)2299elmin = dist[el[j]];23002301el.flags.fixed = elmin > layers;2302// eltyps.Elem(i) = (elmin <= layers) ?2303// FREEELEMENT : FIXEDELEMENT;2304if (elmin <= layers)2305cntfree++;2306}23072308PrintMessage (5, "free: ", cntfree, ", fixed: ", GetNE()-cntfree);2309(*testout) << "free: " << cntfree << ", fixed: " << GetNE()-cntfree << endl;23102311for (pi = PointIndex::BASE;2312pi < GetNP()+PointIndex::BASE; pi++)2313{2314if (dist[pi] > layers+1)2315points[pi].SetType(FIXEDPOINT);2316}2317}2318231923202321void Mesh :: SetLocalH (const Point3d & pmin, const Point3d & pmax, double grading)2322{2323Point3d c = Center (pmin, pmax);2324double d = max3 (pmax.X()-pmin.X(),2325pmax.Y()-pmin.Y(),2326pmax.Z()-pmin.Z());2327d /= 2;2328Point3d pmin2 = c - Vec3d (d, d, d);2329Point3d pmax2 = c + Vec3d (d, d, d);233023312332delete lochfunc;2333lochfunc = new LocalH (pmin2, pmax2, grading);2334}23352336void Mesh :: RestrictLocalH (const Point3d & p, double hloc)2337{2338if(hloc < hmin)2339hloc = hmin;23402341//cout << "restrict h in " << p << " to " << hloc << endl;2342if (!lochfunc)2343{2344PrintWarning("RestrictLocalH called, creating mesh-size tree");23452346Point3d boxmin, boxmax;2347GetBox (boxmin, boxmax);2348SetLocalH (boxmin, boxmax, 0.8);2349}23502351lochfunc -> SetH (p, hloc);2352}23532354void Mesh :: RestrictLocalHLine (const Point3d & p1,2355const Point3d & p2,2356double hloc)2357{2358if(hloc < hmin)2359hloc = hmin;23602361// cout << "restrict h along " << p1 << " - " << p2 << " to " << hloc << endl;2362int i;2363int steps = int (Dist (p1, p2) / hloc) + 2;2364Vec3d v(p1, p2);23652366for (i = 0; i <= steps; i++)2367{2368Point3d p = p1 + (double(i)/double(steps) * v);2369RestrictLocalH (p, hloc);2370}2371}237223732374void Mesh :: SetMinimalH (double h)2375{2376hmin = h;2377}237823792380void Mesh :: SetGlobalH (double h)2381{2382hglob = h;2383}23842385double Mesh :: MaxHDomain (int dom) const2386{2387if (maxhdomain.Size())2388return maxhdomain.Get(dom);2389else2390return 1e10;2391}23922393void Mesh :: SetMaxHDomain (const ARRAY<double> & mhd)2394{2395maxhdomain.SetSize(mhd.Size());2396for (int i = 1; i <= mhd.Size(); i++)2397maxhdomain.Elem(i) = mhd.Get(i);2398}239924002401double Mesh :: GetH (const Point3d & p) const2402{2403double hmin = hglob;2404if (lochfunc)2405{2406double hl = lochfunc->GetH (p);2407if (hl < hglob)2408hmin = hl;2409}2410return hmin;2411}24122413double Mesh :: GetMinH (const Point3d & pmin, const Point3d & pmax)2414{2415double hmin = hglob;2416if (lochfunc)2417{2418double hl = lochfunc->GetMinH (pmin, pmax);2419if (hl < hmin)2420hmin = hl;2421}2422return hmin;2423}242424252426242724282429double Mesh :: AverageH (int surfnr) const2430{2431int i, j, n;2432double hi, hsum;2433double maxh = 0, minh = 1e10;24342435hsum = 0;2436n = 0;2437for (i = 1; i <= GetNSE(); i++)2438{2439const Element2d & el = SurfaceElement(i);2440if (surfnr == 0 || el.GetIndex() == surfnr)2441{2442for (j = 1; j <= 3; j++)2443{2444hi = Dist (Point (el.PNumMod(j)),2445Point (el.PNumMod(j+1)));24462447hsum += hi;24482449if (hi > maxh) maxh = hi;2450if (hi < minh) minh = hi;2451n++;2452}2453}2454}24552456PrintMessage (5, "minh = ", minh, " avh = ", (hsum/n), " maxh = ", maxh);2457return (hsum / n);2458}2459246024612462void Mesh :: CalcLocalH ()2463{2464if (!lochfunc)2465{2466Point3d pmin, pmax;2467GetBox (pmin, pmax);2468SetLocalH (pmin, pmax, mparam.grading);2469}24702471PrintMessage (3,2472"CalcLocalH: ",2473GetNP(), " Points ",2474GetNE(), " Elements ",2475GetNSE(), " Surface Elements");247624772478int i;2479for (i = 0; i < GetNSE(); i++)2480{2481const Element2d & el = surfelements[i];2482int j;24832484if (el.GetNP() == 3)2485{2486double hel = -1;2487for (j = 1; j <= 3; j++)2488{2489const Point3d & p1 = points[el.PNumMod(j)];2490const Point3d & p2 = points[el.PNumMod(j+1)];24912492/*2493INDEX_2 i21(el.PNumMod(j), el.PNumMod(j+1));2494INDEX_2 i22(el.PNumMod(j+1), el.PNumMod(j));2495if (! identifiedpoints->Used (i21) &&2496! identifiedpoints->Used (i22) )2497*/2498if (!ident -> UsedSymmetric (el.PNumMod(j),2499el.PNumMod(j+1)))2500{2501double hedge = Dist (p1, p2);2502if (hedge > hel)2503hel = hedge;2504// lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));2505// (*testout) << "trigseth, p1,2 = " << el.PNumMod(j) << ", " << el.PNumMod(j+1)2506// << " h = " << (2 * Dist(p1, p2)) << endl;2507}2508}25092510if (hel > 0)2511{2512const Point3d & p1 = points[el.PNum(1)];2513const Point3d & p2 = points[el.PNum(2)];2514const Point3d & p3 = points[el.PNum(3)];2515lochfunc->SetH (Center (p1, p2, p3), hel);2516}2517}2518else2519{2520{2521const Point3d & p1 = points[el.PNum(1)];2522const Point3d & p2 = points[el.PNum(2)];2523lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));2524}2525{2526const Point3d & p1 = points[el.PNum(3)];2527const Point3d & p2 = points[el.PNum(4)];2528lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));2529}2530}2531}25322533for (i = 0; i < GetNSeg(); i++)2534{2535const Segment & seg = segments[i];2536const Point3d & p1 = points[seg.p1];2537const Point3d & p2 = points[seg.p2];2538/*2539INDEX_2 i21(seg.p1, seg.p2);2540INDEX_2 i22(seg.p2, seg.p1);2541if (identifiedpoints)2542if (!identifiedpoints->Used (i21) && !identifiedpoints->Used (i22))2543*/2544if (!ident -> UsedSymmetric (seg.p1, seg.p2))2545{2546lochfunc->SetH (Center (p1, p2), Dist (p1, p2));2547}2548}2549/*2550cerr << "do vol" << endl;2551for (i = 1; i <= GetNE(); i++)2552{2553const Element & el = VolumeElement(i);2554if (el.GetType() == TET)2555{2556int j, k;2557for (j = 2; j <= 4; j++)2558for (k = 1; k < j; k++)2559{2560const Point3d & p1 = Point (el.PNum(j));2561const Point3d & p2 = Point (el.PNum(k));2562lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));2563(*testout) << "set vol h to " << (2 * Dist (p1, p2)) << endl;25642565}2566}2567}2568*/25692570/*2571const char * meshsizefilename =2572globflags.GetStringFlag ("meshsize", NULL);2573if (meshsizefilename)2574{2575ifstream msf(meshsizefilename);2576if (msf)2577{2578int nmsp;2579msf >> nmsp;2580for (i = 1; i <= nmsp; i++)2581{2582Point3d pi;2583double hi;2584msf >> pi.X() >> pi.Y() >> pi.Z();2585msf >> hi;2586lochfunc->SetH (pi, hi);2587}2588}2589}2590*/2591// lochfunc -> Convexify();2592// lochfunc -> PrintMemInfo (cout);2593}259425952596void Mesh :: CalcLocalHFromPointDistances(void)2597{2598PrintMessage (3, "Calculating local h from point distances");25992600if (!lochfunc)2601{2602Point3d pmin, pmax;2603GetBox (pmin, pmax);26042605SetLocalH (pmin, pmax, mparam.grading);2606}26072608PointIndex i,j;2609double hl;261026112612for (i = PointIndex::BASE;2613i < GetNP()+PointIndex::BASE; i++)2614{2615for(j=i+1; j<GetNP()+PointIndex::BASE; j++)2616{2617const Point3d & p1 = points[i];2618const Point3d & p2 = points[j];2619hl = Dist(p1,p2);2620RestrictLocalH(p1,hl);2621RestrictLocalH(p2,hl);2622//cout << "restricted h at " << p1 << " and " << p2 << " to " << hl << endl;2623}2624}262526262627}262826292630void Mesh :: CalcLocalHFromSurfaceCurvature (double elperr)2631{2632PrintMessage (3, "Calculating local h from surface curvature");26332634if (!lochfunc)2635{2636Point3d pmin, pmax;2637GetBox (pmin, pmax);26382639SetLocalH (pmin, pmax, mparam.grading);2640}264126422643INDEX_2_HASHTABLE<int> edges(3 * GetNP() + 2);2644INDEX_2_HASHTABLE<int> bedges(GetNSeg() + 2);2645int i, j;26462647for (i = 1; i <= GetNSeg(); i++)2648{2649const Segment & seg = LineSegment(i);2650INDEX_2 i2(seg.p1, seg.p2);2651i2.Sort();2652bedges.Set (i2, 1);2653}2654for (i = 1; i <= GetNSE(); i++)2655{2656const Element2d & sel = SurfaceElement(i);2657if (!sel.PNum(1))2658continue;2659for (j = 1; j <= 3; j++)2660{2661INDEX_2 i2(sel.PNumMod(j), sel.PNumMod(j+1));2662i2.Sort();2663if (bedges.Used(i2)) continue;26642665if (edges.Used(i2))2666{2667int other = edges.Get(i2);26682669const Element2d & elother = SurfaceElement(other);26702671int pi3 = 1;2672while ( (sel.PNum(pi3) == i2.I1()) ||2673(sel.PNum(pi3) == i2.I2()))2674pi3++;2675pi3 = sel.PNum(pi3);26762677int pi4 = 1;2678while ( (elother.PNum(pi4) == i2.I1()) ||2679(elother.PNum(pi4) == i2.I2()))2680pi4++;2681pi4 = elother.PNum(pi4);26822683double rad = ComputeCylinderRadius (Point (i2.I1()),2684Point (i2.I2()),2685Point (pi3),2686Point (pi4));26872688RestrictLocalHLine (Point(i2.I1()), Point(i2.I2()), rad/elperr);268926902691/*2692(*testout) << "pi1,2, 3, 4 = " << i2.I1() << ", " << i2.I2() << ", " << pi3 << ", " << pi42693<< " p1 = " << Point(i2.I1())2694<< ", p2 = " << Point(i2.I2())2695// << ", p3 = " << Point(pi3)2696// << ", p4 = " << Point(pi4)2697<< ", rad = " << rad << endl;2698*/2699}2700else2701edges.Set (i2, i);2702}2703}270427052706// Restrict h due to line segments27072708for (i = 1; i <= GetNSeg(); i++)2709{2710const Segment & seg = LineSegment(i);2711const Point3d & p1 = Point(seg.p1);2712const Point3d & p2 = Point(seg.p2);2713RestrictLocalH (Center (p1, p2), Dist (p1, p2));2714}2715271627172718/*271927202721int i, j;2722int np = GetNP();2723int nseg = GetNSeg();2724int nse = GetNSE();27252726ARRAY<Vec3d> normals(np);2727BitArray linepoint(np);27282729linepoint.Clear();2730for (i = 1; i <= nseg; i++)2731{2732linepoint.Set (LineSegment(i).p1);2733linepoint.Set (LineSegment(i).p2);2734}27352736for (i = 1; i <= np; i++)2737normals.Elem(i) = Vec3d(0,0,0);27382739for (i = 1; i <= nse; i++)2740{2741Element2d & el = SurfaceElement(i);2742Vec3d nf = Cross (Vec3d (Point (el.PNum(1)), Point(el.PNum(2))),2743Vec3d (Point (el.PNum(1)), Point(el.PNum(3))));2744for (j = 1; j <= 3; j++)2745normals.Elem(el.PNum(j)) += nf;2746}27472748for (i = 1; i <= np; i++)2749normals.Elem(i) /= (1e-12 + normals.Elem(i).Length());27502751for (i = 1; i <= nse; i++)2752{2753Element2d & el = SurfaceElement(i);2754Vec3d nf = Cross (Vec3d (Point (el.PNum(1)), Point(el.PNum(2))),2755Vec3d (Point (el.PNum(1)), Point(el.PNum(3))));2756nf /= nf.Length();2757Point3d c = Center (Point(el.PNum(1)),2758Point(el.PNum(2)),2759Point(el.PNum(3)));27602761for (j = 1; j <= 3; j++)2762{2763if (!linepoint.Test (el.PNum(j)))2764{2765double dist = Dist (c, Point(el.PNum(j)));2766double dn = (nf - normals.Get(el.PNum(j))).Length();27672768RestrictLocalH (Point(el.PNum(j)), dist / (dn+1e-12) /elperr);2769}2770}2771}2772*/2773}277427752776void Mesh :: RestrictLocalH (resthtype rht, int nr, double loch)2777{2778int i;2779switch (rht)2780{2781case RESTRICTH_FACE:2782{2783for (i = 1; i <= GetNSE(); i++)2784{2785const Element2d & sel = SurfaceElement(i);2786if (sel.GetIndex() == nr)2787RestrictLocalH (RESTRICTH_SURFACEELEMENT, i, loch);2788}2789break;2790}2791case RESTRICTH_EDGE:2792{2793for (i = 1; i <= GetNSeg(); i++)2794{2795const Segment & seg = LineSegment(i);2796if (seg.edgenr == nr)2797RestrictLocalH (RESTRICTH_SEGMENT, i, loch);2798}2799break;2800}2801case RESTRICTH_POINT:2802{2803RestrictLocalH (Point (nr), loch);2804break;2805}28062807case RESTRICTH_SURFACEELEMENT:2808{2809const Element2d & sel = SurfaceElement(nr);2810Point3d p = Center (Point(sel.PNum(1)),2811Point(sel.PNum(2)),2812Point(sel.PNum(3)));2813RestrictLocalH (p, loch);2814break;2815}2816case RESTRICTH_SEGMENT:2817{2818const Segment & seg = LineSegment(nr);2819RestrictLocalHLine (Point (seg.p1), Point(seg.p2), loch);2820break;2821}2822}2823}282428252826void Mesh :: LoadLocalMeshSize (const char * meshsizefilename)2827{2828if (!meshsizefilename) return;28292830ifstream msf(meshsizefilename);28312832if (!msf) return;28332834PrintMessage (3, "Load local mesh-size");2835int nmsp, nmsl;2836msf >> nmsp;2837for (int i = 0; i < nmsp; i++)2838{2839Point3d pi;2840double hi;2841msf >> pi.X() >> pi.Y() >> pi.Z();2842msf >> hi;2843if (!msf.good())2844throw NgException ("problem in mesh-size file\n");2845RestrictLocalH (pi, hi);2846}2847msf >> nmsl;2848for (int i = 0; i < nmsl; i++)2849{2850Point3d p1, p2;2851double hi;2852msf >> p1.X() >> p1.Y() >> p1.Z();2853msf >> p2.X() >> p2.Y() >> p2.Z();2854msf >> hi;2855if (!msf.good())2856throw NgException ("problem in mesh-size file\n");2857RestrictLocalHLine (p1, p2, hi);2858}2859}2860286128622863void Mesh :: GetBox (Point3d & pmin, Point3d & pmax, int dom) const2864{2865if (points.Size() == 0)2866{2867pmin = pmax = Point3d(0,0,0);2868return;2869}28702871if (dom <= 0)2872{2873pmin = Point3d (1e10, 1e10, 1e10);2874pmax = Point3d (-1e10, -1e10, -1e10);28752876for (PointIndex pi = PointIndex::BASE;2877pi < GetNP()+PointIndex::BASE; pi++)2878{2879pmin.SetToMin ( (*this) [pi] );2880pmax.SetToMax ( (*this) [pi] );2881}2882}2883else2884{2885int j, nse = GetNSE();2886SurfaceElementIndex sei;28872888pmin = Point3d (1e10, 1e10, 1e10);2889pmax = Point3d (-1e10, -1e10, -1e10);2890for (sei = 0; sei < nse; sei++)2891{2892const Element2d & el = (*this)[sei];2893if (el.IsDeleted() ) continue;28942895if (dom == -1 || el.GetIndex() == dom)2896{2897for (j = 0; j < 3; j++)2898{2899pmin.SetToMin ( (*this) [el[j]] );2900pmax.SetToMax ( (*this) [el[j]] );2901}2902}2903}2904}29052906if (pmin.X() > 0.5e10)2907{2908pmin = pmax = Point3d(0,0,0);2909}2910}29112912291329142915void Mesh :: GetBox (Point3d & pmin, Point3d & pmax, POINTTYPE ptyp) const2916{2917if (points.Size() == 0)2918{2919pmin = pmax = Point3d(0,0,0);2920return;2921}29222923pmin = Point3d (1e10, 1e10, 1e10);2924pmax = Point3d (-1e10, -1e10, -1e10);29252926for (PointIndex pi = PointIndex::BASE;2927pi < GetNP()+PointIndex::BASE; pi++)2928if (points[pi].Type() <= ptyp)2929{2930pmin.SetToMin ( (*this) [pi] );2931pmax.SetToMax ( (*this) [pi] );2932}2933}29342935293629372938double Mesh :: ElementError (int eli) const2939{2940const Element & el = volelements.Get(eli);2941return CalcTetBadness (points.Get(el[0]), points.Get(el[1]),2942points.Get(el[2]), points.Get(el[3]), -1);2943}29442945void Mesh :: AddLockedPoint (PointIndex pi)2946{2947lockedpoints.Append (pi);2948}29492950void Mesh :: ClearLockedPoints ()2951{2952lockedpoints.SetSize (0);2953}2954295529562957void Mesh :: Compress ()2958{2959int i, j;2960ARRAY<int,PointIndex::BASE> op2np(GetNP());2961ARRAY<MeshPoint> hpoints;2962BitArrayChar<PointIndex::BASE> pused(GetNP());29632964/*2965(*testout) << "volels: " << endl;2966for (i = 1; i <= volelements.Size(); i++)2967{2968for (j = 1; j <= volelements.Get(i).GetNP(); j++)2969(*testout) << volelements.Get(i).PNum(j) << " ";2970(*testout) << endl;2971}2972(*testout) << "np: " << GetNP() << endl;2973*/29742975for (i = 0; i < volelements.Size(); i++)2976if (volelements[i][0] <= PointIndex::BASE-1 ||2977volelements[i].IsDeleted())2978{2979volelements.Delete(i);2980i--;2981}298229832984for (i = 0; i < surfelements.Size(); i++)2985if (surfelements[i].IsDeleted())2986{2987surfelements.Delete(i);2988i--;2989}29902991for (i = 0; i < segments.Size(); i++)2992if (segments[i].p1 <= PointIndex::BASE-1)2993{2994segments.Delete(i);2995i--;2996}29972998pused.Clear();2999for (i = 0; i < volelements.Size(); i++)3000{3001const Element & el = volelements[i];3002for (j = 0; j < el.GetNP(); j++)3003pused.Set (el[j]);3004}30053006for (i = 0; i < surfelements.Size(); i++)3007{3008const Element2d & el = surfelements[i];3009for (j = 0; j < el.GetNP(); j++)3010pused.Set (el[j]);3011}30123013for (i = 0; i < segments.Size(); i++)3014{3015const Segment & seg = segments[i];3016pused.Set (seg.p1);3017pused.Set (seg.p2);3018}30193020for (i = 0; i < openelements.Size(); i++)3021{3022const Element2d & el = openelements[i];3023for (j = 0; j < el.GetNP(); j++)3024pused.Set(el[j]);3025}30263027for (i = 0; i < lockedpoints.Size(); i++)3028pused.Set (lockedpoints[i]);302930303031/*3032// compress points doesnt work for identified points !3033if (identifiedpoints)3034{3035for (i = 1; i <= identifiedpoints->GetNBags(); i++)3036if (identifiedpoints->GetBagSize(i))3037{3038pused.Set ();3039break;3040}3041}3042*/3043// pused.Set();304430453046int npi = PointIndex::BASE-1;30473048for (i = PointIndex::BASE;3049i < points.Size()+PointIndex::BASE; i++)3050if (pused.Test(i))3051{3052npi++;3053op2np[i] = npi;3054hpoints.Append (points[i]);3055}3056else3057op2np[i] = -1;3058305930603061points.SetSize(0);3062for (i = 0; i < hpoints.Size(); i++)3063points.Append (hpoints[i]);306430653066for (i = 1; i <= volelements.Size(); i++)3067{3068Element & el = VolumeElement(i);3069for (j = 0; j < el.GetNP(); j++)3070el[j] = op2np[el[j]];3071}30723073for (i = 1; i <= surfelements.Size(); i++)3074{3075Element2d & el = SurfaceElement(i);3076for (j = 0; j < el.GetNP(); j++)3077el[j] = op2np[el[j]];3078}30793080for (i = 0; i < segments.Size(); i++)3081{3082Segment & seg = segments[i];3083seg.p1 = op2np[seg.p1];3084seg.p2 = op2np[seg.p2];3085}30863087for (i = 1; i <= openelements.Size(); i++)3088{3089Element2d & el = openelements.Elem(i);3090for (j = 0; j < el.GetNP(); j++)3091el[j] = op2np[el[j]];3092}309330943095for (i = 0; i < lockedpoints.Size(); i++)3096lockedpoints[i] = op2np[lockedpoints[i]];30973098for (int i = 0; i < facedecoding.Size(); i++)3099facedecoding[i].firstelement = -1;3100for (int i = surfelements.Size()-1; i >= 0; i--)3101{3102int ind = surfelements[i].GetIndex();3103surfelements[i].next = facedecoding[ind-1].firstelement;3104facedecoding[ind-1].firstelement = i;3105}310631073108CalcSurfacesOfNode();310931103111// FindOpenElements();3112timestamp = NextTimeStamp();31133114/*3115(*testout) << "compress, done" << endl3116<< "np = " << points.Size()3117<< "ne = " << volelements.Size() << ", type.size = " << eltyps.Size()3118<< "volelements = " << volelements << endl;3119*/3120}312131223123int Mesh :: CheckConsistentBoundary () const3124{3125int nf = GetNOpenElements();3126INDEX_2_HASHTABLE<int> edges(nf+2);3127INDEX_2 i2, i2s, edge;3128int err = 0;31293130for (int i = 1; i <= nf; i++)3131{3132const Element2d & sel = OpenElement(i);31333134for (int j = 1; j <= sel.GetNP(); j++)3135{3136i2.I1() = sel.PNumMod(j);3137i2.I2() = sel.PNumMod(j+1);31383139int sign = (i2.I2() > i2.I1()) ? 1 : -1;3140i2.Sort();3141if (!edges.Used (i2))3142edges.Set (i2, 0);3143edges.Set (i2, edges.Get(i2) + sign);3144}3145}31463147for (int i = 1; i <= edges.GetNBags(); i++)3148for (int j = 1; j <= edges.GetBagSize(i); j++)3149{3150int cnt = 0;3151edges.GetData (i, j, i2, cnt);3152if (cnt)3153{3154PrintError ("Edge ", i2.I1() , " - ", i2.I2(), " multiple times in surface mesh");31553156(*testout) << "Edge " << i2 << " multiple times in surface mesh" << endl;3157i2s = i2;3158i2s.Sort();3159for (int k = 1; k <= nf; k++)3160{3161const Element2d & sel = OpenElement(k);3162for (int l = 1; l <= sel.GetNP(); l++)3163{3164edge.I1() = sel.PNumMod(l);3165edge.I2() = sel.PNumMod(l+1);3166edge.Sort();31673168if (edge == i2s)3169(*testout) << "edge of element " << sel << endl;3170}3171}317231733174err = 2;3175}3176}31773178return err;3179}3180318131823183int Mesh :: CheckOverlappingBoundary ()3184{3185int i, j, k;31863187Point3d pmin, pmax;3188GetBox (pmin, pmax);3189Box3dTree setree(pmin, pmax);3190ARRAY<int> inters;31913192bool overlap = 0;3193bool incons_layers = 0;319431953196for (i = 1; i <= GetNSE(); i++)3197SurfaceElement(i).badel = 0;319831993200for (i = 1; i <= GetNSE(); i++)3201{3202const Element2d & tri = SurfaceElement(i);32033204Point3d tpmin (Point(tri[0]));3205Point3d tpmax (tpmin);32063207for (k = 1; k < tri.GetNP(); k++)3208{3209tpmin.SetToMin (Point (tri[k]));3210tpmax.SetToMax (Point (tri[k]));3211}3212Vec3d diag(tpmin, tpmax);32133214tpmax = tpmax + 0.1 * diag;3215tpmin = tpmin - 0.1 * diag;32163217setree.Insert (tpmin, tpmax, i);3218}32193220for (i = 1; i <= GetNSE(); i++)3221{3222const Element2d & tri = SurfaceElement(i);32233224Point3d tpmin (Point(tri[0]));3225Point3d tpmax (tpmin);32263227for (k = 1; k < tri.GetNP(); k++)3228{3229tpmin.SetToMin (Point (tri[k]));3230tpmax.SetToMax (Point (tri[k]));3231}32323233setree.GetIntersecting (tpmin, tpmax, inters);32343235for (j = 1; j <= inters.Size(); j++)3236{3237const Element2d & tri2 = SurfaceElement(inters.Get(j));32383239if ( (*this)[tri[0]].GetLayer() != (*this)[tri2[0]].GetLayer())3240continue;32413242if ( (*this)[tri[0]].GetLayer() != (*this)[tri[1]].GetLayer() ||3243(*this)[tri[0]].GetLayer() != (*this)[tri[2]].GetLayer())3244{3245incons_layers = 1;3246cout << "inconsistent layers in triangle" << endl;3247}324832493250const netgen::Point<3> *trip1[3], *trip2[3];3251for (k = 1; k <= 3; k++)3252{3253trip1[k-1] = &Point (tri.PNum(k));3254trip2[k-1] = &Point (tri2.PNum(k));3255}32563257if (IntersectTriangleTriangle (&trip1[0], &trip2[0]))3258{3259overlap = 1;3260PrintWarning ("Intersecting elements "3261,i, " and ", inters.Get(j));32623263(*testout) << "Intersecting: " << endl;3264(*testout) << "openelement " << i << " with open element " << inters.Get(j) << endl;32653266cout << "el1 = " << tri << endl;3267cout << "el2 = " << tri2 << endl;3268cout << "layer1 = " << (*this)[tri[0]].GetLayer() << endl;3269cout << "layer2 = " << (*this)[tri2[0]].GetLayer() << endl;327032713272for (k = 1; k <= 3; k++)3273(*testout) << tri.PNum(k) << " ";3274(*testout) << endl;3275for (k = 1; k <= 3; k++)3276(*testout) << tri2.PNum(k) << " ";3277(*testout) << endl;32783279for (k = 0; k <= 2; k++)3280(*testout) << *trip1[k] << " ";3281(*testout) << endl;3282for (k = 0; k <= 2; k++)3283(*testout) << *trip2[k] << " ";3284(*testout) << endl;32853286(*testout) << "Face1 = " << GetFaceDescriptor(tri.GetIndex()) << endl;3287(*testout) << "Face1 = " << GetFaceDescriptor(tri2.GetIndex()) << endl;32883289/*3290INDEX_3 i3(tri.PNum(1), tri.PNum(2), tri.PNum(3));3291i3.Sort();3292for (k = 1; k <= GetNSE(); k++)3293{3294const Element2d & el2 = SurfaceElement(k);3295INDEX_3 i3b(el2.PNum(1), el2.PNum(2), el2.PNum(3));3296i3b.Sort();3297if (i3 == i3b)3298{3299SurfaceElement(k).badel = 1;3300}3301}3302*/3303SurfaceElement(i).badel = 1;3304SurfaceElement(inters.Get(j)).badel = 1;3305}3306}3307}33083309// bug 'fix'3310if (incons_layers) overlap = 0;33113312return overlap;3313}331433153316int Mesh :: CheckVolumeMesh () const3317{3318PrintMessage (3, "Checking volume mesh");33193320int ne = GetNE();3321DenseMatrix dtrans(3,3);3322int i, j;33233324PrintMessage (5, "elements: ", ne);3325for (i = 1; i <= ne; i++)3326{3327Element & el = (Element&) VolumeElement(i);3328el.flags.badel = 0;3329int nip = el.GetNIP();3330for (j = 1; j <= nip; j++)3331{3332el.GetTransformation (j, Points(), dtrans);3333double det = dtrans.Det();3334if (det > 0)3335{3336PrintError ("Element ", i , " has wrong orientation");3337el.flags.badel = 1;3338}3339}3340}33413342return 0;3343}334433453346bool Mesh :: LegalTrig (const Element2d & el) const3347{3348return 1;3349if ( /* hp */ 1) // needed for old, simple hp-refinement3350{3351// trigs with 2 or more segments are illegal3352int i;3353int nseg = 0;33543355if (!segmentht)3356{3357cerr << "no segmentht allocated" << endl;3358return 0;3359}33603361// Point3d cp(0.5, 0.5, 0.5);3362for (i = 1; i <= 3; i++)3363{3364INDEX_2 i2(el.PNumMod (i), el.PNumMod (i+1));3365i2.Sort();3366if (segmentht -> Used (i2))3367nseg++;3368}3369if (nseg >= 2)3370return 0;3371}3372return 1;3373}33743375337633773378///3379bool Mesh :: LegalTet2 (Element & el) const3380{3381// static int timer1 = NgProfiler::CreateTimer ("Legaltet2");338233833384// Test, whether 4 points have a common surface plus3385// at least 4 edges at the boundary33863387if(!boundaryedges)3388const_cast<Mesh *>(this)->BuildBoundaryEdges();338933903391// non-tets are always legal3392if (el.GetType() != TET)3393{3394el.SetLegal (1);3395return 1;3396}33973398POINTTYPE pointtype[4];3399for(int i = 0; i < 4; i++)3400pointtype[i] = (*this)[el[i]].Type();3401340234033404// element has at least 2 inner points ---> legal3405int cnti = 0;3406for (int j = 0; j < 4; j++)3407if ( pointtype[j] == INNERPOINT)3408{3409cnti++;3410if (cnti >= 2)3411{3412el.SetLegal (1);3413return 1;3414}3415}3416341734183419// which faces are boundary faces ?3420int bface[4];3421for (int i = 0; i < 4; i++)3422{3423bface[i] = surfelementht->Used (INDEX_3::Sort(el[gftetfacesa[i][0]],3424el[gftetfacesa[i][1]],3425el[gftetfacesa[i][2]]));3426}34273428int bedge[4][4];3429int segedge[4][4];3430static const int pi3map[4][4] = { { -1, 2, 1, 1 },3431{ 2, -1, 0, 0 },3432{ 1, 0, -1, 0 },3433{ 1, 0, 0, -1 } };34343435static const int pi4map[4][4] = { { -1, 3, 3, 2 },3436{ 3, -1, 3, 2 },3437{ 3, 3, -1, 1 },3438{ 2, 2, 1, -1 } };343934403441for (int i = 0; i < 4; i++)3442for (int j = 0; j < i; j++)3443{3444bool sege = false, be = false;34453446int pos = boundaryedges -> Position(INDEX_2::Sort(el[i], el[j]));3447if (pos)3448{3449be = true;3450if (boundaryedges -> GetData(pos) == 2)3451sege = true;3452}34533454segedge[j][i] = segedge[i][j] = sege;3455bedge[j][i] = bedge[i][j] = be;3456}34573458// two boundary faces and no edge is illegal3459for (int i = 0; i < 3; i++)3460for (int j = i+1; j < 4; j++)3461{3462if (bface[i] && bface[j])3463if (!segedge[pi3map[i][j]][pi4map[i][j]])3464{3465// 2 boundary faces withoud edge in between3466el.SetLegal (0);3467return 0;3468}3469}34703471// three boundary edges meeting in a Surface point3472for (int i = 0; i < 4; i++)3473{3474bool alledges = 1;3475if ( pointtype[i] == SURFACEPOINT)3476{3477bool alledges = 1;3478for (int j = 0; j < 4; j++)3479if (j != i && !bedge[i][j])3480{3481alledges = 0;3482break;3483}3484if (alledges)3485{3486// cout << "tet illegal due to unmarked node" << endl;3487el.SetLegal (0);3488return 0;3489}3490}3491}3492349334943495for (int fnr = 0; fnr < 4; fnr++)3496if (!bface[fnr])3497for (int i = 0; i < 4; i++)3498if (i != fnr)3499{3500int pi1 = pi3map[i][fnr];3501int pi2 = pi4map[i][fnr];35023503if ( pointtype[i] == SURFACEPOINT)3504{3505// two connected edges on surface, but no face3506if (bedge[i][pi1] && bedge[i][pi2])3507{3508el.SetLegal (0);3509return 0;3510}3511}35123513if ( pointtype[i] == EDGEPOINT)3514{3515// connected surface edge and edge edge, but no face3516if (bedge[i][pi1] && segedge[i][pi2] ||3517bedge[i][pi2] && segedge[i][pi1])3518{3519el.SetLegal (0);3520return 0;3521}3522}35233524}352535263527el.SetLegal (1);3528return 1;35293530}3531353235333534int Mesh :: GetNDomains() const3535{3536int ndom = 0;35373538for (int k = 0; k < facedecoding.Size(); k++)3539{3540if (facedecoding[k].DomainIn() > ndom)3541ndom = facedecoding[k].DomainIn();3542if (facedecoding[k].DomainOut() > ndom)3543ndom = facedecoding[k].DomainOut();3544}35453546return ndom;3547}3548354935503551void Mesh :: SurfaceMeshOrientation ()3552{3553int i, j;3554int nse = GetNSE();35553556BitArray used(nse);3557used.Clear();3558INDEX_2_HASHTABLE<int> edges(nse+1);35593560bool haschanged = 0;356135623563const Element2d & tri = SurfaceElement(1);3564for (j = 1; j <= 3; j++)3565{3566INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1));3567edges.Set (i2, 1);3568}3569used.Set(1);35703571bool unused;3572do3573{3574bool changed;3575do3576{3577changed = 0;3578for (i = 1; i <= nse; i++)3579if (!used.Test(i))3580{3581Element2d & el = surfelements.Elem(i);3582int found = 0, foundrev = 0;3583for (j = 1; j <= 3; j++)3584{3585INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1));3586if (edges.Used(i2))3587foundrev = 1;3588swap (i2.I1(), i2.I2());3589if (edges.Used(i2))3590found = 1;3591}35923593if (found || foundrev)3594{3595if (foundrev)3596swap (el.PNum(2), el.PNum(3));35973598changed = 1;3599for (j = 1; j <= 3; j++)3600{3601INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1));3602edges.Set (i2, 1);3603}3604used.Set (i);3605}3606}3607if (changed)3608haschanged = 1;3609}3610while (changed);361136123613unused = 0;3614for (i = 1; i <= nse; i++)3615if (!used.Test(i))3616{3617unused = 1;3618const Element2d & tri = SurfaceElement(i);3619for (j = 1; j <= 3; j++)3620{3621INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1));3622edges.Set (i2, 1);3623}3624used.Set(i);3625break;3626}3627}3628while (unused);36293630if (haschanged)3631timestamp = NextTimeStamp();3632}363336343635void Mesh :: Split2Tets()3636{3637PrintMessage (1, "Split To Tets");3638bool has_prisms = 0;36393640int oldne = GetNE();3641for (int i = 1; i <= oldne; i++)3642{3643Element el = VolumeElement(i);36443645if (el.GetType() == PRISM)3646{3647// prism, to 3 tets36483649// make minimal node to node 13650int minpi=0;3651PointIndex minpnum;3652minpnum = GetNP() + 1;36533654for (int j = 1; j <= 6; j++)3655{3656if (el.PNum(j) < minpnum)3657{3658minpnum = el.PNum(j);3659minpi = j;3660}3661}36623663if (minpi >= 4)3664{3665for (int j = 1; j <= 3; j++)3666swap (el.PNum(j), el.PNum(j+3));3667minpi -= 3;3668}36693670while (minpi > 1)3671{3672int hi = 0;3673for (int j = 0; j <= 3; j+= 3)3674{3675hi = el.PNum(1+j);3676el.PNum(1+j) = el.PNum(2+j);3677el.PNum(2+j) = el.PNum(3+j);3678el.PNum(3+j) = hi;3679}3680minpi--;3681}36823683/*3684version 1: edge from pi2 to pi6,3685version 2: edge from pi3 to pi5,3686*/36873688static const int ntets[2][12] =3689{ { 1, 4, 5, 6, 1, 2, 3, 6, 1, 2, 5, 6 },3690{ 1, 4, 5, 6, 1, 2, 3, 5, 3, 1, 5, 6 } };36913692const int * min2pi;36933694if (min2 (el.PNum(2), el.PNum(6)) <3695min2 (el.PNum(3), el.PNum(5)))3696{3697min2pi = &ntets[0][0];3698// (*testout) << "version 1 ";3699}3700else3701{3702min2pi = &ntets[1][0];3703// (*testout) << "version 2 ";3704}370537063707int firsttet = 1;3708for (int j = 1; j <= 3; j++)3709{3710Element nel(TET);3711for (int k = 1; k <= 4; k++)3712nel.PNum(k) = el.PNum(min2pi[4 * j + k - 5]);3713nel.SetIndex (el.GetIndex());37143715int legal = 1;3716for (int k = 1; k <= 3; k++)3717for (int l = k+1; l <= 4; l++)3718if (nel.PNum(k) == nel.PNum(l))3719legal = 0;37203721// (*testout) << nel << " ";3722if (legal)3723{3724if (firsttet)3725{3726VolumeElement(i) = nel;3727firsttet = 0;3728}3729else3730{3731AddVolumeElement(nel);3732}3733}3734}3735if (firsttet) cout << "no legal";3736(*testout) << endl;3737}3738373937403741else if (el.GetType() == HEX)3742{3743// hex to A) 2 prisms or B) to 5 tets37443745// make minimal node to node 13746int minpi=0;3747PointIndex minpnum;3748minpnum = GetNP() + 1;37493750for (int j = 1; j <= 8; j++)3751{3752if (el.PNum(j) < minpnum)3753{3754minpnum = el.PNum(j);3755minpi = j;3756}3757}37583759if (minpi >= 5)3760{3761for (int j = 1; j <= 4; j++)3762swap (el.PNum(j), el.PNum(j+4));3763minpi -= 4;3764}37653766while (minpi > 1)3767{3768int hi = 0;3769for (int j = 0; j <= 4; j+= 4)3770{3771hi = el.PNum(1+j);3772el.PNum(1+j) = el.PNum(2+j);3773el.PNum(2+j) = el.PNum(3+j);3774el.PNum(3+j) = el.PNum(4+j);3775el.PNum(4+j) = hi;3776}3777minpi--;3778}3779378037813782static const int to_prisms[3][12] =3783{ { 0, 1, 2, 4, 5, 6, 0, 2, 3, 4, 6, 7 },3784{ 0, 1, 5, 3, 2, 6, 0, 5, 4, 3, 6, 7 },3785{ 0, 7, 4, 1, 6, 5, 0, 3, 7, 1, 2, 6 },3786};37873788const int * min2pi = 0;3789if (min2 (el[4], el[6]) < min2 (el[5], el[7]))3790min2pi = &to_prisms[0][0];3791else if (min2 (el[3], el[6]) < min2 (el[2], el[7]))3792min2pi = &to_prisms[1][0];3793else if (min2 (el[1], el[6]) < min2 (el[2], el[5]))3794min2pi = &to_prisms[2][0];37953796if (min2pi)3797{3798has_prisms = 1;3799for (int j = 0; j < 2; j++)3800{3801Element nel(PRISM);3802for (int k = 0; k < 6; k++)3803nel[k] = el[min2pi[6*j + k]];3804nel.SetIndex (el.GetIndex());38053806if (j == 0)3807VolumeElement(i) = nel;3808else3809AddVolumeElement(nel);3810}3811}3812else3813{3814// split to 5 tets38153816static const int to_tets[20] =3817{38181, 2, 0, 5,38193, 0, 2, 7,38204, 5, 7, 0,38216, 7, 5, 2,38220, 2, 7, 53823};38243825for (int j = 0; j < 5; j++)3826{3827Element nel(TET);3828for (int k = 0; k < 4; k++)3829nel[k] = el[to_tets[4*j + k]];3830nel.SetIndex (el.GetIndex());38313832if (j == 0)3833VolumeElement(i) = nel;3834else3835AddVolumeElement(nel);3836}38373838}3839}384038413842384338443845else if (el.GetType() == PYRAMID)3846{3847// pyramid, to 2 tets38483849// cout << "pyramid: " << el << endl;38503851static const int ntets[2][8] =3852{ { 1, 2, 3, 5, 1, 3, 4, 5 },3853{ 1, 2, 4, 5, 4, 2, 3, 5 }};38543855const int * min2pi;38563857if (min2 (el[0], el[2]) < min2 (el[1], el[3]))3858min2pi = &ntets[0][0];3859else3860min2pi = &ntets[1][0];38613862bool firsttet = 1;3863for (int j = 0; j < 2; j++)3864{3865Element nel(TET);3866for (int k = 0; k < 4; k++)3867nel[k] = el[min2pi[4*j + k]-1];3868nel.SetIndex (el.GetIndex());38693870// cout << "pyramid-tet: " << nel << endl;38713872bool legal = 1;3873for (int k = 0; k < 3; k++)3874for (int l = k+1; l < 4; l++)3875if (nel[k] == nel[l])3876legal = 0;38773878if (legal)3879{3880(*testout) << nel << " ";3881if (firsttet)3882VolumeElement(i) = nel;3883else3884AddVolumeElement(nel);38853886firsttet = 0;3887}3888}3889if (firsttet) cout << "no legal";3890(*testout) << endl;3891}3892}389338943895int oldnse = GetNSE();3896for (int i = 1; i <= oldnse; i++)3897{3898Element2d el = SurfaceElement(i);3899if (el.GetNP() == 4)3900{3901(*testout) << "split el: " << el << " to ";39023903static const int ntris[2][6] =3904{ { 1, 2, 3, 1, 3, 4 },3905{ 1, 2, 4, 4, 2, 3 }};39063907const int * min2pi;39083909if (min2 (el.PNum(1), el.PNum(3)) <3910min2 (el.PNum(2), el.PNum(4)))3911min2pi = &ntris[0][0];3912else3913min2pi = &ntris[1][0];39143915for (int j = 0; j <6; j++)3916(*testout) << min2pi[j] << " ";391739183919int firsttri = 1;3920for (int j = 1; j <= 2; j++)3921{3922Element2d nel(3);3923for (int k = 1; k <= 3; k++)3924nel.PNum(k) = el.PNum(min2pi[3 * j + k - 4]);3925nel.SetIndex (el.GetIndex());39263927int legal = 1;3928for (int k = 1; k <= 2; k++)3929for (int l = k+1; l <= 3; l++)3930if (nel.PNum(k) == nel.PNum(l))3931legal = 0;39323933if (legal)3934{3935(*testout) << nel << " ";3936if (firsttri)3937{3938SurfaceElement(i) = nel;3939firsttri = 0;3940}3941else3942{3943AddSurfaceElement(nel);3944}3945}3946}3947(*testout) << endl;39483949}3950}395139523953if (has_prisms)39543955Split2Tets();39563957else3958{3959for (int i = 1; i <= GetNE(); i++)3960{3961Element & el = VolumeElement(i);3962const Point3d & p1 = Point (el.PNum(1));3963const Point3d & p2 = Point (el.PNum(2));3964const Point3d & p3 = Point (el.PNum(3));3965const Point3d & p4 = Point (el.PNum(4));39663967double vol = (Vec3d (p1, p2) *3968Cross (Vec3d (p1, p3), Vec3d(p1, p4)));3969if (vol > 0)3970swap (el.PNum(3), el.PNum(4));3971}3972397339743975UpdateTopology();3976timestamp = NextTimeStamp();3977}3978}39793980void Mesh :: BuildElementSearchTree ()3981{3982if (elementsearchtreets == GetTimeStamp())3983return;39843985NgLock lock(mutex);3986lock.Lock();39873988PrintMessage (4, "Rebuild element searchtree");39893990if (elementsearchtree)3991delete elementsearchtree;3992elementsearchtree = NULL;39933994Box3d box;3995int i, j;3996int ne = GetNE();3997if (!ne)3998{3999lock.UnLock();4000return;4001}40024003box.SetPoint (Point (VolumeElement(1).PNum(1)));4004for (i = 1; i <= ne; i++)4005{4006const Element & el = VolumeElement(i);4007for (j = 1; j <= el.GetNP(); j++)4008box.AddPoint (Point (el.PNum(j)));4009}40104011box.Increase (1.01 * box.CalcDiam());4012elementsearchtree = new Box3dTree (box.PMin(), box.PMax());4013401440154016for (i = 1; i <= ne; i++)4017{4018const Element & el = VolumeElement(i);4019box.SetPoint (Point (el.PNum(1)));4020for (j = 1; j <= el.GetNP(); j++)4021box.AddPoint (Point (el.PNum(j)));40224023elementsearchtree -> Insert (box.PMin(), box.PMax(), i);4024}40254026elementsearchtreets = GetTimeStamp();40274028lock.UnLock();4029}4030403140324033bool Mesh :: PointContainedIn2DElement(const Point3d & p,4034double lami[3],4035const int element,4036bool consider3D) const4037{4038static Vec3d col1, col2, col3;4039static Vec3d rhs, sol;4040const double eps = 1e-6;40414042static ARRAY<Element2d> loctrigs;404340444045//SZ4046if(SurfaceElement(element).GetType()==QUAD)4047{4048const Element2d & el = SurfaceElement(element);40494050const Point3d & p1 = Point(el.PNum(1));4051const Point3d & p2 = Point(el.PNum(2));4052const Point3d & p3 = Point(el.PNum(3));4053const Point3d & p4 = Point(el.PNum(4));40544055// Coefficients of Bilinear Mapping from Ref-Elem to global Elem4056// X = a + b x + c y + d x y4057Vec3d a = p1;4058Vec3d b = p2 - a;4059Vec3d c = p4 - a;4060Vec3d d = p3 - a - b - c;40614062double dxb = d.X()*b.Y()-d.Y()*b.X();4063double dxc = d.X()*c.Y()-d.Y()*c.X();4064double dxa = d.X()*a.Y()-d.Y()*a.X();4065double dxp = d.X()*p.Y()-d.Y()*p.X();40664067double c0,c1,c2,rt;4068lami[2]=0.;4069double eps = 1.E-12;40704071if(fabs(d.X()) <= eps && fabs(d.Y())<= eps)4072{4073//Solve Linear System4074lami[0]=(c.Y()*(p.X()-a.X())-c.X()*(p.Y()-a.Y()))/4075(b.X()*c.Y() -b.Y()*c.X());4076lami[1]=(-b.Y()*(p.X()-a.X())+b.X()*(p.Y()-a.Y()))/4077(b.X()*c.Y() -b.Y()*c.X());4078}4079else4080if(fabs(dxb) <= eps)4081{4082lami[1] = (dxp-dxa)/dxc;4083if(fabs(b.X()-d.X()*lami[1])>=eps)4084lami[0] = (p.X()-a.X() - c.X()*lami[1])/(b.X()+d.X()*lami[1]);4085else4086lami[0] = (p.Y()-a.Y() - c.Y()*lami[1])/(b.Y()+d.Y()*lami[1]);4087}4088else4089if(fabs(dxc) <= eps)4090{4091lami[0] = (dxp-dxa)/dxb;4092if(fabs(c.X()-d.X()*lami[0])>=eps)4093lami[1] = (p.X()-a.X() - b.X()*lami[0])/(c.X()+d.X()*lami[0]);4094else4095lami[1] = (p.Y()-a.Y() - b.Y()*lami[0])/(c.Y()+d.Y()*lami[0]);4096}4097else //Solve quadratic equation4098{4099if(fabs(d.X()) >= eps)4100{4101c2 = d.X()*dxc;4102c1 = d.X()*dxc - c.X()*dxb - d.X()*(dxp-dxa);4103c0 = -b.X()*(dxp -dxa) - (a.X()-p.X())*dxb;4104}4105else4106{4107c2 = d.Y()*dxc;4108c1 = d.Y()*dxc - c.Y()*dxb - d.Y()*(dxp-dxa);4109c0 = -b.Y()*(dxp -dxa) - (a.Y()-p.Y())*dxb;4110}41114112double rt = c1*c1 - 4*c2*c0;4113if (rt < 0.) return false;4114lami[1] = (-c1 + sqrt(rt))/2/c2;4115if(lami[1]<=1. && lami[1]>=0.)4116{4117lami[0] = (dxp - dxa -dxc*lami[1])/dxb;4118if(lami[0]<=1. && lami[0]>=0.)4119return true;4120}41214122lami[1] = (-c1 - sqrt(rt))/2/c2;4123lami[0] = (dxp - dxa -dxc*lami[1])/dxb;4124}41254126if( lami[0] <= 1.+eps && lami[0] >= -eps && lami[1]<=1.+eps && lami[1]>=-eps)4127{4128if(consider3D)4129{4130Vec3d n = Cross(b,c);4131lami[2] = 0;4132for(int i=1; i<=3; i++)4133lami[2] +=(p.X(i)-a.X(i)-lami[0]*b.X(i)-lami[1]*c.X(i)) * n.X(i);4134if(lami[2] >= -eps && lami[2] <= eps)4135return true;4136}4137else4138return true;4139}41404141return false;41424143}4144else4145{4146// SurfaceElement(element).GetTets (loctets);4147loctrigs.SetSize(1);4148loctrigs.Elem(1) = SurfaceElement(element);4149415041514152for (int j = 1; j <= loctrigs.Size(); j++)4153{4154const Element2d & el = loctrigs.Get(j);415541564157const Point3d & p1 = Point(el.PNum(1));4158const Point3d & p2 = Point(el.PNum(2));4159const Point3d & p3 = Point(el.PNum(3));4160/*4161Box3d box;4162box.SetPoint (p1);4163box.AddPoint (p2);4164box.AddPoint (p3);4165box.AddPoint (p4);4166if (!box.IsIn (p))4167continue;4168*/4169col1 = p2-p1;4170col2 = p3-p1;4171col3 = Cross(col1,col2);4172//col3 = Vec3d(0, 0, 1);4173rhs = p - p1;41744175int retval = SolveLinearSystem (col1, col2, col3, rhs, sol);41764177//(*testout) << "retval " << retval << endl;41784179//(*testout) << "col1 " << col1 << " col2 " << col2 << " col3 " << col3 << " rhs " << rhs << endl;4180//(*testout) << "sol " << sol << endl;41814182if (sol.X() >= -eps && sol.Y() >= -eps &&4183sol.X() + sol.Y() <= 1+eps)4184{4185if(!consider3D || (sol.Z() >= -eps && sol.Z() <= eps))4186{4187lami[0] = sol.X();4188lami[1] = sol.Y();4189lami[2] = sol.Z();41904191return true;4192}4193}4194}4195}41964197return false;41984199}42004201420242034204bool Mesh :: PointContainedIn3DElement(const Point3d & p,4205double lami[3],4206const int element) const4207{4208//bool oldresult = PointContainedIn3DElementOld(p,lami,element);4209//(*testout) << "old result: " << oldresult4210// << " lam " << lami[0] << " " << lami[1] << " " << lami[2] << endl;42114212//if(!curvedelems->IsElementCurved(element-1))4213// return PointContainedIn3DElementOld(p,lami,element);421442154216const double eps = 1.e-4;4217const Element & el = VolumeElement(element);42184219netgen::Point<3> lam;42204221if (el.GetType() == TET)4222{4223lam = 0.25;4224}4225else if (el.GetType() == PRISM)4226{4227lam(0) = 0.33; lam(1) = 0.33; lam(2) = 0.5;4228}4229else if (el.GetType() == PYRAMID)4230{4231lam(0) = 0.4; lam(1) = 0.4; lam(2) = 0.2;4232}4233else if (el.GetType() == HEX)4234{4235lam = 0.5;4236}423742384239Vec<3> deltalam,rhs;4240netgen::Point<3> x;4241Mat<3,3> Jac,Jact;42424243double delta=1;42444245bool retval;42464247int i = 0;42484249const int maxits = 30;42504251while(delta > 1e-16 && i<maxits)4252{4253curvedelems->CalcElementTransformation(lam,element-1,x,Jac);42544255rhs = p-x;4256Jac.Solve(rhs,deltalam);42574258lam += deltalam;42594260delta = deltalam.Length2();42614262i++;4263//(*testout) << "pcie i " << i << " delta " << delta << " p " << p << " x " << x << " lam " << lam << endl;4264//<< "Jac " << Jac << endl;4265}42664267if(i==maxits)4268return false;426942704271for(i=0; i<3; i++)4272lami[i] = lam(i);4273427442754276if (el.GetType() == TET)4277{4278retval = (lam(0) > -eps &&4279lam(1) > -eps &&4280lam(2) > -eps &&4281lam(0) + lam(1) + lam(2) < 1+eps);4282}4283else if (el.GetType() == PRISM)4284{4285retval = (lam(0) > -eps &&4286lam(1) > -eps &&4287lam(2) > -eps &&4288lam(2) < 1+eps &&4289lam(0) + lam(1) < 1+eps);4290}4291else if (el.GetType() == PYRAMID)4292{4293retval = (lam(0) > -eps &&4294lam(1) > -eps &&4295lam(2) > -eps &&4296lam(0) + lam(2) < 1+eps &&4297lam(1) + lam(2) < 1+eps);4298}4299else if (el.GetType() == HEX)4300{4301retval = (lam(0) > -eps && lam(0) < 1+eps &&4302lam(1) > -eps && lam(1) < 1+eps &&4303lam(2) > -eps && lam(2) < 1+eps);4304}4305else4306throw NgException("Da haun i wos vagessn");43074308return retval;4309}4310431143124313bool Mesh :: PointContainedIn3DElementOld(const Point3d & p,4314double lami[3],4315const int element) const4316{43174318static Vec3d col1, col2, col3;4319static Vec3d rhs, sol;4320const double eps = 1.e-4;43214322static ARRAY<Element> loctets;43234324VolumeElement(element).GetTets (loctets);43254326for (int j = 1; j <= loctets.Size(); j++)4327{4328const Element & el = loctets.Get(j);43294330const Point3d & p1 = Point(el.PNum(1));4331const Point3d & p2 = Point(el.PNum(2));4332const Point3d & p3 = Point(el.PNum(3));4333const Point3d & p4 = Point(el.PNum(4));43344335Box3d box;4336box.SetPoint (p1);4337box.AddPoint (p2);4338box.AddPoint (p3);4339box.AddPoint (p4);4340if (!box.IsIn (p))4341continue;43424343col1 = p2-p1;4344col2 = p3-p1;4345col3 = p4-p1;4346rhs = p - p1;43474348SolveLinearSystem (col1, col2, col3, rhs, sol);43494350if (sol.X() >= -eps && sol.Y() >= -eps && sol.Z() >= -eps &&4351sol.X() + sol.Y() + sol.Z() <= 1+eps)4352{4353ARRAY<Element> loctetsloc;4354ARRAY<netgen::Point<3> > pointsloc;43554356VolumeElement(element).GetTetsLocal (loctetsloc);4357VolumeElement(element).GetNodesLocalNew (pointsloc);43584359const Element & le = loctetsloc.Get(j);436043614362Point3d pp =4363pointsloc.Get(le.PNum(1))4364+ sol.X() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(2)))4365+ sol.Y() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(3)))4366+ sol.Z() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(4))) ;43674368lami[0] = pp.X();4369lami[1] = pp.Y();4370lami[2] = pp.Z();4371return true;4372}4373}4374return false;4375}437643774378int Mesh :: GetElementOfPoint (const Point3d & p,4379double lami[3],4380bool build_searchtree,4381const int index,4382const bool allowindex) const4383{4384if(index != -1)4385{4386ARRAY<int> dummy(1);4387dummy[0] = index;4388return GetElementOfPoint(p,lami,&dummy,build_searchtree,allowindex);4389}4390else4391return GetElementOfPoint(p,lami,NULL,build_searchtree,allowindex);4392}43934394439543964397int Mesh :: GetElementOfPoint (const Point3d & p,4398double lami[3],4399const ARRAY<int> * const indices,4400bool build_searchtree,4401const bool allowindex) const4402{4403if (dimension == 2)4404{4405int i, j;4406int ne;440744084409if(ps_startelement != 0 && ps_startelement <= GetNSE() && PointContainedIn2DElement(p,lami,ps_startelement))4410return ps_startelement;44114412ARRAY<int> locels;4413if (0)4414{4415elementsearchtree->GetIntersecting (p, p, locels);4416ne = locels.Size();4417}4418else4419ne = GetNSE();44204421for (i = 1; i <= ne; i++)4422{4423int ii;44244425if (0)4426ii = locels.Get(i);4427else4428ii = i;44294430if(ii == ps_startelement) continue;44314432if(indices != NULL && indices->Size() > 0)4433{4434bool contained = indices->Contains(SurfaceElement(ii).GetIndex());4435if((allowindex && !contained) || (!allowindex && contained)) continue;4436}44374438if(PointContainedIn2DElement(p,lami,ii)) return ii;44394440}4441return 0;4442}4443else44444445{4446int i, j;4447int ne;44484449if(ps_startelement != 0 && PointContainedIn3DElement(p,lami,ps_startelement))4450return ps_startelement;44514452ARRAY<int> locels;4453if (elementsearchtree || build_searchtree)4454{4455// update if necessary:4456const_cast<Mesh&>(*this).BuildElementSearchTree ();4457elementsearchtree->GetIntersecting (p, p, locels);4458ne = locels.Size();4459}4460else4461ne = GetNE();44624463for (i = 1; i <= ne; i++)4464{4465int ii;44664467if (elementsearchtree)4468ii = locels.Get(i);4469else4470ii = i;44714472if(ii == ps_startelement) continue;44734474if(indices != NULL && indices->Size() > 0)4475{4476bool contained = indices->Contains(VolumeElement(ii).GetIndex());4477if((allowindex && !contained) || (!allowindex && contained)) continue;4478}447944804481if(PointContainedIn3DElement(p,lami,ii))4482{4483ps_startelement = ii;4484return ii;4485}4486}44874488// Not found, try uncurved variant:4489for (i = 1; i <= ne; i++)4490{4491int ii;44924493if (elementsearchtree)4494ii = locels.Get(i);4495else4496ii = i;44974498if(indices != NULL && indices->Size() > 0)4499{4500bool contained = indices->Contains(VolumeElement(ii).GetIndex());4501if((allowindex && !contained) || (!allowindex && contained)) continue;4502}450345044505if(PointContainedIn3DElementOld(p,lami,ii))4506{4507ps_startelement = ii;4508(*testout) << "WARNING: found element of point " << p <<" only for uncurved mesh" << endl;4509return ii;4510}4511}451245134514return 0;4515}4516}4517451845194520int Mesh :: GetSurfaceElementOfPoint (const Point3d & p,4521double lami[3],4522bool build_searchtree,4523const int index,4524const bool allowindex) const4525{4526if(index != -1)4527{4528ARRAY<int> dummy(1);4529dummy[0] = index;4530return GetSurfaceElementOfPoint(p,lami,&dummy,build_searchtree,allowindex);4531}4532else4533return GetSurfaceElementOfPoint(p,lami,NULL,build_searchtree,allowindex);4534}45354536453745384539int Mesh :: GetSurfaceElementOfPoint (const Point3d & p,4540double lami[3],4541const ARRAY<int> * const indices,4542bool build_searchtree,4543const bool allowindex) const4544{4545if (dimension == 2)4546{4547throw NgException("GetSurfaceElementOfPoint not yet implemented for 2D meshes");4548}4549else4550{4551double vlam[3];4552int velement = GetElementOfPoint(p,vlam,NULL,build_searchtree,allowindex);45534554//(*testout) << "p " << p << endl;4555//(*testout) << "velement " << velement << endl;45564557ARRAY<int> faces;4558topology->GetElementFaces(velement,faces);45594560//(*testout) << "faces " << faces << endl;45614562for(int i=0; i<faces.Size(); i++)4563faces[i] = topology->GetFace2SurfaceElement(faces[i]);45644565//(*testout) << "surfel " << faces << endl;45664567for(int i=0; i<faces.Size(); i++)4568{4569if(faces[i] == 0)4570continue;45714572if(indices && indices->Size() != 0)4573{4574if(indices->Contains(SurfaceElement(faces[i]).GetIndex()) &&4575PointContainedIn2DElement(p,lami,faces[i],true))4576return faces[i];4577}4578else4579{4580if(PointContainedIn2DElement(p,lami,faces[i],true))4581{4582//(*testout) << "found point " << p << " in sel " << faces[i]4583// << ", lam " << lami[0] << ", " << lami[1] << ", " << lami[2] << endl;4584return faces[i];4585}4586}4587}45884589}45904591return 0;4592}459345944595void Mesh::GetIntersectingVolEls(const Point3d& p1, const Point3d& p2,4596ARRAY<int> & locels) const4597{4598elementsearchtree->GetIntersecting (p1, p2, locels);4599}46004601void Mesh :: SplitIntoParts()4602{4603int i, j, dom;4604int ne = GetNE();4605int np = GetNP();4606int nse = GetNSE();46074608BitArray surfused(nse);4609BitArray pused (np);46104611surfused.Clear();46124613dom = 0;46144615while (1)4616{4617int cntd = 1;46184619dom++;46204621pused.Clear();46224623int found = 0;4624for (i = 1; i <= nse; i++)4625if (!surfused.Test(i))4626{4627SurfaceElement(i).SetIndex (dom);4628for (j = 1; j <= 3; j++)4629pused.Set (SurfaceElement(i).PNum(j));4630found = 1;4631cntd = 1;4632surfused.Set(i);4633break;4634}46354636if (!found)4637break;46384639int change;4640do4641{4642change = 0;4643for (i = 1; i <= nse; i++)4644{4645int is = 0, isnot = 0;4646for (j = 1; j <= 3; j++)4647if (pused.Test(SurfaceElement(i).PNum(j)))4648is = 1;4649else4650isnot = 1;46514652if (is && isnot)4653{4654change = 1;4655for (j = 1; j <= 3; j++)4656pused.Set (SurfaceElement(i).PNum(j));4657}46584659if (is)4660{4661if (!surfused.Test(i))4662{4663surfused.Set(i);4664SurfaceElement(i).SetIndex (dom);4665cntd++;4666}4667}4668}466946704671for (i = 1; i <= ne; i++)4672{4673int is = 0, isnot = 0;4674for (j = 1; j <= 4; j++)4675if (pused.Test(VolumeElement(i).PNum(j)))4676is = 1;4677else4678isnot = 1;46794680if (is && isnot)4681{4682change = 1;4683for (j = 1; j <= 4; j++)4684pused.Set (VolumeElement(i).PNum(j));4685}46864687if (is)4688{4689VolumeElement(i).SetIndex (dom);4690}4691}4692}4693while (change);46944695PrintMessage (3, "domain ", dom, " has ", cntd, " surfaceelements");4696}46974698/*4699facedecoding.SetSize (dom);4700for (i = 1; i <= dom; i++)4701{4702facedecoding.Elem(i).surfnr = 0;4703facedecoding.Elem(i).domin = i;4704facedecoding.Elem(i).domout = 0;4705}4706*/4707ClearFaceDescriptors();4708for (i = 1; i <= dom; i++)4709AddFaceDescriptor (FaceDescriptor (0, i, 0, 0));4710CalcSurfacesOfNode();4711timestamp = NextTimeStamp();4712}47134714void Mesh :: SplitSeparatedFaces ()4715{4716PrintMessage (3, "SplitSeparateFaces");4717int fdi;4718int np = GetNP();47194720BitArray usedp(np);4721ARRAY<SurfaceElementIndex> els_of_face;47224723fdi = 1;4724while (fdi <= GetNFD())4725{4726GetSurfaceElementsOfFace (fdi, els_of_face);47274728if (els_of_face.Size() == 0) continue;47294730SurfaceElementIndex firstel = els_of_face[0];47314732usedp.Clear();4733for (int j = 1; j <= SurfaceElement(firstel).GetNP(); j++)4734usedp.Set (SurfaceElement(firstel).PNum(j));47354736bool changed;4737do4738{4739changed = false;47404741for (int i = 0; i < els_of_face.Size(); i++)4742{4743const Element2d & el = SurfaceElement(els_of_face[i]);47444745bool has = 0;4746bool hasno = 0;4747for (int j = 0; j < el.GetNP(); j++)4748{4749if (usedp.Test(el[j]))4750has = true;4751else4752hasno = true;4753}47544755if (has && hasno)4756changed = true;47574758if (has)4759for (int j = 0; j < el.GetNP(); j++)4760usedp.Set (el[j]);4761}4762}4763while (changed);47644765int nface = 0;4766for (int i = 0; i < els_of_face.Size(); i++)4767{4768Element2d & el = SurfaceElement(els_of_face[i]);47694770int hasno = 0;4771for (int j = 1; j <= el.GetNP(); j++)4772if (!usedp.Test(el.PNum(j)))4773hasno = 1;47744775if (hasno)4776{4777if (!nface)4778{4779FaceDescriptor nfd = GetFaceDescriptor(fdi);4780nface = AddFaceDescriptor (nfd);4781}47824783el.SetIndex (nface);4784}4785}47864787// reconnect list4788if (nface)4789{4790facedecoding[nface-1].firstelement = -1;4791facedecoding[fdi-1].firstelement = -1;47924793for (int i = 0; i < els_of_face.Size(); i++)4794{4795int ind = SurfaceElement(els_of_face[i]).GetIndex();4796SurfaceElement(els_of_face[i]).next = facedecoding[ind-1].firstelement;4797facedecoding[ind-1].firstelement = els_of_face[i];4798}4799}48004801fdi++;4802}480348044805/*4806fdi = 1;4807while (fdi <= GetNFD())4808{4809int firstel = 0;4810for (int i = 1; i <= GetNSE(); i++)4811if (SurfaceElement(i).GetIndex() == fdi)4812{4813firstel = i;4814break;4815}4816if (!firstel) continue;48174818usedp.Clear();4819for (int j = 1; j <= SurfaceElement(firstel).GetNP(); j++)4820usedp.Set (SurfaceElement(firstel).PNum(j));48214822int changed;4823do4824{4825changed = 0;4826for (int i = 1; i <= GetNSE(); i++)4827{4828const Element2d & el = SurfaceElement(i);4829if (el.GetIndex() != fdi)4830continue;48314832int has = 0;4833int hasno = 0;4834for (int j = 1; j <= el.GetNP(); j++)4835{4836if (usedp.Test(el.PNum(j)))4837has = 1;4838else4839hasno = 1;4840}4841if (has && hasno)4842changed = 1;48434844if (has)4845for (int j = 1; j <= el.GetNP(); j++)4846usedp.Set (el.PNum(j));4847}4848}4849while (changed);48504851int nface = 0;4852for (int i = 1; i <= GetNSE(); i++)4853{4854Element2d & el = SurfaceElement(i);4855if (el.GetIndex() != fdi)4856continue;48574858int hasno = 0;4859for (int j = 1; j <= el.GetNP(); j++)4860{4861if (!usedp.Test(el.PNum(j)))4862hasno = 1;4863}48644865if (hasno)4866{4867if (!nface)4868{4869FaceDescriptor nfd = GetFaceDescriptor(fdi);4870nface = AddFaceDescriptor (nfd);4871}48724873el.SetIndex (nface);4874}4875}4876fdi++;4877}4878*/4879}488048814882void Mesh :: GetSurfaceElementsOfFace (int facenr, ARRAY<SurfaceElementIndex> & sei) const4883{4884static int timer = NgProfiler::CreateTimer ("GetSurfaceElementsOfFace");4885NgProfiler::RegionTimer reg (timer);48864887/*4888sei.SetSize (0);4889for (SurfaceElementIndex i = 0; i < GetNSE(); i++)4890if ( (*this)[i].GetIndex () == facenr && (*this)[i][0] >= PointIndex::BASE &&4891!(*this)[i].IsDeleted() )4892sei.Append (i);48934894int size1 = sei.Size();4895*/48964897sei.SetSize(0);48984899SurfaceElementIndex si = facedecoding[facenr-1].firstelement;4900while (si != -1)4901{4902if ( (*this)[si].GetIndex () == facenr && (*this)[si][0] >= PointIndex::BASE &&4903!(*this)[si].IsDeleted() )4904{4905sei.Append (si);4906}49074908si = (*this)[si].next;4909}49104911/*4912// *testout << "with list = " << endl << sei << endl;49134914if (size1 != sei.Size())4915{4916cout << "size mismatch" << endl;4917exit(1);4918}4919*/4920}49214922492349244925void Mesh :: CalcMinMaxAngle (double badellimit, double * retvalues)4926{4927int i, j;4928int lpi1, lpi2, lpi3, lpi4;4929double phimax = 0, phimin = 10;4930double facephimax = 0, facephimin = 10;4931int illegaltets = 0, negativetets = 0, badtets = 0;49324933for (i = 1; i <= GetNE(); i++)4934{4935int badel = 0;49364937Element & el = VolumeElement(i);49384939if (el.GetType() != TET)4940{4941VolumeElement(i).flags.badel = 0;4942continue;4943}49444945if (el.Volume(Points()) < 0)4946{4947badel = 1;4948negativetets++;4949}495049514952if (!LegalTet (el))4953{4954badel = 1;4955illegaltets++;4956(*testout) << "illegal tet: " << i << " ";4957for (j = 1; j <= el.GetNP(); j++)4958(*testout) << el.PNum(j) << " ";4959(*testout) << endl;4960}496149624963// angles between faces4964for (lpi1 = 1; lpi1 <= 3; lpi1++)4965for (lpi2 = lpi1+1; lpi2 <= 4; lpi2++)4966{4967lpi3 = 1;4968while (lpi3 == lpi1 || lpi3 == lpi2)4969lpi3++;4970lpi4 = 10 - lpi1 - lpi2 - lpi3;49714972const Point3d & p1 = Point (el.PNum(lpi1));4973const Point3d & p2 = Point (el.PNum(lpi2));4974const Point3d & p3 = Point (el.PNum(lpi3));4975const Point3d & p4 = Point (el.PNum(lpi4));49764977Vec3d n(p1, p2);4978n /= n.Length();4979Vec3d v1(p1, p3);4980Vec3d v2(p1, p4);49814982v1 -= (n * v1) * n;4983v2 -= (n * v2) * n;49844985double cosphi = (v1 * v2) / (v1.Length() * v2.Length());4986double phi = acos (cosphi);4987if (phi > phimax) phimax = phi;4988if (phi < phimin) phimin = phi;49894990if ((180/M_PI) * phi > badellimit)4991badel = 1;4992}499349944995// angles in faces4996for (j = 1; j <= 4; j++)4997{4998Element2d face;4999el.GetFace (j, face);5000for (lpi1 = 1; lpi1 <= 3; lpi1++)5001{5002lpi2 = lpi1 % 3 + 1;5003lpi3 = lpi2 % 3 + 1;50045005const Point3d & p1 = Point (el.PNum(lpi1));5006const Point3d & p2 = Point (el.PNum(lpi2));5007const Point3d & p3 = Point (el.PNum(lpi3));50085009Vec3d v1(p1, p2);5010Vec3d v2(p1, p3);5011double cosphi = (v1 * v2) / (v1.Length() * v2.Length());5012double phi = acos (cosphi);5013if (phi > facephimax) facephimax = phi;5014if (phi < facephimin) facephimin = phi;50155016if ((180/M_PI) * phi > badellimit)5017badel = 1;50185019}5020}502150225023VolumeElement(i).flags.badel = badel;5024if (badel) badtets++;5025}50265027if (!GetNE())5028{5029phimin = phimax = facephimin = facephimax = 0;5030}50315032if (!retvalues)5033{5034PrintMessage (1, "");5035PrintMessage (1, "between planes: phimin = ", (180/M_PI) * phimin,5036" phimax = ", (180/M_PI) *phimax);5037PrintMessage (1, "inside planes: phimin = ", (180/M_PI) * facephimin,5038" phimax = ", (180/M_PI) * facephimax);5039PrintMessage (1, "");5040}5041else5042{5043retvalues[0] = (180/M_PI) * facephimin;5044retvalues[1] = (180/M_PI) * facephimax;5045retvalues[2] = (180/M_PI) * phimin;5046retvalues[3] = (180/M_PI) * phimax;5047}5048PrintMessage (3, "negative tets: ", negativetets);5049PrintMessage (3, "illegal tets: ", illegaltets);5050PrintMessage (3, "bad tets: ", badtets);5051}505250535054int Mesh :: MarkIllegalElements ()5055{5056int cnt = 0;5057int i;50585059for (i = 1; i <= GetNE(); i++)5060{5061LegalTet (VolumeElement(i));50625063/*5064Element & el = VolumeElement(i);5065int leg1 = LegalTet (el);5066el.flags.illegal_valid = 0;5067int leg2 = LegalTet (el);50685069if (leg1 != leg2)5070{5071cerr << "legal differs!!" << endl;5072(*testout) << "legal differs" << endl;5073(*testout) << "elnr = " << i << ", el = " << el5074<< " leg1 = " << leg1 << ", leg2 = " << leg2 << endl;5075}50765077// el.flags.illegal = !LegalTet (el);5078*/5079cnt += VolumeElement(i).Illegal();5080}5081return cnt;5082}50835084// #ifdef NONE5085// void Mesh :: AddIdentification (int pi1, int pi2, int identnr)5086// {5087// INDEX_2 pair(pi1, pi2);5088// // pair.Sort();5089// identifiedpoints->Set (pair, identnr);5090// if (identnr > maxidentnr)5091// maxidentnr = identnr;5092// timestamp = NextTimeStamp();5093// }50945095// int Mesh :: GetIdentification (int pi1, int pi2) const5096// {5097// INDEX_2 pair(pi1, pi2);5098// if (identifiedpoints->Used (pair))5099// return identifiedpoints->Get(pair);5100// else5101// return 0;5102// }51035104// int Mesh :: GetIdentificationSym (int pi1, int pi2) const5105// {5106// INDEX_2 pair(pi1, pi2);5107// if (identifiedpoints->Used (pair))5108// return identifiedpoints->Get(pair);51095110// pair = INDEX_2 (pi2, pi1);5111// if (identifiedpoints->Used (pair))5112// return identifiedpoints->Get(pair);51135114// return 0;5115// }511651175118// void Mesh :: GetIdentificationMap (int identnr, ARRAY<int> & identmap) const5119// {5120// int i, j;51215122// identmap.SetSize (GetNP());5123// for (i = 1; i <= identmap.Size(); i++)5124// identmap.Elem(i) = 0;51255126// for (i = 1; i <= identifiedpoints->GetNBags(); i++)5127// for (j = 1; j <= identifiedpoints->GetBagSize(i); j++)5128// {5129// INDEX_2 i2;5130// int nr;5131// identifiedpoints->GetData (i, j, i2, nr);51325133// if (nr == identnr)5134// {5135// identmap.Elem(i2.I1()) = i2.I2();5136// }5137// }5138// }513951405141// void Mesh :: GetIdentificationPairs (int identnr, ARRAY<INDEX_2> & identpairs) const5142// {5143// int i, j;51445145// identpairs.SetSize(0);51465147// for (i = 1; i <= identifiedpoints->GetNBags(); i++)5148// for (j = 1; j <= identifiedpoints->GetBagSize(i); j++)5149// {5150// INDEX_2 i2;5151// int nr;5152// identifiedpoints->GetData (i, j, i2, nr);51535154// if (identnr == 0 || nr == identnr)5155// identpairs.Append (i2);5156// }5157// }5158// #endif5159516051615162void Mesh :: InitPointCurve(double red, double green, double blue) const5163{5164pointcurves_startpoint.Append(pointcurves.Size());5165pointcurves_red.Append(red);5166pointcurves_green.Append(green);5167pointcurves_blue.Append(blue);5168}5169void Mesh :: AddPointCurvePoint(const Point3d & pt) const5170{5171pointcurves.Append(pt);5172}5173int Mesh :: GetNumPointCurves(void) const5174{5175return pointcurves_startpoint.Size();5176}5177int Mesh :: GetNumPointsOfPointCurve(int curve) const5178{5179if(curve == pointcurves_startpoint.Size()-1)5180return (pointcurves.Size() - pointcurves_startpoint.Last());5181else5182return (pointcurves_startpoint[curve+1]-pointcurves_startpoint[curve]);5183}51845185Point3d & Mesh :: GetPointCurvePoint(int curve, int n) const5186{5187return pointcurves[pointcurves_startpoint[curve]+n];5188}51895190void Mesh :: GetPointCurveColor(int curve, double & red, double & green, double & blue) const5191{5192red = pointcurves_red[curve];5193green = pointcurves_green[curve];5194blue = pointcurves_blue[curve];5195}519651975198void Mesh :: ComputeNVertices ()5199{5200int i, j, nv;5201int ne = GetNE();5202int nse = GetNSE();52035204numvertices = 0;5205for (i = 1; i <= ne; i++)5206{5207const Element & el = VolumeElement(i);5208nv = el.GetNV();5209for (j = 0; j < nv; j++)5210if (el[j] > numvertices)5211numvertices = el[j];5212}5213for (i = 1; i <= nse; i++)5214{5215const Element2d & el = SurfaceElement(i);5216nv = el.GetNV();5217for (j = 1; j <= nv; j++)5218if (el.PNum(j) > numvertices)5219numvertices = el.PNum(j);5220}52215222numvertices += 1- PointIndex::BASE;5223}52245225int Mesh :: GetNV () const5226{5227if (numvertices < 0)5228return GetNP();5229else5230return numvertices;5231}52325233void Mesh :: SetNP (int np)5234{5235points.SetSize(np);5236// ptyps.SetSize(np);52375238int mlold = mlbetweennodes.Size();5239mlbetweennodes.SetSize(np);5240if (np > mlold)5241for (int i = mlold+PointIndex::BASE;5242i < np+PointIndex::BASE; i++)5243{5244mlbetweennodes[i].I1() = PointIndex::BASE-1;5245mlbetweennodes[i].I2() = PointIndex::BASE-1;5246}52475248GetIdentifications().SetMaxPointNr (np + PointIndex::BASE-1);5249}525052515252/*5253void Mesh :: BuildConnectedNodes ()5254{5255if (PureTetMesh())5256{5257connectedtonode.SetSize(0);5258return;5259}526052615262int i, j, k;5263int np = GetNP();5264int ne = GetNE();5265TABLE<int> conto(np);5266for (i = 1; i <= ne; i++)5267{5268const Element & el = VolumeElement(i);52695270if (el.GetType() == PRISM)5271{5272for (j = 1; j <= 6; j++)5273{5274int n1 = el.PNum (j);5275int n2 = el.PNum ((j+2)%6+1);5276// if (n1 != n2)5277{5278int found = 0;5279for (k = 1; k <= conto.EntrySize(n1); k++)5280if (conto.Get(n1, k) == n2)5281{5282found = 1;5283break;5284}5285if (!found)5286conto.Add (n1, n2);5287}5288}5289}5290else if (el.GetType() == PYRAMID)5291{5292for (j = 1; j <= 4; j++)5293{5294int n1, n2;5295switch (j)5296{5297case 1: n1 = 1; n2 = 4; break;5298case 2: n1 = 4; n2 = 1; break;5299case 3: n1 = 2; n2 = 3; break;5300case 4: n1 = 3; n2 = 2; break;5301}53025303int found = 0;5304for (k = 1; k <= conto.EntrySize(n1); k++)5305if (conto.Get(n1, k) == n2)5306{5307found = 1;5308break;5309}5310if (!found)5311conto.Add (n1, n2);5312}5313}5314}53155316connectedtonode.SetSize(np);5317for (i = 1; i <= np; i++)5318connectedtonode.Elem(i) = 0;53195320for (i = 1; i <= np; i++)5321if (connectedtonode.Elem(i) == 0)5322{5323connectedtonode.Elem(i) = i;5324ConnectToNodeRec (i, i, conto);5325}5326532753285329}53305331void Mesh :: ConnectToNodeRec (int node, int tonode,5332const TABLE<int> & conto)5333{5334int i, n2;5335// (*testout) << "connect " << node << " to " << tonode << endl;5336for (i = 1; i <= conto.EntrySize(node); i++)5337{5338n2 = conto.Get(node, i);5339if (!connectedtonode.Get(n2))5340{5341connectedtonode.Elem(n2) = tonode;5342ConnectToNodeRec (n2, tonode, conto);5343}5344}5345}5346*/534753485349bool Mesh :: PureTrigMesh (int faceindex) const5350{5351if (!faceindex)5352return !mparam.quad;53535354int i;5355for (i = 1; i <= GetNSE(); i++)5356if (SurfaceElement(i).GetIndex() == faceindex &&5357SurfaceElement(i).GetNP() != 3)5358return 0;5359return 1;5360}53615362bool Mesh :: PureTetMesh () const5363{5364for (ElementIndex ei = 0; ei < GetNE(); ei++)5365if (VolumeElement(ei).GetNP() != 4)5366return 0;5367return 1;5368}53695370void Mesh :: UpdateTopology()5371{5372topology->Update();5373clusters->Update();5374}537553765377void Mesh :: SetMaterial (int domnr, const char * mat)5378{5379if (domnr > materials.Size())5380{5381int olds = materials.Size();5382materials.SetSize (domnr);5383for (int i = olds; i < domnr; i++)5384materials[i] = 0;5385}5386materials.Elem(domnr) = new char[strlen(mat)+1];5387strcpy (materials.Elem(domnr), mat);5388}53895390const char * Mesh :: GetMaterial (int domnr) const5391{5392if (domnr <= materials.Size())5393return materials.Get(domnr);5394return 0;5395}53965397void Mesh ::SetNBCNames ( int nbcn )5398{5399if ( bcnames.Size() )5400for ( int i = 0; i < bcnames.Size(); i++)5401if ( bcnames[i] ) delete bcnames[i];5402bcnames.SetSize(nbcn);5403bcnames = 0;5404}54055406void Mesh ::SetBCName ( int bcnr, const string & abcname )5407{5408if ( bcnames[bcnr] ) delete bcnames[bcnr];5409if ( abcname != "default" )5410bcnames[bcnr] = new string ( abcname );5411else5412bcnames[bcnr] = 0;5413}54145415string Mesh ::GetBCName ( int bcnr ) const5416{5417if ( !bcnames.Size() )5418return "default";5419if ( bcnames[bcnr] )5420return *bcnames[bcnr];5421else5422return "default";5423}54245425void Mesh :: SetUserData(const char * id, ARRAY<int> & data)5426{5427if(userdata_int.Used(id))5428delete userdata_int.Get(id);54295430ARRAY<int> * newdata = new ARRAY<int>(data);54315432userdata_int.Set(id,newdata);5433}5434bool Mesh :: GetUserData(const char * id, ARRAY<int> & data, int shift) const5435{5436if(userdata_int.Used(id))5437{5438if(data.Size() < (*userdata_int.Get(id)).Size()+shift)5439data.SetSize((*userdata_int.Get(id)).Size()+shift);5440for(int i=0; i<(*userdata_int.Get(id)).Size(); i++)5441data[i+shift] = (*userdata_int.Get(id))[i];5442return true;5443}5444else5445{5446data.SetSize(0);5447return false;5448}5449}5450void Mesh :: SetUserData(const char * id, ARRAY<double> & data)5451{5452if(userdata_double.Used(id))5453delete userdata_double.Get(id);54545455ARRAY<double> * newdata = new ARRAY<double>(data);54565457userdata_double.Set(id,newdata);5458}5459bool Mesh :: GetUserData(const char * id, ARRAY<double> & data, int shift) const5460{5461if(userdata_double.Used(id))5462{5463if(data.Size() < (*userdata_double.Get(id)).Size()+shift)5464data.SetSize((*userdata_double.Get(id)).Size()+shift);5465for(int i=0; i<(*userdata_double.Get(id)).Size(); i++)5466data[i+shift] = (*userdata_double.Get(id))[i];5467return true;5468}5469else5470{5471data.SetSize(0);5472return false;5473}5474}5475547654775478void Mesh :: PrintMemInfo (ostream & ost) const5479{5480ost << "Mesh Mem:" << endl;54815482ost << GetNP() << " Points, of size "5483<< sizeof (Point3d) << " + " << sizeof(POINTTYPE) << " = "5484<< GetNP() * (sizeof (Point3d) + sizeof(POINTTYPE)) << endl;54855486ost << GetNSE() << " Surface elements, of size "5487<< sizeof (Element2d) << " = "5488<< GetNSE() * sizeof(Element2d) << endl;54895490ost << GetNE() << " Volume elements, of size "5491<< sizeof (Element) << " = "5492<< GetNE() * sizeof(Element) << endl;54935494ost << "surfs on node:";5495surfacesonnode.PrintMemInfo (cout);54965497ost << "boundaryedges: ";5498if (boundaryedges)5499boundaryedges->PrintMemInfo (cout);55005501ost << "surfelementht: ";5502if (surfelementht)5503surfelementht->PrintMemInfo (cout);5504}5505}550655075508