Merge branch 'faster_dbl_click' into 'master'

Speed up face/point selection in mesh scene

See merge request ngsolve/netgen!564
This commit is contained in:
Hochsteger, Matthias 2023-04-03 10:17:37 +02:00
commit 9180f9b972
5 changed files with 408 additions and 631 deletions

View File

@ -77,9 +77,11 @@ namespace netgen
int VisualScene :: locpi; int VisualScene :: locpi;
int VisualScene :: seledge; int VisualScene :: seledge;
int VisualScene :: selecttimestamp;
optional<Point<3>> VisualScene :: marker = nullopt; optional<Point<3>> VisualScene :: marker = nullopt;
int VisualScene :: subdivision_timestamp = -1;
int VisualScene :: subdivisions = 2;
int VisualScene :: viewport[4]; int VisualScene :: viewport[4];
VisualizationParameters :: VisualizationParameters() VisualizationParameters :: VisualizationParameters()

View File

@ -31,9 +31,10 @@ namespace netgen
static int locpi; static int locpi;
static int NGGUI_API seledge; static int NGGUI_API seledge;
static int selecttimestamp;
static optional<Point<3>> marker; static optional<Point<3>> marker;
static int subdivision_timestamp;
static int subdivisions;
public: public:
static int viewport[4]; static int viewport[4];
static GLuint coltexname; static GLuint coltexname;
@ -126,35 +127,54 @@ namespace netgen
class VisualSceneMesh : public VisualScene class VisualSceneMesh : public VisualScene
{ {
int filledlist; int filledlist = 0;
int linelist; int linelist = 0;
int edgelist; int edgelist = 0;
int pointnumberlist; int pointnumberlist = 0;
int tetlist; int tetlist = 0;
int prismlist; int prismlist = 0;
int pyramidlist; int pyramidlist = 0;
int hexlist; int hexlist = 0;
int badellist; int badellist = 0;
int identifiedlist; int identifiedlist = 0;
int domainsurflist; int domainsurflist = 0;
int vstimestamp;//, selecttimestamp; int vstimestamp = -1;
int filledtimestamp; int filledtimestamp = -1;
int linetimestamp; int linetimestamp = -1;
int edgetimestamp; int edgetimestamp = -1;
int pointnumbertimestamp; int pointnumbertimestamp = -1;
int tettimestamp; int tettimestamp = -1;
int prismtimestamp; int prismtimestamp = -1;
int pyramidtimestamp; int pyramidtimestamp = -1;
int hextimestamp; int hextimestamp = -1;
int badeltimestamp; int badeltimestamp = -1;
int identifiedtimestamp; int identifiedtimestamp = -1;
int domainsurftimestamp; int domainsurftimestamp = -1;
struct {
unsigned texture = -1;
int width = 0;
int height = 0;
int size = 0;
} colors;
struct {
unsigned framebuffer = 0;
unsigned render_buffers[2];
unsigned width = 0;
unsigned height = 0;
unsigned x = 0;
unsigned y = 0;
int list = 0;
int list_timestamp = -1;
double projmat[16];
int viewport[4];
} select;
#ifdef PARALLELGL #ifdef PARALLELGL
NgArray<int> par_linelists; NgArray<int> par_linelists;
@ -200,7 +220,9 @@ namespace netgen
{ return selelement; } { return selelement; }
NGGUI_API int SelectedPoint () const NGGUI_API int SelectedPoint () const
{ return selpoint; } { return selpoint; }
void BuildFilledList (bool names); void BuildFilledList (bool select);
void BuildColorTexture();
void SelectCenter(int zoomall);
// private: // private:
void BuildLineList(); void BuildLineList();
void BuildEdgeList(); void BuildEdgeList();
@ -215,7 +237,9 @@ namespace netgen
void BuildIdentifiedList(); void BuildIdentifiedList();
void BuildDomainSurfList(); void BuildDomainSurfList();
bool Unproject (int px, int py, Point<3> &p); bool SelectSurfaceElement (int px, int py, Point<3> &p, bool select_on_clipping_plane);
bool Unproject(int px, int py, Point<3> &p);
ngcore::INT<2> Project(Point<3> p);
}; };
NGGUI_API extern VisualSceneMesh vsmesh; NGGUI_API extern VisualSceneMesh vsmesh;

View File

