limited volume meshing to boundary layer only
[engrid-github.git] / src / libengrid / guimainwindow.h
blobd45a8fd13034a647b0afa14afc9873882ec502d9
1 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 // + +
3 // + This file is part of enGrid. +
4 // + +
5 // + Copyright 2008-2014 enGits GmbH +
6 // + +
7 // + enGrid is free software: you can redistribute it and/or modify +
8 // + it under the terms of the GNU General Public License as published by +
9 // + the Free Software Foundation, either version 3 of the License, or +
10 // + (at your option) any later version. +
11 // + +
12 // + enGrid 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 enGrid. If not, see <http://www.gnu.org/licenses/>. +
19 // + +
20 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
21 #ifndef mainwindow_H
22 #define mainwindow_H
24 #define VTK_USE_RENDERING
26 #ifdef DLL_EXPORT
27 #if defined(LIBENGRID_EXPORTS) || defined(libengrid_EXPORTS)
28 #define LIBENGRID_DLL __declspec(dllexport)
29 #else
30 #define LIBENGRID_DLL __declspec(dllimport)
31 #endif
32 #define CLASS_LIBENGRID_DLL LIBENGRID_DLL
33 #else
34 #define LIBENGRID_DLL
35 #define CLASS_LIBENGRID_DLL
36 #endif
38 #include <stdio.h>
40 #include <QMainWindow>
41 #include <QSettings>
42 #include <QLabel>
43 #include <QSet>
44 #include <QFileSystemWatcher>
45 #include <QMutex>
46 #include <QTimer>
47 #include <QDockWidget>
48 #include <QDomDocument>
49 #include <QProgressBar>
51 #include <vtkUnstructuredGrid.h>
52 #include <vtkActor.h>
53 #include <vtkPolyDataMapper.h>
54 #include <vtkGeometryFilter.h>
55 #include <vtkCubeAxesActor2D.h>
56 #include <vtkCellPicker.h>
57 #include <vtkPointPicker.h>
58 #include <vtkSphereSource.h>
59 #include <vtkTextActor.h>
60 #include <vtkVectorText.h>
61 #include <vtkFollower.h>
62 #include <vtkScalarBarActor.h>
63 #include <vtkLookupTable.h>
64 #include <vtkDataSetSurfaceFilter.h>
66 #include "ui_guimainwindow.h"
67 #include "vtkEgBoundaryCodesFilter.h"
68 #include "vtkEgExtractVolumeCells.h"
69 #include "egvtkobject.h"
70 #include "boundarycondition.h"
71 #include "volumedefinition.h"
72 #include "physicalboundarycondition.h"
73 #include "checksurfaceintegrity.h"
75 #include "cadinterface.h"
77 #include "openfoamcase.h"
78 #include "guitransform.h"
79 #include "solvertools.h"
80 #include "std_includes.h"
81 #include "fixcadgeometry.h"
82 #include "xmlhandler.h"
84 #include <QVTKOpenGLNativeWidget.h>
86 /**
87 * This is the main GUI class of enGrid.
89 class CLASS_LIBENGRID_DLL GuiMainWindow : public QMainWindow, public EgVtkObject
92 Q_OBJECT;
94 private: // attributes
96 XmlHandler* m_XmlHandler;
98 Ui::GuiMainWindow ui; ///< The user interface definition -- created by QtDesigner.
99 vtkUnstructuredGrid *m_Grid; ///< The current state of the grid that is being generated.
101 vtkRenderer *m_Renderer; ///< The VTK renderer object, used for visualising the grid
103 vtkActor* m_SurfaceActor;
104 vtkActor* m_TetraActor;
105 vtkActor* m_WedgeActor;
106 vtkActor* m_PyramidActor;
107 vtkActor* m_HexaActor;
108 vtkActor* m_PolyhedraActor;
110 vtkProperty* m_BackfaceProperty;
111 vtkLookupTable* m_LookupTable;
112 vtkScalarBarActor* m_LegendActor;
114 vtkPolyDataMapper* m_SurfaceMapper;
115 vtkPolyDataMapper* m_TetraMapper;
116 vtkPolyDataMapper* m_PyramidMapper;
117 vtkPolyDataMapper* m_WedgeMapper;
118 vtkPolyDataMapper* m_HexaMapper;
119 vtkPolyDataMapper* m_PolyhedraMapper;
121 double m_ColTetraR, m_ColTetraG, m_ColTetraB;
122 double m_ColPyraR, m_ColPyraG, m_ColPyraB;
123 double m_ColPrismR, m_ColPrismG, m_ColPrismB;
124 double m_ColHexR, m_ColHexG, m_ColHexB;
125 double m_ColPolyR, m_ColPolyG, m_ColPolyB;
126 double m_ColAR, m_ColAG, m_ColAB;
127 double m_ColBR, m_ColBG, m_ColBB;
129 vtkEgExtractVolumeCells *m_ExtrTetras;
130 vtkEgExtractVolumeCells *m_ExtrPyramids;
131 vtkEgExtractVolumeCells *m_ExtrWedges;
132 vtkEgExtractVolumeCells *m_ExtrHexes;
133 vtkEgExtractVolumeCells *m_ExtrPolyhedra;
135 vtkDataSetSurfaceFilter *m_TetraGeometry;
136 vtkDataSetSurfaceFilter *m_PyramidGeometry;
137 vtkDataSetSurfaceFilter *m_WedgeGeometry;
138 vtkDataSetSurfaceFilter *m_HexaGeometry;
139 vtkDataSetSurfaceFilter *m_PolyhedraGeometry;
141 vtkIdType m_PickedPoint; ///< Picked point
142 vtkIdType m_PickedCell; ///< Picked cell
143 bool m_UseVTKInteractor; ///< Boolean value specifying whether the VTK Interactor should be used or not
145 static QMutex m_Mutex;
147 vtkDataSetSurfaceFilter* m_SurfaceFilter; ///< VTK filter to extract the surface of the current grid.
148 double m_ReferenceSize; ///< Size to use for picker objects and annotations
150 vector <vtkTextActor*> m_NodeText; ///< 2D Text actor to display node IDs
151 vector <vtkTextActor*> m_CellText; ///< 2D Text actor to display cell IDs
152 vector <vtkVectorText*> m_NodeTextVectorText; ///< 3D Text actor to display node IDs
153 vector <vtkPolyDataMapper*> m_NodeTextPolyDataMapper;
154 vector <vtkFollower*> m_NodeTextFollower;
155 vector <vtkVectorText*> m_CellTextVectorText; ///< 3D Text actor to display cell IDs
156 vector <vtkPolyDataMapper*> m_CellTextPolyDataMapper;
157 vector <vtkFollower*> m_CellTextFollower;
159 vtkPolyDataMapper* m_PickMapper; ///< VTK mapper to map pick marker
160 vtkActor* m_PickActor; ///< VTK actor to display pick marker
161 vtkSphereSource* m_PickSphere; ///< sphere to mark picked cell/points
162 vtkCubeAxesActor2D* m_Axes; ///< VTK actor to display the coordinate system
163 vtkEgBoundaryCodesFilter* m_BCodesFilter; ///< VTK filter to extract boundary elements with certain codes
164 vtkCellPicker* m_CellPicker; ///< VTK CellPicker to pick cells for various user interactions
165 vtkPointPicker* m_PointPicker; ///< VTK PointPicker to pick points for various user interactions
166 int m_PickedObject; ///< 0=none, 1=node, 2=cell
168 QString m_CurrentFilename; ///< The current file name of the grid.
169 int m_CurrentOperation; ///< The current operation number. (used for undo/redo)
170 bool m_undo_redo_enabled; ///< if true, undo/redo operations will be usable.
171 int m_LastOperation; ///< The last operation number. (used for undo/redo)
172 QLabel* m_StatusLabel; ///< Label for the information in the status bar
173 QLabel* m_StatusInfoLabel;
174 QProgressBar* m_StatusProgressBar;
175 QSet<int> m_DisplayBoundaryCodes; ///< A QList with all active boundary codes.
176 QSet<int> m_AllBoundaryCodes; ///< A QList with all boundary codes.
177 bool m_Busy; ///< flag to indicate that enGrid is busy with an operation
179 stringbuf m_CoutBuffer;
180 streambuf *m_OriginalCoutBuffer;
182 QTimer m_GarbageTimer;
183 QTimer m_LogTimer;
184 bool m_Log;
186 QMap<int, BoundaryCondition> m_bcmap; ///< mapping between numerical and symbolic boundary codes
187 QMap<QString, VolumeDefinition> m_VolMap; ///< all volume definitions
188 QMap<QString, PhysicalBoundaryCondition> m_PhysicalBoundaryConditionsMap; ///< all physical boundary conditions definitions
190 QMap<int, CadInterface*> m_CadInterfaces; ///< all CAD interfaces
191 CadInterface* m_UniCadInterface; ///< universal CAD interface for all boundary conditions
193 QMap<QAction*, Operation*> m_PluginOperations;
194 QAction* m_EscAction;
196 int m_SolverIndex;// deprecated
197 SolverTools m_OpenFoamTools;
199 // recent file list support
200 private:
201 QMap<QString,QDateTime> m_RecentFiles;
202 QMenu* recentFileMenu() { return ui.menuOpen_recent; }
203 void readRecentFiles();
204 void writeRecentFiles();
205 void addRecentFile(QString file_name, QDateTime date);
206 private slots:
207 void openRecent(QAction *action);
209 public:
210 void resetXmlDoc();
212 private: // static attributes
215 * Platform independant access to application settings.
216 * For a UNIX system the user preferences will be stored in the file
217 * folder ".config/enGits/enGrid.conf" in the user's home directory;
218 * on Windows preferences will be stored in the registry.
220 static QSettings m_qset;
223 * The current working directory of enGrid
225 static QString m_cwd;
228 * Is the current case unsaved?
230 static bool m_UnSaved;
232 /** a static this pointer (somewhat ugly, but there is only one MainWindow) */
233 static GuiMainWindow* THIS;
235 private: // methods
237 void setupVtk();
238 static void pickCallBack( vtkObject *caller, unsigned long int eid, void *clientdata, void *calldata );
239 void updateSurfaceActors( bool forced );
240 void updateVolumeActors( bool forced );
242 private slots:
244 void setClipX( const QString &txt );
245 void setClipY( const QString &txt );
246 void setClipZ( const QString &txt );
247 void setClipNX( const QString &txt );
248 void setClipNY( const QString &txt );
249 void setClipNZ( const QString &txt );
251 void openBC();
252 void saveBC();
254 void openPhysicalBoundaryConditions();
255 void savePhysicalBoundaryConditions();
257 void openGrid(QString file_name);
259 void pluginCalled();
260 void onEsc();
262 public: // methods
263 GuiMainWindow();///< Default constructor.
264 GuiMainWindow(QString file_name);///< Constructor which opens a file directly.
266 private:
268 * This function connects the menu and toolbar actions and
269 * the VTK basics(i.e. renderer, actor, ...) will be set up.
270 * Furthermore preferences will be read from qset.
272 void setupGuiMainWindow();
273 bool m_open_last;
275 public:
277 * Preferences will be written back.
279 virtual ~GuiMainWindow();
282 * Get the VTK render window
283 * @return the VTK render window
285 vtkRenderWindow* getRenderWindow();
288 * Get the VTK renderer
289 * @return the VTK renderer
291 vtkRenderer* getRenderer();
294 * Get the Qt-VTK interactor
295 * @return the Qt-VTK interactor
297 QVTKInteractor* getInteractor();
300 * Get a pointer to the current grid object
301 * @return a pointer to the current vtkUnstructuredGrid object
303 vtkUnstructuredGrid* getGrid() { return m_Grid; }
305 void setBusy() { m_Busy = true; updateStatusBar(); }
306 void setIdle() { m_Busy = false; updateStatusBar(); }
308 /// Returns the path to the currently loaded file
309 QString getFilePath();
311 /// Returns the index of the solver to use. The index corresponds to the position in solvers.txt .
312 void setSolverIndex(int x) {m_SolverIndex = x;}
313 int getSolverIndex() {return m_SolverIndex;}
315 public: // static methods
318 * Get the current working directory.
319 * @return the current working directory
321 static QString getCwd();
324 * Set the current working directory
325 * @param dir the current working directory
327 static void setCwd( QString dir );
330 * Set m_UnSaved.
331 * @param unsaved Do you want to be asked where to save when clicking on save next time?
333 static void setUnsaved( bool unsaved );
336 * Get the currently picked cell.
337 * @return the picked cell ID or -1 if no cell has been picked
339 vtkIdType getPickedCell();
342 * Get the currently picked point.
343 * @return the picked point ID or -1 if no point has been picked
345 vtkIdType getPickedPoint();
347 vtkIdType getPickedObject() { return m_PickedObject; }
350 * Access to the QSettings object
352 static QSettings* settings() { return &m_qset; }
354 BoundaryCondition getBC(int bc) { return m_bcmap[bc]; }
355 BoundaryCondition getBC(BoundaryCondition BC);
356 VolumeDefinition getVol( QString volname ) { return m_VolMap[volname]; }
357 void clearBCs() { m_bcmap.clear(); }
358 void setBC(int bc, BoundaryCondition BC) { BC.setCode(bc); m_bcmap[bc] = BC; }
360 QList<VolumeDefinition> getAllVols();
361 void setAllVols( QList<VolumeDefinition> vols );
362 void createDefaultVol();
364 QList<PhysicalBoundaryCondition> getAllPhysicalBoundaryConditions();
365 void setAllPhysicalBoundaryConditions (QList<PhysicalBoundaryCondition> physical_boundary_conditions);
366 void setAllPhysicalBoundaryConditions (QMap<QString, PhysicalBoundaryCondition> physical_boundary_conditions);
367 bool physicalTypeDefined(QString name) { return m_PhysicalBoundaryConditionsMap.contains(name); }
368 PhysicalBoundaryCondition getPhysicalBoundaryCondition(QString name) { return m_PhysicalBoundaryConditionsMap[name]; }
370 static GuiMainWindow* pointer() { return THIS; }
371 static void lock();
372 static void unlock();
373 static bool tryLock();
374 void getAllBoundaryCodes(QVector<int> &bcs);
375 QSet<int> getAllBoundaryCodes();
376 void getDisplayBoundaryCodes(QSet<int> &bcs);
377 vtkPointPicker* getPointPicker() { return ( m_PointPicker );}
378 vtkSphereSource* getPickSphere() { return ( m_PickSphere );}
379 bool pickPoint( vtkIdType id_point );
380 bool pickCell( vtkIdType id_cell );
382 QString getFilename() { return( m_CurrentFilename ); }
383 void setFilename(QString filename) { m_CurrentFilename = filename; }
385 CadInterface* getCadInterface(int bc, bool allow_null = false);
386 void setCadInterface(CadInterface* cad_interface, int bc) { m_CadInterfaces[bc] = cad_interface; }
387 void setUniversalCadInterface(CadInterface* cad_interface);
388 bool checkCadInterfaces();
390 void resetProgress(QString info_text, int p_max);
391 void setProgress(int p);
393 public slots:
395 void setUseVTKInteractor( int a_UseVTKInteractor );
396 void setPickMode( bool a_UseVTKInteractor, bool a_CellPickerMode );
398 void exit(); ///< Exit the application
399 void importSTL(); ///< Import an STL file (ASCII or binary)
400 void importGmsh1Ascii(); ///< Import a Gmsh grid from an ASCII file -- using version 1.0 of the Gmsh file format
401 void exportGmsh1Ascii(); ///< Export a grid from to an ASCII Gmsh file -- using version 1.0 of the Gmsh file format
402 void importGmsh2Ascii(); ///< Import a Gmsh grid from an ASCII file -- using version 2.0 of the Gmsh file format
403 void exportGmsh2Ascii(); ///< Export a grid from to an ASCII Gmsh file -- using version 2.0 of the Gmsh file format
404 void exportNeutral(); ///< Export a grid to neutral format for NETGEN
405 void updateActors( bool force = false ); ///< Update the VTK output
406 void forceUpdateActors(); ///< Force an update of the VTK output
407 void scaleToData(); ///< Scale to data
408 void zoomAll(); ///< Move the camera in order to show everything on the screen
409 void zoomOnPickedObject();
410 void deselectAll();
411 void printGrid() {cout << "PrintGrid() called!" << endl; cout_grid( cout, m_Grid, true, true, true, true );}
412 void info();
414 void undo();
415 void redo();
417 void resetOperationCounter();
419 void open(); ///< Open an existing case
420 void open( QString file_name, bool update_current_filename = true ); ///< Open case file_name
421 void save(); ///< Save the current case
422 void saveAs(); ///< Save the current case -- using a different file name
423 QString saveAs( QString file_name, bool update_current_filename = true ); ///< Save the current case as file_name. Returns name under which file was saved (with missing .egc extension for example).
425 int quickSave(); ///< Save the current grid as a_filename_a_operation
426 void quickLoad( int a_operation ); ///< Load a_filename_a_operation
427 void updateStatusBar(); ///< Update the status bar
428 void selectBoundaryCodes(); ///< Select the boundary codes to be displayed/hidden
429 void updateBoundaryCodes( bool all_on ); ///< Update the boundary code book keeping (e.g. after reading a mesh).
430 void normalExtrusion(); ///< Normal extrusion of boundary elements (no validity check).
431 void setAxesVisibility(); ///< Toggle the visibility of the axes annotation.
432 void setViewingMode(); ///< Toggle orthogonal viewing mode.
433 void viewNodeIDs(); ///< Toggle node ID viewing mode.
434 void viewCellIDs(); ///< Toggle cell ID viewing mode.
435 void changeSurfaceOrientation(); ///< Change the orientation of all surface elements
436 void checkSurfaceOrientation(); ///< Check and, if required, change the orientation of all surface elements
437 void improveAspectRatio(); ///< Eliminate edges in order to improve the aspect ratio of the cells
438 void exportAsciiStl(); ///< Write surface elements to an ASCII STL file.
439 void exportBinaryStl(); ///< Write surface elements to a binary STL file.
440 void exportAsciiPly(); ///< Write surface elements to an ASCII PLY file.
441 void exportBinaryPly(); ///< Write surface elements to a binary PLY file.
442 void editBoundaryConditions(); ///< Edit boundary conditions (names and types)
443 void configure(); ///< Edit settings
444 void about(); ///< Display an about message
445 void markOutputLine(); ///< Mark the current position in the output window
447 QString getXmlSection( QString name ); ///< Get a section from the XML case description
448 void setXmlSection( QString name, QString contents ); ///< Set a section of the XML case description
450 void viewRight();
451 void viewLeft();
452 void viewTop();
453 void viewBottom();
454 void viewFront();
455 void viewBack();
457 void appendOutput( QString txt ) { ui.textEditOutput->append( txt ); }
458 void clearOutput() { ui.textEditOutput->clear(); }
459 void updateOutput();
460 void periodicUpdate();
462 void storeCadInterfaces(bool nosave = false);
463 void resetCadInterfaces();
465 void logOn() { m_CoutBuffer.str(""); m_Log = true; }
466 void logOff() { m_Log = false; }
468 // SLOTS for all standard operations should be defined below;
469 // entries should look like this:
470 // void callOperationName() { EG_STDSLOT(OperationName); };
471 // The actual class name in this case, however, would be GuiOperationName.
473 // the following line can be used as a template:
474 // void call() { EG_STDSLOT(); };
475 // IMPORTANT: Using EG_STDSLOT sets lock_gui to true, while EG_STDINTERSLOT does not (default is lock_gui = false)
476 // This is important to determine whether an operation should try to lock the main mutex or not.
477 // If lock_gui is true, the operation will try to lock the main mutex. If it fails (mutex locked by other operation), the operation is stopped.
478 // SUMMARY:
479 // EG_STDSLOT = background operation (There can not be more than one background operation!)
480 // EG_STDINTERSLOT = foreground operation
481 // Note: In practice, EG_STDINTERSLOT locks everything, while EG_STDSLOT prevents other operations, but doesn't lock the text output or prevent minimizing the window.
483 void callCreateSurfaceMesh() { EG_STDINTERSLOT( GuiCreateSurfaceMesh ); }
484 void callCreateBoundaryLayer() { EG_STDSLOT( GuiCreateBoundaryLayer ); }
485 void callDivideBoundaryLayer() { EG_STDSLOT( GuiDivideBoundaryLayer ); }
486 void callDeleteVolumeGrid() { EG_STDINTERSLOT( DeleteVolumeGrid ); }
487 void callDeleteTetras() { EG_STDSLOT( DeleteTetras ); }
488 void callCreateVolumeMesh() { EG_STDSLOT( GuiCreateVolumeMesh ); }
489 void callSmoothVolumeGrid() { EG_STDSLOT( SmoothVolumeGrid ); }
490 void callSetBoundaryCode() { EG_STDINTERSLOT( GuiSetBoundaryCode ); }
491 void callDeleteBadAspectTris() { EG_STDINTERSLOT( GuiDeleteBadAspectTris ); }
492 void callDeletePickedCell() { EG_STDSLOT( DeletePickedCell ); }
493 void callMergeNodes();
494 void callInsertNewCell();
495 void callDeletePickedPoint();
496 void callBoxSelect() { EG_STDINTERSLOT( BoxSelect ); }
497 void callCheckSurfaceIntegrity() { EG_STDINTERSLOT( CheckSurfaceIntegrity ); }
498 void callPick_cell_point() { EG_STDINTERSLOT( GuiPick ); }
499 void callTransform() { EG_STDINTERSLOT( GuiTransform ); }
500 void callUpdateSurfProj() { EG_STDINTERSLOT( UpdateSurfProj ); }
501 void callImportOpenFoamCase() { EG_STDREADERSLOT(FoamReader); }
502 void callMergeVolumes() { EG_STDSLOT(GuiMergeVolumes); }
503 void callMirrorMesh() { EG_STDSLOT(GuiMirrorMesh); }
504 void callCreateHexCore() { EG_STDSLOT( GuiCreateHexCore ); }
505 void callCreateHexIbMesh() { EG_STDSLOT( GuiCreateHexIbMesh ); }
506 void callFillPlane() { EG_STDSLOT( GuiFillPlane ); }
507 void callConvertToPolyMesh() { EG_STDSLOT(GuiConvertToPolyMesh); }
508 void callCreateHexShellMesh() { EG_STDSLOT(GuiCreateHexShell); }
509 void callRestrictToAvailableVolumeCells() { EG_STDSLOT(RestrictToAvailableVolumeCells); }
511 void callFixSTL();
513 void callFoamWriter() { EG_STDINTERSLOT( FoamWriter ); }
514 void callSimpleFoamWriter() { EG_STDINTERSLOT( SimpleFoamWriter ); }
515 void callFoamCaseWriter() { EG_STDINTERSLOT( OpenFOAMcase ); }
516 void callCgnsWriter() { EG_STDINTERSLOT( CgnsWriter ); }
517 void callVtkReader() { EG_STDREADERSLOT( VtkReader ); }
518 void callBlenderReader() { EG_STDREADERSLOT( BlenderReader ); }
519 void callBlenderWriter() { EG_STDREADERSLOT( BlenderWriter ); }
520 void callPolyDataReader() { EG_STDREADERSLOT( PolyDataReader ); }
521 void callReducedPolyDataReader() { EG_STDREADERSLOT( ReducedPolyDataReader ); }
522 void callSeligAirfoilReader() { EG_STDREADERSLOT( SeligAirfoilReader ); }
523 void callMultiSolidAsciiStlReader() { EG_STDREADERSLOT( MultiSolidAsciiStlReader ); }
525 void callExportSu2() { EG_STDREADERSLOT( Su2Writer ); }
526 void callExportDolfyn() { EG_STDREADERSLOT( DolfynWriter ); }
528 void callExportDrNum() { EG_STDREADERSLOT( DrNumWriter ); }
530 void callSurfaceMesher() { EG_STDSLOT(GuiSurfaceMesher); }
531 void callReduceSurfaceTriangulation() { EG_STDSLOT(ReduceSurfaceTriangulation); }
532 void callEliminateSmallBranches() { EG_STDSLOT(EliminateSmallBranches); }
533 void callSmoothAndSwapSurface() { EG_STDSLOT(SmoothAndSwapSurface); }
534 void callCheckForOverlap() { EG_STDSLOT(CheckForOverlap); }
536 void callFixCADGeometry() { EG_STDSLOT(FixCadGeometry); }
537 void callYPlusCalculator() { EG_STDSLOT(GuiYPlusCalculator); }
541 #endif