#include #include #include #include #include namespace netgen { DLL_HEADER NgArray global_specpoints; // for visualization //static NgArray spoints; #define TCL_OK 0 #define TCL_ERROR 1 static void FindPoints (CSGeometry & geom, NgArray & specpoints, NgArray & spoints, Mesh & mesh) { PrintMessage (1, "Start Findpoints"); const char * savetask = multithread.task; multithread.task = "Find points"; mesh.pointelements.SetSize(0); for (int i = 0; i < geom.GetNUserPoints(); i++) { auto up = geom.GetUserPoint(i); auto pnum = mesh.AddPoint(up); mesh.Points().Last().Singularity (geom.GetUserPointRefFactor(i)); mesh.AddLockedPoint (PointIndex (i+1)); int index = up.GetIndex(); if (index == -1) index = mesh.AddCD3Name (up.GetName())+1; // cout << "adding 0d element, pnum = " << pnum << ", material index = " << index << endl; mesh.pointelements.Append (Element0d(pnum, index)); } SpecialPointCalculation spc; spc.SetIdEps(geom.GetIdEps()); if (spoints.Size() == 0) spc.CalcSpecialPoints (geom, spoints); PrintMessage (2, "Analyze spec points"); spc.AnalyzeSpecialPoints (geom, spoints, specpoints); { static mutex mut; lock_guard guard(mut); global_specpoints = specpoints; } PrintMessage (5, "done"); (*testout) << specpoints.Size() << " special points:" << endl; for (int i = 0; i < specpoints.Size(); i++) specpoints[i].Print (*testout); /* for (int i = 1; i <= geom.identifications.Size(); i++) geom.identifications.Elem(i)->IdentifySpecialPoints (specpoints); */ multithread.task = savetask; } static void FindEdges (CSGeometry & geom, Mesh & mesh, NgArray & specpoints, NgArray & spoints, MeshingParameters & mparam, const bool setmeshsize = false) { EdgeCalculation ec (geom, specpoints, mparam); ec.SetIdEps(geom.GetIdEps()); ec.Calc (mparam.maxh, mesh); for (int i = 0; i < geom.singedges.Size(); i++) { geom.singedges[i]->FindPointsOnEdge (mesh); if(setmeshsize) geom.singedges[i]->SetMeshSize(mesh,10.*geom.BoundingBox().Diam()); } for (int i = 0; i < geom.singpoints.Size(); i++) geom.singpoints[i]->FindPoints (mesh); for (int i = 1; i <= mesh.GetNSeg(); i++) { //(*testout) << "segment " << mesh.LineSegment(i) << endl; int ok = 0; for (int k = 1; k <= mesh.GetNFD(); k++) if (mesh.GetFaceDescriptor(k).SegmentFits (mesh.LineSegment(i))) { ok = k; //(*testout) << "fits to " << k << endl; } if (!ok) { ok = mesh.AddFaceDescriptor (FaceDescriptor (mesh.LineSegment(i))); //(*testout) << "did not find, now " << ok << endl; } //(*testout) << "change from " << mesh.LineSegment(i).si; mesh.LineSegment(i).si = ok; //(*testout) << " to " << mesh.LineSegment(i).si << endl; } for(int k = 1; k<=mesh.GetNFD(); k++) { *testout << "face: " << k << endl << "FD: " << mesh.GetFaceDescriptor(k) << endl; } if (geom.identifications.Size()) { PrintMessage (3, "Find Identifications"); for (int i = 0; i < geom.identifications.Size(); i++) { geom.identifications[i]->IdentifyPoints (mesh); //(*testout) << "identification " << i << " is " // << *geom.identifications[i] << endl; } for (int i = 0; i < geom.identifications.Size(); i++) geom.identifications[i]->IdentifyFaces (mesh); } // find intersecting segments PrintMessage (3, "Check intersecting edges"); Point3d pmin, pmax; mesh.GetBox (pmin, pmax); BoxTree<3> segtree (pmin, pmax); for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) { if (mesh[si].seginfo) { Box<3> hbox; hbox.Set (mesh[mesh[si][0]]); hbox.Add (mesh[mesh[si][1]]); segtree.Insert (hbox.PMin(), hbox.PMax(), si); } } NgArray loc; if (!ec.point_on_edge_problem) for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) { if (!mesh[si].seginfo) continue; Box<3> hbox; hbox.Set (mesh[mesh[si][0]]); hbox.Add (mesh[mesh[si][1]]); hbox.Increase (1e-6); segtree.GetIntersecting (hbox.PMin(), hbox.PMax(), loc); // for (SegmentIndex sj = 0; sj < si; sj++) for (int j = 0; j < loc.Size(); j++) { SegmentIndex sj = loc[j]; if (sj >= si) continue; if (!mesh[si].seginfo || !mesh[sj].seginfo) continue; if (mesh[mesh[si][0]].GetLayer() != mesh[mesh[sj][1]].GetLayer()) continue; Point<3> pi1 = mesh[mesh[si][0]]; Point<3> pi2 = mesh[mesh[si][1]]; Point<3> pj1 = mesh[mesh[sj][0]]; Point<3> pj2 = mesh[mesh[sj][1]]; Vec<3> vi = pi2 - pi1; Vec<3> vj = pj2 - pj1; if (sqr (vi * vj) > (1.-1e-6) * Abs2 (vi) * Abs2 (vj)) continue; // pi1 + vi t = pj1 + vj s Mat<3,2> mat; Vec<3> rhs; Vec<2> sol; for (int jj = 0; jj < 3; jj++) { mat(jj,0) = vi(jj); mat(jj,1) = -vj(jj); rhs(jj) = pj1(jj)-pi1(jj); } mat.Solve (rhs, sol); //(*testout) << "mat " << mat << endl << "rhs " << rhs << endl << "sol " << sol << endl; if (sol(0) > 1e-6 && sol(0) < 1-1e-6 && sol(1) > 1e-6 && sol(1) < 1-1e-6 && Abs (rhs - mat*sol) < 1e-6) { Point<3> ip = pi1 + sol(0) * vi; //(*testout) << "ip " << ip << endl; Point<3> pip = ip; ProjectToEdge (geom.GetSurface (mesh[si].surfnr1), geom.GetSurface (mesh[si].surfnr2), pip); //(*testout) << "Dist (ip, pip_si) " << Dist (ip, pip) << endl; if (Dist (ip, pip) > 1e-6*geom.MaxSize()) continue; pip = ip; ProjectToEdge (geom.GetSurface (mesh[sj].surfnr1), geom.GetSurface (mesh[sj].surfnr2), pip); //(*testout) << "Dist (ip, pip_sj) " << Dist (ip, pip) << endl; if (Dist (ip, pip) > 1e-6*geom.MaxSize()) continue; cout << "Intersection at " << ip << endl; geom.AddUserPoint (ip); spoints.Append (MeshPoint (ip, mesh[mesh[si][0]].GetLayer())); mesh.AddPoint (ip); (*testout) << "found intersection at " << ip << endl; (*testout) << "sol = " << sol << endl; (*testout) << "res = " << (rhs - mat*sol) << endl; (*testout) << "segs = " << pi1 << " - " << pi2 << endl; (*testout) << "and = " << pj1 << " - " << pj2 << endl << endl; } } } } static void MeshSurface (CSGeometry & geom, Mesh & mesh, MeshingParameters & mparam) { const char * savetask = multithread.task; multithread.task = "Surface meshing"; NgArray segments; int noldp = mesh.GetNP(); double starttime = GetTime(); // find master faces from identified NgArray masterface(mesh.GetNFD()); for (int i = 1; i <= mesh.GetNFD(); i++) masterface.Elem(i) = i; NgArray fpairs; bool changed; do { changed = 0; for (int i = 0; i < geom.identifications.Size(); i++) { geom.identifications[i]->GetIdentifiedFaces (fpairs); for (int j = 0; j < fpairs.Size(); j++) { if (masterface.Get(fpairs[j].I1()) < masterface.Get(fpairs[j].I2())) { changed = 1; masterface.Elem(fpairs[j].I2()) = masterface.Elem(fpairs[j].I1()); } if (masterface.Get(fpairs[j].I2()) < masterface.Get(fpairs[j].I1())) { changed = 1; masterface.Elem(fpairs[j].I1()) = masterface.Elem(fpairs[j].I2()); } } } } while (changed); int bccnt=0; for (int k = 0; k < geom.GetNSurf(); k++) bccnt = max2 (bccnt, geom.GetSurface(k)->GetBCProperty()); for (int k = 1; k <= mesh.GetNFD(); k++) { bool increased = false; FaceDescriptor & fd = mesh.GetFaceDescriptor(k); const Surface * surf = geom.GetSurface(fd.SurfNr()); if (fd.TLOSurface() && geom.GetTopLevelObject(fd.TLOSurface()-1) -> GetBCProp() > 0) fd.SetBCProperty (geom.GetTopLevelObject(fd.TLOSurface()-1) -> GetBCProp()); else if (surf -> GetBCProperty() != -1) fd.SetBCProperty (surf->GetBCProperty()); else { bccnt++; fd.SetBCProperty (bccnt); increased = true; } for (int l = 0; l < geom.bcmodifications.Size(); l++) { if (geom.GetSurfaceClassRepresentant (fd.SurfNr()) == geom.GetSurfaceClassRepresentant (geom.bcmodifications[l].si) && (fd.DomainIn() == geom.bcmodifications[l].tlonr+1 || fd.DomainOut() == geom.bcmodifications[l].tlonr+1)) { if(geom.bcmodifications[l].bcname == NULL) fd.SetBCProperty (geom.bcmodifications[l].bcnr); else { if(!increased) { bccnt++; fd.SetBCProperty (bccnt); increased = true; } } } } } mesh.SetNBCNames( bccnt ); for (int k = 1; k <= mesh.GetNFD(); k++) { FaceDescriptor & fd = mesh.GetFaceDescriptor(k); const Surface * surf = geom.GetSurface(fd.SurfNr()); if (fd.TLOSurface() ) { int bcp = fd.BCProperty(); string nextbcname = geom.GetTopLevelObject(fd.TLOSurface()-1) -> GetBCName(); if ( nextbcname != "default" ) mesh.SetBCName ( bcp - 1 , nextbcname ); } else // if (surf -> GetBCProperty() != -1) { int bcp = fd.BCProperty(); string nextbcname = surf->GetBCName(); if ( nextbcname != "default" ) mesh.SetBCName ( bcp - 1, nextbcname ); } } for (int k = 1; k <= mesh.GetNFD(); k++) { FaceDescriptor & fd = mesh.GetFaceDescriptor(k); fd.SetBCName ( mesh.GetBCNamePtr ( fd.BCProperty() - 1 ) ); } //!! for (int k = 1; k <= mesh.GetNFD(); k++) { FaceDescriptor & fd = mesh.GetFaceDescriptor(k); //const Surface * surf = geom.GetSurface(fd.SurfNr()); for (int l = 0; l < geom.bcmodifications.Size(); l++) { if (geom.GetSurfaceClassRepresentant (fd.SurfNr()) == geom.GetSurfaceClassRepresentant (geom.bcmodifications[l].si) && (fd.DomainIn() == geom.bcmodifications[l].tlonr+1 || fd.DomainOut() == geom.bcmodifications[l].tlonr+1) && geom.bcmodifications[l].bcname != NULL ) { int bcp = fd.BCProperty(); mesh.SetBCName ( bcp - 1, *(geom.bcmodifications[l].bcname) ); fd.SetBCName ( mesh.GetBCNamePtr ( bcp - 1) ); } } } for(int k = 0; k surfs; geom.GetIndependentSurfaceIndices (geom.singfaces[j]->GetSolid(), geom.BoundingBox(), surfs); for (int k = 1; k <= mesh.GetNFD(); k++) { FaceDescriptor & fd = mesh.GetFaceDescriptor(k); for (int l = 0; l < surfs.Size(); l++) if (surfs[l] == fd.SurfNr()) { if (geom.singfaces[j]->GetDomainNr() == fd.DomainIn()) fd.SetDomainInSingular (1); if (geom.singfaces[j]->GetDomainNr() == fd.DomainOut()) fd.SetDomainOutSingular (1); } } } // assemble edge hash-table mesh.CalcSurfacesOfNode(); for (int k = 1; k <= mesh.GetNFD(); k++) { multithread.percent = 100.0 * k / (mesh.GetNFD()+1e-10); if (masterface.Get(k) != k) continue; FaceDescriptor & fd = mesh.GetFaceDescriptor(k); (*testout) << "Surface " << k << endl; (*testout) << "Face Descriptor: " << fd << endl; PrintMessage (1, "Surface ", k, " / ", mesh.GetNFD()); int oldnf = mesh.GetNSE(); const Surface * surf = geom.GetSurface((mesh.GetFaceDescriptor(k).SurfNr())); Meshing2Surfaces meshing(geom, *surf, mparam, geom.BoundingBox()); meshing.SetStartTime (starttime); double eps = 1e-8 * geom.MaxSize(); for (PointIndex pi = PointIndex::BASE; pi < noldp+PointIndex::BASE; pi++) { // if(surf->PointOnSurface(mesh[pi])) meshing.AddPoint (mesh[pi], pi, NULL, (surf->PointOnSurface(mesh[pi], eps) != 0)); } segments.SetSize (0); for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) if (mesh[si].si == k) { segments.Append (mesh[si]); (*testout) << "appending segment " << mesh[si] << endl; //<< " from " << mesh[mesh[si][0]] // << " to " < BuildSurfaceElements(segments, mesh, surf); } for (int si = 0; si < segments.Size(); si++) { PointGeomInfo gi; gi.trignum = k; meshing.AddBoundaryElement (segments[si][0] + 1 - PointIndex::BASE, segments[si][1] + 1 - PointIndex::BASE, gi, gi); } double maxh = mparam.maxh; if (fd.DomainIn() != 0) { const Solid * s1 = geom.GetTopLevelObject(fd.DomainIn()-1) -> GetSolid(); if (s1->GetMaxH() < maxh) maxh = s1->GetMaxH(); maxh = min2(maxh, geom.GetTopLevelObject(fd.DomainIn()-1)->GetMaxH()); } if (fd.DomainOut() != 0) { const Solid * s1 = geom.GetTopLevelObject(fd.DomainOut()-1) -> GetSolid(); if (s1->GetMaxH() < maxh) maxh = s1->GetMaxH(); maxh = min2(maxh, geom.GetTopLevelObject(fd.DomainOut()-1)->GetMaxH()); } if (fd.TLOSurface() != 0) { double hi = geom.GetTopLevelObject(fd.TLOSurface()-1) -> GetMaxH(); if (hi < maxh) maxh = hi; } (*testout) << "domin = " << fd.DomainIn() << ", domout = " << fd.DomainOut() << ", tlo-surf = " << fd.TLOSurface() << " mpram.maxh = " << mparam.maxh << ", maxh = " << maxh << endl; mparam.checkoverlap = 0; MESHING2_RESULT res = meshing.GenerateMesh (mesh, mparam, maxh, k); if (res != MESHING2_OK) { PrintError ("Problem in Surface mesh generation"); throw NgException ("Problem in Surface mesh generation"); } if (multithread.terminate) return; for (SurfaceElementIndex sei = oldnf; sei < mesh.GetNSE(); sei++) mesh[sei].SetIndex (k); auto n_illegal_trigs = mesh.FindIllegalTrigs(); PrintMessage (3, n_illegal_trigs, " illegal triangles"); // mesh.CalcSurfacesOfNode(); if (segments.Size()) { // surface was meshed, not copied static int timer = NgProfiler::CreateTimer ("total surface mesh optimization"); NgProfiler::RegionTimer reg (timer); PrintMessage (2, "Optimize Surface"); for (int i = 1; i <= mparam.optsteps2d; i++) { if (multithread.terminate) return; { MeshOptimize2d meshopt(mesh); meshopt.SetFaceIndex (k); meshopt.SetImproveEdges (0); meshopt.SetMetricWeight (mparam.elsizeweight); meshopt.SetWriteStatus (0); meshopt.EdgeSwapping (i > mparam.optsteps2d/2); } if (multithread.terminate) return; { // mesh.CalcSurfacesOfNode(); MeshOptimize2d meshopt(mesh); meshopt.SetFaceIndex (k); meshopt.SetImproveEdges (0); meshopt.SetMetricWeight (mparam.elsizeweight); meshopt.SetWriteStatus (0); meshopt.ImproveMesh(mparam); } { MeshOptimize2d meshopt(mesh); meshopt.SetFaceIndex (k); meshopt.SetImproveEdges (0); meshopt.SetMetricWeight (mparam.elsizeweight); meshopt.SetWriteStatus (0); meshopt.CombineImprove(); // mesh.CalcSurfacesOfNode(); } if (multithread.terminate) return; { MeshOptimize2d meshopt(mesh); meshopt.SetFaceIndex (k); meshopt.SetImproveEdges (0); meshopt.SetMetricWeight (mparam.elsizeweight); meshopt.SetWriteStatus (0); meshopt.ImproveMesh(mparam); } } } PrintMessage (3, (mesh.GetNSE() - oldnf), " elements, ", mesh.GetNP(), " points"); mparam.Render(); } mesh.Compress(); do { changed = 0; for (int k = 1; k <= mesh.GetNFD(); k++) { multithread.percent = 100.0 * k / (mesh.GetNFD()+1e-10); if (masterface.Get(k) == k) continue; FaceDescriptor & fd = mesh.GetFaceDescriptor(k); (*testout) << "Surface " << k << endl; (*testout) << "Face Descriptor: " << fd << endl; PrintMessage (2, "Surface ", k); int oldnf = mesh.GetNSE(); const Surface * surf = geom.GetSurface((mesh.GetFaceDescriptor(k).SurfNr())); /* if (surf -> GetBCProperty() != -1) fd.SetBCProperty (surf->GetBCProperty()); else { bccnt++; fd.SetBCProperty (bccnt); } */ segments.SetSize (0); for (int i = 1; i <= mesh.GetNSeg(); i++) { Segment * seg = &mesh.LineSegment(i); if (seg->si == k) segments.Append (*seg); } for (int i = 1; i <= geom.identifications.Size(); i++) { geom.identifications.Elem(i)->GetIdentifiedFaces (fpairs); int found = 0; for (int j = 1; j <= fpairs.Size(); j++) if (fpairs.Get(j).I1() == k || fpairs.Get(j).I2() == k) found = 1; if (!found) continue; geom.identifications.Get(i)-> BuildSurfaceElements(segments, mesh, surf); if (!segments.Size()) break; } if (multithread.terminate) return; for (SurfaceElementIndex sei = oldnf; sei < mesh.GetNSE(); sei++) mesh[sei].SetIndex (k); if (!segments.Size()) { masterface.Elem(k) = k; changed = 1; } PrintMessage (3, (mesh.GetNSE() - oldnf), " elements, ", mesh.GetNP(), " points"); } mparam.Render(); } while (changed); mesh.SplitSeparatedFaces(); mesh.CalcSurfacesOfNode(); multithread.task = savetask; } int CSGGenerateMesh (CSGeometry & geom, shared_ptr & mesh, MeshingParameters & mparam) { NgArray specpoints; NgArray spoints; if (mesh && mesh->GetNSE() && !geom.GetNSolids()) { if (mparam.perfstepsstart < MESHCONST_MESHVOLUME) mparam.perfstepsstart = MESHCONST_MESHVOLUME; } if (mparam.perfstepsstart <= MESHCONST_ANALYSE) { if (mesh) mesh -> DeleteMesh(); else mesh = make_shared(); mesh->SetGlobalH (mparam.maxh); mesh->SetMinimalH (mparam.minh); NgArray maxhdom(geom.GetNTopLevelObjects()); for (int i = 0; i < maxhdom.Size(); i++) maxhdom[i] = geom.GetTopLevelObject(i)->GetMaxH(); mesh->SetMaxHDomain (maxhdom); if (mparam.uselocalh) { double maxsize = geom.MaxSize(); mesh->SetLocalH (Point<3>(-maxsize, -maxsize, -maxsize), Point<3>(maxsize, maxsize, maxsize), mparam.grading); mesh -> LoadLocalMeshSize (mparam.meshsizefilename); for (auto mspnt : mparam.meshsize_points) mesh -> RestrictLocalH (mspnt.pnt, mspnt.h); } spoints.SetSize(0); FindPoints (geom, specpoints, spoints, *mesh); PrintMessage (5, "find points done"); #ifdef LOG_STREAM (*logout) << "Special points found" << endl << "time = " << GetTime() << " sec" << endl << "points: " << mesh->GetNP() << endl << endl; #endif } if (multithread.terminate || mparam.perfstepsend <= MESHCONST_ANALYSE) return TCL_OK; if (mparam.perfstepsstart <= MESHCONST_MESHEDGES) { FindEdges (geom, *mesh, specpoints, spoints, mparam, true); if (multithread.terminate) return TCL_OK; #ifdef LOG_STREAM (*logout) << "Edges meshed" << endl << "time = " << GetTime() << " sec" << endl << "points: " << mesh->GetNP() << endl; #endif if (multithread.terminate) return TCL_OK; if (mparam.uselocalh) { mesh->CalcLocalH(mparam.grading); mesh->DeleteMesh(); FindPoints (geom, specpoints, spoints, *mesh); if (multithread.terminate) return TCL_OK; FindEdges (geom, *mesh, specpoints, spoints, mparam, true); if (multithread.terminate) return TCL_OK; mesh->DeleteMesh(); FindPoints (geom, specpoints, spoints, *mesh); if (multithread.terminate) return TCL_OK; FindEdges (geom, *mesh, specpoints, spoints, mparam); if (multithread.terminate) return TCL_OK; } } if (multithread.terminate || mparam.perfstepsend <= MESHCONST_MESHEDGES) return TCL_OK; if (mparam.perfstepsstart <= MESHCONST_MESHSURFACE) { MeshSurface (geom, *mesh, mparam); if (multithread.terminate) return TCL_OK; #ifdef LOG_STREAM (*logout) << "Surfaces meshed" << endl << "time = " << GetTime() << " sec" << endl << "points: " << mesh->GetNP() << endl; #endif /* if (mparam.uselocalh) { mesh->CalcLocalH(mparam.grading); mesh->DeleteMesh(); FindPoints (geom, *mesh); if (multithread.terminate) return TCL_OK; FindEdges (geom, *mesh, mparam); if (multithread.terminate) return TCL_OK; MeshSurface (geom, *mesh, mparam); if (multithread.terminate) return TCL_OK; } */ #ifdef LOG_STREAM (*logout) << "Surfaces remeshed" << endl << "time = " << GetTime() << " sec" << endl << "points: " << mesh->GetNP() << endl; #endif #ifdef STAT_STREAM (*statout) << mesh->GetNSeg() << " & " << mesh->GetNSE() << " & - &" << GetTime() << " & " << endl; #endif MeshQuality2d (*mesh); mesh->CalcSurfacesOfNode(); } if (multithread.terminate || mparam.perfstepsend <= MESHCONST_OPTSURFACE) return TCL_OK; if (mparam.perfstepsstart <= MESHCONST_MESHVOLUME) { multithread.task = "Volume meshing"; MESHING3_RESULT res = MeshVolume (mparam, *mesh); if (res != MESHING3_OK) return TCL_ERROR; if (multithread.terminate) return TCL_OK; RemoveIllegalElements (*mesh); if (multithread.terminate) return TCL_OK; MeshQuality3d (*mesh); for (int i = 0; i < geom.GetNTopLevelObjects(); i++) mesh->SetMaterial (i+1, geom.GetTopLevelObject(i)->GetMaterial().c_str()); #ifdef STAT_STREAM (*statout) << GetTime() << " & "; #endif #ifdef LOG_STREAM (*logout) << "Volume meshed" << endl << "time = " << GetTime() << " sec" << endl << "points: " << mesh->GetNP() << endl; #endif } if (multithread.terminate || mparam.perfstepsend <= MESHCONST_MESHVOLUME) return TCL_OK; if (mparam.perfstepsstart <= MESHCONST_OPTVOLUME) { multithread.task = "Volume optimization"; OptimizeVolume (mparam, *mesh); if (multithread.terminate) return TCL_OK; #ifdef STAT_STREAM (*statout) << GetTime() << " & " << mesh->GetNE() << " & " << mesh->GetNP() << " " << '\\' << '\\' << " \\" << "hline" << endl; #endif #ifdef LOG_STREAM (*logout) << "Volume optimized" << endl << "time = " << GetTime() << " sec" << endl << "points: " << mesh->GetNP() << endl; #endif } mesh -> OrderElements(); return TCL_OK; } }