Path: blob/devel/ElmerGUI/Application/src/glwidget.cpp
3203 views
/*****************************************************************************1* *2* Elmer, A Finite Element Software for Multiphysical Problems *3* *4* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland *5* *6* This program is free software; you can redistribute it and/or *7* modify it under the terms of the GNU General Public License *8* as published by the Free Software Foundation; either version 2 *9* of the License, or (at your option) any later version. *10* *11* This program is distributed in the hope that it will be useful, *12* but WITHOUT ANY WARRANTY; without even the implied warranty of *13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *14* GNU General Public License for more details. *15* *16* You should have received a copy of the GNU General Public License *17* along with this program (in file fem/GPL-2); if not, write to the *18* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *19* Boston, MA 02110-1301, USA. *20* *21*****************************************************************************/2223/*****************************************************************************24* *25* ElmerGUI glwidget *26* *27*****************************************************************************28* *29* Authors: Mikko Lyly, Juha Ruokolainen and Peter RÃ¥back *30* Email: [email protected] *31* Web: http://www.csc.fi/elmer *32* Address: CSC - IT Center for Science Ltd. *33* Keilaranta 14 *34* 02101 Espoo, Finland *35* *36* Original Date: 15 Mar 2008 *37* *38*****************************************************************************/3940#include <QtGui>41#include <QtOpenGL>42#include <QWheelEvent>43#include <QKeyEvent>44#include <math.h>45#include <iostream>46#include <stdio.h>47#include "glwidget.h"48#include "mainwindow.h"4950using namespace std;5152#define MY_PI 3.1415926553#define ZSHIFT -5.05455// Get qreal regardless of whether it's float or double56static inline void glGetQrealv(GLenum e, GLfloat* data) { glGetFloatv(e,data); }57static inline void glGetQrealv(GLenum e, GLdouble* data) { glGetDoublev(e,data); }58static inline void glMultMatrixq( const GLdouble *m ) { glMultMatrixd(m); }59static inline void glMultMatrixq( const GLfloat *m ) { glMultMatrixf(m); }6061list_t::list_t()62{63nature = PDE_UNKNOWN;64type = UNKNOWNLIST;65index = -1;66object = 0;67child = -1;68parent = -1;69selected = false;70visible = false;71}7273list_t::~list_t()74{75}7677void list_t::setNature(int n)78{79this->nature = n;80}8182int list_t::getNature(void) const83{84return this->nature;85}8687void list_t::setType(int n)88{89this->type = n;90}9192int list_t::getType(void) const93{94return this->type;95}9697void list_t::setIndex(int n)98{99this->index = n;100}101102int list_t::getIndex(void) const103{104return this->index;105}106107void list_t::setObject(GLuint n)108{109this->object = n;110}111112GLuint list_t::getObject(void) const113{114return this->object;115}116117void list_t::setChild(int n)118{119this->child = n;120}121122int list_t::getChild(void) const123{124return this->child;125}126127void list_t::setParent(int n)128{129this->parent = n;130}131132int list_t::getParent(void) const133{134return this->parent;135}136137void list_t::setSelected(bool b)138{139this->selected = b;140}141142bool list_t::isSelected(void) const143{144return this->selected;145}146147void list_t::setVisible(bool b)148{149this->visible = b;150}151152bool list_t::isVisible(void) const153{154return this->visible;155}156157// Construct glWidget...158//-----------------------------------------------------------------------------159#if WITH_QT6160GLWidget::GLWidget(QWidget *parent)161: QOpenGLWidget(parent)162#else163GLWidget::GLWidget(QWidget *parent)164: QGLWidget(parent)165#endif166{167backgroundColor = Qt::white;168surfaceColor = Qt::cyan;169edgeColor = Qt::green;170surfaceMeshColor = Qt::black;171sharpEdgeColor = Qt::black;172selectionColor = Qt::red;173174stateOrtho = false;175stateFlatShade = true;176stateDrawSurfaceMesh = true;177stateDrawVolumeMesh = false;178stateDrawSharpEdges = true;179stateDrawSurfaceElements = true;180stateDrawEdgeElements = true;181stateDrawCoordinates = false;182stateDrawSurfaceNumbers = false;183stateDrawEdgeNumbers = false;184stateDrawNodeNumbers = false;185stateDrawBoundaryIndex = false;186stateDrawBodyIndex = false;187stateBcColors = false;188stateBodyColors = false;189190currentlySelectedBody = -1;191192drawScale = 1.0;193drawTranslate[0] = 0.0;194drawTranslate[1] = 0.0;195drawTranslate[2] = 0.0;196197mesh = NULL;198199helpers = new Helpers;200meshutils = new Meshutils;201202// Coordinate axis:203quadric_axis = gluNewQuadric();204205// Background image:206stateUseBgImage = false;207stateStretchBgImage = false;208stateAlignRightBgImage = false;209bgImageFileName = "";210bgTexture = 0;211bgSizeX = 0;212bgSizeY = 0;213}214215216// dtor...217//-----------------------------------------------------------------------------218GLWidget::~GLWidget()219{220}221222223// Min size hint...224//-----------------------------------------------------------------------------225QSize GLWidget::minimumSizeHint() const226{227return QSize(64, 64);228}229230231// Default size...232//-----------------------------------------------------------------------------233QSize GLWidget::sizeHint() const234{235return QSize(720, 576);236}237238void GLWidget::setMesh(mesh_t *m)239{240this->mesh = m;241}242243mesh_t* GLWidget::getMesh(void) const244{245return this->mesh;246}247248void GLWidget::newMesh(void)249{250this->mesh = new mesh_t;251}252253void GLWidget::deleteMesh(void)254{255delete this->mesh;256}257258bool GLWidget::hasMesh(void) const259{260if(this->mesh)261return true;262263return false;264}265266// Init GL...267//-----------------------------------------------------------------------------268void GLWidget::initializeGL()269{270cout << "Initialize GL" << endl;271272#if WITH_QT6273initializeOpenGLFunctions();274#endif275276cout << "Vendor: " << glGetString(GL_VENDOR) << endl;277cout << "Renderer: " << glGetString(GL_RENDERER) << endl;278cout << "Version: " << glGetString(GL_VERSION) << endl;279cout.flush();280281static GLfloat light_ambient[] = {0.2, 0.2, 0.2, 1.0};282static GLfloat light_diffuse[] = {0.6, 0.6, 0.6, 1.0};283static GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0};284static GLfloat light_position[] = {0.0, 0.0, 5.0, 0.0};285286static GLfloat mat_ambient[] = {0.2, 0.2, 0.2, 1.0};287static GLfloat mat_diffuse[] = {1.0, 1.0, 1.0, 1.0};288static GLfloat mat_specular[] = {0.9, 0.9, 0.9, 1.0};289static GLfloat high_shininess[] = {20.0};290291glMatrixMode(GL_MODELVIEW);292glLoadIdentity();293294glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);295glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, 1.0);296glEnable(GL_LIGHTING);297298glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER,1.0);299glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);300glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);301glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);302glLightfv(GL_LIGHT0, GL_POSITION, light_position);303glEnable(GL_LIGHT0);304305glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);306glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);307glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);308glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, high_shininess);309glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);310glEnable(GL_COLOR_MATERIAL);311312glEnable(GL_DEPTH_TEST);313glDepthFunc(GL_LESS);314// glDepthRange(-10.0, 10.0);315316glShadeModel(GL_SMOOTH);317// glEnable(GL_LINE_SMOOTH);318319glEnable(GL_NORMALIZE);320321#if WITH_QT6322glClearColor( backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), backgroundColor.alphaF());323#else324qglClearColor(backgroundColor);325#endif326327glEnable(GL_TEXTURE_2D);328}329330331332// Paint event...333//-----------------------------------------------------------------------------334void GLWidget::paintGL()335{336#if WITH_QT6337glClearColor( backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), backgroundColor.alphaF());338#endif339float xabs[3], xrel[3];340341glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);342343// Background image:344if(stateUseBgImage)345drawBgImage();346347// FE objects:348if(getLists() > 0) {349350for(int i = 0; i < getLists(); i++) {351list_t *l = getList(i);352353if(l->isVisible()) {354glPushName(i);355356if((l->getType() == SURFACEMESHLIST) && stateDrawSurfaceMesh) {357// translate slightly towards viewer358glMatrixMode(GL_PROJECTION);359glPushMatrix();360glTranslated(0, 0, 0.01);361glTranslated(0, 0, ZSHIFT);362glCallList(l->getObject());363glPopMatrix();364glMatrixMode(GL_MODELVIEW);365366} else if((l->getType() == VOLUMEMESHLIST) && stateDrawVolumeMesh) {367// translate slightly towards viewer368glMatrixMode(GL_PROJECTION);369glPushMatrix();370glTranslated(0, 0, 0.01);371glTranslated(0, 0, ZSHIFT);372glCallList(l->getObject());373glPopMatrix();374glMatrixMode(GL_MODELVIEW);375376} else if ((l->getType() == SHARPEDGELIST) && stateDrawSharpEdges) {377// translate slightly towards viewer378glMatrixMode(GL_PROJECTION);379glPushMatrix();380glTranslated(0, 0, 0.01);381glTranslated(0, 0, ZSHIFT);382glCallList(l->getObject());383glPopMatrix();384glMatrixMode(GL_MODELVIEW);385386} else if((l->getType() == EDGELIST) && stateDrawEdgeElements ) {387// translate slightly towards viewer388glMatrixMode(GL_PROJECTION);389glPushMatrix();390glTranslated(0, 0, 0.02);391glTranslated(0, 0, ZSHIFT);392glCallList(l->getObject());393glPopMatrix();394glMatrixMode(GL_MODELVIEW);395396} else if((l->getType() == SURFACELIST) && stateDrawSurfaceElements ) {397glMatrixMode(GL_PROJECTION);398glPushMatrix();399glTranslated(0, 0, ZSHIFT);400glCallList(l->getObject());401glPopMatrix();402glMatrixMode(GL_MODELVIEW);403404} else {405glMatrixMode(GL_PROJECTION);406glPushMatrix();407glTranslated(0, 0, ZSHIFT);408glCallList(l->getObject());409glPopMatrix();410glMatrixMode(GL_MODELVIEW);411}412413glPopName();414}415}416}417418if(stateDrawCoordinates) {419// push a dummy name420glPushName(DUMMY_NAME);421drawCoordinates();422glPopName();423}424425if(mesh) {426if(stateDrawSurfaceNumbers) {427glMatrixMode(GL_PROJECTION);428glPushMatrix();429glTranslated(0, 0, ZSHIFT);430glTranslated(0, 0, 0.1);431glColor3d(0.5, 0, 0);432433for(int i=0; i < mesh->getSurfaces(); i++) {434surface_t *surface = mesh->getSurface(i);435int nodes = surface->getCode() / 100;436437xabs[0] = xabs[1] = xabs[2] = 0.0;438439for(int j = 0; j < nodes; j++) {440int ind = surface->getNodeIndex(j);441xabs[0] = xabs[0] + mesh->getNode(ind)->getX(0);442xabs[1] = xabs[1] + mesh->getNode(ind)->getX(1);443xabs[2] = xabs[2] + mesh->getNode(ind)->getX(2);444}445446xrel[0] = (xabs[0]/nodes - drawTranslate[0]) / drawScale;447xrel[1] = (xabs[1]/nodes - drawTranslate[1]) / drawScale;448xrel[2] = (xabs[2]/nodes - drawTranslate[2]) / drawScale;449450renderText(xrel[0], xrel[1], xrel[2], QString::number(i+1) );451}452453glPopMatrix();454glMatrixMode(GL_MODELVIEW);455}456457if(stateDrawEdgeNumbers) {458glMatrixMode(GL_PROJECTION);459glPushMatrix();460glTranslated(0, 0, ZSHIFT);461glTranslated(0, 0, 0.1);462glColor3d(0.0, 0.5, 0);463464for(int i=0; i < mesh->getEdges(); i++) {465edge_t *edge = mesh->getEdge(i);466int nodes = edge->getCode() / 100;467468xabs[0] = xabs[1] = xabs[2] = 0.0;469470for(int j = 0; j < nodes; j++) {471int ind = edge->getNodeIndex(j);472xabs[0] = xabs[0] + mesh->getNode(ind)->getX(0);473xabs[1] = xabs[1] + mesh->getNode(ind)->getX(1);474xabs[2] = xabs[2] + mesh->getNode(ind)->getX(2);475}476xrel[0] = (xabs[0]/nodes - drawTranslate[0]) / drawScale;477xrel[1] = (xabs[1]/nodes - drawTranslate[1]) / drawScale;478xrel[2] = (xabs[2]/nodes - drawTranslate[2]) / drawScale;479480renderText(xrel[0], xrel[1], xrel[2], QString::number(i+1) );481}482483glPopMatrix();484glMatrixMode(GL_MODELVIEW);485}486487if(stateDrawNodeNumbers) {488glMatrixMode(GL_PROJECTION);489glPushMatrix();490glTranslated(0, 0, ZSHIFT);491glTranslated(0, 0, 0.1);492glColor3d(0, 0, 0.5);493494for(int i = 0; i < mesh->getNodes(); i++) {495xabs[0] = mesh->getNode(i)->getX(0);496xabs[1] = mesh->getNode(i)->getX(1);497xabs[2] = mesh->getNode(i)->getX(2);498499xrel[0] = (xabs[0] - drawTranslate[0]) / drawScale;500xrel[1] = (xabs[1] - drawTranslate[1]) / drawScale;501xrel[2] = (xabs[2] - drawTranslate[2]) / drawScale;502503renderText(xrel[0], xrel[1], xrel[2], QString::number(i+1) );504}505506glPopMatrix();507glMatrixMode(GL_MODELVIEW);508}509510if(stateDrawBoundaryIndex || stateDrawBodyIndex) {511glMatrixMode(GL_PROJECTION);512glPushMatrix();513glTranslated(0, 0, ZSHIFT);514glTranslated(0, 0, 0.1);515glColor3d(0.5, 0, 0);516517for(int i = 0; i < mesh->getEdges(); i++) {518edge_t *edge = mesh->getEdge(i);519int nodes = edge->getCode() / 100;520521xabs[0] = xabs[1] = xabs[2] = 0.0;522523for(int j = 0; j < nodes;j++) {524int ind = edge->getNodeIndex(j);525xabs[0] = xabs[0] + mesh->getNode(ind)->getX(0);526xabs[1] = xabs[1] + mesh->getNode(ind)->getX(1);527xabs[2] = xabs[2] + mesh->getNode(ind)->getX(2);528}529530xrel[0] = (xabs[0]/nodes - drawTranslate[0]) / drawScale;531xrel[1] = (xabs[1]/nodes - drawTranslate[1]) / drawScale;532xrel[2] = (xabs[2]/nodes - drawTranslate[2]) / drawScale;533534if(stateDrawBoundaryIndex && (edge->getNature() == PDE_BOUNDARY))535renderText(xrel[0], xrel[1], xrel[2], QString::number(edge->getIndex()));536537if(stateDrawBodyIndex && (edge->getNature() == PDE_BULK))538renderText(xrel[0], xrel[1], xrel[2], QString::number(edge->getIndex()));539}540541for(int i = 0; i < mesh->getSurfaces(); i++) {542surface_t *surface = mesh->getSurface(i);543int nodes = surface->getCode() / 100;544545xabs[0] = xabs[1] = xabs[2] = 0.0;546547for(int j = 0; j < nodes; j++) {548int ind = surface->getNodeIndex(j);549xabs[0] = xabs[0] + mesh->getNode(ind)->getX(0);550xabs[1] = xabs[1] + mesh->getNode(ind)->getX(1);551xabs[2] = xabs[2] + mesh->getNode(ind)->getX(2);552}553554xrel[0] = (xabs[0]/nodes - drawTranslate[0]) / drawScale;555xrel[1] = (xabs[1]/nodes - drawTranslate[1]) / drawScale;556xrel[2] = (xabs[2]/nodes - drawTranslate[2]) / drawScale;557558if(stateDrawBoundaryIndex && (surface->getNature() == PDE_BOUNDARY))559renderText(xrel[0], xrel[1], xrel[2], QString::number(surface->getIndex()));560561if(stateDrawBodyIndex && (surface->getNature() == PDE_BULK))562renderText(xrel[0], xrel[1], xrel[2], QString::number(surface->getIndex()));563564// case 3d:565if(stateDrawBodyIndex && (surface->getNature() == PDE_BOUNDARY)) {566for(int i = 0; i < surface->getElements(); i++) {567int j = surface->getElementIndex(i);568if(j >= 0) {569element_t *element = mesh->getElement(j);570renderText(xrel[0], xrel[1], xrel[2], QString::number(element->getIndex()));571}572}573}574575}576577glPopMatrix();578glMatrixMode(GL_MODELVIEW);579}580}581}582583584// Change projection...585//-----------------------------------------------------------------------------586void GLWidget::changeProjection()587{588GLint viewport[4];589glGetIntegerv(GL_VIEWPORT, viewport);590591int width = viewport[2];592int height = viewport[3];593double top = 1.0;594double bottom = -1.0;595double left = -(double)width / (double)height;596double right = (double)width / (double)height;597double _near = -10.0;598double _far = 10.0;599600if(stateOrtho) {601glViewport(0, 0, (GLint)width, (GLint)height);602glMatrixMode(GL_PROJECTION);603glLoadIdentity();604glOrtho(left, right, bottom, top, _near, _far);605glMatrixMode(GL_MODELVIEW);606} else {607glViewport(0, 0, (GLint)width, (GLint)height);608glMatrixMode(GL_PROJECTION);609glLoadIdentity();610gluPerspective(54.0, (float)width/(float)height, 0.1, 10.0);611glMatrixMode(GL_MODELVIEW);612}613}614615// Resize window...616//-----------------------------------------------------------------------------617void GLWidget::resizeGL(int width, int height)618{619double top = 1.0;620double bottom = -1.0;621double left = -(double)width / (double)height;622double right = (double)width / (double)height;623double _near = -10.0;624double _far = 10.0;625626if(stateOrtho) {627glViewport(0, 0, (GLint)width, (GLint)height);628glMatrixMode(GL_PROJECTION);629glLoadIdentity();630glOrtho(left, right, bottom, top, _near, _far);631glMatrixMode(GL_MODELVIEW);632} else {633glViewport(0, 0, (GLint)width, (GLint)height);634glMatrixMode(GL_PROJECTION);635glLoadIdentity();636gluPerspective(45.0, (float)width/(float)height, 0.1, 10.0);637glMatrixMode(GL_MODELVIEW);638}639}640641642// Focus in event...643//-----------------------------------------------------------------------------644void GLWidget::focusInEvent(QFocusEvent *event)645{646Q_UNUSED(event)647648// Should we check the key pressed status here?649}650651652// Key pressed...653//-----------------------------------------------------------------------------654void GLWidget::keyPressEvent(QKeyEvent *event)655{656if(event->key() == Qt::Key_Escape)657emit(escPressed());658}659660661// Key released...662//-----------------------------------------------------------------------------663void GLWidget::keyReleaseEvent(QKeyEvent *event)664{665}666667668669// Mouse button pressed...670//-----------------------------------------------------------------------------671void GLWidget::mousePressEvent(QMouseEvent *event)672{673lastPos = event->pos();674lastPressPos = event->pos();675setFocus(); // for tracing keyboard events676}677678// Mouse button released...679//-----------------------------------------------------------------------------680void GLWidget::mouseReleaseEvent(QMouseEvent *event)681{682if((event->button() == Qt::RightButton) && (event->pos() == lastPressPos)) {683#if WITH_QT6684((MainWindow*)parent())->showContextMenu(event->globalPosition().toPoint());685#else686((MainWindow*)parent())->showContextMenu(event->globalPos());687#endif688}689}690691// Mouse wheel rotates...692//-----------------------------------------------------------------------------693void GLWidget::wheelEvent(QWheelEvent *event)694{695#if WITH_QT6696makeCurrent();697double s = exp((double)(event->angleDelta().y())*0.001);698#else699double s = exp((double)(event->delta())*0.001);700#endif701glScaled(s, s, s);702updateGL();703#if WITH_QT6704lastPos = event->position().toPoint();705#else706lastPos = event->pos();707#endif708getMatrix();709}710711712713// Mouse moves...714//-----------------------------------------------------------------------------715void GLWidget::mouseMoveEvent(QMouseEvent *event)716{717#if WITH_QT6718makeCurrent();719#endif720721GLint viewport[4];722glGetIntegerv(GL_VIEWPORT, viewport);723724#if WITH_QT6725int dx = event->position().x() - lastPos.x();726int dy = event->position().y() - lastPos.y();727#else728int dx = event->x() - lastPos.x();729int dy = event->y() - lastPos.y();730#endif731732dy = -dy;733734if (735#if WITH_QT6736((event->buttons() & Qt::LeftButton) && (event->buttons() & Qt::MiddleButton))737#else738((event->buttons() & Qt::LeftButton) && (event->buttons() & Qt::MidButton))739#endif740||741event->buttons() == Qt::RightButton // added for easy scaling742) {743744// Scale:745double s = exp(dy*0.01);746glScaled(s, s, s);747updateGL();748749} else if (event->buttons() == Qt::LeftButton) {750751// Rotation:752double ax = -(double)dy;753double ay = (double)dx;754double az = 0.0;755756double s = 180.0*sqrt(ax*ax+ay*ay+az*az)/(double)(viewport[3]+1);757double bx = invmatrix[0]*ax + invmatrix[4]*ay + invmatrix[8]*az;758double by = invmatrix[1]*ax + invmatrix[5]*ay + invmatrix[9]*az;759double bz = invmatrix[2]*ax + invmatrix[6]*ay + invmatrix[10]*az;760glRotated(s, bx, by, bz);761updateGL();762763} else if (764#if WITH_QT6765(event->buttons() == Qt::MiddleButton)766#else767(event->buttons() == Qt::MidButton)768#endif769770||771(event->buttons() == (Qt::LeftButton | Qt::RightButton)) // added for 2 button mouse772){773774// Translation:775double s = 2.0/(double)(viewport[3]+1);776double ax = s*dx;777double ay = s*dy;778double az = 0.0;779glLoadIdentity();780glTranslated(ax, ay, az);781glMultMatrixq(matrix);782updateGL();783}784785lastPos = event->pos();786getMatrix();787}788789790791// Mouse button double clicked...792//-----------------------------------------------------------------------------793void GLWidget::mouseDoubleClickEvent(QMouseEvent *event)794{795#if WITH_QT6796makeCurrent();797#endif798if(getLists() == 0)799return;800801/*802To avoid segmentation fault in MSYS2 environment, compass, numbers and indexes are hidden.803These will be restored at the end of this function. Do not return before restoring these.804*/805bool prevStateDrawCoordinates = stateDrawCoordinates;806bool prevStateDrawSurfaceNumbers = stateDrawSurfaceNumbers;807bool prevStateDrawEdgeNumbers = stateDrawEdgeNumbers;808bool prevStateDrawNodeNumbers = stateDrawNodeNumbers;809bool prevStateDrawBoundaryIndex = stateDrawBoundaryIndex;810bool prevStateDrawBodyIndex = stateDrawBodyIndex;811stateDrawCoordinates = false;812stateDrawSurfaceNumbers = false;813stateDrawEdgeNumbers = false;814stateDrawNodeNumbers = false;815stateDrawBoundaryIndex = false;816stateDrawBodyIndex = false;817818819static list_t dummylist;820static GLuint buffer[1024];821const int bufferSize = sizeof(buffer)/sizeof(GLuint);822823GLint viewport[4];824GLdouble projection[16];825826GLint hits;827GLint i, j;828829updateGL();830#if WITH_QT6831makeCurrent();832#endif833834glSelectBuffer(bufferSize, buffer);835glRenderMode(GL_SELECT);836glInitNames();837838glMatrixMode(GL_PROJECTION);839glPushMatrix();840glGetIntegerv(GL_VIEWPORT, viewport);841glGetDoublev(GL_PROJECTION_MATRIX, projection);842glLoadIdentity();843844#if WITH_QT6845GLdouble x = event->position().x();846GLdouble y = (double)viewport[3]-event->position().y()-1;847#else848GLdouble x = event->x();849GLdouble y = (double)viewport[3]-event->y()-1;850#endif851852GLdouble deltaX = 3.0;853GLdouble deltaY = 3.0;854855gluPickMatrix(x, y, deltaX, deltaY, viewport);856glMultMatrixd(projection);857858glMatrixMode(GL_MODELVIEW);859860861/*This is to avoid segmentation fault in Linux with old hardware*/862setMeshVisibility(false, false, false);863864#if WITH_QT6865paintGL();866#else867updateGL();868#endif869870/*Again, this is to avoid segmentation fault in Linux with old hardware and to suppress blinking*/871setMeshVisibility(stateDrawSurfaceMesh, stateDrawVolumeMesh, stateDrawSharpEdges);872873hits = glRenderMode(GL_RENDER);874875bool badDriver = true;876GLuint smallestz = DUMMY_NAME;877GLuint nearest = DUMMY_NAME;878879if(hits != 0) {880for (i=0, j=0; i<hits; i++) {881GLuint minz = buffer[j+1];882GLuint resultz = buffer[j+3];883884badDriver = (badDriver && (minz == 0x80000000));885886if(minz < smallestz) {887nearest = resultz;888smallestz = minz;889}890891j += 3 + buffer[j];892}893}894895glMatrixMode(GL_PROJECTION);896glPopMatrix();897glMatrixMode(GL_MODELVIEW);898899if(badDriver) {900cerr << "Detected bad GL-context or broken graphics driver" << endl;901cerr.flush();902cout << "glRenderMode(GL_RENDER) produces bad z-values" << endl;903cout << "Unable to reliably select objects" << endl;904cout << "Vendor: " << glGetString(GL_VENDOR) << endl;905cout << "Renderer: " << glGetString(GL_RENDERER) << endl;906cout << "Version: " << glGetString(GL_VERSION) << endl;907cout.flush();908}909910// highlight the selected boundary:911if(nearest != DUMMY_NAME) {912list_t *l = getList(nearest);913914// skip sharp edge lists915if(l->getType() == SHARPEDGELIST) {916917/*918Restoration of view settings. These were adjusted at the beginning of this function.919*/920stateDrawCoordinates = prevStateDrawCoordinates;921stateDrawSurfaceNumbers = prevStateDrawSurfaceNumbers;922stateDrawEdgeNumbers = prevStateDrawEdgeNumbers;923stateDrawNodeNumbers = prevStateDrawNodeNumbers;924stateDrawBoundaryIndex = prevStateDrawBoundaryIndex;925stateDrawBodyIndex = prevStateDrawBodyIndex;926927928updateGL();929return;930}931932// substitute surfacemeshlist with the parent surfacelist:933if(l->getType() == SURFACEMESHLIST)934l = getList(l->getParent());935936// if not ctrl pressed, rebuild all selected lists except this one:937if(!(event->modifiers() & Qt::ControlModifier)) {938for(i = 0; i < getLists(); i++) {939list_t *l2 = getList(i);940if(l2->isSelected() && (l2->getIndex() != l->getIndex())) {941glDeleteLists(l2->getObject(), 1);942l2->setSelected(false);943if(l2->getType() == SURFACELIST) {944for( int j = 0; j < mesh->getSurfaces(); j++ ) {945surface_t *surf = mesh->getSurface(j);946if ( surf->getIndex() == l2->getIndex() )947surf->setSelected(l2->isSelected());948}949l2->setObject(generateSurfaceList(l2->getIndex(), surfaceColor)); // cyan950} else if(l2->getType() == EDGELIST) {951for( int j=0; j < mesh->getEdges(); j++ ) {952edge_t *edge = mesh->getEdge(j);953if ( edge->getIndex() == l2->getIndex() )954edge->setSelected(l2->isSelected());955}956l2->setObject(generateEdgeList(l2->getIndex(), edgeColor)); // green957}958}959}960}961962// Toggle selection:963l->setSelected(!l->isSelected());964965glDeleteLists(l->getObject(), 1);966967// Highlight current selection:968if(l->getType() == SURFACELIST) {969if(l->isSelected()) {970l->setObject(generateSurfaceList(l->getIndex(), selectionColor)); // red971} else {972l->setObject(generateSurfaceList(l->getIndex(), surfaceColor)); // cyan973}974975for( int i=0; i<mesh->getSurfaces(); i++ ) {976surface_t *surf = mesh->getSurface(i);977if ( surf->getIndex() == l->getIndex() ) surf->setSelected(l->isSelected());978}979980} else if(l->getType() == EDGELIST) {981if(l->isSelected()) {982l->setObject(generateEdgeList(l->getIndex(), selectionColor)); // red983} else {984l->setObject(generateEdgeList(l->getIndex(), edgeColor)); // green985}986for( int i=0; i < mesh->getEdges(); i++ ) {987edge_t *edge = mesh->getEdge(i);988if ( edge->getIndex() == l->getIndex() ) edge->setSelected(l->isSelected());989}990}991992// body selection:993//----------------994currentlySelectedBody = -1;995if( (event->modifiers() & Qt::ShiftModifier) || bodyEditActive) {996997// determine the max bulk index998int MAX_BULK_INDEX = -1;9991000for(int i = 0; i < mesh->getElements(); i++) {1001element_t *elem = mesh->getElement(i);1002if(elem->getNature() != PDE_BULK)1003break;1004if(elem->getIndex() > MAX_BULK_INDEX)1005MAX_BULK_INDEX = elem->getIndex();1006}10071008for(int i = 0; i < mesh->getSurfaces(); i++) {1009surface_t *surf = mesh->getSurface(i);1010if(surf->getNature() != PDE_BULK)1011break;1012if(surf->getIndex() > MAX_BULK_INDEX)1013MAX_BULK_INDEX = surf->getIndex();1014}10151016for(int i = 0; i < mesh->getEdges(); i++) {1017edge_t *edge = mesh->getEdge(i);1018if(edge->getNature() != PDE_BULK)1019break;1020if(edge->getIndex() > MAX_BULK_INDEX)1021MAX_BULK_INDEX = edge->getIndex();1022}10231024MAX_BULK_INDEX++;1025if(MAX_BULK_INDEX == 0) {1026cout << "Error in body selection: "1027"There are no legal body indices from which to choose" << endl;1028cout.flush();1029goto body_selection_finished;1030}10311032// allocate temp arrays:1033bool *tmp1 = new bool[MAX_BULK_INDEX];1034bool *tmp2 = new bool[MAX_BULK_INDEX];10351036for(int i = 0; i < MAX_BULK_INDEX; i++) {1037tmp1[i] = true;1038tmp2[i] = false;1039}10401041// check if the selected lists uniquely determine a bulk body:1042for(int i = 0; i < getLists(); i++) {1043list_t *l2 = getList(i);10441045if(l2->isSelected() && (l2->getNature() == PDE_BULK)) {1046for(int j = 0; j < MAX_BULK_INDEX; j++) {1047if(j != l2->getIndex())1048tmp1[j] = false;1049}1050}10511052if(l2->isSelected() && (l2->getNature() == PDE_BOUNDARY) &&1053(l2->getType() == SURFACELIST)) {1054for(int j = 0; j < mesh->getSurfaces(); j++) {1055surface_t *surf = mesh->getSurface(j);1056if(surf->getIndex() == l2->getIndex()) {1057for(int k = 0; k < surf->getElements(); k++) {1058int l = surf->getElementIndex(k);1059if(l < 0)1060break;1061element_t *elem = mesh->getElement(l);1062if((elem->getIndex() < 0) || (elem->getIndex() >= MAX_BULK_INDEX))1063break;1064tmp2[elem->getIndex()] = true;1065}1066for(int k = 0; k < MAX_BULK_INDEX; k++) {1067tmp1[k] &= tmp2[k];1068tmp2[k] = false;1069}1070}1071}1072}1073}10741075// array "tmp1" should contain only one entry with value "true"1076int count = 0;1077int found = -1;1078for(int i = 0; i < MAX_BULK_INDEX; i++) {1079if( tmp1[i] ) {1080count++;1081found = i;1082}1083// cout << i << ": tmp1,2= " << tmp1[i] << "," << tmp2[i] << endl;1084}10851086if((count == 1) && (found >= 0))1087currentlySelectedBody = found;1088else if((count > 1)){1089int m = mostVisibleBody(MAX_BULK_INDEX, tmp1);1090if(m >=0) currentlySelectedBody = m;1091}10921093delete [] tmp1;1094delete [] tmp2;1095}1096body_selection_finished:10971098// Emit result to mainwindow:1099emit(signalBoundarySelected(l, event->modifiers()));11001101} else {11021103// Emit "nothing selected":1104dummylist.setNature(-1);1105dummylist.setType(-1);1106dummylist.setIndex(-1);1107emit(signalBoundarySelected(&dummylist, event->modifiers()));11081109}11101111/*1112Restoration of view settings. These were adjusted at the beginning of this function.1113*/1114stateDrawCoordinates = prevStateDrawCoordinates;1115stateDrawSurfaceNumbers = prevStateDrawSurfaceNumbers;1116stateDrawEdgeNumbers = prevStateDrawEdgeNumbers;1117stateDrawNodeNumbers = prevStateDrawNodeNumbers;1118stateDrawBoundaryIndex = prevStateDrawBoundaryIndex;1119stateDrawBodyIndex = prevStateDrawBodyIndex;112011211122updateGL();1123}1124112511261127// Get current matrix and its inverse...1128//-----------------------------------------------------------------------------1129void GLWidget::getMatrix()1130{1131glGetQrealv(GL_MODELVIEW_MATRIX, matrix);1132helpers->invertMatrix(matrix, invmatrix);1133}1134113511361137// Rebuild lists...1138//-----------------------------------------------------------------------------1139void GLWidget::rebuildLists()1140{1141#if WITH_QT61142makeCurrent();1143#endif1144double *bb = mesh->boundingBox();11451146drawTranslate[0] = bb[6]; // x-center1147drawTranslate[1] = bb[7]; // y-center1148drawTranslate[2] = bb[8]; // z-center1149drawScale = bb[9]; // scaling11501151delete [] bb;11521153if(getLists() > 0) {1154for(int i=0; i < getLists(); i++) {1155list_t *l = getList(i);1156glDeleteLists(l->getObject(), 1);1157}1158}11591160makeLists();11611162updateGL();1163}11641165// Compose GL surface lists...1166//-----------------------------------------------------------------------------1167void GLWidget::rebuildSurfaceLists()1168{1169for( int i = 0; i < getLists(); i++ )1170{1171list_t *l = getList(i);1172if( l->getType() == SURFACELIST )1173{1174glDeleteLists( l->getObject(), 1 );1175if(l->isSelected()) {1176l->setObject(generateSurfaceList(l->getIndex(), selectionColor)); // red1177} else {1178l->setObject(generateSurfaceList(l->getIndex(), surfaceColor)); // cyan1179}1180}1181}1182}11831184// Compose GL edge lists...1185//-----------------------------------------------------------------------------1186void GLWidget::rebuildEdgeLists()1187{1188for( int i = 0; i < getLists(); i++ )1189{1190list_t *l = getList(i);1191if ( l->getType() == EDGELIST )1192{1193glDeleteLists( l->getObject(), 1 );1194if(l->isSelected()) {1195l->setObject(generateEdgeList(l->getIndex(), selectionColor)); // red1196} else {1197l->setObject(generateEdgeList(l->getIndex(), edgeColor)); // green1198}1199}1200}1201}1202120312041205// Compose GL object lists...1206//-----------------------------------------------------------------------------1207GLuint GLWidget::makeLists()1208{1209#if WITH_QT61210makeCurrent();1211#endif12121213int i;1214list_t *l;12151216if((mesh == NULL) || mesh->isUndefined())1217return 0;12181219// The rule for composing lists to display is the following:1220//---------------------------------------------------------------------------1221// - All surface elements with index >= 0 will be drawn - one list/index1222// (list->type = SURFACELIST)1223// - For each surface element list, one auxiliary list will be drawn1224// (list->type = SURFACEMESHLIST)1225// - All edge elements with index >= 0 will be drawn - one list/index1226// (list->type = EDGELIST)1227// - All point elements with index >= 0 will be drawn - one list/index1228// (list->type = POINTLIST)1229// - A list of sharp edges will always be drawn (even if it is empty)1230//---------------------------------------------------------------------------12311232// Simultaneously, populate hash for mapping body & boundary indices:1233//--------------------------------------------------------------------1234boundaryMap.clear();1235bodyMap.clear();1236int boundaryCount = 0;1237int bodyCount = 0;12381239// Scan volume elements to determine the number of material indices:1240//-------------------------------------------------------------------1241QMap<int, int> bodyNatures;12421243for(i = 0; i < mesh->getElements(); i++) {1244element_t *element = mesh->getElement(i);1245int index = element->getIndex();12461247if(index >= 0) {1248int nature = element->getNature();12491250if(!bodyNatures.contains(index))1251bodyNatures.insert(index, nature);1252}1253}12541255QMapIterator<int, int> itrBody(bodyNatures);1256while (itrBody.hasNext()) {1257itrBody.next();1258int index = itrBody.key();1259int nature = itrBody.value();12601261if(nature == PDE_BULK)1262bodyMap.insert(index, bodyCount++);1263}12641265// Scan surface elements to determine the number of bcs. / mat. indices:1266//-----------------------------------------------------------------------1267int surface_bcs = 0;12681269QMap<int, int> surfaceNatures;12701271for(i = 0; i < mesh->getSurfaces(); i++) {1272surface_t *surface = mesh->getSurface(i);1273int index = surface->getIndex();12741275if(index > 0) {1276int nature = surface->getNature();12771278if(!surfaceNatures.contains(index))1279surfaceNatures.insert(index, nature);1280}1281}12821283QMapIterator<int, int> itrSurface(surfaceNatures);1284while (itrSurface.hasNext()) {1285itrSurface.next();1286int index = itrSurface.key();1287int nature = itrSurface.value();12881289if(nature > 0) {1290surface_bcs++;12911292if(nature == PDE_BULK)1293bodyMap.insert(index, bodyCount++);12941295if(nature == PDE_BOUNDARY)1296boundaryMap.insert(index, boundaryCount++);1297}1298}12991300cout << "Bcs/materials on surface elements: " << surface_bcs << endl;1301cout.flush();13021303// Scan edge elements to determine the number of bcs. / mat. indices:1304//--------------------------------------------------------------------1305int edge_bcs = 0;13061307QMap<int, int> edgeNatures;13081309for(i = 0; i < mesh->getEdges(); i++) {1310edge_t *edge = mesh->getEdge(i);1311int index = edge->getIndex();13121313if(index > 0) {1314int nature = edge->getNature();13151316if(!edgeNatures.contains(index))1317edgeNatures.insert(index, nature);1318}1319}13201321QMapIterator<int, int> itrEdge(edgeNatures);1322while (itrEdge.hasNext()) {1323itrEdge.next();1324int index = itrEdge.key();1325int nature = itrEdge.value();13261327if(nature > 0) {1328edge_bcs++;13291330if(nature == PDE_BULK)1331bodyMap.insert(index, bodyCount++);13321333if(nature == PDE_BOUNDARY)1334boundaryMap.insert(index, boundaryCount++);1335}1336}13371338cout << "Bcs/materials on edge elements: " << edge_bcs << endl;1339cout.flush();13401341// Scan point elements to determine the number of bcs. / mat. indices:1342//---------------------------------------------------------------------1343int point_bcs = 0;13441345// TODO13461347cout << "Bcs/materials on point elements: " << point_bcs << endl;1348cout.flush();13491350// Generate lists:1351//---------------------------------------------------------------------1352for(i = 0; i < getLists(); i++)1353delete list.at(i);13541355list.clear();13561357cout << "Generating lists to display" << endl;1358cout.flush();13591360// Surface lists:1361//----------------1362for(i = 0; i < mesh->getSurfaces(); i++)1363mesh->getSurface(i)->setSelected(false);13641365itrSurface.toFront();1366while (itrSurface.hasNext()) {1367itrSurface.next();1368int index = itrSurface.key();1369int nature = itrSurface.value();13701371if(nature > 0) {1372l = new list_t;1373list.push_back(l);13741375l->setNature(nature);1376l->setType(SURFACELIST);1377l->setIndex(index);1378l->setObject(generateSurfaceList(l->getIndex(), surfaceColor)); // cyan1379l->setChild(getLists());1380l->setParent(-1);1381l->setSelected(false);1382l->setVisible(stateDrawSurfaceElements);13831384// edges of surface elements (just for visual):1385l = new list_t;1386list.push_back(l);13871388l->setNature(PDE_UNKNOWN);1389l->setType(SURFACEMESHLIST);1390l->setIndex(index);1391l->setObject(generateSurfaceMeshList(l->getIndex(), surfaceMeshColor)); // black1392l->setChild(-1);1393l->setParent(getLists() - 2);1394l->setSelected(false);1395l->setVisible(stateDrawSurfaceMesh);1396}1397}13981399// Edge lists (only PDE_BOUNDARY):1400//---------------------------------1401for(i = 0; i < mesh->getEdges(); i++)1402mesh->getEdge(i)->setSelected(false);14031404itrEdge.toFront();1405while (itrEdge.hasNext()) {1406itrEdge.next();1407int index = itrEdge.key();1408int nature = itrEdge.value();14091410if(nature > 0) {1411l = new list_t;1412list.push_back(l);14131414l->setNature(nature);1415l->setType(EDGELIST);1416l->setIndex(index);1417l->setObject(generateEdgeList(l->getIndex(), edgeColor)); // green1418l->setChild(-1);1419l->setParent(-1);1420l->setSelected(false);1421l->setVisible(stateDrawEdgeElements);1422}1423}14241425// Point lists: TODO14261427// Sharp edges (just for visual):1428//--------------------------------1429l = new list_t;1430list.push_back(l);14311432l->setNature(PDE_UNKNOWN);1433l->setType(SHARPEDGELIST);1434l->setIndex(-1);1435l->setObject(generateSharpEdgeList(sharpEdgeColor)); // black1436l->setChild(-1);1437l->setParent(-1);1438l->setSelected(false);1439l->setVisible(stateDrawSharpEdges);14401441// Volume mesh (visual only):1442//----------------------------1443l = new list_t;1444list.push_back(l);14451446l->setNature(PDE_UNKNOWN);1447l->setType(VOLUMEMESHLIST);1448l->setIndex(-1);1449l->setObject(generateVolumeMeshList(Qt::black)); // black1450l->setChild(-1);1451l->setParent(-1);1452l->setSelected(false);1453l->setVisible(stateDrawVolumeMesh);14541455// Clean up:1456//-----------1457edgeNatures.clear();1458surfaceNatures.clear();1459bodyNatures.clear();14601461updateGL();1462getMatrix();14631464cout << "Generated " << getLists() << " lists" << endl;1465cout.flush();14661467return getLists();1468}146914701471// Generate volume mesh list...1472//-----------------------------------------------------------------------------1473GLuint GLWidget::generateVolumeMeshList(QColor qColor)1474{1475static int tetmap[6][2] = {{0, 1}, {0, 2}, {0, 3},1476{1, 2}, {1, 3}, {2, 3}};14771478static int wedgemap[9][2] = {{0, 1}, {1, 2}, {2, 0},1479{0, 3}, {1, 4}, {2, 5},1480{3, 4}, {4, 5}, {5, 3}};148114821483static int hexmap[12][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0},1484{0, 4}, {1, 5}, {2, 6}, {3, 7},1485{4, 5}, {5, 6}, {6, 7}, {7, 4}};14861487double R = qColor.red() / 255.0;1488double G = qColor.green() / 255.0;1489double B = qColor.blue() / 255.0;14901491GLuint current = glGenLists(1);1492glNewList(current, GL_COMPILE);14931494glBegin(GL_LINES);14951496for(int i = 0; i < mesh->getElements(); i++) {1497element_t *element = mesh->getElement(i);14981499glColor3d(R, G, B);15001501int nofEdges = 0;1502int *edgeMap = 0;15031504switch((int)(element->getCode() / 100)) {1505case 5:1506nofEdges = 6;1507edgeMap = &tetmap[0][0];1508break;1509case 7:1510nofEdges = 9;1511edgeMap = &wedgemap[0][0];1512break;1513case 8:1514nofEdges = 12;1515edgeMap = &hexmap[0][0];1516break;1517}15181519// draw edges:1520for(int j = 0; j < nofEdges; j++) {1521int p0 = *edgeMap++;1522int p1 = *edgeMap++;15231524int q0 = element->getNodeIndex(p0);1525int q1 = element->getNodeIndex(p1);15261527node_t *n0 = mesh->getNode(q0);1528node_t *n1 = mesh->getNode(q1);15291530double x0 = ( n0->getX(0) - drawTranslate[0] ) / drawScale;1531double y0 = ( n0->getX(1) - drawTranslate[1] ) / drawScale;1532double z0 = ( n0->getX(2) - drawTranslate[2] ) / drawScale;15331534double x1 = ( n1->getX(0) - drawTranslate[0] ) / drawScale;1535double y1 = ( n1->getX(1) - drawTranslate[1] ) / drawScale;1536double z1 = ( n1->getX(2) - drawTranslate[2] ) / drawScale;15371538glVertex3d(x0, y0, z0);1539glVertex3d(x1, y1, z1);1540}1541}15421543glEnd();15441545glEndList();15461547return current;1548}1549155015511552// Generate surface list...1553//-----------------------------------------------------------------------------1554GLuint GLWidget::generateSurfaceList(int index, QColor qColor)1555{1556double x0[3], x1[3], x2[3], x3[3], u[3];15571558double R = qColor.red() / 255.0;1559double G = qColor.green() / 255.0;1560double B = qColor.blue() / 255.0;15611562GLuint current = glGenLists(1);1563glNewList(current, GL_COMPILE);15641565// Draw triangles:1566//-----------------1567glBegin(GL_TRIANGLES);15681569for(int i=0; i < mesh->getSurfaces(); i++) {1570surface_t *surface = mesh->getSurface(i);15711572if((surface->getIndex() == index) && ((int)(surface->getCode() / 100) == 3)) {15731574glColor3d(R, G, B);15751576if(stateBcColors && (surface->getNature() == PDE_BOUNDARY)) {1577double c[3];1578indexColors(c, index);1579glColor3d(c[0], c[1], c[2]);1580}15811582if(stateBodyColors) {1583int bodyIndex = surface->getIndex();1584if(surface->getNature() == PDE_BOUNDARY) {1585int parentIndex = surface->getElementIndex(0);1586element_t *parent = mesh->getElement(parentIndex);1587bodyIndex = parent->getIndex();1588}1589double c[3];1590indexColors(c, bodyIndex);1591glColor3d(c[0], c[1], c[2]);1592}15931594// change normal direction:1595changeNormalDirection(u, surface->getNormalVec());1596glNormal3dv(u);15971598int n0 = surface->getNodeIndex(0);1599int n1 = surface->getNodeIndex(1);1600int n2 = surface->getNodeIndex(2);16011602x0[0] = (mesh->getNode(n0)->getX(0) - drawTranslate[0]) / drawScale;1603x0[1] = (mesh->getNode(n0)->getX(1) - drawTranslate[1]) / drawScale;1604x0[2] = (mesh->getNode(n0)->getX(2) - drawTranslate[2]) / drawScale;16051606x1[0] = (mesh->getNode(n1)->getX(0) - drawTranslate[0]) / drawScale;1607x1[1] = (mesh->getNode(n1)->getX(1) - drawTranslate[1]) / drawScale;1608x1[2] = (mesh->getNode(n1)->getX(2) - drawTranslate[2]) / drawScale;16091610x2[0] = (mesh->getNode(n2)->getX(0) - drawTranslate[0]) / drawScale;1611x2[1] = (mesh->getNode(n2)->getX(1) - drawTranslate[1]) / drawScale;1612x2[2] = (mesh->getNode(n2)->getX(2) - drawTranslate[2]) / drawScale;16131614changeNormalDirection(u, surface->getVertexNormalVec(0));1615if ( !stateFlatShade ) glNormal3dv(u);1616glVertex3dv(x0);16171618changeNormalDirection(u, surface->getVertexNormalVec(1));1619if ( !stateFlatShade ) glNormal3dv(u);1620glVertex3dv(x1);16211622changeNormalDirection(u, surface->getVertexNormalVec(2));1623if ( !stateFlatShade ) glNormal3dv(u);1624glVertex3dv(x2);1625}1626}16271628glEnd();16291630// Draw quads:1631//------------1632glBegin(GL_QUADS);16331634for(int i=0; i < mesh->getSurfaces(); i++) {1635surface_t *surface = mesh->getSurface(i);16361637if((surface->getIndex() == index) && ((int)(surface->getCode() / 100) == 4)) {16381639glColor3d(R, G, B);16401641if(stateBcColors && (surface->getNature() == PDE_BOUNDARY)) {1642double c[3];1643indexColors(c, index);1644glColor3d(c[0], c[1], c[2]);1645}16461647if(stateBodyColors) {1648int bodyIndex = surface->getIndex();1649if(surface->getNature() == PDE_BOUNDARY) {1650int parentIndex = surface->getElementIndex(0);1651element_t *parent = mesh->getElement(parentIndex);1652bodyIndex = parent->getIndex();1653}1654double c[3];1655indexColors(c, bodyIndex);1656glColor3d(c[0], c[1], c[2]);1657}16581659// change normal direction:1660changeNormalDirection(u, surface->getNormalVec());1661glNormal3dv(u);16621663int n0 = surface->getNodeIndex(0);1664int n1 = surface->getNodeIndex(1);1665int n2 = surface->getNodeIndex(2);1666int n3 = surface->getNodeIndex(3);16671668x0[0] = (mesh->getNode(n0)->getX(0) - drawTranslate[0]) / drawScale;1669x0[1] = (mesh->getNode(n0)->getX(1) - drawTranslate[1]) / drawScale;1670x0[2] = (mesh->getNode(n0)->getX(2) - drawTranslate[2]) / drawScale;16711672x1[0] = (mesh->getNode(n1)->getX(0) - drawTranslate[0]) / drawScale;1673x1[1] = (mesh->getNode(n1)->getX(1) - drawTranslate[1]) / drawScale;1674x1[2] = (mesh->getNode(n1)->getX(2) - drawTranslate[2]) / drawScale;16751676x2[0] = (mesh->getNode(n2)->getX(0) - drawTranslate[0]) / drawScale;1677x2[1] = (mesh->getNode(n2)->getX(1) - drawTranslate[1]) / drawScale;1678x2[2] = (mesh->getNode(n2)->getX(2) - drawTranslate[2]) / drawScale;16791680x3[0] = (mesh->getNode(n3)->getX(0) - drawTranslate[0]) / drawScale;1681x3[1] = (mesh->getNode(n3)->getX(1) - drawTranslate[1]) / drawScale;1682x3[2] = (mesh->getNode(n3)->getX(2) - drawTranslate[2]) / drawScale;16831684changeNormalDirection(u, surface->getVertexNormalVec(0));1685if ( !stateFlatShade ) glNormal3dv(u);1686glVertex3dv(x0);16871688changeNormalDirection(u, surface->getVertexNormalVec(1));1689if ( !stateFlatShade ) glNormal3dv(u);1690glVertex3dv(x1);16911692changeNormalDirection(u, surface->getVertexNormalVec(2));1693if ( !stateFlatShade ) glNormal3dv(u);1694glVertex3dv(x2);16951696changeNormalDirection(u, surface->getVertexNormalVec(3));1697if ( !stateFlatShade ) glNormal3dv(u);1698glVertex3dv(x3);1699}1700}17011702glEnd();1703glEndList();17041705return current;1706}1707170817091710// Generate surface edge list...1711//-----------------------------------------------------------------------------1712GLuint GLWidget::generateSurfaceMeshList(int index, QColor qColor)1713{1714double x0[3], x1[3], x2[3], x3[3];17151716double R = qColor.red() / 255.0;1717double G = qColor.green() / 255.0;1718double B = qColor.blue() / 255.0;17191720GLuint current = glGenLists(1);1721glNewList(current, GL_COMPILE);17221723// Draw lines:1724//------------1725glLineWidth(1.0);1726glDisable(GL_LIGHTING);1727glColor3d(R, G, B);1728glBegin(GL_LINES);17291730for(int i=0; i < mesh->getSurfaces(); i++) {1731surface_t *surface = mesh->getSurface(i);17321733if((surface->getIndex() == index) && ((int)(surface->getCode() / 100) == 3)) {1734int n0 = surface->getNodeIndex(0);1735int n1 = surface->getNodeIndex(1);1736int n2 = surface->getNodeIndex(2);17371738x0[0] = (mesh->getNode(n0)->getX(0) - drawTranslate[0]) / drawScale;1739x0[1] = (mesh->getNode(n0)->getX(1) - drawTranslate[1]) / drawScale;1740x0[2] = (mesh->getNode(n0)->getX(2) - drawTranslate[2]) / drawScale;17411742x1[0] = (mesh->getNode(n1)->getX(0) - drawTranslate[0]) / drawScale;1743x1[1] = (mesh->getNode(n1)->getX(1) - drawTranslate[1]) / drawScale;1744x1[2] = (mesh->getNode(n1)->getX(2) - drawTranslate[2]) / drawScale;17451746x2[0] = (mesh->getNode(n2)->getX(0) - drawTranslate[0]) / drawScale;1747x2[1] = (mesh->getNode(n2)->getX(1) - drawTranslate[1]) / drawScale;1748x2[2] = (mesh->getNode(n2)->getX(2) - drawTranslate[2]) / drawScale;17491750glVertex3dv(x0);1751glVertex3dv(x1);17521753glVertex3dv(x1);1754glVertex3dv(x2);17551756glVertex3dv(x2);1757glVertex3dv(x0);1758}1759}17601761for(int i=0; i < mesh->getSurfaces(); i++) {1762surface_t *surface = mesh->getSurface(i);17631764if((surface->getIndex() == index) && ((int)(surface->getCode() / 100) == 4)) {1765int n0 = surface->getNodeIndex(0);1766int n1 = surface->getNodeIndex(1);1767int n2 = surface->getNodeIndex(2);1768int n3 = surface->getNodeIndex(3);17691770x0[0] = (mesh->getNode(n0)->getX(0) - drawTranslate[0]) / drawScale;1771x0[1] = (mesh->getNode(n0)->getX(1) - drawTranslate[1]) / drawScale;1772x0[2] = (mesh->getNode(n0)->getX(2) - drawTranslate[2]) / drawScale;17731774x1[0] = (mesh->getNode(n1)->getX(0) - drawTranslate[0]) / drawScale;1775x1[1] = (mesh->getNode(n1)->getX(1) - drawTranslate[1]) / drawScale;1776x1[2] = (mesh->getNode(n1)->getX(2) - drawTranslate[2]) / drawScale;17771778x2[0] = (mesh->getNode(n2)->getX(0) - drawTranslate[0]) / drawScale;1779x2[1] = (mesh->getNode(n2)->getX(1) - drawTranslate[1]) / drawScale;1780x2[2] = (mesh->getNode(n2)->getX(2) - drawTranslate[2]) / drawScale;17811782x3[0] = (mesh->getNode(n3)->getX(0) - drawTranslate[0]) / drawScale;1783x3[1] = (mesh->getNode(n3)->getX(1) - drawTranslate[1]) / drawScale;1784x3[2] = (mesh->getNode(n3)->getX(2) - drawTranslate[2]) / drawScale;17851786glVertex3dv(x0);1787glVertex3dv(x1);17881789glVertex3dv(x1);1790glVertex3dv(x2);17911792glVertex3dv(x2);1793glVertex3dv(x3);17941795glVertex3dv(x3);1796glVertex3dv(x0);1797}1798}1799glEnd();18001801glEnable(GL_LIGHTING);1802glEndList();18031804return current;1805}180618071808// Generate edge list...1809//-----------------------------------------------------------------------------1810GLuint GLWidget::generateEdgeList(int index, QColor qColor)1811{1812double x0[3], x1[3];18131814double R = qColor.red() / 255.0;1815double G = qColor.green() / 255.0;1816double B = qColor.blue() / 255.0;18171818GLuint current = glGenLists(1);1819glNewList(current, GL_COMPILE);1820glColor3d(R, G, B);1821glLineWidth(4.0);1822glDisable(GL_LIGHTING);1823glBegin(GL_LINES);18241825for(int i=0; i < mesh->getEdges(); i++) {1826edge_t *edge = mesh->getEdge(i);18271828if(edge->getIndex() == index) {1829int n0 = edge->getNodeIndex(0);1830int n1 = edge->getNodeIndex(1);18311832x0[0] = (mesh->getNode(n0)->getX(0) - drawTranslate[0]) / drawScale;1833x0[1] = (mesh->getNode(n0)->getX(1) - drawTranslate[1]) / drawScale;1834x0[2] = (mesh->getNode(n0)->getX(2) - drawTranslate[2]) / drawScale;18351836x1[0] = (mesh->getNode(n1)->getX(0) - drawTranslate[0]) / drawScale;1837x1[1] = (mesh->getNode(n1)->getX(1) - drawTranslate[1]) / drawScale;1838x1[2] = (mesh->getNode(n1)->getX(2) - drawTranslate[2]) / drawScale;18391840glVertex3dv(x0);1841glVertex3dv(x1);1842}1843}18441845glEnd();18461847glEnable(GL_LIGHTING);1848glEndList();18491850return current;1851}1852185318541855// Generate sharp edge list...1856//-----------------------------------------------------------------------------1857GLuint GLWidget::generateSharpEdgeList(QColor qColor)1858{1859double x0[3], x1[3];18601861double R = qColor.red() / 255.0;1862double G = qColor.green() / 255.0;1863double B = qColor.blue() / 255.0;18641865GLuint current = glGenLists(1);1866glNewList(current, GL_COMPILE);18671868glColor3d(R, G, B);1869glLineWidth(1.0);1870glDisable(GL_LIGHTING);1871glBegin(GL_LINES);18721873for(int i=0; i < mesh->getEdges(); i++) {1874edge_t *edge = mesh->getEdge(i);18751876if(edge->isSharp()) {1877int n0 = edge->getNodeIndex(0);1878int n1 = edge->getNodeIndex(1);18791880x0[0] = (mesh->getNode(n0)->getX(0) - drawTranslate[0]) / drawScale;1881x0[1] = (mesh->getNode(n0)->getX(1) - drawTranslate[1]) / drawScale;1882x0[2] = (mesh->getNode(n0)->getX(2) - drawTranslate[2]) / drawScale;18831884x1[0] = (mesh->getNode(n1)->getX(0) - drawTranslate[0]) / drawScale;1885x1[1] = (mesh->getNode(n1)->getX(1) - drawTranslate[1]) / drawScale;1886x1[2] = (mesh->getNode(n1)->getX(2) - drawTranslate[2]) / drawScale;18871888glVertex3dv(x0);1889glVertex3dv(x1);1890}1891}18921893glEnd();1894glEnable(GL_LIGHTING);1895glEndList();18961897return current;1898}189919001901// Draw coordinates:1902//-----------------------------------------------------------------------------1903void GLWidget::drawCoordinates()1904{1905glMatrixMode(GL_PROJECTION);1906glPushMatrix();19071908// glTranslated(-0.8, -0.8, 5.0);1909glTranslated(-0.8, -0.8, ZSHIFT);19101911glMatrixMode(GL_MODELVIEW);19121913// z-axis1914glColor3d(0, 0, 1);1915gluCylinder(quadric_axis, 0.02, 0.0, 0.2, 8, 8);1916renderText(0.0, 0.0, 0.25, "Z");19171918// x-axis1919glColor3d(1, 0, 0);1920glRotated(90, 0, 1, 0);1921gluCylinder(quadric_axis, 0.02, 0.0, 0.2, 8, 8);1922renderText(0.0, 0.0, 0.25, "X");1923glRotated(-90, 0, 1, 0);19241925// y-axis1926glColor3d(0, 1, 0);1927glRotated(-90, 1, 0, 0);1928gluCylinder(quadric_axis, 0.02, 0.0, 0.2, 8, 8);1929renderText(0.0, 0.0, 0.25, "Y");1930glRotated(90, 1, 0, 0);19311932glMatrixMode(GL_PROJECTION);1933glPopMatrix();19341935glMatrixMode(GL_MODELVIEW);19361937return;1938}19391940bool GLWidget::toggleCoordinates()1941{1942#if WITH_QT61943makeCurrent();1944#endif1945stateDrawCoordinates = !stateDrawCoordinates;1946updateGL();1947return stateDrawCoordinates;1948}19491950// Draw background image...1951//-----------------------------------------------------------------------------1952void GLWidget::drawBgImage()1953{1954GLint viewport[4];19551956if(!bgTexture) {1957#if WITH_QT5 || WITH_QT61958cout << "Bind texture " << string(bgImageFileName.toLatin1()) << "... ";1959QOpenGLTexture texture(QImage(bgImageFileName).mirrored());1960bgSizeX = texture.width();1961bgSizeY = texture.height();1962bgTexture = texture.textureId();1963cout << "done" << endl;1964#else1965cout << "Bind texture " << string(bgImageFileName.toAscii()) << "... ";1966QPixmap pixmap(bgImageFileName);1967bgSizeX = pixmap.width();1968bgSizeY = pixmap.height();1969bgTexture = bindTexture(pixmap, GL_TEXTURE_2D);1970cout << "done" << endl;1971#endif1972}19731974if(!bgTexture) {1975cout << "Failed to bind texture" << endl;1976stateUseBgImage = false;1977return;1978}19791980glGetIntegerv(GL_VIEWPORT, viewport);19811982double relativeSizeX = (double)viewport[2] / (double)viewport[3];1983double relativeSizeY = 1.0;19841985double bgRelativeSizeX = (double)bgSizeX / (double)viewport[3];1986double bgRelativeSizeY = (double)bgSizeY / (double)viewport[3];19871988double width = 1.0;1989double height = 1.0;1990double depth = 9.9;1991double xshift = 0.0;1992double yshift = 0.0;19931994if(stateAlignRightBgImage) {1995width = bgRelativeSizeX;1996height = bgRelativeSizeY;1997xshift = relativeSizeX - bgRelativeSizeX;1998yshift = bgRelativeSizeY - relativeSizeY;1999}20002001if(stateStretchBgImage) {2002width = (double)viewport[2] / (double)viewport[3];2003height = 1.0;2004xshift = 0.0;2005yshift = 0.0;2006}20072008glDisable(GL_DEPTH_TEST);2009glPushMatrix();2010glLoadIdentity();2011glColor3d(1, 1, 1);2012glDisable(GL_LIGHTING);2013glEnable(GL_TEXTURE_2D);2014glBindTexture(GL_TEXTURE_2D, bgTexture);20152016glBegin(GL_QUADS);2017glTexCoord2d(0, 0);2018glVertex3d(-width+xshift, -height+yshift, -depth);2019glTexCoord2d(1, 0);2020glVertex3d(+width+xshift, -height+yshift, -depth);2021glTexCoord2d(1, 1);2022glVertex3d(+width+xshift, +height+yshift, -depth);2023glTexCoord2d(0, 1);2024glVertex3d(-width+xshift, +height+yshift, -depth);2025glEnd();20262027glDisable(GL_TEXTURE_2D);2028glEnable(GL_LIGHTING);2029glPopMatrix();2030glEnable(GL_DEPTH_TEST);2031}203220332034// Auxiliary function for changing the direction of a vector...2035//---------------------------------------------------------------------------2036void GLWidget::changeNormalDirection(double *u, double *v)2037{2038u[0] = -v[0];2039u[1] = -v[1];2040u[2] = -v[2];2041}20422043list_t* GLWidget::getList(int i) const2044{2045return list.at(i);2046}20472048int GLWidget::getLists() const2049{2050return list.count();2051}20522053// Set 'c' to an RGB color corresponding to index 'i'.2054// 'c' should be pre-allocated to a length of at least 3.2055void GLWidget::indexColors(double *c, int i)2056{2057c[0] = 0.5 + 0.5 * sin(1.0 * i);2058c[1] = 0.5 + 0.5 * cos(2.0 * i);2059c[2] = 0.5 + 0.5 * cos(3.0 * i);2060}20612062void GLWidget::indexColors(int *c, int i)2063{2064double tmp[3];20652066indexColors(tmp, i);2067for (int j = 0; j < 3; j++) c[j] = int(tmp[j]*255 + 0.5);2068}206920702071void GLWidget::setMeshVisibility(bool stateDrawSurfaceMesh, bool stateDrawVolumeMesh, bool stateDrawSharpEdges){2072/*2073This function is used in mouseDoubleClickEvent(mouseEvent event) to avoid segmentation fault observed Linux2074environment with old hardware.2075*/20762077mesh_t *mesh = getMesh();2078int lists = getLists();20792080if (mesh == NULL) {2081return;2082}208320842085for (int i = 0; i < lists; i++) {2086list_t *l = getList(i);2087int type = l->getType();2088if (type == SURFACEMESHLIST) {2089l->setVisible(stateDrawSurfaceMesh);20902091// do not set visible if the parent surface list is hidden2092int p = l->getParent();2093if (p >= 0) {2094list_t *lp = getList(p);2095if (!lp->isVisible())2096l->setVisible(false);2097}2098}else if (type == VOLUMEMESHLIST) {2099l->setVisible(stateDrawVolumeMesh);2100}else if (type == SHARPEDGELIST) {2101l->setVisible(stateDrawSharpEdges);2102}2103}2104}21052106int GLWidget::mostVisibleBody(int n, bool* tmp1){2107/*2108This function is called in GLWidget::mouseDoubleClickEvent(QMouseEvent *event) to2109identify the most visible body when the double-clicked surface is shared by multiple bodies.2110This is a public function to be called from ObjectBrowser.2111*/21122113long *nElement = new long[n];2114long *nVisibleElement = new long[n];2115for(int i = 0; i < n; i++){2116nElement[i] = 0;2117nVisibleElement[i] = 0;2118}21192120for(int i = 0; i < getLists(); i++) {2121list_t *l2 = getList(i);2122if(l2->getNature() == PDE_BOUNDARY && l2->getType() == SURFACELIST) {2123for(int j = 0; j < mesh->getSurfaces(); j++) {2124surface_t *surf = mesh->getSurface(j);2125if(surf->getIndex() == l2->getIndex()) {2126for(int k = 0; k < surf->getElements(); k++) {2127int l = surf->getElementIndex(k);2128if(l < 0)2129break;2130element_t *elem = mesh->getElement(l);2131if((elem->getIndex() < 0) || (elem->getIndex() >= n))2132break;2133nElement[elem->getIndex()]++;2134if(l2->isVisible())nVisibleElement[elem->getIndex()]++;2135}2136}2137}2138}2139}21402141double max = -1.0;2142int selected = -1;2143double visibility = -2.0;2144for(int i = 0; i < n; i++){2145if(tmp1[i] && nElement[i] > 0){2146visibility = ((double) nVisibleElement[i]) / nElement[i];2147//cout << i << " visibility=" << visibility << " (" << nVisibleElement[i] << "/" << nElement[i] << ")" << endl;2148if(visibility > max){2149max = visibility;2150selected = i;2151}2152}2153}2154delete[] nElement;2155delete[] nVisibleElement;2156//cout << "selected: " << selected << endl;2157return selected;2158}21592160#if WITH_QT62161void GLWidget::updateGL()2162{2163update();2164}2165216621672168/*2169Reference http://stackoverflow.com/questions/28216001/how-to-render-text-with-qopenglwidget/33674071#336740712170*/2171void GLWidget::renderText(double x, double y, double z, const QString & str, const QFont & font/* = QFont()*/, int listBase /*= 2000*/)2172{2173int width = this->width();2174int height = this->height();21752176GLdouble model[4][4], proj[4][4];2177GLint view[4];2178glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);2179glGetDoublev(GL_PROJECTION_MATRIX, &proj[0][0]);2180glGetIntegerv(GL_VIEWPORT, &view[0]);2181GLdouble textPosX = 0, textPosY = 0, textPosZ = 0;21822183project(x, y, z,2184&model[0][0], &proj[0][0], &view[0],2185&textPosX, &textPosY, &textPosZ);21862187textPosY = height - textPosY; // y is inverted21882189QPainter painter(this);2190painter.setPen(Qt::black);2191painter.setFont(font);2192painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);2193painter.drawText(textPosX, textPosY, str); // z = pointT4.z + distOverOp / 42194painter.end();2195}21962197inline GLint GLWidget::project(GLdouble objx, GLdouble objy, GLdouble objz,2198const GLdouble model[16], const GLdouble proj[16],2199const GLint viewport[4],2200GLdouble * winx, GLdouble * winy, GLdouble * winz)2201{2202GLdouble in[4], out[4];22032204in[0] = objx;2205in[1] = objy;2206in[2] = objz;2207in[3] = 1.0;2208transformPoint(out, model, in);2209transformPoint(in, proj, out);22102211if (in[3] == 0.0)2212return GL_FALSE;22132214in[0] /= in[3];2215in[1] /= in[3];2216in[2] /= in[3];22172218*winx = viewport[0] + (1 + in[0]) * viewport[2] / 2;2219*winy = viewport[1] + (1 + in[1]) * viewport[3] / 2;22202221*winz = (1 + in[2]) / 2;2222return GL_TRUE;2223}22242225inline void GLWidget::transformPoint(GLdouble out[4], const GLdouble m[16], const GLdouble in[4])2226{2227#define M(row,col) m[col*4+row]2228out[0] =2229M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];2230out[1] =2231M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];2232out[2] =2233M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];2234out[3] =2235M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];2236#undef M2237}22382239#endif224022412242