Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/ElmerGUI/Application/src/mainwindow.cpp
3203 views
1
/*****************************************************************************
2
* *
3
* Elmer, A Finite Element Software for Multiphysical Problems *
4
* *
5
* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland *
6
* *
7
* This program is free software; you can redistribute it and/or *
8
* modify it under the terms of the GNU General Public License *
9
* as published by the Free Software Foundation; either version 2 *
10
* of the License, or (at your option) any later version. *
11
* *
12
* This program is distributed in the hope that it will be useful, *
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
* GNU General Public License for more details. *
16
* *
17
* You should have received a copy of the GNU General Public License *
18
* along with this program (in file fem/GPL-2); if not, write to the *
19
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
20
* Boston, MA 02110-1301, USA. *
21
* *
22
*****************************************************************************/
23
24
/*****************************************************************************
25
* *
26
* ElmerGUI mainwindow *
27
* *
28
*****************************************************************************
29
* *
30
* Authors: Mikko Lyly, Juha Ruokolainen and Peter RÃ¥back *
31
* Email: [email protected] *
32
* Web: http://www.csc.fi/elmer *
33
* Address: CSC - IT Center for Science Ltd. *
34
* Keilaranta 14 *
35
* 02101 Espoo, Finland *
36
* *
37
* Original Date: 15 Mar 2008 *
38
* *
39
*****************************************************************************/
40
41
#include <QAction>
42
#include <QContextMenuEvent>
43
#include <QDir>
44
#include <QFile>
45
#include <QFileInfo>
46
#include <QFont>
47
#include <QProgressBar>
48
#include <QStringList>
49
#include <QSystemTrayIcon>
50
#include <QTimeLine>
51
#include <QtGui>
52
53
#include <fstream>
54
#include <iostream>
55
56
#include <QDebug>
57
58
#include "mainwindow.h"
59
#include "newprojectdialog.h"
60
61
#ifdef EG_VTK
62
#include "vtkpost/vtkpost.h"
63
VtkPost *vtkp;
64
#endif
65
66
#ifdef __APPLE__
67
#include <mach-o/dyld.h>
68
// #ifndef EG_OCC
69
// #define EG_OCC
70
// #endif
71
#endif
72
73
using namespace std;
74
75
#undef MPICH2
76
77
// Construct main window...
78
//-----------------------------------------------------------------------------
79
MainWindow::MainWindow() {
80
#ifdef __APPLE__
81
// find "Home directory":
82
char executablePath[MAXPATHLENGTH] = {0};
83
uint32_t len = MAXPATHLENGTH;
84
this->homePath = "";
85
if (!_NSGetExecutablePath((char *)executablePath, &len)) {
86
// remove executable name from path:
87
*(strrchr(executablePath, '/')) = '\0';
88
// remove last path component name from path:
89
*(strrchr(executablePath, '/')) = '\0';
90
this->homePath = executablePath;
91
}
92
#else
93
homePath = "";
94
#endif
95
96
97
// Set icon theme path
98
#ifdef __APPLE__DONTGO_HERE_TODO
99
QString themePath = this->homePath + "/icons";
100
#else
101
QString themePath =
102
QCoreApplication::applicationDirPath() + "/../share/ElmerGUI/icons";
103
104
QString elmerGuiHome = QString(getenv("ELMERGUI_HOME"));
105
106
if (!elmerGuiHome.isEmpty())
107
themePath = elmerGuiHome + "/icons";
108
109
themePath.replace('\\', '/');
110
#endif
111
QIcon::setThemeSearchPaths(QStringList(themePath));
112
QIcon::setThemeName("TangoElmerGUI");
113
114
115
// load ini file:
116
egIni = new EgIni(this);
117
118
// splash screen:
119
setupSplash();
120
121
// load splash screen:
122
updateSplash("Loading images...");
123
124
// load tetlib:
125
updateSplash("Loading tetlib...");
126
tetlibAPI = new TetlibAPI;
127
tetlibPresent = tetlibAPI->loadTetlib();
128
this->in = tetlibAPI->in;
129
this->out = tetlibAPI->out;
130
131
// load nglib:
132
updateSplash("Loading nglib...");
133
nglibAPI = new NglibAPI;
134
nglibPresent = true;
135
136
// construct elmergrid:
137
updateSplash("Constructing elmergrid...");
138
elmergridAPI = new ElmergridAPI;
139
140
// set dynamic limits:
141
limit = new Limit;
142
setDynamicLimits();
143
144
// widgets and utilities:
145
updateSplash("ElmerGUI loading...");
146
glWidget = new GLWidget(this);
147
#ifdef WIN32
148
glWidget->stateDrawSharpEdges = false;
149
#endif
150
setCentralWidget(glWidget);
151
sifWindow = new SifWindow(this);
152
meshControl = new MeshControl(this);
153
boundaryDivide = new BoundaryDivide(this);
154
meshingThread = new MeshingThread(this);
155
meshutils = new Meshutils;
156
solverLogWindow = new SolverLogWindow(this);
157
solver = new QProcess(this);
158
post = new QProcess(this);
159
paraview = new QProcess(this);
160
compiler = new QProcess(this);
161
meshSplitter = new QProcess(this);
162
meshUnifier = new QProcess(this);
163
generalSetup = new GeneralSetup(this);
164
summaryEditor = new SummaryEditor(this);
165
sifGenerator = new SifGenerator;
166
sifGenerator->setLimit(this->limit);
167
elmerDefs = new QDomDocument;
168
edfEditor = new EdfEditor;
169
glControl = new GLcontrol(this);
170
parallel = new Parallel(this);
171
checkMpi = new CheckMpi;
172
materialLibrary = new MaterialLibrary(this);
173
twodView = new TwodView;
174
grabTimeLine = new QTimeLine(1000, this);
175
176
#ifdef EG_QWT
177
convergenceView = new ConvergenceView(limit, this);
178
#endif
179
180
#ifdef EG_VTK
181
vtkp = vtkPost = new VtkPost(this);
182
vtkPostMeshUnifierRunning = false;
183
#endif
184
185
#ifdef EG_OCC
186
cadView = new CadView();
187
if (egIni->isPresent("deflection"))
188
cadView->setDeflection(egIni->value("deflection").toDouble());
189
#endif
190
191
createActions();
192
createMenus();
193
createToolBars();
194
createStatusBar();
195
runPostProcessorAct->setMenu(selectPostMenu);
196
197
// Always, when an action from the menu bar has been selected, synchronize
198
// menu to state:
199
connect(menuBar(), SIGNAL(triggered(QAction *)), this,
200
SLOT(menuBarTriggeredSlot(QAction *)));
201
connect(contextMenu, SIGNAL(triggered(QAction *)), this,
202
SLOT(menuBarTriggeredSlot(QAction *)));
203
204
// glWidget emits (list_t*) when a boundary is selected by double clicking:
205
connect(glWidget, SIGNAL(signalBoundarySelected(list_t *, Qt::KeyboardModifiers)), this,
206
SLOT(boundarySelectedSlot(list_t *, Qt::KeyboardModifiers)));
207
208
// glWidget emits (void) when esc has been pressed:
209
connect(glWidget, SIGNAL(escPressed()), this, SLOT(viewNormalModeSlot()));
210
211
// meshingThread emits (void) when the mesh generation has finished or
212
// terminated:
213
connect(meshingThread, SIGNAL(started()), this, SLOT(meshingStartedSlot()));
214
connect(meshingThread, SIGNAL(finished()), this, SLOT(meshingFinishedSlot()));
215
connect(meshingThread, SIGNAL(terminated()), this,
216
SLOT(meshingTerminatedSlot()));
217
218
// boundaryDivide emits (double) when "divide button" has been clicked:
219
connect(boundaryDivide, SIGNAL(signalDoDivideSurface(double)), this,
220
SLOT(doDivideSurfaceSlot(double)));
221
222
// boundaryDivide emits (double) when "divide button" has been clicked:
223
connect(boundaryDivide, SIGNAL(signalDoDivideEdge(double)), this,
224
SLOT(doDivideEdgeSlot(double)));
225
226
// solver emits (int) when finished:
227
connect(solver, SIGNAL(finished(int)), this, SLOT(solverFinishedSlot(int)));
228
229
// solver emits (void) when there is something to read from stdout:
230
connect(solver, SIGNAL(readyReadStandardOutput()), this,
231
SLOT(solverStdoutSlot()));
232
233
// solver emits (void) when there is something to read from stderr:
234
connect(solver, SIGNAL(readyReadStandardError()), this,
235
SLOT(solverStderrSlot()));
236
237
// solver emits (QProcess::ProcessError) when error occurs:
238
connect(solver, SIGNAL(error(QProcess::ProcessError)), this,
239
SLOT(solverErrorSlot(QProcess::ProcessError)));
240
241
// solver emits (QProcess::ProcessState) when state changed:
242
connect(solver, SIGNAL(stateChanged(QProcess::ProcessState)), this,
243
SLOT(solverStateChangedSlot(QProcess::ProcessState)));
244
245
// compiler emits (int) when finished:
246
connect(compiler, SIGNAL(finished(int)), this,
247
SLOT(compilerFinishedSlot(int)));
248
249
// compiler emits (void) when there is something to read from stdout:
250
connect(compiler, SIGNAL(readyReadStandardOutput()), this,
251
SLOT(compilerStdoutSlot()));
252
253
// compiler emits (void) when there is something to read from stderr:
254
connect(compiler, SIGNAL(readyReadStandardError()), this,
255
SLOT(compilerStderrSlot()));
256
257
// post emits (int) when finished:
258
connect(post, SIGNAL(finished(int)), this,
259
SLOT(postProcessFinishedSlot(int)));
260
261
// paraview emits (int) when finished:
262
connect(paraview, SIGNAL(finished(int)), this,
263
SLOT(paraviewProcessFinishedSlot(int)));
264
265
// meshSplitter emits (int) when finished:
266
connect(meshSplitter, SIGNAL(finished(int)), this,
267
SLOT(meshSplitterFinishedSlot(int)));
268
269
// meshSplitter emits(void) when there is something to read from stdout:
270
connect(meshSplitter, SIGNAL(readyReadStandardOutput()), this,
271
SLOT(meshSplitterStdoutSlot()));
272
273
// meshSplitter emits(void) when there is something to read from stderr:
274
connect(meshSplitter, SIGNAL(readyReadStandardError()), this,
275
SLOT(meshSplitterStderrSlot()));
276
277
// meshUnifier emits (int) when finished:
278
connect(meshUnifier, SIGNAL(finished(int)), this,
279
SLOT(meshUnifierFinishedSlot(int)));
280
281
// meshUnifier emits(void) when there is something to read from stdout:
282
connect(meshUnifier, SIGNAL(readyReadStandardOutput()), this,
283
SLOT(meshUnifierStdoutSlot()));
284
285
// meshUnifier emits(void) when there is something to read from stderr:
286
connect(meshUnifier, SIGNAL(readyReadStandardError()), this,
287
SLOT(meshUnifierStderrSlot()));
288
289
// grabTimeLine emits finished() when done:
290
connect(grabTimeLine, SIGNAL(finished()), this, SLOT(grabFrameSlot()));
291
292
// set initial state:
293
operations = 0;
294
meshControl->nglibPresent = nglibPresent;
295
meshControl->tetlibPresent = tetlibPresent;
296
meshControl->defaultControls();
297
nglibInputOk = false;
298
tetlibInputOk = false;
299
activeGenerator = GEN_UNKNOWN;
300
bcEditActive = false;
301
bodyEditActive = false;
302
showConvergence = egIni->isSet("showconvergence");
303
geometryInputFileName = "";
304
occInputOk = false;
305
306
// background image:
307
glWidget->stateUseBgImage = egIni->isSet("bgimage");
308
glWidget->stateStretchBgImage = egIni->isSet("bgimagestretch");
309
glWidget->stateAlignRightBgImage = egIni->isSet("bgimagealignright");
310
glWidget->bgImageFileName = egIni->value("bgimagefile");
311
312
// set font for text editors:
313
// QFont sansFont("Courier", 10);
314
// sifWindow->getTextEdit()->setCurrentFont(sansFont);
315
// solverLogWindow->getTextEdit()->setCurrentFont(sansFont);
316
317
// load definition files:
318
updateSplash("Loading definitions...");
319
loadDefinitions();
320
321
// initialization ready:
322
// synchronizeMenuToState(); Commented out as this will be called from loadSettings() later
323
setWindowTitle(tr("ElmerGUI"));
324
setWindowIcon(QIcon(":/icons/Mesh3D.png"));
325
finalizeSplash();
326
setupSysTrayIcon();
327
328
// default size:
329
int defW = egIni->value("width").toInt();
330
int defH = egIni->value("height").toInt();
331
if (defW <= 300)
332
defW = 300;
333
if (defH <= 300)
334
defH = 300;
335
this->resize(defW, defH);
336
sifWindow->resize(defW - 50, defH - 50);
337
solverLogWindow->resize(defW - 50, defH - 50);
338
339
loadSettings();
340
}
341
342
// dtor...
343
//-----------------------------------------------------------------------------
344
MainWindow::~MainWindow() {
345
saveSettings();
346
qApp->closeAllWindows();
347
}
348
349
// Set limits for dynamic editors, materials, bcs, etc...
350
//-----------------------------------------------------------------------------
351
void MainWindow::setDynamicLimits() {
352
// Values defined in "edf/egini.xml" that override default limits:
353
354
// Deprecated ** 23/04/09 **
355
if (egIni->isPresent("max_boundaries")) {
356
limit->setMaxBoundaries(egIni->value("max_boundaries").toInt());
357
// cout << "Max boundaries: " << limit->maxBoundaries() << endl;
358
}
359
360
// Deprecated ** 23/04/09 **
361
if (egIni->isPresent("max_solvers")) {
362
limit->setMaxSolvers(egIni->value("max_solvers").toInt());
363
// cout << "Max solvers: " << limit->maxSolvers() << endl;
364
}
365
366
// Deprecated ** 23/04/09 **
367
if (egIni->isPresent("max_bodies")) {
368
limit->setMaxBodies(egIni->value("max_bodies").toInt());
369
// cout << "Max bodies: " << limit->maxBodies() << endl;
370
}
371
372
// Deprecated ** 21/04/09 **
373
if (egIni->isPresent("max_equations")) {
374
limit->setMaxEquations(egIni->value("max_equations").toInt());
375
// cout << "Max equations: " << limit->maxEquations() << endl;
376
}
377
378
// Deprecated ** 21/04/09 **
379
if (egIni->isPresent("max_materials")) {
380
limit->setMaxMaterials(egIni->value("max_materials").toInt());
381
// cout << "Max materials: " << limit->maxMaterials() << endl;
382
}
383
384
// Deprecated ** 21/04/09 **
385
if (egIni->isPresent("max_bodyforces")) {
386
limit->setMaxBodyforces(egIni->value("max_bodyforces").toInt());
387
// cout << "Max bodyforces: " << limit->maxBodyforces() << endl;
388
}
389
390
// Deprecated ** 21/04/09 **
391
if (egIni->isPresent("max_initialconditions")) {
392
limit->setMaxInitialconditions(
393
egIni->value("max_initialconditions").toInt());
394
// cout << "Max initialconditions: " << limit->maxInitialconditions() <<
395
// endl;
396
}
397
398
// Deprecated ** 21/04/09 **
399
if (egIni->isPresent("max_bcs")) {
400
limit->setMaxBcs(egIni->value("max_bcs").toInt());
401
// cout << "Max bcs: " << limit->maxBcs() << endl;
402
}
403
}
404
405
// Always synchronize menu to state when the menubar has been triggered...
406
//-----------------------------------------------------------------------------
407
void MainWindow::menuBarTriggeredSlot(QAction *act) {
408
synchronizeMenuToState();
409
}
410
411
// Create actions...
412
//-----------------------------------------------------------------------------
413
void MainWindow::createActions() {
414
// File -> Open file
415
openAct =
416
new QAction(QIcon::fromTheme("document-open"), tr("&Open..."), this);
417
openAct->setShortcut(tr("Ctrl+O"));
418
openAct->setStatusTip(tr("Open geometry input file"));
419
connect(openAct, SIGNAL(triggered()), this, SLOT(openSlot()));
420
421
// File -> Load mesh...
422
loadAct = new QAction(QIcon::fromTheme("folder"),
423
tr("&Load mesh..."), this);
424
loadAct->setStatusTip(tr("Load Elmer mesh files"));
425
connect(loadAct, SIGNAL(triggered()), this, SLOT(loadSlot()));
426
427
// File -> Load project...
428
loadProjectAct = new QAction(QIcon::fromTheme("project-load"),
429
tr("Load &project..."), this);
430
loadProjectAct->setStatusTip(tr("Load previously saved project"));
431
connect(loadProjectAct, SIGNAL(triggered()), this, SLOT(loadProjectSlot()));
432
433
// File -> New project...
434
newProjectAct = new QAction(QIcon::fromTheme("project-new"),
435
tr("&New project..."), this);
436
newProjectAct->setStatusTip(tr("Create a new project"));
437
connect(newProjectAct, SIGNAL(triggered()), this, SLOT(newProjectSlot()));
438
439
// File -> Recent Projects
440
recentProject0Act = new QAction("", this);
441
connect(recentProject0Act, SIGNAL(triggered()), this,
442
SLOT(loadRecentProject0Slot()));
443
recentProject1Act = new QAction("", this);
444
connect(recentProject1Act, SIGNAL(triggered()), this,
445
SLOT(loadRecentProject1Slot()));
446
recentProject2Act = new QAction("", this);
447
connect(recentProject2Act, SIGNAL(triggered()), this,
448
SLOT(loadRecentProject2Slot()));
449
recentProject3Act = new QAction("", this);
450
connect(recentProject3Act, SIGNAL(triggered()), this,
451
SLOT(loadRecentProject3Slot()));
452
recentProject4Act = new QAction("", this);
453
connect(recentProject4Act, SIGNAL(triggered()), this,
454
SLOT(loadRecentProject4Slot()));
455
recentProject5Act = new QAction("", this);
456
connect(recentProject5Act, SIGNAL(triggered()), this,
457
SLOT(loadRecentProject5Slot()));
458
recentProject6Act = new QAction("", this);
459
connect(recentProject6Act, SIGNAL(triggered()), this,
460
SLOT(loadRecentProject6Slot()));
461
recentProject7Act = new QAction("", this);
462
connect(recentProject7Act, SIGNAL(triggered()), this,
463
SLOT(loadRecentProject7Slot()));
464
recentProject8Act = new QAction("", this);
465
connect(recentProject8Act, SIGNAL(triggered()), this,
466
SLOT(loadRecentProject8Slot()));
467
recentProject9Act = new QAction("", this);
468
connect(recentProject9Act, SIGNAL(triggered()), this,
469
SLOT(loadRecentProject9Slot()));
470
// File -> Definitions...
471
editDefinitionsAct = new QAction(QIcon::fromTheme("preferences-system"),
472
tr("&Definitions..."), this);
473
editDefinitionsAct->setStatusTip(
474
tr("Load and edit Elmer sif definitions file"));
475
connect(editDefinitionsAct, SIGNAL(triggered()), this,
476
SLOT(editDefinitionsSlot()));
477
478
// File -> Save...
479
saveAct =
480
new QAction(QIcon::fromTheme("document-save"), tr("&Save..."), this);
481
saveAct->setShortcut(tr("Ctrl+S"));
482
saveAct->setStatusTip(tr("Save Elmer mesh and sif-files"));
483
connect(saveAct, SIGNAL(triggered()), this, SLOT(saveSlot()));
484
485
// File -> Save as...
486
saveAsAct = new QAction(QIcon::fromTheme("document-save-as"),
487
tr("&Save as..."), this);
488
saveAsAct->setStatusTip(tr("Save Elmer mesh and sif-files"));
489
connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAsSlot()));
490
491
// File -> Save project
492
saveProjectAct = new QAction(QIcon::fromTheme("project-save"),
493
tr("&Save project"), this);
494
saveProjectAct->setStatusTip(tr("Save current project"));
495
connect(saveProjectAct, SIGNAL(triggered()), this, SLOT(saveProjectSlot()));
496
497
// File -> Save project as...
498
saveProjectAsAct = new QAction(QIcon::fromTheme("project-save-as"),
499
tr("&Save project as..."), this);
500
saveProjectAsAct->setStatusTip(
501
tr("Save current project by specifying directory"));
502
connect(saveProjectAsAct, SIGNAL(triggered()), this,
503
SLOT(saveProjectAsSlot()));
504
505
// File -> Save picture as...
506
savePictureAct = new QAction(QIcon::fromTheme("image-x-generic"),
507
tr("&Save picture as..."), this);
508
savePictureAct->setStatusTip(tr("Save picture in file"));
509
connect(savePictureAct, SIGNAL(triggered()), this, SLOT(savePictureSlot()));
510
511
// File -> Exit
512
exitAct =
513
new QAction(QIcon::fromTheme("emblem-unreadable"), tr("E&xit"), this);
514
exitAct->setShortcut(tr("Ctrl+Q"));
515
exitAct->setStatusTip(tr("Exit"));
516
connect(exitAct, SIGNAL(triggered()), this, SLOT(closeMainWindowSlot()));
517
518
// Model -> Setup...
519
modelSetupAct = new QAction(QIcon::fromTheme("applications-system"), tr("Setup..."), this);
520
modelSetupAct->setStatusTip(tr("Setup simulation environment"));
521
connect(modelSetupAct, SIGNAL(triggered()), this, SLOT(modelSetupSlot()));
522
523
// Model -> Equation...
524
addEquationAct = new QAction(QIcon(), tr("Add..."), this);
525
addEquationAct->setStatusTip(tr("Add a PDE-system to the equation list"));
526
connect(addEquationAct, SIGNAL(triggered()), this, SLOT(addEquationSlot()));
527
528
// Model -> Material...
529
addMaterialAct = new QAction(QIcon(), tr("Add..."), this);
530
addMaterialAct->setStatusTip(tr("Add a material set to the material list"));
531
connect(addMaterialAct, SIGNAL(triggered()), this, SLOT(addMaterialSlot()));
532
533
// Model -> Body force...
534
addBodyForceAct = new QAction(QIcon(), tr("Add..."), this);
535
addBodyForceAct->setStatusTip(tr("Add body forces..."));
536
connect(addBodyForceAct, SIGNAL(triggered()), this, SLOT(addBodyForceSlot()));
537
538
// Model -> Initial condition...
539
addInitialConditionAct = new QAction(QIcon(), tr("Add..."), this);
540
addInitialConditionAct->setStatusTip(tr("Add initial conditions..."));
541
connect(addInitialConditionAct, SIGNAL(triggered()), this,
542
SLOT(addInitialConditionSlot()));
543
544
// Model -> Boundary condition...
545
addBoundaryConditionAct = new QAction(QIcon(), tr("Add..."), this);
546
addBoundaryConditionAct->setStatusTip(tr("Add boundary conditions..."));
547
connect(addBoundaryConditionAct, SIGNAL(triggered()), this,
548
SLOT(addBoundaryConditionSlot()));
549
550
// Model -> Set body properties
551
bodyEditAct = new QAction(QIcon(":/icons/set-body-property.png"),
552
tr("Set body properties"), this);
553
bodyEditAct->setStatusTip(
554
tr("Set body properties (equivalent to holding down the SHIFT key)"));
555
connect(bodyEditAct, SIGNAL(triggered()), this, SLOT(bodyEditSlot()));
556
bodyEditAct->setCheckable(true);
557
558
// Model -> Set boundary conditions
559
bcEditAct = new QAction(QIcon(":/icons/set-boundary-property.png"),
560
tr("Set boundary properties"), this);
561
bcEditAct->setStatusTip(
562
tr("Set boundary properties (equivalent to holding down the ALT key)"));
563
connect(bcEditAct, SIGNAL(triggered()), this, SLOT(bcEditSlot()));
564
bcEditAct->setCheckable(true);
565
566
// Model -> Summary...
567
modelSummaryAct = new QAction(QIcon(), tr("Summary..."), this);
568
modelSummaryAct->setStatusTip(tr("Model summary"));
569
connect(modelSummaryAct, SIGNAL(triggered()), this, SLOT(modelSummarySlot()));
570
571
// Model -> Clear
572
modelClearAct = new QAction(QIcon(), tr("Clear all"), this);
573
modelClearAct->setStatusTip(tr("Clear all model definitions"));
574
connect(modelClearAct, SIGNAL(triggered()), this, SLOT(modelClearSlot()));
575
576
// Edit -> Generate sif
577
generateSifAct = new QAction(QIcon(""), tr("&Generate"), this);
578
generateSifAct->setShortcut(tr("Ctrl+G"));
579
generateSifAct->setStatusTip(tr("Generate solver input file"));
580
connect(generateSifAct, SIGNAL(triggered()), this, SLOT(generateSifSlot()));
581
582
// Edit -> Solver input file...
583
showsifAct = new QAction(QIcon::fromTheme("text-x-generic-with-pencil"),
584
tr("&Edit..."), this);
585
showsifAct->setShortcut(tr("Ctrl+S"));
586
showsifAct->setStatusTip(tr("Edit solver input file"));
587
connect(showsifAct, SIGNAL(triggered()), this, SLOT(showsifSlot()));
588
589
// Mesh -> Control
590
meshcontrolAct =
591
new QAction(QIcon::fromTheme("configure"), tr("&Configure..."), this);
592
meshcontrolAct->setShortcut(tr("Ctrl+C"));
593
meshcontrolAct->setStatusTip(tr("Configure mesh generators"));
594
connect(meshcontrolAct, SIGNAL(triggered()), this, SLOT(meshcontrolSlot()));
595
596
// Mesh -> Remesh
597
remeshAct = new QAction(QIcon::fromTheme("edit-redo"), tr("&Remesh"), this);
598
remeshAct->setShortcut(tr("Ctrl+R"));
599
remeshAct->setStatusTip(tr("Remesh"));
600
connect(remeshAct, SIGNAL(triggered()), this, SLOT(remeshSlot()));
601
602
// Mesh -> Kill generator
603
stopMeshingAct = new QAction(QIcon::fromTheme("dialog-error-round"),
604
tr("&Terminate meshing"), this);
605
stopMeshingAct->setStatusTip(tr("Terminate mesh generator"));
606
connect(stopMeshingAct, SIGNAL(triggered()), this, SLOT(stopMeshingSlot()));
607
stopMeshingAct->setEnabled(false);
608
609
// Mesh -> Divide surface
610
surfaceDivideAct =
611
new QAction(QIcon(":/icons/divide.png"), tr("&Divide surface..."), this);
612
surfaceDivideAct->setStatusTip(tr("Divide surface by sharp edges"));
613
connect(surfaceDivideAct, SIGNAL(triggered()), this,
614
SLOT(surfaceDivideSlot()));
615
616
// Mesh -> Unify surface
617
surfaceUnifyAct =
618
new QAction(QIcon(":/icons/unify.png"), tr("&Unify surface"), this);
619
surfaceUnifyAct->setStatusTip(tr("Unify surface (merge selected)"));
620
connect(surfaceUnifyAct, SIGNAL(triggered()), this, SLOT(surfaceUnifySlot()));
621
622
// Mesh -> Divide edge
623
edgeDivideAct = new QAction(QIcon(":/icons/divide-edge.png"),
624
tr("&Divide edge..."), this);
625
edgeDivideAct->setStatusTip(tr("Divide edge by sharp points"));
626
connect(edgeDivideAct, SIGNAL(triggered()), this, SLOT(edgeDivideSlot()));
627
628
// Mesh -> Unify edges
629
edgeUnifyAct =
630
new QAction(QIcon(":/icons/unify-edge.png"), tr("&Unify edge"), this);
631
edgeUnifyAct->setStatusTip(tr("Unify edge (merge selected)"));
632
connect(edgeUnifyAct, SIGNAL(triggered()), this, SLOT(edgeUnifySlot()));
633
634
// Mesh -> Clean up
635
cleanHangingSharpEdgesAct = new QAction(QIcon::fromTheme("edit-clear"), tr("Clean up"), this);
636
cleanHangingSharpEdgesAct->setStatusTip(
637
tr("Removes hanging/orphan sharp edges (for visualization)"));
638
connect(cleanHangingSharpEdgesAct, SIGNAL(triggered()), this,
639
SLOT(cleanHangingSharpEdgesSlot()));
640
641
// View -> Full screen
642
viewFullScreenAct = new QAction(QIcon::fromTheme("view-fullscreen"), tr("Full screen"), this);
643
viewFullScreenAct->setShortcut(tr("Ctrl+L"));
644
viewFullScreenAct->setStatusTip(tr("Full screen mode"));
645
connect(viewFullScreenAct, SIGNAL(triggered()), this,
646
SLOT(viewFullScreenSlot()));
647
viewFullScreenAct->setCheckable(true);
648
649
// View -> Show surface mesh
650
hidesurfacemeshAct = new QAction(QIcon(), tr("Surface mesh"), this);
651
hidesurfacemeshAct->setStatusTip(tr("Show/hide surface mesh "
652
"(do/do not outline surface elements)"));
653
connect(hidesurfacemeshAct, SIGNAL(triggered()), this,
654
SLOT(hidesurfacemeshSlot()));
655
hidesurfacemeshAct->setCheckable(true);
656
657
// View -> Show volume mesh
658
hidevolumemeshAct = new QAction(QIcon(), tr("Volume mesh"), this);
659
hidevolumemeshAct->setStatusTip(tr("Show/hide volume mesh "
660
"(do/do not outline volume mesh edges)"));
661
connect(hidevolumemeshAct, SIGNAL(triggered()), this,
662
SLOT(hidevolumemeshSlot()));
663
hidevolumemeshAct->setCheckable(true);
664
665
// View -> Show sharp edges
666
hidesharpedgesAct = new QAction(QIcon(), tr("Sharp edges"), this);
667
hidesharpedgesAct->setStatusTip(tr("Show/hide sharp edges"));
668
connect(hidesharpedgesAct, SIGNAL(triggered()), this,
669
SLOT(hidesharpedgesSlot()));
670
hidesharpedgesAct->setCheckable(true);
671
672
// View -> Compass
673
viewCoordinatesAct = new QAction(QIcon(), tr("Compass"), this);
674
viewCoordinatesAct->setStatusTip(tr("View coordinates "
675
"(RGB=XYZ modulo translation)"));
676
connect(viewCoordinatesAct, SIGNAL(triggered()), this,
677
SLOT(viewCoordinatesSlot()));
678
viewCoordinatesAct->setCheckable(true);
679
680
// View -> Select all surfaces
681
selectAllSurfacesAct = new QAction(QIcon(), tr("Select all surfaces"), this);
682
selectAllSurfacesAct->setStatusTip(tr("Select all surfaces"));
683
connect(selectAllSurfacesAct, SIGNAL(triggered()), this,
684
SLOT(selectAllSurfacesSlot()));
685
686
// View -> Select all edges
687
selectAllEdgesAct = new QAction(QIcon(), tr("Select all edges"), this);
688
selectAllEdgesAct->setStatusTip(tr("Select all edges"));
689
connect(selectAllEdgesAct, SIGNAL(triggered()), this,
690
SLOT(selectAllEdgesSlot()));
691
692
// View -> Select defined edges
693
selectDefinedEdgesAct =
694
new QAction(QIcon(), tr("Select defined edges"), this);
695
selectDefinedEdgesAct->setStatusTip(tr("Select defined edges"));
696
connect(selectDefinedEdgesAct, SIGNAL(triggered()), this,
697
SLOT(selectDefinedEdgesSlot()));
698
699
// View -> Select defined surfaces
700
selectDefinedSurfacesAct =
701
new QAction(QIcon(), tr("Select defined surfaces"), this);
702
selectDefinedSurfacesAct->setStatusTip(tr("Select defined surfaces"));
703
connect(selectDefinedSurfacesAct, SIGNAL(triggered()), this,
704
SLOT(selectDefinedSurfacesSlot()));
705
706
// View -> Hide/show selected
707
hideselectedAct = new QAction(QIcon(), tr("&Hide/show selected"), this);
708
hideselectedAct->setShortcut(tr("Ctrl+H"));
709
hideselectedAct->setStatusTip(tr("Show/hide selected objects"));
710
connect(hideselectedAct, SIGNAL(triggered()), this, SLOT(hideselectedSlot()));
711
712
// View -> Show surface numbers
713
showSurfaceNumbersAct =
714
new QAction(QIcon(), tr("Surface element numbers"), this);
715
showSurfaceNumbersAct->setStatusTip(
716
tr("Show surface element numbers "
717
"(Show the surface element numbering)"));
718
connect(showSurfaceNumbersAct, SIGNAL(triggered()), this,
719
SLOT(showSurfaceNumbersSlot()));
720
showSurfaceNumbersAct->setCheckable(true);
721
722
// View -> Show edge numbers
723
showEdgeNumbersAct = new QAction(QIcon(), tr("Edge element numbers"), this);
724
showEdgeNumbersAct->setStatusTip(tr("Show edge element numbers "
725
"(Show the node element numbering)"));
726
connect(showEdgeNumbersAct, SIGNAL(triggered()), this,
727
SLOT(showEdgeNumbersSlot()));
728
showEdgeNumbersAct->setCheckable(true);
729
730
// View -> Show node numbers
731
showNodeNumbersAct = new QAction(QIcon(), tr("Node numbers"), this);
732
showNodeNumbersAct->setStatusTip(tr("Show node numbers "
733
"(Show the node numbers)"));
734
connect(showNodeNumbersAct, SIGNAL(triggered()), this,
735
SLOT(showNodeNumbersSlot()));
736
showNodeNumbersAct->setCheckable(true);
737
738
// View -> Show boundary index
739
showBoundaryIndexAct = new QAction(QIcon(), tr("Boundary index"), this);
740
showBoundaryIndexAct->setStatusTip(tr("Show boundary index"));
741
connect(showBoundaryIndexAct, SIGNAL(triggered()), this,
742
SLOT(showBoundaryIndexSlot()));
743
showBoundaryIndexAct->setCheckable(true);
744
745
// View -> Show body index
746
showBodyIndexAct = new QAction(QIcon(), tr("Body index"), this);
747
showBodyIndexAct->setStatusTip(tr("Show body index"));
748
connect(showBodyIndexAct, SIGNAL(triggered()), this,
749
SLOT(showBodyIndexSlot()));
750
showBodyIndexAct->setCheckable(true);
751
752
// View -> Colors -> GL controls
753
glControlAct = new QAction(QIcon(), tr("GL controls..."), this);
754
glControlAct->setStatusTip(
755
tr("Control GL parameters for lights and materials"));
756
connect(glControlAct, SIGNAL(triggered()), this, SLOT(glControlSlot()));
757
758
// View -> Colors -> Background
759
chooseBGColorAct = new QAction(QIcon(), tr("Background..."), this);
760
chooseBGColorAct->setStatusTip(tr("Set background color"));
761
connect(chooseBGColorAct, SIGNAL(triggered()), this,
762
SLOT(backgroundColorSlot()));
763
764
// View -> Colors -> Surface elements
765
chooseSurfaceColorAct = new QAction(QIcon(), tr("Surface elements..."), this);
766
chooseSurfaceColorAct->setStatusTip(tr("Set surface color"));
767
connect(chooseSurfaceColorAct, SIGNAL(triggered()), this,
768
SLOT(surfaceColorSlot()));
769
770
// View -> Colors -> Edge elements
771
chooseEdgeColorAct = new QAction(QIcon(), tr("Edge elements..."), this);
772
chooseEdgeColorAct->setStatusTip(tr("Set edge color"));
773
connect(chooseEdgeColorAct, SIGNAL(triggered()), this, SLOT(edgeColorSlot()));
774
775
// View -> Colors -> Surface mesh
776
chooseSurfaceMeshColorAct = new QAction(QIcon(), tr("Surface mesh..."), this);
777
chooseSurfaceMeshColorAct->setStatusTip(tr("Set surface mesh color"));
778
connect(chooseSurfaceMeshColorAct, SIGNAL(triggered()), this,
779
SLOT(surfaceMeshColorSlot()));
780
781
// View -> Colors -> Sharp edges
782
chooseSharpEdgeColorAct = new QAction(QIcon(), tr("Sharp edges..."), this);
783
chooseSharpEdgeColorAct->setStatusTip(tr("Set sharp edge color"));
784
connect(chooseSharpEdgeColorAct, SIGNAL(triggered()), this,
785
SLOT(sharpEdgeColorSlot()));
786
787
// View -> Colors -> Selection
788
chooseSelectionColorAct = new QAction(QIcon(), tr("Selection..."), this);
789
chooseSelectionColorAct->setStatusTip(tr("Set selection color"));
790
connect(chooseSelectionColorAct, SIGNAL(triggered()), this,
791
SLOT(selectionColorSlot()));
792
793
// View -> Colors -> Boundaries
794
showBoundaryColorAct = new QAction(QIcon(), tr("Boundaries"), this);
795
showBoundaryColorAct->setStatusTip(
796
tr("Visualize different boundary parts with color patches"));
797
connect(showBoundaryColorAct, SIGNAL(triggered()), this,
798
SLOT(colorizeBoundarySlot()));
799
showBoundaryColorAct->setCheckable(true);
800
801
// View -> Colors -> Bodies
802
showBodyColorAct = new QAction(QIcon(), tr("Bodies"), this);
803
showBodyColorAct->setStatusTip(
804
tr("Visualize different body with color patches"));
805
connect(showBodyColorAct, SIGNAL(triggered()), this,
806
SLOT(colorizeBodySlot()));
807
showBodyColorAct->setCheckable(true);
808
809
// View -> Shade model -> Smooth
810
smoothShadeAct = new QAction(QIcon(), tr("Smooth"), this);
811
smoothShadeAct->setStatusTip(tr("Set shade model to smooth"));
812
connect(smoothShadeAct, SIGNAL(triggered()), this, SLOT(smoothShadeSlot()));
813
smoothShadeAct->setCheckable(true);
814
815
// View -> Shade model -> Flat
816
flatShadeAct = new QAction(QIcon(), tr("Flat"), this);
817
flatShadeAct->setStatusTip(tr("Set shade model to flat"));
818
connect(flatShadeAct, SIGNAL(triggered()), this, SLOT(flatShadeSlot()));
819
flatShadeAct->setCheckable(true);
820
821
// View -> Projection -> Orthogonal
822
orthoAct = new QAction(QIcon(), tr("Orthogonal"), this);
823
orthoAct->setStatusTip(tr("Set projection to orthogonal"));
824
connect(orthoAct, SIGNAL(triggered()), this, SLOT(orthoSlot()));
825
orthoAct->setCheckable(true);
826
827
// View -> Projection -> Perspective
828
perspectiveAct = new QAction(QIcon(), tr("Perspective"), this);
829
perspectiveAct->setStatusTip(tr("Set projection to perspective"));
830
connect(perspectiveAct, SIGNAL(triggered()), this, SLOT(perspectiveSlot()));
831
perspectiveAct->setCheckable(true);
832
833
// View -> Show all
834
showallAct = new QAction(QIcon(), tr("Show all"), this);
835
showallAct->setStatusTip(tr("Show all objects"));
836
connect(showallAct, SIGNAL(triggered()), this, SLOT(showallSlot()));
837
838
// View -> Reset model view
839
resetAct = new QAction(QIcon(), tr("Reset model view"), this);
840
resetAct->setStatusTip(tr("Reset model view"));
841
connect(resetAct, SIGNAL(triggered()), this, SLOT(resetSlot()));
842
843
// View -> Show cad model
844
showCadModelAct = new QAction(QIcon(), tr("Cad model..."), this);
845
showCadModelAct->setStatusTip(
846
tr("Displays the cad model in a separate window"));
847
connect(showCadModelAct, SIGNAL(triggered()), this, SLOT(showCadModelSlot()));
848
849
// View -> Show 2d view
850
showTwodViewAct = new QAction(QIcon(), tr("2D modeler..."), this);
851
showTwodViewAct->setStatusTip(
852
tr("Displays the 2d geometry in a separate window"));
853
connect(showTwodViewAct, SIGNAL(triggered()), this, SLOT(showTwodViewSlot()));
854
855
// View -> Show Object Browser
856
showObjectBrowserAct = new QAction(QIcon(), tr("Show Object Browser"), this);
857
showObjectBrowserAct->setStatusTip(tr("Show Object Browser"));
858
connect(showObjectBrowserAct, SIGNAL(triggered()), this,
859
SLOT(showObjectBrowserSlot()));
860
showObjectBrowserAct->setCheckable(true);
861
862
// Solver -> Parallel settings
863
parallelSettingsAct = new QAction(QIcon(), tr("Parallel settings..."), this);
864
parallelSettingsAct->setStatusTip(
865
tr("Choose parameters and methods for parallel solution"));
866
connect(parallelSettingsAct, SIGNAL(triggered()), this,
867
SLOT(parallelSettingsSlot()));
868
869
// Solver -> Run solver
870
runsolverAct =
871
new QAction(QIcon(":/icons/Solver.png"), tr("Start solver"), this);
872
runsolverAct->setStatusTip(tr("Run ElmerSolver"));
873
connect(runsolverAct, SIGNAL(triggered()), this, SLOT(runsolverSlot()));
874
875
// Solver -> Kill solver
876
killsolverAct =
877
new QAction(QIcon::fromTheme("dialog-error-round"), tr("Kill solver"), this);
878
killsolverAct->setStatusTip(tr("Kill ElmerSolver"));
879
connect(killsolverAct, SIGNAL(triggered()), this, SLOT(killsolverSlot()));
880
killsolverAct->setEnabled(false);
881
882
// Solver -> Show convergence
883
showConvergenceAct = new QAction(QIcon(), tr("Show convergence"), this);
884
showConvergenceAct->setStatusTip(tr("Show/hide convergence plot"));
885
connect(showConvergenceAct, SIGNAL(triggered()), this,
886
SLOT(showConvergenceSlot()));
887
showConvergenceAct->setCheckable(true);
888
889
// Solver -> Post process
890
resultsAct =
891
new QAction(QIcon(":/icons/Post.png"), tr("Start ElmerPost"), this);
892
resultsAct->setStatusTip(tr("Run ElmerPost for visualization"));
893
connect(resultsAct, SIGNAL(triggered()), this, SLOT(resultsSlot()));
894
895
// Solver -> Kill post process
896
killresultsAct = new QAction(QIcon::fromTheme("dialog-error-round"),
897
tr("Kill ElmerPost"), this);
898
killresultsAct->setStatusTip(tr("Kill ElmerPost"));
899
connect(killresultsAct, SIGNAL(triggered()), this, SLOT(killresultsSlot()));
900
killresultsAct->setEnabled(false);
901
902
// Solver -> Show Vtk postprocessor
903
showVtkPostAct = new QAction(QIcon(":/icons/Mesh3D.png"), tr("Start ElmerVTK"), this);
904
showVtkPostAct->setStatusTip(tr("Invokes VTK based ElmerGUI postprocessor"));
905
connect(showVtkPostAct, SIGNAL(triggered()), this, SLOT(showVtkPostSlot()));
906
907
// Solver -> Show ParaView postprocessor
908
paraviewAct =
909
new QAction(QIcon(":/icons/Paraview.png"), tr("Start ParaView"), this);
910
paraviewAct->setStatusTip(tr("Invokes ParaView for visualization"));
911
connect(paraviewAct, SIGNAL(triggered()), this, SLOT(showParaViewSlot()));
912
913
// Solver -> Compiler...
914
compileSolverAct = new QAction(QIcon(""), tr("Compiler..."), this);
915
compileSolverAct->setStatusTip(tr(
916
"Compile Elmer specific source code (f90) into a shared library (dll)"));
917
connect(compileSolverAct, SIGNAL(triggered()), this,
918
SLOT(compileSolverSlot()));
919
920
// Help -> About
921
aboutAct = new QAction(QIcon::fromTheme("emblem-notice"), tr("About..."), this);
922
aboutAct->setStatusTip(tr("Information about the program"));
923
connect(aboutAct, SIGNAL(triggered()), this, SLOT(showaboutSlot()));
924
925
// Help -> Get started
926
getStartedAct = new QAction(QIcon(""), tr("Get started..."), this);
927
getStartedAct->setStatusTip(tr("Information to get started"));
928
connect(getStartedAct, SIGNAL(triggered()), this, SLOT(getStartedSlot()));
929
930
generateAndSaveAndRunAct =
931
new QAction(QIcon::fromTheme("doubletriangle-right"),
932
tr("&Generate, save and run"), this);
933
generateAndSaveAndRunAct->setStatusTip(
934
tr("Generate and save sif, save project, then run solver"));
935
connect(generateAndSaveAndRunAct, SIGNAL(triggered()), this,
936
SLOT(generateAndSaveAndRunSlot()));
937
;
938
939
#if WIN32
940
#else
941
compileSolverAct->setEnabled(false);
942
#endif
943
944
if (egIni->isSet("bgimage"))
945
chooseBGColorAct->setEnabled(false);
946
947
runPostProcessorAct = new QAction(QIcon(":/icons/Post.png"), tr("ElmerPost"), this);
948
runPostProcessorAct->setStatusTip(tr("Select ElmerPost as post-processor"));
949
connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(resultsSlot()));
950
951
selectElmerPostAct = new QAction(QIcon(":/icons/Post.png"), tr("ElmerPost"), this);
952
selectElmerPostAct->setStatusTip(tr("Select ElmerPost as post-processor"));
953
connect(selectElmerPostAct, SIGNAL(triggered()), this, SLOT(selectElmerPostSlot()));
954
selectElmerPostAct->setCheckable(true);
955
956
selectVtkPostAct = new QAction(QIcon(":/icons/Mesh3D.png"), tr("ElmerVTK"), this);
957
selectVtkPostAct->setStatusTip(tr("Select ElmerVTK as post-processor"));
958
connect(selectVtkPostAct, SIGNAL(triggered()), this, SLOT(selectVtkPostSlot()));
959
selectVtkPostAct->setCheckable(true);
960
961
selectParaViewAct = new QAction(QIcon(":/icons/Paraview.png"), tr("ParaView"), this);
962
selectParaViewAct->setStatusTip(tr("Select ParaView as post-processor"));
963
connect(selectParaViewAct, SIGNAL(triggered()), this, SLOT(selectParaViewSlot()));
964
selectParaViewAct->setCheckable(true);
965
}
966
967
// Create menus...
968
//-----------------------------------------------------------------------------
969
void MainWindow::createMenus() {
970
// File menu
971
fileMenu = menuBar()->addMenu(tr("&File"));
972
fileMenu->addAction(newProjectAct);
973
fileMenu->addAction(loadProjectAct);
974
recentProjectsMenu = fileMenu->addMenu(tr("&Recent projects"));
975
recentProjectsMenu->setEnabled(false);
976
fileMenu->addAction(saveProjectAct);
977
fileMenu->addAction(saveProjectAct);
978
fileMenu->addAction(saveProjectAsAct);
979
fileMenu->addSeparator();
980
fileMenu->addAction(openAct);
981
fileMenu->addAction(loadAct);
982
fileMenu->addAction(saveAct);
983
fileMenu->addAction(saveAsAct);
984
fileMenu->addSeparator();
985
fileMenu->addAction(editDefinitionsAct);
986
fileMenu->addSeparator();
987
fileMenu->addAction(savePictureAct);
988
fileMenu->addSeparator();
989
fileMenu->addAction(exitAct);
990
991
// Mesh menu
992
meshMenu = menuBar()->addMenu(tr("&Mesh"));
993
meshMenu->addAction(meshcontrolAct);
994
meshMenu->addAction(remeshAct);
995
meshMenu->addAction(stopMeshingAct);
996
meshMenu->addSeparator();
997
meshMenu->addAction(surfaceDivideAct);
998
meshMenu->addAction(surfaceUnifyAct);
999
meshMenu->addSeparator();
1000
meshMenu->addAction(edgeDivideAct);
1001
meshMenu->addAction(edgeUnifyAct);
1002
meshMenu->addSeparator();
1003
meshMenu->addAction(cleanHangingSharpEdgesAct);
1004
1005
// Model menu
1006
modelMenu = menuBar()->addMenu(tr("&Model"));
1007
1008
modelMenu->addAction(modelSetupAct);
1009
modelMenu->addSeparator();
1010
1011
equationMenu = modelMenu->addMenu(tr("Equation"));
1012
equationMenu->addAction(addEquationAct);
1013
equationMenu->addSeparator();
1014
connect(equationMenu, SIGNAL(triggered(QAction *)), this,
1015
SLOT(equationSelectedSlot(QAction *)));
1016
1017
modelMenu->addSeparator();
1018
materialMenu = modelMenu->addMenu(tr("Material"));
1019
materialMenu->addAction(addMaterialAct);
1020
materialMenu->addSeparator();
1021
connect(materialMenu, SIGNAL(triggered(QAction *)), this,
1022
SLOT(materialSelectedSlot(QAction *)));
1023
1024
modelMenu->addSeparator();
1025
bodyForceMenu = modelMenu->addMenu(tr("Body force"));
1026
bodyForceMenu->addAction(addBodyForceAct);
1027
bodyForceMenu->addSeparator();
1028
connect(bodyForceMenu, SIGNAL(triggered(QAction *)), this,
1029
SLOT(bodyForceSelectedSlot(QAction *)));
1030
1031
modelMenu->addSeparator();
1032
initialConditionMenu = modelMenu->addMenu(tr("Initial condition"));
1033
initialConditionMenu->addAction(addInitialConditionAct);
1034
initialConditionMenu->addSeparator();
1035
connect(initialConditionMenu, SIGNAL(triggered(QAction *)), this,
1036
SLOT(initialConditionSelectedSlot(QAction *)));
1037
1038
modelMenu->addSeparator();
1039
boundaryConditionMenu = modelMenu->addMenu(tr("Boundary condition"));
1040
boundaryConditionMenu->addAction(addBoundaryConditionAct);
1041
boundaryConditionMenu->addSeparator();
1042
connect(boundaryConditionMenu, SIGNAL(triggered(QAction *)), this,
1043
SLOT(boundaryConditionSelectedSlot(QAction *)));
1044
1045
modelMenu->addSeparator();
1046
modelMenu->addAction(bodyEditAct);
1047
modelMenu->addAction(bcEditAct);
1048
modelMenu->addSeparator();
1049
modelMenu->addAction(modelSummaryAct);
1050
modelMenu->addSeparator();
1051
modelMenu->addAction(modelClearAct);
1052
modelMenu->addSeparator();
1053
1054
// View menu
1055
viewMenu = menuBar()->addMenu(tr("&View"));
1056
viewMenu->addAction(viewFullScreenAct);
1057
viewMenu->addSeparator();
1058
viewMenu->addAction(hidesurfacemeshAct);
1059
viewMenu->addAction(hidevolumemeshAct);
1060
viewMenu->addAction(hidesharpedgesAct);
1061
viewMenu->addAction(viewCoordinatesAct);
1062
viewMenu->addSeparator();
1063
viewMenu->addAction(selectAllSurfacesAct);
1064
viewMenu->addAction(selectAllEdgesAct);
1065
// Momentarily disabled (see comment *** TODO *** below):
1066
// viewMenu->addSeparator();
1067
// viewMenu->addAction(selectDefinedEdgesAct);
1068
// viewMenu->addAction(selectDefinedSurfacesAct);
1069
viewMenu->addSeparator();
1070
viewMenu->addAction(hideselectedAct);
1071
viewMenu->addSeparator();
1072
shadeMenu = viewMenu->addMenu(tr("Shade model"));
1073
shadeMenu->addAction(flatShadeAct);
1074
shadeMenu->addAction(smoothShadeAct);
1075
viewMenu->addSeparator();
1076
projectionMenu = viewMenu->addMenu(tr("Projection"));
1077
projectionMenu->addAction(orthoAct);
1078
projectionMenu->addAction(perspectiveAct);
1079
viewMenu->addSeparator();
1080
numberingMenu = viewMenu->addMenu(tr("Numbering"));
1081
numberingMenu->addAction(showSurfaceNumbersAct);
1082
numberingMenu->addAction(showEdgeNumbersAct);
1083
numberingMenu->addAction(showNodeNumbersAct);
1084
numberingMenu->addSeparator();
1085
numberingMenu->addAction(showBoundaryIndexAct);
1086
numberingMenu->addAction(showBodyIndexAct);
1087
viewMenu->addSeparator();
1088
colorizeMenu = viewMenu->addMenu(tr("Lights and colors"));
1089
colorizeMenu->addAction(glControlAct);
1090
colorizeMenu->addSeparator();
1091
colorizeMenu->addAction(chooseBGColorAct);
1092
colorizeMenu->addSeparator();
1093
colorizeMenu->addAction(chooseSurfaceColorAct);
1094
colorizeMenu->addAction(chooseEdgeColorAct);
1095
colorizeMenu->addSeparator();
1096
colorizeMenu->addAction(chooseSurfaceMeshColorAct);
1097
colorizeMenu->addAction(chooseSharpEdgeColorAct);
1098
colorizeMenu->addSeparator();
1099
colorizeMenu->addAction(chooseSelectionColorAct);
1100
colorizeMenu->addSeparator();
1101
colorizeMenu->addAction(showBoundaryColorAct);
1102
colorizeMenu->addAction(showBodyColorAct);
1103
viewMenu->addSeparator();
1104
viewMenu->addAction(showallAct);
1105
viewMenu->addAction(resetAct);
1106
#ifdef EG_OCC
1107
viewMenu->addSeparator();
1108
viewMenu->addAction(showCadModelAct);
1109
#endif
1110
viewMenu->addAction(showTwodViewAct);
1111
viewMenu->addSeparator();
1112
viewMenu->addAction(showObjectBrowserAct);
1113
1114
// Edit menu
1115
editMenu = menuBar()->addMenu(tr("&Sif"));
1116
editMenu->addAction(generateSifAct);
1117
editMenu->addSeparator();
1118
editMenu->addAction(showsifAct);
1119
1120
// SolverMenu
1121
solverMenu = menuBar()->addMenu(tr("&Run"));
1122
solverMenu->addAction(parallelSettingsAct);
1123
solverMenu->addSeparator();
1124
solverMenu->addAction(runsolverAct);
1125
solverMenu->addAction(killsolverAct);
1126
#ifdef EG_QWT
1127
solverMenu->addAction(showConvergenceAct);
1128
#endif
1129
solverMenu->addSeparator();
1130
solverMenu->addAction(resultsAct);
1131
solverMenu->addAction(killresultsAct);
1132
#ifdef EG_VTK
1133
solverMenu->addSeparator();
1134
solverMenu->addAction(showVtkPostAct);
1135
#endif
1136
#ifdef EG_PARAVIEW
1137
solverMenu->addSeparator();
1138
solverMenu->addAction(paraviewAct);
1139
#endif
1140
solverMenu->addSeparator();
1141
solverMenu->addAction(compileSolverAct);
1142
1143
// Help menu
1144
helpMenu = menuBar()->addMenu(tr("&Help"));
1145
helpMenu->addAction(getStartedAct);
1146
helpMenu->addAction(aboutAct);
1147
1148
// Sys tray menu:
1149
sysTrayMenu = new QMenu;
1150
sysTrayMenu->addAction(modelSummaryAct);
1151
sysTrayMenu->addSeparator();
1152
sysTrayMenu->addAction(stopMeshingAct);
1153
sysTrayMenu->addSeparator();
1154
sysTrayMenu->addAction(killsolverAct);
1155
sysTrayMenu->addAction(killresultsAct);
1156
sysTrayMenu->addSeparator();
1157
sysTrayMenu->addAction(aboutAct);
1158
sysTrayMenu->addSeparator();
1159
sysTrayMenu->addAction(exitAct);
1160
1161
// Context menu:
1162
contextMenu = new QMenu;
1163
contextMenu->addMenu(fileMenu);
1164
contextMenu->addMenu(meshMenu);
1165
contextMenu->addMenu(modelMenu);
1166
contextMenu->addMenu(viewMenu);
1167
contextMenu->addMenu(editMenu);
1168
contextMenu->addMenu(solverMenu);
1169
contextMenu->addMenu(helpMenu);
1170
1171
selectPostMenu = new QMenu;
1172
selectPostMenu->addAction(selectElmerPostAct);
1173
selectPostMenu->addAction(selectVtkPostAct);
1174
selectPostMenu->addAction(selectParaViewAct);
1175
#ifndef EG_VTK
1176
selectVtkPostAct->setEnabled(false);
1177
#endif
1178
#ifndef EG_PARAVIEW
1179
selectParaViewAct->setEnabled(false);
1180
#endif
1181
// Disable unavailable external components:
1182
//------------------------------------------
1183
if (!egIni->isSet("checkexternalcomponents"))
1184
return;
1185
1186
QProcess testProcess;
1187
QStringList args;
1188
1189
cout << "Checking for ElmerSolver... ";
1190
updateSplash("Checking for ElmerSolver...");
1191
args << "-v";
1192
testProcess.start("ElmerSolver", args);
1193
if (!testProcess.waitForStarted()) {
1194
logMessage("no - disabling solver features");
1195
runsolverAct->setEnabled(false);
1196
showConvergenceAct->setEnabled(false);
1197
killsolverAct->setEnabled(false);
1198
} else {
1199
cout << "yes" << endl;
1200
}
1201
testProcess.waitForFinished(2000);
1202
1203
cout << "Checking for ... ";
1204
updateSplash("Checking for ElmerPost...");
1205
args << "-v";
1206
testProcess.start("ElmerPost", args);
1207
if (!testProcess.waitForStarted()) {
1208
logMessage("no - disabling ElmerPost postprocessing features");
1209
resultsAct->setEnabled(false);
1210
killresultsAct->setEnabled(false);
1211
} else {
1212
cout << "yes" << endl;
1213
}
1214
testProcess.waitForFinished(2000);
1215
1216
cout << "Checking for ElmerGrid... ";
1217
updateSplash("Checking for ElmerGrid...");
1218
testProcess.start("ElmerGrid");
1219
if (!testProcess.waitForStarted()) {
1220
logMessage("no - disabling parallel features");
1221
parallelSettingsAct->setEnabled(false);
1222
} else {
1223
cout << "yes" << endl;
1224
}
1225
testProcess.waitForFinished(2000);
1226
1227
cout << "Checking for ElmerSolver_mpi... ";
1228
updateSplash("Checking for ElmerSolver_mpi...");
1229
args << "-v";
1230
testProcess.start("ElmerSolver_mpi", args);
1231
if (!testProcess.waitForStarted()) {
1232
logMessage("no - disabling parallel features");
1233
parallelSettingsAct->setEnabled(false);
1234
} else {
1235
cout << "yes" << endl;
1236
}
1237
testProcess.waitForFinished(2000);
1238
}
1239
1240
// Create tool bars...
1241
//-----------------------------------------------------------------------------
1242
void MainWindow::createToolBars() {
1243
// File toolbar
1244
fileToolBar = addToolBar(tr("&File"));
1245
fileToolBar->addAction(newProjectAct);
1246
fileToolBar->addAction(loadProjectAct);
1247
fileToolBar->addAction(saveProjectAct);
1248
fileToolBar->addAction(saveProjectAsAct);
1249
fileToolBar->addSeparator();
1250
fileToolBar->addAction(openAct);
1251
fileToolBar->addAction(loadAct);
1252
fileToolBar->addAction(saveAct);
1253
fileToolBar->addAction(saveAsAct);
1254
1255
fileToolBar->addSeparator();
1256
fileToolBar->addAction(savePictureAct);
1257
1258
// Edit toolbar
1259
editToolBar = addToolBar(tr("&Edit"));
1260
editToolBar->addAction(showsifAct);
1261
1262
// Mesh toolbar
1263
meshToolBar = addToolBar(tr("&Mesh"));
1264
meshToolBar->addAction(meshcontrolAct);
1265
meshToolBar->addAction(remeshAct);
1266
meshToolBar->addSeparator();
1267
meshToolBar->addAction(surfaceDivideAct);
1268
meshToolBar->addAction(surfaceUnifyAct);
1269
meshToolBar->addSeparator();
1270
meshToolBar->addAction(edgeDivideAct);
1271
meshToolBar->addAction(edgeUnifyAct);
1272
meshToolBar->addSeparator();
1273
meshToolBar->addAction(bodyEditAct);
1274
meshToolBar->addAction(bcEditAct);
1275
1276
// Solver toolbar
1277
solverToolBar = addToolBar(tr("&Solver"));
1278
solverToolBar->addAction(runsolverAct);
1279
solverToolBar->addAction(runPostProcessorAct);
1280
solverToolBar->addAction(generateAndSaveAndRunAct);
1281
1282
if (egIni->isSet("hidetoolbars")) {
1283
fileToolBar->hide();
1284
editToolBar->hide();
1285
meshToolBar->hide();
1286
solverToolBar->hide();
1287
}
1288
}
1289
1290
// Create status bar...
1291
//-----------------------------------------------------------------------------
1292
void MainWindow::createStatusBar() {
1293
progressBar = new QProgressBar;
1294
progressBar->setMaximumHeight(12);
1295
progressBar->setMaximumWidth(120);
1296
progressBar->setTextVisible(false);
1297
progressBar->hide();
1298
1299
progressLabel = new QLabel;
1300
progressLabel->hide();
1301
1302
statusBar()->addPermanentWidget(progressLabel);
1303
statusBar()->addPermanentWidget(progressBar);
1304
1305
statusBar()->showMessage(tr("Ready"));
1306
1307
connect(grabTimeLine, SIGNAL(frameChanged(int)), progressBar,
1308
SLOT(setValue(int)));
1309
}
1310
1311
//*****************************************************************************
1312
//
1313
// File MENU
1314
//
1315
//*****************************************************************************
1316
1317
// File -> Open...
1318
//-----------------------------------------------------------------------------
1319
void MainWindow::newProjectSlot() {
1320
NewProjectDialog dlg;
1321
1322
#ifdef __APPLE__DONTGO_HERE_TODO
1323
QString extraDirpath = this->homePath + "/edf-extra";
1324
#else
1325
QString extraDirPath =
1326
QCoreApplication::applicationDirPath() + "/../share/ElmerGUI/edf-extra";
1327
1328
QString elmerGuiHome = QString(getenv("ELMERGUI_HOME"));
1329
1330
if (!elmerGuiHome.isEmpty())
1331
extraDirPath = elmerGuiHome + "/edf-extra";
1332
1333
extraDirPath.replace('\\', '/');
1334
#endif
1335
1336
QString defaultDir = getDefaultDirName();
1337
dlg.setDirectories(defaultDir, extraDirPath);
1338
1339
if (dlg.exec() == QDialog::Accepted) {
1340
1341
// re-initialize
1342
delete elmerDefs;
1343
elmerDefs = new QDomDocument;
1344
delete edfEditor;
1345
edfEditor = new EdfEditor;
1346
loadDefinitions();
1347
geometryInputFileName = "";
1348
currentProjectDirName = "";
1349
sifWindow->getTextEdit()->clear();
1350
sifWindow->hide();
1351
solverLogWindow->getTextEdit()->clear();
1352
solverLogWindow->hide();
1353
delete generalSetup;
1354
generalSetup = new GeneralSetup(this);
1355
summaryEditor->ui.summaryEdit->clear();
1356
delete twodView;
1357
twodView = new TwodView;
1358
meshControl->defaultControls();
1359
delete parallel;
1360
parallel = new Parallel(this);
1361
1362
#ifdef EG_QWT
1363
convergenceView->removeData();
1364
#endif
1365
1366
#ifdef EG_VTK
1367
vtkPost->hideAll();
1368
#endif
1369
1370
#ifdef EG_OCC
1371
settings_setValue("cadView/geometry", cadView->saveGeometry());
1372
delete cadView;
1373
cadView = new CadView();
1374
if (egIni->isPresent("deflection"))
1375
cadView->setDeflection(egIni->value("deflection").toDouble());
1376
cadView->restoreGeometry(settings_value("cadView/geometry").toByteArray());
1377
#endif
1378
1379
// delete operations
1380
operation_t *p = operation.next;
1381
operation_t *q = NULL;
1382
while (p != NULL) {
1383
if (p->select_set != NULL)
1384
delete[] p->select_set;
1385
q = p->next;
1386
if (p != NULL)
1387
delete p;
1388
p = q;
1389
}
1390
operations = 0;
1391
operation.next = NULL;
1392
1393
// reset mesh
1394
if (glWidget->hasMesh()) {
1395
glWidget->getMesh()->clear();
1396
glWidget->deleteMesh();
1397
}
1398
glWidget->newMesh();
1399
meshutils->findSurfaceElementEdges(glWidget->getMesh());
1400
meshutils->findSurfaceElementNormals(glWidget->getMesh());
1401
glWidget->rebuildLists();
1402
1403
modelClearSlot();
1404
1405
// load Elmer mesh/open geometry file
1406
bool bStartMeshing = false;
1407
if (dlg.ui.radioButton_elmerMesh->isChecked() &&
1408
!dlg.ui.label_meshDir->text().isEmpty()) {
1409
loadElmerMesh(dlg.ui.label_meshDir->text());
1410
} else if (dlg.ui.radioButton_geometryFile->isChecked() &&
1411
!dlg.ui.label_geometryFile->text().isEmpty()) {
1412
QString fileName = dlg.ui.label_geometryFile->text();
1413
geometryInputFileName = fileName;
1414
saveDirName = "";
1415
readInputFile(fileName);
1416
if (egIni->isSet("automesh"))
1417
bStartMeshing = true;
1418
}
1419
1420
// save and load project
1421
saveProject(dlg.ui.label_projectDir->text());
1422
loadProject(dlg.ui.label_projectDir->text());
1423
1424
// load extra solvers
1425
QString message;
1426
for (int i = 0; i < dlg.ui.listWidget_selectedSolvers->count(); i++) {
1427
message = "Load " + extraDirPath + "/" +
1428
dlg.ui.listWidget_selectedSolvers->item(i)->text() + "... ";
1429
#if WITH_QT5 || WITH_QT6
1430
cout << string(message.toLatin1());
1431
cout.flush();
1432
#else
1433
cout << string(message.toAscii());
1434
cout.flush();
1435
#endif
1436
edfEditor->appendFrom(extraDirPath + "/" +
1437
dlg.ui.listWidget_selectedSolvers->item(i)->text());
1438
cout << " done" << endl;
1439
}
1440
1441
if (bStartMeshing)
1442
remeshSlot();
1443
}
1444
}
1445
1446
void MainWindow::parseCmdLine() {
1447
QStringList args = QCoreApplication::arguments();
1448
1449
if (!args.contains("-nogui"))
1450
this->show();
1451
1452
int input = args.indexOf("-i");
1453
1454
if (input > 0) {
1455
QString fileName = args.at(input + 1);
1456
1457
QFileInfo fileInfo(fileName);
1458
1459
if (!fileInfo.exists()) {
1460
#if WITH_QT5 || WITH_QT6
1461
cout << "Input file \"" << fileName.toLatin1().data()
1462
<< "\" does not exist" << endl;
1463
#else
1464
cout << "Input file \"" << fileName.toAscii().data()
1465
<< "\" does not exist" << endl;
1466
#endif
1467
QApplication::closeAllWindows();
1468
exit(0);
1469
}
1470
1471
if (fileName.left(1) != "-") {
1472
#if WITH_QT5 || WITH_QT6
1473
cout << "Reading input file " << fileName.toLatin1().data() << endl;
1474
#else
1475
cout << "Reading input file " << fileName.toAscii().data() << endl;
1476
#endif
1477
readInputFile(fileName);
1478
remeshSlot();
1479
}
1480
}
1481
}
1482
1483
// File -> Open...
1484
//-----------------------------------------------------------------------------
1485
void MainWindow::openSlot() {
1486
QString defaultDirName = getDefaultDirName();
1487
1488
QString fileName = QFileDialog::getOpenFileName(
1489
this, tr("Open geometry input file"), defaultDirName);
1490
1491
if (!fileName.isEmpty()) {
1492
1493
QFileInfo fi(fileName);
1494
QString absolutePath = fi.absolutePath();
1495
QDir::setCurrent(absolutePath);
1496
1497
} else {
1498
1499
logMessage("Unable to open file: file name is empty");
1500
return;
1501
}
1502
1503
geometryInputFileName = fileName;
1504
1505
operation_t *p = operation.next;
1506
operation_t *q = NULL;
1507
1508
while (p != NULL) {
1509
if (p->select_set != NULL)
1510
delete[] p->select_set;
1511
1512
q = p->next;
1513
1514
if (p != NULL)
1515
delete p;
1516
1517
p = q;
1518
}
1519
1520
operations = 0;
1521
operation.next = NULL;
1522
1523
saveDirName = "";
1524
readInputFile(fileName);
1525
1526
if (egIni->isSet("automesh"))
1527
remeshSlot();
1528
}
1529
1530
// Read input file and populate mesh generator's input structures:
1531
//-----------------------------------------------------------------------------
1532
void MainWindow::readInputFile(QString fileName) {
1533
occInputOk = false;
1534
1535
char cs[1024];
1536
1537
QFileInfo fi(fileName);
1538
QString absolutePath = fi.absolutePath();
1539
QString baseName = fi.baseName();
1540
QString fileSuffix = fi.suffix();
1541
QString baseFileName = absolutePath + "/" + baseName;
1542
#if WITH_QT5 || WITH_QT6
1543
sprintf(cs, "%s", baseFileName.toLatin1().data());
1544
#else
1545
sprintf(cs, "%s", baseFileName.toAscii().data());
1546
#endif
1547
1548
fileSuffix = fileSuffix.toLower();
1549
activeGenerator = GEN_UNKNOWN;
1550
tetlibInputOk = false;
1551
nglibInputOk = false;
1552
ngDim = 3;
1553
1554
// Choose generator according to fileSuffix:
1555
//------------------------------------------
1556
if ((fileSuffix == "smesh") || (fileSuffix == "poly")) {
1557
1558
if (!tetlibPresent) {
1559
logMessage("unable to mesh - tetlib unavailable");
1560
return;
1561
}
1562
1563
activeGenerator = GEN_TETLIB;
1564
cout << "Selected tetlib for smesh/poly-format" << endl;
1565
1566
in->deinitialize();
1567
in->initialize();
1568
in->load_poly(cs);
1569
1570
tetlibInputOk = true;
1571
1572
} else if (fileSuffix == "off") {
1573
1574
if (!tetlibPresent) {
1575
logMessage("unable to mesh - tetlib unavailable");
1576
return;
1577
}
1578
1579
activeGenerator = GEN_TETLIB;
1580
cout << "Selected tetlib for off-format" << endl;
1581
1582
in->deinitialize();
1583
in->initialize();
1584
in->load_off(cs);
1585
1586
tetlibInputOk = true;
1587
1588
} else if (fileSuffix == "ply") {
1589
1590
if (!tetlibPresent) {
1591
logMessage("unable to mesh - tetlib unavailable");
1592
return;
1593
}
1594
1595
activeGenerator = GEN_TETLIB;
1596
cout << "Selected tetlib for ply-format" << endl;
1597
1598
in->deinitialize();
1599
in->initialize();
1600
in->load_ply(cs);
1601
1602
tetlibInputOk = true;
1603
1604
} else if (fileSuffix == "mesh") {
1605
1606
if (!tetlibPresent) {
1607
logMessage("unable to mesh - tetlib unavailable");
1608
return;
1609
}
1610
1611
activeGenerator = GEN_TETLIB;
1612
cout << "Selected tetlib for mesh-format" << endl;
1613
1614
in->deinitialize();
1615
in->initialize();
1616
in->load_medit(cs, 1);
1617
1618
tetlibInputOk = true;
1619
1620
} else if (fileSuffix == "stl") {
1621
1622
// for stl there are two alternative generators:
1623
if (meshControl->generatorType == GEN_NGLIB) {
1624
1625
if (!nglibPresent) {
1626
logMessage("unable to mesh - nglib unavailable");
1627
return;
1628
}
1629
1630
activeGenerator = GEN_NGLIB;
1631
cout << "Selected nglib for stl-format" << endl;
1632
1633
stlFileName = fileName;
1634
1635
nglibInputOk = true;
1636
1637
} else {
1638
1639
if (!tetlibPresent) {
1640
logMessage("unable to mesh - tetlib unavailable");
1641
return;
1642
}
1643
1644
activeGenerator = GEN_TETLIB;
1645
cout << "Selected tetlib for stl-format" << endl;
1646
1647
in->deinitialize();
1648
in->initialize();
1649
in->load_stl(cs);
1650
1651
tetlibInputOk = true;
1652
}
1653
1654
} else if ((fileSuffix == "grd") || (fileSuffix == "fdneut") ||
1655
(fileSuffix == "msh") || (fileSuffix == "mphtxt") ||
1656
(fileSuffix == "inp") || (fileSuffix == "unv") ||
1657
(fileSuffix == "plt")) {
1658
1659
activeGenerator = GEN_ELMERGRID;
1660
cout << "Selected elmergrid" << endl;
1661
1662
#if WITH_QT5 || WITH_QT6
1663
int errstat = elmergridAPI->loadElmerMeshStructure(
1664
(const char *)(fileName.toLatin1()));
1665
#else
1666
int errstat = elmergridAPI->loadElmerMeshStructure(
1667
(const char *)(fileName.toAscii()));
1668
#endif
1669
1670
if (errstat)
1671
logMessage("loadElmerMeshStructure failed!");
1672
1673
return;
1674
1675
#ifdef EG_OCC
1676
1677
} else if ((fileSuffix.toLower() == "brep") ||
1678
(fileSuffix.toLower() == "step") ||
1679
(fileSuffix.toLower() == "stp") ||
1680
(fileSuffix.toLower() == "iges") ||
1681
(fileSuffix.toLower() == "igs")) {
1682
1683
meshControl->ui.nglibRadioButton->setChecked(true);
1684
meshControl->generatorType = GEN_NGLIB;
1685
activeGenerator = meshControl->generatorType;
1686
1687
if (egIni->isSet("autoview"))
1688
cadView->show();
1689
1690
occInputOk = cadView->readFile(fileName);
1691
1692
ngDim = cadView->getDim();
1693
1694
if (!occInputOk) {
1695
logMessage("Cad import: error: Unable to proceed with input file");
1696
cadView->close();
1697
return;
1698
}
1699
1700
nglibInputOk = true;
1701
1702
#endif
1703
1704
} else if ((fileSuffix.toLower() == "in2d")) {
1705
1706
if (!nglibPresent) {
1707
logMessage("unable to mesh - nglib unavailable");
1708
return;
1709
}
1710
1711
activeGenerator = GEN_NGLIB;
1712
cout << "Selected nglib for in2d-format" << endl;
1713
1714
in2dFileName = fileName;
1715
1716
nglibInputOk = true;
1717
1718
ngDim = 2;
1719
1720
} else {
1721
1722
logMessage("Unable to open file: file type unknown");
1723
activeGenerator = GEN_UNKNOWN;
1724
1725
return;
1726
}
1727
}
1728
1729
// Populate elmer's mesh structure and make GL-lists (tetlib):
1730
//-----------------------------------------------------------------------------
1731
void MainWindow::makeElmerMeshFromTetlib() {
1732
meshutils->clearMesh(glWidget->getMesh());
1733
1734
glWidget->setMesh(tetlibAPI->createElmerMeshStructure());
1735
1736
glWidget->rebuildLists();
1737
1738
logMessage("Input file processed");
1739
}
1740
1741
// Populate elmer's mesh structure and make GL-lists (nglib):
1742
//-----------------------------------------------------------------------------
1743
void MainWindow::makeElmerMeshFromNglib() {
1744
meshutils->clearMesh(glWidget->getMesh());
1745
nglibAPI->setDim(this->ngDim);
1746
nglibAPI->setNgmesh(ngmesh);
1747
1748
glWidget->setMesh(nglibAPI->createElmerMeshStructure());
1749
glWidget->rebuildLists();
1750
1751
logMessage("Input file processed");
1752
}
1753
1754
// File -> Load mesh...
1755
//-----------------------------------------------------------------------------
1756
void MainWindow::loadSlot() {
1757
QString defaultDirName = getDefaultDirName();
1758
1759
QString dirName = QFileDialog::getExistingDirectory(
1760
this, tr("Open mesh directory"), defaultDirName);
1761
1762
if (!dirName.isEmpty()) {
1763
1764
logMessage("Loading from directory " + dirName);
1765
1766
} else {
1767
1768
logMessage("Unable to load mesh: directory undefined");
1769
return;
1770
}
1771
1772
loadElmerMesh(dirName);
1773
}
1774
1775
// Import mesh files in elmer-format:
1776
//-----------------------------------------------------------------------------
1777
void MainWindow::loadElmerMesh(QString dirName) {
1778
logMessage("Loading elmer mesh files");
1779
1780
if (glWidget->hasMesh()) {
1781
glWidget->getMesh()->clear();
1782
glWidget->deleteMesh();
1783
}
1784
1785
glWidget->newMesh();
1786
1787
#if WITH_QT5 || WITH_QT6
1788
bool success = glWidget->getMesh()->load(dirName.toLatin1().data());
1789
#else
1790
bool success = glWidget->getMesh()->load(dirName.toAscii().data());
1791
#endif
1792
1793
if (!success) {
1794
glWidget->getMesh()->clear();
1795
glWidget->deleteMesh();
1796
logMessage("Failed loading mesh files");
1797
return;
1798
}
1799
1800
meshutils->findSurfaceElementEdges(glWidget->getMesh());
1801
meshutils->findSurfaceElementNormals(glWidget->getMesh());
1802
1803
glWidget->rebuildLists();
1804
1805
QDir::setCurrent(dirName);
1806
saveDirName = dirName;
1807
1808
logMessage("Ready");
1809
}
1810
1811
// File -> Save...
1812
//-----------------------------------------------------------------------------
1813
void MainWindow::saveSlot() {
1814
if (!glWidget->hasMesh()) {
1815
logMessage("Unable to save mesh: no data");
1816
return;
1817
}
1818
1819
if (!saveDirName.isEmpty()) {
1820
logMessage("Output directory " + saveDirName);
1821
} else {
1822
saveAsSlot();
1823
return;
1824
}
1825
1826
saveElmerMesh(saveDirName);
1827
}
1828
1829
// File -> Save as...
1830
//-----------------------------------------------------------------------------
1831
void MainWindow::saveAsSlot() {
1832
if (!glWidget->hasMesh()) {
1833
logMessage("Unable to save mesh: no data");
1834
return;
1835
}
1836
1837
QString defaultDirName = getDefaultDirName();
1838
1839
QString dirName = QFileDialog::getExistingDirectory(
1840
this, tr("Open directory to save mesh"), defaultDirName);
1841
1842
if (!dirName.isEmpty()) {
1843
logMessage("Output directory " + dirName);
1844
saveDirName = dirName;
1845
} else {
1846
logMessage("Unable to save: directory undefined");
1847
return;
1848
}
1849
1850
saveElmerMesh(saveDirName);
1851
}
1852
1853
// File -> Save project
1854
//-----------------------------------------------------------------------------
1855
void MainWindow::saveProjectSlot() {
1856
if (!glWidget->hasMesh()) {
1857
logMessage("Unable to save project: no mesh");
1858
return;
1859
}
1860
1861
QString projectDirName = currentProjectDirName;
1862
if (!projectDirName.isEmpty()) {
1863
logMessage("Project directory " + projectDirName);
1864
saveProject(projectDirName);
1865
} else {
1866
saveProjectAsSlot();
1867
}
1868
}
1869
1870
// File -> Save project as...
1871
//-----------------------------------------------------------------------------
1872
void MainWindow::saveProjectAsSlot() {
1873
if (!glWidget->hasMesh()) {
1874
logMessage("Unable to save project: no mesh");
1875
return;
1876
}
1877
1878
QString defaultDirName = getDefaultDirName();
1879
1880
QString projectDirName = QFileDialog::getExistingDirectory(
1881
this, tr("Open directory to save project"), defaultDirName);
1882
1883
if (!projectDirName.isEmpty()) {
1884
logMessage("Project directory " + projectDirName);
1885
} else {
1886
logMessage("Unable to save project: directory undefined");
1887
return;
1888
}
1889
1890
saveProject(projectDirName);
1891
}
1892
1893
bool MainWindow::saveProject(QString projectDirName) {
1894
if (!glWidget->hasMesh()) {
1895
logMessage("Unable to save project: no mesh");
1896
return false;
1897
}
1898
1899
progressBar->show();
1900
progressBar->setRange(0, 13);
1901
1902
progressLabel->setText("Saving");
1903
progressLabel->show();
1904
1905
// Create project document:
1906
//-------------------------
1907
progressBar->setValue(1);
1908
1909
QDomDocument projectDoc("egproject");
1910
QDomElement contents = projectDoc.createElement("contents");
1911
projectDoc.appendChild(contents);
1912
1913
//===========================================================================
1914
// SAVE MESH
1915
//===========================================================================
1916
progressBar->setValue(2);
1917
logMessage("Saving mesh files...");
1918
saveElmerMesh(projectDirName);
1919
1920
//===========================================================================
1921
// SAVE GEOMETRY INPUT FILE(S)
1922
//===========================================================================
1923
progressBar->setValue(3);
1924
1925
#ifdef Q_OS_LINUX
1926
QFileInfo fileInfo(geometryInputFileName);
1927
QString pathName(fileInfo.absolutePath());
1928
QString baseName(fileInfo.baseName());
1929
1930
// System copy command:
1931
QString cmd("cp -f " + pathName + "/" + baseName + ".* " + projectDirName);
1932
1933
if (system(cmd.toLatin1().data()))
1934
logMessage("Geometry input file(s) not copied");
1935
1936
QDomElement geomInput(projectDoc.createElement("geometryinputfile"));
1937
QDomText geomInputValue(projectDoc.createTextNode(fileInfo.fileName()));
1938
geomInput.appendChild(geomInputValue);
1939
contents.appendChild(geomInput);
1940
1941
#else
1942
QFileInfo geometryInputFileInfo(geometryInputFileName);
1943
QString baseName(geometryInputFileInfo.baseName());
1944
1945
QString srcPathName(geometryInputFileInfo.absolutePath());
1946
QString dstPathName(QDir(projectDirName).absolutePath());
1947
1948
// Avoid copying file(s) into it self:
1949
1950
if (srcPathName != dstPathName) {
1951
QDirIterator srcDirIterator(srcPathName);
1952
1953
while (srcDirIterator.hasNext()) {
1954
QString srcFileName(srcDirIterator.next());
1955
QFileInfo srcFileInfo(srcDirIterator.fileInfo());
1956
1957
if (srcFileInfo.baseName() == baseName) {
1958
logMessage("Copying: " + srcFileName);
1959
1960
QFile src(srcFileName);
1961
1962
if (!src.open(QFile::ReadOnly)) {
1963
logMessage("Unable to read: " + src.fileName());
1964
continue;
1965
}
1966
1967
QFile dst(dstPathName + "/" + srcFileInfo.fileName());
1968
1969
if (!dst.open(QFile::WriteOnly)) {
1970
logMessage("Unable to write: " + dst.fileName());
1971
src.close();
1972
continue;
1973
}
1974
1975
QTextStream srcStream(&src);
1976
QTextStream dstStream(&dst);
1977
dstStream << srcStream.readAll();
1978
1979
dst.close();
1980
src.close();
1981
}
1982
}
1983
1984
} else {
1985
logMessage("Geometry input file(s) not copied");
1986
}
1987
1988
QDomElement geomInput = projectDoc.createElement("geometryinputfile");
1989
QDomText geomInputValue =
1990
projectDoc.createTextNode(geometryInputFileInfo.fileName());
1991
geomInput.appendChild(geomInputValue);
1992
contents.appendChild(geomInput);
1993
#endif
1994
1995
//===========================================================================
1996
// SAVE OPERATIONS
1997
//===========================================================================
1998
progressBar->setValue(4);
1999
QDomElement ops = projectDoc.createElement("operations");
2000
contents.appendChild(ops);
2001
operation.appendToProject(&projectDoc, &ops);
2002
2003
//===========================================================================
2004
// SAVE GENERAL SETUP
2005
//===========================================================================
2006
progressBar->setValue(5);
2007
logMessage("Saving menu contents... ");
2008
QDomElement gsBlock = projectDoc.createElement("generalsetup");
2009
projectDoc.documentElement().appendChild(gsBlock);
2010
generalSetup->appendToProject(&projectDoc, &gsBlock);
2011
2012
//===========================================================================
2013
// SAVE PARALLEL SETTINGS
2014
//===========================================================================
2015
progressBar->setValue(6);
2016
QDomElement paraBlock = projectDoc.createElement("parallelsettings");
2017
projectDoc.documentElement().appendChild(paraBlock);
2018
parallel->appendToProject(&projectDoc, &paraBlock);
2019
2020
//===========================================================================
2021
// SAVE MESH PARAMETERS
2022
//===========================================================================
2023
progressBar->setValue(7);
2024
QDomElement meshParams = projectDoc.createElement("meshparameters");
2025
projectDoc.documentElement().appendChild(meshParams);
2026
meshControl->appendToProject(&projectDoc, &meshParams);
2027
2028
//===========================================================================
2029
// SAVE SOLVER PARAMETERS
2030
//===========================================================================
2031
progressBar->setValue(8);
2032
QDomElement speBlock = projectDoc.createElement("solverparameters");
2033
projectDoc.documentElement().appendChild(speBlock);
2034
2035
for (int index = 0; index < solverParameterEditor.size(); index++) {
2036
SolverParameterEditor *spe = solverParameterEditor[index];
2037
2038
if (!spe)
2039
continue;
2040
2041
QDomElement item = projectDoc.createElement("item");
2042
item.setAttribute("index", QString::number(index));
2043
item.setAttribute("name", spe->solverName);
2044
speBlock.appendChild(item);
2045
spe->appendToProject(&projectDoc, &item);
2046
}
2047
2048
//===========================================================================
2049
// SAVE DYNAMIC MENU CONTENTS
2050
//===========================================================================
2051
progressBar->setValue(9);
2052
saveProjectContents(projectDoc, "equation", equationEditor);
2053
saveProjectContents(projectDoc, "material", materialEditor);
2054
saveProjectContents(projectDoc, "bodyforce", bodyForceEditor);
2055
saveProjectContents(projectDoc, "initialcondition", initialConditionEditor);
2056
saveProjectContents(projectDoc, "boundarycondition", boundaryConditionEditor);
2057
2058
//===========================================================================
2059
// SAVE SOLVER SPECIFIC OPTIONS
2060
//===========================================================================
2061
progressBar->setValue(10);
2062
QDomElement solverOptionsBlock =
2063
projectDoc.createElement("solverspecificoptions");
2064
projectDoc.documentElement().appendChild(solverOptionsBlock);
2065
2066
for (int index = 0; index < solverParameterEditor.size(); index++) {
2067
SolverParameterEditor *spe = solverParameterEditor[index];
2068
2069
if (!spe)
2070
continue;
2071
2072
DynamicEditor *dynEdit = spe->generalOptions;
2073
2074
if (!dynEdit)
2075
continue;
2076
2077
QDomElement item = projectDoc.createElement("item");
2078
item.setAttribute("index", QString::number(index));
2079
item.setAttribute("name", spe->solverName);
2080
item.setAttribute("id", QString::number(dynEdit->ID));
2081
solverOptionsBlock.appendChild(item);
2082
2083
dynEdit->dumpHash(&projectDoc, &item);
2084
}
2085
2086
//===========================================================================
2087
// SAVE BODY PROPERTIES
2088
//===========================================================================
2089
progressBar->setValue(11);
2090
QDomElement bodyBlock = projectDoc.createElement("bodyproperties");
2091
projectDoc.documentElement().appendChild(bodyBlock);
2092
2093
for (int index = 0; index < bodyPropertyEditor.size(); index++) {
2094
BodyPropertyEditor *bpe = bodyPropertyEditor[index];
2095
2096
if (!bpe)
2097
continue;
2098
2099
QDomElement item = projectDoc.createElement("item");
2100
item.setAttribute("index", QString::number(index));
2101
bodyBlock.appendChild(item);
2102
bpe->appendToProject(&projectDoc, &item);
2103
}
2104
2105
//===========================================================================
2106
// SAVE BOUNDARY PROPERTIES
2107
//===========================================================================
2108
progressBar->setValue(12);
2109
QDomElement boundaryBlock = projectDoc.createElement("boundaryproperties");
2110
projectDoc.documentElement().appendChild(boundaryBlock);
2111
2112
for (int index = 0; index < boundaryPropertyEditor.size(); index++) {
2113
BoundaryPropertyEditor *bpe = boundaryPropertyEditor[index];
2114
2115
if (!bpe)
2116
continue;
2117
2118
QDomElement item = projectDoc.createElement("item");
2119
item.setAttribute("index", QString::number(index));
2120
boundaryBlock.appendChild(item);
2121
bpe->appendToProject(&projectDoc, &item);
2122
}
2123
2124
//===========================================================================
2125
// SAVE PROJECT DOCUMENT
2126
//===========================================================================
2127
progressBar->setValue(13);
2128
const int indent = 3;
2129
QFile projectFile("egproject.xml");
2130
projectFile.open(QIODevice::WriteOnly);
2131
QTextStream projectTextStream(&projectFile);
2132
projectDoc.save(projectTextStream, indent);
2133
2134
saveDirName = projectDirName;
2135
logMessage("Ready");
2136
2137
progressBar->hide();
2138
progressLabel->hide();
2139
2140
setWindowTitle(QString("ElmerGUI - ") + projectDirName);
2141
addRecentProject(projectDirName, true);
2142
currentProjectDirName = projectDirName;
2143
2144
return true;
2145
}
2146
2147
// Helper function for saveProject
2148
//-----------------------------------------------------------------------------
2149
void MainWindow::saveProjectContents(QDomDocument projectDoc, QString blockName,
2150
QVector<DynamicEditor *> &editor) {
2151
int Nmax = editor.size();
2152
2153
QDomElement editorBlock = projectDoc.createElement(blockName);
2154
projectDoc.documentElement().appendChild(editorBlock);
2155
int index = 0; // index excluding removed DynamicEditor instances
2156
2157
for (int i = 0; i < Nmax; i++) {
2158
DynamicEditor *de = editor[i];
2159
2160
if (de->menuAction == NULL)
2161
continue;
2162
2163
// Menu item number:
2164
QDomElement item = projectDoc.createElement("item");
2165
item.setAttribute("index", QString::number(index++));
2166
editorBlock.appendChild(item);
2167
2168
// Is active?
2169
QDomElement itemActive = projectDoc.createElement("active");
2170
QDomText itemActiveValue =
2171
projectDoc.createTextNode(QString::number(de->menuAction != NULL));
2172
itemActive.appendChild(itemActiveValue);
2173
item.appendChild(itemActive);
2174
2175
// Name:
2176
if (de->menuAction != NULL) {
2177
QDomElement itemName = projectDoc.createElement("name");
2178
QDomText itemNameValue =
2179
projectDoc.createTextNode(de->nameEdit->text().trimmed());
2180
itemName.appendChild(itemNameValue);
2181
item.appendChild(itemName);
2182
}
2183
2184
de->dumpHash(&projectDoc, &item);
2185
}
2186
}
2187
2188
// File -> Load project...
2189
//-----------------------------------------------------------------------------
2190
void MainWindow::loadProjectSlot() {
2191
QString defaultDirName = getDefaultDirName();
2192
2193
QString projectDirName = QFileDialog::getExistingDirectory(
2194
this, tr("Open project directory"), defaultDirName);
2195
2196
loadProject(projectDirName);
2197
}
2198
2199
void MainWindow::loadProject(QString projectDirName) {
2200
if (!projectDirName.isEmpty()) {
2201
logMessage("Project directory: " + projectDirName);
2202
} else {
2203
logMessage("Unable to load project: directory undefined");
2204
return;
2205
}
2206
2207
QDir::setCurrent(projectDirName);
2208
saveDirName = projectDirName;
2209
2210
progressBar->show();
2211
progressBar->setRange(0, 14);
2212
2213
progressLabel->setText("Loading");
2214
progressLabel->show();
2215
2216
// Clear previous data:
2217
//----------------------
2218
progressBar->setValue(1);
2219
2220
logMessage("Clearing model data");
2221
modelClearSlot();
2222
2223
// Re-initialize definitions and edfEditor
2224
delete elmerDefs;
2225
delete edfEditor;
2226
elmerDefs = new QDomDocument;
2227
edfEditor = new EdfEditor;
2228
loadDefinitions();
2229
2230
// Load project doc:
2231
//-------------------
2232
progressBar->setValue(2);
2233
2234
logMessage("Loading project document...");
2235
QDomDocument projectDoc;
2236
QString errStr;
2237
int errRow;
2238
int errCol;
2239
QFile projectFile("egproject.xml");
2240
2241
if (!projectFile.exists()) {
2242
QMessageBox::information(window(), tr("Project loader"),
2243
tr("Project file does not exist"));
2244
2245
progressBar->hide();
2246
progressLabel->hide();
2247
2248
return;
2249
2250
} else {
2251
2252
if (!projectDoc.setContent(&projectFile, true, &errStr, &errRow, &errCol)) {
2253
QMessageBox::information(window(), tr("Project loader"),
2254
tr("Parse error at line %1, col %2:\n%3")
2255
.arg(errRow)
2256
.arg(errCol)
2257
.arg(errStr));
2258
projectFile.close();
2259
2260
progressBar->hide();
2261
progressLabel->hide();
2262
2263
return;
2264
}
2265
}
2266
2267
projectFile.close();
2268
2269
if (projectDoc.documentElement().tagName() != "contents") {
2270
QMessageBox::information(window(), tr("Project loader"),
2271
tr("This is not a project file"));
2272
2273
progressBar->hide();
2274
progressLabel->hide();
2275
2276
return;
2277
}
2278
2279
// load extra solvers from /edf-extra
2280
checkAndLoadExtraSolvers(&projectFile);
2281
2282
setWindowTitle(QString("ElmerGUI - ") + projectDirName);
2283
addRecentProject(projectDirName, true);
2284
currentProjectDirName = projectDirName;
2285
2286
QDomElement contents = projectDoc.documentElement();
2287
2288
//===========================================================================
2289
// LOAD MESH
2290
//===========================================================================
2291
progressBar->setValue(3);
2292
logMessage("Loading mesh files...");
2293
loadElmerMesh(projectDirName);
2294
resetSlot();
2295
2296
//===========================================================================
2297
// LOAD GEOMETRY INPUT FILE
2298
//===========================================================================
2299
progressBar->setValue(4);
2300
cout << "Loading geometry input file" << endl;
2301
QDomElement geomInput = contents.firstChildElement("geometryinputfile");
2302
geometryInputFileName = projectDirName + "/" + geomInput.text().trimmed();
2303
logMessage("Geometry input file: " + geometryInputFileName);
2304
readInputFile(geometryInputFileName);
2305
2306
//===========================================================================
2307
// LOAD OPERATIONS
2308
//===========================================================================
2309
logMessage("Loading operations...");
2310
progressBar->setValue(5);
2311
QDomElement ops = contents.firstChildElement("operations");
2312
operations = operation.readFromProject(&projectDoc, &ops);
2313
2314
//===========================================================================
2315
// LOAD GENERAL SETUP
2316
//===========================================================================
2317
logMessage("Loading general setup...");
2318
progressBar->setValue(6);
2319
QDomElement gsBlock = contents.firstChildElement("generalsetup");
2320
generalSetup->readFromProject(&projectDoc, &gsBlock);
2321
2322
//===========================================================================
2323
// LOAD PARALLEL SETTINGS
2324
//===========================================================================
2325
logMessage("Loading parallel settings...");
2326
progressBar->setValue(7);
2327
QDomElement paraBlock = contents.firstChildElement("parallelsettings");
2328
parallel->readFromProject(&projectDoc, &paraBlock);
2329
2330
//===========================================================================
2331
// LOAD MESH PARAMETERS
2332
//===========================================================================
2333
logMessage("Loading mesh parameters...");
2334
progressBar->setValue(8);
2335
QDomElement meshParams = contents.firstChildElement("meshparameters");
2336
meshControl->readFromProject(&projectDoc, &meshParams);
2337
2338
//===========================================================================
2339
// LOAD SOLVER PARAMETERS
2340
//===========================================================================
2341
logMessage("Loading solver parameters...");
2342
progressBar->setValue(9);
2343
QDomElement speBlock = contents.firstChildElement("solverparameters");
2344
2345
QDomElement item = speBlock.firstChildElement("item");
2346
for (; !item.isNull(); item = item.nextSiblingElement()) {
2347
int index = item.attribute("index").toInt();
2348
QString name = item.attribute("name");
2349
2350
if (name.trimmed().isEmpty())
2351
continue;
2352
2353
// Find the real index for the current edf setup:
2354
int count = 0, realIndex = -1;
2355
QDomElement root = elmerDefs->documentElement();
2356
QDomElement elem = root.firstChildElement("PDE");
2357
while (!elem.isNull()) {
2358
QDomElement pdeName = elem.firstChildElement("Name");
2359
if (pdeName.text().trimmed() == name.trimmed())
2360
realIndex = count;
2361
elem = elem.nextSiblingElement();
2362
count++;
2363
}
2364
2365
if (realIndex < 0) {
2366
cout << "ERROR: The current edf setup conflicts with the project. "
2367
"Aborting."
2368
<< endl;
2369
2370
progressBar->hide();
2371
progressLabel->hide();
2372
2373
return;
2374
}
2375
2376
index = realIndex - 1;
2377
2378
if (index < 0) {
2379
logMessage("Load project: solver parameters: index out of bounds");
2380
2381
progressBar->hide();
2382
progressLabel->hide();
2383
2384
return;
2385
}
2386
2387
if (index >= solverParameterEditor.size())
2388
solverParameterEditor.resize(index + 1);
2389
2390
if (!solverParameterEditor[index])
2391
solverParameterEditor[index] = new SolverParameterEditor;
2392
2393
SolverParameterEditor *spe = solverParameterEditor[index];
2394
spe->readFromProject(&projectDoc, &item);
2395
}
2396
2397
#if 0
2398
// Changed the load order in 19 March 2009 for taking the "use as a body"
2399
// flags into account. The original boundary property loader is below.
2400
//
2401
// Changed back to original 23 March 2009. Todo...
2402
//===========================================================================
2403
// LOAD BOUNDARY PROPERTIES
2404
//===========================================================================
2405
progressBar->setValue(10);
2406
QDomElement boundaryBlock = contents.firstChildElement("boundaryproperties");
2407
2408
item = boundaryBlock.firstChildElement("item");
2409
for( ; !item.isNull(); item = item.nextSiblingElement()) {
2410
int index = item.attribute("index").toInt();
2411
2412
if(index < 0) {
2413
logMessage("Load project: boundary properties: index out of bounds");
2414
2415
progressBar->hide();
2416
progressLabel->hide();
2417
2418
return;
2419
}
2420
2421
if(index >= boundaryPropertyEditor.size())
2422
boundaryPropertyEditor.resize(index + 1);
2423
2424
if(!boundaryPropertyEditor[index])
2425
boundaryPropertyEditor[index] = new BoundaryPropertyEditor;
2426
2427
BoundaryPropertyEditor *bpe = boundaryPropertyEditor[index];
2428
2429
bpe->readFromProject(&projectDoc, &item);
2430
2431
if(bpe->ui.boundaryAsABody->isChecked()) {
2432
connect(bpe, SIGNAL(BoundaryAsABodyChanged(BoundaryPropertyEditor*, int)),
2433
this, SLOT(boundaryAsABodyChanged(BoundaryPropertyEditor*, int)));
2434
2435
populateBoundaryComboBoxes(bpe);
2436
2437
bpe->ui.boundaryAsABody->toggle();
2438
bpe->ui.boundaryAsABody->toggle();
2439
bpe->ui.applyButton->click();
2440
}
2441
}
2442
#endif
2443
2444
//===========================================================================
2445
// LOAD DYNAMIC EDITOR CONTENTS
2446
//===========================================================================
2447
logMessage("Loading dynamic editor contents...");
2448
progressBar->setValue(11);
2449
QDomElement element =
2450
projectDoc.documentElement().firstChildElement("equation");
2451
loadProjectContents(element, equationEditor, "Equation");
2452
element = projectDoc.documentElement().firstChildElement("material");
2453
loadProjectContents(element, materialEditor, "Material");
2454
element = projectDoc.documentElement().firstChildElement("bodyforce");
2455
loadProjectContents(element, bodyForceEditor, "BodyForce");
2456
element = projectDoc.documentElement().firstChildElement("initialcondition");
2457
loadProjectContents(element, initialConditionEditor, "InitialCondition");
2458
element = projectDoc.documentElement().firstChildElement("boundarycondition");
2459
loadProjectContents(element, boundaryConditionEditor, "BoundaryCondition");
2460
2461
//===========================================================================
2462
// LOAD SOLVER SPECIFIC OPTIONS
2463
//===========================================================================
2464
logMessage("Loading solver specific options...");
2465
progressBar->setValue(12);
2466
QDomElement solverOptionsBlock =
2467
contents.firstChildElement("solverspecificoptions");
2468
2469
for (item = solverOptionsBlock.firstChildElement("item"); !item.isNull();
2470
item = item.nextSiblingElement()) {
2471
2472
int index = item.attribute("index").toInt();
2473
QString name = item.attribute("name");
2474
int id = item.attribute("id").toInt();
2475
2476
if (name.trimmed().isEmpty())
2477
continue;
2478
2479
// Find the real index for the current edf setup:
2480
int count = 0, realIndex = -1;
2481
QDomElement root = elmerDefs->documentElement();
2482
QDomElement elem = root.firstChildElement("PDE");
2483
while (!elem.isNull()) {
2484
QDomElement pdeName = elem.firstChildElement("Name");
2485
if (pdeName.text().trimmed() == name.trimmed())
2486
realIndex = count;
2487
elem = elem.nextSiblingElement();
2488
count++;
2489
}
2490
2491
if (realIndex < 0) {
2492
cout << "ERROR: The current edf setup conflicts with the project. "
2493
"Aborting."
2494
<< endl;
2495
2496
progressBar->hide();
2497
progressLabel->hide();
2498
2499
return;
2500
}
2501
2502
index = realIndex - 1;
2503
2504
if (index < 0) {
2505
logMessage("Load project: solver specific options: index out of bounds");
2506
2507
progressBar->hide();
2508
progressLabel->hide();
2509
2510
return;
2511
}
2512
2513
if (index >= solverParameterEditor.size())
2514
solverParameterEditor.resize(index + 1);
2515
2516
if (!solverParameterEditor[index])
2517
solverParameterEditor[index] = new SolverParameterEditor;
2518
2519
SolverParameterEditor *spe = solverParameterEditor[index];
2520
spe->solverName = name;
2521
2522
if (spe->generalOptions == NULL) {
2523
spe->generalOptions = new DynamicEditor;
2524
2525
// following 3 lines were moved into if() block to avoid doubled "Solver
2526
// specific options" tabs (Nov 2019 by TS)
2527
// The argument "index" in the following two functions is changed from "id" to avoid
2528
// crossed parameters (Mar 2022 by TS) See http://www.elmerfem.org/forum/viewtopic.php?t=7696
2529
spe->generalOptions->setupTabs(elmerDefs, "Solver", index);
2530
spe->generalOptions->populateHash(&item);
2531
spe->ui.solverControlTabs->insertTab(
2532
0, spe->generalOptions->tabWidget->widget(index),
2533
"Solver specific options");
2534
}
2535
}
2536
2537
//===========================================================================
2538
// LOAD BODY PROPERTIES
2539
//===========================================================================
2540
logMessage("Loading body properties...");
2541
progressBar->setValue(13);
2542
QDomElement bodyBlock = contents.firstChildElement("bodyproperties");
2543
2544
item = bodyBlock.firstChildElement("item");
2545
for (; !item.isNull(); item = item.nextSiblingElement()) {
2546
int index = item.attribute("index").toInt();
2547
2548
if (index < 0) {
2549
logMessage("Load project: body properties: index out of bounds");
2550
2551
progressBar->hide();
2552
progressLabel->hide();
2553
2554
return;
2555
}
2556
2557
if (index >= bodyPropertyEditor.size())
2558
bodyPropertyEditor.resize(index + 1);
2559
2560
if (!bodyPropertyEditor[index])
2561
bodyPropertyEditor[index] = new BodyPropertyEditor;
2562
2563
BodyPropertyEditor *bpe = bodyPropertyEditor[index];
2564
bpe->readFromProject(&projectDoc, &item);
2565
}
2566
2567
//===========================================================================
2568
// LOAD BOUNDARY PROPERTIES
2569
//===========================================================================
2570
logMessage("Loading boundary properties...");
2571
progressBar->setValue(13);
2572
QDomElement boundaryBlock = contents.firstChildElement("boundaryproperties");
2573
2574
item = boundaryBlock.firstChildElement("item");
2575
for (; !item.isNull(); item = item.nextSiblingElement()) {
2576
int index = item.attribute("index").toInt();
2577
2578
if (index < 0) {
2579
logMessage("Load project: boundary properties: index out of bounds");
2580
2581
progressBar->hide();
2582
progressLabel->hide();
2583
2584
return;
2585
}
2586
2587
if (index >= boundaryPropertyEditor.size())
2588
boundaryPropertyEditor.resize(index + 1);
2589
2590
if (!boundaryPropertyEditor[index])
2591
boundaryPropertyEditor[index] = new BoundaryPropertyEditor;
2592
2593
BoundaryPropertyEditor *bpe = boundaryPropertyEditor[index];
2594
bpe->readFromProject(&projectDoc, &item);
2595
}
2596
2597
//===========================================================================
2598
// LOAD SIF
2599
//===========================================================================
2600
progressBar->setValue(14);
2601
if (glWidget->hasMesh()) {
2602
QFile file;
2603
QString sifName = generalSetup->ui.solverInputFileEdit->text().trimmed();
2604
file.setFileName(sifName);
2605
if (file.open(QIODevice::ReadOnly)) {
2606
QTextStream inputStream(&file);
2607
QString line = inputStream.readAll();
2608
file.close();
2609
sifWindow->getTextEdit()->clear();
2610
sifWindow->getTextEdit()->append(line);
2611
sifWindow->setFirstTime(true);
2612
sifWindow->setFound(false);
2613
logMessage(sifName + " loaded.");
2614
} else {
2615
logMessage(" failed to open " + sifName);
2616
}
2617
}
2618
2619
logMessage("Ready");
2620
2621
progressBar->hide();
2622
progressLabel->hide();
2623
2624
#ifdef EG_VTK
2625
vtkPost->hideAll();
2626
#endif
2627
}
2628
2629
// Helper function for load project
2630
//--------------------------------------------------------------------------------------------
2631
void MainWindow::loadProjectContents(QDomElement projectElement,
2632
QVector<DynamicEditor *> &editor,
2633
QString Mname) {
2634
int Nmax = editor.size();
2635
2636
QDomElement item = projectElement.firstChildElement("item");
2637
2638
for (; !item.isNull(); item = item.nextSiblingElement()) {
2639
int index = item.attribute("index").toInt();
2640
2641
if (index < 0) {
2642
logMessage("Project loader: index out of bounds (dynamic editor)");
2643
return;
2644
}
2645
2646
if (index >= editor.size())
2647
editor.resize(index + 1);
2648
2649
if (!editor[index])
2650
editor[index] = new DynamicEditor;
2651
2652
DynamicEditor *de = editor[index];
2653
2654
bool active = (item.firstChildElement("active").text().toInt() > 0);
2655
2656
if (!active)
2657
continue;
2658
2659
// Set up dynamic editor and connect:
2660
//------------------------------------
2661
QString itemName = item.firstChildElement("name").text().trimmed();
2662
2663
de->setupTabs(elmerDefs, Mname, index);
2664
de->nameEdit->setText(itemName);
2665
de->applyButton->setText("Update");
2666
de->applyButton->setIcon(QIcon::fromTheme("view-refresh"));
2667
de->discardButton->setText("Remove");
2668
de->discardButton->setIcon(QIcon::fromTheme("list-remove"));
2669
2670
const QString &tmpName = itemName;
2671
QAction *act = new QAction(tmpName, this);
2672
2673
if (Mname == "Equation") {
2674
connect(de, SIGNAL(dynamicEditorReady(int, int)), this,
2675
SLOT(pdeEditorFinishedSlot(int, int)));
2676
de->spareButton->setText("Edit Solver Settings");
2677
de->spareButton->show();
2678
de->spareButton->setIcon(QIcon::fromTheme("preferences-system"));
2679
de->spareButton->setWhatsThis(tr("Open solver setting window"));
2680
connect(de, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,
2681
SLOT(editNumericalMethods(int, int)));
2682
equationMenu->addAction(act);
2683
}
2684
2685
if (Mname == "Material") {
2686
connect(de, SIGNAL(dynamicEditorReady(int, int)), this,
2687
SLOT(matEditorFinishedSlot(int, int)));
2688
de->spareButton->setText("Material library");
2689
de->spareButton->show();
2690
de->spareButton->setIcon(QIcon::fromTheme("book-cover-A-Z"));
2691
de->spareButton->setWhatsThis(tr("Open material library"));
2692
connect(de, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,
2693
SLOT(showMaterialLibrary(int, int)));
2694
materialMenu->addAction(act);
2695
}
2696
2697
if (Mname == "BodyForce") {
2698
connect(de, SIGNAL(dynamicEditorReady(int, int)), this,
2699
SLOT(bodyForceEditorFinishedSlot(int, int)));
2700
bodyForceMenu->addAction(act);
2701
}
2702
2703
if (Mname == "InitialCondition") {
2704
connect(de, SIGNAL(dynamicEditorReady(int, int)), this,
2705
SLOT(initialConditionEditorFinishedSlot(int, int)));
2706
initialConditionMenu->addAction(act);
2707
}
2708
2709
if (Mname == "BoundaryCondition") {
2710
connect(de, SIGNAL(dynamicEditorReady(int, int)), this,
2711
SLOT(boundaryConditionEditorFinishedSlot(int, int)));
2712
boundaryConditionMenu->addAction(act);
2713
}
2714
2715
de->menuAction = act;
2716
2717
if (Mname == "Equation")
2718
createBodyCheckBoxes(BODY_EQUATION, de);
2719
2720
if (Mname == "Material")
2721
createBodyCheckBoxes(BODY_MATERIAL, de);
2722
2723
if (Mname == "BodyForce")
2724
createBodyCheckBoxes(BODY_FORCE, de);
2725
2726
if (Mname == "InitialCondition")
2727
createBodyCheckBoxes(BODY_INITIAL, de);
2728
2729
if (Mname == "BoundaryCondition")
2730
createBoundaryCheckBoxes(de);
2731
2732
de->populateHash(&item);
2733
}
2734
}
2735
2736
// Export mesh files in elmer-format:
2737
//-----------------------------------------------------------------------------
2738
void MainWindow::saveElmerMesh(QString dirName) {
2739
logMessage("Saving elmer mesh files");
2740
2741
QDir dir(dirName);
2742
2743
if (!dir.exists())
2744
dir.mkdir(dirName);
2745
2746
dir.setCurrent(dirName);
2747
2748
// Save mesh files:
2749
//------------------
2750
#if WITH_QT5 || WITH_QT6
2751
glWidget->getMesh()->save(dirName.toLatin1().data());
2752
#else
2753
glWidget->getMesh()->save(dirName.toAscii().data());
2754
#endif
2755
2756
// Save solver input file:
2757
//-------------------------
2758
QFile file;
2759
QString sifName = generalSetup->ui.solverInputFileEdit->text().trimmed();
2760
file.setFileName(sifName);
2761
file.open(QIODevice::WriteOnly);
2762
QTextStream sif(&file);
2763
2764
QApplication::setOverrideCursor(Qt::WaitCursor);
2765
sif << sifWindow->getTextEdit()->toPlainText();
2766
QApplication::restoreOverrideCursor();
2767
2768
file.close();
2769
2770
// Save ELMERSOLVER_STARTINFO:
2771
//-----------------------------
2772
file.setFileName("ELMERSOLVER_STARTINFO");
2773
file.open(QIODevice::WriteOnly);
2774
QTextStream startinfo(&file);
2775
2776
#if WITH_QT6
2777
startinfo << sifName.toLatin1() << Qt::endl << "1" << Qt::endl;
2778
#elif WITH_QT5
2779
startinfo << sifName.toLatin1() << endl << "1" << endl;
2780
#else
2781
startinfo << sifName.toAscii() << endl << "1" << endl;
2782
#endif
2783
2784
file.close();
2785
2786
logMessage("Ready");
2787
}
2788
2789
// File -> Exit
2790
//-----------------------------------------------------------------------------
2791
void MainWindow::closeMainWindowSlot() {
2792
saveSlot();
2793
QApplication::closeAllWindows();
2794
// close();
2795
}
2796
2797
// File -> Save picture as...
2798
//-----------------------------------------------------------------------------
2799
void MainWindow::savePictureSlot() {
2800
QString defaultDirName(getDefaultDirName());
2801
2802
pictureFileName = QFileDialog::getSaveFileName(
2803
this, tr("Save picture"), defaultDirName,
2804
tr("Picture files (*.bmp *.jpg *.png *.pbm *.pgm *.ppm)"));
2805
2806
if (pictureFileName.isEmpty()) {
2807
logMessage("File name is empty");
2808
return;
2809
}
2810
2811
int delay = egIni->value("screenshotdelay").toInt();
2812
2813
grabTimeLine->stop();
2814
grabTimeLine->setDuration(delay);
2815
#if WITH_QT6
2816
grabTimeLine->setEasingCurve(QEasingCurve(QEasingCurve::Linear));
2817
#else
2818
grabTimeLine->setCurveShape(QTimeLine::LinearCurve);
2819
#endif
2820
grabTimeLine->setDirection(QTimeLine::Backward);
2821
grabTimeLine->setFrameRange(0, 10);
2822
progressLabel->setText("Delay screen shot");
2823
progressLabel->show();
2824
progressBar->setRange(0, 10);
2825
progressBar->show();
2826
grabTimeLine->start();
2827
}
2828
2829
void MainWindow::grabFrameSlot() {
2830
progressLabel->hide();
2831
progressBar->hide();
2832
2833
if (pictureFileName.isEmpty()) {
2834
logMessage("Unable to take screen shot - file name is empty");
2835
return;
2836
}
2837
2838
QFileInfo fi(pictureFileName);
2839
QString suffix(fi.suffix());
2840
suffix = suffix.toUpper();
2841
2842
int imageQuality(egIni->value("defaultimagequality").toInt());
2843
2844
bool withAlpha(false);
2845
2846
glWidget->updateGL();
2847
glReadBuffer(GL_BACK);
2848
2849
#if WITH_QT6
2850
QImage image(glWidget->grabFramebuffer());
2851
#else
2852
QImage image(glWidget->grabFrameBuffer(withAlpha));
2853
#endif
2854
2855
#if WITH_QT5 || WITH_QT6
2856
bool success(image.save(pictureFileName, suffix.toLatin1(), imageQuality));
2857
#else
2858
bool success(image.save(pictureFileName, suffix.toAscii(), imageQuality));
2859
#endif
2860
2861
if (!success)
2862
logMessage("Failed writing picture file");
2863
}
2864
2865
//*****************************************************************************
2866
//
2867
// Model MENU
2868
//
2869
//*****************************************************************************
2870
2871
// Model -> Setup...
2872
//-----------------------------------------------------------------------------
2873
void MainWindow::modelSetupSlot() { generalSetup->show(); }
2874
2875
//-----------------------------------------------------------------------------
2876
void MainWindow::createBodyCheckBoxes(int which, DynamicEditor *pe) {
2877
if (!glWidget->hasMesh())
2878
return;
2879
2880
if (pe->spareScroll->widget())
2881
delete pe->spareScroll->widget();
2882
2883
QGridLayout *slayout = new QGridLayout;
2884
QLabel *l = new QLabel(tr("Apply to bodies:"));
2885
2886
int count = 0, even = 0;
2887
2888
slayout->addWidget(l, count, 0);
2889
count++;
2890
2891
QMapIterator<int, int> itr(glWidget->bodyMap);
2892
while (itr.hasNext()) {
2893
itr.next();
2894
int n = itr.key();
2895
if (n >= 0) {
2896
int m = itr.value();
2897
2898
if (m >= bodyPropertyEditor.size())
2899
bodyPropertyEditor.resize(m + 1);
2900
2901
if (!bodyPropertyEditor[m])
2902
bodyPropertyEditor[m] = new BodyPropertyEditor;
2903
2904
BodyPropertyEditor *body = bodyPropertyEditor[m];
2905
2906
populateBodyComboBoxes(body);
2907
2908
QString title = body->ui.nameEdit->text().trimmed();
2909
QCheckBox *a;
2910
2911
if (title.isEmpty())
2912
// a = new QCheckBox("Body " + QString::number(n));
2913
a = new QCheckBox("Body Property " + QString::number(n));
2914
else
2915
a = new QCheckBox(title);
2916
2917
DynamicEditor *p = NULL;
2918
2919
switch (which) {
2920
case BODY_MATERIAL:
2921
p = body->material;
2922
connect(a, SIGNAL(stateChanged(int)), this,
2923
SLOT(materialBodyChanged(int)));
2924
break;
2925
case BODY_INITIAL:
2926
p = body->initial;
2927
connect(a, SIGNAL(stateChanged(int)), this,
2928
SLOT(initialBodyChanged(int)));
2929
break;
2930
case BODY_FORCE:
2931
p = body->force;
2932
connect(a, SIGNAL(stateChanged(int)), this,
2933
SLOT(forceBodyChanged(int)));
2934
break;
2935
case BODY_EQUATION:
2936
p = body->equation;
2937
connect(a, SIGNAL(stateChanged(int)), this,
2938
SLOT(equationBodyChanged(int)));
2939
break;
2940
}
2941
2942
a->setProperty("body", (qulonglong)body);
2943
a->setProperty("editor", (qulonglong)pe);
2944
2945
if (p == pe)
2946
a->setChecked(true);
2947
else if (p != NULL)
2948
a->setEnabled(false);
2949
else
2950
a->setChecked(false);
2951
2952
slayout->addWidget(a, count, even);
2953
even = 1 - even;
2954
if (!even)
2955
count++;
2956
}
2957
}
2958
2959
for (int i = 0; i < boundaryPropertyEditor.size(); i++) {
2960
BoundaryPropertyEditor *boundary = boundaryPropertyEditor[i];
2961
2962
if (!boundary)
2963
continue;
2964
2965
if (boundary->bodyProperties) {
2966
BodyPropertyEditor *body = boundary->bodyProperties;
2967
populateBodyComboBoxes(body);
2968
2969
QString title = body->ui.nameEdit->text().trimmed();
2970
QCheckBox *a;
2971
2972
if (title.isEmpty())
2973
a = new QCheckBox("Body{Boundary " + QString::number(i) + "}");
2974
else
2975
a = new QCheckBox(title);
2976
2977
DynamicEditor *p = NULL;
2978
2979
switch (which) {
2980
case BODY_MATERIAL:
2981
p = body->material;
2982
connect(a, SIGNAL(stateChanged(int)), this,
2983
SLOT(materialBodyChanged(int)));
2984
break;
2985
case BODY_INITIAL:
2986
p = body->initial;
2987
connect(a, SIGNAL(stateChanged(int)), this,
2988
SLOT(initialBodyChanged(int)));
2989
break;
2990
case BODY_FORCE:
2991
p = body->force;
2992
connect(a, SIGNAL(stateChanged(int)), this,
2993
SLOT(forceBodyChanged(int)));
2994
break;
2995
case BODY_EQUATION:
2996
p = body->equation;
2997
connect(a, SIGNAL(stateChanged(int)), this,
2998
SLOT(equationBodyChanged(int)));
2999
break;
3000
}
3001
3002
a->setProperty("body", (qulonglong)body);
3003
a->setProperty("editor", (qulonglong)pe);
3004
3005
if (p == pe)
3006
a->setChecked(true);
3007
else if (p != NULL)
3008
a->setEnabled(false);
3009
3010
slayout->addWidget(a, count, even);
3011
even = 1 - even;
3012
if (!even)
3013
count++;
3014
}
3015
}
3016
3017
QGroupBox *box = new QGroupBox;
3018
box->setLayout(slayout);
3019
3020
pe->spareScroll->setWidget(box);
3021
pe->spareScroll->setMinimumHeight(80);
3022
pe->spareScroll->show();
3023
}
3024
3025
//-----------------------------------------------------------------------------
3026
3027
//*****************************************************************************
3028
3029
// Model -> Equation -> Add...
3030
//-----------------------------------------------------------------------------
3031
void MainWindow::addEquationSlot() {
3032
DynamicEditor *pe = new DynamicEditor;
3033
equationEditor.append(pe);
3034
int current = equationEditor.size() - 1;
3035
3036
pe->setupTabs(elmerDefs, "Equation", current);
3037
3038
pe->applyButton->setText("Add");
3039
pe->applyButton->setIcon(QIcon::fromTheme("list-add"));
3040
pe->discardButton->setText("Cancel");
3041
pe->discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));
3042
pe->show();
3043
3044
connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,
3045
SLOT(pdeEditorFinishedSlot(int, int)));
3046
3047
// Use "spareButton" to invoke solver parameter editor:
3048
pe->spareButton->setText("Edit Solver Settings");
3049
pe->spareButton->show();
3050
pe->spareButton->setIcon(QIcon::fromTheme("preferences-system"));
3051
pe->spareButton->setWhatsThis(tr("Open solver setting window"));
3052
connect(pe, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,
3053
SLOT(editNumericalMethods(int, int)));
3054
3055
// Equation is new - add to menu:
3056
const QString &equationName = pe->nameEdit->text().trimmed();
3057
QAction *act = new QAction(equationName, this);
3058
equationMenu->addAction(act);
3059
pe->menuAction = act;
3060
3061
connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,
3062
SLOT(dynamicEditorNameChange(QString)));
3063
3064
createBodyCheckBoxes(BODY_EQUATION, pe);
3065
}
3066
3067
// signal (int, int) emitted by dynamic editor when "spare button" clicked:
3068
//-----------------------------------------------------------------------------
3069
void MainWindow::editNumericalMethods(int current, int id) {
3070
QString title = "";
3071
3072
for (int i = 0; i < equationEditor.size(); i++) {
3073
// ** 23/04/09 **
3074
if (equationEditor[i]->ID == id) {
3075
title = equationEditor[i]->tabWidget->tabText(current);
3076
break;
3077
}
3078
}
3079
3080
if (title == "General") {
3081
logMessage("No solver controls for 'General' equation options");
3082
return;
3083
}
3084
3085
if (current >= solverParameterEditor.size())
3086
solverParameterEditor.resize(current + 1);
3087
3088
if (!solverParameterEditor[current])
3089
solverParameterEditor[current] = new SolverParameterEditor;
3090
3091
SolverParameterEditor *spe = solverParameterEditor[current];
3092
3093
spe->setWindowTitle("Solver control for " + title);
3094
3095
spe->solverName = title;
3096
3097
if (spe->generalOptions == NULL) {
3098
spe->generalOptions = new DynamicEditor(spe);
3099
spe->generalOptions->setupTabs(elmerDefs, "Solver", current);
3100
spe->ui.solverControlTabs->insertTab(
3101
0, spe->generalOptions->tabWidget->widget(current),
3102
"Solver specific options");
3103
3104
#if 0
3105
for( int i=0; i < spe->generalOptions->tabWidget->count(); i++ )
3106
{
3107
if ( spe->generalOptions->tabWidget->tabText(i) == title )
3108
{
3109
spe->ui.solverControlTabs->insertTab(0, spe->generalOptions->tabWidget->widget(i),
3110
"Solver specific options");
3111
break;
3112
}
3113
}
3114
#endif
3115
}
3116
3117
spe->show();
3118
spe->raise();
3119
}
3120
3121
void MainWindow::dynamicEditorNameChange(QString t) {
3122
for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3123
if (!bodyPropertyEditor[i])
3124
continue;
3125
3126
if (bodyPropertyEditor[i]->touched)
3127
populateBodyComboBoxes(bodyPropertyEditor[i]);
3128
}
3129
3130
for (int i = 0; i < boundaryPropertyEditor.size(); i++) {
3131
if (!boundaryPropertyEditor[i])
3132
continue;
3133
3134
if (boundaryPropertyEditor[i]->touched)
3135
populateBoundaryComboBoxes(boundaryPropertyEditor[i]);
3136
}
3137
}
3138
3139
// signal (int,int) emitted by equation editor when ready:
3140
//-----------------------------------------------------------------------------
3141
void MainWindow::pdeEditorFinishedSlot(int signal, int id) {
3142
DynamicEditor *pe = equationEditor[id];
3143
3144
const QString &equationName = pe->nameEdit->text().trimmed();
3145
3146
bool signalOK = signal == MAT_OK || signal == MAT_APPLY;
3147
3148
if ((equationName.isEmpty()) && signalOK) {
3149
logMessage("Refusing to add/update equation without name");
3150
return;
3151
}
3152
3153
if (signalOK) {
3154
if (pe->menuAction != NULL) {
3155
pe->menuAction->setText(equationName);
3156
logMessage("Equation updated");
3157
if (signal == MAT_OK)
3158
pe->close();
3159
}
3160
} else if (signal == MAT_NEW) {
3161
addEquationSlot();
3162
3163
} else if (signal == MAT_DELETE) {
3164
3165
for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3166
BodyPropertyEditor *body = bodyPropertyEditor[i];
3167
3168
if (!body)
3169
continue;
3170
3171
if (body->equation == pe) {
3172
body->equation = NULL;
3173
body->ui.equationCombo->setCurrentIndex(0);
3174
body->touched = true;
3175
}
3176
}
3177
3178
// Equation is not in menu:
3179
if (pe->menuAction == NULL) {
3180
logMessage("Ready");
3181
pe->close();
3182
return;
3183
}
3184
3185
// Delete from menu:
3186
delete pe->menuAction;
3187
pe->menuAction = NULL;
3188
pe->close();
3189
3190
pe->ID = -100;
3191
pe->nameEdit->setText("");
3192
3193
logMessage("Equation deleted");
3194
}
3195
}
3196
3197
// signal (QAction*) emitted by equationMenu when an item has been selected:
3198
//-----------------------------------------------------------------------------
3199
void MainWindow::equationSelectedSlot(QAction *act) {
3200
// Edit the selected material:
3201
for (int i = 0; i < equationEditor.size(); i++) {
3202
DynamicEditor *pe = equationEditor[i];
3203
if (pe->menuAction == act) {
3204
pe->applyButton->setText("Update");
3205
pe->applyButton->setIcon(QIcon::fromTheme("view-refresh"));
3206
pe->discardButton->setText("Remove");
3207
pe->discardButton->setIcon(QIcon::fromTheme("list-remove"));
3208
createBodyCheckBoxes(BODY_EQUATION, pe);
3209
pe->show();
3210
pe->raise();
3211
}
3212
}
3213
}
3214
3215
//-----------------------------------------------------------------------------
3216
void MainWindow::equationBodyChanged(int state) {
3217
QWidget *a = (QWidget *)QObject::sender();
3218
if (glWidget->getMesh()) {
3219
BodyPropertyEditor *body =
3220
(BodyPropertyEditor *)a->property("body").toULongLong();
3221
populateBodyComboBoxes(body);
3222
if (state) {
3223
DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();
3224
QString mat_name = mat->nameEdit->text().trimmed();
3225
int ind = body->ui.equationCombo->findText(mat_name);
3226
body->touched = true;
3227
body->equation = mat;
3228
body->ui.equationCombo->setCurrentIndex(ind);
3229
} else {
3230
body->equation = NULL;
3231
body->ui.equationCombo->setCurrentIndex(-1);
3232
}
3233
}
3234
}
3235
3236
//*****************************************************************************
3237
3238
// Model -> Material -> Add...
3239
//-----------------------------------------------------------------------------
3240
void MainWindow::addMaterialSlot() {
3241
DynamicEditor *pe = new DynamicEditor;
3242
materialEditor.append(pe);
3243
int current = materialEditor.size() - 1;
3244
3245
pe->setupTabs(elmerDefs, "Material", current);
3246
pe->applyButton->setText("Add");
3247
pe->applyButton->setIcon(QIcon::fromTheme("list-add"));
3248
pe->discardButton->setText("Cancel");
3249
pe->discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));
3250
3251
connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,
3252
SLOT(matEditorFinishedSlot(int, int)));
3253
3254
// Use "spareButton" to invoke material library:
3255
pe->spareButton->setText("Material library");
3256
pe->spareButton->show();
3257
pe->spareButton->setIcon(QIcon::fromTheme("book-cover-A-Z"));
3258
pe->spareButton->setWhatsThis(tr("Open material library"));
3259
connect(pe, SIGNAL(dynamicEditorSpareButtonClicked(int, int)), this,
3260
SLOT(showMaterialLibrary(int, int)));
3261
3262
connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,
3263
SLOT(dynamicEditorNameChange(QString)));
3264
3265
// Material is new - add to menu:
3266
const QString &materialName = pe->nameEdit->text().trimmed();
3267
QAction *act = new QAction(materialName, this);
3268
materialMenu->addAction(act);
3269
pe->menuAction = act;
3270
3271
createBodyCheckBoxes(BODY_MATERIAL, pe);
3272
pe->show();
3273
pe->raise();
3274
}
3275
3276
void MainWindow::showMaterialLibrary(int tab, int ID) {
3277
materialLibrary->editor = materialEditor[ID];
3278
materialLibrary->elmerDefs = this->elmerDefs;
3279
materialLibrary->show();
3280
}
3281
3282
// signal (int,int) emitted by material editor when ready:
3283
//-----------------------------------------------------------------------------
3284
void MainWindow::matEditorFinishedSlot(int signal, int id) {
3285
DynamicEditor *pe = materialEditor[id];
3286
3287
const QString &materialName = pe->nameEdit->text().trimmed();
3288
3289
bool signalOK = signal == MAT_OK || signal == MAT_APPLY;
3290
if (materialName.isEmpty() && signalOK) {
3291
logMessage("Refusing to add/update material with no name");
3292
return;
3293
}
3294
3295
if (signalOK) {
3296
if (pe->menuAction != NULL) {
3297
pe->menuAction->setText(materialName);
3298
logMessage("Material updated");
3299
if (signal == MAT_OK)
3300
pe->close();
3301
return;
3302
}
3303
} else if (signal == MAT_NEW) {
3304
3305
addMaterialSlot();
3306
3307
} else if (signal == MAT_DELETE) {
3308
3309
for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3310
BodyPropertyEditor *body = bodyPropertyEditor[i];
3311
3312
if (!body)
3313
continue;
3314
3315
if (body->material == pe) {
3316
body->material = NULL;
3317
body->ui.materialCombo->setCurrentIndex(0);
3318
body->touched = true;
3319
}
3320
}
3321
3322
// Material is not in menu:
3323
if (pe->menuAction == NULL) {
3324
logMessage("Ready");
3325
pe->close();
3326
return;
3327
}
3328
3329
// Delete from menu:
3330
delete pe->menuAction;
3331
pe->menuAction = NULL;
3332
pe->close();
3333
3334
pe->ID = -100;
3335
pe->nameEdit->setText("");
3336
3337
logMessage("Material deleted");
3338
3339
} else {
3340
cout << "Matedit: unknown signal" << endl;
3341
}
3342
}
3343
3344
// signal (QAction*) emitted by materialMenu when an item has been selected:
3345
//-----------------------------------------------------------------------------
3346
void MainWindow::materialSelectedSlot(QAction *act) {
3347
// Edit the selected material:
3348
for (int i = 0; i < materialEditor.size(); i++) {
3349
DynamicEditor *pe = materialEditor[i];
3350
3351
if (pe->menuAction == act) {
3352
pe->applyButton->setText("Update");
3353
pe->applyButton->setIcon(QIcon::fromTheme("view-refresh"));
3354
pe->discardButton->setText("Remove");
3355
pe->discardButton->setIcon(QIcon::fromTheme("list-remove"));
3356
createBodyCheckBoxes(BODY_MATERIAL, pe);
3357
pe->show();
3358
pe->raise();
3359
}
3360
}
3361
}
3362
3363
void MainWindow::materialBodyChanged(int state) {
3364
QWidget *a = (QWidget *)QObject::sender();
3365
if (glWidget->hasMesh()) {
3366
BodyPropertyEditor *body =
3367
(BodyPropertyEditor *)a->property("body").toULongLong();
3368
populateBodyComboBoxes(body);
3369
3370
if (state > 0) {
3371
DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();
3372
QString mat_name = mat->nameEdit->text().trimmed();
3373
int ind = body->ui.materialCombo->findText(mat_name);
3374
3375
body->touched = true;
3376
body->material = mat;
3377
body->ui.materialCombo->setCurrentIndex(ind);
3378
} else {
3379
body->material = NULL;
3380
body->ui.materialCombo->setCurrentIndex(-1);
3381
}
3382
}
3383
}
3384
3385
//*****************************************************************************
3386
3387
// Model -> Body force -> Add...
3388
//-----------------------------------------------------------------------------
3389
void MainWindow::addBodyForceSlot() {
3390
DynamicEditor *pe = new DynamicEditor;
3391
bodyForceEditor.append(pe);
3392
int current = bodyForceEditor.size() - 1;
3393
3394
pe->setupTabs(elmerDefs, "BodyForce", current);
3395
3396
pe->applyButton->setText("Add");
3397
pe->applyButton->setIcon(QIcon::fromTheme("list-add"));
3398
pe->discardButton->setText("Cancel");
3399
pe->discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));
3400
3401
connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,
3402
SLOT(bodyForceEditorFinishedSlot(int, int)));
3403
3404
// Body force is new - add to menu:
3405
const QString &bodyForceName = pe->nameEdit->text().trimmed();
3406
QAction *act = new QAction(bodyForceName, this);
3407
bodyForceMenu->addAction(act);
3408
pe->menuAction = act;
3409
3410
connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,
3411
SLOT(dynamicEditorNameChange(QString)));
3412
3413
createBodyCheckBoxes(BODY_FORCE, pe);
3414
pe->show();
3415
pe->raise();
3416
}
3417
3418
// signal (int,int) emitted by body force editor when ready:
3419
//-----------------------------------------------------------------------------
3420
void MainWindow::bodyForceEditorFinishedSlot(int signal, int id) {
3421
DynamicEditor *pe = bodyForceEditor[id];
3422
3423
const QString &bodyForceName = pe->nameEdit->text().trimmed();
3424
3425
bool signalOK = signal == MAT_OK || signal == MAT_APPLY;
3426
3427
if ((bodyForceName.isEmpty()) && signalOK) {
3428
logMessage("Refusing to add/update body force with no name");
3429
return;
3430
}
3431
3432
if (signalOK) {
3433
if (pe->menuAction != NULL) {
3434
pe->menuAction->setText(bodyForceName);
3435
logMessage("Body force updated");
3436
if (signal == MAT_OK)
3437
pe->close();
3438
}
3439
3440
} else if (signal == MAT_NEW) {
3441
addBodyForceSlot();
3442
3443
} else if (signal == MAT_DELETE) {
3444
for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3445
BodyPropertyEditor *body = bodyPropertyEditor[i];
3446
3447
if (!body)
3448
continue;
3449
3450
if (body->force == pe) {
3451
body->force = NULL;
3452
body->ui.bodyForceCombo->setCurrentIndex(0);
3453
body->touched = true;
3454
}
3455
}
3456
3457
if (pe->menuAction == NULL) {
3458
logMessage("Ready");
3459
pe->close();
3460
return;
3461
}
3462
3463
// Delete from menu:
3464
delete pe->menuAction;
3465
pe->menuAction = NULL;
3466
pe->close();
3467
3468
pe->ID = -100;
3469
pe->nameEdit->setText("");
3470
3471
logMessage("Body force deleted");
3472
}
3473
}
3474
3475
// signal (QAction*) emitted by bodyForceMenu when an item has been selected:
3476
//-----------------------------------------------------------------------------
3477
void MainWindow::bodyForceSelectedSlot(QAction *act) {
3478
// Edit the selected body force:
3479
for (int i = 0; i < bodyForceEditor.size(); i++) {
3480
DynamicEditor *pe = bodyForceEditor[i];
3481
if (pe->menuAction == act) {
3482
pe->applyButton->setText("Update");
3483
pe->applyButton->setIcon(QIcon::fromTheme("view-refresh"));
3484
pe->discardButton->setText("Remove");
3485
pe->discardButton->setIcon(QIcon::fromTheme("list-remove"));
3486
createBodyCheckBoxes(BODY_FORCE, pe);
3487
pe->show();
3488
pe->raise();
3489
}
3490
}
3491
}
3492
3493
//-----------------------------------------------------------------------------
3494
void MainWindow::forceBodyChanged(int state) {
3495
QWidget *a = (QWidget *)QObject::sender();
3496
if (glWidget->hasMesh()) {
3497
BodyPropertyEditor *body =
3498
(BodyPropertyEditor *)a->property("body").toULongLong();
3499
populateBodyComboBoxes(body);
3500
3501
if (state) {
3502
DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();
3503
QString mat_name = mat->nameEdit->text().trimmed();
3504
int ind = body->ui.bodyForceCombo->findText(mat_name);
3505
3506
body->touched = true;
3507
body->force = mat;
3508
body->ui.bodyForceCombo->setCurrentIndex(ind);
3509
} else {
3510
body->force = NULL;
3511
body->ui.bodyForceCombo->setCurrentIndex(-1);
3512
}
3513
}
3514
}
3515
3516
//*****************************************************************************
3517
3518
// Model -> Initial condition -> Add...
3519
//-----------------------------------------------------------------------------
3520
void MainWindow::addInitialConditionSlot() {
3521
DynamicEditor *pe = new DynamicEditor;
3522
initialConditionEditor.append(pe);
3523
int current = initialConditionEditor.size() - 1;
3524
3525
pe->setupTabs(elmerDefs, "InitialCondition", current);
3526
3527
pe->applyButton->setText("Add");
3528
pe->applyButton->setIcon(QIcon::fromTheme("list-add"));
3529
pe->discardButton->setText("Cancel");
3530
pe->discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));
3531
3532
connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,
3533
SLOT(initialConditionEditorFinishedSlot(int, int)));
3534
3535
// Initial condition is new - add to menu:
3536
const QString &initialConditionName = pe->nameEdit->text().trimmed();
3537
QAction *act = new QAction(initialConditionName, this);
3538
initialConditionMenu->addAction(act);
3539
pe->menuAction = act;
3540
3541
connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,
3542
SLOT(dynamicEditorNameChange(QString)));
3543
3544
createBodyCheckBoxes(BODY_INITIAL, pe);
3545
pe->show();
3546
pe->raise();
3547
}
3548
3549
// signal (int,int) emitted by initial condition editor when ready:
3550
//-----------------------------------------------------------------------------
3551
void MainWindow::initialConditionEditorFinishedSlot(int signal, int id) {
3552
DynamicEditor *pe = initialConditionEditor[id];
3553
3554
const QString &initialConditionName = pe->nameEdit->text().trimmed();
3555
3556
bool signalOK = signal == MAT_OK || signal == MAT_APPLY;
3557
if ((initialConditionName.isEmpty()) && signalOK) {
3558
logMessage("Refusing to add/update initial condition with no name");
3559
return;
3560
}
3561
3562
if (signalOK) {
3563
if (pe->menuAction != NULL) {
3564
pe->menuAction->setText(initialConditionName);
3565
logMessage("Initial condition updated");
3566
if (signal == MAT_OK)
3567
pe->close();
3568
}
3569
} else if (signal == MAT_NEW) {
3570
addInitialConditionSlot();
3571
3572
} else if (signal == MAT_DELETE) {
3573
3574
for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3575
BodyPropertyEditor *body = bodyPropertyEditor[i];
3576
3577
if (!body)
3578
continue;
3579
3580
if (body->initial == pe) {
3581
body->initial = NULL;
3582
body->ui.initialConditionCombo->setCurrentIndex(0);
3583
body->touched = true;
3584
}
3585
}
3586
3587
// Initial condition is not in menu:
3588
if (pe->menuAction == NULL) {
3589
logMessage("Ready");
3590
pe->close();
3591
return;
3592
}
3593
3594
// Delete from menu:
3595
delete pe->menuAction;
3596
pe->menuAction = NULL;
3597
pe->close();
3598
3599
pe->ID = -100;
3600
pe->nameEdit->setText("");
3601
3602
logMessage("Initial condition deleted");
3603
}
3604
}
3605
3606
// signal (QAction*) emitted by initialConditionMenu when item selected:
3607
//-----------------------------------------------------------------------------
3608
void MainWindow::initialConditionSelectedSlot(QAction *act) {
3609
// Edit the selected initial condition:
3610
for (int i = 0; i < initialConditionEditor.size(); i++) {
3611
DynamicEditor *pe = initialConditionEditor[i];
3612
if (pe->menuAction == act) {
3613
pe->applyButton->setText("Update");
3614
pe->applyButton->setIcon(QIcon::fromTheme("view-refresh"));
3615
pe->discardButton->setText("Remove");
3616
pe->discardButton->setIcon(QIcon::fromTheme("list-remove"));
3617
createBodyCheckBoxes(BODY_INITIAL, pe);
3618
pe->show();
3619
pe->raise();
3620
}
3621
}
3622
}
3623
3624
//-----------------------------------------------------------------------------
3625
void MainWindow::initialBodyChanged(int state) {
3626
QWidget *a = (QWidget *)QObject::sender();
3627
if (glWidget->hasMesh()) {
3628
BodyPropertyEditor *body =
3629
(BodyPropertyEditor *)a->property("body").toULongLong();
3630
populateBodyComboBoxes(body);
3631
3632
if (state) {
3633
DynamicEditor *mat = (DynamicEditor *)a->property("editor").toULongLong();
3634
QString mat_name = mat->nameEdit->text().trimmed();
3635
int ind = body->ui.initialConditionCombo->findText(mat_name);
3636
body->touched = true;
3637
body->initial = mat;
3638
body->ui.initialConditionCombo->setCurrentIndex(ind);
3639
} else {
3640
body->initial = NULL;
3641
body->ui.initialConditionCombo->setCurrentIndex(-1);
3642
}
3643
}
3644
}
3645
3646
//*****************************************************************************
3647
//-----------------------------------------------------------------------------
3648
void MainWindow::createBoundaryCheckBoxes(DynamicEditor *pe) {
3649
if (!glWidget->hasMesh())
3650
return;
3651
3652
if (pe->spareScroll->widget()) {
3653
delete pe->spareScroll->widget();
3654
}
3655
3656
QGridLayout *slayout = new QGridLayout;
3657
QLabel *l = new QLabel(tr("Apply to boundaries:"));
3658
int count = 0, even = 0;
3659
3660
slayout->addWidget(l, count, 0);
3661
count++;
3662
3663
QMapIterator<int, int> itr(glWidget->boundaryMap);
3664
while (itr.hasNext()) {
3665
itr.next();
3666
int n = itr.key();
3667
if (n >= 0) {
3668
int m = itr.value();
3669
3670
if (m >= boundaryPropertyEditor.size())
3671
boundaryPropertyEditor.resize(m + 1);
3672
3673
if (!boundaryPropertyEditor[m])
3674
boundaryPropertyEditor[m] = new BoundaryPropertyEditor;
3675
3676
BoundaryPropertyEditor *boundary = boundaryPropertyEditor[m];
3677
3678
populateBoundaryComboBoxes(boundary);
3679
3680
// TODO: check this
3681
QString title = ""; // boundary->ui.nameEdit->text().trimmed();
3682
QCheckBox *a;
3683
3684
if (title.isEmpty())
3685
a = new QCheckBox("Boundary " + QString::number(n));
3686
else
3687
a = new QCheckBox(title);
3688
3689
if (glWidget->stateBcColors) {
3690
int c[3];
3691
QPixmap pm(16, 16);
3692
3693
GLWidget::indexColors(c, n);
3694
pm.fill(qRgb(c[0], c[1], c[2]));
3695
a->setIcon(QIcon(pm));
3696
}
3697
3698
DynamicEditor *p = NULL;
3699
3700
p = boundary->condition;
3701
connect(a, SIGNAL(stateChanged(int)), this, SLOT(bcBoundaryChanged(int)));
3702
3703
a->setProperty("boundary", (qulonglong)boundary);
3704
a->setProperty("condition", (qulonglong)pe);
3705
3706
if (p == pe)
3707
a->setChecked(true);
3708
else if (p != NULL)
3709
a->setEnabled(false);
3710
3711
slayout->addWidget(a, count, even);
3712
even = 1 - even;
3713
if (!even)
3714
count++;
3715
}
3716
}
3717
3718
QGroupBox *box = new QGroupBox;
3719
box->setLayout(slayout);
3720
3721
pe->spareScroll->setWidget(box);
3722
pe->spareScroll->setMinimumHeight(80);
3723
pe->spareScroll->show();
3724
}
3725
3726
//-----------------------------------------------------------------------------
3727
3728
// Model -> Boundary condition -> Add...
3729
//-----------------------------------------------------------------------------
3730
void MainWindow::addBoundaryConditionSlot() {
3731
DynamicEditor *pe = new DynamicEditor;
3732
boundaryConditionEditor.append(pe);
3733
int current = boundaryConditionEditor.size() - 1;
3734
3735
pe->setupTabs(elmerDefs, "BoundaryCondition", current);
3736
3737
pe->applyButton->setText("Add");
3738
pe->applyButton->setIcon(QIcon::fromTheme("list-add"));
3739
pe->discardButton->setText("Cancel");
3740
pe->discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));
3741
pe->show();
3742
3743
connect(pe, SIGNAL(dynamicEditorReady(int, int)), this,
3744
SLOT(boundaryConditionEditorFinishedSlot(int, int)));
3745
3746
// Boundary condition is new - add to menu:
3747
const QString &boundaryConditionName = pe->nameEdit->text().trimmed();
3748
QAction *act = new QAction(boundaryConditionName, this);
3749
boundaryConditionMenu->addAction(act);
3750
pe->menuAction = act;
3751
3752
connect(pe->nameEdit, SIGNAL(textChanged(QString)), this,
3753
SLOT(dynamicEditorNameChange(QString)));
3754
3755
createBoundaryCheckBoxes(pe);
3756
}
3757
3758
// signal (int,int) emitted by boundary condition editor when ready:
3759
//-----------------------------------------------------------------------------
3760
void MainWindow::boundaryConditionEditorFinishedSlot(int signal, int id) {
3761
DynamicEditor *pe = boundaryConditionEditor[id];
3762
3763
const QString &boundaryConditionName = pe->nameEdit->text().trimmed();
3764
3765
bool signalOK = signal == MAT_OK || signal == MAT_APPLY;
3766
3767
if ((boundaryConditionName.isEmpty()) && signalOK) {
3768
logMessage("Refusing to add/update boundary condition with no name");
3769
return;
3770
}
3771
3772
if (signalOK) {
3773
if (pe->menuAction != NULL) {
3774
pe->menuAction->setText(boundaryConditionName);
3775
logMessage("Boundary condition updated");
3776
if (signal == MAT_OK)
3777
pe->close();
3778
}
3779
} else if (signal == MAT_NEW) {
3780
addBoundaryConditionSlot();
3781
3782
} else if (signal == MAT_DELETE) {
3783
3784
pe->nameEdit->setText(QString());
3785
3786
for (int i = 0; i < boundaryPropertyEditor.size(); i++) {
3787
BoundaryPropertyEditor *bndry = boundaryPropertyEditor[i];
3788
3789
if (!bndry)
3790
continue;
3791
3792
if (bndry->condition == pe) {
3793
bndry->condition = NULL;
3794
bndry->ui.boundaryConditionCombo->setCurrentIndex(0);
3795
bndry->touched = true;
3796
}
3797
}
3798
3799
// Boundary condition is not in menu:
3800
if (pe->menuAction == NULL) {
3801
logMessage("Ready");
3802
pe->close();
3803
return;
3804
}
3805
3806
// Delete from menu:
3807
delete pe->menuAction;
3808
pe->menuAction = NULL;
3809
pe->close();
3810
3811
pe->ID = -100;
3812
pe->nameEdit->setText("");
3813
3814
logMessage("Boundary condition deleted");
3815
}
3816
}
3817
3818
// signal (QAction*) emitted by boundaryConditionMenu when item selected:
3819
//-----------------------------------------------------------------------------
3820
void MainWindow::boundaryConditionSelectedSlot(QAction *act) {
3821
// Edit the selected boundary condition:
3822
for (int i = 0; i < boundaryConditionEditor.size(); i++) {
3823
DynamicEditor *pe = boundaryConditionEditor[i];
3824
if (pe->menuAction == act) {
3825
pe->applyButton->setText("Update");
3826
pe->applyButton->setIcon(QIcon::fromTheme("view-refresh"));
3827
pe->discardButton->setText("Remove");
3828
pe->discardButton->setIcon(QIcon::fromTheme("list-remove"));
3829
createBoundaryCheckBoxes(pe);
3830
pe->show();
3831
pe->raise();
3832
}
3833
}
3834
}
3835
3836
//-----------------------------------------------------------------------------
3837
void MainWindow::bcBoundaryChanged(int state) {
3838
QWidget *a = (QWidget *)QObject::sender();
3839
if (glWidget->hasMesh()) {
3840
BoundaryPropertyEditor *boundary =
3841
(BoundaryPropertyEditor *)a->property("boundary").toULongLong();
3842
populateBoundaryComboBoxes(boundary);
3843
3844
if (state) {
3845
DynamicEditor *mat =
3846
(DynamicEditor *)a->property("condition").toULongLong();
3847
QString mat_name = mat->nameEdit->text().trimmed();
3848
int ind = boundary->ui.boundaryConditionCombo->findText(mat_name);
3849
boundary->touched = true;
3850
boundary->condition = mat;
3851
boundary->ui.boundaryConditionCombo->setCurrentIndex(ind);
3852
} else {
3853
boundary->condition = NULL;
3854
boundary->ui.boundaryConditionCombo->setCurrentIndex(-1);
3855
}
3856
}
3857
}
3858
3859
// Model -> Set body properties
3860
//-----------------------------------------------------------------------------
3861
void MainWindow::bodyEditSlot() {
3862
if (!glWidget->hasMesh()) {
3863
logMessage("Unable to open body editor - no mesh");
3864
bodyEditActive = false;
3865
synchronizeMenuToState();
3866
return;
3867
}
3868
3869
bodyEditActive = !bodyEditActive;
3870
glWidget->bodyEditActive = bodyEditActive;
3871
3872
if (bodyEditActive)
3873
bcEditActive = false;
3874
3875
synchronizeMenuToState();
3876
3877
if (bodyEditActive)
3878
logMessage("Double click a boundary to edit body properties");
3879
}
3880
3881
// Model -> Set boundary conditions
3882
//-----------------------------------------------------------------------------
3883
void MainWindow::bcEditSlot() {
3884
if (!glWidget->hasMesh()) {
3885
logMessage("Unable to open BC editor - no mesh");
3886
bcEditActive = false;
3887
synchronizeMenuToState();
3888
return;
3889
}
3890
3891
bcEditActive = !bcEditActive;
3892
3893
if (bcEditActive)
3894
bodyEditActive = false;
3895
3896
synchronizeMenuToState();
3897
3898
if (bcEditActive)
3899
logMessage("Double click a boundary to edit BCs");
3900
}
3901
3902
// Model -> Summary...
3903
//-----------------------------------------------------------------------------
3904
void MainWindow::modelSummarySlot() {
3905
mesh_t *mesh = glWidget->getMesh();
3906
QTextEdit *te = summaryEditor->ui.summaryEdit;
3907
te->clear();
3908
summaryEditor->show();
3909
3910
if (mesh == NULL) {
3911
te->append("No mesh");
3912
return;
3913
}
3914
3915
te->append("FINITE ELEMENT MESH");
3916
te->append("Mesh dimension: " + QString::number(mesh->getCdim()));
3917
te->append("Leading element dimension: " + QString::number(mesh->getDim()));
3918
te->append("Nodes: " + QString::number(mesh->getNodes()));
3919
te->append("Volume elements: " + QString::number(mesh->getElements()));
3920
te->append("Surface elements: " + QString::number(mesh->getSurfaces()));
3921
te->append("Edge elements: " + QString::number(mesh->getEdges()));
3922
te->append("Point elements: " + QString::number(mesh->getPoints()));
3923
te->append("");
3924
3925
// This is almost duplicate info with the above, they might be fused in some
3926
// way...
3927
te->append("ELEMENT TYPES");
3928
int *elementtypes = new int[828];
3929
for (int i = 0; i <= 827; i++)
3930
elementtypes[i] = 0;
3931
for (int i = 0; i < mesh->getElements(); i++)
3932
elementtypes[mesh->getElement(i)->getCode()] += 1;
3933
for (int i = 0; i < mesh->getSurfaces(); i++)
3934
elementtypes[mesh->getSurface(i)->getCode()] += 1;
3935
for (int i = 0; i < mesh->getEdges(); i++)
3936
elementtypes[mesh->getEdge(i)->getCode()] += 1;
3937
for (int i = 0; i < mesh->getPoints(); i++)
3938
elementtypes[mesh->getPoint(i)->getCode()] += 1;
3939
for (int i = 827; i > 0; i--)
3940
if (elementtypes[i])
3941
te->append(QString::number(i) + ": " + QString::number(elementtypes[i]));
3942
te->append("");
3943
delete[] elementtypes;
3944
3945
te->append("BOUNDING BOX");
3946
QString coordnames[3] = {"X","Y","Z"};
3947
for (int j = 0; j < 3; j++) {
3948
double mincoord, maxcoord, coord;
3949
mincoord = maxcoord = mesh->getNode(0)->getX(j);
3950
for (int i = 0; i < mesh->getNodes(); i++) {
3951
coord = mesh->getNode(i)->getX(j);
3952
if (mincoord > coord)
3953
mincoord = coord;
3954
if (maxcoord < coord)
3955
maxcoord = coord;
3956
}
3957
te->append(coordnames[j] + "-coordinate: [ " + QString::number(mincoord) +
3958
" , " + QString::number(maxcoord) + " ]");
3959
}
3960
te->append("");
3961
3962
// Check equations:
3963
int count = 0;
3964
for (int i = 0; i < equationEditor.size(); i++) {
3965
if (equationEditor[i]->menuAction != NULL)
3966
count++;
3967
}
3968
te->append("GENERAL");
3969
te->append("Equations: " + QString::number(count));
3970
3971
// Check materials:
3972
count = 0;
3973
for (int i = 0; i < materialEditor.size(); i++) {
3974
if (materialEditor[i]->menuAction != NULL)
3975
count++;
3976
}
3977
te->append("Materials: " + QString::number(count));
3978
3979
// Check boundary conditions:
3980
count = 0;
3981
for (int i = 0; i < boundaryConditionEditor.size(); i++) {
3982
if (boundaryConditionEditor[i]->touched)
3983
count++;
3984
}
3985
te->append("Boundary conditions: " + QString::number(count));
3986
3987
// Check body properties:
3988
count = 0;
3989
for (int i = 0; i < bodyPropertyEditor.size(); i++) {
3990
3991
if (!bodyPropertyEditor[i])
3992
continue;
3993
3994
if (bodyPropertyEditor[i]->touched)
3995
count++;
3996
}
3997
3998
te->append("Body properties: " + QString::number(count));
3999
te->append("");
4000
4001
// Count volume bodies:
4002
//---------------------
4003
int undetermined = 0;
4004
int *tmp = new int[mesh->getElements()];
4005
for (int i = 0; i < mesh->getElements(); i++)
4006
tmp[i] = 0;
4007
4008
for (int i = 0; i < mesh->getElements(); i++) {
4009
element_t *e = mesh->getElement(i);
4010
if (e->getNature() == PDE_BULK) {
4011
if (e->getIndex() >= 0)
4012
tmp[e->getIndex()]++;
4013
else
4014
undetermined++;
4015
}
4016
}
4017
4018
te->append("VOLUME BODIES");
4019
count = 0;
4020
for (int i = 0; i < mesh->getElements(); i++) {
4021
if (tmp[i] > 0) {
4022
count++;
4023
QString qs = "Body " + QString::number(i) + ": " +
4024
QString::number(tmp[i]) + " volume elements";
4025
4026
element_t *e = mesh->getElement(i);
4027
int j = e->getIndex();
4028
4029
if ((j >= 0) && (j < bodyPropertyEditor.size()))
4030
if (bodyPropertyEditor[j] && bodyPropertyEditor[j]->touched)
4031
qs.append(" (Body property set)");
4032
4033
te->append(qs);
4034
}
4035
}
4036
te->append("Undetermined: " + QString::number(undetermined));
4037
te->append("Total: " + QString::number(count) + " volume bodies");
4038
te->append("");
4039
4040
delete[] tmp;
4041
4042
// Count surface bodies:
4043
//---------------------
4044
undetermined = 0;
4045
tmp = new int[mesh->getSurfaces()];
4046
for (int i = 0; i < mesh->getSurfaces(); i++)
4047
tmp[i] = 0;
4048
4049
for (int i = 0; i < mesh->getSurfaces(); i++) {
4050
surface_t *s = mesh->getSurface(i);
4051
if (s->getNature() == PDE_BULK) {
4052
if (s->getIndex() >= 0)
4053
tmp[s->getIndex()]++;
4054
else
4055
undetermined++;
4056
}
4057
}
4058
4059
te->append("SURFACE BODIES");
4060
count = 0;
4061
for (int i = 0; i < mesh->getSurfaces(); i++) {
4062
if (tmp[i] > 0) {
4063
count++;
4064
QString qs = "Body " + QString::number(i) + ": " +
4065
QString::number(tmp[i]) + " surface elements";
4066
4067
surface_t *s = mesh->getSurface(i);
4068
int j = s->getIndex();
4069
4070
if ((j >= 0) && (j < bodyPropertyEditor.size()))
4071
if (bodyPropertyEditor[j] && bodyPropertyEditor[j]->touched)
4072
qs.append(" (Body property set)");
4073
4074
te->append(qs);
4075
}
4076
}
4077
te->append("Undetermined: " + QString::number(undetermined));
4078
te->append("Total: " + QString::number(count) + " surface bodies");
4079
te->append("");
4080
4081
delete[] tmp;
4082
4083
// Count edge bodies:
4084
//---------------------
4085
undetermined = 0;
4086
tmp = new int[mesh->getEdges()];
4087
for (int i = 0; i < mesh->getEdges(); i++)
4088
tmp[i] = 0;
4089
4090
for (int i = 0; i < mesh->getEdges(); i++) {
4091
edge_t *e = mesh->getEdge(i);
4092
if (e->getNature() == PDE_BULK) {
4093
if (e->getIndex() >= 0)
4094
tmp[e->getIndex()]++;
4095
else
4096
undetermined++;
4097
}
4098
}
4099
4100
te->append("EDGE BODIES");
4101
count = 0;
4102
for (int i = 0; i < mesh->getEdges(); i++) {
4103
if (tmp[i] > 0) {
4104
count++;
4105
QString qs = "Body " + QString::number(i) + ": " +
4106
QString::number(tmp[i]) + " edge elements";
4107
4108
edge_t *e = mesh->getEdge(i);
4109
int j = e->getIndex();
4110
4111
if ((j >= 0) && (j < bodyPropertyEditor.size()))
4112
if (bodyPropertyEditor[j] && bodyPropertyEditor[j]->touched)
4113
qs.append(" (Body property set)");
4114
4115
te->append(qs);
4116
}
4117
}
4118
te->append("Undetermined: " + QString::number(undetermined));
4119
te->append("Total: " + QString::number(count) + " edge bodies");
4120
te->append("");
4121
4122
delete[] tmp;
4123
4124
// Count surface boundaries:
4125
//--------------------------
4126
undetermined = 0;
4127
tmp = new int[mesh->getSurfaces()];
4128
for (int i = 0; i < mesh->getSurfaces(); i++)
4129
tmp[i] = 0;
4130
4131
for (int i = 0; i < mesh->getSurfaces(); i++) {
4132
surface_t *s = mesh->getSurface(i);
4133
if (s->getNature() == PDE_BOUNDARY) {
4134
if (s->getIndex() >= 0)
4135
tmp[s->getIndex()]++;
4136
else
4137
undetermined++;
4138
}
4139
}
4140
4141
te->append("SURFACE BOUNDARIES");
4142
count = 0;
4143
for (int i = 0; i < mesh->getSurfaces(); i++) {
4144
if (tmp[i] > 0) {
4145
count++;
4146
QString qs = "Boundary " + QString::number(i) + ": " +
4147
QString::number(tmp[i]) + " surface elements";
4148
4149
surface_t *s = mesh->getSurface(i);
4150
int j = s->getIndex();
4151
if ((j >= 0) && (j < boundaryConditionEditor.size()))
4152
if (boundaryConditionEditor[j]->touched)
4153
qs.append(" (BC set)");
4154
4155
te->append(qs);
4156
}
4157
}
4158
te->append("Undetermined: " + QString::number(undetermined));
4159
te->append("Total: " + QString::number(count) + " surface boundaries");
4160
te->append("");
4161
4162
delete[] tmp;
4163
4164
// Count edge boundaries:
4165
//--------------------------
4166
undetermined = 0;
4167
tmp = new int[mesh->getEdges()];
4168
for (int i = 0; i < mesh->getEdges(); i++)
4169
tmp[i] = 0;
4170
4171
for (int i = 0; i < mesh->getEdges(); i++) {
4172
edge_t *e = mesh->getEdge(i);
4173
if (e->getNature() == PDE_BOUNDARY) {
4174
if (e->getIndex() >= 0)
4175
tmp[e->getIndex()]++;
4176
else
4177
undetermined++;
4178
}
4179
}
4180
4181
te->append("EDGE BOUNDARIES");
4182
count = 0;
4183
for (int i = 0; i < mesh->getEdges(); i++) {
4184
if (tmp[i] > 0) {
4185
count++;
4186
QString qs = "Boundary " + QString::number(i) + ": " +
4187
QString::number(tmp[i]) + " edge elements";
4188
4189
edge_t *e = mesh->getEdge(i);
4190
int j = e->getIndex();
4191
if ((j >= 0) && (j < boundaryConditionEditor.size()))
4192
if (boundaryConditionEditor[j]->touched)
4193
qs.append(" (BC set)");
4194
4195
te->append(qs);
4196
}
4197
}
4198
te->append("Undetermined: " + QString::number(undetermined));
4199
te->append("Total: " + QString::number(count) + " edge boundaries");
4200
te->append("");
4201
4202
delete[] tmp;
4203
}
4204
4205
// Model -> Clear
4206
//-----------------------------------------------------------------------------
4207
void MainWindow::modelClearSlot() {
4208
// clear equations:
4209
for (int i = 0; i < equationEditor.size(); i++) {
4210
DynamicEditor *pe = equationEditor[i];
4211
if (pe->menuAction != NULL)
4212
delete pe->menuAction;
4213
}
4214
4215
for (int i = 0; i < equationEditor.size(); i++)
4216
delete equationEditor[i];
4217
4218
equationEditor.clear();
4219
4220
// clear materials:
4221
for (int i = 0; i < materialEditor.size(); i++) {
4222
DynamicEditor *de = materialEditor[i];
4223
if (de->menuAction != NULL)
4224
delete de->menuAction;
4225
}
4226
4227
for (int i = 0; i < materialEditor.size(); i++)
4228
delete materialEditor[i];
4229
4230
materialEditor.clear();
4231
4232
// clear body forces:
4233
for (int i = 0; i < bodyForceEditor.size(); i++) {
4234
DynamicEditor *de = bodyForceEditor[i];
4235
if (de->menuAction != NULL)
4236
delete de->menuAction;
4237
}
4238
4239
for (int i = 0; i < bodyForceEditor.size(); i++)
4240
delete bodyForceEditor[i];
4241
4242
bodyForceEditor.clear();
4243
4244
// clear initial conditions:
4245
for (int i = 0; i < initialConditionEditor.size(); i++) {
4246
DynamicEditor *de = initialConditionEditor[i];
4247
if (de->menuAction != NULL)
4248
delete de->menuAction;
4249
}
4250
4251
for (int i = 0; i < initialConditionEditor.size(); i++)
4252
delete initialConditionEditor[i];
4253
4254
initialConditionEditor.clear();
4255
4256
// clear boundary conditions:
4257
for (int i = 0; i < boundaryConditionEditor.size(); i++) {
4258
DynamicEditor *de = boundaryConditionEditor[i];
4259
if (de->menuAction != NULL)
4260
delete de->menuAction;
4261
}
4262
4263
for (int i = 0; i < boundaryConditionEditor.size(); i++)
4264
if (boundaryConditionEditor[i])
4265
delete boundaryConditionEditor[i];
4266
4267
boundaryConditionEditor.clear();
4268
4269
// clear boundary setting:
4270
for (int i = 0; i < boundaryPropertyEditor.size(); i++)
4271
if (boundaryPropertyEditor[i])
4272
delete boundaryPropertyEditor[i];
4273
4274
boundaryPropertyEditor.clear();
4275
4276
// clear body settings:
4277
for (int i = 0; i < bodyPropertyEditor.size(); i++)
4278
if (bodyPropertyEditor[i])
4279
delete bodyPropertyEditor[i];
4280
4281
bodyPropertyEditor.clear();
4282
4283
// clear solver specific settings:
4284
for (int i = 0; i < solverParameterEditor.size(); i++)
4285
if (solverParameterEditor[i])
4286
delete solverParameterEditor[i];
4287
4288
solverParameterEditor.clear();
4289
}
4290
4291
//*****************************************************************************
4292
//
4293
// View MENU
4294
//
4295
//*****************************************************************************
4296
4297
// View -> Full screen
4298
//-----------------------------------------------------------------------------
4299
void MainWindow::viewFullScreenSlot() {
4300
if (!isFullScreen()) {
4301
cout << "Switching to full screen mode" << endl;
4302
cout << "Press 'Esc' to leave full screen mode" << endl;
4303
menuBar()->hide();
4304
statusBar()->hide();
4305
fileToolBar->hide();
4306
editToolBar->hide();
4307
meshToolBar->hide();
4308
solverToolBar->hide();
4309
this->showFullScreen();
4310
} else {
4311
viewNormalModeSlot();
4312
}
4313
synchronizeMenuToState();
4314
}
4315
4316
// Return to normal mode (GLWidget emits (void) when esc is pressed)...
4317
//-----------------------------------------------------------------------------
4318
void MainWindow::viewNormalModeSlot() {
4319
if (isFullScreen()) {
4320
cout << "Switching to normal window mode" << endl;
4321
this->showNormal();
4322
menuBar()->show();
4323
statusBar()->show();
4324
if (!egIni->isSet("hidetoolbars")) {
4325
fileToolBar->show();
4326
editToolBar->show();
4327
meshToolBar->show();
4328
solverToolBar->show();
4329
}
4330
}
4331
synchronizeMenuToState();
4332
statusBar()->showMessage(tr("Ready"));
4333
}
4334
4335
// Context menu event (usually mouse has been right clicked)...
4336
//-----------------------------------------------------------------------------
4337
void MainWindow::contextMenuEvent(QContextMenuEvent *event) {
4338
if(event->reason() != QContextMenuEvent::Mouse){
4339
contextMenu->popup(event->globalPos());
4340
}
4341
}
4342
4343
void MainWindow::showContextMenu(QPoint globalPos){
4344
contextMenu->popup(globalPos);
4345
}
4346
4347
// View -> Surface mesh
4348
//-----------------------------------------------------------------------------
4349
void MainWindow::hidesurfacemeshSlot() {
4350
mesh_t *mesh = glWidget->getMesh();
4351
int lists = glWidget->getLists();
4352
4353
if (mesh == NULL) {
4354
logMessage("There is no surface mesh to hide/show");
4355
return;
4356
}
4357
4358
glWidget->stateDrawSurfaceMesh = !glWidget->stateDrawSurfaceMesh;
4359
4360
for (int i = 0; i < lists; i++) {
4361
list_t *l = glWidget->getList(i);
4362
if (l->getType() == SURFACEMESHLIST) {
4363
l->setVisible(glWidget->stateDrawSurfaceMesh);
4364
4365
// do not set visible if the parent surface list is hidden
4366
int p = l->getParent();
4367
if (p >= 0) {
4368
list_t *lp = glWidget->getList(p);
4369
if (!lp->isVisible())
4370
l->setVisible(false);
4371
}
4372
}
4373
}
4374
4375
synchronizeMenuToState();
4376
4377
if (!glWidget->stateDrawSurfaceMesh)
4378
logMessage("Surface mesh hidden");
4379
else
4380
logMessage("Surface mesh shown");
4381
}
4382
4383
// View -> Volume mesh
4384
//-----------------------------------------------------------------------------
4385
void MainWindow::hidevolumemeshSlot() {
4386
mesh_t *mesh = glWidget->getMesh();
4387
int lists = glWidget->getLists();
4388
4389
if (mesh == NULL) {
4390
logMessage("There is no volume mesh to hide/show");
4391
return;
4392
}
4393
4394
glWidget->stateDrawVolumeMesh = !glWidget->stateDrawVolumeMesh;
4395
4396
for (int i = 0; i < lists; i++) {
4397
list_t *l = glWidget->getList(i);
4398
if (l->getType() == VOLUMEMESHLIST)
4399
l->setVisible(glWidget->stateDrawVolumeMesh);
4400
}
4401
4402
synchronizeMenuToState();
4403
4404
if (!glWidget->stateDrawVolumeMesh)
4405
logMessage("Volume mesh hidden");
4406
else
4407
logMessage("Volume mesh shown");
4408
}
4409
4410
// View -> Sharp edges
4411
//-----------------------------------------------------------------------------
4412
void MainWindow::hidesharpedgesSlot() {
4413
mesh_t *mesh = glWidget->getMesh();
4414
int lists = glWidget->getLists();
4415
4416
if (mesh == NULL) {
4417
logMessage("There are no sharp edges to hide/show");
4418
return;
4419
}
4420
4421
glWidget->stateDrawSharpEdges = !glWidget->stateDrawSharpEdges;
4422
4423
for (int i = 0; i < lists; i++) {
4424
list_t *l = glWidget->getList(i);
4425
if (l->getType() == SHARPEDGELIST)
4426
l->setVisible(glWidget->stateDrawSharpEdges);
4427
}
4428
4429
synchronizeMenuToState();
4430
4431
if (!glWidget->stateDrawSharpEdges)
4432
logMessage("Sharp edges hidden");
4433
else
4434
logMessage("Sharp edges shown");
4435
}
4436
4437
// View -> Coordinates
4438
//-----------------------------------------------------------------------------
4439
void MainWindow::viewCoordinatesSlot() {
4440
if (glWidget->toggleCoordinates())
4441
logMessage("Coordinates shown");
4442
else
4443
logMessage("Coordinates hidden");
4444
4445
synchronizeMenuToState();
4446
}
4447
4448
// View -> Select defined edges
4449
//-----------------------------------------------------------------------------
4450
void MainWindow::selectDefinedEdgesSlot() {
4451
mesh_t *mesh = glWidget->getMesh();
4452
int lists = glWidget->getLists();
4453
4454
if (mesh == NULL) {
4455
logMessage("There are no entities from which to select");
4456
return;
4457
}
4458
4459
// At the moment only edges are included in search:
4460
int nmax = 0;
4461
for (int i = 0; i < glWidget->boundaryMap.count(); i++) {
4462
int n = glWidget->boundaryMap.key(i);
4463
if (n > nmax)
4464
nmax = n;
4465
}
4466
4467
bool *activeboundary = new bool[nmax + 1];
4468
for (int i = 0; i <= nmax; i++)
4469
activeboundary[i] = false;
4470
4471
for (int i = 0; i < glWidget->boundaryMap.count(); i++) {
4472
int n = glWidget->boundaryMap.key(i);
4473
if (n >= 0) {
4474
int m = glWidget->boundaryMap.value(n);
4475
4476
if (m >= boundaryPropertyEditor.size())
4477
boundaryPropertyEditor.resize(m + 1);
4478
4479
if (!boundaryPropertyEditor[m])
4480
boundaryPropertyEditor[m] = new BoundaryPropertyEditor;
4481
4482
BoundaryPropertyEditor *boundary = boundaryPropertyEditor[m];
4483
activeboundary[n] = boundary->condition;
4484
}
4485
}
4486
4487
for (int i = 0; i < lists; i++) {
4488
list_t *l = glWidget->getList(i);
4489
if (l->getType() == EDGELIST) {
4490
int j = l->getIndex();
4491
if (j < 0)
4492
continue;
4493
4494
// *** TODO ***
4495
//
4496
// This is wrong: Comparing body indices with boundary indices
4497
if (activeboundary[j])
4498
l->setSelected(true);
4499
}
4500
}
4501
4502
for (int i = 0; i < mesh->getEdges(); i++) {
4503
edge_t *edge = mesh->getEdge(i);
4504
if (edge->getNature() == PDE_BOUNDARY) {
4505
int j = edge->getIndex();
4506
if (j < 0)
4507
continue;
4508
if (activeboundary[j])
4509
edge->setSelected(true);
4510
}
4511
}
4512
delete[] activeboundary;
4513
4514
glWidget->rebuildEdgeLists();
4515
glWidget->updateGL();
4516
4517
logMessage("Defined edges selected");
4518
}
4519
4520
// View -> Select defined surfaces
4521
//-----------------------------------------------------------------------------
4522
void MainWindow::selectDefinedSurfacesSlot() {
4523
mesh_t *mesh = glWidget->getMesh();
4524
int lists = glWidget->getLists();
4525
4526
if (mesh == NULL) {
4527
logMessage("There are no entities from which to select");
4528
return;
4529
}
4530
4531
// At the moment only surfaces are included in search:
4532
int nmax = 0;
4533
for (int i = 0; i < glWidget->bodyMap.count(); i++) {
4534
int n = glWidget->bodyMap.key(i);
4535
if (n > nmax)
4536
nmax = n;
4537
}
4538
4539
bool *activebody = new bool[nmax + 1];
4540
for (int i = 0; i <= nmax; i++)
4541
activebody[i] = false;
4542
4543
for (int i = 0; i < glWidget->bodyMap.count(); i++) {
4544
int n = glWidget->bodyMap.key(i);
4545
if (n >= 0) {
4546
int m = glWidget->bodyMap.value(n);
4547
4548
BodyPropertyEditor *body = bodyPropertyEditor[m];
4549
4550
if (!body) {
4551
cout << "MainWindow: Body index out of bounds" << endl;
4552
continue;
4553
}
4554
4555
activebody[n] = body->material && body->equation;
4556
}
4557
}
4558
4559
for (int i = 0; i < lists; i++) {
4560
list_t *l = glWidget->getList(i);
4561
if (l->getType() == SURFACELIST) {
4562
int j = l->getIndex();
4563
if (j < 0)
4564
continue;
4565
4566
// *** TODO ***
4567
//
4568
// This is wrong: Comparing body indices with boundary indexes
4569
if (activebody[j])
4570
l->setSelected(true);
4571
}
4572
}
4573
4574
for (int i = 0; i < mesh->getSurfaces(); i++) {
4575
surface_t *surface = mesh->getSurface(i);
4576
if (surface->getNature() == PDE_BULK) {
4577
int j = surface->getIndex();
4578
if (j < 0)
4579
continue;
4580
if (activebody[j])
4581
surface->setSelected(true);
4582
}
4583
}
4584
delete[] activebody;
4585
4586
glWidget->rebuildSurfaceLists();
4587
glWidget->updateGL();
4588
4589
logMessage("Defined surfaces selected");
4590
}
4591
4592
// View -> Select all surfaces
4593
//-----------------------------------------------------------------------------
4594
void MainWindow::selectAllSurfacesSlot() {
4595
mesh_t *mesh = glWidget->getMesh();
4596
int lists = glWidget->getLists();
4597
4598
if (mesh == NULL) {
4599
logMessage("There are no surfaces to select");
4600
return;
4601
}
4602
4603
for (int i = 0; i < lists; i++) {
4604
list_t *l = glWidget->getList(i);
4605
if (l->getType() == SURFACELIST) {
4606
l->setSelected(true);
4607
for (int j = 0; j < mesh->getSurfaces(); j++) {
4608
surface_t *surf = mesh->getSurface(j);
4609
if (l->getIndex() == surf->getIndex())
4610
surf->setSelected(l->isSelected());
4611
}
4612
}
4613
}
4614
4615
glWidget->rebuildSurfaceLists();
4616
glWidget->updateGL();
4617
4618
logMessage("All surfaces selected");
4619
}
4620
4621
// View -> Select all edges
4622
//-----------------------------------------------------------------------------
4623
void MainWindow::selectAllEdgesSlot() {
4624
mesh_t *mesh = glWidget->getMesh();
4625
int lists = glWidget->getLists();
4626
4627
if (mesh == NULL) {
4628
logMessage("There are no edges to select");
4629
return;
4630
}
4631
4632
for (int i = 0; i < lists; i++) {
4633
list_t *l = glWidget->getList(i);
4634
4635
if (l->getType() == EDGELIST)
4636
l->setSelected(true);
4637
4638
for (int j = 0; j < mesh->getEdges(); j++) {
4639
edge_t *edge = mesh->getEdge(j);
4640
if (l->getIndex() == edge->getIndex())
4641
edge->setSelected(l->isSelected());
4642
}
4643
}
4644
4645
glWidget->rebuildEdgeLists();
4646
glWidget->updateGL();
4647
4648
logMessage("All edges selected");
4649
}
4650
4651
// View -> Hide/Show selected
4652
//-----------------------------------------------------------------------------
4653
void MainWindow::hideselectedSlot() {
4654
mesh_t *mesh = glWidget->getMesh();
4655
int lists = glWidget->getLists();
4656
4657
if (mesh == NULL) {
4658
logMessage("There is nothing to hide/show");
4659
return;
4660
}
4661
4662
bool something_selected = false;
4663
for (int i = 0; i < lists; i++) {
4664
list_t *l = glWidget->getList(i);
4665
something_selected |= l->isSelected();
4666
}
4667
4668
if (!something_selected) {
4669
logMessage("Nothing selected");
4670
return;
4671
}
4672
4673
bool vis = false;
4674
for (int i = 0; i < lists; i++) {
4675
list_t *l = glWidget->getList(i);
4676
if (l->isSelected()) {
4677
l->setVisible(!l->isVisible());
4678
if (l->isVisible())
4679
vis = true;
4680
4681
// hide the child surface edge list if parent is hidden
4682
int c = l->getChild();
4683
if (c >= 0) {
4684
list_t *lc = glWidget->getList(c);
4685
lc->setVisible(l->isVisible());
4686
if (!glWidget->stateDrawSurfaceMesh)
4687
lc->setVisible(false);
4688
}
4689
}
4690
}
4691
glWidget->updateGL();
4692
4693
if (!vis)
4694
logMessage("Selected objects hidden");
4695
else
4696
logMessage("Selected objects shown");
4697
}
4698
4699
// View -> Show all
4700
//-----------------------------------------------------------------------------
4701
void MainWindow::showallSlot() {
4702
int lists = glWidget->getLists();
4703
4704
glWidget->stateDrawSurfaceMesh = true;
4705
#ifndef WIN32
4706
glWidget->stateDrawSharpEdges = true;
4707
#endif
4708
glWidget->stateDrawSurfaceElements = true;
4709
glWidget->stateDrawEdgeElements = true;
4710
4711
synchronizeMenuToState();
4712
4713
for (int i = 0; i < lists; i++) {
4714
list_t *l = glWidget->getList(i);
4715
l->setVisible(true);
4716
}
4717
4718
logMessage("All objects visible");
4719
}
4720
4721
// View -> Reset model view
4722
//-----------------------------------------------------------------------------
4723
void MainWindow::resetSlot() {
4724
mesh_t *mesh = glWidget->getMesh();
4725
int lists = glWidget->getLists();
4726
4727
if (mesh == NULL) {
4728
logMessage("There is nothing to reset");
4729
return;
4730
}
4731
4732
glWidget->stateFlatShade = true;
4733
glWidget->stateDrawSurfaceMesh = true;
4734
#ifndef WIN32
4735
glWidget->stateDrawSharpEdges = true;
4736
#endif
4737
glWidget->stateDrawSurfaceElements = true;
4738
glWidget->stateDrawEdgeElements = true;
4739
glWidget->stateDrawSurfaceNumbers = false;
4740
glWidget->stateDrawEdgeNumbers = false;
4741
glWidget->stateDrawNodeNumbers = false;
4742
4743
for (int i = 0; i < lists; i++) {
4744
list_t *l = glWidget->getList(i);
4745
l->setVisible(true);
4746
l->setSelected(false);
4747
4748
for (int j = 0; j < mesh->getSurfaces(); j++) {
4749
surface_t *surf = mesh->getSurface(j);
4750
if (l->getIndex() == surf->getIndex())
4751
surf->setSelected(l->isSelected());
4752
}
4753
for (int j = 0; j < mesh->getEdges(); j++) {
4754
edge_t *edge = mesh->getEdge(j);
4755
if (l->getIndex() == edge->getIndex())
4756
edge->setSelected(l->isSelected());
4757
}
4758
}
4759
4760
glWidget->stateBcColors = false;
4761
glWidget->stateBodyColors = false;
4762
4763
glLoadIdentity();
4764
glWidget->rebuildLists();
4765
glWidget->updateGL();
4766
4767
synchronizeMenuToState();
4768
logMessage("Reset model view");
4769
}
4770
4771
// View -> Shade model -> Flat
4772
//-----------------------------------------------------------------------------
4773
void MainWindow::flatShadeSlot() {
4774
if (!glWidget->hasMesh()) {
4775
logMessage("Refusing to change shade model when mesh is empty");
4776
return;
4777
}
4778
4779
glWidget->stateFlatShade = true;
4780
glWidget->rebuildSurfaceLists();
4781
glWidget->updateGL();
4782
4783
synchronizeMenuToState();
4784
logMessage("Shade model: flat");
4785
}
4786
4787
// View -> Shade model -> Smooth
4788
//-----------------------------------------------------------------------------
4789
void MainWindow::smoothShadeSlot() {
4790
if (!glWidget->hasMesh()) {
4791
logMessage("Refusing to change shade model when mesh is empty");
4792
return;
4793
}
4794
4795
glWidget->stateFlatShade = false;
4796
glWidget->rebuildSurfaceLists();
4797
glWidget->updateGL();
4798
4799
synchronizeMenuToState();
4800
logMessage("Shade model: smooth");
4801
}
4802
4803
// View -> Projection -> Orthogonal
4804
//-----------------------------------------------------------------------------
4805
void MainWindow::orthoSlot() {
4806
if (!glWidget->hasMesh()) {
4807
logMessage("Refusing to change projection when mesh is empty");
4808
return;
4809
}
4810
4811
glWidget->stateOrtho = true;
4812
glWidget->changeProjection();
4813
glWidget->updateGL();
4814
4815
synchronizeMenuToState();
4816
logMessage("Projection: orthogonal");
4817
}
4818
4819
// View -> Projection -> Perspective
4820
//-----------------------------------------------------------------------------
4821
void MainWindow::perspectiveSlot() {
4822
if (!glWidget->hasMesh()) {
4823
logMessage("Refusing to change projection when mesh is empty");
4824
return;
4825
}
4826
4827
glWidget->stateOrtho = false;
4828
glWidget->changeProjection();
4829
glWidget->updateGL();
4830
4831
synchronizeMenuToState();
4832
logMessage("Projection: perspective");
4833
}
4834
4835
// View -> Show numbering -> Surface numbering
4836
//-----------------------------------------------------------------------------
4837
void MainWindow::showSurfaceNumbersSlot() {
4838
if (!glWidget->hasMesh()) {
4839
logMessage("Refusing to show surface element numbering when mesh is empty");
4840
return;
4841
}
4842
glWidget->stateDrawSurfaceNumbers = !glWidget->stateDrawSurfaceNumbers;
4843
glWidget->updateGL();
4844
synchronizeMenuToState();
4845
4846
if (glWidget->stateDrawSurfaceNumbers)
4847
logMessage("Surface element numbering turned on");
4848
else
4849
logMessage("Surface element numbering turned off");
4850
}
4851
4852
// View -> Show numbering -> Edge numbering
4853
//-----------------------------------------------------------------------------
4854
void MainWindow::showEdgeNumbersSlot() {
4855
if (!glWidget->hasMesh()) {
4856
logMessage("Refusing to show edge element numbering when mesh is empty");
4857
return;
4858
}
4859
glWidget->stateDrawEdgeNumbers = !glWidget->stateDrawEdgeNumbers;
4860
glWidget->updateGL();
4861
synchronizeMenuToState();
4862
4863
if (glWidget->stateDrawEdgeNumbers)
4864
logMessage("Edge element numbering turned on");
4865
else
4866
logMessage("Edge element numbering turned off");
4867
}
4868
4869
// View -> Numbering -> Node numbers
4870
//-----------------------------------------------------------------------------
4871
void MainWindow::showNodeNumbersSlot() {
4872
if (!glWidget->hasMesh()) {
4873
logMessage("Refusing to show node numbering when mesh is empty");
4874
return;
4875
}
4876
glWidget->stateDrawNodeNumbers = !glWidget->stateDrawNodeNumbers;
4877
glWidget->updateGL();
4878
synchronizeMenuToState();
4879
4880
if (glWidget->stateDrawNodeNumbers)
4881
logMessage("Node numbering turned on");
4882
else
4883
logMessage("Node numbering turned off");
4884
}
4885
4886
// View -> Numbering -> Boundary index
4887
//-----------------------------------------------------------------------------
4888
void MainWindow::showBoundaryIndexSlot() {
4889
if (!glWidget->hasMesh()) {
4890
logMessage("Refusing to show boundary indices when mesh is empty");
4891
return;
4892
}
4893
glWidget->stateDrawBoundaryIndex = !glWidget->stateDrawBoundaryIndex;
4894
glWidget->updateGL();
4895
synchronizeMenuToState();
4896
4897
if (glWidget->stateDrawBoundaryIndex)
4898
logMessage("Boundary indices visible");
4899
else
4900
logMessage("Boundary indices hidden");
4901
}
4902
4903
// View -> Numbering -> Body index
4904
//-----------------------------------------------------------------------------
4905
void MainWindow::showBodyIndexSlot() {
4906
if (!glWidget->hasMesh()) {
4907
logMessage("Refusing to show body indices when mesh is empty");
4908
return;
4909
}
4910
4911
glWidget->stateDrawBodyIndex = !glWidget->stateDrawBodyIndex;
4912
glWidget->updateGL();
4913
synchronizeMenuToState();
4914
4915
if (glWidget->stateDrawBodyIndex)
4916
logMessage("Body indices visible");
4917
else
4918
logMessage("Body indices hidden");
4919
}
4920
4921
// View -> Colors -> GL controls
4922
//-----------------------------------------------------------------------------
4923
void MainWindow::glControlSlot() {
4924
if (!glWidget->hasMesh()) {
4925
logMessage("No mesh - unable to set GL parameters when the mesh is empty");
4926
return;
4927
}
4928
4929
glControl->glWidget = this->glWidget;
4930
glControl->show();
4931
}
4932
4933
// View -> Colors -> Boundaries
4934
//-----------------------------------------------------------------------------
4935
void MainWindow::colorizeBoundarySlot() {
4936
if (!glWidget->hasMesh()) {
4937
logMessage("No mesh - unable to colorize boundaries");
4938
return;
4939
}
4940
4941
glWidget->stateBcColors = !glWidget->stateBcColors;
4942
4943
if (glWidget->stateBcColors)
4944
glWidget->stateBodyColors = false;
4945
4946
glWidget->rebuildLists();
4947
synchronizeMenuToState();
4948
}
4949
4950
// View -> Colors -> Bodies
4951
//-----------------------------------------------------------------------------
4952
void MainWindow::colorizeBodySlot() {
4953
if (!glWidget->hasMesh()) {
4954
logMessage("No mesh - unable to colorize bodies");
4955
return;
4956
}
4957
4958
glWidget->stateBodyColors = !glWidget->stateBodyColors;
4959
4960
if (glWidget->stateBodyColors)
4961
glWidget->stateBcColors = false;
4962
4963
glWidget->rebuildLists();
4964
synchronizeMenuToState();
4965
}
4966
4967
// View -> Colors -> Background
4968
//-----------------------------------------------------------------------------
4969
void MainWindow::backgroundColorSlot() {
4970
QColor newColor = QColorDialog::getColor(glWidget->backgroundColor, this);
4971
if(!newColor.isValid()) return;
4972
4973
#if WITH_QT6
4974
glClearColor(newColor.redF(), newColor.greenF(), newColor.redF(), newColor.alphaF());
4975
#else
4976
glWidget->qglClearColor(newColor);
4977
#endif
4978
glWidget->backgroundColor = newColor;
4979
}
4980
4981
// View -> Colors -> Surface
4982
//-----------------------------------------------------------------------------
4983
void MainWindow::surfaceColorSlot() {
4984
if (!glWidget->hasMesh()) {
4985
logMessage("Unable to change surface color when the mesh is empty");
4986
return;
4987
}
4988
4989
QColor newColor = QColorDialog::getColor(glWidget->surfaceColor, this);
4990
if(!newColor.isValid()) return;
4991
glWidget->surfaceColor = newColor;
4992
glWidget->rebuildLists();
4993
}
4994
4995
// View -> Colors -> Edge
4996
//-----------------------------------------------------------------------------
4997
void MainWindow::edgeColorSlot() {
4998
if (!glWidget->hasMesh()) {
4999
logMessage("Unable to change edge color when the mesh is empty");
5000
return;
5001
}
5002
5003
QColor newColor = QColorDialog::getColor(glWidget->edgeColor, this);
5004
if(!newColor.isValid()) return;
5005
glWidget->edgeColor = newColor;
5006
glWidget->rebuildLists();
5007
}
5008
5009
// View -> Colors -> Surface mesh
5010
//-----------------------------------------------------------------------------
5011
void MainWindow::surfaceMeshColorSlot() {
5012
if (!glWidget->hasMesh()) {
5013
logMessage("Unable to change surface mesh color when the mesh is empty");
5014
return;
5015
}
5016
5017
QColor newColor = QColorDialog::getColor(glWidget->surfaceMeshColor, this);
5018
if(!newColor.isValid()) return;
5019
glWidget->surfaceMeshColor = newColor;
5020
glWidget->rebuildLists();
5021
}
5022
5023
// View -> Colors -> Sharp edges
5024
//-----------------------------------------------------------------------------
5025
void MainWindow::sharpEdgeColorSlot() {
5026
if (!glWidget->hasMesh()) {
5027
logMessage("Unable to change sharp edge colors when the mesh is empty");
5028
return;
5029
}
5030
5031
QColor newColor = QColorDialog::getColor(glWidget->sharpEdgeColor, this);
5032
if(!newColor.isValid()) return;
5033
glWidget->sharpEdgeColor = newColor;
5034
glWidget->rebuildLists();
5035
}
5036
5037
// View -> Colors -> Selection
5038
//-----------------------------------------------------------------------------
5039
void MainWindow::selectionColorSlot() {
5040
if (!glWidget->hasMesh()) {
5041
logMessage("Unable to change sharp edge colors when the mesh is empty");
5042
return;
5043
}
5044
5045
QColor newColor = QColorDialog::getColor(glWidget->selectionColor, this);
5046
if(!newColor.isValid()) return;
5047
glWidget->selectionColor = newColor;
5048
glWidget->rebuildLists();
5049
}
5050
5051
// View -> Cad model...
5052
//-----------------------------------------------------------------------------
5053
void MainWindow::showCadModelSlot() {
5054
#ifdef EG_OCC
5055
cadView->show();
5056
#endif
5057
}
5058
5059
// View -> Twod model...
5060
//-----------------------------------------------------------------------------
5061
void MainWindow::showTwodViewSlot() { twodView->show(); }
5062
5063
// View -> VTK post...
5064
//-----------------------------------------------------------------------------
5065
void MainWindow::showVtkPostSlot() {
5066
#ifdef EG_VTK
5067
5068
if (glWidget->getMesh() == NULL) {
5069
vtkPost->show();
5070
return;
5071
}
5072
5073
QString postFileName =
5074
saveDirName + "/" + generalSetup->ui.postFileEdit->text().trimmed();
5075
// Parallel solution:
5076
//====================
5077
Ui::parallelDialog ui = parallel->ui;
5078
bool parallelActive = ui.parallelActiveCheckBox->isChecked();
5079
5080
if (parallelActive) {
5081
5082
// unify mesh:
5083
if (meshUnifier->state() == QProcess::Running) {
5084
logMessage("Mesh unifier is already running - aborted");
5085
return;
5086
}
5087
5088
if (saveDirName.isEmpty()) {
5089
logMessage("saveDirName is empty - unable to locate result files");
5090
return;
5091
}
5092
5093
// Set up log window:
5094
solverLogWindow->setWindowTitle(tr("ElmerGrid log"));
5095
solverLogWindow->getTextEdit()->clear();
5096
solverLogWindow->setFound(false);
5097
solverLogWindow->show();
5098
5099
QString postName = generalSetup->ui.postFileEdit->text().trimmed();
5100
QStringList postNameSplitted = postName.split(".");
5101
int nofProcessors = ui.nofProcessorsSpinBox->value();
5102
5103
QString unifyingCommand = ui.mergeLineEdit->text().trimmed();
5104
unifyingCommand.replace(QString("%ep"), postNameSplitted.at(0).trimmed());
5105
unifyingCommand.replace(QString("%n"), QString::number(nofProcessors));
5106
5107
logMessage("Executing: " + unifyingCommand);
5108
5109
meshUnifier->start(unifyingCommand);
5110
5111
if (!meshUnifier->waitForStarted()) {
5112
solverLogWindow->getTextEdit()->append(
5113
"Unable to start ElmerGrid for mesh unification - aborted");
5114
logMessage("Unable to start ElmerGrid for mesh unification - aborted");
5115
vtkPostMeshUnifierRunning = false;
5116
return;
5117
}
5118
5119
// The rest is done in meshUnifierFinishedSlot:
5120
vtkPostMeshUnifierRunning = true;
5121
return;
5122
}
5123
5124
// Scalar solution:
5125
//-----------------
5126
vtkPost->show();
5127
5128
QFileInfo info(postFileName);
5129
QDir dir = info.dir();
5130
if(postFileName.endsWith(".vtu", Qt::CaseInsensitive)){
5131
if(!parallelActive){
5132
QString vtuFileName = postFileName;
5133
vtuFileName.insert(vtuFileName.length()-4, "_t0001");
5134
if(!vtkPost->ReadSingleVtuFile(vtuFileName)){
5135
vtuFileName = postFileName;
5136
vtuFileName.insert(vtuFileName.length()-4, "0001");
5137
vtkPost->ReadSingleVtuFile(vtuFileName);
5138
}
5139
}
5140
}else{
5141
vtkPost->ReadPostFile(postFileName);
5142
}
5143
#endif
5144
}
5145
5146
// View -> Paraview
5147
//-----------------------------------------------------------------------------
5148
void MainWindow::showParaViewSlot() {
5149
#ifdef EG_PARAVIEW
5150
5151
if (paraview->state() == QProcess::Running) {
5152
logMessage("ParaView is already running");
5153
return;
5154
}
5155
5156
QString postFileName = generalSetup->ui.postFileEdit->text().trimmed();
5157
QFileInfo pvFile(postFileName);
5158
5159
Ui::parallelDialog ui = parallel->ui;
5160
bool parallelActive = ui.parallelActiveCheckBox->isChecked();
5161
5162
QDir currentDir;
5163
QStringList args;
5164
QString secondName;
5165
5166
currentDir = QDir(saveDirName);
5167
5168
// Paraview can deal with case..vtu kind of arguments which however,
5169
// fail if there is only one file. Use dirty check to see that there
5170
// are more than one file.
5171
5172
if (!parallelActive) {
5173
secondName = pvFile.baseName() + "_t0002.vtu";
5174
} else {
5175
secondName = pvFile.baseName() + "_t0002.pvtu";
5176
}
5177
5178
QFile secondFile(secondName);
5179
5180
// Serial solution
5181
//================
5182
if (!parallelActive) {
5183
if (secondFile.exists())
5184
args << pvFile.baseName() + "_t..vtu";
5185
else
5186
args << pvFile.baseName() + "_t0001.vtu";
5187
}
5188
5189
// Parallel solution
5190
//==================
5191
if (parallelActive) {
5192
if (secondFile.exists())
5193
args << pvFile.baseName() + "_t..pvtu";
5194
else
5195
args << pvFile.baseName() + "_t0001.pvtu";
5196
}
5197
5198
// Launch ParaView
5199
//================
5200
paraview->start("paraview", args);
5201
5202
if (!paraview->waitForStarted()) {
5203
logMessage("Unable to start ParaView");
5204
return;
5205
}
5206
5207
logMessage("ParaView started");
5208
5209
updateSysTrayIcon("ParaView started",
5210
"");
5211
5212
#endif
5213
}
5214
5215
//*****************************************************************************
5216
//
5217
// Mesh MENU
5218
//
5219
//*****************************************************************************
5220
5221
// Mesh -> Control...
5222
//-----------------------------------------------------------------------------
5223
void MainWindow::meshcontrolSlot() {
5224
meshControl->tetlibPresent = this->tetlibPresent;
5225
meshControl->nglibPresent = this->nglibPresent;
5226
5227
if (!tetlibPresent) {
5228
meshControl->tetlibPresent = false;
5229
meshControl->ui.nglibRadioButton->setChecked(true);
5230
meshControl->ui.tetlibRadioButton->setEnabled(false);
5231
meshControl->ui.tetlibStringEdit->setEnabled(false);
5232
}
5233
5234
if (!nglibPresent) {
5235
meshControl->nglibPresent = false;
5236
meshControl->ui.tetlibRadioButton->setChecked(true);
5237
meshControl->ui.nglibRadioButton->setEnabled(false);
5238
meshControl->ui.nglibMaxHEdit->setEnabled(false);
5239
meshControl->ui.nglibFinenessEdit->setEnabled(false);
5240
meshControl->ui.nglibBgmeshEdit->setEnabled(false);
5241
}
5242
5243
if (!tetlibPresent && !nglibPresent)
5244
meshControl->ui.elmerGridRadioButton->setChecked(true);
5245
5246
meshControl->show();
5247
}
5248
5249
int checkStlForAscii(const char * filename)
5250
{
5251
char ch;
5252
char bufin[100];
5253
int stlbinary = 0;
5254
ifstream stlfile(filename);
5255
5256
if (stlfile.is_open()) {
5257
cout << "Open stl input file: " << filename << endl;
5258
5259
for (int j = 0; j < 100; j++) {
5260
stlfile.get(ch);
5261
bufin[j] = ch;
5262
}
5263
//cout << "bufin: " << bufin << endl;
5264
if( strstr(bufin,"facet")) {
5265
cout << "stl input file is in ASCII file format" << endl;
5266
} else {
5267
stlbinary = 1;
5268
cout << "stl input file is in binary file format" << endl;
5269
}
5270
cout << endl;
5271
stlfile.close();
5272
} else {
5273
cout << "stl input file not found or is corrupted" << filename << endl;
5274
}
5275
5276
return stlbinary;
5277
}
5278
// Mesh -> Remesh
5279
//-----------------------------------------------------------------------------
5280
void MainWindow::remeshSlot() {
5281
if (activeGenerator == GEN_UNKNOWN) {
5282
logMessage("Unable to (re)mesh: no input data or mesh generator. Allowed: "
5283
"smesh, poly, off, ply, mesh, stl, grd, FDNEUT, msh, mphtxt, inp, unv, plt, in2d");
5284
return;
5285
}
5286
5287
// ***** ELMERGRID *****
5288
5289
if (activeGenerator == GEN_ELMERGRID) {
5290
5291
meshutils->clearMesh(glWidget->getMesh());
5292
glWidget->newMesh();
5293
mesh_t *mesh = glWidget->getMesh();
5294
5295
#if WITH_QT5 || WITH_QT6
5296
elmergridAPI->createElmerMeshStructure(
5297
mesh, meshControl->elmerGridControlString.toLatin1());
5298
#else
5299
elmergridAPI->createElmerMeshStructure(
5300
mesh, meshControl->elmerGridControlString.toAscii());
5301
#endif
5302
5303
if (mesh->getSurfaces() == 0)
5304
meshutils->findSurfaceElements(mesh);
5305
5306
for (int i = 0; i < mesh->getSurfaces(); i++) {
5307
surface_t *surface = mesh->getSurface(i);
5308
5309
surface->setEdges((int)(surface->getCode() / 100));
5310
surface->newEdgeIndexes(surface->getEdges());
5311
for (int j = 0; j < surface->getEdges(); j++)
5312
surface->setEdgeIndex(j, -1);
5313
}
5314
5315
meshutils->findSurfaceElementEdges(mesh);
5316
meshutils->findSurfaceElementNormals(mesh);
5317
5318
glWidget->rebuildLists();
5319
applyOperations();
5320
5321
return;
5322
}
5323
5324
// ***** Threaded generators *****
5325
5326
if (!remeshAct->isEnabled()) {
5327
logMessage("Meshing thread is already running - aborting");
5328
return;
5329
}
5330
5331
if (activeGenerator == GEN_TETLIB) {
5332
5333
if (!tetlibPresent) {
5334
logMessage("tetlib functionality unavailable");
5335
return;
5336
}
5337
5338
if (!tetlibInputOk) {
5339
logMessage("Remesh: error: no input data for tetlib");
5340
return;
5341
}
5342
5343
// Usually "J" should be included in the control string:
5344
tetlibControlString = meshControl->tetlibControlString;
5345
5346
} else if (activeGenerator == GEN_NGLIB) {
5347
5348
if (!nglibPresent) {
5349
logMessage("nglib functionality unavailable");
5350
return;
5351
}
5352
5353
if (!nglibInputOk) {
5354
logMessage("Remesh: error: no input data for nglib");
5355
return;
5356
}
5357
5358
// Init & set mesh params.:
5359
//--------------------------
5360
cout << "Initializing nglib" << endl;
5361
nglib::Ng_Init();
5362
5363
char backgroundmesh[1024];
5364
#if WITH_QT5 || WITH_QT6
5365
sprintf(backgroundmesh, "%s",
5366
meshControl->nglibBackgroundmesh.toLatin1().data());
5367
#else
5368
sprintf(backgroundmesh, "%s",
5369
meshControl->nglibBackgroundmesh.toAscii().data());
5370
#endif
5371
5372
mp.maxh = meshControl->nglibMaxH.toDouble();
5373
mp.fineness = meshControl->nglibFineness.toDouble();
5374
mp.secondorder = 0;
5375
mp.meshsize_filename = backgroundmesh;
5376
5377
if (ngDim == 3) {
5378
5379
// STL (3D):
5380
//-----------
5381
cout << "Start meshing..." << endl;
5382
5383
nggeom = nglib::Ng_STL_NewGeometry();
5384
5385
ngmesh = nglib::Ng_NewMesh();
5386
5387
if (!occInputOk) {
5388
5389
// STL: regenerate structures for nglib:
5390
//--------------------------------------
5391
// check if input file is in ascii or binary format
5392
#if WITH_QT5 || WITH_QT6
5393
int stlbinary = checkStlForAscii(stlFileName.toLatin1().data());
5394
#else
5395
int stlbinary = checkStlForAscii(stlFileName.toAscii().data());
5396
#endif
5397
5398
#if WITH_QT5 || WITH_QT6
5399
nggeom = nglib::Ng_STL_LoadGeometry(stlFileName.toLatin1().data(), stlbinary);
5400
#else
5401
nggeom = nglib::Ng_STL_LoadGeometry(stlFileName.toAscii().data(), stlbinary);
5402
#endif
5403
5404
if (!nggeom) {
5405
logMessage("Ng_STL_LoadGeometry failed");
5406
return;
5407
}
5408
5409
nglib::Ng_STL_InitSTLGeometry(nggeom);
5410
5411
nglib::Ng_STL_MakeEdges(nggeom, ngmesh, &mp);
5412
5413
double maxMeshSize = mp.maxh;
5414
5415
if (maxMeshSize <= 0)
5416
maxMeshSize = 10000000;
5417
5418
nglib::Ng_RestrictMeshSizeGlobal(ngmesh, maxMeshSize);
5419
5420
#ifdef EG_OCC
5421
} else {
5422
5423
// OCC: (re)generate STL for nglib:
5424
//----------------------------------
5425
cadView->setMesh(ngmesh);
5426
cadView->setGeom(nggeom);
5427
cadView->setMp(&mp);
5428
cadView->generateSTL();
5429
#endif
5430
}
5431
5432
} else if (ngDim == 2) {
5433
5434
// IN2D (2D):
5435
//------------
5436
cout << "Start 2D meshing..." << endl;
5437
5438
if (!occInputOk) {
5439
5440
// Native 2D geometry input for Ng:
5441
//----------------------------------
5442
if (in2dFileName.isEmpty()) {
5443
logMessage("File name is empty - aborting");
5444
return;
5445
}
5446
5447
ngmesh = nglib::Ng_NewMesh();
5448
5449
#if WITH_QT5 || WITH_QT6
5450
nggeom2d = nglib::Ng_LoadGeometry_2D(in2dFileName.toLatin1().data());
5451
#else
5452
nggeom2d = nglib::Ng_LoadGeometry_2D(in2dFileName.toAscii().data());
5453
#endif
5454
5455
if (!nggeom2d) {
5456
logMessage("Ng_LoadGeometry_2D failed");
5457
return;
5458
}
5459
5460
nglibAPI->setNggeom2D(nggeom2d);
5461
5462
double maxMeshSize = mp.maxh;
5463
5464
if (maxMeshSize <= 0)
5465
maxMeshSize = 10000000;
5466
5467
nglib::Ng_RestrictMeshSizeGlobal(ngmesh, maxMeshSize);
5468
5469
#ifdef EG_OCC
5470
} else {
5471
5472
// Model originates from a 2D cad file:
5473
//--------------------------------------
5474
cadView->generateIn2dFile();
5475
5476
ngmesh = nglib::Ng_NewMesh();
5477
5478
nggeom2d = nglib::Ng_LoadGeometry_2D("iges2ng.in2d");
5479
5480
if (!nggeom2d) {
5481
logMessage("Ng_LoadGeometry_2D failed");
5482
return;
5483
}
5484
5485
nglibAPI->setNggeom2D(nggeom2d);
5486
5487
double maxMeshSize = mp.maxh;
5488
5489
if (maxMeshSize <= 0)
5490
maxMeshSize = 10000000;
5491
5492
nglib::Ng_RestrictMeshSizeGlobal(ngmesh, maxMeshSize);
5493
#endif
5494
}
5495
5496
} else {
5497
5498
// Unknown spatial dimension:
5499
//----------------------------
5500
cout << "Unknown spatial dimension" << endl;
5501
return;
5502
}
5503
5504
} else {
5505
5506
logMessage("Remesh: unknown generator type");
5507
return;
5508
}
5509
5510
// ***** Start meshing thread *****
5511
5512
logMessage("Sending start request to mesh generator...");
5513
5514
meshutils->clearMesh(glWidget->getMesh());
5515
glWidget->newMesh();
5516
mesh_t *mesh = glWidget->getMesh();
5517
5518
// Re-enable when finished() or terminated() signal is received:
5519
remeshAct->setEnabled(false);
5520
stopMeshingAct->setEnabled(true);
5521
5522
if (activeGenerator == GEN_NGLIB)
5523
stopMeshingAct->setEnabled(false);
5524
5525
meshingThread->generate(activeGenerator, tetlibControlString, tetlibAPI,
5526
ngmesh, nggeom, nggeom2d, ngDim, &mp);
5527
}
5528
5529
// Mesh -> Kill generator
5530
//-----------------------------------------------------------------------------
5531
void MainWindow::stopMeshingSlot() {
5532
if (remeshAct->isEnabled()) {
5533
logMessage("Mesh generator is not running");
5534
return;
5535
}
5536
5537
logMessage("Sending termination request to mesh generator...");
5538
meshingThread->stopMeshing();
5539
}
5540
5541
// Meshing has started (signaled by meshingThread):
5542
//-----------------------------------------------------------------------------
5543
void MainWindow::meshingStartedSlot() {
5544
logMessage("Mesh generator started");
5545
5546
updateSysTrayIcon("Mesh generator started",
5547
"Use Mesh->Terminate to stop processing");
5548
5549
statusBar()->showMessage(tr("Mesh generator started"));
5550
5551
progressBar->show();
5552
progressBar->setRange(0, 0);
5553
5554
progressLabel->show();
5555
progressLabel->setText("Meshing");
5556
}
5557
5558
// Meshing has been terminated (signaled by meshingThread):
5559
//-----------------------------------------------------------------------------
5560
void MainWindow::meshingTerminatedSlot() {
5561
logMessage("Mesh generator terminated");
5562
5563
progressBar->hide();
5564
progressBar->setRange(0, 100);
5565
5566
progressLabel->hide();
5567
5568
stopMeshingAct->setEnabled(true);
5569
5570
updateSysTrayIcon("Mesh generator terminated", "Use Mesh->Remesh to restart");
5571
5572
statusBar()->showMessage(tr("Ready"));
5573
5574
// clean up:
5575
if (activeGenerator == GEN_TETLIB) {
5576
cout << "Cleaning up...";
5577
out->deinitialize();
5578
cout << "done" << endl;
5579
cout.flush();
5580
}
5581
5582
if (activeGenerator == GEN_NGLIB) {
5583
nglib::Ng_DeleteMesh(ngmesh);
5584
nglib::Ng_Exit();
5585
}
5586
5587
remeshAct->setEnabled(true);
5588
stopMeshingAct->setEnabled(false);
5589
}
5590
5591
// Mesh is ready (signaled by meshingThread):
5592
//-----------------------------------------------------------------------------
5593
void MainWindow::meshingFinishedSlot() {
5594
logMessage("Mesh generation ready");
5595
5596
progressBar->hide();
5597
progressBar->setRange(0, 100);
5598
5599
progressLabel->hide();
5600
5601
if (activeGenerator == GEN_TETLIB) {
5602
5603
makeElmerMeshFromTetlib();
5604
5605
} else if (activeGenerator == GEN_NGLIB) {
5606
5607
this->ngmesh = meshingThread->getNgMesh();
5608
5609
makeElmerMeshFromNglib();
5610
5611
nglib::Ng_DeleteMesh(ngmesh);
5612
nglib::Ng_Exit();
5613
5614
} else {
5615
5616
logMessage("MeshOk: error: unknown mesh generator");
5617
}
5618
5619
applyOperations();
5620
5621
statusBar()->showMessage(tr("Ready"));
5622
5623
updateSysTrayIcon("Mesh generator has finished",
5624
"Select Model->Summary for statistics");
5625
5626
remeshAct->setEnabled(true);
5627
stopMeshingAct->setEnabled(false);
5628
5629
// Check cmd line arguments:
5630
//---------------------------
5631
QStringList args = QCoreApplication::arguments();
5632
5633
int output = args.indexOf("-o");
5634
5635
if (output > 0) {
5636
QString dirName = args.at(output + 1);
5637
5638
if (dirName.left(1) != "-") {
5639
cout << "Saving mesh files" << endl;
5640
saveElmerMesh(dirName);
5641
}
5642
}
5643
5644
if (args.contains("-e") || args.contains("-nogui")) {
5645
cout << "Exiting" << endl;
5646
QApplication::closeAllWindows();
5647
exit(0);
5648
}
5649
5650
resetSlot();
5651
}
5652
5653
// Mesh -> Divide surface...
5654
//-----------------------------------------------------------------------------
5655
void MainWindow::surfaceDivideSlot() {
5656
if (!glWidget->hasMesh()) {
5657
logMessage("There is nothing to divide - mesh is empty");
5658
return;
5659
}
5660
5661
boundaryDivide->target = TARGET_SURFACES;
5662
boundaryDivide->show();
5663
}
5664
5665
// Make surface division by sharp edges (signalled by boundaryDivide)...
5666
//-----------------------------------------------------------------------------
5667
void MainWindow::doDivideSurfaceSlot(double angle) {
5668
mesh_t *mesh = glWidget->getMesh();
5669
int lists = glWidget->getLists();
5670
5671
if (mesh == NULL) {
5672
logMessage("No mesh to divide");
5673
return;
5674
}
5675
5676
operations++;
5677
operation_t *p = new operation_t;
5678
operation_t *q = NULL;
5679
5680
for (q = &operation; q->next; q = q->next)
5681
;
5682
q->next = p;
5683
p->next = NULL;
5684
5685
p->type = OP_DIVIDE_SURFACE;
5686
p->angle = angle;
5687
5688
int selected = 0;
5689
5690
for (int i = 0; i < lists; i++) {
5691
list_t *l = glWidget->getList(i);
5692
5693
if (l->isSelected() && (l->getType() == SURFACELIST) &&
5694
(l->getNature() == PDE_BOUNDARY))
5695
selected++;
5696
}
5697
p->selected = selected;
5698
p->select_set = new int[selected];
5699
selected = 0;
5700
5701
for (int i = 0; i < lists; i++) {
5702
list_t *l = glWidget->getList(i);
5703
if (l->isSelected() && (l->getType() == SURFACELIST) &&
5704
(l->getNature() == PDE_BOUNDARY))
5705
p->select_set[selected++] = i;
5706
}
5707
5708
meshutils->findSharpEdges(mesh, angle);
5709
int parts = meshutils->divideSurfaceBySharpEdges(mesh);
5710
5711
QString qs = "Surface divided into " + QString::number(parts) + " parts";
5712
statusBar()->showMessage(qs);
5713
5714
synchronizeMenuToState();
5715
glWidget->rebuildLists();
5716
glWidget->updateGL();
5717
5718
// Added 05 September 2009
5719
boundaryPropertyEditor.clear();
5720
boundaryPropertyEditor.resize(parts);
5721
for (int i = 0; i < parts; i++)
5722
boundaryPropertyEditor[i] = new BoundaryPropertyEditor;
5723
}
5724
5725
// Mesh -> Unify surface
5726
//-----------------------------------------------------------------------------
5727
void MainWindow::surfaceUnifySlot() {
5728
mesh_t *mesh = glWidget->getMesh();
5729
int lists = glWidget->getLists();
5730
5731
if (mesh == NULL) {
5732
logMessage("No surfaces to unify");
5733
return;
5734
}
5735
5736
int targetindex = -1, selected = 0;
5737
QVector<BoundaryPropertyEditor *> unusedBoundary;
5738
for (int i = 0; i < lists; i++) {
5739
list_t *l = glWidget->getList(i);
5740
if (l->isSelected() && (l->getType() == SURFACELIST) &&
5741
(l->getNature() == PDE_BOUNDARY)) {
5742
selected++;
5743
if (targetindex < 0)
5744
targetindex = l->getIndex();
5745
else {
5746
int v = glWidget->boundaryMap.value(l->getIndex());
5747
if (v >= 0 && v < boundaryPropertyEditor.size() &&
5748
boundaryPropertyEditor[v] != NULL) {
5749
unusedBoundary.append(boundaryPropertyEditor[v]);
5750
}
5751
}
5752
}
5753
}
5754
5755
if (targetindex < 0) {
5756
logMessage("No surfaces selected");
5757
return;
5758
}
5759
5760
operations++;
5761
operation_t *p = new operation_t, *q;
5762
for (q = &operation; q->next; q = q->next)
5763
;
5764
q->next = p;
5765
p->next = NULL;
5766
p->type = OP_UNIFY_SURFACE;
5767
p->selected = selected;
5768
p->select_set = new int[selected];
5769
5770
selected = 0;
5771
for (int i = 0; i < lists; i++) {
5772
list_t *l = glWidget->getList(i);
5773
if (l->isSelected() && (l->getType() == SURFACELIST) &&
5774
(l->getNature() == PDE_BOUNDARY)) {
5775
p->select_set[selected++] = i;
5776
for (int j = 0; j < mesh->getSurfaces(); j++) {
5777
surface_t *s = mesh->getSurface(j);
5778
if ((s->getIndex() == l->getIndex()) &&
5779
(s->getNature() == PDE_BOUNDARY))
5780
s->setIndex(targetindex);
5781
}
5782
}
5783
}
5784
5785
for (int i = 0; i < unusedBoundary.size(); i++) {
5786
boundaryPropertyEditor.remove(
5787
boundaryPropertyEditor.indexOf(unusedBoundary[i]));
5788
delete unusedBoundary[i];
5789
}
5790
5791
cout << "Selected surfaces marked with index " << targetindex << endl;
5792
cout.flush();
5793
5794
glWidget->rebuildLists();
5795
5796
logMessage("Selected surfaces unified");
5797
}
5798
5799
void MainWindow::applyOperations() {
5800
mesh_t *mesh = glWidget->getMesh();
5801
5802
cout << "Apply " << operations << " operations" << endl;
5803
cout.flush();
5804
5805
operation_t *p = operation.next;
5806
for (; p; p = p->next) {
5807
int lists = glWidget->getLists();
5808
5809
for (int i = 0; i < lists; i++)
5810
glWidget->getList(i)->setSelected(false);
5811
5812
for (int j = 0; j < mesh->getSurfaces(); j++)
5813
mesh->getSurface(j)->setSelected(false);
5814
5815
for (int j = 0; j < mesh->getEdges(); j++)
5816
mesh->getEdge(j)->setSelected(false);
5817
5818
for (int i = 0; i < p->selected; i++) {
5819
list_t *l = glWidget->getList(p->select_set[i]);
5820
5821
l->setSelected(true);
5822
if (p->type < OP_UNIFY_EDGE) {
5823
for (int j = 0; j < mesh->getSurfaces(); j++) {
5824
surface_t *surf = mesh->getSurface(j);
5825
if (l->getIndex() == surf->getIndex())
5826
surf->setSelected(l->isSelected());
5827
}
5828
} else {
5829
for (int j = 0; j < mesh->getEdges(); j++) {
5830
edge_t *edge = mesh->getEdge(j);
5831
if (l->getIndex() == edge->getIndex())
5832
edge->setSelected(l->isSelected());
5833
}
5834
}
5835
}
5836
5837
if (p->type == OP_DIVIDE_SURFACE) {
5838
meshutils->findSharpEdges(mesh, p->angle);
5839
int parts = meshutils->divideSurfaceBySharpEdges(mesh);
5840
QString qs = "Surface divided into " + QString::number(parts) + " parts";
5841
statusBar()->showMessage(qs);
5842
5843
} else if (p->type == OP_DIVIDE_EDGE) {
5844
meshutils->findEdgeElementPoints(mesh);
5845
meshutils->findSharpPoints(mesh, p->angle);
5846
int parts = meshutils->divideEdgeBySharpPoints(mesh);
5847
QString qs = "Edges divided into " + QString::number(parts) + " parts";
5848
statusBar()->showMessage(qs);
5849
5850
} else if (p->type == OP_UNIFY_SURFACE) {
5851
int targetindex = -1;
5852
5853
for (int i = 0; i < lists; i++) {
5854
list_t *l = glWidget->getList(i);
5855
if (l->isSelected() && (l->getType() == SURFACELIST) &&
5856
(l->getNature() == PDE_BOUNDARY)) {
5857
if (targetindex < 0) {
5858
targetindex = l->getIndex();
5859
break;
5860
}
5861
}
5862
}
5863
for (int i = 0; i < lists; i++) {
5864
list_t *l = glWidget->getList(i);
5865
if (l->isSelected() && (l->getType() == SURFACELIST) &&
5866
(l->getNature() == PDE_BOUNDARY)) {
5867
for (int j = 0; j < mesh->getSurfaces(); j++) {
5868
surface_t *s = mesh->getSurface(j);
5869
if ((s->getIndex() == l->getIndex()) &&
5870
(s->getNature() == PDE_BOUNDARY))
5871
s->setIndex(targetindex);
5872
}
5873
}
5874
}
5875
cout << "Selected surfaces marked with index " << targetindex << endl;
5876
cout.flush();
5877
5878
} else if (p->type == OP_UNIFY_EDGE) {
5879
int targetindex = -1;
5880
for (int i = 0; i < lists; i++) {
5881
list_t *l = glWidget->getList(i);
5882
if (l->isSelected() && l->getType() == EDGELIST &&
5883
l->getNature() == PDE_BOUNDARY) {
5884
if (targetindex < 0) {
5885
targetindex = l->getIndex();
5886
break;
5887
}
5888
}
5889
}
5890
for (int i = 0; i < lists; i++) {
5891
list_t *l = glWidget->getList(i);
5892
if (l->isSelected() && l->getType() == EDGELIST &&
5893
l->getNature() == PDE_BOUNDARY) {
5894
for (int j = 0; j < mesh->getEdges(); j++) {
5895
edge_t *e = mesh->getEdge(j);
5896
if (e->getIndex() == l->getIndex() &&
5897
e->getNature() == PDE_BOUNDARY)
5898
e->setIndex(targetindex);
5899
}
5900
}
5901
}
5902
cout << "Selected edges marked with index " << targetindex << endl;
5903
cout.flush();
5904
}
5905
glWidget->rebuildLists();
5906
}
5907
5908
synchronizeMenuToState();
5909
glWidget->updateGL();
5910
5911
// Added 05 September 2009
5912
boundaryPropertyEditor.clear();
5913
int parts = glWidget->getLists();
5914
boundaryPropertyEditor.resize(parts);
5915
for (int i = 0; i < parts; i++)
5916
boundaryPropertyEditor[i] = new BoundaryPropertyEditor;
5917
}
5918
5919
// Mesh -> Divide edge...
5920
//-----------------------------------------------------------------------------
5921
void MainWindow::edgeDivideSlot() {
5922
if (!glWidget->hasMesh()) {
5923
logMessage("There is nothing to divide - mesh is empty");
5924
return;
5925
}
5926
5927
boundaryDivide->target = TARGET_EDGES;
5928
boundaryDivide->show();
5929
}
5930
5931
// Make edge division by sharp points (signalled by boundaryDivide)...
5932
//-----------------------------------------------------------------------------
5933
void MainWindow::doDivideEdgeSlot(double angle) {
5934
mesh_t *mesh = glWidget->getMesh();
5935
int lists = glWidget->getLists();
5936
5937
if (mesh == NULL) {
5938
logMessage("No mesh to divide");
5939
return;
5940
}
5941
5942
operations++;
5943
operation_t *p = new operation_t, *q;
5944
for (q = &operation; q->next; q = q->next)
5945
;
5946
q->next = p;
5947
p->next = NULL;
5948
5949
p->type = OP_DIVIDE_EDGE;
5950
p->angle = angle;
5951
5952
int selected = 0;
5953
for (int i = 0; i < lists; i++) {
5954
list_t *l = glWidget->getList(i);
5955
if (l->isSelected() && l->getType() == EDGELIST &&
5956
l->getNature() == PDE_BOUNDARY)
5957
selected++;
5958
}
5959
p->selected = selected;
5960
p->select_set = new int[selected];
5961
selected = 0;
5962
5963
for (int i = 0; i < lists; i++) {
5964
list_t *l = glWidget->getList(i);
5965
if (l->isSelected() && l->getType() == EDGELIST &&
5966
l->getNature() == PDE_BOUNDARY)
5967
p->select_set[selected++] = i;
5968
}
5969
5970
meshutils->findEdgeElementPoints(mesh);
5971
meshutils->findSharpPoints(mesh, angle);
5972
int parts = meshutils->divideEdgeBySharpPoints(mesh);
5973
5974
QString qs = "Edge divided into " + QString::number(parts) + " parts";
5975
statusBar()->showMessage(qs);
5976
5977
synchronizeMenuToState();
5978
glWidget->rebuildLists();
5979
glWidget->updateGL();
5980
5981
// Added 05 September 2009
5982
boundaryPropertyEditor.clear();
5983
boundaryPropertyEditor.resize(parts);
5984
for (int i = 0; i < parts; i++)
5985
boundaryPropertyEditor[i] = new BoundaryPropertyEditor;
5986
}
5987
5988
// Mesh -> Unify edge
5989
//-----------------------------------------------------------------------------
5990
void MainWindow::edgeUnifySlot() {
5991
mesh_t *mesh = glWidget->getMesh();
5992
int lists = glWidget->getLists();
5993
5994
if (mesh == NULL) {
5995
logMessage("No edges to unify");
5996
return;
5997
}
5998
5999
int targetindex = -1, selected = 0;
6000
QVector<BoundaryPropertyEditor *> unusedBoundary;
6001
for (int i = 0; i < lists; i++) {
6002
list_t *l = glWidget->getList(i);
6003
if (l->isSelected() && l->getType() == EDGELIST &&
6004
l->getNature() == PDE_BOUNDARY) {
6005
selected++;
6006
if (targetindex < 0)
6007
targetindex = l->getIndex();
6008
else {
6009
int v = glWidget->boundaryMap.value(l->getIndex());
6010
if (v >= 0 && v < boundaryPropertyEditor.size() &&
6011
boundaryPropertyEditor[v] != NULL) {
6012
unusedBoundary.append(boundaryPropertyEditor[v]);
6013
}
6014
}
6015
}
6016
}
6017
6018
if (targetindex < 0) {
6019
logMessage("No edges selected");
6020
return;
6021
}
6022
6023
operations++;
6024
operation_t *p = new operation_t, *q;
6025
for (q = &operation; q->next; q = q->next)
6026
;
6027
q->next = p;
6028
p->next = NULL;
6029
p->type = OP_UNIFY_EDGE;
6030
p->selected = selected;
6031
p->select_set = new int[selected];
6032
6033
selected = 0;
6034
6035
for (int i = 0; i < lists; i++) {
6036
list_t *l = glWidget->getList(i);
6037
if (l->isSelected() && l->getType() == EDGELIST &&
6038
l->getNature() == PDE_BOUNDARY) {
6039
p->select_set[selected++] = i;
6040
for (int j = 0; j < mesh->getEdges(); j++) {
6041
edge_t *e = mesh->getEdge(j);
6042
if (e->getIndex() == l->getIndex() && e->getNature() == PDE_BOUNDARY)
6043
e->setIndex(targetindex);
6044
}
6045
}
6046
}
6047
6048
for (int i = 0; i < unusedBoundary.size(); i++) {
6049
boundaryPropertyEditor.remove(
6050
boundaryPropertyEditor.indexOf(unusedBoundary[i]));
6051
delete unusedBoundary[i];
6052
}
6053
6054
cout << "Selected edges marked with index " << targetindex << endl;
6055
cout.flush();
6056
6057
glWidget->rebuildLists();
6058
6059
logMessage("Selected edges unified");
6060
}
6061
6062
// Mesh -> Clean up
6063
//-----------------------------------------------------------------------------
6064
void MainWindow::cleanHangingSharpEdgesSlot() {
6065
mesh_t *mesh = glWidget->getMesh();
6066
6067
if (mesh == NULL)
6068
return;
6069
6070
int count = meshutils->cleanHangingSharpEdges(mesh);
6071
6072
cout << "Removed " << count << " hanging sharp edges" << endl;
6073
cout.flush();
6074
6075
glWidget->rebuildLists();
6076
}
6077
6078
//*****************************************************************************
6079
//
6080
// Edit MENU
6081
//
6082
//*****************************************************************************
6083
6084
// Edit -> Sif...
6085
//-----------------------------------------------------------------------------
6086
void MainWindow::showsifSlot() {
6087
// QFont sansFont("Courier", 10);
6088
// sifWindow->getTextEdit()->setCurrentFont(sansFont);
6089
if(sifWindow->windowState() & Qt::WindowMinimized){
6090
sifWindow->showNormal();
6091
}
6092
else sifWindow->show();
6093
}
6094
6095
// Edit -> Generate sif
6096
//-----------------------------------------------------------------------------
6097
void MainWindow::generateSifSlot() {
6098
mesh_t *mesh = glWidget->getMesh();
6099
6100
if (mesh == NULL) {
6101
logMessage("Unable to create SIF: no mesh");
6102
return;
6103
}
6104
6105
if ((mesh->getDim() < 1) || (mesh->getCdim() < 1)) {
6106
logMessage("Model dimension inconsistent with SIF syntax");
6107
return;
6108
}
6109
6110
// Clear SIF text editor:
6111
//------------------------
6112
sifWindow->getTextEdit()->clear();
6113
sifWindow->setFirstTime(true);
6114
sifWindow->setFound(false);
6115
// QFont sansFont("Courier", 10);
6116
// sifWindow->getTextEdit()->setCurrentFont(sansFont);
6117
6118
// Set up SIF generator:
6119
//-----------------------
6120
sifGenerator->setMesh(mesh);
6121
sifGenerator->setTextEdit(sifWindow->getTextEdit());
6122
sifGenerator->setDim(mesh->getDim());
6123
sifGenerator->setCdim(mesh->getCdim());
6124
sifGenerator->setGeneralSetup(generalSetup);
6125
6126
sifGenerator->setEquationEditor(equationEditor);
6127
sifGenerator->setMaterialEditor(materialEditor);
6128
sifGenerator->setBodyForceEditor(bodyForceEditor);
6129
sifGenerator->setInitialConditionEditor(initialConditionEditor);
6130
sifGenerator->setBoundaryConditionEditor(boundaryConditionEditor);
6131
sifGenerator->setSolverParameterEditor(solverParameterEditor);
6132
sifGenerator->setBoundaryPropertyEditor(boundaryPropertyEditor);
6133
sifGenerator->setBodyPropertyEditor(bodyPropertyEditor);
6134
sifGenerator->setMeshControl(meshControl);
6135
sifGenerator->setElmerDefs(elmerDefs);
6136
sifGenerator->bodyMap = glWidget->bodyMap;
6137
sifGenerator->boundaryMap = glWidget->boundaryMap;
6138
6139
// Make SIF:
6140
//----------
6141
sifGenerator->makeHeaderBlock();
6142
sifGenerator->makeSimulationBlock();
6143
sifGenerator->makeConstantsBlock();
6144
sifGenerator->makeBodyBlocks();
6145
sifGenerator->makeEquationBlocks();
6146
sifGenerator->makeMaterialBlocks();
6147
sifGenerator->makeBodyForceBlocks();
6148
sifGenerator->makeInitialConditionBlocks();
6149
sifGenerator->makeBoundaryBlocks();
6150
}
6151
6152
// Boundary selected by double clicking (signaled by glWidget::select):
6153
//-----------------------------------------------------------------------------
6154
void MainWindow::boundarySelectedSlot(list_t *l, Qt::KeyboardModifiers modifiers) {
6155
QString qs;
6156
6157
if (l->getIndex() < 0) {
6158
statusBar()->showMessage("Ready");
6159
return;
6160
}
6161
6162
if (l->isSelected()) {
6163
if (l->getType() == SURFACELIST) {
6164
qs = "Selected surface " + QString::number(l->getIndex());
6165
} else if (l->getType() == EDGELIST) {
6166
qs = "Selected edge " + QString::number(l->getIndex());
6167
} else {
6168
qs = "Selected object " + QString::number(l->getIndex()) +
6169
" (type unknown)";
6170
}
6171
} else {
6172
if (l->getType() == SURFACELIST) {
6173
qs = "Unselected surface " + QString::number(l->getIndex());
6174
} else if (l->getType() == EDGELIST) {
6175
qs = "Unselected edge " + QString::number(l->getIndex());
6176
} else {
6177
qs = "Unselected object " + QString::number(l->getIndex()) +
6178
" (type unknown)";
6179
}
6180
}
6181
6182
logMessage(qs);
6183
6184
// Open bc property sheet for selected boundary:
6185
//-----------------------------------------------
6186
if (l->isSelected() && ((modifiers & Qt::AltModifier) || bcEditActive)) {
6187
6188
if (l->getNature() != PDE_BOUNDARY) {
6189
/*Ignore when double clicking a body of 2D geometry under boundary
6190
* selection mode*/
6191
raise();
6192
return;
6193
}
6194
6195
// renumbering:
6196
int n = glWidget->boundaryMap.value(l->getIndex());
6197
6198
if (n >= boundaryPropertyEditor.size()) {
6199
logMessage("Error: Boundary index mismatch");
6200
return;
6201
}
6202
6203
BoundaryPropertyEditor *boundaryEdit = boundaryPropertyEditor[n];
6204
populateBoundaryComboBoxes(boundaryEdit);
6205
6206
connect(boundaryEdit,
6207
SIGNAL(BoundaryAsABodyChanged(BoundaryPropertyEditor *, int)), this,
6208
SLOT(boundaryAsABodyChanged(BoundaryPropertyEditor *, int)));
6209
6210
if (boundaryEdit->touched) {
6211
boundaryEdit->ui.applyButton->setText("Update");
6212
// boundaryEdit->ui.discardButton->setText("Remove");
6213
boundaryEdit->ui.discardButton->setText("Cancel");
6214
boundaryEdit->ui.applyButton->setIcon(
6215
QIcon::fromTheme("view-refresh"));
6216
// boundaryEdit->ui.discardButton->setIcon(QIcon::fromTheme("list-remove"));
6217
boundaryEdit->ui.discardButton->setIcon(
6218
QIcon::fromTheme("dialog-error-round"));
6219
} else {
6220
boundaryEdit->ui.applyButton->setText("Add");
6221
boundaryEdit->ui.discardButton->setText("Cancel");
6222
boundaryEdit->ui.applyButton->setIcon(QIcon::fromTheme("list-add"));
6223
boundaryEdit->ui.discardButton->setIcon(
6224
QIcon::fromTheme("dialog-error-round"));
6225
}
6226
6227
boundaryEdit->setWindowTitle("Properties for boundary " +
6228
QString::number(l->getIndex()));
6229
boundaryEdit->show();
6230
boundaryEdit->raise();
6231
}
6232
6233
BodyPropertyEditor *bodyEdit = NULL;
6234
int current = -1, n = -1;
6235
6236
// boundary as a body treatment
6237
// ----------------------------
6238
if (l->isSelected() && (modifiers & Qt::ControlModifier)) {
6239
6240
// renumbering:
6241
int n = glWidget->boundaryMap.value(l->getIndex());
6242
6243
if (n >= boundaryPropertyEditor.size()) {
6244
logMessage("Error: Boundary index mismatch");
6245
return;
6246
}
6247
6248
BoundaryPropertyEditor *boundaryEdit = boundaryPropertyEditor[n];
6249
6250
if (!boundaryEdit) {
6251
cout << "MainWindow: Boundary index out of bounds" << endl;
6252
return;
6253
}
6254
6255
bodyEdit = boundaryEdit->bodyProperties;
6256
6257
if (bodyEdit) {
6258
6259
bodyEdit->setWindowTitle("Properties for body " +
6260
QString::number(current));
6261
6262
// if(bodyEdit->ui.nameEdit->text().trimmed().isEmpty())
6263
// bodyEdit->ui.nameEdit->setText("Body Property{Boundary " +
6264
// QString::number(n+1) + "}");
6265
bodyEdit->ui.nameEdit->setText("Body {Boundary " +
6266
QString::number(n + 1) + "}");
6267
}
6268
}
6269
6270
// Open body property sheet for selected body:
6271
//---------------------------------------------
6272
if ((glWidget->currentlySelectedBody >= 0) &&
6273
( (modifiers & Qt::ShiftModifier) || bodyEditActive)) {
6274
6275
current = glWidget->currentlySelectedBody;
6276
6277
cout << "Current selection uniquely determines body: " << current << endl;
6278
cout.flush();
6279
6280
// renumbering:
6281
n = glWidget->bodyMap.value(current);
6282
6283
if (n >= bodyPropertyEditor.size()) {
6284
logMessage("MainWindow: Body index out of bounds)");
6285
return;
6286
}
6287
6288
bodyEdit = bodyPropertyEditor[n];
6289
6290
if (!bodyEdit)
6291
cout << "MainWindow: Undetermined body index" << endl;
6292
6293
bodyEdit->setWindowTitle("Properties for body " + QString::number(current));
6294
6295
if (bodyEdit->ui.nameEdit->text().trimmed().isEmpty())
6296
bodyEdit->ui.nameEdit->setText("Body Property " + QString::number(n + 1));
6297
}
6298
6299
if (bodyEdit) {
6300
populateBodyComboBoxes(bodyEdit);
6301
6302
if (bodyEdit->touched) {
6303
bodyEdit->ui.applyButton->setText("Update");
6304
// bodyEdit->ui.discardButton->setText("Remove");
6305
bodyEdit->ui.discardButton->setText("Cancel");
6306
bodyEdit->ui.applyButton->setIcon(QIcon::fromTheme("view-refresh"));
6307
// bodyEdit->ui.discardButton->setIcon(QIcon::fromTheme("list-remove"));
6308
bodyEdit->ui.discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));
6309
} else {
6310
bodyEdit->ui.applyButton->setText("Add");
6311
bodyEdit->ui.discardButton->setText("Cancel");
6312
bodyEdit->ui.applyButton->setIcon(QIcon::fromTheme("list-add"));
6313
bodyEdit->ui.discardButton->setIcon(QIcon::fromTheme("dialog-error-round"));
6314
}
6315
6316
bodyEdit->show();
6317
bodyEdit->raise();
6318
}
6319
}
6320
6321
// Populate boundary editor's comboboxes:
6322
//---------------------------------------
6323
void MainWindow::populateBoundaryComboBoxes(BoundaryPropertyEditor *boundary) {
6324
boundary->disconnect(
6325
SIGNAL(BoundaryComboChanged(BoundaryPropertyEditor *, QString)));
6326
while (boundary && boundary->ui.boundaryConditionCombo &&
6327
boundary->ui.boundaryConditionCombo->count() > 0)
6328
boundary->ui.boundaryConditionCombo->removeItem(0);
6329
6330
int takethis = 1; //-1;
6331
int count = 1;
6332
boundary->ui.boundaryConditionCombo->insertItem(count++, "");
6333
6334
for (int i = 0; i < boundaryConditionEditor.size(); i++) {
6335
DynamicEditor *bcEdit = boundaryConditionEditor[i];
6336
if (bcEdit->menuAction != NULL) {
6337
const QString &name = bcEdit->nameEdit->text().trimmed();
6338
boundary->ui.boundaryConditionCombo->insertItem(count, name);
6339
if (boundary->condition == bcEdit)
6340
takethis = count;
6341
count++;
6342
}
6343
}
6344
connect(boundary,
6345
SIGNAL(BoundaryComboChanged(BoundaryPropertyEditor *, QString)), this,
6346
SLOT(boundaryComboChanged(BoundaryPropertyEditor *, QString)));
6347
6348
boundary->ui.boundaryConditionCombo->setCurrentIndex(takethis - 1);
6349
}
6350
6351
//-----------------------------------------------------------------------------
6352
void MainWindow::boundaryComboChanged(BoundaryPropertyEditor *b, QString text) {
6353
b->condition = 0;
6354
b->touched = false;
6355
6356
for (int i = 0; i < boundaryConditionEditor.size(); i++) {
6357
DynamicEditor *bc = boundaryConditionEditor[i];
6358
if (bc->ID >= 0) {
6359
if (bc->nameEdit->text().trimmed() == text) {
6360
b->condition = bc;
6361
b->touched = true;
6362
break;
6363
}
6364
}
6365
}
6366
}
6367
6368
//-----------------------------------------------------------------------------
6369
void MainWindow::boundaryAsABodyChanged(BoundaryPropertyEditor *b, int status) {
6370
int indx = glWidget->bodyMap.count();
6371
6372
if (status) {
6373
for (int i = 0; i < boundaryPropertyEditor.size(); i++)
6374
if (boundaryPropertyEditor[i] &&
6375
boundaryPropertyEditor[i]->bodyProperties)
6376
indx++;
6377
6378
if (indx >= bodyPropertyEditor.size()) {
6379
cout << "MainWindow: Body index out of bounds" << endl;
6380
return;
6381
}
6382
6383
if (bodyPropertyEditor[indx])
6384
b->bodyProperties = bodyPropertyEditor[indx];
6385
6386
} else {
6387
6388
b->bodyProperties = NULL;
6389
}
6390
}
6391
6392
// Populate body editor's comboboxes:
6393
//-----------------------------------
6394
void MainWindow::populateBodyComboBoxes(BodyPropertyEditor *bodyEdit) {
6395
// Equation:
6396
// =========
6397
bodyEdit->disconnect(
6398
SIGNAL(BodyEquationComboChanged(BodyPropertyEditor *, QString)));
6399
bodyEdit->ui.equationCombo->clear();
6400
6401
int count = 1;
6402
int takethis = 1; // -1
6403
bodyEdit->ui.equationCombo->insertItem(count++, "");
6404
6405
for (int i = 0; i < equationEditor.size(); i++) {
6406
DynamicEditor *eqEdit = equationEditor[i];
6407
if (eqEdit->menuAction != NULL) {
6408
const QString &name = eqEdit->nameEdit->text().trimmed();
6409
bodyEdit->ui.equationCombo->insertItem(count, name);
6410
if (bodyEdit->equation == eqEdit)
6411
takethis = count;
6412
count++;
6413
}
6414
}
6415
connect(bodyEdit,
6416
SIGNAL(BodyEquationComboChanged(BodyPropertyEditor *, QString)), this,
6417
SLOT(equationComboChanged(BodyPropertyEditor *, QString)));
6418
bodyEdit->ui.equationCombo->setCurrentIndex(takethis - 1);
6419
6420
// Material
6421
// =========
6422
bodyEdit->disconnect(
6423
SIGNAL(BodyMaterialComboChanged(BodyPropertyEditor *, QString)));
6424
bodyEdit->ui.materialCombo->clear();
6425
6426
count = 1;
6427
takethis = 1;
6428
bodyEdit->ui.materialCombo->insertItem(count, "");
6429
count++;
6430
6431
for (int i = 0; i < materialEditor.size(); i++) {
6432
DynamicEditor *matEdit = materialEditor[i];
6433
6434
if (matEdit->menuAction != NULL) {
6435
const QString &name = matEdit->nameEdit->text().trimmed();
6436
bodyEdit->ui.materialCombo->insertItem(count, name);
6437
if (bodyEdit->material == matEdit)
6438
takethis = count;
6439
count++;
6440
}
6441
}
6442
6443
connect(bodyEdit,
6444
SIGNAL(BodyMaterialComboChanged(BodyPropertyEditor *, QString)), this,
6445
SLOT(materialComboChanged(BodyPropertyEditor *, QString)));
6446
6447
bodyEdit->ui.materialCombo->setCurrentIndex(takethis - 1);
6448
6449
// Bodyforce:
6450
//===========
6451
bodyEdit->disconnect(
6452
SIGNAL(BodyForceComboChanged(BodyPropertyEditor *, QString)));
6453
bodyEdit->ui.bodyForceCombo->clear();
6454
6455
count = 1;
6456
takethis = 1; // -1
6457
bodyEdit->ui.bodyForceCombo->insertItem(count++, "");
6458
6459
for (int i = 0; i < bodyForceEditor.size(); i++) {
6460
DynamicEditor *bodyForceEdit = bodyForceEditor[i];
6461
if (bodyForceEdit->menuAction != NULL) {
6462
const QString &name = bodyForceEdit->nameEdit->text().trimmed();
6463
bodyEdit->ui.bodyForceCombo->insertItem(count, name);
6464
if (bodyEdit->force == bodyForceEdit)
6465
takethis = count;
6466
count++;
6467
}
6468
}
6469
connect(bodyEdit,
6470
SIGNAL(BodyForceComboChanged(BodyPropertyEditor *, QString)), this,
6471
SLOT(forceComboChanged(BodyPropertyEditor *, QString)));
6472
bodyEdit->ui.bodyForceCombo->setCurrentIndex(takethis - 1);
6473
6474
// Initial Condition:
6475
//====================
6476
bodyEdit->disconnect(
6477
SIGNAL(BodyInitialComboChanged(BodyPropertyEditor *, QString)));
6478
bodyEdit->ui.initialConditionCombo->clear();
6479
6480
count = 1;
6481
takethis = 1; // -1
6482
bodyEdit->ui.initialConditionCombo->insertItem(count++, "");
6483
6484
for (int i = 0; i < initialConditionEditor.size(); i++) {
6485
DynamicEditor *initialConditionEdit = initialConditionEditor[i];
6486
if (initialConditionEdit->menuAction != NULL) {
6487
const QString &name = initialConditionEdit->nameEdit->text().trimmed();
6488
bodyEdit->ui.initialConditionCombo->insertItem(count, name);
6489
if (bodyEdit->initial == initialConditionEdit)
6490
takethis = count;
6491
count++;
6492
}
6493
}
6494
connect(bodyEdit,
6495
SIGNAL(BodyInitialComboChanged(BodyPropertyEditor *, QString)), this,
6496
SLOT(initialComboChanged(BodyPropertyEditor *, QString)));
6497
bodyEdit->ui.initialConditionCombo->setCurrentIndex(takethis - 1);
6498
}
6499
6500
//-----------------------------------------------------------------------------
6501
void MainWindow::materialComboChanged(BodyPropertyEditor *b, QString text) {
6502
b->material = 0;
6503
b->touched = false;
6504
for (int i = 0; i < materialEditor.size(); i++) {
6505
DynamicEditor *mat = materialEditor[i];
6506
6507
if (mat->ID >= 0) {
6508
if (mat->nameEdit->text().trimmed() == text) {
6509
b->material = mat;
6510
b->touched = true;
6511
break;
6512
}
6513
}
6514
}
6515
}
6516
6517
//-----------------------------------------------------------------------------
6518
void MainWindow::initialComboChanged(BodyPropertyEditor *b, QString text) {
6519
b->initial = 0;
6520
b->touched = false;
6521
6522
for (int i = 0; i < initialConditionEditor.size(); i++) {
6523
DynamicEditor *ic = initialConditionEditor[i];
6524
if (ic->ID >= 0) {
6525
if (ic->nameEdit->text().trimmed() == text) {
6526
b->initial = ic;
6527
b->touched = true;
6528
break;
6529
}
6530
}
6531
}
6532
}
6533
6534
//-----------------------------------------------------------------------------
6535
void MainWindow::forceComboChanged(BodyPropertyEditor *b, QString text) {
6536
b->force = 0;
6537
b->touched = false;
6538
6539
for (int i = 0; i < bodyForceEditor.size(); i++) {
6540
DynamicEditor *bf = bodyForceEditor[i];
6541
if (bf->ID >= 0) {
6542
if (bf->nameEdit->text().trimmed() == text) {
6543
b->force = bf;
6544
b->touched = true;
6545
break;
6546
}
6547
}
6548
}
6549
}
6550
6551
//-----------------------------------------------------------------------------
6552
void MainWindow::equationComboChanged(BodyPropertyEditor *b, QString text) {
6553
b->equation = 0;
6554
b->touched = false;
6555
6556
for (int i = 0; i < equationEditor.size(); i++) {
6557
DynamicEditor *equ = equationEditor[i];
6558
if (equ->ID >= 0) {
6559
if (equ->nameEdit->text().trimmed() == text) {
6560
b->equation = equ;
6561
b->touched = true;
6562
break;
6563
}
6564
}
6565
}
6566
}
6567
6568
// Edit -> Definitions...
6569
//-----------------------------------------------------------------------------
6570
void MainWindow::editDefinitionsSlot() {
6571
if (elmerDefs == NULL)
6572
return;
6573
6574
edfEditor->show();
6575
}
6576
6577
//*****************************************************************************
6578
//
6579
// Solver MENU
6580
//
6581
//*****************************************************************************
6582
6583
// Solver -> Parallel settings
6584
//-----------------------------------------------------------------------------
6585
void MainWindow::parallelSettingsSlot() { parallel->show(); }
6586
6587
// Solver -> Run solver
6588
//-----------------------------------------------------------------------------
6589
void MainWindow::runsolverSlot() {
6590
if (!glWidget->hasMesh()) {
6591
logMessage("No mesh - unable to start solver");
6592
return;
6593
}
6594
6595
if (solver->state() == QProcess::Running) {
6596
logMessage("Solver is already running - returning");
6597
return;
6598
}
6599
6600
// Parallel solution:
6601
//====================
6602
Ui::parallelDialog ui = parallel->ui;
6603
bool parallelActive = ui.parallelActiveCheckBox->isChecked();
6604
bool partitioningActive = !ui.skipPartitioningCheckBox->isChecked();
6605
int nofProcessors = ui.nofProcessorsSpinBox->value();
6606
6607
if (parallelActive) {
6608
6609
// Set up log window:
6610
solverLogWindow->setWindowTitle(tr("Solver log"));
6611
solverLogWindow->getTextEdit()->clear();
6612
solverLogWindow->setFound(false);
6613
solverLogWindow->show();
6614
6615
if (!partitioningActive) {
6616
6617
// skip splitting:
6618
meshSplitterFinishedSlot(0);
6619
6620
} else {
6621
6622
// split mesh:
6623
if (meshSplitter->state() == QProcess::Running) {
6624
logMessage("Mesh partitioner is already running - aborted");
6625
return;
6626
}
6627
6628
if (saveDirName.isEmpty()) {
6629
logMessage("Please save the mesh before running the parallel solver - "
6630
"aborted");
6631
return;
6632
}
6633
6634
QString partitioningCommand = ui.divideLineEdit->text().trimmed();
6635
partitioningCommand.replace(QString("%msh"), saveDirName);
6636
partitioningCommand.replace(QString("%n"),
6637
QString::number(nofProcessors));
6638
6639
logMessage("Executing: " + partitioningCommand);
6640
6641
meshSplitter->start(partitioningCommand);
6642
6643
if (!meshSplitter->waitForStarted()) {
6644
logMessage("Unable to start ElmerGrid for mesh partitioning - aborted");
6645
return;
6646
}
6647
}
6648
6649
// the rest is done in meshSplitterFinishedSlot:
6650
return;
6651
}
6652
6653
// Scalar solution:
6654
//==================
6655
solver->start("ElmerSolver");
6656
killsolverAct->setEnabled(true);
6657
6658
if (!solver->waitForStarted()) {
6659
logMessage("Unable to start solver");
6660
return;
6661
}
6662
6663
solverLogWindow->setWindowTitle(tr("Solver log"));
6664
solverLogWindow->getTextEdit()->clear();
6665
solverLogWindow->setFound(false);
6666
solverLogWindow->show();
6667
6668
// convergence plot:
6669
#ifdef EG_QWT
6670
convergenceView->removeData();
6671
convergenceView->title = "Convergence history";
6672
#endif
6673
6674
logMessage("Solver started");
6675
6676
runsolverAct->setIcon(QIcon(":/icons/Solver-red.png"));
6677
6678
updateSysTrayIcon("ElmerSolver started",
6679
"Use Run->Kill solver to stop processing");
6680
}
6681
6682
// meshSplitter emits (int) when ready...
6683
//-----------------------------------------------------------------------------
6684
void MainWindow::meshSplitterFinishedSlot(int exitCode) {
6685
if (exitCode != 0) {
6686
solverLogWindow->getTextEdit()->append("MeshSplitter failed - aborting");
6687
logMessage("MeshSplitter failed - aborting");
6688
return;
6689
}
6690
6691
logMessage("MeshSplitter ready");
6692
6693
// Prepare for parallel solution:
6694
Ui::parallelDialog ui = parallel->ui;
6695
6696
int nofProcessors = ui.nofProcessorsSpinBox->value();
6697
6698
QString parallelExec = ui.parallelExecLineEdit->text().trimmed();
6699
#ifdef WIN32
6700
parallelExec = "\"" + parallelExec + "\"";
6701
#endif
6702
6703
QString parallelArgs = ui.parallelArgsLineEdit->text().trimmed();
6704
parallelArgs.replace(QString("%n"), QString::number(nofProcessors));
6705
6706
QString parallelCmd = parallelExec + " " + parallelArgs;
6707
6708
logMessage("Executing: " + parallelCmd);
6709
6710
solver->start(parallelCmd);
6711
killsolverAct->setEnabled(true);
6712
6713
if (!solver->waitForStarted()) {
6714
solverLogWindow->getTextEdit()->append("Unable to start parallel solver");
6715
logMessage("Unable to start parallel solver");
6716
return;
6717
}
6718
6719
// Set up convergence plot:
6720
#ifdef EG_QWT
6721
convergenceView->removeData();
6722
convergenceView->title = "Convergence history";
6723
#endif
6724
logMessage("Parallel solver started");
6725
runsolverAct->setIcon(QIcon(":/icons/Solver-red.png"));
6726
6727
updateSysTrayIcon("ElmerSolver started",
6728
"Use Run->Kill solver to stop processing");
6729
}
6730
6731
// meshSplitter emits (void) when there is something to read from stdout:
6732
//-----------------------------------------------------------------------------
6733
void MainWindow::meshSplitterStdoutSlot() {
6734
QString qs = meshSplitter->readAllStandardOutput();
6735
6736
while (qs.at(qs.size() - 1).unicode() == '\n')
6737
qs.chop(1);
6738
6739
solverLogWindow->getTextEdit()->append(qs);
6740
}
6741
6742
// meshSplitter emits (void) when there is something to read from stderr:
6743
//-----------------------------------------------------------------------------
6744
void MainWindow::meshSplitterStderrSlot() {
6745
QString qs = meshSplitter->readAllStandardError();
6746
6747
while (qs.at(qs.size() - 1).unicode() == '\n')
6748
qs.chop(1);
6749
6750
solverLogWindow->getTextEdit()->append(qs);
6751
}
6752
6753
// meshUnifier emits (int) when ready...
6754
//-----------------------------------------------------------------------------
6755
void MainWindow::meshUnifierFinishedSlot(int exitCode) {
6756
QStringList args;
6757
6758
if (exitCode != 0) {
6759
solverLogWindow->getTextEdit()->append("MeshUnifier failed - aborting");
6760
logMessage("MeshUnifier failed - aborting");
6761
vtkPostMeshUnifierRunning = false;
6762
return;
6763
}
6764
6765
logMessage("MeshUnifier ready");
6766
6767
// Prepare for post processing parallel results:
6768
//----------------------------------------------
6769
QString postName = generalSetup->ui.postFileEdit->text().trimmed();
6770
6771
// VtkPost:
6772
//---------
6773
#ifdef EG_VTK
6774
if (vtkPostMeshUnifierRunning) {
6775
vtkPost->show();
6776
6777
vtkPost->ReadPostFile(postName);
6778
// if(!vtkPost->ReadPostFile(postName)) vtkPost->readEpFileSlot();
6779
6780
vtkPostMeshUnifierRunning = false;
6781
return;
6782
}
6783
#endif
6784
6785
QFile file(postName);
6786
if (!file.exists()) {
6787
solverLogWindow->getTextEdit()->append(
6788
"Elmerpost input file does not exist.");
6789
logMessage("Elmerpost input file does not exist.");
6790
vtkPostMeshUnifierRunning = false;
6791
return;
6792
}
6793
6794
file.open(QIODevice::ReadOnly);
6795
QTextStream header(&file);
6796
6797
int nn, ne, nt, nf;
6798
QString type, name, tstep;
6799
6800
header >> nn >> ne >> nf >> nt >> type >> name;
6801
if (type == "vector:")
6802
name = name + "_abs";
6803
6804
file.close();
6805
6806
QString simtype =
6807
generalSetup->ui.simulationTypeCombo->currentText().trimmed();
6808
if (simtype.toLower() == "transient") {
6809
tstep = QString::number(1);
6810
} else {
6811
tstep = QString::number(nt);
6812
}
6813
6814
args << "readfile " + postName + " " + tstep + " " + tstep +
6815
"1; "
6816
"set ColorScaleY -0.85; "
6817
"set ColorScaleEntries 4;"
6818
"set ColorScaleDecimals 2;"
6819
"set ColorScaleColor " +
6820
name +
6821
";"
6822
"set DisplayStyle(ColorScale) 1; "
6823
"set MeshStyle 1; "
6824
"set MeshColor " +
6825
name +
6826
";"
6827
"set DisplayStyle(ColorMesh) 1; "
6828
"translate -y 0.2; "
6829
"UpdateObject; ";
6830
6831
post->start("ElmerPost", args);
6832
killresultsAct->setEnabled(true);
6833
6834
if (!post->waitForStarted()) {
6835
logMessage("Unable to start post processor");
6836
return;
6837
}
6838
6839
resultsAct->setIcon(QIcon(":/icons/Post-red.png"));
6840
6841
logMessage("Post processor started");
6842
6843
updateSysTrayIcon("ElmerPost started",
6844
"Use Run->Kill ElmerPost to stop processing");
6845
}
6846
6847
// meshUnifier emits (void) when there is something to read from stdout:
6848
//-----------------------------------------------------------------------------
6849
void MainWindow::meshUnifierStdoutSlot() {
6850
QString qs = meshUnifier->readAllStandardOutput();
6851
6852
while (qs.at(qs.size() - 1).unicode() == '\n')
6853
qs.chop(1);
6854
6855
solverLogWindow->getTextEdit()->append(qs);
6856
}
6857
6858
// meshUnifier emits (void) when there is something to read from stderr:
6859
//-----------------------------------------------------------------------------
6860
void MainWindow::meshUnifierStderrSlot() {
6861
QString qs = meshUnifier->readAllStandardError();
6862
6863
while (qs.at(qs.size() - 1).unicode() == '\n')
6864
qs.chop(1);
6865
6866
solverLogWindow->getTextEdit()->append(qs);
6867
}
6868
6869
// solver process emits (void) when there is something to read from stdout:
6870
//-----------------------------------------------------------------------------
6871
void MainWindow::solverStdoutSlot() {
6872
static QString qs_save = "";
6873
6874
QString qs = qs_save + solver->readAllStandardOutput();
6875
6876
int n = qs.lastIndexOf('\n');
6877
6878
if ((n > 0) && (n < qs.size() - 1)) {
6879
qs_save = qs.mid(n + 1);
6880
qs = qs.mid(0, n);
6881
6882
} else if (n == 0) {
6883
if (qs.size() == 1) {
6884
qs_save = "";
6885
return;
6886
}
6887
qs_save = qs.mid(1);
6888
return;
6889
6890
} else if (n < 0) {
6891
qs_save = qs;
6892
return;
6893
6894
} else
6895
qs_save = "";
6896
6897
while (qs.at(qs.size() - 1).unicode() == '\n')
6898
qs.chop(1);
6899
6900
if (qs.isEmpty())
6901
return;
6902
6903
solverLogWindow->getTextEdit()->append(qs);
6904
6905
#ifdef EG_QWT
6906
if (!showConvergence) {
6907
6908
// hide convergence plot
6909
//----------------------
6910
convergenceView->hide();
6911
6912
} else {
6913
6914
// show convergence plot
6915
//----------------------
6916
if (!convergenceView->isVisible())
6917
convergenceView->show();
6918
}
6919
#endif
6920
6921
QStringList qsl = qs.split("\n");
6922
for (int i = 0; i < qsl.count(); i++) {
6923
QString tmp = qsl.at(i).trimmed();
6924
6925
if (tmp.contains("Time:")) {
6926
QStringList tmpSplitted = tmp.split(" ");
6927
int last = tmpSplitted.count() - 1;
6928
QString timeString = tmpSplitted.at(last);
6929
double timeDouble = timeString.toDouble();
6930
#ifdef EG_QWT
6931
convergenceView->title =
6932
"Convergence history (time=" + QString::number(timeDouble) + ")";
6933
#endif
6934
}
6935
6936
if (tmp.contains("ComputeChange")) { // && tmp.contains("NS")) {
6937
QString copyOfTmp = tmp;
6938
6939
// check solver name:
6940
QStringList tmpSplitted = tmp.split(":");
6941
int last = tmpSplitted.count() - 1;
6942
QString name = tmpSplitted.at(last).trimmed();
6943
6944
// parse rest of the line:
6945
double res1 = 0.0;
6946
double res2 = 0.0;
6947
int n = tmp.indexOf("NRM,RELC");
6948
tmp = tmp.mid(n);
6949
tmpSplitted = tmp.split("(");
6950
6951
if (tmpSplitted.count() >= 2) {
6952
QString tmp2 = tmpSplitted.at(1).trimmed();
6953
QStringList tmp2Splitted = tmp2.split(" ");
6954
QString qs1 = tmp2Splitted.at(0).trimmed();
6955
res1 = qs1.toDouble();
6956
int pos = 1;
6957
// while(tmp2Splitted.at(pos).trimmed() == "") {
6958
while (tmp2Splitted.at(pos).trimmed().isEmpty()) {
6959
pos++;
6960
if (pos > tmp2Splitted.count())
6961
break;
6962
}
6963
QString qs2 = tmp2Splitted.at(pos).trimmed();
6964
res2 = max(qs2.toDouble(), 1.0e-16);
6965
}
6966
6967
// res1 = norm, res2 = relative change
6968
#ifdef EG_QWT
6969
if (copyOfTmp.contains("NS"))
6970
convergenceView->appendData(res2, "NS/" + name);
6971
6972
if (copyOfTmp.contains("SS"))
6973
convergenceView->appendData(res2, "SS/" + name);
6974
#endif
6975
}
6976
}
6977
}
6978
6979
// solver process emits (void) when there is something to read from stderr:
6980
//-----------------------------------------------------------------------------
6981
void MainWindow::solverStderrSlot() {
6982
QString qs = solver->readAllStandardError();
6983
6984
while (qs.at(qs.size() - 1).unicode() == '\n')
6985
qs.chop(1);
6986
6987
solverLogWindow->getTextEdit()->append(qs);
6988
}
6989
6990
// solver process emits (int) when ready...
6991
//-----------------------------------------------------------------------------
6992
void MainWindow::solverFinishedSlot(int) {
6993
logMessage("Solver ready");
6994
runsolverAct->setIcon(QIcon(":/icons/Solver.png"));
6995
updateSysTrayIcon(
6996
"ElmerSolver has finished",
6997
"Use Run->Start ElmerPost, ElmerVTK or Paraview to view results");
6998
killsolverAct->setEnabled(false);
6999
}
7000
7001
// solver process emits (QProcess::ProcessError) when error occurs...
7002
//-----------------------------------------------------------------------------
7003
void MainWindow::solverErrorSlot(QProcess::ProcessError error) {
7004
logMessage("Solver emitted error signal: " + QString::number(error));
7005
solver->kill();
7006
runsolverAct->setIcon(QIcon(":/icons/Solver.png"));
7007
}
7008
7009
// solver process emits (QProcess::ProcessState) when state changed...
7010
//-----------------------------------------------------------------------------
7011
void MainWindow::solverStateChangedSlot(QProcess::ProcessState state) {
7012
logMessage("Solver emitted signal: QProcess::ProcessState: " +
7013
QString::number(state));
7014
// solver->kill();
7015
// runsolverAct->setIcon(QIcon(":/icons/Solver.png"));
7016
}
7017
7018
// Solver -> Kill solver
7019
//-----------------------------------------------------------------------------
7020
void MainWindow::killsolverSlot() {
7021
solver->kill();
7022
7023
logMessage("Solver killed");
7024
runsolverAct->setIcon(QIcon(":/icons/Solver.png"));
7025
}
7026
7027
// Solver -> Show convergence
7028
//-----------------------------------------------------------------------------
7029
void MainWindow::showConvergenceSlot() {
7030
showConvergence = !showConvergence;
7031
synchronizeMenuToState();
7032
}
7033
7034
// Solver -> Run post process
7035
//-----------------------------------------------------------------------------
7036
void MainWindow::resultsSlot() {
7037
QStringList args;
7038
7039
if (post->state() == QProcess::Running) {
7040
logMessage("Post processor is already running");
7041
return;
7042
}
7043
7044
// Parallel solution:
7045
//====================
7046
Ui::parallelDialog ui = parallel->ui;
7047
bool parallelActive = ui.parallelActiveCheckBox->isChecked();
7048
7049
if (parallelActive) {
7050
7051
// unify mesh:
7052
if (meshUnifier->state() == QProcess::Running) {
7053
logMessage("Mesh unifier is already running - aborted");
7054
return;
7055
}
7056
7057
if (saveDirName.isEmpty()) {
7058
logMessage("saveDirName is empty - unable to locate result files");
7059
return;
7060
}
7061
7062
// Set up log window:
7063
solverLogWindow->setWindowTitle(tr("ElmerGrid log"));
7064
solverLogWindow->getTextEdit()->clear();
7065
solverLogWindow->setFound(false);
7066
solverLogWindow->show();
7067
7068
QString postName = generalSetup->ui.postFileEdit->text().trimmed();
7069
QStringList postNameSplitted = postName.split(".");
7070
int nofProcessors = ui.nofProcessorsSpinBox->value();
7071
7072
QString unifyingCommand = ui.mergeLineEdit->text().trimmed();
7073
unifyingCommand.replace(QString("%ep"), postNameSplitted.at(0).trimmed());
7074
unifyingCommand.replace(QString("%n"), QString::number(nofProcessors));
7075
7076
logMessage("Executing: " + unifyingCommand);
7077
7078
meshUnifier->start(unifyingCommand);
7079
7080
if (!meshUnifier->waitForStarted()) {
7081
solverLogWindow->getTextEdit()->append(
7082
"Unable to start ElmerGrid for mesh unification - aborted");
7083
logMessage("Unable to start ElmerGrid for mesh unification - aborted");
7084
return;
7085
}
7086
7087
// The rest is done in meshUnifierFinishedSlot:
7088
return;
7089
}
7090
7091
// Scalar solution:
7092
//==================
7093
QString postName = generalSetup->ui.postFileEdit->text().trimmed();
7094
QFile file(postName);
7095
if (!file.exists()) {
7096
logMessage("Elmerpost input file does not exist.");
7097
/*Even though input file does not exist, launch ElmerPost*/
7098
post->start("ElmerPost");
7099
killresultsAct->setEnabled(true);
7100
if (!post->waitForStarted()) {
7101
logMessage("Unable to start ElmerPost");
7102
return;
7103
}
7104
resultsAct->setIcon(QIcon(":/icons/Post-red.png"));
7105
7106
logMessage("ElmerPost started");
7107
7108
updateSysTrayIcon("ElmerPost started",
7109
"Elmerpost input file does not exist.");
7110
return;
7111
}
7112
7113
file.open(QIODevice::ReadOnly);
7114
QTextStream header(&file);
7115
7116
int nn, ne, nt, nf;
7117
QString type, name, tstep;
7118
7119
header >> nn >> ne >> nf >> nt >> type >> name;
7120
if (type == "vector:")
7121
name = name + "_abs";
7122
7123
file.close();
7124
7125
QString simtype =
7126
generalSetup->ui.simulationTypeCombo->currentText().trimmed();
7127
if (simtype.toLower() == "transient") {
7128
tstep = QString::number(1);
7129
} else {
7130
tstep = QString::number(nt);
7131
}
7132
7133
args << "readfile " + postName + " " + tstep + " " + tstep +
7134
" 1; "
7135
"set ColorScaleY -0.85; "
7136
"set ColorScaleEntries 4;"
7137
"set ColorScaleDecimals 2;"
7138
"set ColorScaleColor " +
7139
name +
7140
";"
7141
"set DisplayStyle(ColorScale) 1; "
7142
"set MeshStyle 1; "
7143
"set MeshColor " +
7144
name +
7145
";"
7146
"set DisplayStyle(ColorMesh) 1; "
7147
"translate -y 0.2; "
7148
"UpdateObject; ";
7149
7150
post->start("ElmerPost", args);
7151
killresultsAct->setEnabled(true);
7152
7153
if (!post->waitForStarted()) {
7154
logMessage("Unable to start ElmerPost");
7155
return;
7156
}
7157
7158
resultsAct->setIcon(QIcon(":/icons/Post-red.png"));
7159
7160
logMessage("ElmerPost started");
7161
7162
updateSysTrayIcon("ElmerPost started",
7163
"Use Run->Kill ElmerPost to stop processing");
7164
}
7165
7166
// Signal (int) emitted by postProcess when finished:
7167
//-----------------------------------------------------------------------------
7168
void MainWindow::postProcessFinishedSlot(int) {
7169
logMessage("ElmerPost finished");
7170
resultsAct->setIcon(QIcon(":/icons/Post.png"));
7171
updateSysTrayIcon("ElmerPost has finished",
7172
"Use Run->Start ElmerPost to restart");
7173
killresultsAct->setEnabled(false);
7174
}
7175
7176
// Signal (int) emitted by paraview when finished:
7177
//-----------------------------------------------------------------------------
7178
void MainWindow::paraviewProcessFinishedSlot(int) {
7179
logMessage("ParaView finished");
7180
updateSysTrayIcon("ParaView has finished",
7181
"Use Run->Start ParaView to restart");
7182
}
7183
7184
// Solver -> Kill post process
7185
//-----------------------------------------------------------------------------
7186
void MainWindow::killresultsSlot() {
7187
post->kill();
7188
7189
logMessage("Post process killed");
7190
resultsAct->setIcon(QIcon(":/icons/Post.png"));
7191
}
7192
7193
// Solver -> Compile...
7194
//-----------------------------------------------------------------------------
7195
void MainWindow::compileSolverSlot() {
7196
QString defaultDirName = getDefaultDirName();
7197
7198
QString fileName = QFileDialog::getOpenFileName(
7199
this, tr("Open source file"), defaultDirName, tr("F90 files (*.f90)"));
7200
7201
if (!fileName.isEmpty()) {
7202
QFileInfo fi(fileName);
7203
QString absolutePath = fi.absolutePath();
7204
QDir::setCurrent(absolutePath);
7205
} else {
7206
logMessage("Unable to open file: file name is empty");
7207
return;
7208
}
7209
7210
if (compiler->state() == QProcess::Running) {
7211
logMessage("Compiler is currently running");
7212
return;
7213
}
7214
7215
QStringList args;
7216
#ifdef WIN32
7217
args << "/C";
7218
args << "" + QString(qgetenv("ELMER_HOME")) + "\\bin\\elmerf90.bat";
7219
QString dllFileName;
7220
dllFileName = fileName.left(fileName.lastIndexOf(".")) + ".dll";
7221
args << "-o";
7222
args << dllFileName;
7223
#endif
7224
args << fileName;
7225
7226
#ifdef WIN32
7227
compiler->start("cmd.exe", args);
7228
#else
7229
logMessage("Run->compiler is currently not implemented on this platform");
7230
return;
7231
#endif
7232
7233
if (!compiler->waitForStarted()) {
7234
logMessage("Unable to start compiler");
7235
return;
7236
}
7237
7238
solverLogWindow->setWindowTitle(tr("Compiler log"));
7239
solverLogWindow->getTextEdit()->clear();
7240
solverLogWindow->setFound(false);
7241
solverLogWindow->show();
7242
solverLogWindow->statusBar()->showMessage("Compiling...");
7243
7244
logMessage("Compiling...");
7245
}
7246
7247
// compiler process emits (void) when there is something to read from stdout:
7248
//-----------------------------------------------------------------------------
7249
void MainWindow::compilerStdoutSlot() {
7250
QString qs = compiler->readAllStandardOutput();
7251
7252
while (qs.at(qs.size() - 1).unicode() == '\n')
7253
qs.chop(1);
7254
7255
solverLogWindow->getTextEdit()->append(qs);
7256
}
7257
7258
// compiler process emits (void) when there is something to read from stderr:
7259
//-----------------------------------------------------------------------------
7260
void MainWindow::compilerStderrSlot() {
7261
QString qs = compiler->readAllStandardError();
7262
7263
while (qs.at(qs.size() - 1).unicode() == '\n')
7264
qs.chop(1);
7265
7266
solverLogWindow->getTextEdit()->append(qs);
7267
}
7268
7269
// Signal (int) emitted by compiler when finished:
7270
//-----------------------------------------------------------------------------
7271
void MainWindow::compilerFinishedSlot(int) {
7272
logMessage("Ready");
7273
solverLogWindow->statusBar()->showMessage("Ready");
7274
solverLogWindow->getTextEdit()->append("Ready");
7275
}
7276
7277
//*****************************************************************************
7278
//
7279
// Help MENU
7280
//
7281
//*****************************************************************************
7282
7283
// About dialog...
7284
//-----------------------------------------------------------------------------
7285
7286
void MainWindow::showaboutSlot() {
7287
7288
QMessageBox msgBox(this);
7289
msgBox.setTextFormat(Qt::RichText);
7290
QIcon icon(windowIcon());
7291
msgBox.setIconPixmap( icon.pixmap(32));
7292
msgBox.setWindowTitle(tr("Information about ElmerGUI"));
7293
msgBox.setText(
7294
tr("<P>ElmerGUI is a preprocessor for two and "
7295
"three dimensional modeling with Elmer "
7296
"finite element software. The program "
7297
"uses elmergrid, nglib, and optionally tetlib, "
7298
"as finite element mesh generators:<BR>"
7299
"<A HREF='https://www.csc.fi/elmer/'>https://www.csc.fi/elmer/</A><BR>"
7300
"<A HREF='https://ngsolve.org/'>https://ngsolve.org/</A><BR>"
7301
"<A HREF='https://www.berlios.de/software/tetgen/'>https://www.berlios.de/software/tetgen/</A></P>"
7302
"<P>ElmerGUI uses the Qt Cross-Platform "
7303
"Application Framework by The Qt Company:<BR>"
7304
"<A HREF='https://www.qt.io/'>https://www.qt.io/</A></P>"
7305
#ifdef EG_VTK
7306
"<P>This version of ElmerGUI contains a built-in "
7307
"postprocessor based on the Visualization Toolkit "
7308
"(VTK):<BR>"
7309
"<A HREF='https://vtk.org/'>https://vtk.org/</A></P>"
7310
#endif
7311
7312
#ifdef EG_PARAVIEW
7313
"<P>This version of ElmerGUI has been linked "
7314
"against ParaView visualization software.<BR>"
7315
"<A HREF='https://www.paraview.org/'>https://www.paraview.org</A></P>"
7316
#endif
7317
7318
#ifdef EG_OCC
7319
"<P>This version of ElmerGUI has been compiled with "
7320
"the OpenCascade solids modeling library:<BR>"
7321
"<A HREF='https://www.opencascade.org/'>https://www.opencascade.org/</P>"
7322
#endif
7323
7324
#ifdef EG_QWT
7325
"<P>This version of ElmerGUI is based in part on the work of the Qwt project.<BR>"
7326
"<A HREF='http://qwt.sf.net'>http://qwt.sf.net</A></P>"
7327
#endif
7328
7329
#ifdef MPICH2
7330
"<P>The parallel solver of this package has been linked "
7331
"against the MPICH2 library v. 1.0.7 from Argonne "
7332
"national laboratory. In order to use the parallel "
7333
"solver, the MPICH2 runtime environment should be "
7334
"installed and configured on your system. For more "
7335
"details, see:<BR>"
7336
"<A HREF='https://www.mpich.org/'>https://www.mpich.org/</A></P>"
7337
#endif
7338
));
7339
msgBox.setInformativeText(
7340
tr("<P>The GPL-licensed source code of ElmerGUI is available "
7341
"from the git repository<BR>"
7342
"<A HREF='https://github.com/ElmerCSC/elmerfem/'>https://github.com/ElmerCSC/elmerfem/</A></P>"
7343
"<P>Written by Mikko Lyly, Saeki Takayuki, Juha Ruokolainen, "
7344
"Peter RÃ¥back and Sampo Sillanpaa 2008-2023</P>"
7345
"<P>Compiled on " __DATE__ "</P>"));
7346
msgBox.exec();
7347
}
7348
7349
void MainWindow::getStartedSlot() {
7350
QMessageBox msgBox(this);
7351
msgBox.setTextFormat(Qt::RichText);
7352
QIcon icon(windowIcon());
7353
msgBox.setIconPixmap( icon.pixmap(32));
7354
msgBox.setWindowTitle(tr("Get started with Elmer"));
7355
msgBox.setText(tr(
7356
"<P>"
7357
"GetStartedElmer.pdf contains instructions for Windows users, "
7358
"along with useful information for Linux users."
7359
"</P>"
7360
"<A HREF='//www.nic.funet.fi/index/elmer/doc/GetStartedElmer.pdf'>GetStartedElmer.pdf</A>"
7361
"<P>"
7362
"Download the full set of Elmer documentation from:"
7363
"</P>"
7364
"<A HREF='//www.nic.funet.fi/index/elmer/doc/'>//www.nic.funet.fi/index/elmer/doc/</A>"
7365
"<P>"
7366
"Be sure to review ElmerSolverManual.pdf and ElmerModelsManual.pdf<BR><BR>"
7367
"Youtube has videos about Elmer and Elmer Webinars"
7368
"</P>"
7369
"<A HREF='//www.youtube.com/@elmerfem'>Elmer Youtube Webinars and videos</A>"
7370
"<P>"
7371
"The Elmer users forum can be found at:"
7372
"</P>"
7373
"<A HREF='//http://www.elmerfem.org/forum/'>//http://www.elmerfem.org/forum/</A>"
7374
"<P>"
7375
"After having reviewed some of the above documents, and "
7376
"trying out a few of the tutorials, feel free to post questions on "
7377
"the forum. To help get answers in a timely fashion, be sure to "
7378
"post a minimal working example, including a sif file and "
7379
"geometry file. ElmerGUI project folders can be archived into zip "
7380
"files or gz files. The forum allows up to 3 attachments per "
7381
"post and up to 1 Megabyte per post.<BR><BR>"
7382
"Context Sensitive Help<BR><BR>"
7383
"Some of the ElmerGUI menu items have context sensitive help text. "
7384
"Look for the button labeled 'Whatis'. Clicking on the 'Whatis' button "
7385
"will turn the cursor into either a red 'not' symbol or a small "
7386
"question mark. Move the cursor around the window and if context "
7387
"help text is available for a data entry box, then the cursor will "
7388
"change from a red 'not' symbol into the small question mark. Single "
7389
"click the left mouse button inside the data entry box to display the help text.<BR>"
7390
"If the 'Whatis' button is not present in a menu window, then Qt also "
7391
"offers an alternate method, where after clicking into a data "
7392
"entry box, press 'shift F1'. If help text is available, then it will be displayed."
7393
"</P>"
7394
));
7395
msgBox.exec();
7396
}
7397
7398
7399
//*****************************************************************************
7400
//
7401
// Auxiliary non-menu items
7402
//
7403
//*****************************************************************************
7404
7405
// Log message...
7406
//-----------------------------------------------------------------------------
7407
void MainWindow::logMessage(QString message) {
7408
#if WITH_QT5 || WITH_QT6
7409
cout << string(message.toLatin1()) << endl;
7410
#else
7411
cout << string(message.toAscii()) << endl;
7412
#endif
7413
statusBar()->showMessage(message, 0);
7414
cout.flush();
7415
}
7416
7417
// Synchronize menu to GL glwidget state variables:
7418
//-----------------------------------------------------------------------------
7419
void MainWindow::synchronizeMenuToState() {
7420
// glwidget state variables:
7421
if (glWidget->stateDrawSurfaceMesh)
7422
hidesurfacemeshAct->setChecked(true);
7423
else
7424
hidesurfacemeshAct->setChecked(false);
7425
7426
if (glWidget->stateDrawVolumeMesh)
7427
hidevolumemeshAct->setChecked(true);
7428
else
7429
hidevolumemeshAct->setChecked(false);
7430
7431
if (glWidget->stateDrawSharpEdges)
7432
hidesharpedgesAct->setChecked(true);
7433
else
7434
hidesharpedgesAct->setChecked(false);
7435
7436
if (glWidget->stateFlatShade) {
7437
flatShadeAct->setChecked(true);
7438
smoothShadeAct->setChecked(false);
7439
} else {
7440
flatShadeAct->setChecked(false);
7441
smoothShadeAct->setChecked(true);
7442
}
7443
7444
if (glWidget->stateOrtho) {
7445
orthoAct->setChecked(true);
7446
perspectiveAct->setChecked(false);
7447
} else {
7448
orthoAct->setChecked(false);
7449
perspectiveAct->setChecked(true);
7450
}
7451
7452
if (glWidget->stateDrawSurfaceNumbers)
7453
showSurfaceNumbersAct->setChecked(true);
7454
else
7455
showSurfaceNumbersAct->setChecked(false);
7456
7457
if (glWidget->stateDrawEdgeNumbers)
7458
showEdgeNumbersAct->setChecked(true);
7459
else
7460
showEdgeNumbersAct->setChecked(false);
7461
7462
if (glWidget->stateDrawNodeNumbers)
7463
showNodeNumbersAct->setChecked(true);
7464
else
7465
showNodeNumbersAct->setChecked(false);
7466
7467
if (glWidget->stateDrawBoundaryIndex)
7468
showBoundaryIndexAct->setChecked(true);
7469
else
7470
showBoundaryIndexAct->setChecked(false);
7471
7472
if (glWidget->stateDrawBodyIndex)
7473
showBodyIndexAct->setChecked(true);
7474
else
7475
showBodyIndexAct->setChecked(false);
7476
7477
if (glWidget->stateDrawCoordinates)
7478
viewCoordinatesAct->setChecked(true);
7479
else
7480
viewCoordinatesAct->setChecked(false);
7481
7482
if (bodyEditActive)
7483
bodyEditAct->setChecked(true);
7484
else
7485
bodyEditAct->setChecked(false);
7486
7487
if (bcEditActive)
7488
bcEditAct->setChecked(true);
7489
else
7490
bcEditAct->setChecked(false);
7491
7492
if (showConvergence)
7493
showConvergenceAct->setChecked(true);
7494
else
7495
showConvergenceAct->setChecked(false);
7496
7497
if (glWidget->stateBcColors)
7498
showBoundaryColorAct->setChecked(true);
7499
else
7500
showBoundaryColorAct->setChecked(false);
7501
7502
if (glWidget->stateBodyColors)
7503
showBodyColorAct->setChecked(true);
7504
else
7505
showBodyColorAct->setChecked(false);
7506
7507
if (isFullScreen())
7508
viewFullScreenAct->setChecked(true);
7509
else
7510
viewFullScreenAct->setChecked(false);
7511
}
7512
7513
// Load definitions...
7514
//-----------------------------------------------------------------------------
7515
void MainWindow::loadDefinitions() {
7516
// Determine edf-file location and name:
7517
//--------------------------------------
7518
QString elmerGuiHome;
7519
7520
#ifdef __APPLE__DONTGO_HERE_TODO
7521
QString generalDefs = this->homePath + "/edf/edf.xml";
7522
#else
7523
QString generalDefs =
7524
QCoreApplication::applicationDirPath() +
7525
"/../share/ElmerGUI/edf/edf.xml"; // @TODO: fix path to share/ElmerGUI/edf
7526
7527
elmerGuiHome = QString(getenv("ELMERGUI_HOME"));
7528
7529
if (!elmerGuiHome.isEmpty())
7530
generalDefs = elmerGuiHome + "/edf/edf.xml";
7531
7532
// ML 5. August 2010
7533
generalDefs.replace('\\', '/');
7534
#endif
7535
7536
// Load general definitions file:
7537
//--------------------------------
7538
#if WITH_QT5 || WITH_QT6
7539
cout << "Load " << string(generalDefs.toLatin1()) << "... ";
7540
#else
7541
cout << "Load " << string(generalDefs.toAscii()) << "... ";
7542
#endif
7543
cout.flush();
7544
updateSplash("Loading general definitions...");
7545
7546
QFile file(generalDefs);
7547
7548
QString errStr;
7549
int errRow;
7550
int errCol;
7551
7552
if (!file.exists()) {
7553
7554
elmerDefs = NULL;
7555
QMessageBox::information(window(), tr("Edf loader: ") + generalDefs,
7556
tr("Definitions file does not exist"));
7557
return;
7558
7559
} else {
7560
7561
if (!elmerDefs->setContent(&file, true, &errStr, &errRow, &errCol)) {
7562
QMessageBox::information(window(), tr("Edf loader: ") + generalDefs,
7563
tr("Parse error at line %1, col %2:\n%3")
7564
.arg(errRow)
7565
.arg(errCol)
7566
.arg(errStr));
7567
file.close();
7568
return;
7569
7570
} else {
7571
7572
if (elmerDefs->documentElement().tagName() != "edf") {
7573
QMessageBox::information(window(), tr("Edf loader: ") + generalDefs,
7574
tr("This is not an edf file"));
7575
delete elmerDefs;
7576
file.close();
7577
return;
7578
}
7579
}
7580
}
7581
7582
edfEditor->setupEditor(elmerDefs);
7583
file.close();
7584
7585
cout << "done" << endl;
7586
cout.flush();
7587
7588
// load additional definitions:
7589
//-----------------------------
7590
#ifdef __APPLE__DONTGO_HERE_TODO
7591
QDirIterator iterator(homePath + "/edf", QDirIterator::Subdirectories);
7592
#else
7593
QString additionalEdfs =
7594
QCoreApplication::applicationDirPath() +
7595
"/../share/ElmerGUI/edf"; // @TODO: fix path to share/ElmerGUI/edf
7596
7597
if (!elmerGuiHome.isEmpty())
7598
additionalEdfs = elmerGuiHome + "/edf";
7599
7600
QDirIterator iterator(additionalEdfs, QDirIterator::Subdirectories);
7601
#endif
7602
7603
while (iterator.hasNext()) {
7604
QString fileName = iterator.next();
7605
7606
// ML 5. August 2010
7607
fileName.replace('\\', '/');
7608
7609
QFileInfo fileInfo(fileName);
7610
QString fileSuffix = fileInfo.suffix();
7611
7612
// The names "egini" and "egmaterials" are reserved, skip them:
7613
if (fileInfo.completeBaseName() == "egini")
7614
continue;
7615
7616
if (fileInfo.completeBaseName() == "egmaterials")
7617
continue;
7618
7619
if ((fileSuffix == "xml") && (fileName != generalDefs)) {
7620
7621
#if WITH_QT5 || WITH_QT6
7622
cout << "Load " << string(fileName.toLatin1()) << "... ";
7623
#else
7624
cout << "Load " << string(fileName.toAscii()) << "... ";
7625
#endif
7626
cout.flush();
7627
7628
updateSplash("Loading " + fileName + "...");
7629
7630
file.setFileName(fileName);
7631
7632
QDomDocument tmpDoc;
7633
tmpDoc.clear();
7634
7635
if (!tmpDoc.setContent(&file, true, &errStr, &errRow, &errCol)) {
7636
QMessageBox::information(window(), tr("Edf loader: ") + fileName,
7637
tr("Parse error at line %1, col %2:\n%3")
7638
.arg(errRow)
7639
.arg(errCol)
7640
.arg(errStr));
7641
file.close();
7642
return;
7643
7644
} else {
7645
7646
if (tmpDoc.documentElement().tagName() != "edf") {
7647
QMessageBox::information(window(), tr("Edf loader: ") + fileName,
7648
tr("This is not an edf file"));
7649
file.close();
7650
return;
7651
}
7652
}
7653
7654
// add new elements to the document
7655
QDomElement root = elmerDefs->documentElement();
7656
QDomElement tmpRoot = tmpDoc.documentElement();
7657
QDomElement element = tmpRoot.firstChildElement();
7658
7659
while (!element.isNull()) {
7660
root.appendChild(element);
7661
element = tmpRoot.firstChildElement();
7662
}
7663
7664
edfEditor->setupEditor(elmerDefs);
7665
7666
file.close();
7667
7668
cout << "done" << endl;
7669
cout.flush();
7670
}
7671
}
7672
7673
// Load qss:
7674
//-----------
7675
QString qssFileName = QCoreApplication::applicationDirPath() +
7676
"/elmergui.qss"; // @TODO: fix path to share/ElmerGUI
7677
7678
#ifdef __APPLE__
7679
qssFileName = homePath + "/elmergui.qss";
7680
#else
7681
if (!elmerGuiHome.isEmpty())
7682
qssFileName = elmerGuiHome + "/elmergui.qss";
7683
#endif
7684
7685
QFile qssFile(qssFileName);
7686
7687
if (qssFile.exists()) {
7688
cout << "Loading QSS style sheet... ";
7689
qssFile.open(QFile::ReadOnly);
7690
QString styleSheet = QLatin1String(qssFile.readAll());
7691
qssFile.close();
7692
qApp->setStyleSheet(styleSheet);
7693
cout << "done" << endl;
7694
}
7695
}
7696
7697
// Setup splash...
7698
//-----------------------------------------------------------------------------
7699
void MainWindow::setupSplash() {
7700
QStringList args = QCoreApplication::arguments();
7701
7702
if (args.contains("-nogui"))
7703
return;
7704
7705
if (egIni->isSet("splashscreen")) {
7706
pixmap.load(":/images/splash.png");
7707
splash.setPixmap(pixmap);
7708
splash.show();
7709
qApp->processEvents();
7710
}
7711
}
7712
7713
// Update splash...
7714
//-----------------------------------------------------------------------------
7715
void MainWindow::updateSplash(QString text) {
7716
QStringList args = QCoreApplication::arguments();
7717
7718
if (args.contains("-nogui"))
7719
return;
7720
7721
if (!egIni->isSet("splashscreen"))
7722
return;
7723
7724
if (splash.isVisible()) {
7725
splash.showMessage(text, Qt::AlignBottom);
7726
qApp->processEvents();
7727
}
7728
}
7729
7730
// Finalize splash...
7731
//-----------------------------------------------------------------------------
7732
void MainWindow::finalizeSplash() {
7733
if (!egIni->isSet("splashscreen"))
7734
return;
7735
7736
if (splash.isVisible())
7737
splash.finish(this);
7738
}
7739
7740
// Setup system tray icon...
7741
//-----------------------------------------------------------------------------
7742
void MainWindow::setupSysTrayIcon() {
7743
sysTrayIcon = NULL;
7744
7745
QStringList args = QCoreApplication::arguments();
7746
7747
if (args.contains("-nogui"))
7748
return;
7749
7750
if (!egIni->isSet("systrayicon"))
7751
return;
7752
7753
if (QSystemTrayIcon::isSystemTrayAvailable()) {
7754
sysTrayIcon = new QSystemTrayIcon(this);
7755
sysTrayIcon->setIcon(QIcon(":/icons/Mesh3D.png"));
7756
sysTrayIcon->setVisible(true);
7757
sysTrayIcon->setContextMenu(sysTrayMenu);
7758
}
7759
}
7760
7761
// Update system tray icon...
7762
//-----------------------------------------------------------------------------
7763
void MainWindow::updateSysTrayIcon(QString label, QString msg) {
7764
int duration = 3000;
7765
7766
QStringList args = QCoreApplication::arguments();
7767
7768
if (args.contains("-nogui"))
7769
return;
7770
7771
if (!sysTrayIcon)
7772
return;
7773
7774
if (!egIni->isSet("systraymessages"))
7775
return;
7776
7777
if (isFullScreen())
7778
return;
7779
7780
if (egIni->isPresent("systraymsgduration"))
7781
duration = egIni->value("systraymsgduration").toInt();
7782
7783
if (sysTrayIcon->supportsMessages())
7784
sysTrayIcon->showMessage(label, msg, QSystemTrayIcon::Information,
7785
duration);
7786
}
7787
7788
// Finalize system tray icon...
7789
//-----------------------------------------------------------------------------
7790
void MainWindow::finalizeSysTrayIcon() {}
7791
7792
// Get default open/save directory
7793
//-----------------------------------------------------------------------------
7794
QString MainWindow::getDefaultDirName() {
7795
QString defaultDirName = "";
7796
7797
#ifdef WIN32
7798
defaultDirName = egIni->value("win32defaultdir");
7799
#else
7800
#ifdef __APPLE__
7801
defaultDirName = egIni->value("macxdefaultdir");
7802
#else
7803
defaultDirName = egIni->value("unixdefaultdir");
7804
#endif
7805
#endif
7806
7807
if (!saveDirName.isEmpty())
7808
defaultDirName = saveDirName;
7809
7810
return defaultDirName;
7811
}
7812
7813
// Load settings
7814
//-----------------------------------------------------------------------------
7815
void MainWindow::loadSettings() {
7816
restoreGeometry(settings_value("mainWindow/geometry").toByteArray());
7817
sifWindow->restoreGeometry(
7818
settings_value("sifWindow/geometry").toByteArray());
7819
solverLogWindow->restoreGeometry(
7820
settings_value("solverLogWindow/geometry").toByteArray());
7821
7822
#ifdef EG_QWT
7823
convergenceView->restoreGeometry(
7824
settings_value("convergenceView/geometry").toByteArray());
7825
#endif
7826
7827
#ifdef EG_OCC
7828
cadView->restoreGeometry(settings_value("cadView/geometry").toByteArray());
7829
#endif
7830
7831
#ifdef EG_VTK
7832
vtkPost->restoreGeometry(settings_value("vtkPost/geometry").toByteArray());
7833
#endif
7834
7835
int n = settings_value("recentProject/n", 0).toInt();
7836
QString key = "recentProject/";
7837
char num[] = "0123456789";
7838
QString path;
7839
for (int i = n - 1; i >= 0; i--) {
7840
path = settings_value(key + num[i], "$").toString();
7841
if (path != "$")
7842
addRecentProject(path, false);
7843
}
7844
7845
if (settings_value("objectBrowser/show", true).toBool()) {
7846
objectBrowser = new ObjectBrowser(this);
7847
showObjectBrowserAct->setChecked(true);
7848
} else {
7849
objectBrowser = NULL;
7850
}
7851
7852
switch (settings_value("postProcessor/i", 0).toInt()){
7853
case 0: selectElmerPostSlot(); break;
7854
case 1: selectVtkPostSlot(); break;
7855
case 2: selectParaViewSlot(); break;
7856
}
7857
7858
saveDirName = settings_value("defaultDir/project", "").toString();
7859
// Color settings
7860
glWidget->backgroundColor = settings_value("color/background", glWidget->backgroundColor).value<QColor>();
7861
glWidget->surfaceColor = settings_value("color/surface", glWidget->surfaceColor).value<QColor>();
7862
glWidget->edgeColor = settings_value("color/edge", glWidget->edgeColor).value<QColor>();
7863
glWidget->surfaceMeshColor = settings_value("color/surfaceMesh", glWidget->surfaceMeshColor).value<QColor>();
7864
glWidget->sharpEdgeColor = settings_value("color/sharpEdge", glWidget->sharpEdgeColor).value<QColor>();
7865
glWidget->selectionColor = settings_value("color/selection", glWidget->selectionColor).value<QColor>();
7866
7867
synchronizeMenuToState();
7868
}
7869
7870
// Save settings
7871
//-----------------------------------------------------------------------------
7872
void MainWindow::saveSettings() {
7873
settings_setValue("mainWindow/geometry", saveGeometry());
7874
settings_setValue("sifWindow/geometry", sifWindow->saveGeometry());
7875
settings_setValue("solverLogWindow/geometry",
7876
solverLogWindow->saveGeometry());
7877
7878
#ifdef EG_QWT
7879
settings_setValue("convergenceView/geometry",
7880
convergenceView->saveGeometry());
7881
#endif
7882
7883
#ifdef EG_OCC
7884
settings_setValue("cadView/geometry", cadView->saveGeometry());
7885
#endif
7886
7887
#ifdef EG_VTK
7888
settings_setValue("vtkPost/geometry", vtkPost->saveGeometry());
7889
#endif
7890
7891
if (showObjectBrowserAct->isChecked() && objectBrowser != NULL) {
7892
settings_setValue("objectBrowser/show", true);
7893
} else {
7894
settings_setValue("objectBrowser/show", false);
7895
}
7896
7897
if(selectElmerPostAct->isChecked()){
7898
settings_setValue("postProcessor/i", 0);
7899
}else if(selectVtkPostAct->isChecked()){
7900
settings_setValue("postProcessor/i", 1);
7901
}else if(selectParaViewAct->isChecked()){
7902
settings_setValue("postProcessor/i", 2);
7903
}
7904
7905
settings_setValue("defaultDir/project", saveDirName);
7906
7907
// Commented out as restoring defaultEdfDir is not so useful
7908
// settings_setValue("defaultDir/edfEditor", edfEditor->defaultEdfDir());
7909
7910
// Color settings
7911
settings_setValue("color/background", glWidget->backgroundColor);
7912
settings_setValue("color/surface", glWidget->surfaceColor);
7913
settings_setValue("color/edge", glWidget->edgeColor);
7914
settings_setValue("color/surfaceMesh", glWidget->surfaceMeshColor);
7915
settings_setValue("color/sharpEdge", glWidget->sharpEdgeColor);
7916
settings_setValue("color/selection", glWidget->selectionColor);
7917
}
7918
7919
void MainWindow::addRecentProject(QString dir, bool bSaveToIni) {
7920
if (recentProject.indexOf(dir) != -1) {
7921
recentProject.removeAt(recentProject.indexOf(dir));
7922
}
7923
recentProject.prepend(dir);
7924
7925
int i = 0;
7926
7927
recentProjectsMenu->removeAction(recentProject0Act);
7928
recentProjectsMenu->removeAction(recentProject1Act);
7929
recentProjectsMenu->removeAction(recentProject2Act);
7930
recentProjectsMenu->removeAction(recentProject3Act);
7931
recentProjectsMenu->removeAction(recentProject4Act);
7932
recentProjectsMenu->removeAction(recentProject5Act);
7933
recentProjectsMenu->removeAction(recentProject6Act);
7934
recentProjectsMenu->removeAction(recentProject7Act);
7935
recentProjectsMenu->removeAction(recentProject8Act);
7936
recentProjectsMenu->removeAction(recentProject9Act);
7937
recentProjectsMenu->clear(); // just in case
7938
7939
if (i < 10 && i < recentProject.size()) {
7940
recentProject0Act->setText(recentProject.at(i));
7941
recentProjectsMenu->addAction(recentProject0Act);
7942
}
7943
i++;
7944
if (i < 10 && i < recentProject.size()) {
7945
recentProject1Act->setText(recentProject.at(i));
7946
recentProjectsMenu->addAction(recentProject1Act);
7947
}
7948
i++;
7949
if (i < 10 && i < recentProject.size()) {
7950
recentProject2Act->setText(recentProject.at(i));
7951
recentProjectsMenu->addAction(recentProject2Act);
7952
}
7953
i++;
7954
if (i < 10 && i < recentProject.size()) {
7955
recentProject3Act->setText(recentProject.at(i));
7956
recentProjectsMenu->addAction(recentProject3Act);
7957
}
7958
i++;
7959
if (i < 10 && i < recentProject.size()) {
7960
recentProject4Act->setText(recentProject.at(i));
7961
recentProjectsMenu->addAction(recentProject4Act);
7962
}
7963
i++;
7964
if (i < 10 && i < recentProject.size()) {
7965
recentProject5Act->setText(recentProject.at(i));
7966
recentProjectsMenu->addAction(recentProject5Act);
7967
}
7968
i++;
7969
if (i < 10 && i < recentProject.size()) {
7970
recentProject6Act->setText(recentProject.at(i));
7971
recentProjectsMenu->addAction(recentProject6Act);
7972
}
7973
i++;
7974
if (i < 10 && i < recentProject.size()) {
7975
recentProject7Act->setText(recentProject.at(i));
7976
recentProjectsMenu->addAction(recentProject7Act);
7977
}
7978
i++;
7979
if (i < 10 && i < recentProject.size()) {
7980
recentProject8Act->setText(recentProject.at(i));
7981
recentProjectsMenu->addAction(recentProject8Act);
7982
}
7983
i++;
7984
if (i < 10 && i < recentProject.size()) {
7985
recentProject9Act->setText(recentProject.at(i));
7986
recentProjectsMenu->addAction(recentProject9Act);
7987
}
7988
recentProjectsMenu->setEnabled(recentProject.size() > 0);
7989
7990
if (bSaveToIni) {
7991
int n = recentProject.size();
7992
if (n > 10)
7993
n = 10;
7994
settings_setValue("recentProject/n", n);
7995
QString key = "recentProject/";
7996
char num[] = "0123456789";
7997
for (int i = 0; i < n; i++) {
7998
settings_setValue(key + num[i], recentProject.at(i));
7999
}
8000
}
8001
}
8002
8003
void MainWindow::loadRecentProject0Slot() { loadProject(recentProject.at(0)); }
8004
8005
void MainWindow::loadRecentProject1Slot() { loadProject(recentProject.at(1)); }
8006
8007
void MainWindow::loadRecentProject2Slot() { loadProject(recentProject.at(2)); }
8008
8009
void MainWindow::loadRecentProject3Slot() { loadProject(recentProject.at(3)); }
8010
8011
void MainWindow::loadRecentProject4Slot() { loadProject(recentProject.at(4)); }
8012
8013
void MainWindow::loadRecentProject5Slot() { loadProject(recentProject.at(5)); }
8014
8015
void MainWindow::loadRecentProject6Slot() { loadProject(recentProject.at(6)); }
8016
8017
void MainWindow::loadRecentProject7Slot() { loadProject(recentProject.at(7)); }
8018
8019
void MainWindow::loadRecentProject8Slot() { loadProject(recentProject.at(8)); }
8020
8021
void MainWindow::loadRecentProject9Slot() { loadProject(recentProject.at(9)); }
8022
8023
bool MainWindow::loadExtraSolver(QString solverName) {
8024
8025
#ifdef __APPLE__DONTGO_HERE_TODO
8026
QString extraDirpath = this->homePath + "/edf-extra";
8027
#else
8028
QString extraDirPath =
8029
QCoreApplication::applicationDirPath() + "/../share/ElmerGUI/edf-extra";
8030
8031
QString elmerGuiHome = QString(getenv("ELMERGUI_HOME"));
8032
8033
if (!elmerGuiHome.isEmpty())
8034
extraDirPath = elmerGuiHome + "/edf-extra";
8035
8036
extraDirPath.replace('\\', '/');
8037
#endif
8038
8039
QString name;
8040
QDir extraDir(extraDirPath);
8041
QStringList nameFilters;
8042
nameFilters << "*.xml";
8043
QString message;
8044
QStringList fileNameList =
8045
extraDir.entryList(nameFilters, QDir::Files | QDir::Readable);
8046
for (int i = 0; i < fileNameList.size(); i++) {
8047
QFile file(extraDirPath + "/" + fileNameList.at(i));
8048
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
8049
QTextStream in(&file);
8050
while (!in.atEnd()) {
8051
QString line = in.readLine();
8052
if (line.indexOf("<PDE Name=") > 0) {
8053
line = in.readLine();
8054
while (line.indexOf("<Name>") == -1 && !in.atEnd())
8055
line = in.readLine();
8056
int i0 = line.indexOf("<Name>");
8057
if (i0 >= 0) {
8058
int i1 = line.indexOf("</Name>", i0 + 6);
8059
if (i1 > 0) {
8060
name = line.mid(i0 + 6, i1 - i0 - 6).trimmed();
8061
if (solverName.trimmed() == name) {
8062
file.close();
8063
8064
message =
8065
"Load " + extraDirPath + "/" + fileNameList.at(i) + "... ";
8066
#if WITH_QT5 || WITH_QT6
8067
cout << string(message.toLatin1());
8068
cout.flush();
8069
#else
8070
cout << string(message.toAscii());
8071
cout.flush();
8072
#endif
8073
8074
edfEditor->appendFrom(extraDirPath + "/" + fileNameList.at(i));
8075
8076
cout << "done" << endl;
8077
8078
return true;
8079
}
8080
}
8081
}
8082
}
8083
}
8084
8085
file.close();
8086
} else {
8087
logMessage(" failed to open " + fileNameList.at(i));
8088
return false;
8089
}
8090
}
8091
logMessage(" Extra solver " + solverName + " not found");
8092
return false;
8093
}
8094
8095
void MainWindow::checkAndLoadExtraSolvers(QFile *file) {
8096
QStringList loadedSolverName;
8097
QStringList unloadedSolverName;
8098
QDomElement root = elmerDefs->documentElement();
8099
QDomElement elem = root.firstChildElement("PDE");
8100
while (!elem.isNull()) {
8101
QDomElement pdeName = elem.firstChildElement("Name");
8102
loadedSolverName.append(pdeName.text().trimmed());
8103
elem = elem.nextSiblingElement();
8104
}
8105
8106
QString name;
8107
if (file->open(QIODevice::ReadOnly | QIODevice::Text)) {
8108
QTextStream in(file);
8109
while (!in.atEnd()) {
8110
QString line = in.readLine();
8111
int i0, i1;
8112
i0 = line.indexOf("<key>/");
8113
if (i0 >= 0) {
8114
i1 = line.indexOf("/", i0 + 7);
8115
if (i1 > 0) {
8116
name = line.mid(i0 + 6, i1 - i0 - 6);
8117
if (!loadedSolverName.contains(name)) {
8118
loadExtraSolver(name);
8119
8120
// update list (to avoid doubled loading - one solver file can
8121
// generate multiple tabs)
8122
loadedSolverName.clear();
8123
QDomElement root = elmerDefs->documentElement();
8124
QDomElement elem = root.firstChildElement("PDE");
8125
while (!elem.isNull()) {
8126
QDomElement pdeName = elem.firstChildElement("Name");
8127
loadedSolverName.append(pdeName.text().trimmed());
8128
elem = elem.nextSiblingElement();
8129
}
8130
}
8131
}
8132
}
8133
}
8134
} else {
8135
logMessage(" failed to open project file" + name);
8136
}
8137
8138
/*
8139
QString name;
8140
if (file->open(QIODevice::ReadOnly | QIODevice::Text)){
8141
QTextStream in(file);
8142
while (!in.atEnd()) {
8143
QString line = in.readLine();
8144
int i0, i1;
8145
i0=line.indexOf("<key>/");
8146
if( i0 >= 0){
8147
i1 = line.indexOf("/", i0+7);
8148
if(i1 > 0){
8149
name = line.mid(i0+6, i1-i0-6);
8150
if(!loadedSolverName.contains(name) &&
8151
!unloadedSolverName.contains(name) ){ unloadedSolverName.append(name);
8152
loadExtraSolver(name);
8153
}
8154
}
8155
}
8156
}
8157
}else{
8158
logMessage(" failed to open project file" + name);
8159
}
8160
*/
8161
}
8162
8163
QVariant MainWindow::settings_value(const QString &key,
8164
const QVariant &defaultValue) {
8165
QString oldElmerGuiIniFilePath =
8166
QCoreApplication::applicationDirPath() + "/ElmerGUI.ini";
8167
QString elmerGuiIniFilePath = QDir::homePath() + "/.elmergui";
8168
if (!QFile::exists(elmerGuiIniFilePath) &&
8169
QFile::exists(oldElmerGuiIniFilePath)) {
8170
elmerGuiIniFilePath = oldElmerGuiIniFilePath;
8171
}
8172
QSettings settings(elmerGuiIniFilePath, QSettings::IniFormat);
8173
return settings.value(key, defaultValue);
8174
}
8175
8176
void MainWindow::settings_setValue(const QString &key, const QVariant &value) {
8177
QString elmerGuiIniFilePath = QDir::homePath() + "/.elmergui";
8178
QSettings settings(elmerGuiIniFilePath, QSettings::IniFormat);
8179
settings.setValue(key, value);
8180
}
8181
8182
void MainWindow::saveAndRun(bool generateSif) {
8183
8184
//------- Save project -------//
8185
if (!glWidget->hasMesh()) {
8186
logMessage("Unable to save project: no mesh");
8187
return;
8188
}
8189
8190
QString projectDirName = currentProjectDirName;
8191
if (projectDirName.isEmpty()) {
8192
QString defaultDirName = getDefaultDirName();
8193
projectDirName = QFileDialog::getExistingDirectory(
8194
this, tr("Open directory to save project"), defaultDirName);
8195
8196
if (!projectDirName.isEmpty()) {
8197
logMessage("Project directory " + projectDirName);
8198
} else {
8199
logMessage("Unable to save project: directory undefined");
8200
return;
8201
}
8202
}
8203
8204
if(generateSif){ generateSifSlot();}
8205
8206
bool ret = saveProject(projectDirName);
8207
8208
//------- Run solver -------//
8209
if (ret) {
8210
runsolverSlot();
8211
}
8212
}
8213
8214
void MainWindow::generateAndSaveAndRunSlot() { saveAndRun(true); }
8215
8216
void MainWindow::closeEvent(QCloseEvent *event) {
8217
saveSettings();
8218
delete objectBrowser;
8219
}
8220
8221
void MainWindow::showObjectBrowserSlot() {
8222
if (showObjectBrowserAct->isChecked()) {
8223
delete objectBrowser; // just in case
8224
objectBrowser = new ObjectBrowser(this);
8225
} else {
8226
delete objectBrowser;
8227
objectBrowser = NULL;
8228
}
8229
}
8230
8231
void MainWindow::selectElmerPostSlot(){
8232
runPostProcessorAct->setText(tr("Start ElmerPost"));
8233
runPostProcessorAct->setIcon(QIcon(":/icons/Post.png"));
8234
runPostProcessorAct->setStatusTip(tr("Run ElmerPost for visualization"));
8235
runPostProcessorAct->disconnect();
8236
connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(resultsSlot()));
8237
selectElmerPostAct->setChecked(true);
8238
selectVtkPostAct->setChecked(false);
8239
selectParaViewAct->setChecked(false);
8240
}
8241
void MainWindow::selectVtkPostSlot(){
8242
runPostProcessorAct->setText(tr("Start ElmerVTK"));
8243
runPostProcessorAct->setIcon(QIcon(":/icons/Mesh3D.png"));
8244
runPostProcessorAct->setStatusTip(tr("Invokes VTK based ElmerGUI postprocessor"));
8245
runPostProcessorAct->disconnect();
8246
connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(showVtkPostSlot()));
8247
selectElmerPostAct->setChecked(false);
8248
selectVtkPostAct->setChecked(true);
8249
selectParaViewAct->setChecked(false);
8250
}
8251
void MainWindow::selectParaViewSlot(){
8252
runPostProcessorAct->setText(tr("Start ParaView"));
8253
runPostProcessorAct->setIcon(QIcon(":/icons/Paraview.png"));
8254
runPostProcessorAct->setStatusTip(tr("Invokes ParaView for visualization"));
8255
runPostProcessorAct->disconnect();
8256
connect(runPostProcessorAct, SIGNAL(triggered()), this, SLOT(showParaViewSlot()));
8257
selectElmerPostAct->setChecked(false);
8258
selectVtkPostAct->setChecked(false);
8259
selectParaViewAct->setChecked(true);
8260
}
8261
8262
void MainWindow::rebuildGLLists(){
8263
/*
8264
This function is assumed to be called from ObjectBrowser to avoid a problem of 3D surface
8265
mesh not shown correctly when project loading (typically, TemperatureGeneric sample)
8266
*/
8267
glWidget->rebuildLists();
8268
}
8269
8270