@ -23,38 +23,9 @@ namespace netgen
VisualSceneMesh :: VisualSceneMesh () VisualSceneMesh :: VisualSceneMesh ()
: VisualScene() : VisualScene()
{ {
filledlist = 0;
linelist = 0;
edgelist = 0;
badellist = 0;
tetlist = 0;
prismlist = 0;
hexlist = 0;
pyramidlist = 0;
identifiedlist = 0;
pointnumberlist = 0;
domainsurflist = 0;
vstimestamp = -1; // GetTimeStamp();
selecttimestamp = -1; // GetTimeStamp();
filledtimestamp = -1; // GetTimeStamp();
linetimestamp = -1; // GetTimeStamp();
edgetimestamp = -1; // GetTimeStamp();
pointnumbertimestamp = -1; // GetTimeStamp();
tettimestamp = -1; // GetTimeStamp();
prismtimestamp = -1; // GetTimeStamp();
hextimestamp = -1; // GetTimeStamp();
pyramidtimestamp = -1; // GetTimeStamp();
badeltimestamp = -1; // GetTimeStamp();
identifiedtimestamp = -1; // GetTimeStamp();
domainsurftimestamp = -1; // GetTimeStamp();
selface = -1; selface = -1;
selelement = -1; selelement = -1;
locpi = 1; locpi = -2;
selpoint = PointIndex::INVALID; selpoint = PointIndex::INVALID;
selpoint2 = PointIndex::INVALID; selpoint2 = PointIndex::INVALID;
seledge = -1; seledge = -1;
@ -62,7 +33,6 @@ namespace netgen
minh = 0.0; minh = 0.0;
maxh = 0.0; maxh = 0.0;
user_me_handler = NULL; user_me_handler = NULL;
} }
VisualSceneMesh :: ~VisualSceneMesh () VisualSceneMesh :: ~VisualSceneMesh ()
@ -149,12 +119,8 @@ namespace netgen
SetClippingPlane (); SetClippingPlane ();
if (vispar.drawfilledtrigs) if (vispar.drawfilledtrigs)
{
if (filledtimestamp < mesh->GetTimeStamp () ||
filledtimestamp < selecttimestamp)
{ {
BuildFilledList (false); BuildFilledList (false);
}
#ifdef PARALLELGL #ifdef PARALLELGL
@ -219,7 +185,6 @@ namespace netgen
glPolygonOffset (1, 1); glPolygonOffset (1, 1);
glEnable (GL_POLYGON_OFFSET_LINE); glEnable (GL_POLYGON_OFFSET_LINE);
if (linetimestamp < mesh->GetTimeStamp ())
BuildLineList (); BuildLineList ();
#ifdef PARALLELGL #ifdef PARALLELGL
@ -288,6 +253,47 @@ namespace netgen
} }
void VisualSceneMesh :: SelectCenter (int zoomall)
{
shared_ptr<Mesh> mesh = GetMesh();
Point3d pmin, pmax;
mesh->GetBox (pmin, pmax, -1);
// works in NGSolve, mesh view
if (mesh->GetDimension() == 2)
mesh->GetBox (pmin, pmax);
else // otherwise strange zooms during mesh generation
mesh->GetBox (pmin, pmax, SURFACEPOINT);
if (vispar.use_center_coords && zoomall==2)
{
center.X() = vispar.centerx;
center.Y() = vispar.centery;
center.Z() = vispar.centerz;
}
else if (selpoint >= 1 && zoomall==2)
center = mesh->Point (selpoint);
else if (marker && zoomall==2)
center = *marker;
else if (vispar.centerpoint >= 1 && zoomall==2)
center = mesh->Point (vispar.centerpoint);
else
center = Center (pmin, pmax);
double oldrad = rad;
rad = 0.5 * Dist (pmin, pmax);
if(rad == 0) rad = 1e-6;
if (rad > 1.2 * oldrad ||
mesh->GetMajorTimeStamp() > vstimestamp ||
zoomall)
{
CalcTransformationMatrices();
}
glEnable (GL_NORMALIZE);
}
void VisualSceneMesh :: BuildScene (int zoomall) void VisualSceneMesh :: BuildScene (int zoomall)
{ {
@ -312,48 +318,11 @@ namespace netgen
Point3d pmin, pmax;
static double oldrad = 0;
NgArray<Element2d> faces; NgArray<Element2d> faces;
int meshtimestamp = mesh->GetTimeStamp(); int meshtimestamp = mesh->GetTimeStamp();
if (meshtimestamp > vstimestamp || zoomall) if (meshtimestamp > vstimestamp || zoomall)
{ SelectCenter(zoomall);
if (mesh->GetDimension() == 2)
{
// works in NGSolve, mesh view
mesh->GetBox (pmin, pmax);
}
else
{
// otherwise strange zooms douring mesh generation
mesh->GetBox (pmin, pmax, SURFACEPOINT);
}
if (vispar.use_center_coords && zoomall == 2)
{
center.X() = vispar.centerx; center.Y() = vispar.centery; center.Z() = vispar.centerz;
}
else if (selpoint >= 1 && zoomall == 2)
center = mesh->Point (selpoint);
else if (vispar.centerpoint >= 1 && zoomall == 2)
center = mesh->Point (vispar.centerpoint);
else
center = Center (pmin, pmax);
rad = 0.5 * Dist (pmin, pmax);
if(rad == 0) rad = 1e-6;
if (rad > 1.2 * oldrad ||
mesh->GetMajorTimeStamp() > vstimestamp ||
zoomall)
{
CalcTransformationMatrices();
oldrad = rad;
}
}
glEnable (GL_NORMALIZE);
if (pointnumberlist) if (pointnumberlist)
{ {
@ -882,13 +851,45 @@ namespace netgen
void VisualSceneMesh :: BuildColorTexture ()
{
shared_ptr<Mesh> mesh = GetMesh();
void VisualSceneMesh :: BuildFilledList (bool names) if(colors.texture == -1)
glGenTextures(1, &colors.texture);
// build color texture
glBindTexture(GL_TEXTURE_2D, colors.texture);
Array<float> data;
for(auto fdi : Range(1, mesh->GetNFD()+1))
{
auto c = mesh->GetFaceDescriptor(fdi).SurfColour();
ArrayMem<float, 4> cf{float(c[0]), float(c[1]), float(c[2]), float(c[3])};
if(fdi==selface)
cf = {1.0f, 0.0f, 0.0f, 1.0f};
data.Append(cf);
}
int n = data.Size()/4;
colors.width = min2(n, 1024);
colors.height = (n+colors.width-1)/colors.width;
for(auto i: Range(n, colors.width*colors.height))
data.Append({0.0f, 0.0f, 0.0f, 0.0f});
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, colors.width, colors.height, 0, GL_RGBA, GL_FLOAT, data.Data());
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
void VisualSceneMesh :: BuildFilledList (bool build_select)
{ {
shared_ptr<Mesh> mesh = GetMesh(); shared_ptr<Mesh> mesh = GetMesh();
static int timer = NgProfiler::CreateTimer ("Mesh::BuildFilledList"); static int timer = NgProfiler::CreateTimer ("Mesh::BuildFilledList");
NgProfiler::RegionTimer reg (timer); NgProfiler::RegionTimer reg (timer);
auto & list = build_select ? select.list : filledlist;
auto & timestamp = build_select ? select.list_timestamp : filledtimestamp;
if (list && timestamp > max(mesh->GetTimeStamp(), subdivision_timestamp))
return;
#ifdef PARALLELGL #ifdef PARALLELGL
if (id == 0 && ntasks > 1) if (id == 0 && ntasks > 1)
@ -901,18 +902,18 @@ namespace netgen
for ( int dest = 1; dest < ntasks; dest++ ) for ( int dest = 1; dest < ntasks; dest++ )
MyMPI_Recv (par_filledlists[dest], dest, MPI_TAG_VIS); MyMPI_Recv (par_filledlists[dest], dest, MPI_TAG_VIS);
if (filledlist) if (list)
glDeleteLists (filledlist, 1); glDeleteLists (list, 1);
filledlist = glGenLists (1); list = glGenLists (1);
glNewList (filledlist, GL_COMPILE); glNewList (list, GL_COMPILE);
for ( int dest = 1; dest < ntasks; dest++ ) for ( int dest = 1; dest < ntasks; dest++ )
glCallList (par_filledlists[dest]); glCallList (par_filledlists[dest]);
glEndList(); glEndList();
filledtimestamp = NextTimeStamp(); timestamp = NextTimeStamp();
return; return;
} }
@ -925,14 +926,18 @@ namespace netgen
lock -> Lock(); lock -> Lock();
} }
filledtimestamp = NextTimeStamp(); timestamp = NextTimeStamp();
if (filledlist) if(!build_select && !vispar.colormeshsize && colors.texture==-1)
glDeleteLists (filledlist, 1); BuildColorTexture();
filledlist = glGenLists (1); if (list)
glNewList (filledlist, GL_COMPILE); glDeleteLists (list, 1);
list = glGenLists (1);
glNewList (list, GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, colors.texture);
#ifdef STLGEOM #ifdef STLGEOM
STLGeometry * stlgeometry = dynamic_cast<STLGeometry*> (ng_geometry); STLGeometry * stlgeometry = dynamic_cast<STLGeometry*> (ng_geometry);
@ -964,9 +969,21 @@ namespace netgen
maxh = 10; maxh = 10;
} }
} }
else else if (build_select)
{
glDisable(GL_TEXTURE_1D);
glDisable(GL_TEXTURE_2D);
glDisable(GL_FOG);
glDisable(GL_LIGHTING);
glDisable (GL_COLOR_MATERIAL); glDisable (GL_COLOR_MATERIAL);
}
else
{
glDisable(GL_TEXTURE_1D);
glEnable(GL_TEXTURE_2D);
glEnable (GL_COLOR_MATERIAL);
glBindTexture(GL_TEXTURE_2D, colors.texture);
}
GLfloat matcol[] = { 0, 1, 0, 1 }; GLfloat matcol[] = { 0, 1, 0, 1 };
GLfloat matcolsel[] = { 1, 0, 0, 1 }; GLfloat matcolsel[] = { 1, 0, 0, 1 };
@ -976,7 +993,7 @@ namespace netgen
CurvedElements & curv = mesh->GetCurvedElements(); CurvedElements & curv = mesh->GetCurvedElements();
int hoplotn = 1 << vispar.subdivisions; int hoplotn = 1 << subdivisions;
Array<SurfaceElementIndex> seia; Array<SurfaceElementIndex> seia;
@ -985,18 +1002,13 @@ namespace netgen
{ {
mesh->GetSurfaceElementsOfFace (faceindex, seia); mesh->GetSurfaceElementsOfFace (faceindex, seia);
// Philippose - 06/07/2009 if(!build_select && !vispar.colormeshsize)
// Modified the colour system to integrate the face colours into {
// the mesh data structure, rather than limit it to the OCC geometry int i = faceindex-1;
// structure... allows other geometry types to use face colours too float x = (0.5+i%colors.width)/colors.width;
float y = (0.5+i/colors.width)/colors.height;
for (auto i : Range(4)) glTexCoord2f(x,y);
matcol[i] = mesh->GetFaceDescriptor(faceindex).SurfColour()[i]; }
if (faceindex == selface)
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcolsel);
else
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcol);
static Point<3> xa[129]; static Point<3> xa[129];
static Vec<3> na[129]; static Vec<3> na[129];
@ -1020,8 +1032,14 @@ namespace netgen
if (!drawel) if (!drawel)
continue; continue;
if (names) if (build_select)
glLoadName (sei+1); {
GLushort r,g,b;
r = (sei+1) % (1<<16);
g = (sei+1) >> 16;
b = 0;
glColor3us(r,g,b);
}
switch (el.GetType()) switch (el.GetType())
{ {
@ -1261,13 +1279,14 @@ namespace netgen
glLoadName (0); glLoadName (0);
glBindTexture(GL_TEXTURE_2D, 0);
glEndList (); glEndList ();
#ifdef PARALLELGL #ifdef PARALLELGL
glFinish(); glFinish();
if (id > 0) if (id > 0)
MyMPI_Send (filledlist, 0, MPI_TAG_VIS); MyMPI_Send (list, 0, MPI_TAG_VIS);
#endif #endif
} }
@ -1275,6 +1294,8 @@ namespace netgen
void VisualSceneMesh :: BuildLineList() void VisualSceneMesh :: BuildLineList()
{ {
shared_ptr<Mesh> mesh = GetMesh(); shared_ptr<Mesh> mesh = GetMesh();
if (linetimestamp > max(mesh->GetTimeStamp (), subdivision_timestamp))
return;
static int timer = NgProfiler::CreateTimer ("Mesh::BuildLineList"); static int timer = NgProfiler::CreateTimer ("Mesh::BuildLineList");
NgProfiler::RegionTimer reg (timer); NgProfiler::RegionTimer reg (timer);
@ -1335,7 +1356,7 @@ namespace netgen
glLineWidth (1.0f); glLineWidth (1.0f);
int hoplotn = 1 << vispar.subdivisions; int hoplotn = 1 << subdivisions;
// PrintMessage (3, "nse = ", mesh->GetNSE()); // PrintMessage (3, "nse = ", mesh->GetNSE());
for (SurfaceElementIndex sei = 0; sei < mesh->GetNSE(); sei++) for (SurfaceElementIndex sei = 0; sei < mesh->GetNSE(); sei++)
@ -1564,7 +1585,7 @@ namespace netgen
lock -> Lock(); lock -> Lock();
} }
if (edgetimestamp > mesh->GetTimeStamp () && vispar.drawtetsdomain == 0 if (edgetimestamp > max(mesh->GetTimeStamp(), subdivision_timestamp) && vispar.drawtetsdomain == 0
&& vispar.shrink == 1) && vispar.shrink == 1)
return; return;
@ -1621,7 +1642,7 @@ namespace netgen
if (mesh->GetCurvedElements().IsHighOrder()) if (mesh->GetCurvedElements().IsHighOrder())
{ {
int hoplotn = 1 << vispar.subdivisions; int hoplotn = 1 << subdivisions;
// mesh->GetCurvedElements().GetNVisualSubsecs(); // mesh->GetCurvedElements().GetNVisualSubsecs();
Point<3> x; Point<3> x;
@ -1832,7 +1853,7 @@ namespace netgen
else else
glShadeModel (GL_SMOOTH); glShadeModel (GL_SMOOTH);
int hoplotn = max (2, 1 << vispar.subdivisions); int hoplotn = max (2, 1 << subdivisions);
@ -2134,7 +2155,7 @@ namespace netgen
Point<3> grid[11][11]; Point<3> grid[11][11];
Point<3> fpts[4]; Point<3> fpts[4];
int order = vispar.subdivisions+1; int order = subdivisions+1;
for (int trig = 0; trig < 2; trig++) for (int trig = 0; trig < 2; trig++)
{ {
@ -2233,7 +2254,7 @@ namespace netgen
/* /*
int hoplotn = 1 << vispar.subdivisions; int hoplotn = 1 << subdivisions;
// int hoplotn = curv.GetNVisualSubsecs(); // int hoplotn = curv.GetNVisualSubsecs();
const Point3d * facepoint = MeshTopology :: GetVertices (TRIG); const Point3d * facepoint = MeshTopology :: GetVertices (TRIG);
@ -2521,7 +2542,7 @@ namespace netgen
Point<3> grid[11][11]; Point<3> grid[11][11];
Point<3> fpts[4]; Point<3> fpts[4];
int order = vispar.subdivisions+1; int order = subdivisions+1;
for (int quad = 0; quad<6; quad++) for (int quad = 0; quad<6; quad++)
{ {
@ -2672,7 +2693,7 @@ namespace netgen
Point<3> grid[11][11]; Point<3> grid[11][11];
Point<3> fpts[4]; Point<3> fpts[4];
int order = vispar.subdivisions+1; int order = subdivisions+1;
for (int trig = 0; trig < 4; trig++) for (int trig = 0; trig < 4; trig++)
{ {
@ -3097,28 +3118,105 @@ namespace netgen
bool VisualSceneMesh :: SelectSurfaceElement (int px, int py, Point<3> &p, bool select_on_clipping_plane)
bool VisualSceneMesh :: Unproject (int px, int py, Point<3> &p)
{ {
selelement = -1;
marker = nullopt;
shared_ptr<Mesh> mesh = GetMesh(); shared_ptr<Mesh> mesh = GetMesh();
if(px != select.x || py != select.y)
{
select.x = px;
select.y = py;
locpi = -2;
}
glGetIntegerv (GL_VIEWPORT, select.viewport);
GLenum err;
if(select.framebuffer == 0 || select.viewport[2] != select.width || select.viewport[3] != select.height)
{
select.width = select.viewport[2];
select.height = select.viewport[3];
if(select.framebuffer != 0)
{
glDeleteRenderbuffers(2, select.render_buffers);
glDeleteFramebuffers(1, &select.framebuffer);
}
glGenFramebuffers(1, &select.framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, select.framebuffer);
// create, reserve and attach color and depth renderbuffer
glGenRenderbuffers(2, select.render_buffers);
glBindRenderbuffer(GL_RENDERBUFFER, select.render_buffers[0]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB16, select.width, select.height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, select.render_buffers[0]);
glBindRenderbuffer(GL_RENDERBUFFER, select.render_buffers[1]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, select.width, select.height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, select.render_buffers[1]);
// check if framebuffer status is complete
if(int fbstatus; (fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE)
cerr << "no frame buffer " << fbstatus << endl;
}
glFlush();
glBindFramebuffer(GL_FRAMEBUFFER, select.framebuffer);
BuildFilledList (true); BuildFilledList (true);
marker = nullopt; glEnable(GL_DEPTH_TEST);
MouseDblClickSelect(px,py,clipplane,backcolor,transformationmat,center,rad, glClearColor(0, 0, 0, 1.0);
filledlist,selelement,selface,seledge,selpoint,selpoint2,locpi); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMultMatrixd (transformationmat);
GLdouble /* modelview[16], */ projection[16]; glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
GLint viewport[4]; auto hy = select.viewport[3] - py;
GLdouble result[3];
glGetDoublev(GL_PROJECTION_MATRIX, &projection[0]); SetClippingPlane();
glGetIntegerv(GL_VIEWPORT, &viewport[0]); if (vispar.clipping.enable)
{
Vec<3> n(clipplane[0], clipplane[1], clipplane[2]);
double len = Abs(n);
double mu = -clipplane[3] / (len*len);
Point<3> p (mu * n);
n /= len;
Vec<3> t1 = n.GetNormal ();
Vec<3> t2 = Cross (n, t1);
int hy = viewport[3]-py; double xi1mid = (center - p) * t1;
double xi2mid = (center - p) * t2;
GLfloat pz; if(select_on_clipping_plane)
{
glColor3us(0,0,0);
glBegin (GL_QUADS);
glVertex3dv (p + (xi1mid-rad) * t1 + (xi2mid-rad) * t2);
glVertex3dv (p + (xi1mid+rad) * t1 + (xi2mid-rad) * t2);
glVertex3dv (p + (xi1mid+rad) * t1 + (xi2mid+rad) * t2);
glVertex3dv (p + (xi1mid-rad) * t1 + (xi2mid+rad) * t2);
glEnd ();
}
}
glCallList (select.list);
glFinish();
glGetDoublev (GL_PROJECTION_MATRIX, select.projmat);
auto found = Unproject(px, py, p);
if(found)
{
marker = p;
GLushort numbers[3];
glReadPixels (px, hy, 1, 1, GL_RGB, GL_UNSIGNED_SHORT, numbers);
selelement = numbers[0] + numbers[1]*(1<<16);
locpi++;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glPopMatrix();
if(lock) if(lock)
{ {
@ -3127,59 +3225,81 @@ namespace netgen
lock = NULL; lock = NULL;
} }
// cout << "x, y = " << px << ", " << hy << endl; return found;
}
bool VisualSceneMesh :: Unproject(int px, int py, Point<3> &p)
{
auto hy = select.viewport[3] - py;
float pz;
glReadPixels (px, hy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &pz); glReadPixels (px, hy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &pz);
if(pz<1 && pz>0)
gluUnProject(px, hy, pz, transformationmat, select.projmat, select.viewport,
&p[0], &p[1], &p[2]);
return pz<1 && pz>0;
}
if(pz>=1.0) ngcore::INT<2> VisualSceneMesh :: Project(Point<3> p)
return false; {
if(pz<=0.0) Point<3> pwin;
return false; gluProject(p[0], p[1], p[2], transformationmat, select.projmat, select.viewport,
&pwin[0], &pwin[1], &pwin[2]);
// cout << "pz = " << pz << endl; return ngcore::INT<2>(pwin[0]+0.5, select.viewport[3]-pwin[1]+0.5);
gluUnProject(px, hy, pz, transformationmat, projection, viewport,
&result[0], &result[1], &result[2]);
p = Point<3>{result[0], result[1], result[2]};
marker = p;
return true;
} }
void VisualSceneMesh :: MouseDblClick (int px, int py) void VisualSceneMesh :: MouseDblClick (int px, int py)
{ {
Point<3> p; Point<3> p;
bool found_point = Unproject(px, py, p); bool found_point = SelectSurfaceElement(px, py, p, false);
if(selelement!=-1) if(selelement>0)
{ {
const Element2d & sel = GetMesh()->SurfaceElement(selelement); const Element2d & sel = GetMesh()->SurfaceElement(selelement);
SetSelectedFace(sel.GetIndex());
cout << "select element " << selelement auto pi_nearest = sel[0];
double min_dist = 1e99;
for(auto pi : sel.PNums())
if(Dist2(GetMesh()->Point(pi), p) < min_dist)
{
min_dist = Dist2(GetMesh()->Point(pi), p);
pi_nearest = pi;
}
auto p_win = Project(GetMesh()->Point(pi_nearest));
if(abs(p_win[0]-px) < 5 && abs(p_win[1]-py) < 5)
{
marker = GetMesh()->Point(pi_nearest);
selpoint = pi_nearest;
cout << "select point " << pi_nearest << " at " << *marker << endl;
locpi = -2;
}
else
{
if(locpi < 0)
{
cout << endl << "select element " << selelement
<< " on face " << sel.GetIndex() << endl; << " on face " << sel.GetIndex() << endl;
cout << "Nodes: "; cout << "\tpoint: " << p << endl;;
cout << "\tnodes: ";
for (int i = 1; i <= sel.GetNP(); i++) for (int i = 1; i <= sel.GetNP(); i++)
cout << sel.PNum(i) << " "; cout << sel.PNum(i) << " ";
cout << endl; cout << endl;
}
cout << "selected point " << selpoint else {
<< ", pos = " << GetMesh()->Point (selpoint) auto pi = sel[locpi%sel.GetNP()];
<< endl; marker = GetMesh()->Points()[pi];
cout << "select point " << pi << " at " << *marker << endl;
cout << "seledge = " << seledge << endl; }
}
} }
if(found_point) if(found_point && user_me_handler)
{
cout << "point : " << p << endl;
if (user_me_handler)
{ {
if (selelement != -1) if (selelement != -1)
user_me_handler -> DblClick (selelement-1, p[0], p[1], p[2]); user_me_handler -> DblClick (selelement-1, p[0], p[1], p[2]);
} }
}
selecttimestamp = NextTimeStamp();
if(lock) if(lock)
{ {
@ -3187,345 +3307,17 @@ namespace netgen
delete lock; delete lock;
lock = NULL; lock = NULL;
} }
/*
int i, hits;
// select surface triangle by mouse click
GLuint selbuf[10000];
glSelectBuffer (10000, selbuf);
glRenderMode (GL_SELECT);
GLint viewport[4];
glGetIntegerv (GL_VIEWPORT, viewport);
glMatrixMode (GL_PROJECTION);
glPushMatrix();
GLdouble projmat[16];
glGetDoublev (GL_PROJECTION_MATRIX, projmat);
glLoadIdentity();
gluPickMatrix (px, viewport[3] - py, 1, 1, viewport);
glMultMatrixd (projmat);
glClearColor(backcolor, backcolor, backcolor, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glPushMatrix();
glMultMatrixf (transformationmat);
// SetClippingPlane();
glInitNames();
glPushName (1);
glPolygonOffset (1, 1);
glEnable (GL_POLYGON_OFFSET_FILL);
glDisable(GL_CLIP_PLANE0);
if (vispar.clipenable)
{
Vec<3> n(clipplane[0], clipplane[1], clipplane[2]);
double len = Abs(n);
double mu = -clipplane[3] / (len*len);
Point<3> p (mu * n);
n /= len;
Vec<3> t1 = n.GetNormal ();
Vec<3> t2 = Cross (n, t1);
double xi1mid = (center - p) * t1;
double xi2mid = (center - p) * t2;
glLoadName (0);
glBegin (GL_QUADS);
glVertex3dv (p + (xi1mid-rad) * t1 + (xi2mid-rad) * t2);
glVertex3dv (p + (xi1mid+rad) * t1 + (xi2mid-rad) * t2);
glVertex3dv (p + (xi1mid+rad) * t1 + (xi2mid+rad) * t2);
glVertex3dv (p + (xi1mid-rad) * t1 + (xi2mid+rad) * t2);
glEnd ();
} }
// SetClippingPlane();
glCallList (filledlist);
glDisable (GL_POLYGON_OFFSET_FILL);
glPopName();
glMatrixMode (GL_PROJECTION);
glPopMatrix();
glMatrixMode (GL_MODELVIEW);
glPopMatrix();
glFlush();
hits = glRenderMode (GL_RENDER);
// cout << "hits = " << hits << endl;
int minname = 0;
GLuint mindepth = 0;
// find clippingplane
GLuint clipdepth = 0; // GLuint(-1);
for (i = 0; i < hits; i++)
{
int curname = selbuf[4*i+3];
if (!curname) clipdepth = selbuf[4*i+1];
}
for (i = 0; i < hits; i++)
{
int curname = selbuf[4*i+3];
GLuint curdepth = selbuf[4*i+1];
if (curname && (curdepth > clipdepth) &&
(curdepth < mindepth || !minname))
{
mindepth = curdepth;
minname = curname;
}
}
seledge = -1;
if (minname)
{
const Element2d & sel = mesh->SurfaceElement(minname);
cout << "select element " << minname
<< " on face " << sel.GetIndex() << endl;
cout << "Nodes: ";
for (i = 1; i <= sel.GetNP(); i++)
cout << sel.PNum(i) << " ";
cout << endl;
selelement = minname;
selface = mesh->SurfaceElement(minname).GetIndex();
locpi = (locpi % sel.GetNP()) + 1;
selpoint2 = selpoint;
selpoint = sel.PNum(locpi);
cout << "selected point " << selpoint
<< ", pos = " << mesh->Point (selpoint)
<< endl;
for (i = 1; i <= mesh->GetNSeg(); i++)
{
const Segment & seg = mesh->LineSegment(i);
if (seg[0] == selpoint && seg[1] == selpoint2 ||
seg[1] == selpoint && seg[0] == selpoint2)
{
seledge = seg.edgenr;
cout << "seledge = " << seledge << endl;
}
}
}
else
{
selface = -1;
selelement = -1;
selpoint = -1;
selpoint2 = -1;
}
glDisable(GL_CLIP_PLANE0);
selecttimestamp = NextTimeStamp();
*/
}
void MouseDblClickSelect (const int px, const int py,
const GLdouble * clipplane, const GLdouble backcolor,
const double * transformationmat,
const Point3d & center,
const double rad,
const int displaylist,
int & selelement, int & selface, int & seledge, PointIndex & selpoint,
PointIndex & selpoint2, int & locpi)
{
auto mesh = vsmesh.GetMesh();
int i, hits;
// select surface triangle by mouse click
GLuint selbuf[10000];
glSelectBuffer (10000, selbuf);
glRenderMode (GL_SELECT);
GLint viewport[4];
glGetIntegerv (GL_VIEWPORT, viewport);
glMatrixMode (GL_PROJECTION);
glPushMatrix();
GLdouble projmat[16];
glGetDoublev (GL_PROJECTION_MATRIX, projmat);
glLoadIdentity();
gluPickMatrix (px, viewport[3] - py, 1, 1, viewport);
glMultMatrixd (projmat);
glClearColor(backcolor, backcolor, backcolor, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glPushMatrix();
glMultMatrixd (transformationmat);
// SetClippingPlane();
glInitNames();
glPushName (1);
glPolygonOffset (1, 1);
glEnable (GL_POLYGON_OFFSET_FILL);
glDisable(GL_CLIP_PLANE0);
if (vispar.clipping.enable)
{
glEnable(GL_CLIP_PLANE0);
Vec<3> n(clipplane[0], clipplane[1], clipplane[2]);
double len = Abs(n);
double mu = -clipplane[3] / (len*len);
Point<3> p (mu * n);
n /= len;
Vec<3> t1 = n.GetNormal ();
Vec<3> t2 = Cross (n, t1);
double xi1mid = (center - p) * t1;
double xi2mid = (center - p) * t2;
glLoadName (0);
glBegin (GL_QUADS);
glVertex3dv (p + (xi1mid-rad) * t1 + (xi2mid-rad) * t2);
glVertex3dv (p + (xi1mid+rad) * t1 + (xi2mid-rad) * t2);
glVertex3dv (p + (xi1mid+rad) * t1 + (xi2mid+rad) * t2);
glVertex3dv (p + (xi1mid-rad) * t1 + (xi2mid+rad) * t2);
glEnd ();
}
// SetClippingPlane();
glCallList (displaylist);
glDisable (GL_POLYGON_OFFSET_FILL);
glPopName();
glMatrixMode (GL_PROJECTION);
glPopMatrix();
glMatrixMode (GL_MODELVIEW);
glPopMatrix();
glFlush();
hits = glRenderMode (GL_RENDER);
//cout << "hits = " << hits << endl;
int minname = 0;
GLuint mindepth = 0;
// find clippingplane
GLuint clipdepth = 0; // GLuint(-1);
for (i = 0; i < hits; i++)
{
int curname = selbuf[4*i+3];
if (!curname) clipdepth = selbuf[4*i+1];
}
for (i = 0; i < hits; i++)
{
int curname = selbuf[4*i+3];
GLuint curdepth = selbuf[4*i+1];
/*
cout << selbuf[4*i] << " " << selbuf[4*i+1] << " "
<< selbuf[4*i+2] << " " << selbuf[4*i+3] << endl;
*/
if (curname && (curdepth > clipdepth) &&
(curdepth < mindepth || !minname))
{
mindepth = curdepth;
minname = curname;
}
}
seledge = -1;
if (minname)
{
const Element2d & sel = mesh->SurfaceElement(minname);
selelement = minname;
selface = mesh->SurfaceElement(minname).GetIndex();
locpi = (locpi % sel.GetNP()) + 1;
selpoint2 = selpoint;
selpoint = sel.PNum(locpi);
for (i = 1; i <= mesh->GetNSeg(); i++)
{
const Segment & seg = mesh->LineSegment(i);
if ( (seg[0] == selpoint && seg[1] == selpoint2) ||
(seg[1] == selpoint && seg[0] == selpoint2) )
{
seledge = seg.edgenr;
}
}
}
else
{
selface = -1;
selelement = -1;
selpoint = -1;
selpoint2 = -1;
}
glDisable(GL_CLIP_PLANE0);
#ifdef PARALLELGL
vsmesh.Broadcast ();
#endif
}
void VisualSceneMesh :: SetSelectedFace (int asf) void VisualSceneMesh :: SetSelectedFace (int asf)
{
if(selface != asf)
{ {
selface = asf; selface = asf;
selecttimestamp = NextTimeStamp(); BuildColorTexture();
}
} }

View File

@ -791,35 +791,7 @@ namespace netgen
if (mesh->GetTimeStamp() > surfeltimestamp || zoomall) if (mesh->GetTimeStamp() > surfeltimestamp || zoomall)
{ {
// mesh has changed // mesh has changed
vsmesh.SelectCenter(zoomall);
Point3d pmin, pmax;
static double oldrad = 0;
mesh->GetBox (pmin, pmax, -1);
if(vispar.use_center_coords && zoomall == 2)
{
center.X() = vispar.centerx;
center.Y() = vispar.centery;
center.Z() = vispar.centerz;
}
else if(selpoint >= 1 && zoomall == 2)
center = mesh->Point(selpoint);
else if(vispar.centerpoint >= 1 && zoomall == 2)
center = mesh->Point(vispar.centerpoint);
else
center = Center (pmin, pmax);
rad = 0.5 * Dist (pmin, pmax);
if(rad == 0) rad = 1e-6;
glEnable (GL_NORMALIZE);
if (rad > 1.2 * oldrad ||
mesh->GetMajorTimeStamp() > surfeltimestamp ||
zoomall)
{
CalcTransformationMatrices();
oldrad = rad;
}
} }
DrawSurfaceElements(); DrawSurfaceElements();
@ -4775,6 +4747,7 @@ namespace netgen
auto printScalValue = [&formatComplex] auto printScalValue = [&formatComplex]
(SolData & sol, int comp, double value, double imag=0., bool iscomplex=false) (SolData & sol, int comp, double value, double imag=0., bool iscomplex=false)
{ {
cout << '\t';
if(sol.components>1) if(sol.components>1)
{ {
if(comp==0) if(comp==0)
@ -4806,8 +4779,15 @@ namespace netgen
} }
}; };
// Check if clipping plane is drawn at current mouse cursor position Point<3> p;
if(dim==3 && clipsolution && vispar.clipping.enable) bool found_point = vsmesh.SelectSurfaceElement(px, py, p, showclipsolution && clipsolution);
if(!found_point)
return;
// marker = p;
// found point on clipping plane
if(selelement==0)
{ {
GLint viewport[4]; GLint viewport[4];
GLdouble projection[16]; GLdouble projection[16];
@ -4815,33 +4795,26 @@ namespace netgen
glGetIntegerv(GL_VIEWPORT, &viewport[0]); glGetIntegerv(GL_VIEWPORT, &viewport[0]);
int hy = viewport[3]-py;
// manually intersect the view vector with the clipping plane (also working if clipping vectors are shown)
Point<3> p_clipping_plane;
gluUnProject(px, hy, 1.0, transformationmat, projection, viewport,
&p_clipping_plane[0], &p_clipping_plane[1], &p_clipping_plane[2]);
Point<3> eye; Point<3> eye;
gluUnProject( (viewport[2]-viewport[0])/2 , (viewport[3]-viewport[1])/2, gluUnProject( (viewport[2]-viewport[0])/2 , (viewport[3]-viewport[1])/2,
0.0, transformationmat, projection, viewport, &eye[0], &eye[1], &eye[2]); 0.0, transformationmat, projection, viewport, &eye[0], &eye[1], &eye[2]);
Vec<3> n{vispar.clipping.normal}; Vec<3> n{vispar.clipping.normal};
n.Normalize(); n.Normalize();
Vec<3> view = p_clipping_plane-eye; Vec<3> view = p-eye;
// check if we look at the clipping plane from the right direction // check if we look at the clipping plane from the right direction
if(n*view > 1e-8) if(n*view > 1e-8)
{ {
double lam = vispar.clipping.dist - Vec<3>{eye}*n; double lam = vispar.clipping.dist - Vec<3>{eye}*n;
lam /= n*view; lam /= n*view;
p_clipping_plane = eye + lam*view; p = eye + lam*view;
double lami[3]; double lami[3];
if(auto el3d = mesh->GetElementOfPoint( p_clipping_plane, lami )) if(auto el3d = mesh->GetElementOfPoint( p, lami ))
{ {
cout << endl << "Selected point " << p_clipping_plane << " on clipping plane" << endl; cout << endl << "Selected point " << p << " on clipping plane" << endl;
marker = p_clipping_plane; // marker = p;
bool have_scal_func = scalfunction!=-1 && soldata[scalfunction]->draw_volume; bool have_scal_func = scalfunction!=-1 && soldata[scalfunction]->draw_volume;
bool have_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_volume; bool have_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_volume;
@ -4875,22 +4848,10 @@ namespace netgen
} }
} }
// no point on clipping plane found -> continue searching for surface element
Point<3> p;
bool found_point = vsmesh.Unproject(px, py, p);
if(!found_point)
return;
marker = p;
if(selelement<=0)
return;
double lami[3] = {0.0, 0.0, 0.0}; double lami[3] = {0.0, 0.0, 0.0};
// Check if unprojected Point is close to surface element (eps of 1e-3 due to z-Buffer accuracy) // Check if unprojected Point is close to surface element (eps of 1e-3 due to z-Buffer accuracy)
bool found_2del = false; bool found_2del = false;
if(mesh->PointContainedIn2DElement(p, lami, selelement, false && fabs(lami[2])<1e-3)) if(selelement>0 && mesh->PointContainedIn2DElement(p, lami, selelement, false && fabs(lami[2])<1e-3))
{ {
// Found it, use coordinates of point projected to surface element // Found it, use coordinates of point projected to surface element
mesh->GetCurvedElements().CalcSurfaceTransformation({1.0-lami[0]-lami[1], lami[0]}, selelement-1, p); mesh->GetCurvedElements().CalcSurfaceTransformation({1.0-lami[0]-lami[1], lami[0]}, selelement-1, p);

View File

@ -94,7 +94,6 @@ class NGGUI_API VisualSceneSolution : public VisualScene
int fieldlinestimestamp, surface_vector_timestamp; int fieldlinestimestamp, surface_vector_timestamp;
int pointcurve_timestamp; int pointcurve_timestamp;
int isosurface_timestamp; int isosurface_timestamp;
int subdivision_timestamp;
int timetimestamp; int timetimestamp;
double minval, maxval; double minval, maxval;
@ -174,7 +173,6 @@ public:
int autoscale, logscale; int autoscale, logscale;
double mminval, mmaxval; double mminval, mmaxval;
int numisolines; int numisolines;
int subdivisions;
bool showclipsolution; bool showclipsolution;
bool showsurfacesolution; bool showsurfacesolution;