diff --git a/Fltk/openglWindow.cpp b/Fltk/openglWindow.cpp index 90d40f66fd3c10acbe1aad27daf2c2b508c227fa..0097e47b6d6315e651b225d2737a531d5ff447d5 100644 --- a/Fltk/openglWindow.cpp +++ b/Fltk/openglWindow.cpp @@ -14,7 +14,6 @@ #include "MElement.h" #include "Numeric.h" #include "FlGui.h" -#include "VertexArray.h" #include "Context.h" static void lassoZoom(drawContext *ctx, mousePosition &click1, mousePosition &click2) @@ -108,9 +107,9 @@ void openglWindow::draw() { // some drawing routines can create data (STL triangulations, etc.): // make sure that we don't fire draw() while we are already drawing, - // e.g. due to an impromptu Fl::check(). The same lock is also used in - // _processSelectionBuffer to guarantee that we don't mix GL_RENDER and - // GL_SELECT rendering passes. + // e.g. due to an impromptu Fl::check(). The same lock is also used + // in _select to guarantee that we don't mix GL_RENDER and GL_SELECT + // rendering passes. if(_lock) return; _lock = true; @@ -430,10 +429,9 @@ int openglWindow::handle(int event) std::vector<GFace*> faces; std::vector<GRegion*> regions; std::vector<MElement*> elements; - bool res = _processSelectionBuffer(_selection, false, - CTX::instance()->mouseHoverMeshes, - (int)_curr.win[0], (int)_curr.win[1], 5, 5, - vertices, edges, faces, regions, elements); + bool res = _select(_selection, false, CTX::instance()->mouseHoverMeshes, + (int)_curr.win[0], (int)_curr.win[1], 5, 5, + vertices, edges, faces, regions, elements); if((_selection == ENT_ALL && res) || (_selection == ENT_POINT && vertices.size()) || (_selection == ENT_LINE && edges.size()) || @@ -461,220 +459,24 @@ int openglWindow::handle(int event) } } -class hit{ - public: - GLuint type, ient, depth, type2, ient2; - hit(GLuint t, GLuint i, GLuint d, GLuint t2=0, GLuint i2=0) - : type(t), ient(i), depth(d), type2(t2), ient2(i2) {} -}; - -class hitDepthLessThan{ - public: - bool operator()(const hit &h1, const hit &h2) const - { - return h1.depth < h2.depth; - } -}; - -// returns the element at a given position in a vertex array (element -// pointers are not always stored: returning 0 is not an error) -static MElement *getElement(GEntity *e, int va_type, int index) +bool openglWindow::_select(int type, bool multiple, bool mesh, + int x, int y, int w, int h, + std::vector<GVertex*> &vertices, + std::vector<GEdge*> &edges, + std::vector<GFace*> &faces, + std::vector<GRegion*> ®ions, + std::vector<MElement*> &elements) { - switch(va_type){ - case 2: - if(e->va_lines && index < e->va_lines->getNumElementPointers()) - return *e->va_lines->getElementPointerArray(index); - break; - case 3: - if(e->va_triangles && index < e->va_triangles->getNumElementPointers()) - return *e->va_triangles->getElementPointerArray(index); - break; - } - return 0; -} - -bool openglWindow::_processSelectionBuffer(int type, bool multipleSelection, - bool meshSelection, int x, int y, int w, int h, - std::vector<GVertex*> &vertices, - std::vector<GEdge*> &edges, - std::vector<GFace*> &faces, - std::vector<GRegion*> ®ions, - std::vector<MElement*> &elements) -{ - vertices.clear(); - edges.clear(); - faces.clear(); - regions.clear(); - elements.clear(); - - // In our case the selection buffer size is equal to between 5 and 7 - // times the maximum number of possible hits - GModel *m = GModel::current(); - int eles = (meshSelection && CTX::instance()->pickElements) ? - 4 * m->getNumMeshElements() : 0; - int size = 7 * (m->getNumVertices() + m->getNumEdges() + m->getNumFaces() + - m->getNumRegions() + eles); - - if(!size) return false; // we won't get any hits: the model is empty! - - size += 1000; // security - // same lock as in draw() to prevent firing up a GL_SELECT rendering pass // while a GL_RENDER pass is happening (due to the asynchronus nature of // Fl::check()s if(_lock) return false; _lock = true; - make_current(); - GLuint *selectionBuffer = new GLuint[size]; - glSelectBuffer(size, selectionBuffer); - - glRenderMode(GL_SELECT); - _ctx->render_mode = drawContext::GMSH_SELECT; - - glInitNames(); - glPushMatrix(); - _ctx->initProjection(x, y, w, h); - _ctx->initPosition(); - _ctx->drawGeom(); - if(meshSelection) _ctx->drawMesh(); - glPopMatrix(); - - GLint numhits = glRenderMode(GL_RENDER); - _ctx->render_mode = drawContext::GMSH_RENDER; - + bool ret = _ctx->select(type, multiple, mesh, x, y, w, h, + vertices, edges, faces, regions, elements); _lock = false; - - if(!numhits){ // no hits - delete [] selectionBuffer; - return false; - } - else if(numhits < 0){ // overflow - delete [] selectionBuffer; - Msg::Warning("Too many entities selected"); - return false; - } - - std::vector<hit> hits; - GLuint *ptr = selectionBuffer; - for(int i = 0; i < numhits; i++) { - // in Gmsh 'names' should always be 0, 2 or 4: - // * names == 0 means that there is nothing on the stack - // * if names == 2, the first name is the type of the entity - // (0 for point, 1 for edge, 2 for face or 3 for volume) and - // the second is the entity number; - // * if names == 4, the first name is the type of the entity, - // the second is the entity number, the third is the type - // of vertex array (2 for line, 3 for triangle, 4 for quad) - // and the fourth is the index of the element in the vertex - // array - GLuint names = *ptr++; - *ptr++; // mindepth - GLuint maxdepth = *ptr++; - if(names == 2){ - GLuint depth = maxdepth; - GLuint type = *ptr++; - GLuint ient = *ptr++; - hits.push_back(hit(type, ient, depth)); - } - else if(names == 4){ - GLuint depth = maxdepth; - GLuint type = *ptr++; - GLuint ient = *ptr++; - GLuint type2 = *ptr++; - GLuint ient2 = *ptr++; - hits.push_back(hit(type, ient, depth, type2, ient2)); - } - } - - delete [] selectionBuffer; - - if(!hits.size()){ // no entities - return false; - } - - // sort hits to get closest entities first - std::sort(hits.begin(), hits.end(), hitDepthLessThan()); - - // filter result: if type == ENT_NONE, return the closest entity of - // "lowest dimension" (point < line < surface < volume). Otherwise, - // return the closest entity of type "type" - GLuint typmin = 10; - for(unsigned int i = 0; i < hits.size(); i++) - typmin = std::min(typmin, hits[i].type); - - for(unsigned int i = 0; i < hits.size(); i++) { - if((type == ENT_ALL) || - (type == ENT_NONE && hits[i].type == typmin) || - (type == ENT_POINT && hits[i].type == 0) || - (type == ENT_LINE && hits[i].type == 1) || - (type == ENT_SURFACE && hits[i].type == 2) || - (type == ENT_VOLUME && hits[i].type == 3)){ - switch (hits[i].type) { - case 0: - { - GVertex *v = m->getVertexByTag(hits[i].ient); - if(!v){ - Msg::Error("Problem in point selection processing"); - return false; - } - vertices.push_back(v); - if(!multipleSelection) return true; - } - break; - case 1: - { - GEdge *e = m->getEdgeByTag(hits[i].ient); - if(!e){ - Msg::Error("Problem in line selection processing"); - return false; - } - if(hits[i].type2){ - MElement *ele = getElement(e, hits[i].type2, hits[i].ient2); - if(ele) elements.push_back(ele); - } - edges.push_back(e); - if(!multipleSelection) return true; - } - break; - case 2: - { - GFace *f = m->getFaceByTag(hits[i].ient); - if(!f){ - Msg::Error("Problem in surface selection processing"); - return false; - } - if(hits[i].type2){ - MElement *ele = getElement(f, hits[i].type2, hits[i].ient2); - if(ele) elements.push_back(ele); - } - faces.push_back(f); - if(!multipleSelection) return true; - } - break; - case 3: - { - GRegion *r = m->getRegionByTag(hits[i].ient); - if(!r){ - Msg::Error("Problem in volume selection processing"); - return false; - } - if(hits[i].type2){ - MElement *ele = getElement(r, hits[i].type2, hits[i].ient2); - if(ele) elements.push_back(ele); - } - regions.push_back(r); - if(!multipleSelection) return true; - } - break; - } - } - } - - if(vertices.size() || edges.size() || faces.size() || - regions.size() || elements.size()) - return true; - return false; + return ret; } char openglWindow::selectEntity(int type, @@ -730,10 +532,10 @@ char openglWindow::selectEntity(int type, selectionMode = false; return 'c'; } - else if(_processSelectionBuffer(_selection, multi, true, _trySelectionXYWH[0], - _trySelectionXYWH[1], _trySelectionXYWH[2], - _trySelectionXYWH[3], vertices, edges, faces, - regions, elements)){ + else if(_select(_selection, multi, true, _trySelectionXYWH[0], + _trySelectionXYWH[1], _trySelectionXYWH[2], + _trySelectionXYWH[3], vertices, edges, faces, + regions, elements)){ _selection = ENT_NONE; selectionMode = false; if(add) diff --git a/Fltk/openglWindow.h b/Fltk/openglWindow.h index 85b3efdc760895327df90a06e141d1f56c44727b..af9c11c165a71e32b8375bdc311c6a7c4cf4a7ba 100644 --- a/Fltk/openglWindow.h +++ b/Fltk/openglWindow.h @@ -30,14 +30,10 @@ class openglWindow : public Fl_Gl_Window { double _lassoXY[2]; void _drawScreenMessage(); void _drawBorder(); - bool _processSelectionBuffer(int type, - bool multipleSelection, bool meshSelection, - int x, int y, int w, int h, - std::vector<GVertex*> &vertices, - std::vector<GEdge*> &edges, - std::vector<GFace*> &faces, - std::vector<GRegion*> ®ions, - std::vector<MElement*> &elements); + bool _select(int type, bool multiple, bool mesh, int x, int y, int w, int h, + std::vector<GVertex*> &vertices, std::vector<GEdge*> &edges, + std::vector<GFace*> &faces, std::vector<GRegion*> ®ions, + std::vector<MElement*> &elements); protected: void draw(); int handle(int); diff --git a/Graphics/drawContext.cpp b/Graphics/drawContext.cpp index 8e9eeaeff0f1a562a10d4dcb8bcac0e401ca385c..fd45d67146d28a200278c454b80fd81b4fa351a8 100644 --- a/Graphics/drawContext.cpp +++ b/Graphics/drawContext.cpp @@ -11,8 +11,10 @@ #include "Context.h" #include "Numeric.h" #include "GModel.h" +#include "MElement.h" #include "PView.h" #include "PViewOptions.h" +#include "VertexArray.h" #include "gl2ps.h" #if defined(HAVE_FLTK) @@ -644,3 +646,209 @@ void drawContext::world2Viewport(double xyz[3], double win[3]) glGetDoublev(GL_MODELVIEW_MATRIX, model); gluProject(xyz[0], xyz[1], xyz[2], model, proj, viewport, &win[0], &win[1], &win[2]); } + +class hit{ + public: + GLuint type, ient, depth, type2, ient2; + hit(GLuint t, GLuint i, GLuint d, GLuint t2=0, GLuint i2=0) + : type(t), ient(i), depth(d), type2(t2), ient2(i2) {} +}; + +class hitDepthLessThan{ + public: + bool operator()(const hit &h1, const hit &h2) const + { + return h1.depth < h2.depth; + } +}; + +// returns the element at a given position in a vertex array (element +// pointers are not always stored: returning 0 is not an error) +static MElement *getElement(GEntity *e, int va_type, int index) +{ + switch(va_type){ + case 2: + if(e->va_lines && index < e->va_lines->getNumElementPointers()) + return *e->va_lines->getElementPointerArray(index); + break; + case 3: + if(e->va_triangles && index < e->va_triangles->getNumElementPointers()) + return *e->va_triangles->getElementPointerArray(index); + break; + } + return 0; +} + +bool drawContext::select(int type, bool multiple, bool mesh, + int x, int y, int w, int h, + std::vector<GVertex*> &vertices, + std::vector<GEdge*> &edges, + std::vector<GFace*> &faces, + std::vector<GRegion*> ®ions, + std::vector<MElement*> &elements) +{ + vertices.clear(); + edges.clear(); + faces.clear(); + regions.clear(); + elements.clear(); + + // in our case the selection buffer size is equal to between 5 and 7 + // times the maximum number of possible hits + GModel *m = GModel::current(); + int eles = (mesh && CTX::instance()->pickElements) ? 4 * m->getNumMeshElements() : 0; + int size = 7 * (m->getNumVertices() + m->getNumEdges() + m->getNumFaces() + + m->getNumRegions() + eles); + + if(!size) return false; // the model is empty, don't bother! + + // allocate selection buffer + size += 1000; // just to make sure + GLuint *selectionBuffer = new GLuint[size]; + glSelectBuffer(size, selectionBuffer); + + // do one rendering pass in select mode + render_mode = drawContext::GMSH_SELECT; + glRenderMode(GL_SELECT); + glInitNames(); + glPushMatrix(); + initProjection(x, y, w, h); + initPosition(); + drawGeom(); + if(mesh) drawMesh(); + glPopMatrix(); + GLint numhits = glRenderMode(GL_RENDER); + render_mode = drawContext::GMSH_RENDER; + + if(!numhits){ // no hits + delete [] selectionBuffer; + return false; + } + else if(numhits < 0){ // overflow + delete [] selectionBuffer; + Msg::Warning("Too many entities selected"); + return false; + } + + // decode the hits + std::vector<hit> hits; + GLuint *ptr = selectionBuffer; + for(int i = 0; i < numhits; i++) { + // in Gmsh 'names' should always be 0, 2 or 4: + // * names == 0 means that there is nothing on the stack + // * if names == 2, the first name is the type of the entity + // (0 for point, 1 for edge, 2 for face or 3 for volume) and + // the second is the entity number; + // * if names == 4, the first name is the type of the entity, + // the second is the entity number, the third is the type + // of vertex array (2 for line, 3 for triangle, 4 for quad) + // and the fourth is the index of the element in the vertex + // array + GLuint names = *ptr++; + *ptr++; // mindepth + GLuint maxdepth = *ptr++; + if(names == 2){ + GLuint depth = maxdepth; + GLuint type = *ptr++; + GLuint ient = *ptr++; + hits.push_back(hit(type, ient, depth)); + } + else if(names == 4){ + GLuint depth = maxdepth; + GLuint type = *ptr++; + GLuint ient = *ptr++; + GLuint type2 = *ptr++; + GLuint ient2 = *ptr++; + hits.push_back(hit(type, ient, depth, type2, ient2)); + } + } + + delete [] selectionBuffer; + + if(!hits.size()){ // no entities + return false; + } + + // sort hits to get closest entities first + std::sort(hits.begin(), hits.end(), hitDepthLessThan()); + + // filter result: if type == ENT_NONE, return the closest entity of + // "lowest dimension" (point < line < surface < volume). Otherwise, + // return the closest entity of type "type" + GLuint typmin = 10; + for(unsigned int i = 0; i < hits.size(); i++) + typmin = std::min(typmin, hits[i].type); + + for(unsigned int i = 0; i < hits.size(); i++) { + if((type == ENT_ALL) || + (type == ENT_NONE && hits[i].type == typmin) || + (type == ENT_POINT && hits[i].type == 0) || + (type == ENT_LINE && hits[i].type == 1) || + (type == ENT_SURFACE && hits[i].type == 2) || + (type == ENT_VOLUME && hits[i].type == 3)){ + switch (hits[i].type) { + case 0: + { + GVertex *v = m->getVertexByTag(hits[i].ient); + if(!v){ + Msg::Error("Problem in point selection processing"); + return false; + } + vertices.push_back(v); + if(!multiple) return true; + } + break; + case 1: + { + GEdge *e = m->getEdgeByTag(hits[i].ient); + if(!e){ + Msg::Error("Problem in line selection processing"); + return false; + } + if(hits[i].type2){ + MElement *ele = getElement(e, hits[i].type2, hits[i].ient2); + if(ele) elements.push_back(ele); + } + edges.push_back(e); + if(!multiple) return true; + } + break; + case 2: + { + GFace *f = m->getFaceByTag(hits[i].ient); + if(!f){ + Msg::Error("Problem in surface selection processing"); + return false; + } + if(hits[i].type2){ + MElement *ele = getElement(f, hits[i].type2, hits[i].ient2); + if(ele) elements.push_back(ele); + } + faces.push_back(f); + if(!multiple) return true; + } + break; + case 3: + { + GRegion *r = m->getRegionByTag(hits[i].ient); + if(!r){ + Msg::Error("Problem in volume selection processing"); + return false; + } + if(hits[i].type2){ + MElement *ele = getElement(r, hits[i].type2, hits[i].ient2); + if(ele) elements.push_back(ele); + } + regions.push_back(r); + if(!multiple) return true; + } + break; + } + } + } + + if(vertices.size() || edges.size() || faces.size() || + regions.size() || elements.size()) + return true; + return false; +} diff --git a/Graphics/drawContext.h b/Graphics/drawContext.h index 2d7295c145ccad6d7dfa29c63e09df8029df27c8..4319b4f26c5c1987e77d8fcf953c2da6143f1875 100644 --- a/Graphics/drawContext.h +++ b/Graphics/drawContext.h @@ -27,6 +27,11 @@ class PView; class GModel; +class GVertex; +class GEdge; +class GFace; +class GRegion; +class MElement; class drawTransform { public: @@ -164,6 +169,10 @@ class drawContext { void unproject(double x, double y, double p[3], double d[3]); void viewport2World(double win[3], double xyz[3]); void world2Viewport(double xyz[3], double win[3]); + bool select(int type, bool multiple, bool mesh, int x, int y, int w, int h, + std::vector<GVertex*> &vertices, std::vector<GEdge*> &edges, + std::vector<GFace*> &faces, std::vector<GRegion*> ®ions, + std::vector<MElement*> &elements); int fix2dCoordinates(double *x, double *y); void draw3d(); void draw2d(); diff --git a/Mesh/Field.cpp b/Mesh/Field.cpp index c4063a46f765070fec93b8905809827edc8f625c..d8a1a71f59cc882e0595422cf3bbd00a3e8b08ff 100644 --- a/Mesh/Field.cpp +++ b/Mesh/Field.cpp @@ -1217,11 +1217,11 @@ class AttractorField : public Field dist = new ANNdist[1]; n_nodes_by_edge = 20; options["NodesList"] = new FieldOptionList - (nodes_id, "Indices of nodes in the geomtric model", &update_needed); + (nodes_id, "Indices of nodes in the geometric model", &update_needed); options["EdgesList"] = new FieldOptionList (edges_id, "Indices of curves in the geometric model", &update_needed); options["NNodesByEdge"] = new FieldOptionInt - (n_nodes_by_edge, "Number of nodes used to discetized each curve", + (n_nodes_by_edge, "Number of nodes used to discretized each curve", &update_needed); options["FacesList"] = new FieldOptionList (faces_id, "Indices of surfaces in the geometric model (Warning: might\n" diff --git a/utils/api_demos/mainAntTweakBar.cpp b/utils/api_demos/mainAntTweakBar.cpp index 0c6eb9b6542a6f5f03cab07c9e6be4012dbd8cd1..0e6a7ed6c0ea2243d0bed69caa31b5b87a779944 100644 --- a/utils/api_demos/mainAntTweakBar.cpp +++ b/utils/api_demos/mainAntTweakBar.cpp @@ -14,7 +14,9 @@ #include <gmsh/MElement.h> #include <gmsh/drawContext.h> -drawContext *ctx = 0; +static drawContext *ctx = 0; +static mousePosition clickPos, prevPos; +static int specialKey = 0; class drawContextTw : public drawContextGlobal{ public: @@ -70,9 +72,6 @@ void keyboard(unsigned char key, int x, int y) glutPostRedisplay(); } -static mousePosition clickPos, prevPos; -static int specialKey = 0; - void mouseMotion(int x, int y) { if(TwEventMouseMotionGLUT(x, y)) return; @@ -108,6 +107,29 @@ void mouseMotion(int x, int y) glutPostRedisplay(); } +void mousePassiveMotion(int x, int y) +{ + if(TwEventMouseMotionGLUT(x, y)) return; + + std::vector<GVertex*> vertices; + std::vector<GEdge*> edges; + std::vector<GFace*> faces; + std::vector<GRegion*> regions; + std::vector<MElement*> elements; + bool ret = ctx->select(ENT_ALL, false, false, x, y, 5, 5, + vertices, edges, faces, regions, elements); + if(ret){ + GEntity *ge = 0; + if(vertices.size()) ge = vertices[0]; + else if(edges.size()) ge = edges[0]; + else if(faces.size()) ge = faces[0]; + else if(regions.size()) ge = regions[0]; + MElement *me = elements.size() ? elements[0] : 0; + printf("%s %s\n", ge ? ge->getInfoString().c_str() : "", + me ? me->getInfoString().c_str() : ""); + } +} + void mouseButton(int button, int state, int x, int y) { if(TwEventMouseButtonGLUT(button, state, x, y)) return; @@ -214,7 +236,7 @@ int main(int argc, char **argv) glutReshapeFunc(reshape); glutMouseFunc(mouseButton); glutMotionFunc(mouseMotion); - glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT); + glutPassiveMotionFunc(mousePassiveMotion); glutKeyboardFunc(keyboard); glutSpecialFunc((GLUTspecialfun)TwEventSpecialGLUT); TwGLUTModifiersFunc(glutGetModifiers);