Path: blob/devel/ElmerGUI/netgen/libsrc/stlgeom/stlgeom.cpp
3206 views
#include <mystdlib.h>12#include <myadt.hpp>3#include <linalg.hpp>4#include <gprim.hpp>56#include <meshing.hpp>78#include "stlgeom.hpp"91011namespace netgen12{1314//globalen searchtree fuer gesamte geometry aktivieren15int geomsearchtreeon = 0;1617int usechartnormal = 1;1819//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++2021void STLMeshing (STLGeometry & geom,22Mesh & mesh)23{24geom.Clear();25geom.BuildEdges();26geom.MakeAtlas(mesh);27geom.CalcFaceNums();28geom.AddFaceEdges();29geom.LinkEdges();3031mesh.ClearFaceDescriptors();32for (int i = 1; i <= geom.GetNOFaces(); i++)33mesh.AddFaceDescriptor (FaceDescriptor (i, 1, 0, 0));34}3536//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++37//+++++++++++++++++++ STL GEOMETRY ++++++++++++++++++++++++++++38//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++394041STLGeometry :: STLGeometry()42: edges(), edgesperpoint(),43normals(), externaledges(),44atlas(), chartmark(),45lines(), outerchartspertrig(), vicinity(), markedtrigs(), markedsegs(),46lineendpoints(), spiralpoints(), selectedmultiedge()47{48edgedata = new STLEdgeDataList(*this);49externaledges.SetSize(0);50Clear();51meshchart = 0; // initialize all ?? JS5253if (geomsearchtreeon)54searchtree = new Box3dTree (GetBoundingBox().PMin() - Vec3d(1,1,1),55GetBoundingBox().PMax() + Vec3d(1,1,1));56else57searchtree = NULL;5859status = STL_GOOD;60statustext = "Good Geometry";61smoothedges = NULL;62}6364STLGeometry :: ~STLGeometry()65{66delete edgedata;67}6869void STLGeometry :: STLInfo(double* data)70{71data[0] = GetNT();7273Box<3> b = GetBoundingBox();74data[1] = b.PMin()(0);75data[2] = b.PMax()(0);76data[3] = b.PMin()(1);77data[4] = b.PMax()(1);78data[5] = b.PMin()(2);79data[6] = b.PMax()(2);8081int i;8283int cons = 1;84for (i = 1; i <= GetNT(); i++)85{86if (NONeighbourTrigs(i) != 3) {cons = 0;}87}88data[7] = cons;89}9091void STLGeometry :: MarkNonSmoothNormals()92{9394PrintFnStart("Mark Non-Smooth Normals");9596int i,j;9798markedtrigs.SetSize(GetNT());99100for (i = 1; i <= GetNT(); i++)101{102SetMarkedTrig(i, 0);103}104105double dirtyangle = stlparam.yangle/180.*M_PI;106107int cnt = 0;108int lp1,lp2;109for (i = 1; i <= GetNT(); i++)110{111for (j = 1; j <= NONeighbourTrigs(i); j++)112{113if (GetAngle(i, NeighbourTrig(i,j)) > dirtyangle)114{115GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)), lp1, lp2);116if (!IsEdge(lp1,lp2))117{118if (!IsMarkedTrig(i)) {SetMarkedTrig(i,1); cnt++;}119}120}121}122}123124PrintMessage(5,"marked ",cnt," non-smooth trig-normals");125126}127128void STLGeometry :: SmoothNormals()129{130multithread.terminate = 0;131132// UseExternalEdges();133134BuildEdges();135136137DenseMatrix m(3), hm(3);138Vector rhs(3), sol(3), hv(3), hv2(3);139140Vec<3> ri;141142double wnb = stldoctor.smoothnormalsweight; // neigbour normal weight143double wgeom = 1-wnb; // geometry normal weight144145146// minimize147// wgeom sum_T \sum ri \| ri^T (n - n_geom) \|^2148// + wnb sum_SE \| ri x (n - n_nb) \|^2149150int i, j, k, l;151int nt = GetNT();152153PushStatusF("Smooth Normals");154155//int testmode;156157for (i = 1; i <= nt; i++)158{159160SetThreadPercent( 100.0 * (double)i / (double)nt);161162const STLTriangle & trig = GetTriangle (i);163164m = 0;165rhs = 0;166167// normal of geometry:168Vec<3> ngeom = trig.GeomNormal(points);169ngeom.Normalize();170171for (j = 1; j <= 3; j++)172{173int pi1 = trig.PNumMod (j);174int pi2 = trig.PNumMod (j+1);175176// edge vector177ri = GetPoint (pi2) - GetPoint (pi1);178179for (k = 0; k < 3; k++)180for (l = 0; l < 3; l++)181hm.Elem(k+1, l+1) = wgeom * ri(k) * ri(l);182183184for (k = 0; k < 3; k++)185hv.Elem(k+1) = ngeom(k);186187hm.Mult (hv, hv2);188/*189if (testmode)190(*testout) << "add vec " << hv2 << endl191<< " add m " << hm << endl;192*/193rhs.Add (1, hv2);194m += hm;195196197int nbt = 0;198int fp1,fp2;199for (k = 1; k <= NONeighbourTrigs(i); k++)200{201trig.GetNeighbourPoints(GetTriangle(NeighbourTrig(i, k)),fp1,fp2);202if (fp1 == pi1 && fp2 == pi2)203{204nbt = NeighbourTrig(i, k);205}206}207208if (!nbt)209{210cerr << "ERROR: stlgeom::Smoothnormals, nbt = 0" << endl;211}212213// smoothed normal214Vec<3> nnb = GetTriangle(nbt).Normal(); // neighbour normal215nnb.Normalize();216217if (!IsEdge(pi1,pi2))218{219double lr2 = ri * ri;220for (k = 0; k < 3; k++)221{222for (l = 0; l < k; l++)223{224hm.Elem(k+1, l+1) = -wnb * ri(k) * ri(l);225hm.Elem(l+1, k+1) = -wnb * ri(k) * ri(l);226}227228hm.Elem(k+1, k+1) = wnb * (lr2 - ri(k) * ri(k));229}230231for (k = 0; k < 3; k++)232hv.Elem(k+1) = nnb(k);233234hm.Mult (hv, hv2);235/*236if (testmode)237(*testout) << "add nb vec " << hv2 << endl238<< " add nb m " << hm << endl;239*/240241rhs.Add (1, hv2);242m += hm;243}244}245246m.Solve (rhs, sol);247Vec3d newn(sol.Get(1), sol.Get(2), sol.Get(3));248newn /= (newn.Length() + 1e-24);249250GetTriangle(i).SetNormal(newn);251// setnormal (sol);252}253254/*255for (i = 1; i <= nt; i++)256SetMarkedTrig(i, 0);257258259260int crloop;261for (crloop = 1; crloop <= 3; crloop++)262{263264// find critical:265266ARRAY<INDEX_2> critpairs;267for (i = 1; i <= nt; i++)268{269const STLTriangle & trig = GetTriangle (i);270271Vec3d ngeom = GetTriangleNormal (i); // trig.Normal(points);272ngeom /= (ngeom.Length() + 1e-24);273274for (j = 1; j <= 3; j++)275{276int pi1 = trig.PNumMod (j);277int pi2 = trig.PNumMod (j+1);278279int nbt = 0;280int fp1,fp2;281for (k = 1; k <= NONeighbourTrigs(i); k++)282{283trig.GetNeighbourPoints(GetTriangle(NeighbourTrig(i, k)),fp1,fp2);284if (fp1 == pi1 && fp2 == pi2)285{286nbt = NeighbourTrig(i, k);287}288}289290if (!nbt)291{292cerr << "ERROR: stlgeom::Smoothnormals, nbt = 0" << endl;293}294295Vec3d nnb = GetTriangleNormal(nbt); // neighbour normal296nnb /= (nnb.Length() + 1e-24);297298if (!IsEdge(pi1,pi2))299{300if (Angle (nnb, ngeom) > 150 * M_PI/180)301{302SetMarkedTrig(i, 1);303SetMarkedTrig(nbt, 1);304critpairs.Append (INDEX_2 (i, nbt));305}306}307308}309}310311if (!critpairs.Size())312{313break;314}315316if (critpairs.Size())317{318319ARRAY<int> friends;320double area1 = 0, area2 = 0;321322for (i = 1; i <= critpairs.Size(); i++)323{324int tnr1 = critpairs.Get(i).I1();325int tnr2 = critpairs.Get(i).I2();326(*testout) << "t1 = " << tnr1 << ", t2 = " << tnr2327<< " angle = " << Angle (GetTriangleNormal (tnr1),328GetTriangleNormal (tnr2))329<< endl;330331// who has more friends ?332int side;333area1 = 0;334area2 = 0;335for (side = 1; side <= 2; side++)336{337friends.SetSize (0);338friends.Append ( (side == 1) ? tnr1 : tnr2);339340for (j = 1; j <= 3; j++)341{342int fsize = friends.Size();343for (k = 1; k <= fsize; k++)344{345int testtnr = friends.Get(k);346Vec3d ntt = GetTriangleNormal(testtnr);347ntt /= (ntt.Length() + 1e-24);348349for (l = 1; l <= NONeighbourTrigs(testtnr); l++)350{351int testnbnr = NeighbourTrig(testtnr, l);352Vec3d nbt = GetTriangleNormal(testnbnr);353nbt /= (nbt.Length() + 1e-24);354355if (Angle (nbt, ntt) < 15 * M_PI/180)356{357int ii;358int found = 0;359for (ii = 1; ii <= friends.Size(); ii++)360{361if (friends.Get(ii) == testnbnr)362{363found = 1;364break;365}366}367if (!found)368friends.Append (testnbnr);369}370}371}372}373374// compute area:375for (k = 1; k <= friends.Size(); k++)376{377double area =378GetTriangle (friends.Get(k)).Area(points);379380if (side == 1)381area1 += area;382else383area2 += area;384}385386}387388(*testout) << "area1 = " << area1 << " area2 = " << area2 << endl;389if (area1 < 0.1 * area2)390{391Vec3d n = GetTriangleNormal (tnr1);392n *= -1;393SetTriangleNormal(tnr1, n);394}395if (area2 < 0.1 * area1)396{397Vec3d n = GetTriangleNormal (tnr2);398n *= -1;399SetTriangleNormal(tnr2, n);400}401}402}403}404*/405406calcedgedataanglesnew = 1;407PopStatus();408}409410411int STLGeometry :: AddEdge(int ap1, int ap2)412{413STLEdge e(ap1,ap2);414e.SetLeftTrig(GetLeftTrig(ap1,ap2));415e.SetRightTrig(GetRightTrig(ap1,ap2));416return edges.Append(e);417}418419void STLGeometry :: STLDoctorConfirmEdge()420{421StoreEdgeData();422if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())423{424if (stldoctor.selectmode == 1)425{426int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());427int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);428edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus (ED_CONFIRMED);429}430else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)431{432int i;433for (i = 1; i <= selectedmultiedge.Size(); i++)434{435int ap1 = selectedmultiedge.Get(i).i1;436int ap2 = selectedmultiedge.Get(i).i2;437edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus (ED_CONFIRMED);438}439}440}441}442443void STLGeometry :: STLDoctorCandidateEdge()444{445StoreEdgeData();446if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())447{448if (stldoctor.selectmode == 1)449{450int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());451int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);452edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus (ED_CANDIDATE);453}454else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)455{456int i;457for (i = 1; i <= selectedmultiedge.Size(); i++)458{459int ap1 = selectedmultiedge.Get(i).i1;460int ap2 = selectedmultiedge.Get(i).i2;461edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus (ED_CANDIDATE);462}463}464}465}466467void STLGeometry :: STLDoctorExcludeEdge()468{469StoreEdgeData();470if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())471{472if (stldoctor.selectmode == 1)473{474int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());475int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);476edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus(ED_EXCLUDED);477}478else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)479{480int i;481for (i = 1; i <= selectedmultiedge.Size(); i++)482{483int ap1 = selectedmultiedge.Get(i).i1;484int ap2 = selectedmultiedge.Get(i).i2;485edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus(ED_EXCLUDED);486}487}488}489}490491void STLGeometry :: STLDoctorUndefinedEdge()492{493StoreEdgeData();494if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT() && GetNodeOfSelTrig())495{496if (stldoctor.selectmode == 1)497{498int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());499int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);500edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus(ED_UNDEFINED);501}502else if (stldoctor.selectmode == 3 || stldoctor.selectmode == 4)503{504int i;505for (i = 1; i <= selectedmultiedge.Size(); i++)506{507int ap1 = selectedmultiedge.Get(i).i1;508int ap2 = selectedmultiedge.Get(i).i2;509edgedata->Elem(edgedata->GetEdgeNum(ap1,ap2)).SetStatus(ED_UNDEFINED);510}511}512}513}514515void STLGeometry :: STLDoctorSetAllUndefinedEdges()516{517edgedata->ResetAll();518}519520void STLGeometry :: STLDoctorEraseCandidateEdges()521{522StoreEdgeData();523edgedata->ChangeStatus(ED_CANDIDATE, ED_UNDEFINED);524}525526void STLGeometry :: STLDoctorConfirmCandidateEdges()527{528StoreEdgeData();529edgedata->ChangeStatus(ED_CANDIDATE, ED_CONFIRMED);530}531532void STLGeometry :: STLDoctorConfirmedToCandidateEdges()533{534StoreEdgeData();535edgedata->ChangeStatus(ED_CONFIRMED, ED_CANDIDATE);536}537538void STLGeometry :: STLDoctorDirtyEdgesToCandidates()539{540StoreEdgeData();541}542543void STLGeometry :: STLDoctorLongLinesToCandidates()544{545StoreEdgeData();546}547548twoint STLGeometry :: GetNearestSelectedDefinedEdge()549{550Point<3> pestimate = Center(GetTriangle(GetSelectTrig()).center,551GetPoint(GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig())));552//Point3d pestimate = GetTriangle(GetSelectTrig()).center;553554int i, j, en;555ARRAY<int> vic;556GetVicinity(GetSelectTrig(),4,vic);557558559twoint fedg;560fedg.i1 = 0;561fedg.i2 = 0;562double mindist = 1E50;563double dist;564Point<3> p;565566for (i = 1; i <= vic.Size(); i++)567{568const STLTriangle& t = GetTriangle(vic.Get(i));569for (j = 1; j <= 3; j++)570{571en = edgedata->GetEdgeNum(t.PNum(j),t.PNumMod(j+1));572if (edgedata->Get(en).GetStatus() != ED_UNDEFINED)573{574p = pestimate;575dist = GetDistFromLine(GetPoint(t.PNum(j)),GetPoint(t.PNumMod(j+1)),p);576if (dist < mindist)577{578mindist = dist;579fedg.i1 = t.PNum(j);580fedg.i2 = t.PNumMod(j+1);581}582}583}584}585return fedg;586}587588void STLGeometry :: BuildSelectedMultiEdge(twoint ep)589{590if (edgedata->Size() == 0 ||591!GetEPPSize())592{593return;594}595596selectedmultiedge.SetSize(0);597int tenum = GetTopEdgeNum (ep.i1, ep.i2);598599if (edgedata->Get(tenum).GetStatus() == ED_UNDEFINED)600{601twoint epnew = GetNearestSelectedDefinedEdge();602if (epnew.i1)603{604ep = epnew;605tenum = GetTopEdgeNum (ep.i1, ep.i2);606}607}608609selectedmultiedge.Append(twoint(ep));610611if (edgedata->Get(tenum).GetStatus() == ED_UNDEFINED)612{613return;614}615616edgedata->BuildLineWithEdge(ep.i1,ep.i2,selectedmultiedge);617}618619void STLGeometry :: BuildSelectedEdge(twoint ep)620{621if (edgedata->Size() == 0 ||622!GetEPPSize())623{624return;625}626627selectedmultiedge.SetSize(0);628629selectedmultiedge.Append(twoint(ep));630}631632void STLGeometry :: BuildSelectedCluster(twoint ep)633{634if (edgedata->Size() == 0 ||635!GetEPPSize())636{637return;638}639640selectedmultiedge.SetSize(0);641642int tenum = GetTopEdgeNum (ep.i1, ep.i2);643644if (edgedata->Get(tenum).GetStatus() == ED_UNDEFINED)645{646twoint epnew = GetNearestSelectedDefinedEdge();647if (epnew.i1)648{649ep = epnew;650tenum = GetTopEdgeNum (ep.i1, ep.i2);651}652}653654selectedmultiedge.Append(twoint(ep));655656if (edgedata->Get(tenum).GetStatus() == ED_UNDEFINED)657{658return;659}660661edgedata->BuildClusterWithEdge(ep.i1,ep.i2,selectedmultiedge);662}663664void STLGeometry :: ImportEdges()665{666StoreEdgeData();667668PrintMessage(5, "import edges from file 'edges.ng'");669ifstream fin("edges.ng");670671int ne;672fin >> ne;673674ARRAY<Point<3> > eps;675676int i;677Point<3> p;678for (i = 1; i <= 2*ne; i++)679{680fin >> p(0);681fin >> p(1);682fin >> p(2);683eps.Append(p);684}685AddEdges(eps);686}687688void STLGeometry :: AddEdges(const ARRAY<Point<3> >& eps)689{690int i;691int ne = eps.Size()/2;692693ARRAY<int> epsi;694Box<3> bb = GetBoundingBox();695bb.Increase(1);696697Point3dTree ptree (bb.PMin(),698bb.PMax());699ARRAY<int> pintersect;700701double gtol = GetBoundingBox().Diam()/1.E10;702Point<3> p;703704for (i = 1; i <= GetNP(); i++)705{706p = GetPoint(i);707ptree.Insert (p, i);708}709710int error = 0;711for (i = 1; i <= 2*ne; i++)712{713p = eps.Get(i);714Point3d pmin = p - Vec3d (gtol, gtol, gtol);715Point3d pmax = p + Vec3d (gtol, gtol, gtol);716717ptree.GetIntersecting (pmin, pmax, pintersect);718if (pintersect.Size() > 1)719{720PrintError("Found too much points in epsilon-dist");721error = 1;722}723else if (pintersect.Size() == 0)724{725error = 1;726PrintError("edgepoint does not exist!");727PrintMessage(5,"p=",Point3d(eps.Get(i)));728}729else730{731epsi.Append(pintersect.Get(1));732}733}734735if (error) return;736737int en;738for (i = 1; i <= ne; i++)739{740if (epsi.Get(2*i-1) == epsi.Get(2*i)) {PrintError("Edge with zero length!");}741else742{743en = edgedata->GetEdgeNum(epsi.Get(2*i-1),epsi.Get(2*i));744edgedata->Elem(en).SetStatus (ED_CONFIRMED);745}746}747748}749750751752void STLGeometry :: ImportExternalEdges(const char * filename)753{754//AVL edges!!!!!!755756ifstream inf (filename);757char ch;758//int cnt = 0;759int records, units, i, j;760PrintFnStart("Import edges from ",filename);761762const int flen=30;763char filter[flen+1];764filter[flen] = 0;765char buf[20];766767ARRAY<Point3d> importpoints;768ARRAY<int> importlines;769ARRAY<int> importpnums;770771while (inf.good())772{773inf.get(ch);774// (*testout) << cnt << ": " << ch << endl;775776for (i = 0; i < flen; i++)777filter[i] = filter[i+1];778filter[flen-1] = ch;779// (*testout) << filter << endl;780781if (strcmp (filter+flen-7, "RECORDS") == 0)782{783inf.get(ch); // '='784inf >> records;785}786if (strcmp (filter+flen-5, "UNITS") == 0)787{788inf.get(ch); // '='789inf >> units;790}791792if (strcmp (filter+flen-17, "EDGE NODE NUMBERS") == 0)793{794int nodenr;795importlines.SetSize (units);796for (i = 1; i <= units; i++)797{798inf >> nodenr;799importlines.Elem(i) = nodenr;800// (*testout) << nodenr << endl;801}802}803804if (strcmp (filter+flen-23, "EDGE POINT COORD IN DIR") == 0)805{806int coord;807808inf >> coord;809810importpoints.SetSize (units);811812inf >> ch;813inf.putback (ch);814815for (i = 1; i <= units; i++)816{817for (j = 0; j < 12; j++)818inf.get (buf[j]);819buf[12] = 0;820821importpoints.Elem(i).X(coord) = 1000 * atof (buf);822}823}824}825826/*827(*testout) << "lines: " << endl;828for (i = 1; i <= importlines.Size(); i++)829(*testout) << importlines.Get(i) << endl;830(*testout) << "points: " << endl;831for (i = 1; i <= importpoints.Size(); i++)832(*testout) << importpoints.Get(i) << endl;833*/834835836837importpnums.SetSize (importpoints.Size());838839840Box3d bb (GetBoundingBox().PMin() + Vec3d (-1,-1,-1),841GetBoundingBox().PMax() + Vec3d (1, 1, 1));842843Point3dTree ptree (bb.PMin(),844bb.PMax());845846847PrintMessage(7,"stl - bb: ",bb.PMin(), " - ", bb.PMax());848849Box3d ebb;850ebb.SetPoint (importpoints.Get(1));851for (i = 1; i <= importpoints.Size(); i++)852ebb.AddPoint (importpoints.Get(i));853PrintMessage(7,"edgep - bb: ", ebb.PMin(), " - ", ebb.PMax());854855ARRAY<int> pintersect;856857double gtol = GetBoundingBox().Diam()/1.E6;858859for (i = 1; i <= GetNP(); i++)860{861Point3d p = GetPoint(i);862// (*testout) << "stlpt: " << p << endl;863ptree.Insert (p, i);864}865866867for (i = 1; i <= importpoints.Size(); i++)868{869Point3d p = importpoints.Get(i);870Point3d pmin = p - Vec3d (gtol, gtol, gtol);871Point3d pmax = p + Vec3d (gtol, gtol, gtol);872873ptree.GetIntersecting (pmin, pmax, pintersect);874if (pintersect.Size() > 1)875{876importpnums.Elem(i) = 0;877PrintError("Found too many points in epsilon-dist");878}879else if (pintersect.Size() == 0)880{881importpnums.Elem(i) = 0;882PrintError("Edgepoint does not exist!");883}884else885{886importpnums.Elem(i) = pintersect.Get(1);887}888}889890// if (!error)891{892PrintMessage(7,"found all edge points in stl file");893894895StoreEdgeData();896897int oldp = 0;898899for (i = 1; i <= importlines.Size(); i++)900{901int newp = importlines.Get(i);902if (!importpnums.Get(abs(newp)))903newp = 0;904905if (oldp && newp)906{907int en = edgedata->GetEdgeNum(importpnums.Get(oldp),908importpnums.Get(abs(newp)));909edgedata->Elem(en).SetStatus (ED_CONFIRMED);910}911912if (newp < 0)913oldp = 0;914else915oldp = newp;916}917}918919920}921922923924void STLGeometry :: ExportEdges()925{926PrintFnStart("Save edges to file 'edges.ng'");927928ofstream fout("edges.ng");929fout.precision(16);930931int n = edgedata->GetNConfEdges();932933fout << n << endl;934935int i;936for (i = 1; i <= edgedata->Size(); i++)937{938if (edgedata->Get(i).GetStatus() == ED_CONFIRMED)939{940const STLTopEdge & e = edgedata->Get(i);941fout << GetPoint(e.PNum(1))(0) << " " << GetPoint(e.PNum(1))(1) << " " << GetPoint(e.PNum(1))(2) << endl;942fout << GetPoint(e.PNum(2))(0) << " " << GetPoint(e.PNum(2))(1) << " " << GetPoint(e.PNum(2))(2) << endl;943}944}945946}947948void STLGeometry :: LoadEdgeData(const char* file)949{950StoreEdgeData();951952PrintFnStart("Load edges from file '", file, "'");953ifstream fin(file);954955edgedata->Read(fin);956957// calcedgedataanglesnew = 1;958}959960void STLGeometry :: SaveEdgeData(const char* file)961{962PrintFnStart("save edges to file '", file, "'");963ofstream fout(file);964965edgedata->Write(fout);966}967968969970971972973974/*975void STLGeometry :: SaveExternalEdges()976{977ofstream fout("externaledgesp3.ng");978fout.precision(16);979980int n = NOExternalEdges();981fout << n << endl;982983int i;984for (i = 1; i <= n; i++)985{986twoint e = GetExternalEdge(i);987fout << GetPoint(e.i1)(0) << " " << GetPoint(e.i1)(1) << " " << GetPoint(e.i1)(2) << endl;988fout << GetPoint(e.i2)(0) << " " << GetPoint(e.i2)(1) << " " << GetPoint(e.i2)(2) << endl;989}990991}992*/993void STLGeometry :: StoreExternalEdges()994{995storedexternaledges.SetSize(0);996undoexternaledges = 1;997int i;998for (i = 1; i <= externaledges.Size(); i++)999{1000storedexternaledges.Append(externaledges.Get(i));1001}10021003}10041005void STLGeometry :: UndoExternalEdges()1006{1007if (!undoexternaledges)1008{1009PrintMessage(1, "undo not further possible!");1010return;1011}1012RestoreExternalEdges();1013undoexternaledges = 0;1014}10151016void STLGeometry :: RestoreExternalEdges()1017{1018externaledges.SetSize(0);1019int i;1020for (i = 1; i <= storedexternaledges.Size(); i++)1021{1022externaledges.Append(storedexternaledges.Get(i));1023}10241025}102610271028void STLGeometry :: AddExternalEdgeAtSelected()1029{1030StoreExternalEdges();1031if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT())1032{1033int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());1034int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);1035if (!IsExternalEdge(ap1,ap2)) {AddExternalEdge(ap1,ap2);}1036}1037}10381039void STLGeometry :: AddClosedLinesToExternalEdges()1040{1041StoreExternalEdges();10421043int i, j;1044for (i = 1; i <= GetNLines(); i++)1045{1046STLLine* l = GetLine(i);1047if (l->StartP() == l->EndP())1048{1049for (j = 1; j < l->NP(); j++)1050{1051int ap1 = l->PNum(j);1052int ap2 = l->PNum(j+1);10531054if (!IsExternalEdge(ap1,ap2)) {AddExternalEdge(ap1,ap2);}1055}1056}1057}1058}10591060void STLGeometry :: AddLongLinesToExternalEdges()1061{1062StoreExternalEdges();10631064double diamfact = stldoctor.dirtytrigfact;1065double diam = GetBoundingBox().Diam();10661067int i, j;1068for (i = 1; i <= GetNLines(); i++)1069{1070STLLine* l = GetLine(i);1071if (l->GetLength(points) >= diamfact*diam)1072{1073for (j = 1; j < l->NP(); j++)1074{1075int ap1 = l->PNum(j);1076int ap2 = l->PNum(j+1);10771078if (!IsExternalEdge(ap1,ap2)) {AddExternalEdge(ap1,ap2);}1079}1080}1081}1082}10831084void STLGeometry :: AddAllNotSingleLinesToExternalEdges()1085{1086StoreExternalEdges();10871088int i, j;1089for (i = 1; i <= GetNLines(); i++)1090{1091STLLine* l = GetLine(i);1092if (GetNEPP(l->StartP()) > 1 || GetNEPP(l->EndP()) > 1)1093{1094for (j = 1; j < l->NP(); j++)1095{1096int ap1 = l->PNum(j);1097int ap2 = l->PNum(j+1);10981099if (!IsExternalEdge(ap1,ap2)) {AddExternalEdge(ap1,ap2);}1100}1101}1102}1103}11041105void STLGeometry :: DeleteDirtyExternalEdges()1106{1107//delete single triangle edges and single edge-lines in clusters"1108StoreExternalEdges();11091110int i, j;1111for (i = 1; i <= GetNLines(); i++)1112{1113STLLine* l = GetLine(i);1114if (l->NP() <= 3 || (l->StartP() == l->EndP() && l->NP() == 4))1115{1116for (j = 1; j < l->NP(); j++)1117{1118int ap1 = l->PNum(j);1119int ap2 = l->PNum(j+1);11201121if (IsExternalEdge(ap1,ap2)) {DeleteExternalEdge(ap1,ap2);}1122}1123}1124}1125}11261127void STLGeometry :: AddExternalEdgesFromGeomLine()1128{1129StoreExternalEdges();1130if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT())1131{1132int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());1133int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);11341135if (IsEdge(ap1,ap2))1136{1137int edgenum = IsEdgeNum(ap1,ap2);1138if (!IsExternalEdge(ap1,ap2)) {AddExternalEdge(ap1,ap2);}11391140int noend = 1;1141int startp = ap1;1142int laste = edgenum;1143int np1, np2;1144while (noend)1145{1146if (GetNEPP(startp) == 2)1147{1148if (GetEdgePP(startp,1) != laste) {laste = GetEdgePP(startp,1);}1149else {laste = GetEdgePP(startp,2);}1150np1 = GetEdge(laste).PNum(1);1151np2 = GetEdge(laste).PNum(2);11521153if (!IsExternalEdge(np1, np2)) {AddExternalEdge(np1, np2);}1154else {noend = 0;}1155if (np1 != startp) {startp = np1;}1156else {startp = np2;}1157}1158else {noend = 0;}1159}11601161startp = ap2;1162laste = edgenum;1163noend = 1;1164while (noend)1165{1166if (GetNEPP(startp) == 2)1167{1168if (GetEdgePP(startp,1) != laste) {laste = GetEdgePP(startp,1);}1169else {laste = GetEdgePP(startp,2);}1170np1 = GetEdge(laste).PNum(1);1171np2 = GetEdge(laste).PNum(2);11721173if (!IsExternalEdge(np1, np2)) {AddExternalEdge(np1, np2);}1174else {noend = 0;}1175if (np1 != startp) {startp = np1;}1176else {startp = np2;}1177}1178else {noend = 0;}1179}11801181}11821183}11841185}11861187void STLGeometry :: ClearEdges()1188{1189edgesfound = 0;1190edges.SetSize(0);1191//edgedata->SetSize(0);1192// externaledges.SetSize(0);1193edgesperpoint.SetSize(0);1194undoexternaledges = 0;11951196}11971198void STLGeometry :: STLDoctorBuildEdges()1199{1200// if (!trigsconverted) {return;}1201ClearEdges();12021203meshlines.SetSize(0);1204FindEdgesFromAngles();1205}12061207void STLGeometry :: DeleteExternalEdgeAtSelected()1208{1209StoreExternalEdges();1210if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT())1211{1212int ap1 = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());1213int ap2 = GetTriangle(GetSelectTrig()).PNumMod(GetNodeOfSelTrig()+1);1214if (IsExternalEdge(ap1,ap2)) {DeleteExternalEdge(ap1,ap2);}1215}1216}12171218void STLGeometry :: DeleteExternalEdgeInVicinity()1219{1220StoreExternalEdges();1221if (!stldoctor.showvicinity || vicinity.Size() != GetNT()) {return;}12221223int i, j, ap1, ap2;12241225for (i = 1; i <= GetNT(); i++)1226{1227if (vicinity.Elem(i))1228{1229for (j = 1; j <= 3; j++)1230{1231ap1 = GetTriangle(i).PNum(j);1232ap2 = GetTriangle(i).PNumMod(j+1);12331234if (IsExternalEdge(ap1,ap2))1235{1236DeleteExternalEdge(ap1,ap2);1237}1238}1239}1240}1241}12421243void STLGeometry :: BuildExternalEdgesFromEdges()1244{1245StoreExternalEdges();12461247if (GetNE() == 0) {PrintWarning("Edges possibly not generated!");}12481249int i;1250externaledges.SetSize(0);12511252for (i = 1; i <= GetNE(); i++)1253{1254STLEdge e = GetEdge(i);1255AddExternalEdge(e.PNum(1), e.PNum(2));1256}12571258}125912601261void STLGeometry :: AddExternalEdge(int ap1, int ap2)1262{1263externaledges.Append(twoint(ap1,ap2));1264}12651266void STLGeometry :: DeleteExternalEdge(int ap1, int ap2)1267{12681269int i;1270int found = 0;1271for (i = 1; i <= NOExternalEdges(); i++)1272{1273if ((GetExternalEdge(i).i1 == ap1 && GetExternalEdge(i).i2 == ap2) ||1274(GetExternalEdge(i).i1 == ap2 && GetExternalEdge(i).i2 == ap1)) {found = 1;};1275if (found && i < NOExternalEdges())1276{1277externaledges.Elem(i) = externaledges.Get(i+1);1278}1279}1280if (!found) {PrintWarning("edge not found");}1281else1282{1283externaledges.SetSize(externaledges.Size()-1);1284}12851286}12871288int STLGeometry :: IsExternalEdge(int ap1, int ap2)1289{1290int i;1291for (i = 1; i <= NOExternalEdges(); i++)1292{1293if ((GetExternalEdge(i).i1 == ap1 && GetExternalEdge(i).i2 == ap2) ||1294(GetExternalEdge(i).i1 == ap2 && GetExternalEdge(i).i2 == ap1)) {return 1;};1295}1296return 0;1297}12981299void STLGeometry :: DestroyDirtyTrigs()1300{13011302PrintFnStart("Destroy dirty triangles");1303PrintMessage(5,"original number of triangles=", GetNT());13041305//destroy every triangle with other than 3 neighbours;1306int changed = 1;1307int i, j, k;1308while (changed)1309{1310changed = 0;1311Clear();13121313for (i = 1; i <= GetNT(); i++)1314{1315int dirty = NONeighbourTrigs(i) < 3;13161317for (j = 1; j <= 3; j++)1318{1319int pnum = GetTriangle(i).PNum(j);1320/*1321if (pnum == 1546)1322{1323// for (k = 1; k <= NOTrigsPerPoint(pnum); k++)1324}1325*/1326if (NOTrigsPerPoint(pnum) <= 2)1327dirty = 1;1328}13291330int pi1 = GetTriangle(i).PNum(1);1331int pi2 = GetTriangle(i).PNum(2);1332int pi3 = GetTriangle(i).PNum(3);1333if (pi1 == pi2 || pi1 == pi3 || pi2 == pi3)1334{1335PrintMessage(5,"triangle with Volume 0: ", i, " nodes: ", pi1, ", ", pi2, ", ", pi3);1336dirty = 1;1337}13381339if (dirty)1340{1341for (k = i+1; k <= GetNT(); k++)1342{1343trias.Elem(k-1) = trias.Get(k);1344// readtrias: not longer permanent, JS1345// readtrias.Elem(k-1) = readtrias.Get(k);1346}1347int size = GetNT();1348trias.SetSize(size-1);1349// readtrias.SetSize(size-1);1350changed = 1;1351break;1352}1353}1354}13551356FindNeighbourTrigs();1357PrintMessage(5,"final number of triangles=", GetNT());1358}13591360void STLGeometry :: CalcNormalsFromGeometry()1361{1362int i;1363for (i = 1; i <= GetNT(); i++)1364{1365const STLTriangle & tr = GetTriangle(i);1366const Point3d& ap1 = GetPoint(tr.PNum(1));1367const Point3d& ap2 = GetPoint(tr.PNum(2));1368const Point3d& ap3 = GetPoint(tr.PNum(3));13691370Vec3d normal = Cross (ap2-ap1, ap3-ap1);13711372if (normal.Length() != 0)1373{1374normal /= (normal.Length());1375}1376GetTriangle(i).SetNormal(normal);1377}1378PrintMessage(5,"Normals calculated from geometry!!!");13791380calcedgedataanglesnew = 1;1381}13821383void STLGeometry :: SetSelectTrig(int trig)1384{1385stldoctor.selecttrig = trig;1386}13871388int STLGeometry :: GetSelectTrig() const1389{1390return stldoctor.selecttrig;1391}13921393void STLGeometry :: SetNodeOfSelTrig(int n)1394{1395stldoctor.nodeofseltrig = n;1396}13971398int STLGeometry :: GetNodeOfSelTrig() const1399{1400return stldoctor.nodeofseltrig;1401}14021403void STLGeometry :: MoveSelectedPointToMiddle()1404{1405if (GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT())1406{1407int p = GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig());1408Point<3> pm(0.,0.,0.); //Middlevector;1409Point<3> p0(0.,0.,0.);1410PrintMessage(5,"original point=", Point3d(GetPoint(p)));14111412int i;1413int cnt = 0;1414for (i = 1; i <= trigsperpoint.EntrySize(p); i++)1415{1416const STLTriangle& tr = GetTriangle(trigsperpoint.Get(p,i));1417int j;1418for (j = 1; j <= 3; j++)1419{1420if (tr.PNum(j) != p)1421{1422cnt++;1423pm(0) += GetPoint(tr.PNum(j))(0);1424pm(1) += GetPoint(tr.PNum(j))(1);1425pm(2) += GetPoint(tr.PNum(j))(2);1426}1427}1428}14291430Point<3> origp = GetPoint(p);1431double fact = 0.2;14321433SetPoint(p, p0 + fact*(1./(double)cnt)*(pm-p0)+(1.-fact)*(origp-p0));14341435PrintMessage(5,"middle point=", Point3d (GetPoint(p)));14361437PrintMessage(5,"moved point ", Point3d (p));14381439}1440}14411442void STLGeometry :: PrintSelectInfo()1443{14441445//int trig = GetSelectTrig();1446//int p = GetTriangle(trig).PNum(GetNodeOfSelTrig());14471448PrintMessage(1,"touch triangle ", GetSelectTrig()1449, ", local node ", GetNodeOfSelTrig()1450, " (=", GetTriangle(GetSelectTrig()).PNum(GetNodeOfSelTrig()), ")");1451if (AtlasMade() && GetSelectTrig() >= 1 && GetSelectTrig() <= GetNT())1452{1453PrintMessage(1," chartnum=",GetChartNr(GetSelectTrig()));1454/*1455PointBetween(Center(Center(GetPoint(GetTriangle(270).PNum(1)),1456GetPoint(GetTriangle(270).PNum(2))),1457GetPoint(GetTriangle(270).PNum(3))),270,1458Center(Center(GetPoint(GetTriangle(trig).PNum(1)),1459GetPoint(GetTriangle(trig).PNum(2))),1460GetPoint(GetTriangle(trig).PNum(3))),trig);1461*/1462//PointBetween(Point3d(5.7818, 7.52768, 4.14879),260,Point3d(6.80292, 6.55392, 4.70184),233);1463}1464}14651466void STLGeometry :: ShowSelectedTrigChartnum()1467{1468int st = GetSelectTrig();14691470if (st >= 1 && st <= GetNT() && AtlasMade())1471PrintMessage(1,"selected trig ", st, " has chartnumber ", GetChartNr(st));1472}14731474void STLGeometry :: ShowSelectedTrigCoords()1475{1476int st = GetSelectTrig();14771478/*1479//testing!!!!1480ARRAY<int> trigs;1481GetSortedTrianglesAroundPoint(GetTriangle(st).PNum(GetNodeOfSelTrig()),st,trigs);1482*/14831484if (st >= 1 && st <= GetNT())1485{1486PrintMessage(1, "coordinates of selected trig ", st, ":");1487PrintMessage(1, " p1 = ", GetTriangle(st).PNum(1), " = ",1488Point3d (GetPoint(GetTriangle(st).PNum(1))));1489PrintMessage(1, " p2 = ", GetTriangle(st).PNum(2), " = ",1490Point3d (GetPoint(GetTriangle(st).PNum(2))));1491PrintMessage(1, " p3 = ", GetTriangle(st).PNum(3), " = ",1492Point3d (GetPoint(GetTriangle(st).PNum(3))));1493}1494}14951496void STLGeometry :: LoadMarkedTrigs()1497{1498PrintFnStart("load marked trigs from file 'markedtrigs.ng'");1499ifstream fin("markedtrigs.ng");15001501int n;1502fin >> n;1503if (n != GetNT() || n == 0) {PrintError("Not a suitable marked-trig-file!"); return;}15041505int i, m;1506for (i = 1; i <= n; i++)1507{1508fin >> m;1509SetMarkedTrig(i, m);1510}15111512fin >> n;1513if (n != 0)1514{15151516Point<3> ap1, ap2;1517for (i = 1; i <= n; i++)1518{1519fin >> ap1(0); fin >> ap1(1); fin >> ap1(2);1520fin >> ap2(0); fin >> ap2(1); fin >> ap2(2);1521AddMarkedSeg(ap1,ap2);1522}1523}1524}15251526void STLGeometry :: SaveMarkedTrigs()1527{1528PrintFnStart("save marked trigs to file 'markedtrigs.ng'");1529ofstream fout("markedtrigs.ng");15301531int n = GetNT();1532fout << n << endl;15331534int i;1535for (i = 1; i <= n; i++)1536{1537fout << IsMarkedTrig(i) << "\n";1538}15391540n = GetNMarkedSegs();1541fout << n << endl;15421543Point<3> ap1,ap2;1544for (i = 1; i <= n; i++)1545{1546GetMarkedSeg(i,ap1,ap2);1547fout << ap1(0) << " " << ap1(1) << " " << ap1(2) << " ";1548fout << ap2(0) << " " << ap2(1) << " " << ap2(2) << " " << "\n";1549}15501551}15521553void STLGeometry :: NeighbourAnglesOfSelectedTrig()1554{1555int st = GetSelectTrig();15561557if (st >= 1 && st <= GetNT())1558{1559int i;1560PrintMessage(1,"Angle to triangle ", st, ":");1561for (i = 1; i <= NONeighbourTrigs(st); i++)1562{1563PrintMessage(1," triangle ", NeighbourTrig(st,i), ": angle = ",1564180./M_PI*GetAngle(st, NeighbourTrig(st,i)), "�",1565", calculated = ", 180./M_PI*Angle(GetTriangle(st).GeomNormal(points),1566GetTriangle(NeighbourTrig(st,i)).GeomNormal(points)), "�");1567}1568}1569}15701571void STLGeometry :: GetVicinity(int starttrig, int size, ARRAY<int>& vic)1572{1573if (starttrig == 0 || starttrig > GetNT()) {return;}15741575ARRAY<int> vicarray;1576vicarray.SetSize(GetNT());15771578int i;1579for (i = 1; i <= vicarray.Size(); i++)1580{1581vicarray.Elem(i) = 0;1582}15831584vicarray.Elem(starttrig) = 1;15851586int j = 0,k;15871588ARRAY <int> list1;1589list1.SetSize(0);1590ARRAY <int> list2;1591list2.SetSize(0);1592list1.Append(starttrig);15931594while (j < size)1595{1596j++;1597for (i = 1; i <= list1.Size(); i++)1598{1599for (k = 1; k <= NONeighbourTrigs(i); k++)1600{1601int nbtrig = NeighbourTrig(list1.Get(i),k);1602if (nbtrig && vicarray.Get(nbtrig) == 0)1603{1604list2.Append(nbtrig);1605vicarray.Elem(nbtrig) = 1;1606}1607}1608}1609list1.SetSize(0);1610for (i = 1; i <= list2.Size(); i++)1611{1612list1.Append(list2.Get(i));1613}1614list2.SetSize(0);1615}16161617vic.SetSize(0);1618for (i = 1; i <= vicarray.Size(); i++)1619{1620if (vicarray.Get(i)) {vic.Append(i);}1621}1622}16231624void STLGeometry :: CalcVicinity(int starttrig)1625{1626if (starttrig == 0 || starttrig > GetNT()) {return;}16271628vicinity.SetSize(GetNT());16291630if (!stldoctor.showvicinity) {return;}16311632int i;1633for (i = 1; i <= vicinity.Size(); i++)1634{1635vicinity.Elem(i) = 0;1636}16371638vicinity.Elem(starttrig) = 1;16391640int j = 0,k;16411642ARRAY <int> list1;1643list1.SetSize(0);1644ARRAY <int> list2;1645list2.SetSize(0);1646list1.Append(starttrig);16471648// int cnt = 1;1649while (j < stldoctor.vicinity)1650{1651j++;1652for (i = 1; i <= list1.Size(); i++)1653{1654for (k = 1; k <= NONeighbourTrigs(i); k++)1655{1656int nbtrig = NeighbourTrig(list1.Get(i),k);1657if (nbtrig && vicinity.Get(nbtrig) == 0)1658{1659list2.Append(nbtrig);1660vicinity.Elem(nbtrig) = 1;1661//cnt++;1662}1663}1664}1665list1.SetSize(0);1666for (i = 1; i <= list2.Size(); i++)1667{1668list1.Append(list2.Get(i));1669}1670list2.SetSize(0);1671}16721673}16741675int STLGeometry :: Vicinity(int trig) const1676{1677if (trig <= vicinity.Size() && trig >=1)1678{1679return vicinity.Get(trig);1680}1681else {PrintSysError("In STLGeometry::Vicinity");}1682return 0;1683}16841685void STLGeometry :: InitMarkedTrigs()1686{1687markedtrigs.SetSize(GetNT());1688int i;1689for (i = 1; i <= GetNT(); i++)1690{1691SetMarkedTrig(i, 0);1692}1693}16941695void STLGeometry :: MarkDirtyTrigs()1696{1697PrintFnStart("mark dirty trigs");1698int i,j;16991700markedtrigs.SetSize(GetNT());17011702for (i = 1; i <= GetNT(); i++)1703{1704SetMarkedTrig(i, 0);1705}17061707int found;1708double dirtyangle = stlparam.yangle/2./180.*M_PI;1709int cnt = 0;1710for (i = 1; i <= GetNT(); i++)1711{1712found = 0;1713for (j = 1; j <= NONeighbourTrigs(i); j++)1714{1715if (GetAngle(i, NeighbourTrig(i,j)) > dirtyangle)1716{1717found++;1718}1719}1720if (found && GetTriangle(i).MinHeight(points) <1721stldoctor.dirtytrigfact*GetTriangle(i).MaxLength(points))1722{1723SetMarkedTrig(i, 1); cnt++;1724}1725/*1726else if (found == 3)1727{1728SetMarkedTrig(i, 1); cnt++;1729}1730*/1731}17321733PrintMessage(1, "marked ", cnt, " dirty trigs");1734}173517361737void STLGeometry :: MarkTopErrorTrigs()1738{1739int cnt = 0;1740markedtrigs.SetSize(GetNT());1741for (int i = 1; i <= GetNT(); i++)1742{1743const STLTriangle & trig = GetTriangle(i);17441745SetMarkedTrig(i, trig.flags.toperror);1746if (trig.flags.toperror) cnt++;1747}1748PrintMessage(1,"marked ", cnt, " inconsistent triangles");1749}1750175117521753double STLGeometry :: CalcTrigBadness(int i)1754{1755int j;1756double maxbadness = 0;1757int ap1, ap2;1758for (j = 1; j <= NONeighbourTrigs(i); j++)1759{1760GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)), ap1, ap2);17611762if (!IsEdge(ap1,ap2) && GetGeomAngle(i, NeighbourTrig(i,j)) > maxbadness)1763{1764maxbadness = GetGeomAngle(i, NeighbourTrig(i,j));1765}1766}1767return maxbadness;17681769}17701771void STLGeometry :: GeomSmoothRevertedTrigs()1772{1773//double revertedangle = stldoctor.smoothangle/180.*M_PI;1774double fact = stldoctor.dirtytrigfact;17751776MarkRevertedTrigs();17771778int i, j, k, l, p;17791780for (i = 1; i <= GetNT(); i++)1781{1782if (IsMarkedTrig(i))1783{1784for (j = 1; j <= 3; j++)1785{1786double origbadness = CalcTrigBadness(i);17871788p = GetTriangle(i).PNum(j);1789Point<3> pm(0.,0.,0.); //Middlevector;1790Point<3> p0(0.,0.,0.);17911792int cnt = 0;17931794for (k = 1; k <= trigsperpoint.EntrySize(p); k++)1795{1796const STLTriangle& tr = GetTriangle(trigsperpoint.Get(p,k));1797for (l = 1; l <= 3; l++)1798{1799if (tr.PNum(l) != p)1800{1801cnt++;1802pm(0) += GetPoint(tr.PNum(l))(0);1803pm(1) += GetPoint(tr.PNum(l))(1);1804pm(2) += GetPoint(tr.PNum(l))(2);1805}1806}1807}1808Point3d origp = GetPoint(p);1809Point3d newp = p0 + fact*(1./(double)cnt)*(pm-p0)+(1.-fact)*(origp-p0);18101811SetPoint(p, newp);18121813if (CalcTrigBadness(i) > 0.9*origbadness) {SetPoint(p,origp); PrintDot('f');}1814else {PrintDot('s');}1815}1816}1817}1818MarkRevertedTrigs();1819}18201821void STLGeometry :: MarkRevertedTrigs()1822{1823int i,j;1824if (edgesperpoint.Size() != GetNP()) {BuildEdges();}18251826PrintFnStart("mark reverted trigs");18271828InitMarkedTrigs();18291830int found;1831double revertedangle = stldoctor.smoothangle/180.*M_PI;18321833int cnt = 0;1834int ap1, ap2;1835for (i = 1; i <= GetNT(); i++)1836{1837found = 0;1838for (j = 1; j <= NONeighbourTrigs(i); j++)1839{1840GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)), ap1, ap2);18411842if (!IsEdge(ap1,ap2))1843{1844if (GetGeomAngle(i, NeighbourTrig(i,j)) > revertedangle)1845{1846found = 1;1847break;1848}1849}1850}18511852if (found)1853{1854SetMarkedTrig(i, 1); cnt++;1855}18561857}18581859PrintMessage(5, "found ", cnt, " reverted trigs");186018611862}18631864void STLGeometry :: SmoothDirtyTrigs()1865{1866PrintFnStart("smooth dirty trigs");18671868MarkDirtyTrigs();18691870int i,j;1871int changed = 1;1872int ap1, ap2;18731874while (changed)1875{1876changed = 0;1877for (i = 1; i <= GetNT(); i++)1878{1879if (IsMarkedTrig(i))1880{1881int foundtrig = 0;1882double maxlen = 0;1883// JS: darf normalvector nicht ueber kurze Seite erben1884maxlen = GetTriangle(i).MaxLength(GetPoints()) / 2.1; //JG: bei flachem dreieck auch kurze Seite18851886for (j = 1; j <= NONeighbourTrigs(i); j++)1887{1888if (!IsMarkedTrig(NeighbourTrig(i,j)))1889{1890GetTriangle(i).GetNeighbourPoints(GetTriangle(NeighbourTrig(i,j)),ap1,ap2);1891if (Dist(GetPoint(ap1),GetPoint(ap2)) >= maxlen)1892{1893foundtrig = NeighbourTrig(i,j);1894maxlen = Dist(GetPoint(ap1),GetPoint(ap2));1895}1896}1897}1898if (foundtrig)1899{1900GetTriangle(i).SetNormal(GetTriangle(foundtrig).Normal());1901changed = 1;1902SetMarkedTrig(i,0);1903}1904}1905}1906}19071908calcedgedataanglesnew = 1;190919101911MarkDirtyTrigs();19121913int cnt = 0;1914for (i = 1; i <= GetNT(); i++)1915{1916if (IsMarkedTrig(i)) {cnt++;}1917}19181919PrintMessage(5,"NO marked dirty trigs=", cnt);19201921}19221923int STLGeometry :: IsMarkedTrig(int trig) const1924{1925if (trig <= markedtrigs.Size() && trig >=1)1926{1927return markedtrigs.Get(trig);1928}1929else {PrintSysError("In STLGeometry::IsMarkedTrig");}19301931return 0;1932}19331934void STLGeometry :: SetMarkedTrig(int trig, int num)1935{1936if (trig <= markedtrigs.Size() && trig >=1)1937{1938markedtrigs.Elem(trig) = num;1939}1940else {PrintSysError("In STLGeometry::SetMarkedTrig");}1941}19421943void STLGeometry :: Clear()1944{1945PrintFnStart("Clear");19461947surfacemeshed = 0;1948surfaceoptimized = 0;1949volumemeshed = 0;19501951selectedmultiedge.SetSize(0);1952meshlines.SetSize(0);1953// neighbourtrigs.SetSize(0);1954outerchartspertrig.SetSize(0);1955atlas.SetSize(0);1956ClearMarkedSegs();1957ClearSpiralPoints();1958ClearLineEndPoints();19591960SetSelectTrig(0);1961SetNodeOfSelTrig(1);1962facecnt = 0;19631964SetThreadPercent(100.);19651966ClearEdges();1967}19681969double STLGeometry :: Area()1970{1971double ar = 0;1972int i;1973for (i = 1; i <= GetNT(); i++)1974{1975ar += GetTriangle(i).Area(points);1976}1977return ar;1978}19791980double STLGeometry :: GetAngle(int t1, int t2)1981{1982return Angle(GetTriangle(t1).Normal(),GetTriangle(t2).Normal());1983}19841985double STLGeometry :: GetGeomAngle(int t1, int t2)1986{1987Vec3d n1 = GetTriangle(t1).GeomNormal(points);1988Vec3d n2 = GetTriangle(t2).GeomNormal(points);1989return Angle(n1,n2);1990}199119921993void STLGeometry :: InitSTLGeometry(const ARRAY<STLReadTriangle> & readtrias)1994{1995PrintFnStart("Init STL Geometry");1996STLTopology::InitSTLGeometry(readtrias);19971998int i, k;19992000//const double geometry_tol_fact = 1E8; //distances lower than max_box_size/tol are ignored20012002int np = GetNP();2003PrintMessage(5,"NO points= ", GetNP());2004normals.SetSize(GetNP());2005ARRAY<int> normal_cnt(GetNP()); // counts number of added normals in a point20062007for (i = 1; i <= np; i++)2008{2009normal_cnt.Elem(i) = 0;2010normals.Elem(i) = Vec3d (0,0,0);2011}20122013for(i = 1; i <= GetNT(); i++)2014{2015// STLReadTriangle t = GetReadTriangle(i);2016// STLTriangle st;20172018Vec<3> n = GetTriangle(i).Normal ();20192020for (k = 1; k <= 3; k++)2021{2022int pi = GetTriangle(i).PNum(k);20232024normal_cnt.Elem(pi)++;2025SetNormal(pi, GetNormal(pi) + n);2026}2027}20282029//normalize the normals2030for (i = 1; i <= GetNP(); i++)2031{2032SetNormal(i,1./(double)normal_cnt.Get(i)*GetNormal(i));2033}20342035trigsconverted = 1;20362037vicinity.SetSize(GetNT());2038markedtrigs.SetSize(GetNT());2039for (i = 1; i <= GetNT(); i++)2040{2041markedtrigs.Elem(i) = 0;2042vicinity.Elem(i) = 1;2043}20442045ha_points.SetSize(GetNP());2046for (i = 1; i <= GetNP(); i++)2047ha_points.Elem(i) = 0;20482049calcedgedataanglesnew = 0;2050edgedatastored = 0;2051edgedata->Clear();205220532054if (GetStatus() == STL_ERROR) return;20552056CalcEdgeData();2057CalcEdgeDataAngles();20582059ClearLineEndPoints();20602061CheckGeometryOverlapping();2062}20632064void STLGeometry :: TopologyChanged()2065{2066calcedgedataanglesnew = 1;2067}20682069int STLGeometry :: CheckGeometryOverlapping()2070{2071int i, j, k;20722073Box<3> geombox = GetBoundingBox();2074Point<3> pmin = geombox.PMin();2075Point<3> pmax = geombox.PMax();20762077Box3dTree setree(pmin, pmax);2078ARRAY<int> inters;20792080int oltrigs = 0;2081markedtrigs.SetSize(GetNT());20822083for (i = 1; i <= GetNT(); i++)2084SetMarkedTrig(i, 0);20852086for (i = 1; i <= GetNT(); i++)2087{2088const STLTriangle & tri = GetTriangle(i);20892090Point<3> tpmin = tri.box.PMin();2091Point<3> tpmax = tri.box.PMax();2092Vec<3> diag = tpmax - tpmin;20932094tpmax = tpmax + 0.001 * diag;2095tpmin = tpmin - 0.001 * diag;20962097setree.Insert (tpmin, tpmax, i);2098}20992100for (i = 1; i <= GetNT(); i++)2101{2102const STLTriangle & tri = GetTriangle(i);21032104Point<3> tpmin = tri.box.PMin();2105Point<3> tpmax = tri.box.PMax();21062107setree.GetIntersecting (tpmin, tpmax, inters);21082109for (j = 1; j <= inters.Size(); j++)2110{2111const STLTriangle & tri2 = GetTriangle(inters.Get(j));21122113const Point<3> *trip1[3], *trip2[3];2114Point<3> hptri1[3], hptri2[3];2115/*2116for (k = 1; k <= 3; k++)2117{2118trip1[k-1] = &GetPoint (tri.PNum(k));2119trip2[k-1] = &GetPoint (tri2.PNum(k));2120}2121*/21222123for (k = 0; k < 3; k++)2124{2125hptri1[k] = GetPoint (tri[k]);2126hptri2[k] = GetPoint (tri2[k]);2127trip1[k] = &hptri1[k];2128trip2[k] = &hptri2[k];2129}21302131if (IntersectTriangleTriangle (&trip1[0], &trip2[0]))2132{2133oltrigs++;2134PrintMessage(5,"Intersecting Triangles: trig ",i," with ",inters.Get(j),"!");2135SetMarkedTrig(i, 1);2136SetMarkedTrig(inters.Get(j), 1);2137}2138}2139}21402141PrintMessage(3,"Check Geometry Overlapping: overlapping triangles = ",oltrigs);2142return oltrigs;2143}21442145/*2146void STLGeometry :: InitSTLGeometry()2147{2148STLTopology::InitSTLGeometry();21492150int i, j, k;21512152const double geometry_tol_fact = 1E8; //distances lower than max_box_size/tol are ignored215321542155trias.SetSize(0);2156points.SetSize(0);2157normals.SetSize(0);21582159ARRAY<int> normal_cnt; // counts number of added normals in a point21602161Box3d bb (GetBoundingBox().PMin() + Vec3d (-1,-1,-1),2162GetBoundingBox().PMax() + Vec3d (1, 1, 1));21632164Point3dTree pointtree (bb.PMin(),2165bb.PMax());2166ARRAY<int> pintersect;21672168double gtol = GetBoundingBox().CalcDiam()/geometry_tol_fact;21692170for(i = 1; i <= GetReadNT(); i++)2171{2172//if (i%500==499) {(*mycout) << (double)i/(double)GetReadNT()*100. << "%" << endl;}21732174STLReadTriangle t = GetReadTriangle(i);2175STLTriangle st;2176Vec3d n = t.normal;21772178for (k = 0; k < 3; k++)2179{2180Point3d p = t.pts[k];21812182Point3d pmin = p - Vec3d (gtol, gtol, gtol);2183Point3d pmax = p + Vec3d (gtol, gtol, gtol);21842185pointtree.GetIntersecting (pmin, pmax, pintersect);21862187if (pintersect.Size() > 1)2188(*mycout) << "found too much " << char(7) << endl;2189int foundpos = 0;2190if (pintersect.Size())2191foundpos = pintersect.Get(1);21922193if (foundpos)2194{2195normal_cnt[foundpos]++;2196SetNormal(foundpos,GetNormal(foundpos)+n);2197// (*testout) << "found p " << p << endl;2198}2199else2200{2201foundpos = AddPoint(p);2202AddNormal(n);2203normal_cnt.Append(1);22042205pointtree.Insert (p, foundpos);2206}2207//(*mycout) << "foundpos=" << foundpos << endl;2208st.pts[k] = foundpos;2209}22102211if ( (st.pts[0] == st.pts[1]) ||2212(st.pts[0] == st.pts[2]) ||2213(st.pts[1] == st.pts[2]) )2214{2215(*mycout) << "ERROR: STL Triangle degenerated" << endl;2216}2217else2218{2219// do not add ? js2220AddTriangle(st);2221}2222//(*mycout) << "TRIG" << i << " = " << st << endl;22232224}2225//normal the normals2226for (i = 1; i <= GetNP(); i++)2227{2228SetNormal(i,1./(double)normal_cnt[i]*GetNormal(i));2229}22302231trigsconverted = 1;22322233vicinity.SetSize(GetNT());2234markedtrigs.SetSize(GetNT());2235for (i = 1; i <= GetNT(); i++)2236{2237markedtrigs.Elem(i) = 0;2238vicinity.Elem(i) = 1;2239}22402241ha_points.SetSize(GetNP());2242for (i = 1; i <= GetNP(); i++)2243ha_points.Elem(i) = 0;22442245calcedgedataanglesnew = 0;2246edgedatastored = 0;2247edgedata->Clear();22482249CalcEdgeData();2250CalcEdgeDataAngles();22512252ClearLineEndPoints();22532254(*mycout) << "done" << endl;2255}2256*/2257225822592260void STLGeometry :: SetLineEndPoint(int pn)2261{2262if (pn <1 || pn > lineendpoints.Size()) {PrintSysError("Illegal pnum in SetLineEndPoint!!!"); return; }2263lineendpoints.Elem(pn) = 1;2264}22652266int STLGeometry :: IsLineEndPoint(int pn)2267{2268// return 0;2269if (pn <1 || pn > lineendpoints.Size())2270{PrintSysError("Illegal pnum in IsLineEndPoint!!!"); return 0;}2271return lineendpoints.Get(pn);2272}22732274void STLGeometry :: ClearLineEndPoints()2275{2276lineendpoints.SetSize(GetNP());2277int i;2278for (i = 1; i <= GetNP(); i++)2279{2280lineendpoints.Elem(i) = 0;2281}2282}22832284int STLGeometry :: IsEdge(int ap1, int ap2)2285{2286int i,j;2287for (i = 1; i <= GetNEPP(ap1); i++)2288{2289for (j = 1; j <= GetNEPP(ap2); j++)2290{2291if (GetEdgePP(ap1,i) == GetEdgePP(ap2,j)) {return 1;}2292}2293}2294return 0;2295}22962297int STLGeometry :: IsEdgeNum(int ap1, int ap2)2298{2299int i,j;2300for (i = 1; i <= GetNEPP(ap1); i++)2301{2302for (j = 1; j <= GetNEPP(ap2); j++)2303{2304if (GetEdgePP(ap1,i) == GetEdgePP(ap2,j)) {return GetEdgePP(ap1,i);}2305}2306}2307return 0;2308}230923102311void STLGeometry :: BuildEdges()2312{2313//PrintFnStart("build edges");2314edges.SetSize(0);2315meshlines.SetSize(0);2316FindEdgesFromAngles();2317}23182319void STLGeometry :: UseExternalEdges()2320{2321int i;2322for (i = 1; i <= NOExternalEdges(); i++)2323{2324AddEdge(GetExternalEdge(i).i1,GetExternalEdge(i).i2);2325}2326//BuildEdgesPerPointy();2327}23282329void STLGeometry :: UndoEdgeChange()2330{2331if (edgedatastored)2332{2333RestoreEdgeData();2334}2335else2336{2337PrintWarning("no edge undo possible");2338}2339}234023412342void STLGeometry :: StoreEdgeData()2343{2344// edgedata_store = *edgedata;23452346edgedata->Store();2347edgedatastored = 1;23482349// put stlgeom-edgedata to stltopology edgedata2350/*2351int i;2352for (i = 1; i <= GetNTE(); i++)2353{2354const STLTopEdge & topedge = GetTopEdge (i);2355int ednum = edgedata->GetEdgeNum (topedge.PNum(1),2356topedge.PNum(2));2357topedges.Elem(i).SetStatus (edgedata->Get (ednum).status);2358}2359*/2360}23612362void STLGeometry :: RestoreEdgeData()2363{2364// *edgedata = edgedata_store;2365edgedata->Restore();2366edgedatastored=0;2367}236823692370void STLGeometry :: CalcEdgeData()2371{2372PushStatus("Calc Edge Data");23732374int np1, np2;2375int i;23762377int ecnt = 0;2378edgedata->SetSize(GetNT()/2*3);23792380for (i = 1; i <= GetNT(); i++)2381{2382SetThreadPercent((double)i/(double)GetNT()*100.);23832384const STLTriangle & t1 = GetTriangle(i);23852386for (int j = 1; j <= NONeighbourTrigs(i); j++)2387{2388int nbti = NeighbourTrig(i,j);2389if (nbti > i)2390{2391const STLTriangle & t2 = GetTriangle(nbti);23922393if (t1.IsNeighbourFrom(t2))2394{2395ecnt++; if (ecnt > edgedata->Size()) {PrintError("In Calc edge data, illegal geometry");}23962397t1.GetNeighbourPoints(t2,np1,np2);23982399/* ang = GetAngle(i,nbti);2400if (ang < -M_PI) {ang += 2*M_PI;}*/240124022403// edgedata->Add(STLEdgeData(0, np1, np2, i, nbti),ecnt);2404edgedata->Elem(ecnt).SetStatus(ED_UNDEFINED);24052406// edgedata->Elem(ecnt).top = this;2407// edgedata->Elem(ecnt).topedgenr = GetTopEdgeNum (np1, np2);2408}2409}2410}2411}24122413//BuildEdgesPerPoint();2414PopStatus();2415}24162417void STLGeometry :: CalcEdgeDataAngles()2418{2419PrintMessage(5,"calc edge data angles");24202421int i;24222423for (i = 1; i <= GetNTE(); i++)2424{2425STLTopEdge & edge = GetTopEdge (i);2426double cosang =2427GetTriangle(edge.TrigNum(1)).Normal() *2428GetTriangle(edge.TrigNum(2)).Normal();2429edge.SetCosAngle (cosang);2430}24312432for (i = 1; i <= edgedata->Size(); i++)2433{2434/*2435const STLEdgeData& e = edgedata->Get(i);2436ang = GetAngle(e.lt,e.rt);2437if (ang < -M_PI) {ang += 2*M_PI;}2438edgedata->Elem(i).angle = fabs(ang);2439*/2440}24412442}24432444void STLGeometry :: FindEdgesFromAngles()2445{2446// PrintFnStart("find edges from angles");24472448double min_edge_angle = stlparam.yangle/180.*M_PI;2449double cont_min_edge_angle = stlparam.contyangle/180.*M_PI;24502451double cos_min_edge_angle = cos (min_edge_angle);2452double cos_cont_min_edge_angle = cos (cont_min_edge_angle);24532454if (calcedgedataanglesnew) {CalcEdgeDataAngles(); calcedgedataanglesnew = 0;}24552456int i;2457for (i = 1; i <= edgedata->Size(); i++)2458{2459STLTopEdge & sed = edgedata->Elem(i);2460if (sed.GetStatus() == ED_CANDIDATE ||2461sed.GetStatus() == ED_UNDEFINED)2462{2463if (sed.CosAngle() <= cos_min_edge_angle)2464{2465sed.SetStatus (ED_CANDIDATE);2466}2467else2468{2469sed.SetStatus(ED_UNDEFINED);2470}2471}2472}24732474if (stlparam.contyangle < stlparam.yangle)2475{2476int changed = 1;2477int its = 0;2478while (changed && stlparam.contyangle < stlparam.yangle)2479{2480its++;2481//(*mycout) << "." << flush;2482changed = 0;2483for (i = 1; i <= edgedata->Size(); i++)2484{2485STLTopEdge & sed = edgedata->Elem(i);2486if (sed.CosAngle() <= cos_cont_min_edge_angle2487&& sed.GetStatus() == ED_UNDEFINED &&2488(edgedata->GetNConfCandEPP(sed.PNum(1)) == 1 ||2489edgedata->GetNConfCandEPP(sed.PNum(2)) == 1))2490{2491changed = 1;2492sed.SetStatus (ED_CANDIDATE);2493}2494}2495}2496}24972498int confcand = 0;2499if (edgedata->GetNConfEdges() == 0)2500{2501confcand = 1;2502}25032504for (i = 1; i <= edgedata->Size(); i++)2505{2506STLTopEdge & sed = edgedata->Elem(i);2507if (sed.GetStatus() == ED_CONFIRMED ||2508(sed.GetStatus() == ED_CANDIDATE && confcand))2509{2510STLEdge se(sed.PNum(1),sed.PNum(2));2511se.SetLeftTrig(sed.TrigNum(1));2512se.SetRightTrig(sed.TrigNum(2));2513AddEdge(se);2514}2515}2516BuildEdgesPerPoint();2517251825192520//(*mycout) << "its for continued angle = " << its << endl;2521PrintMessage(5,"built ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree");25222523}25242525/*2526void STLGeometry :: FindEdgesFromAngles()2527{2528double yangle = stlparam.yangle;2529char * savetask = multithread.task;2530multithread.task = "find edges";25312532const double min_edge_angle = yangle/180.*M_PI;25332534int np1, np2;2535double ang;2536int i;25372538//(*mycout) << "area=" << Area() << endl;25392540for (i = 1; i <= GetNT(); i++)2541{2542multithread.percent = (double)i/(double)GetReadNT()*100.;25432544const STLTriangle & t1 = GetTriangle(i);2545//NeighbourTrigs(nt,i);25462547for (int j = 1; j <= NONeighbourTrigs(i); j++)2548{2549int nbti = NeighbourTrig(i,j);2550if (nbti > i)2551{2552const STLTriangle & t2 = GetTriangle(nbti);25532554if (t1.IsNeighbourFrom(t2))2555{2556ang = GetAngle(i,nbti);2557if (ang < -M_PI*0.5) {ang += 2*M_PI;}25582559t1.GetNeighbourPoints(t2,np1,np2);25602561if (fabs(ang) >= min_edge_angle)2562{2563STLEdge se(np1,np2);2564se.SetLeftTrig(i);2565se.SetRightTrig(nbti);2566AddEdge(se);2567}2568}2569}2570}2571}25722573(*mycout) << "added " << GetNE() << " edges" << endl;25742575//BuildEdgesPerPoint();25762577multithread.percent = 100.;2578multithread.task = savetask;25792580}2581*/2582void STLGeometry :: BuildEdgesPerPoint()2583{2584//cout << "*** build edges per point" << endl;2585edgesperpoint.SetSize(GetNP());25862587//add edges to points2588int i;2589for (i = 1; i <= GetNE(); i++)2590{2591//(*mycout) << "EDGE " << GetEdge(i).PNum(1) << " - " << GetEdge(i).PNum(2) << endl;2592for (int j = 1; j <= 2; j++)2593{2594AddEdgePP(GetEdge(i).PNum(j),i);2595}2596}2597}25982599void STLGeometry :: AddFaceEdges()2600{2601PrintFnStart("Add starting edges for faces");26022603//f�r Kugel eine STLLine hinzuf�gen (Vorteil: verfeinerbar, unabh�ngig von Aufl�sung der Geometrie!!!):2604//Grenze von 1. gefundener chart26052606ARRAY<int> edgecnt;2607ARRAY<int> chartindex;2608edgecnt.SetSize(GetNOFaces());2609chartindex.SetSize(GetNOFaces());26102611int i,j;2612for (i = 1; i <= GetNOFaces(); i++)2613{2614edgecnt.Elem(i) = 0;2615chartindex.Elem(i) = 0;2616}26172618for (i = 1; i <= GetNT(); i++)2619{2620int fn = GetTriangle(i).GetFaceNum();2621if (!chartindex.Get(fn)) {chartindex.Elem(fn) = GetChartNr(i);}2622for (j = 1; j <= 3; j++)2623{2624edgecnt.Elem(fn) += GetNEPP(GetTriangle(i).PNum(j));2625}2626}26272628for (i = 1; i <= GetNOFaces(); i++)2629{2630if (!edgecnt.Get(i)) {PrintMessage(5,"Face", i, " has no edge!");}2631}26322633int changed = 0;2634int k, ap1, ap2;2635for (i = 1; i <= GetNOFaces(); i++)2636{2637if (!edgecnt.Get(i))2638{2639const STLChart& c = GetChart(chartindex.Get(i));2640for (j = 1; j <= c.GetNChartT(); j++)2641{2642const STLTriangle& t1 = GetTriangle(c.GetChartTrig(j));2643for (k = 1; k <= 3; k++)2644{2645int nt = NeighbourTrig(c.GetChartTrig(j),k);2646if (GetChartNr(nt) != chartindex.Get(i))2647{2648t1.GetNeighbourPoints(GetTriangle(nt),ap1,ap2);2649AddEdge(ap1,ap2);2650changed = 1;2651}2652}2653}2654}26552656}26572658if (changed) BuildEdgesPerPoint();26592660}26612662void STLGeometry :: LinkEdges()2663{2664PushStatusF("Link Edges");2665PrintMessage(5,"have now ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree");26662667int i;26682669lines.SetSize(0);2670int starte(0);2671int edgecnt = 0;2672int found;2673int rev(0); //indicates, that edge is inserted reverse26742675//worked edges2676ARRAY<int> we(GetNE());26772678//setlineendpoints; wenn 180�, dann keine endpunkte2679//nur punkte mit 2 edges kommen in frage, da bei mehr oder weniger punkten ohnehin ein meshpoint hinkommt26802681Vec3d v1,v2;2682double cos_eca = cos(stlparam.edgecornerangle/180.*M_PI);2683int ecnt = 0;2684int lp1, lp2;2685if (stlparam.edgecornerangle < 180)2686{2687for (i = 1; i <= GetNP(); i++)2688{2689if (GetNEPP(i) == 2)2690{2691if (GetEdge(GetEdgePP(i,1)).PNum(2) == GetEdge(GetEdgePP(i,2)).PNum(1) ||2692GetEdge(GetEdgePP(i,1)).PNum(1) == GetEdge(GetEdgePP(i,2)).PNum(2))2693{2694lp1 = 1; lp2 = 2;2695}2696else2697{2698lp1 = 2; lp2 = 1;2699}27002701v1 = Vec3d(GetPoint(GetEdge(GetEdgePP(i,1)).PNum(1)),2702GetPoint(GetEdge(GetEdgePP(i,1)).PNum(2)));2703v2 = Vec3d(GetPoint(GetEdge(GetEdgePP(i,2)).PNum(lp1)),2704GetPoint(GetEdge(GetEdgePP(i,2)).PNum(lp2)));2705if ((v1*v2)/sqrt(v1.Length2()*v2.Length2()) < cos_eca)2706{2707//(*testout) << "add edgepoint " << i << endl;2708SetLineEndPoint(i);2709ecnt++;2710}2711}2712}2713}2714PrintMessage(5, "added ", ecnt, " mesh_points due to edge corner angle (",2715stlparam.edgecornerangle, " degree)");27162717for (i = 1; i <= GetNE(); i++) {we.Elem(i) = 0;}27182719while(edgecnt < GetNE())2720{2721SetThreadPercent((double)edgecnt/(double)GetNE()*100.);27222723STLLine* line = new STLLine(this);27242725//find start edge2726int j = 1;2727found = 0;2728//try second time, if only rings are left!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!2729int second = 0;27302731//find a starting edge at point with 1 or more than 2 edges or at lineendpoint2732while (!found && j<=GetNE())2733{2734if (!we.Get(j))2735{2736if (GetNEPP(GetEdge(j).PNum(1)) != 2 || IsLineEndPoint(GetEdge(j).PNum(1)))2737{2738starte = j;2739found = 1;2740rev = 0;2741}2742else2743if (GetNEPP(GetEdge(j).PNum(2)) != 2 || IsLineEndPoint(GetEdge(j).PNum(2)))2744{2745starte = j;2746found = 1;2747rev = 1;2748}2749else if (second)2750{2751starte = j;2752found = 1;2753rev = 0; //0 or 1 are possible2754}2755}2756j++;2757if (!second && j == GetNE()) {second = 1; j = 1;}2758}27592760if (!found) {PrintSysError("No starting edge found, edgecnt=", edgecnt, ", GETNE=", GetNE());}27612762line->AddPoint(GetEdge(starte).PNum(1+rev));2763line->AddPoint(GetEdge(starte).PNum(2-rev));2764if (!rev)2765{2766line->AddLeftTrig(GetEdge(starte).LeftTrig());2767line->AddRightTrig(GetEdge(starte).RightTrig());2768}2769else2770{2771line->AddLeftTrig(GetEdge(starte).RightTrig());2772line->AddRightTrig(GetEdge(starte).LeftTrig());2773}2774edgecnt++; we.Elem(starte) = 1;27752776//add segments to line as long as segments other than starting edge are found or lineendpoint is reached2777found = 1;2778int other;2779while(found)2780{2781found = 0;2782int fp = GetEdge(starte).PNum(2-rev);2783if (GetNEPP(fp) == 2 && !IsLineEndPoint(fp))2784{2785//find the "other" edge of point fp2786other = 0;2787if (GetEdgePP(fp,1) == starte) {other = 1;}27882789starte = GetEdgePP(fp,1+other);27902791//falls ring -> aufhoeren !!!!!!!!!!!2792if (!we.Elem(starte))2793{2794found = 1;2795rev = 0;2796if (GetEdge(starte).PNum(2) == fp) {rev = 1;}2797else if (GetEdge(starte).PNum(1) != fp) {PrintSysError("In Link Edges!");}27982799line->AddPoint(GetEdge(starte).PNum(2-rev));2800if (!rev)2801{2802line->AddLeftTrig(GetEdge(starte).LeftTrig());2803line->AddRightTrig(GetEdge(starte).RightTrig());2804}2805else2806{2807line->AddLeftTrig(GetEdge(starte).RightTrig());2808line->AddRightTrig(GetEdge(starte).LeftTrig());2809}2810edgecnt++; we.Elem(starte) = 1;2811}2812}2813}2814AddLine(line);2815}2816PrintMessage(5,"number of lines generated = ", GetNLines());28172818//check, which lines must have at least one midpoint2819INDEX_2_HASHTABLE<int> lineht(GetNLines()+1);28202821for (i = 1; i <= GetNLines(); i++)2822{2823if (GetLine(i)->StartP() == GetLine(i)->EndP())2824{2825GetLine(i)->DoSplit();2826}2827}28282829for (i = 1; i <= GetNLines(); i++)2830{2831INDEX_2 lineep (GetLine(i)->StartP(),GetLine(i)->EndP());2832lineep.Sort();28332834if (lineht.Used (lineep))2835{2836GetLine(i)->DoSplit();2837int other = lineht.Get(lineep);2838GetLine(other)->DoSplit();2839}2840else2841{2842lineht.Set (lineep, i);2843}2844}28452846for (i = 1; i <= GetNLines(); i++)2847{2848STLLine* line = GetLine(i);2849for (int ii = 1; ii <= line->GetNS(); ii++)2850{2851int ap1, ap2;2852line->GetSeg(ii,ap1,ap2);2853// (*mycout) << "SEG " << p1 << " - " << p2 << endl;2854}2855}28562857PopStatus();2858}28592860int STLGeometry :: GetNOBodys()2861{2862int markedtrigs1 = 0;2863int starttrig = 1;2864int i, k, nnt;2865int bodycnt = 0;28662867ARRAY<int> bodynum(GetNT());28682869for (i = 1; i <= GetNT(); i++)2870bodynum.Elem(i)=0;287128722873while (markedtrigs1 < GetNT())2874{2875for (i = starttrig; i <= GetNT(); i++)2876{2877if (!bodynum.Get(i))2878{2879starttrig = i;2880break;2881}2882}2883//add all triangles around starttriangle, which is reachable without going over an edge2884ARRAY<int> todolist;2885ARRAY<int> nextlist;2886bodycnt++;2887markedtrigs1++;2888bodynum.Elem(starttrig) = bodycnt;2889todolist.Append(starttrig);28902891while(todolist.Size())2892{2893for (i = 1; i <= todolist.Size(); i++)2894{2895//const STLTriangle& tt = GetTriangle(todolist.Get(i));2896for (k = 1; k <= NONeighbourTrigs(todolist.Get(i)); k++)2897{2898nnt = NeighbourTrig(todolist.Get(i),k);2899if (!bodynum.Get(nnt))2900{2901nextlist.Append(nnt);2902bodynum.Elem(nnt) = bodycnt;2903markedtrigs1++;2904}2905}2906}29072908todolist.SetSize(0);2909for (i = 1; i <= nextlist.Size(); i++)2910{2911todolist.Append(nextlist.Get(i));2912}2913nextlist.SetSize(0);2914}2915}2916PrintMessage(3, "Geometry has ", bodycnt, " separated bodys");29172918return bodycnt;2919}29202921void STLGeometry :: CalcFaceNums()2922{2923int markedtrigs1 = 0;2924int starttrig(0);2925int laststarttrig = 1;2926int i, k, nnt;2927facecnt = 0;292829292930for (i = 1; i <= GetNT(); i++)2931GetTriangle(i).SetFaceNum(0);293229332934while (markedtrigs1 < GetNT())2935{2936for (i = laststarttrig; i <= GetNT(); i++)2937{2938if (!GetTriangle(i).GetFaceNum())2939{2940starttrig = i;2941laststarttrig = i;2942break;2943}2944}2945//add all triangles around starttriangle, which is reachable without going over an edge2946ARRAY<int> todolist;2947ARRAY<int> nextlist;2948facecnt++;2949markedtrigs1++;2950GetTriangle(starttrig).SetFaceNum(facecnt);2951todolist.Append(starttrig);2952int ap1, ap2;29532954while(todolist.Size())2955{2956for (i = 1; i <= todolist.Size(); i++)2957{2958const STLTriangle& tt = GetTriangle(todolist.Get(i));2959for (k = 1; k <= NONeighbourTrigs(todolist.Get(i)); k++)2960{2961nnt = NeighbourTrig(todolist.Get(i),k);2962STLTriangle& nt = GetTriangle(nnt);2963if (!nt.GetFaceNum())2964{2965tt.GetNeighbourPoints(nt,ap1,ap2);2966if (!IsEdge(ap1,ap2))2967{2968nextlist.Append(nnt);2969nt.SetFaceNum(facecnt);2970markedtrigs1++;2971}2972}2973}2974}29752976todolist.SetSize(0);2977for (i = 1; i <= nextlist.Size(); i++)2978{2979todolist.Append(nextlist.Get(i));2980}2981nextlist.SetSize(0);2982}2983}2984GetNOBodys();2985PrintMessage(3,"generated ", facecnt, " faces");2986}29872988void STLGeometry :: ClearSpiralPoints()2989{2990spiralpoints.SetSize(GetNP());2991int i;2992for (i = 1; i <= spiralpoints.Size(); i++)2993{2994spiralpoints.Elem(i) = 0;2995}2996}299729982999void STLGeometry :: BuildSmoothEdges ()3000{3001if (smoothedges) delete smoothedges;30023003smoothedges = new INDEX_2_HASHTABLE<int> (GetNE()/10 + 1);300430053006// Jack: Ok ?3007// UseExternalEdges();30083009PushStatusF("Build Smooth Edges");30103011int i, j;//, k, l;3012int nt = GetNT();3013Vec3d ng1, ng2;30143015for (i = 1; i <= nt; i++)3016{3017if (multithread.terminate)3018{PopStatus();return;}30193020SetThreadPercent(100.0 * (double)i / (double)nt);30213022const STLTriangle & trig = GetTriangle (i);30233024ng1 = trig.GeomNormal(points);3025ng1 /= (ng1.Length() + 1e-24);30263027for (j = 1; j <= 3; j++)3028{3029int nbt = NeighbourTrig (i, j);30303031ng2 = GetTriangle(nbt).GeomNormal(points);3032ng2 /= (ng2.Length() + 1e-24);303330343035int pi1, pi2;30363037trig.GetNeighbourPoints(GetTriangle(nbt), pi1, pi2);30383039if (!IsEdge(pi1,pi2))3040{3041if (ng1 * ng2 < 0)3042{3043PrintMessage(7,"smoothedge found");3044INDEX_2 i2(pi1, pi2);3045i2.Sort();3046smoothedges->Set (i2, 1);3047}3048}3049}3050}30513052PopStatus();3053}305430553056305730583059int STLGeometry :: IsSmoothEdge (int pi1, int pi2) const3060{3061if (!smoothedges)3062return 0;3063INDEX_2 i2(pi1, pi2);3064i2.Sort();3065return smoothedges->Used (i2);3066}30673068306930703071//function is not used now3072int IsInArray(int n, const ARRAY<int>& ia)3073{3074int i;3075for (i = 1; i <= ia.Size(); i++)3076{3077if (ia.Get(i) == n) {return 1;}3078}3079return 0;3080}30813082void STLGeometry :: AddConeAndSpiralEdges()3083{3084PrintMessage(5,"have now ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree");30853086PrintFnStart("AddConeAndSpiralEdges");30873088int i,j,k,n;3089// int changed = 0;30903091//check edges, where inner chart and no outer chart come together without an edge3092int np1, np2, nt;3093int cnt = 0;30943095for (i = 1; i <= GetNOCharts(); i++)3096{3097STLChart& chart = GetChart(i);3098for (j = 1; j <= chart.GetNChartT(); j++)3099{3100int t = chart.GetChartTrig(j);3101const STLTriangle& tt = GetTriangle(t);31023103for (k = 1; k <= 3; k++)3104{3105nt = NeighbourTrig(t,k);3106if (GetChartNr(nt) != i && !TrigIsInOC(nt,i))3107{3108tt.GetNeighbourPoints(GetTriangle(nt),np1,np2);3109if (!IsEdge(np1,np2))3110{3111STLEdge se(np1,np2);3112se.SetLeftTrig(t);3113se.SetRightTrig(nt);3114int edgenum = AddEdge(se);3115AddEdgePP(np1,edgenum);3116AddEdgePP(np2,edgenum);3117//changed = 1;3118PrintWarning("Found a spiral like structure: chart=", i,3119", trig=", t, ", p1=", np1, ", p2=", np2);3120cnt++;3121}3122}3123}3124}31253126}31273128PrintMessage(5, "found ", cnt, " spiral like structures");3129PrintMessage(5, "added ", cnt, " edges due to spiral like structures");31303131cnt = 0;3132int edgecnt = 0;31333134ARRAY<int> trigsaroundp;3135ARRAY<int> chartpointchecked; //gets number of chart, if in this chart already checked3136chartpointchecked.SetSize(GetNP());31373138for (i = 1; i <= GetNP(); i++)3139{3140chartpointchecked.Elem(i) = 0;3141}31423143int onoc, notonoc, tpp, pn;3144int ap1, ap2, tn1, tn2, l, problem;31453146if (!stldoctor.conecheck) {PrintWarning("++++++++++++ \ncone checking deactivated by user!!!!!\n+++++++++++++++"); return ;}31473148PushStatus("Find Critical Points");31493150int addedges = 0;31513152for (i = 1; i <= GetNOCharts(); i++)3153{3154SetThreadPercent((double)i/(double)GetNOCharts()*100.);3155if (multithread.terminate)3156{PopStatus();return;}31573158STLChart& chart = GetChart(i);3159for (j = 1; j <= chart.GetNChartT(); j++)3160{3161int t = chart.GetChartTrig(j);3162const STLTriangle& tt = GetTriangle(t);31633164for (k = 1; k <= 3; k++)3165{3166pn = tt.PNum(k);3167if (chartpointchecked.Get(pn) == i)3168{continue;}31693170int checkpoint = 0;3171for (n = 1; n <= trigsperpoint.EntrySize(pn); n++)3172{3173if (trigsperpoint.Get(pn,n) != t &&3174GetChartNr(trigsperpoint.Get(pn,n)) != i &&3175!TrigIsInOC(trigsperpoint.Get(pn,n),i)) {checkpoint = 1;};3176}3177if (checkpoint)3178{3179chartpointchecked.Elem(pn) = i;31803181int worked = 0;3182int spworked = 0;3183GetSortedTrianglesAroundPoint(pn,t,trigsaroundp);3184trigsaroundp.Append(t);31853186problem = 0;3187for (l = 2; l <= trigsaroundp.Size()-1; l++)3188{3189tn1 = trigsaroundp.Get(l-1);3190tn2 = trigsaroundp.Get(l);3191const STLTriangle& t1 = GetTriangle(tn1);3192const STLTriangle& t2 = GetTriangle(tn2);3193t1.GetNeighbourPoints(t2, ap1, ap2);3194if (IsEdge(ap1,ap2)) break;31953196if (GetChartNr(tn2) != i && !TrigIsInOC(tn2,i)) {problem = 1;}3197}31983199if (problem)3200{3201for (l = 2; l <= trigsaroundp.Size()-1; l++)3202{3203tn1 = trigsaroundp.Get(l-1);3204tn2 = trigsaroundp.Get(l);3205const STLTriangle& t1 = GetTriangle(tn1);3206const STLTriangle& t2 = GetTriangle(tn2);3207t1.GetNeighbourPoints(t2, ap1, ap2);3208if (IsEdge(ap1,ap2)) break;32093210if ((GetChartNr(tn1) == i && GetChartNr(tn2) != i && TrigIsInOC(tn2,i)) ||3211(GetChartNr(tn2) == i && GetChartNr(tn1) != i && TrigIsInOC(tn1,i)))3212{3213if (addedges || !GetNEPP(pn))3214{3215STLEdge se(ap1,ap2);3216se.SetLeftTrig(tn1);3217se.SetRightTrig(tn2);3218int edgenum = AddEdge(se);3219AddEdgePP(ap1,edgenum);3220AddEdgePP(ap2,edgenum);3221edgecnt++;3222}3223if (!addedges && !GetSpiralPoint(pn))3224{3225SetSpiralPoint(pn);3226spworked = 1;3227}3228worked = 1;3229}3230}3231}3232//backwards:3233problem = 0;3234for (l = trigsaroundp.Size()-1; l >= 2; l--)3235{3236tn1 = trigsaroundp.Get(l+1);3237tn2 = trigsaroundp.Get(l);3238const STLTriangle& t1 = GetTriangle(tn1);3239const STLTriangle& t2 = GetTriangle(tn2);3240t1.GetNeighbourPoints(t2, ap1, ap2);3241if (IsEdge(ap1,ap2)) break;32423243if (GetChartNr(tn2) != i && !TrigIsInOC(tn2,i)) {problem = 1;}3244}3245if (problem)3246for (l = trigsaroundp.Size()-1; l >= 2; l--)3247{3248tn1 = trigsaroundp.Get(l+1);3249tn2 = trigsaroundp.Get(l);3250const STLTriangle& t1 = GetTriangle(tn1);3251const STLTriangle& t2 = GetTriangle(tn2);3252t1.GetNeighbourPoints(t2, ap1, ap2);3253if (IsEdge(ap1,ap2)) break;32543255if ((GetChartNr(tn1) == i && GetChartNr(tn2) != i && TrigIsInOC(tn2,i)) ||3256(GetChartNr(tn2) == i && GetChartNr(tn1) != i && TrigIsInOC(tn1,i)))3257{3258if (addedges || !GetNEPP(pn))3259{3260STLEdge se(ap1,ap2);3261se.SetLeftTrig(tn1);3262se.SetRightTrig(tn2);3263int edgenum = AddEdge(se);3264AddEdgePP(ap1,edgenum);3265AddEdgePP(ap2,edgenum);3266edgecnt++;3267}3268if (!addedges && !GetSpiralPoint(pn))3269{3270SetSpiralPoint(pn);3271spworked = 1;3272//if (GetNEPP(pn) == 0) {(*mycout) << "ERROR: spiralpoint with no edge found!" << endl;}3273}3274worked = 1;3275}3276}32773278if (worked)3279{3280//(*testout) << "set edgepoint due to spirals: pn=" << i << endl;3281SetLineEndPoint(pn);3282}3283if (spworked)3284{3285/*3286(*mycout) << "Warning: Critical Point " << tt.PNum(k)3287<< "( chart " << i << ", trig " << t3288<< ") has been neutralized!!!" << endl;3289*/3290cnt++;3291}3292// markedpoints.Elem(tt.PNum(k)) = 1;3293}3294}3295}3296}3297PrintMessage(5, "found ", cnt, " critical points!");3298PrintMessage(5, "added ", edgecnt, " edges due to critical points!");32993300PopStatus();33013302//search points where inner chart and outer chart and "no chart" trig come together at edge-point33033304PrintMessage(7,"search for special chart points");3305for (i = 1; i <= GetNOCharts(); i++)3306{3307STLChart& chart = GetChart(i);3308for (j = 1; j <= chart.GetNChartT(); j++)3309{3310int t = chart.GetChartTrig(j);3311const STLTriangle& tt = GetTriangle(t);33123313for (k = 1; k <= 3; k++)3314{3315pn = tt.PNum(k);3316if (GetNEPP(pn) == 2)3317{3318onoc = 0;3319notonoc = 0;3320for (n = 1; n <= trigsperpoint.EntrySize(pn); n++)3321{3322tpp = trigsperpoint.Get(pn,n);3323if (tpp != t && GetChartNr(tpp) != i)3324{3325if (TrigIsInOC(tpp,i)) {onoc = 1;}3326if (!TrigIsInOC(tpp,i)) {notonoc = 1;}3327}3328}3329if (onoc && notonoc && !IsLineEndPoint(pn))3330{3331GetSortedTrianglesAroundPoint(pn,t,trigsaroundp);3332int here = 1; //we start on this side of edge, !here = there3333int thereOC = 0;3334int thereNotOC = 0;3335for (l = 2; l <= trigsaroundp.Size(); l++)3336{3337GetTriangle(trigsaroundp.Get(l-1)).3338GetNeighbourPoints(GetTriangle(trigsaroundp.Get(l)), ap1, ap2);3339if (IsEdge(ap1,ap2)) {here = (here+1)%2;}3340if (!here && TrigIsInOC(trigsaroundp.Get(l),i)) {thereOC = 1;}3341if (!here && !TrigIsInOC(trigsaroundp.Get(l),i)) {thereNotOC = 1;}3342}3343if (thereOC && thereNotOC)3344{3345//(*mycout) << "Special OCICnotC - point " << pn << " found!" << endl;3346//(*testout) << "set edgepoint due to spirals: pn=" << i << endl;3347SetLineEndPoint(pn);3348}3349}3350}3351}3352}3353}3354PrintMessage(5,"have now ", GetNE(), " edges with yellow angle = ", stlparam.yangle, " degree");3355}33563357//get trigs at a point, started with starttrig, then every left3358void STLGeometry :: GetSortedTrianglesAroundPoint(int p, int starttrig, ARRAY<int>& trigs)3359{3360int acttrig = starttrig;3361trigs.SetAllocSize(trigsperpoint.EntrySize(p));3362trigs.SetSize(0);3363trigs.Append(acttrig);3364int i, j, t, ap1, ap2, locindex1(0), locindex2(0);33653366//(*mycout) << "trigs around point " << p << endl;33673368int end = 0;3369while (!end)3370{3371const STLTriangle& at = GetTriangle(acttrig);3372for (i = 1; i <= trigsperpoint.EntrySize(p); i++)3373{3374t = trigsperpoint.Get(p,i);3375const STLTriangle& nt = GetTriangle(t);3376if (at.IsNeighbourFrom(nt))3377{3378at.GetNeighbourPoints(nt, ap1, ap2);3379if (ap2 == p) {Swap(ap1,ap2);}3380if (ap1 != p) {PrintSysError("In GetSortedTrianglesAroundPoint!!!");}33813382for (j = 1; j <= 3; j++)3383{3384if (at.PNum(j) == ap1) {locindex1 = j;};3385if (at.PNum(j) == ap2) {locindex2 = j;};3386}3387if ((locindex2+1)%3+1 == locindex1)3388{3389if (t != starttrig)3390{3391trigs.Append(t);3392// (*mycout) << "trig " << t << endl;3393acttrig = t;3394}3395else3396{3397end = 1;3398}3399break;3400}3401}3402}3403}34043405}34063407/*3408int STLGeometry :: NeighbourTrig(int trig, int nr) const3409{3410return neighbourtrigs.Get(trig,nr);3411}3412*/3413341434153416void STLGeometry :: SmoothGeometry ()3417{3418int i, j, k;34193420double maxerr0, maxerr;34213422for (i = 1; i <= GetNP(); i++)3423{3424if (GetNEPP(i)) continue;34253426maxerr0 = 0;3427for (j = 1; j <= NOTrigsPerPoint(i); j++)3428{3429int tnum = TrigPerPoint(i, j);3430double err = Angle (GetTriangle(tnum).Normal (),3431GetTriangle(tnum).GeomNormal(GetPoints()));3432if (err > maxerr0)3433maxerr0 = err;3434}34353436Point3d pi = GetPoint (i);3437if (maxerr0 < 1.1) continue; // about 60 degree34383439maxerr0 /= 2; // should be at least halfen34403441for (k = 1; k <= NOTrigsPerPoint(i); k++)3442{3443const STLTriangle & trig = GetTriangle (TrigPerPoint (i, k));3444Point3d c = Center(GetPoint (trig.PNum(1)),3445GetPoint (trig.PNum(2)),3446GetPoint (trig.PNum(3)));34473448Point3d np = pi + 0.1 * (c - pi);3449SetPoint (i, np);34503451maxerr = 0;3452for (j = 1; j <= NOTrigsPerPoint(i); j++)3453{3454int tnum = TrigPerPoint(i, j);3455double err = Angle (GetTriangle(tnum).Normal (),3456GetTriangle(tnum).GeomNormal(GetPoints()));3457if (err > maxerr)3458maxerr = err;3459}34603461if (maxerr < maxerr0)3462{3463pi = np;3464}3465}34663467SetPoint (i, pi);3468}3469}3470}347134723473