mirror of
https://github.com/NGSolve/netgen.git
synced 2025-01-11 21:50:34 +05:00
Interpolate growth vectors on surfaces
also: - clean up delaunay2d code (Use Point<2>, remove comments) - implement CalcWeights() used to interpolate data from boundary points to surface points
This commit is contained in:
parent
f6a7ffa4fe
commit
dabb3b9dbf
@ -1184,6 +1184,8 @@ public:
|
|||||||
: DelaunayTree(box.PMin(), box.PMax())
|
: DelaunayTree(box.PMin(), box.PMax())
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
double GetTolerance() { return tol; }
|
||||||
|
|
||||||
size_t GetNLeaves()
|
size_t GetNLeaves()
|
||||||
{
|
{
|
||||||
return n_leaves;
|
return n_leaves;
|
||||||
|
@ -26,7 +26,7 @@ add_library(mesh ${NG_LIB_TYPE}
|
|||||||
ruler2.cpp ruler3.cpp secondorder.cpp smoothing2.5.cpp
|
ruler2.cpp ruler3.cpp secondorder.cpp smoothing2.5.cpp
|
||||||
smoothing2.cpp smoothing3.cpp specials.cpp
|
smoothing2.cpp smoothing3.cpp specials.cpp
|
||||||
topology.cpp validate.cpp bcfunctions.cpp
|
topology.cpp validate.cpp bcfunctions.cpp
|
||||||
parallelmesh.cpp paralleltop.cpp paralleltop.hpp basegeom.cpp
|
parallelmesh.cpp paralleltop.cpp basegeom.cpp
|
||||||
python_mesh.cpp surfacegeom.cpp
|
python_mesh.cpp surfacegeom.cpp
|
||||||
../../ng/onetcl.cpp
|
../../ng/onetcl.cpp
|
||||||
${rules_sources}
|
${rules_sources}
|
||||||
@ -53,6 +53,6 @@ install(FILES
|
|||||||
localh.hpp meshclass.hpp meshfunc.hpp meshing2.hpp meshing3.hpp
|
localh.hpp meshclass.hpp meshfunc.hpp meshing2.hpp meshing3.hpp
|
||||||
meshing.hpp meshtool.hpp meshtype.hpp msghandler.hpp paralleltop.hpp
|
meshing.hpp meshtool.hpp meshtype.hpp msghandler.hpp paralleltop.hpp
|
||||||
ruler2.hpp ruler3.hpp specials.hpp topology.hpp validate.hpp
|
ruler2.hpp ruler3.hpp specials.hpp topology.hpp validate.hpp
|
||||||
python_mesh.hpp surfacegeom.hpp
|
python_mesh.hpp surfacegeom.hpp delaunay2d.hpp
|
||||||
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/meshing COMPONENT netgen_devel
|
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/meshing COMPONENT netgen_devel
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <mystdlib.h>
|
#include <mystdlib.h>
|
||||||
#include "meshing.hpp"
|
#include "meshing.hpp"
|
||||||
#include "meshing2.hpp"
|
#include "meshing2.hpp"
|
||||||
|
#include "delaunay2d.hpp"
|
||||||
#include "global.hpp"
|
#include "global.hpp"
|
||||||
#include "../geom2d/csg2d.hpp"
|
#include "../geom2d/csg2d.hpp"
|
||||||
|
|
||||||
@ -262,6 +263,8 @@ namespace netgen
|
|||||||
{
|
{
|
||||||
for(auto pi : sel.PNums())
|
for(auto pi : sel.PNums())
|
||||||
{
|
{
|
||||||
|
if(mesh[pi].Type() >= SURFACEPOINT)
|
||||||
|
continue;
|
||||||
auto & np = growthvectors[pi];
|
auto & np = growthvectors[pi];
|
||||||
if(np.Length() == 0) { np = n; continue; }
|
if(np.Length() == 0) { np = n; continue; }
|
||||||
auto npn = np * n;
|
auto npn = np * n;
|
||||||
@ -352,6 +355,8 @@ namespace netgen
|
|||||||
for(auto i : Range(sel.PNums()))
|
for(auto i : Range(sel.PNums()))
|
||||||
{
|
{
|
||||||
auto pi = sel.PNums()[i];
|
auto pi = sel.PNums()[i];
|
||||||
|
if(mesh[pi].Type() >= SURFACEPOINT)
|
||||||
|
continue;
|
||||||
if(growthvectors[pi].Length2() == 0.)
|
if(growthvectors[pi].Length2() == 0.)
|
||||||
continue;
|
continue;
|
||||||
auto next = sel.PNums()[(i+1)%sel.GetNV()];
|
auto next = sel.PNums()[(i+1)%sel.GetNV()];
|
||||||
@ -393,6 +398,73 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Array<Point<2>, PointIndex> delaunay_points(mesh.GetNP());
|
||||||
|
Array<int, PointIndex> p2face(mesh.GetNP());
|
||||||
|
p2face = 0;
|
||||||
|
|
||||||
|
// interpolate growth vectors at inner surface points from surrounding edge points
|
||||||
|
Array<SurfaceElementIndex> surface_els;
|
||||||
|
Array<PointIndex> edge_points;
|
||||||
|
Array<PointIndex> surface_points;
|
||||||
|
for(auto facei : Range(1, fd_old+1))
|
||||||
|
{
|
||||||
|
if(!blp.surfid.Contains(facei))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
p2face = 0;
|
||||||
|
|
||||||
|
edge_points.SetSize(0);
|
||||||
|
surface_points.SetSize(0);
|
||||||
|
surface_els.SetSize(0);
|
||||||
|
mesh.GetSurfaceElementsOfFace (facei, surface_els);
|
||||||
|
Box<2> bbox ( Box<2>::EMPTY_BOX );
|
||||||
|
for(auto sei : surface_els)
|
||||||
|
{
|
||||||
|
const auto & sel = mesh[sei];
|
||||||
|
for (auto i : Range(sel.GetNP()))
|
||||||
|
{
|
||||||
|
auto pi = sel[i];
|
||||||
|
if(p2face[pi] != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
p2face[pi] = facei;
|
||||||
|
|
||||||
|
if(mesh[pi].Type() <= EDGEPOINT)
|
||||||
|
edge_points.Append(pi);
|
||||||
|
else
|
||||||
|
surface_points.Append(pi);
|
||||||
|
|
||||||
|
auto & gi = sel.GeomInfo()[i];
|
||||||
|
// TODO: project to plane if u,v not available?
|
||||||
|
delaunay_points[pi] = {gi.u, gi.v};
|
||||||
|
bbox.Add(delaunay_points[pi]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(surface_points.Size()==0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DelaunayMesh dmesh( delaunay_points, bbox );
|
||||||
|
|
||||||
|
for(auto pi : edge_points)
|
||||||
|
{
|
||||||
|
p2face[pi] = 0;
|
||||||
|
dmesh.AddPoint(pi);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<PointIndex, double> weights;
|
||||||
|
for(auto pi : surface_points)
|
||||||
|
{
|
||||||
|
dmesh.AddPoint(pi, &weights);
|
||||||
|
auto & v = growthvectors[pi];
|
||||||
|
for(auto & [pi_other, weight] : weights)
|
||||||
|
v += weight * growthvectors[pi_other];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// insert new points
|
// insert new points
|
||||||
for (PointIndex pi = 1; pi <= np; pi++)
|
for (PointIndex pi = 1; pi <= np; pi++)
|
||||||
if (growthvectors[pi].Length2() != 0)
|
if (growthvectors[pi].Length2() != 0)
|
||||||
|
@ -1,265 +1,172 @@
|
|||||||
#include <mystdlib.h>
|
#include <mystdlib.h>
|
||||||
#include "meshing.hpp"
|
#include "delaunay2d.hpp"
|
||||||
|
|
||||||
#include <geom2d/csg2d.hpp>
|
#include <geom2d/csg2d.hpp>
|
||||||
|
|
||||||
|
|
||||||
// not yet working ....
|
|
||||||
|
|
||||||
namespace netgen
|
namespace netgen
|
||||||
{
|
{
|
||||||
using ngcore::INT;
|
using ngcore::INT;
|
||||||
extern void Optimize2d (Mesh & mesh, MeshingParameters & mp);
|
|
||||||
|
|
||||||
static inline Point<2> P2( Point<3> p )
|
|
||||||
|
void DelaunayTrig::CalcCenter (FlatArray<Point<2>, PointIndex> points)
|
||||||
{
|
{
|
||||||
return {p[0], p[1]};
|
Point<2> p1 = points[pnums[0]];
|
||||||
|
Point<2> p2 = points[pnums[1]];
|
||||||
|
Point<2> p3 = points[pnums[2]];
|
||||||
|
|
||||||
|
Vec<2> v1 = p2-p1;
|
||||||
|
Vec<2> v2 = p3-p1;
|
||||||
|
|
||||||
|
// without normal equation ...
|
||||||
|
Mat<2,2> mat, inv;
|
||||||
|
mat(0,0) = v1(0); mat(0,1) = v1(1);
|
||||||
|
mat(1,0) = v2(0); mat(1,1) = v2(1);
|
||||||
|
CalcInverse (mat, inv);
|
||||||
|
Vec<2> rhs, sol;
|
||||||
|
rhs(0) = 0.5 * v1*v1;
|
||||||
|
rhs(1) = 0.5 * v2*v2;
|
||||||
|
sol = inv * rhs;
|
||||||
|
c = p1 + sol;
|
||||||
|
|
||||||
|
rad2 = Dist2(c, p1);
|
||||||
|
r = sqrt(rad2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Point<3> P3( Point<2> p )
|
int DelaunayMesh::GetNeighbour( int eli, int edge )
|
||||||
{
|
{
|
||||||
return {p[0], p[1], 0};
|
auto p0 = trigs[eli][(edge+1)%3];
|
||||||
|
auto p1 = trigs[eli][(edge+2)%3];
|
||||||
|
if(p1<p0)
|
||||||
|
Swap(p0,p1);
|
||||||
|
|
||||||
|
INT<2> hash = {p0,p1};
|
||||||
|
|
||||||
|
auto pos = edge_to_trig.Position(hash);
|
||||||
|
if (pos == -1) return -1;
|
||||||
|
auto i2 = edge_to_trig.GetData(pos);
|
||||||
|
return i2[0] == eli ? i2[1] : i2[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DelaunayMesh::SetNeighbour( int eli, int edge )
|
||||||
class DelaunayTrig
|
|
||||||
{
|
{
|
||||||
PointIndex pnums[3];
|
auto p0 = trigs[eli][(edge+1)%3];
|
||||||
Point<2> c;
|
auto p1 = trigs[eli][(edge+2)%3];
|
||||||
public:
|
if(p1<p0)
|
||||||
double r;
|
Swap(p0,p1);
|
||||||
double rad2;
|
|
||||||
DelaunayTrig () = default;
|
|
||||||
DelaunayTrig (int p1, int p2, int p3)
|
|
||||||
{
|
|
||||||
pnums[0] = p1;
|
|
||||||
pnums[1] = p2;
|
|
||||||
pnums[2] = p3;
|
|
||||||
}
|
|
||||||
|
|
||||||
PointIndex & operator[] (int j) { return pnums[j]; }
|
INT<2> hash = {p0,p1};
|
||||||
const PointIndex & operator[] (int j) const { return pnums[j]; }
|
auto pos = edge_to_trig.Position(hash);
|
||||||
|
if (pos == -1)
|
||||||
void CalcCenter (Mesh & mesh)
|
edge_to_trig[hash] = {eli, -1};
|
||||||
{
|
else
|
||||||
Point<2> p1 = P2(mesh[pnums[0]]);
|
|
||||||
Point<2> p2 = P2(mesh[pnums[1]]);
|
|
||||||
Point<2> p3 = P2(mesh[pnums[2]]);
|
|
||||||
|
|
||||||
Vec<2> v1 = p2-p1;
|
|
||||||
Vec<2> v2 = p3-p1;
|
|
||||||
/*
|
|
||||||
Mat<2,2> mat, inv;
|
|
||||||
mat(0,0) = v1*v1;
|
|
||||||
mat(0,1) = v1*v2;
|
|
||||||
mat(1,0) = v2*v1;
|
|
||||||
mat(1,1) = v2*v2;
|
|
||||||
Vec<2> rhs, sol;
|
|
||||||
rhs(0) = 0.5 * v1*v1;
|
|
||||||
rhs(1) = 0.5 * v2*v2;
|
|
||||||
CalcInverse (mat, inv);
|
|
||||||
sol = inv * rhs;
|
|
||||||
|
|
||||||
c = p1 + sol(0) * v1 + sol(1) * v2;
|
|
||||||
rad2 = Dist2(c, p1);
|
|
||||||
r = sqrt(rad2);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// without normal equation ...
|
|
||||||
Mat<2,2> mat, inv;
|
|
||||||
mat(0,0) = v1(0); mat(0,1) = v1(1);
|
|
||||||
mat(1,0) = v2(0); mat(1,1) = v2(1);
|
|
||||||
CalcInverse (mat, inv);
|
|
||||||
Vec<2> rhs, sol;
|
|
||||||
rhs(0) = 0.5 * v1*v1;
|
|
||||||
rhs(1) = 0.5 * v2*v2;
|
|
||||||
sol = inv * rhs;
|
|
||||||
c = p1 + sol;
|
|
||||||
|
|
||||||
rad2 = Dist2(c, p1);
|
|
||||||
r = sqrt(rad2);
|
|
||||||
}
|
|
||||||
|
|
||||||
Point<2> Center() const { return c; }
|
|
||||||
double Radius2() const { return rad2; }
|
|
||||||
Box<2> BoundingBox() const { return Box<2> (c-Vec<2>(r,r), c+Vec<2>(r,r)); }
|
|
||||||
|
|
||||||
mutable PointIndex visited_pi = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DelaunayMesh
|
|
||||||
{
|
|
||||||
ngcore::ClosedHashTable<INT<2>, INT<2>> edge_to_trig;
|
|
||||||
Array<DelaunayTrig> trigs;
|
|
||||||
unique_ptr<DelaunayTree<2>> tree;
|
|
||||||
Mesh & mesh;
|
|
||||||
|
|
||||||
Array<int> closeels;
|
|
||||||
Array<int> intersecting;
|
|
||||||
Array<INT<2>> edges;
|
|
||||||
|
|
||||||
int GetNeighbour( int eli, int edge )
|
|
||||||
{
|
|
||||||
auto p0 = trigs[eli][(edge+1)%3];
|
|
||||||
auto p1 = trigs[eli][(edge+2)%3];
|
|
||||||
if(p1<p0)
|
|
||||||
Swap(p0,p1);
|
|
||||||
|
|
||||||
INT<2> hash = {p0,p1};
|
|
||||||
/*
|
|
||||||
if(!edge_to_trig.Used(hash))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
auto i2 = edge_to_trig.Get({p0,p1});
|
|
||||||
|
|
||||||
return i2[0] == eli ? i2[1] : i2[0];
|
|
||||||
*/
|
|
||||||
auto pos = edge_to_trig.Position(hash);
|
|
||||||
if (pos == -1) return -1;
|
|
||||||
auto i2 = edge_to_trig.GetData(pos);
|
|
||||||
return i2[0] == eli ? i2[1] : i2[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetNeighbour( int eli, int edge )
|
|
||||||
{
|
|
||||||
auto p0 = trigs[eli][(edge+1)%3];
|
|
||||||
auto p1 = trigs[eli][(edge+2)%3];
|
|
||||||
if(p1<p0)
|
|
||||||
Swap(p0,p1);
|
|
||||||
|
|
||||||
INT<2> hash = {p0,p1};
|
|
||||||
auto pos = edge_to_trig.Position(hash);
|
|
||||||
if (pos == -1)
|
|
||||||
edge_to_trig[hash] = {eli, -1};
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto i2 = edge_to_trig.GetData(pos);
|
|
||||||
if(i2[0]==-1)
|
|
||||||
i2[0] = eli;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(i2[1]==-1)
|
|
||||||
i2[1] = eli;
|
|
||||||
}
|
|
||||||
edge_to_trig.SetData (pos, i2);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if(!edge_to_trig.Used(hash))
|
|
||||||
edge_to_trig[hash] = {eli, -1};
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
auto i2 = edge_to_trig.GetData(pos);
|
||||||
auto i2 = edge_to_trig.Get({p0,p1});
|
|
||||||
|
|
||||||
if(i2[0]==-1)
|
if(i2[0]==-1)
|
||||||
i2[0] = eli;
|
i2[0] = eli;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(i2[1]==-1)
|
if(i2[1]==-1)
|
||||||
i2[1] = eli;
|
i2[1] = eli;
|
||||||
}
|
}
|
||||||
|
|
||||||
edge_to_trig[hash] = i2;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnsetNeighbours( int eli )
|
|
||||||
{
|
|
||||||
for(int edge : Range(3))
|
|
||||||
{
|
|
||||||
auto p0 = trigs[eli][(edge+1)%3];
|
|
||||||
auto p1 = trigs[eli][(edge+2)%3];
|
|
||||||
if(p1<p0)
|
|
||||||
Swap(p0,p1);
|
|
||||||
|
|
||||||
INT<2> hash = {p0,p1};
|
|
||||||
// auto i2 = edge_to_trig.Get({p0,p1});
|
|
||||||
auto pos = edge_to_trig.Position(hash);
|
|
||||||
auto i2 = edge_to_trig.GetData(pos);
|
|
||||||
|
|
||||||
if(i2[0]==eli)
|
|
||||||
i2[0] = i2[1];
|
|
||||||
i2[1] = -1;
|
|
||||||
|
|
||||||
// edge_to_trig[hash] = i2;
|
|
||||||
edge_to_trig.SetData (pos, i2);
|
edge_to_trig.SetData (pos, i2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DelaunayMesh::UnsetNeighbours( int eli )
|
||||||
void AppendTrig( int pi0, int pi1, int pi2 )
|
{
|
||||||
|
for(int edge : Range(3))
|
||||||
{
|
{
|
||||||
DelaunayTrig el;
|
auto p0 = trigs[eli][(edge+1)%3];
|
||||||
el[0] = pi0;
|
auto p1 = trigs[eli][(edge+2)%3];
|
||||||
el[1] = pi1;
|
if(p1<p0)
|
||||||
el[2] = pi2;
|
Swap(p0,p1);
|
||||||
|
|
||||||
el.CalcCenter(mesh);
|
INT<2> hash = {p0,p1};
|
||||||
|
auto pos = edge_to_trig.Position(hash);
|
||||||
|
auto i2 = edge_to_trig.GetData(pos);
|
||||||
|
|
||||||
trigs.Append(el);
|
if(i2[0]==eli)
|
||||||
int ti = trigs.Size()-1;
|
i2[0] = i2[1];
|
||||||
tree->Insert(el.BoundingBox(), ti);
|
i2[1] = -1;
|
||||||
|
|
||||||
for(int i : Range(3))
|
edge_to_trig.SetData (pos, i2);
|
||||||
SetNeighbour(ti, i);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
DelaunayMesh( Mesh & mesh_, Box<2> box )
|
|
||||||
: mesh(mesh_)
|
|
||||||
{
|
|
||||||
Vec<2> vdiag = box.PMax()-box.PMin();
|
|
||||||
|
|
||||||
double w = vdiag(0);
|
void DelaunayMesh::AppendTrig( int pi0, int pi1, int pi2 )
|
||||||
double h = vdiag(1);
|
{
|
||||||
|
DelaunayTrig el;
|
||||||
|
el[0] = pi0;
|
||||||
|
el[1] = pi1;
|
||||||
|
el[2] = pi2;
|
||||||
|
|
||||||
Point<2> p0 = box.PMin() + Vec<2> ( -3*h, -h);
|
el.CalcCenter(points);
|
||||||
Point<2> p1 = box.PMin() + Vec<2> (w+3*h, -h);
|
|
||||||
Point<2> p2 = box.Center() + Vec<2> (0, 1.5*h+0.5*w);
|
|
||||||
|
|
||||||
box.Add( p0 );
|
trigs.Append(el);
|
||||||
box.Add( p1 );
|
int ti = trigs.Size()-1;
|
||||||
box.Add( p2 );
|
tree->Insert(el.BoundingBox(), ti);
|
||||||
|
|
||||||
tree = make_unique<DelaunayTree<2>>(box);
|
for(int i : Range(3))
|
||||||
|
SetNeighbour(ti, i);
|
||||||
|
}
|
||||||
|
|
||||||
auto pi0 = mesh.AddPoint (P3(p0));
|
DelaunayMesh::DelaunayMesh( Array<Point<2>, PointIndex> & points_, Box<2> box )
|
||||||
auto pi1 = mesh.AddPoint (P3(p1));
|
: points(points_)
|
||||||
auto pi2 = mesh.AddPoint (P3(p2));
|
{
|
||||||
AppendTrig(pi0, pi1, pi2);
|
Vec<2> vdiag = box.PMax()-box.PMin();
|
||||||
}
|
|
||||||
|
|
||||||
void AddPoint( PointIndex pi_new )
|
double w = vdiag(0);
|
||||||
{
|
double h = vdiag(1);
|
||||||
static Timer t("AddPoint"); RegionTimer reg(t);
|
|
||||||
Point<2> newp = P2(mesh[pi_new]);
|
|
||||||
intersecting.SetSize(0);
|
|
||||||
edges.SetSize(0);
|
|
||||||
|
|
||||||
int definitive_overlapping_trig = -1;
|
Point<2> p0 = box.PMin() + Vec<2> ( -3*h, -h);
|
||||||
|
Point<2> p1 = box.PMin() + Vec<2> (w+3*h, -h);
|
||||||
|
Point<2> p2 = box.Center() + Vec<2> (0, 1.5*h+0.5*w);
|
||||||
|
|
||||||
double minquot{1e20};
|
box.Add( p0 );
|
||||||
tree->GetFirstIntersecting (newp, newp, [&] (const auto i_trig)
|
box.Add( p1 );
|
||||||
{
|
box.Add( p2 );
|
||||||
const auto trig = trigs[i_trig];
|
|
||||||
double rad2 = trig.Radius2();
|
tree = make_unique<DelaunayTree<2>>(box);
|
||||||
double d2 = Dist2 (trig.Center(), newp);
|
|
||||||
if (d2 >= rad2) return false;
|
auto pi0 = points.Append (p0);
|
||||||
|
auto pi1 = points.Append (p1);
|
||||||
if (d2 < 0.999 * rad2)
|
auto pi2 = points.Append (p2);
|
||||||
{
|
AppendTrig(pi0, pi1, pi2);
|
||||||
definitive_overlapping_trig = i_trig;
|
}
|
||||||
return true;
|
|
||||||
}
|
void DelaunayMesh::CalcIntersecting( PointIndex pi_new )
|
||||||
|
{
|
||||||
if (definitive_overlapping_trig == -1 || d2 < 0.99*minquot*rad2)
|
static Timer t("CalcIntersecting"); RegionTimer reg(t);
|
||||||
{
|
|
||||||
minquot = d2/rad2;
|
Point<2> newp = points[pi_new];
|
||||||
definitive_overlapping_trig = i_trig;
|
intersecting.SetSize(0);
|
||||||
}
|
edges.SetSize(0);
|
||||||
return false;
|
|
||||||
});
|
int definitive_overlapping_trig = -1;
|
||||||
|
|
||||||
|
double minquot{1e20};
|
||||||
|
tree->GetFirstIntersecting (newp, newp, [&] (const auto i_trig)
|
||||||
|
{
|
||||||
|
const auto trig = trigs[i_trig];
|
||||||
|
double rad2 = trig.Radius2();
|
||||||
|
double d2 = Dist2 (trig.Center(), newp);
|
||||||
|
if (d2 >= rad2) return false;
|
||||||
|
|
||||||
|
if (d2 < 0.999 * rad2)
|
||||||
|
{
|
||||||
|
definitive_overlapping_trig = i_trig;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (definitive_overlapping_trig == -1 || d2 < 0.99*minquot*rad2)
|
||||||
|
{
|
||||||
|
minquot = d2/rad2;
|
||||||
|
definitive_overlapping_trig = i_trig;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
if(definitive_overlapping_trig==-1)
|
if(definitive_overlapping_trig==-1)
|
||||||
{
|
{
|
||||||
@ -284,52 +191,63 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// static Timer tvis("trig visited");
|
|
||||||
// tvis.Start();
|
|
||||||
// BitArray trig_visited(trigs.Size());
|
|
||||||
// trig_visited.Clear();
|
|
||||||
if(definitive_overlapping_trig==-1)
|
if(definitive_overlapping_trig==-1)
|
||||||
|
{
|
||||||
|
Mesh m;
|
||||||
|
m.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 0));
|
||||||
|
for(auto pi : points.Range())
|
||||||
|
m.AddPoint(P3(points[pi]));
|
||||||
|
|
||||||
|
for (DelaunayTrig & trig : trigs)
|
||||||
|
{
|
||||||
|
if (trig[0] < 0) continue;
|
||||||
|
|
||||||
|
Vec<3> n = Cross (P3(points[trig[1]])-P3(points[trig[0]]),
|
||||||
|
P3(points[trig[2]])-P3(points[trig[0]]));
|
||||||
|
if (n(2) < 0) Swap (trig[1], trig[2]);
|
||||||
|
|
||||||
|
Element2d el(trig[0], trig[1], trig[2]);
|
||||||
|
el.SetIndex (1);
|
||||||
|
m.AddSurfaceElement (el);
|
||||||
|
}
|
||||||
|
m.Compress();
|
||||||
|
m.AddPoint(P3(points[pi_new]));
|
||||||
|
m.Save("error.vol.gz");
|
||||||
throw Exception("point not in any circle "+ ToString(pi_new));
|
throw Exception("point not in any circle "+ ToString(pi_new));
|
||||||
// tvis.Stop();
|
}
|
||||||
// static Timer t2("addpoint - rest"); RegionTimer r2(t2);
|
|
||||||
Array<int> trigs_to_visit;
|
Array<int> trigs_to_visit;
|
||||||
trigs_to_visit.Append(definitive_overlapping_trig);
|
trigs_to_visit.Append(definitive_overlapping_trig);
|
||||||
intersecting.Append(definitive_overlapping_trig);
|
intersecting.Append(definitive_overlapping_trig);
|
||||||
// trig_visited.SetBit(definitive_overlapping_trig);
|
|
||||||
trigs[definitive_overlapping_trig].visited_pi = pi_new;
|
trigs[definitive_overlapping_trig].visited_pi = pi_new;
|
||||||
|
|
||||||
while(trigs_to_visit.Size())
|
while(trigs_to_visit.Size())
|
||||||
{
|
{
|
||||||
int ti = trigs_to_visit.Last();
|
int ti = trigs_to_visit.Last();
|
||||||
trigs_to_visit.DeleteLast();
|
trigs_to_visit.DeleteLast();
|
||||||
|
|
||||||
// trig_visited.SetBit(ti);
|
|
||||||
|
|
||||||
auto & trig = trigs[ti];
|
auto & trig = trigs[ti];
|
||||||
trig.visited_pi = pi_new;
|
trig.visited_pi = pi_new;
|
||||||
|
|
||||||
for(auto ei : Range(3))
|
for(auto ei : Range(3))
|
||||||
{
|
{
|
||||||
auto nb = GetNeighbour(ti, ei);
|
auto nb = GetNeighbour(ti, ei);
|
||||||
if(nb==-1)
|
if(nb==-1)
|
||||||
continue;
|
continue;
|
||||||
// if(trig_visited.Test(nb))
|
|
||||||
// continue;
|
|
||||||
|
|
||||||
const auto & trig_nb = trigs[nb];
|
const auto & trig_nb = trigs[nb];
|
||||||
if (trig_nb.visited_pi == pi_new)
|
if (trig_nb.visited_pi == pi_new)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// trig_visited.SetBit(nb);
|
|
||||||
trig_nb.visited_pi = pi_new;
|
trig_nb.visited_pi = pi_new;
|
||||||
|
|
||||||
bool is_intersecting = Dist2(newp, trig_nb.Center()) < trig_nb.Radius2()*(1+1e-12);
|
bool is_intersecting = Dist2(newp, trig_nb.Center()) < trig_nb.Radius2()*(1+1e-12);
|
||||||
|
|
||||||
if(!is_intersecting)
|
if(!is_intersecting)
|
||||||
{
|
{
|
||||||
const Point<2> p0 = P2(mesh[PointIndex (trig[(ei+1)%3])]);
|
const Point<2> p0 = points[PointIndex (trig[(ei+1)%3])];
|
||||||
const Point<2> p1 = P2(mesh[PointIndex (trig[(ei+2)%3])]);
|
const Point<2> p1 = points[PointIndex (trig[(ei+2)%3])];
|
||||||
const Point<2> p2 = P2(mesh[PointIndex (trig[ei])]);
|
const Point<2> p2 = points[PointIndex (trig[ei])];
|
||||||
auto v = p1-p0;
|
auto v = p1-p0;
|
||||||
|
|
||||||
Vec<2> n = {-v[1], v[0]};
|
Vec<2> n = {-v[1], v[0]};
|
||||||
@ -365,7 +283,7 @@ namespace netgen
|
|||||||
for (int l = 0; l < edges.Size(); l++)
|
for (int l = 0; l < edges.Size(); l++)
|
||||||
if (edges[l] == edge)
|
if (edges[l] == edge)
|
||||||
{
|
{
|
||||||
edges.RemoveElement(l);
|
edges.RemoveElement(l);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -373,47 +291,56 @@ namespace netgen
|
|||||||
edges.Append (edge);
|
edges.Append (edge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int j : intersecting)
|
void DelaunayMesh::CalcWeights( PointIndex pi_new, std::map<PointIndex, double> & weights )
|
||||||
{
|
{
|
||||||
UnsetNeighbours(j);
|
double eps = tree->GetTolerance();
|
||||||
trigs[j][0] = -1;
|
weights.clear();
|
||||||
trigs[j][1] = -1;
|
double sum = 0.0;
|
||||||
trigs[j][2] = -1;
|
auto p = points[pi_new];
|
||||||
}
|
auto pi_last = *points.Range().end()-3;
|
||||||
|
for(auto edge : edges)
|
||||||
for (auto edge : edges)
|
|
||||||
AppendTrig( edge[0], edge[1], pi_new );
|
|
||||||
|
|
||||||
for (int j : intersecting)
|
|
||||||
tree->DeleteElement (j);
|
|
||||||
|
|
||||||
static int counter=0;
|
|
||||||
if(0)
|
|
||||||
{
|
|
||||||
Mesh m;
|
|
||||||
m = mesh;
|
|
||||||
m.ClearSurfaceElements();
|
|
||||||
for (DelaunayTrig & trig : trigs)
|
|
||||||
{
|
{
|
||||||
if (trig[0] < 0) continue;
|
for(PointIndex pi : {edge[0], edge[1]})
|
||||||
|
{
|
||||||
Vec<3> n = Cross (mesh[trig[1]]-mesh[trig[0]],
|
if(pi>=pi_last)
|
||||||
mesh[trig[2]]-mesh[trig[0]]);
|
continue;
|
||||||
if (n(2) < 0) Swap (trig[1], trig[2]);
|
if(weights.count(pi))
|
||||||
|
continue;
|
||||||
Element2d el(trig[0], trig[1], trig[2]);
|
double weight = 1.0/(eps+Dist(p, points[pi]));
|
||||||
el.SetIndex (1);
|
sum += weight;
|
||||||
m.AddSurfaceElement (el);
|
weights[pi] = weight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m.Save("meshes/mesh_"+ToString(counter++)+".vol.gz");
|
double isum = 1.0/sum;
|
||||||
}
|
for(auto & [pi, weight] : weights)
|
||||||
|
weight *= isum;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
void DelaunayMesh::AddPoint( PointIndex pi_new, std::map<PointIndex, double> * weights )
|
||||||
|
{
|
||||||
|
static Timer t("AddPoint"); RegionTimer reg(t);
|
||||||
|
|
||||||
Array<DelaunayTrig> & GetElements() { return trigs; }
|
CalcIntersecting(pi_new);
|
||||||
|
|
||||||
};
|
if(weights)
|
||||||
|
CalcWeights(pi_new, *weights);
|
||||||
|
|
||||||
|
for (int j : intersecting)
|
||||||
|
{
|
||||||
|
UnsetNeighbours(j);
|
||||||
|
trigs[j][0] = -1;
|
||||||
|
trigs[j][1] = -1;
|
||||||
|
trigs[j][2] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto edge : edges)
|
||||||
|
AppendTrig( edge[0], edge[1], pi_new );
|
||||||
|
|
||||||
|
for (int j : intersecting)
|
||||||
|
tree->DeleteElement (j);
|
||||||
|
}
|
||||||
|
|
||||||
ostream & operator<< (ostream & ost, DelaunayTrig trig)
|
ostream & operator<< (ostream & ost, DelaunayTrig trig)
|
||||||
{
|
{
|
||||||
@ -699,26 +626,25 @@ namespace netgen
|
|||||||
Array<PointIndex, PointIndex> compress;
|
Array<PointIndex, PointIndex> compress;
|
||||||
Array<PointIndex, PointIndex> icompress(mesh.Points().Size());
|
Array<PointIndex, PointIndex> icompress(mesh.Points().Size());
|
||||||
|
|
||||||
/*
|
Array<Point<2>, PointIndex> temp_points;
|
||||||
for(auto pi : mesh.Points().Range())
|
|
||||||
if(add_point.Test(pi))
|
|
||||||
*/
|
|
||||||
for (PointIndex pi : addpoints)
|
for (PointIndex pi : addpoints)
|
||||||
{
|
{
|
||||||
icompress[pi] = tempmesh.AddPoint(mesh[pi]);
|
icompress[pi] = tempmesh.AddPoint(mesh[pi]);
|
||||||
compress.Append(pi);
|
compress.Append(pi);
|
||||||
|
temp_points.Append(P2(mesh[pi]));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PointIndex pi : Range(first_point_blockfill, last_point_blockfill))
|
for (PointIndex pi : Range(first_point_blockfill, last_point_blockfill))
|
||||||
{
|
{
|
||||||
icompress[pi] = tempmesh.AddPoint(mesh[pi]);
|
icompress[pi] = tempmesh.AddPoint(mesh[pi]);
|
||||||
compress.Append(pi);
|
compress.Append(pi);
|
||||||
|
temp_points.Append(P2(mesh[pi]));
|
||||||
}
|
}
|
||||||
t3.Stop();
|
t3.Stop();
|
||||||
// DelaunayMesh adds surrounding trig (don't add the last 3 points to delaunay AGAIN!
|
// DelaunayMesh adds surrounding trig (don't add the last 3 points to delaunay AGAIN!
|
||||||
auto tempmesh_points = tempmesh.Points().Range();
|
auto points_range = temp_points.Range();
|
||||||
|
|
||||||
DelaunayMesh dmesh(tempmesh, bbox);
|
DelaunayMesh dmesh(temp_points, bbox);
|
||||||
|
|
||||||
timer_addpoints.Start();
|
timer_addpoints.Start();
|
||||||
|
|
||||||
@ -736,7 +662,7 @@ namespace netgen
|
|||||||
// for (PointIndex pi : old_points)
|
// for (PointIndex pi : old_points)
|
||||||
// mixed[pi] = PointIndex ( (prim * pi) % old_points.Size() + PointIndex::BASE );
|
// mixed[pi] = PointIndex ( (prim * pi) % old_points.Size() + PointIndex::BASE );
|
||||||
|
|
||||||
for (auto pi : tempmesh_points)
|
for (auto pi : points_range)
|
||||||
dmesh.AddPoint(pi);
|
dmesh.AddPoint(pi);
|
||||||
|
|
||||||
timer_addpoints.Stop();
|
timer_addpoints.Stop();
|
||||||
|
72
libsrc/meshing/delaunay2d.hpp
Normal file
72
libsrc/meshing/delaunay2d.hpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include "meshing.hpp"
|
||||||
|
|
||||||
|
namespace netgen
|
||||||
|
{
|
||||||
|
static inline Point<2> P2( Point<3> p )
|
||||||
|
{
|
||||||
|
return {p[0], p[1]};
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline Point<3> P3( Point<2> p )
|
||||||
|
{
|
||||||
|
return {p[0], p[1], 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
class DelaunayTrig
|
||||||
|
{
|
||||||
|
PointIndex pnums[3];
|
||||||
|
Point<2> c;
|
||||||
|
|
||||||
|
public:
|
||||||
|
double r;
|
||||||
|
double rad2;
|
||||||
|
DelaunayTrig () = default;
|
||||||
|
DelaunayTrig (int p1, int p2, int p3)
|
||||||
|
{
|
||||||
|
pnums[0] = p1;
|
||||||
|
pnums[1] = p2;
|
||||||
|
pnums[2] = p3;
|
||||||
|
}
|
||||||
|
|
||||||
|
PointIndex & operator[] (int j) { return pnums[j]; }
|
||||||
|
const PointIndex & operator[] (int j) const { return pnums[j]; }
|
||||||
|
|
||||||
|
void CalcCenter (FlatArray<Point<2>, PointIndex> points);
|
||||||
|
|
||||||
|
Point<2> Center() const { return c; }
|
||||||
|
double Radius2() const { return rad2; }
|
||||||
|
Box<2> BoundingBox() const { return Box<2> (c-Vec<2>(r,r), c+Vec<2>(r,r)); }
|
||||||
|
|
||||||
|
mutable PointIndex visited_pi = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DelaunayMesh
|
||||||
|
{
|
||||||
|
ngcore::ClosedHashTable<INT<2>, INT<2>> edge_to_trig;
|
||||||
|
Array<DelaunayTrig> trigs;
|
||||||
|
unique_ptr<DelaunayTree<2>> tree;
|
||||||
|
Array<Point<2>, PointIndex> & points;
|
||||||
|
|
||||||
|
Array<int> closeels;
|
||||||
|
Array<int> intersecting;
|
||||||
|
Array<INT<2>> edges;
|
||||||
|
|
||||||
|
int GetNeighbour( int eli, int edge );
|
||||||
|
|
||||||
|
void SetNeighbour( int eli, int edge );
|
||||||
|
|
||||||
|
void UnsetNeighbours( int eli );
|
||||||
|
|
||||||
|
void AppendTrig( int pi0, int pi1, int pi2 );
|
||||||
|
|
||||||
|
public:
|
||||||
|
DelaunayMesh( Array<Point<2>, PointIndex> & points_, Box<2> box );
|
||||||
|
|
||||||
|
void CalcIntersecting( PointIndex pi_new );
|
||||||
|
void CalcWeights( PointIndex pi_new, std::map<PointIndex, double> & weights );
|
||||||
|
void AddPoint( PointIndex pi_new, std::map<PointIndex, double> * weights = nullptr );
|
||||||
|
Array<DelaunayTrig> & GetElements() { return trigs; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace netgen
|
Loading…
Reference in New Issue
Block a user