Code_TYMPAN  4.4.0
Industrial site acoustic simulation
TYResultatWidget.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) <2012-2024> <EDF-DTG> <FRANCE>
3  * This file is part of Code_TYMPAN (R).
4  * Code_TYMPAN (R) is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * Code_TYMPAN (R) is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  * See the GNU General Public License for more details.
12  * You should have received a copy of the GNU General Public License along
13  * with Code_TYMPAN (R). If not, see <https://www.gnu.org/licenses/>.
14  */
15 
21 #include <cstdlib>
22 #include <qradiobutton.h>
23 #include <qbuttongroup.h>
24 #include <qtablewidget.h>
25 #include <qcombobox.h>
26 #include <qmenu.h>
27 #include <qfiledialog.h>
28 #include <qpainter.h>
29 
30 // Added by qt3to4:
31 #include <QHBoxLayout>
32 #include <QBoxLayout>
33 #include <QGridLayout>
34 #include <QFrame>
35 #include <QPixmap>
36 #include <QHeaderView>
37 #include <QtWidgets>
38 
39 #include <QtPrintSupport/QPrinter>
40 #include <QtPrintSupport/QPrintDialog>
41 
42 #include "Tympan/core/logging.h"
53 #include "TYResultatTreeDialog.h"
54 #include "TYResultatWidget.h"
55 
56 using namespace QXlsx;
57 
58 #define TR(id) OLocalizator::getString("TYResultatWidget", (id))
59 #define IMG(id) OLocalizator::getPicture("TYResultatWidget", (id))
60 
61 // Declaration de la fonction utilisee par qsort pour le tri des valeurs numerique
62 static int compareRes(const void* elem1, const void* elem2);
63 
64 // Declaration de la fonction utilisee par qsort pour le tri par nom des sources
65 static int compareName(const void* elem1, const void* elem2);
66 
67 TYResultatWidget::TYResultatWidget(TYResultat* pElement, QWidget* _pParent /*=nullptr*/)
68  : TYWidget(pElement, _pParent)
69 {
70  _freq = 100;
71  _choixOperation = 0;
72  _nbSources = 0;
73  _nbRecepteurs = 0;
74  _nbLignes = 0;
75  _nbColonnes = 0;
76 
77  resize(300, 50);
78  setWindowTitle(TR("id_caption"));
79  _resultatLayout = new QGridLayout();
80  setLayout(_resultatLayout);
81 
82  // Placement de l'element (evite de renumeroter les lignes chaque fois qu'on deplace un widget)
83  int iln = 0;
84 
85  QGroupBox* groupBoxFlag = new QGroupBox(this);
86  groupBoxFlag->setTitle(TR(""));
87  QGridLayout* groupBoxFlagLayout = new QGridLayout();
88  groupBoxFlag->setLayout(groupBoxFlagLayout);
89 
90  // Bouton radio dB(A)/dB(Lin)/dB(freq)
91  QButtonGroup* buttonGroupALIN = new QButtonGroup();
92  _radioButtonDBA = new QRadioButton(TR("id_radiobutton_db_a"));
93  buttonGroupALIN->addButton(_radioButtonDBA, 0);
94  _radioButtonDBLIN = new QRadioButton(TR("id_radiobutton_db_lin"));
95  buttonGroupALIN->addButton(_radioButtonDBLIN, 1);
96  _radioButtonDBFRQ = new QRadioButton(TR("id_radiobutton_db_freq"));
97  buttonGroupALIN->addButton(_radioButtonDBFRQ, 2);
98 
99  _choixAffichage = DBA; // Affichage par defaut dBA
100  _radioButtonDBA->setChecked(true);
101  _radioButtonDBLIN->setChecked(false);
102  _radioButtonDBFRQ->setChecked(false);
103 
104  // ComboBox de choix des frequences
105  _comboBoxFreq = new QComboBox();
106  updateFreqList();
107  _comboBoxFreq->setEnabled(false);
108 
109  // Gestion des seuils de contribution (affichage colore)
110  QLabel* pLabelContribution = new QLabel(this);
111  pLabelContribution->setText(TR("id_label_contribution"));
112 
113  static const char dirName[] = "UserPreferences";
114 
116  _pContributionLineEditBas->setFixedSize(50, 20);
117  QString val;
118  if (TYPreferenceManager::getInstance().exists(dirName, "TYAcousticSeuilContribBas"))
119  val = QString::number(
120  TYPreferenceManager::getInstance().getDouble(dirName, "TYAcousticSeuilContribBas"));
121  else
122  {
123  val = QString::number(3);
124  TYPreferenceManager::getInstance().setDouble("TYAcousticSeuilContribBas", 3);
125  }
126  QString leqBas = "Leq - " + QString(val) + " dB";
127  _pContributionLineEditBas->setText(val);
128 
130  _pContributionLineEditMoy->setFixedSize(50, 20);
131 
132  if (TYPreferenceManager::getInstance().exists(dirName, "TYAcousticSeuilContribMoy"))
133  val = QString::number(
134  TYPreferenceManager::getInstance().getDouble(dirName, "TYAcousticSeuilContribMoy"));
135  else
136  {
137  val = QString::number(1.5);
138  TYPreferenceManager::getInstance().setDouble("TYAcousticSeuilContribMoy", 1.5);
139  }
140  QString leqMoy = "Leq - " + QString(val) + " dB";
141  _pContributionLineEditMoy->setText(val);
142 
144  _pContributionLineEditHaut->setFixedSize(50, 20);
145 
146  if (TYPreferenceManager::getInstance().exists(dirName, "TYAcousticSeuilContribHaut"))
147  val = QString::number(
148  TYPreferenceManager::getInstance().getDouble(dirName, "TYAcousticSeuilContribHaut"));
149  else
150  {
151  val = QString::number(0.5);
152  TYPreferenceManager::getInstance().setDouble("TYAcousticSeuilContribHaut", 0.5);
153  }
154  QString leqHaut = "Leq - " + QString(val) + " dB";
155  _pContributionLineEditHaut->setText(val);
156 
157  _pLabelLeqBas = new QLabel(this);
158  _pLabelLeqBas->setText(leqBas);
159  _pLabelLeqMoy = new QLabel(this);
160  _pLabelLeqMoy->setText(leqMoy);
161  _pLabelLeqHaut = new QLabel(this);
162  _pLabelLeqHaut->setText(leqHaut);
163  _pLabelLeq100 = new QLabel(this);
164  _pLabelLeq100->setText(QString("Leq"));
165  _pLabelPres = new QLabel(this);
166  _pLabelPres->setText(TR("id_label_pres"));
167  _pLabelPres->setAlignment(Qt::AlignLeft);
168 
169  _pLabelPctBas = new QLabel(this);
170  _pLabelPctMoy = new QLabel(this);
171  _pLabelPctHaut = new QLabel(this);
172  _pLabelPct100 = new QLabel(this);
173  _pLabelPct100->setText(QString("100 %"));
174  _pLabelEner = new QLabel(this);
175  _pLabelEner->setText(TR("id_label_ener"));
176  _pLabelEner->setAlignment(Qt::AlignLeft);
177 
178  _pLabelLeqBas->setFixedWidth(210);
179  _pLabelLeqMoy->setFixedWidth(85);
180  _pLabelLeqHaut->setFixedWidth(80);
181  _pLabelLeq100->setFixedWidth(25);
182 
183  _pLabelLeqBas->setAlignment(Qt::AlignRight);
184  _pLabelLeqMoy->setAlignment(Qt::AlignRight);
185  _pLabelLeqHaut->setAlignment(Qt::AlignRight);
186  _pLabelLeq100->setAlignment(Qt::AlignHCenter);
187 
188  _pLabelPctBas->setFixedWidth(210);
189  _pLabelPctMoy->setFixedWidth(85);
190  _pLabelPctHaut->setFixedWidth(75);
191  _pLabelPct100->setFixedWidth(30);
192 
193  _pLabelPctBas->setAlignment(Qt::AlignRight);
194  _pLabelPctMoy->setAlignment(Qt::AlignRight);
195  _pLabelPctHaut->setAlignment(Qt::AlignRight);
196  _pLabelPct100->setAlignment(Qt::AlignRight);
197 
198  // Ajout au layout
199  QGridLayout* groupBoALINLayout = new QGridLayout();
200  groupBoALINLayout->addWidget(_radioButtonDBA, 0, 0);
201  groupBoALINLayout->addWidget(_radioButtonDBLIN, 0, 1);
202  groupBoALINLayout->addWidget(_radioButtonDBFRQ, 0, 2);
203  groupBoALINLayout->addWidget(_comboBoxFreq, 0, 3);
204 
205  groupBoALINLayout->addWidget(pLabelContribution, 1, 0);
206  groupBoALINLayout->addWidget(_pContributionLineEditBas, 1, 1);
207  groupBoALINLayout->addWidget(_pContributionLineEditMoy, 1, 2);
208  groupBoALINLayout->addWidget(_pContributionLineEditHaut, 1, 3);
209 
210  QWidget* _pHorizontalLineWidget = new QWidget;
211  _pHorizontalLineWidget->setFixedHeight(2);
212  _pHorizontalLineWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
213  _pHorizontalLineWidget->setStyleSheet(QString("background-color: #c0c0c0;"));
214 
215  QSpacerItem* vspace = new QSpacerItem(50, 50);
216  groupBoALINLayout->addItem(vspace, 1, 0);
217  groupBoALINLayout->addWidget(_pHorizontalLineWidget, 2, 1, 1, 3);
218 
219  groupBoALINLayout->addWidget(_pLabelLeqBas, 3, 0);
220  groupBoALINLayout->addWidget(_pLabelLeqMoy, 3, 1);
221  groupBoALINLayout->addWidget(_pLabelLeqHaut, 3, 2);
222  groupBoALINLayout->addWidget(_pLabelLeq100, 3, 3);
223  groupBoALINLayout->addWidget(_pLabelPres, 3, 4);
224 
225  QPixmap pixmap(IMG("id_pixmap_niveau"));
226  QLabel* labmap = new QLabel(this);
227  labmap->setPixmap(pixmap.scaledToWidth(400));
228  groupBoALINLayout->addWidget(labmap, 4, 0, 1, 4);
229 
230  groupBoALINLayout->addWidget(_pLabelPctBas, 5, 0);
231  groupBoALINLayout->addWidget(_pLabelPctMoy, 5, 1);
232  groupBoALINLayout->addWidget(_pLabelPctHaut, 5, 2);
233  groupBoALINLayout->addWidget(_pLabelPct100, 5, 3);
234  groupBoALINLayout->addWidget(_pLabelEner, 5, 4);
235 
236  QGroupBox* groupBoxALIN = new QGroupBox();
237  groupBoxALIN->setTitle(TR(""));
238  groupBoxALIN->setLayout(groupBoALINLayout);
239 
240  groupBoxFlagLayout->addWidget(groupBoxALIN, 0, 0);
241 
242  // Disambiguate the overloaded signals
243  void (QComboBox::*_qComboBox_activated)(int) = &QComboBox::activated;
244  void (QButtonGroup::*_qButtonGroup_clicked)(int) = &QButtonGroup::idClicked;
245 
246  // Choix du type d'operation a effectuer (Aucun / Difference / Emergence / Bruit ambiant)
247  _buttonGroupOperation = new QButtonGroup();
248  _radioButtonNoOp = new QRadioButton((TR("id_radiobutton_noop")));
250  _radioButtonDelta = new QRadioButton(TR("id_radiobutton_delta"));
252  _radioButtonEmergence = new QRadioButton(TR("id_radiobutton_emergence"));
254  _radioButtonAmbiant = new QRadioButton(TR("id_radiobutton_ambiant"));
256 
257  _radioButtonNoOp->setChecked(true);
258  _radioButtonDelta->setChecked(false);
259  _radioButtonEmergence->setChecked(false);
260  _radioButtonAmbiant->setChecked(false);
261 
262  // Choix du calcul associe au resultat
263  QLabel* labelSubstCalcul = new QLabel(this);
264  labelSubstCalcul->setText(TR("id_subst_calcul"));
265  _comboBoxSubstCalcul = new QComboBox(this);
266  connect(_comboBoxSubstCalcul, _qComboBox_activated, this, &TYResultatWidget::changeSubstCalcul);
267 
268  QGridLayout* groupBoxCalculLayout = new QGridLayout();
269  groupBoxCalculLayout->addWidget(_radioButtonNoOp, 0, 0, Qt::AlignLeft);
270  groupBoxCalculLayout->addWidget(_radioButtonDelta, 1, 0, Qt::AlignLeft);
271  groupBoxCalculLayout->addWidget(_radioButtonEmergence, 2, 0, Qt::AlignLeft);
272  groupBoxCalculLayout->addWidget(_radioButtonAmbiant, 3, 0, Qt::AlignLeft);
273  groupBoxCalculLayout->addWidget(labelSubstCalcul, 0, 1, Qt::AlignRight);
274  groupBoxCalculLayout->addWidget(_comboBoxSubstCalcul, 0, 2, Qt::AlignLeft);
275 
276  QGroupBox* groupBoxCalcul = new QGroupBox();
277  groupBoxCalcul->setTitle(TR(""));
278  groupBoxCalcul->setLayout(groupBoxCalculLayout);
279 
280  groupBoxFlagLayout->addWidget(groupBoxCalcul, 0, 1);
281 
282  _resultatLayout->addWidget(groupBoxFlag, iln, 0);
283 
284  // Table des resultats
285  _pTable = new QTableWidget();
286  _pTable->setSelectionMode(QAbstractItemView::NoSelection);
287  _pTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
288  _resultatLayout->addWidget(_pTable, ++iln, 0);
289 
290  QGroupBox* pGroupBox = new QGroupBox(this);
291  QHBoxLayout* pGroupBoxLayout = new QHBoxLayout();
292  pGroupBox->setLayout(pGroupBoxLayout);
293 
294  _pButtonExportXlsx = new QPushButton(TR("id_export_global_xlsx"));
295  pGroupBoxLayout->addWidget(_pButtonExportXlsx);
296  _pButtonExportXlsx->setEnabled(true);
297 
298  _pButtonExport = new QPushButton(TR("id_export_global"));
299  pGroupBoxLayout->addWidget(_pButtonExport);
300  _pButtonExport->setEnabled(true);
301 
302  _pButtonExportSpectre = new QPushButton(TR("id_export_spectres"));
303  pGroupBoxLayout->addWidget(_pButtonExportSpectre);
304  _pButtonExportSpectre->setEnabled(true);
305 
306  QPushButton* pButtonPrint = new QPushButton(TR("id_print"));
307  pGroupBoxLayout->addWidget(pButtonPrint);
308 
309  _resultatLayout->addWidget(pGroupBox, ++iln, 0);
310 
311  // Permettre le tri en cliquant sur le haut d'une colonne
312  QHeaderView* entetesRecepteurs =
313  _pTable->horizontalHeader(); // On recupere un pointeur sur les entetes horizontales
314  entetesRecepteurs->resizeSections(QHeaderView::ResizeToContents);
315  QObject::connect(entetesRecepteurs, &QHeaderView::sectionClicked, this, &TYResultatWidget::sortCol);
316 
317  QObject::connect(_pContributionLineEditBas, &QLineEdit::textChanged, this,
319  QObject::connect(_pContributionLineEditMoy, &QLineEdit::textChanged, this,
321  QObject::connect(_pContributionLineEditHaut, &QLineEdit::textChanged, this,
323  QObject::connect(buttonGroupALIN, _qButtonGroup_clicked, this, &TYResultatWidget::changeAffichage);
324  QObject::connect(_comboBoxFreq, _qComboBox_activated, this, &TYResultatWidget::setFrequency);
325  QObject::connect(_buttonGroupOperation, _qButtonGroup_clicked, this, &TYResultatWidget::changeOperation);
326  QObject::connect(_pButtonExportXlsx, &QPushButton::clicked, this, &TYResultatWidget::exportExcelXlsx);
327  QObject::connect(_pButtonExport, &QPushButton::clicked, this, &TYResultatWidget::exportExcel);
328  QObject::connect(_pButtonExportSpectre, &QPushButton::clicked, this, &TYResultatWidget::exportSpectre);
329  QObject::connect(pButtonPrint, &QPushButton::clicked, this, &TYResultatWidget::print);
330 
331  // Tableau pour le tri des resultats
332  _tabSortedRes = new TYStructIndiceResultat[getElement()->getNbOfSources()];
333 
337 
338  _pLabelPctBas->setText(QString::number(calcPct(_seuilContributionBas)) + QString(" %"));
339  // _pLabelPctBas->setMaximumWidth(90);
340  _pLabelPctMoy->setText(QString::number(calcPct(_seuilContributionMoy)) + QString(" %"));
341  // _pLabelPctBas->setFixedWidth(25);
342  _pLabelPctHaut->setText(QString::number(calcPct(_seuilContributionHaut)) + QString(" %"));
343  // _pLabelPctBas->setFixedWidth(25);
344  // _pLabelPct100->setFixedWidth(25);
345 
346  groupBoALINLayout->setAlignment(Qt::AlignRight);
347 
348  TYPreferenceManager::completePreferences();
349 
350  updateContent();
351 
352  _printer = new QPrinter();
353 }
354 
356 {
357 
358  if (_tabSortedRes)
359  {
360  delete[] _tabSortedRes;
361  }
362 
363  if (_printer)
364  {
365  delete _printer;
366  }
367 
368  _tabSortedRes = nullptr;
369  _printer = nullptr;
370 }
371 
373 {
374  // ACtualisation du combo des calculs
376 
377  // Par defaut le combo des frequences est positionne a 100 Hz
378  int indFreq = TYSpectre::getIndice(100);
379  _comboBoxFreq->setCurrentIndex(indFreq);
380 
381  _nbSources = static_cast<int>(getElement()->getNbOfSources());
382  _nbRecepteurs = static_cast<int>(getElement()->getNbOfRecepteurs());
383  _nbLignes = _nbSources + 1; // Ajouter la ligne "synthese"
384  _nbColonnes = _nbRecepteurs + 2; // Ajouter les colonnes "Nom sources", et "Puissance source"
385 
386  // Initialisation du tableau des contributions cumulées
387  _cumulatedContribs = std::vector<std::vector<double>>(_nbSources, std::vector<double>(_nbRecepteurs, 0));
388 
389  // Nb lignes = Nb sources + 1 car on ajoute la synthese ligne 1
390  _pTable->setRowCount(_nbLignes);
391 
392  // Nb colonnes = Nb recepteurs + 2 car : nom des sources en colonne 1 et puissance sources en colonne 2
393  _pTable->setColumnCount(_nbColonnes);
394 
395  // une boucle pour mettre les entetes horizontales (numeros des lignes)
396  for (unsigned int row = 0; row < _nbLignes; row++)
397  {
398  _pTable->setVerticalHeaderItem(row, new QTableWidgetItem(QString().setNum(row)));
399  }
400 
402 
403  // L'entete de la colonne 1 indique que cette colonne donne acces a la puissance
404  _pTable->setHorizontalHeaderItem(1, new QTableWidgetItem(QString("LW")));
405 
406  // une boucle pour mettre les nom des recepteurs
407  for (unsigned int col = 0; col < _nbRecepteurs; col++)
408  {
409  if (getElement()->getRecepteur(col) == nullptr)
410  {
411  continue;
412  }
413 
414  QString titre = getElement()->getRecepteur(col)->getName();
415  _pTable->setHorizontalHeaderItem(col + 2, new QTableWidgetItem(titre));
416  }
417 
418  // On trie par ordre decroissant des niveaux du premier point
419  sortCol(1);
420 
421  _pTable->setColumnHidden(1, getElement()->isLWHidden());
423 }
424 
426 {
427  QString strVal; // Cree ici car pb avec switch/case
428  // L'entete de la colonne 0 rappelle le choix d'affichage
429  switch (_choixAffichage)
430  {
431  case DBLIN:
432  _pTable->setHorizontalHeaderItem(0, new QTableWidgetItem(QString("dBZ")));
433  break;
434  case DBFREQ:
435  strVal = QString("dB(") + QString("%1").arg(_freq) + QString(" Hz)");
436  _pTable->setHorizontalHeaderItem(0, new QTableWidgetItem(strVal));
437  break;
438  case DBA:
439  default:
440  _pTable->setHorizontalHeaderItem(0, new QTableWidgetItem(QString("dBA")));
441  break;
442  }
443 }
444 
446 
448 {
449  updateTable();
450 }
452 {
453  _comboBoxSubstCalcul->clear();
454 
455  // Remplissage du comboBox des calculs
456  if (_pElement->getParent()->getParent()->isA("TYProjet"))
457  {
458  TYProjet* pProjet = TYProjet::safeDownCast(getElement()->getParent()->getParent());
459 
460  TYTabLPCalcul listCalcul = pProjet->getListCalcul();
461  for (int i = 0; i < listCalcul.size(); i++)
462  {
463  _comboBoxSubstCalcul->insertItem(i, listCalcul[i]->getName());
464  }
465  }
466 
467  // On affiche la forme d'objet courante
468  _comboBoxSubstCalcul->setCurrentIndex(0);
469 
470  // Si mode de calcul = none alors le combo est bloque
471  if (_choixOperation == 0)
472  {
473  _comboBoxSubstCalcul->setEnabled(false);
474  }
475  else
476  {
477  _comboBoxSubstCalcul->setEnabled(true);
478  }
479 }
480 
482 {
483  if (_pElement->getParent()->getParent()->isA("TYProjet"))
484  {
485  if (!_radioButtonNoOp->isChecked())
486  {
487  int calcul = _comboBoxSubstCalcul->currentIndex();
488  TYProjet* pProjet = TYProjet::safeDownCast(getElement()->getParent()->getParent());
489  return pProjet->getListCalcul()[calcul];
490  }
491  }
492  return nullptr;
493 }
494 
496 {
497  TYResultat* pResultat = TYResultat::safeDownCast(getElement());
498  if (!pResultat)
499  {
500  return;
501  } // Securite
502 
503  QString qFileName = QFileDialog::getSaveFileName(this, "Choose a file", "", "CSVFile (*.csv)");
504 
505  if (!qFileName.isNull())
506  {
507  if (qFileName.right(3) != "csv")
508  {
509  qFileName += ".csv";
510  }
511 
512  pResultat->saveSpectre(qFileName, getSelectedSubstCalcul());
513  }
514 }
515 
517 {
518  TYResultat* pResultat = TYResultat::safeDownCast(getElement());
519 
520  if (!pResultat)
521  {
522  return;
523  } // Security
524 
525  QString qFileName = QFileDialog::getSaveFileName(this, "Choose a file", "", "Classeur Excel (*.xlsx)");
526 
527  if (!qFileName.isEmpty())
528  {
529  QFileInfo fileInfo(qFileName);
530  if (fileInfo.suffix().toLower() != "xlsx")
531  {
532  qFileName += ".xlsx";
533  }
534 
535  Document documentQXlsx;
536  documentQXlsx.workbook()->setStringsToNumbersEnabled(true);
537 
538  // Onglet 1 : Contributions
539  documentQXlsx.addSheet("Contributions");
540  documentQXlsx.selectSheet("Contributions");
541  exportContributionsTableToSheet(documentQXlsx);
542 
543  // Onglet 2 : Contributions cumulées
544  documentQXlsx.addSheet("Contributions cumulées");
545  documentQXlsx.selectSheet("Contributions cumulées");
547 
548  documentQXlsx.selectSheet("Contributions");
549 
550  if (!documentQXlsx.saveAs(qFileName))
551 
552  {
553  QMessageBox::warning(this, tr("Erreur de sauvegarde"),
554  tr("Impossible d'enregistrer le fichier Excel.\n"
555  "Il est peut-être déjà ouvert dans une autre "
556  "application.\n\n"
557  "Veuillez fermer le fichier ou choisir un autre nom pour l'export."));
558  }
559  }
560 }
561 
563 {
564  int columnCount = _pTable->columnCount();
565  int rowCount = _pTable->rowCount();
566 
567  writeContributionsTableRow(columnCount, 0, documentQXlsx);
568  writeColHeadersToSheet(documentQXlsx, columnCount /* maxCharCount*/);
569 
570  // Write row headers and cell contents
571  for (int row = 1; row < rowCount; ++row)
572  {
573  writeRowHeadersToSheet(row, documentQXlsx);
574  writeContributionsTableRow(columnCount, row, documentQXlsx);
575  }
576  adjustXlsxDocumentColumnWidths(columnCount, documentQXlsx);
577 }
578 
579 void TYResultatWidget::writeContributionsTableRow(int columnCount, int row, QXlsx::Document& documentQXlsx)
580 {
581  int xlsxRow = getXlsxRow(row);
582  QHeaderView* hh = _pTable->horizontalHeader();
583 
584  for (int visualIndex = 0; visualIndex < columnCount; ++visualIndex)
585  {
586  QXlsx::Format format;
587  int col = hh->logicalIndex(visualIndex);
588  QTableWidgetItem* item = _pTable->item(row, col);
589  if (!item)
590  continue;
591 
592  QString cellText = item->text();
593 
594  getFormatFromContributionsTable(item, format);
595 
596  // Write with or without format depending on the case
597  if (format.isValid())
598  documentQXlsx.write(xlsxRow, visualIndex + 2, cellText, format);
599  else
600  documentQXlsx.write(xlsxRow, visualIndex + 2, cellText);
601  }
602 }
603 
605 {
606  int xlsxRow = 1;
607  // La synthèse au-dessus des autres lignes pour faciliter le tri
608  if (row != 0)
609  {
610  xlsxRow = row + 2;
611  }
612  return xlsxRow;
613 }
614 
616 {
617  int columnCount = _pTable->columnCount();
618  int rowCount = _pTable->rowCount();
619  writeCumulatedContributionsTableRow(columnCount, 0, documentQXlsx);
620  writeColHeadersToSheet(documentQXlsx, columnCount);
621 
622  for (int row = 1; row < rowCount; ++row)
623  {
624  writeRowHeadersToSheet(row, documentQXlsx);
625  writeCumulatedContributionsTableRow(columnCount, row, documentQXlsx);
626  }
627  adjustXlsxDocumentColumnWidths(columnCount, documentQXlsx);
628 }
629 
630 void TYResultatWidget::adjustXlsxDocumentColumnWidths(int columnCount, QXlsx::Document& documentQXlsx)
631 {
632  // Ajustement automatique des colonnes
633  for (int col = 0; col <= columnCount + 1; ++col)
634  {
635  documentQXlsx.autosizeColumnWidth(col + 1);
636  }
637 }
638 
640  QXlsx::Document& documentQXlsx)
641 {
642  int xlsxRow = getXlsxRow(row);
643  QHeaderView* hh = _pTable->horizontalHeader();
644 
645  for (int visualIndex = 0; visualIndex < columnCount; ++visualIndex)
646  {
647  QXlsx::Format format;
648  int col = hh->logicalIndex(visualIndex);
649  QTableWidgetItem* item = _pTable->item(row, col);
650  QString cellText;
651  if (!item)
652  continue;
653  if (col <= 1 || row == 0) // La synthèse, les noms et les puissances des sources
654  {
655  cellText = item->text();
656  }
657  else
658  {
659  cellText = QString("%1").arg(_cumulatedContribs[row - 1][col - 2], 7, 'f', 1);
660  }
661 
662  getFormatFromContributionsTable(item, format);
663 
664  // Write with or without format depending on the case
665  if (format.isValid())
666  documentQXlsx.write(xlsxRow, visualIndex + 2, cellText, format);
667  else
668  documentQXlsx.write(xlsxRow, visualIndex + 2, cellText);
669  }
670 }
671 
672 void TYResultatWidget::writeRowHeadersToSheet(int row, QXlsx::Document& documentQXlsx)
673 {
674  int xlsxRow = getXlsxRow(row);
675 
676  QString rowHeader =
677  _pTable->verticalHeaderItem(row) ? _pTable->verticalHeaderItem(row)->text() : QString();
678 
679  documentQXlsx.write(xlsxRow, 1, rowHeader);
680 }
681 
682 void TYResultatWidget::getFormatFromContributionsTable(QTableWidgetItem* item, QXlsx::Format& format)
683 {
684  // Apply background color only if it is defined
685  QVariant bgVariant = item->data(Qt::BackgroundRole);
686  if (bgVariant.isValid())
687  {
688  QColor bgColor = bgVariant.value<QColor>();
689 
690  // If color is different from Qt::white or trnasparent, apply it
691  if (bgColor.isValid() && bgColor != Qt::white && bgColor.alpha() > 0)
692  {
693  format.setPatternBackgroundColor(bgColor);
694  }
695  // Else, do not apply any format to leave grid pattern visible
696  }
697 }
698 
699 void TYResultatWidget::writeColHeadersToSheet(QXlsx::Document& documentQXlsx, int columnCount)
700 {
701  // Write column headers (shifted by 1 to the right)
702  documentQXlsx.write(1, 1, ""); // Top-left cell left empty
703  QHeaderView* hh = _pTable->horizontalHeader();
704  for (int visualIndex = 0; visualIndex < columnCount; ++visualIndex)
705  {
706  int col = hh->logicalIndex(visualIndex);
707  QString headerText =
708  _pTable->horizontalHeaderItem(col) ? _pTable->horizontalHeaderItem(col)->text() : QString();
709  documentQXlsx.write(2, visualIndex + 2, headerText);
710  }
711 }
712 
714 {
715  TYResultat* pResultat = TYResultat::safeDownCast(getElement());
716 
717  if (!pResultat)
718  {
719  return;
720  } // Securite
721 
722  QString qFileName = QFileDialog::getSaveFileName(this, "Choose a file", "", "CSVFile (*.csv)");
723 
724  if (!qFileName.isNull())
725  {
726  if (qFileName.right(3) != "csv")
727  {
728  qFileName += ".csv";
729  }
730 
731  pResultat->saveValue(qFileName, _choixAffichage, _freq);
732  }
733 }
734 
735 void TYResultatWidget::contextMenuEvent(QContextMenuEvent* e)
736 {
737  TYCalcul* pCalcul = TYCalcul::safeDownCast(getElement()->getParent());
738  TYCalcul* pSubstCalcul = getSelectedSubstCalcul();
739 
740  QPoint point = _pTable->mapFrom(this, e->pos());
741  if ((point.x() >= 0) && (point.y() >= 0) && (point.x() <= _pTable->width()) &&
742  (point.y() <= _pTable->height()))
743  {
744  QPoint resPoint = QPoint(point.x(), point.y() - _pTable->horizontalHeader()->height());
745  QTableWidgetItem* item = _pTable->itemAt(resPoint);
746  if (item)
747  {
748  int row = _pTable->indexAt(resPoint).row();
749  row = row >= 0 ? row : 0; // Securite
750  int col = _pTable->indexAt(resPoint).column();
751  col = col >= 0 ? col : 0; // Securite
752  int ligne = row > 0 ? _tabSortedRes[row - 1].indice : 0;
753 
754  OSpectre spectre1 = getSpectre(row, col, pCalcul);
755  OSpectre spectre2 = getSpectre(row, col, pSubstCalcul);
756 
757  TYSpectre spectre = resuSpectre(spectre1, spectre2, 1);
758 
759  spectre.setType(SPECTRE_TYPE_LP);
760  spectre = spectre.toDB();
761 
762  QAction *editSource = nullptr, *editRecepteur = nullptr, *editSpectre = nullptr,
763  *editContrib = nullptr;
764 
765  QMenu* pPopup = new QMenu(this);
766  if ((row == 0) && (col > 1)) // Ligne de synthese
767  {
768  if (_choixOperation == 0) // pas d'operation
769  {
770  editRecepteur = pPopup->addAction(TR("id_popup_see_recepteur"));
771  pPopup->addSeparator();
772  }
773  else
774  {
775  editSpectre = pPopup->addAction(TR("id_popup_see_spectre"));
776  }
777 
778  // Si on a conserve la matrice des resultats bruts
779  if (getElement()->getPartialState())
780  {
781  editContrib = pPopup->addAction(TR("id_popup_see_contrib"));
782  }
783  }
784  else if ((row > 0) && (col > 1)) // Si on selectionne une contribution par source (!= synthese)
785  {
786  editSpectre = pPopup->addAction(TR("id_popup_see_spectre"));
787  pPopup->addSeparator();
788  editSource = pPopup->addAction(TR("id_popup_see_source"));
789  pPopup->addSeparator();
790  editRecepteur = pPopup->addAction(TR("id_popup_see_recepteur"));
791  }
792  else if ((row > 0) && (col == 0))
793  {
794  editSource = pPopup->addAction(TR("id_popup_see_source"));
795  }
796  else if ((row > 0) && (col == 1))
797  {
798  editSource = pPopup->addAction(TR("id_popup_see_source"));
799  }
800 
801  QAction* ret = pPopup->exec(_pTable->mapToGlobal(point));
802 
803  if (ret)
804  {
805  if (ret == editSource)
806  {
807  getElement()->getSource(ligne)->edit(this);
808  }
809  else if (ret == editRecepteur)
810  {
811  TYCalcul* pCalcul = static_cast<TYCalcul*>(getElement()->getParent());
812  TYPointCalcul* pPoint = getElement()->getRecepteur(col - 2);
813  LPTYSpectre pSpectre = nullptr;
814 
815  if (pPoint)
816  {
817  pSpectre = pCalcul->getSpectre(pPoint->getID());
818  }
819  if (pSpectre == nullptr)
820  {
821  return;
822  }
823 
824  // Si c'est un resultat calcule, on ne peut pas changer les valeurs
825  if (pCalcul && (pCalcul->getState() == TYCalcul::Actif))
826  {
827  pSpectre->setIsReadOnly(true);
828  }
829  else
830  {
831  pSpectre->setIsReadOnly(false);
832  }
833 
834  pSpectre->edit(this);
835 
836  // Si c'est une mesure, on actualise le tableau resultat
837  if (pCalcul && (pCalcul->getState() == TYCalcul::Locked))
838  {
839  updateTable();
840  }
841  }
842  else if (ret == editSpectre)
843  {
844  spectre.setIsReadOnly(true);
845  spectre.edit(this);
846  spectre.setIsReadOnly(false);
847  }
848  else if (ret == editContrib)
849  {
851  }
852  }
853  }
854  }
855 }
856 
858 {
859  TYPrintDialog* pDialog = new TYPrintDialog(this);
860  pDialog->_groupBoxProjet->setEnabled(false);
861  pDialog->_groupBoxCalcul->setEnabled(false);
862  if (pDialog->exec() == QDialog::Accepted)
863  {
864  QPrintDialog dialog(_printer, this);
865  if (dialog.exec())
866  {
867  QPainter paint(_printer);
868 
869  QPixmap tmpPix;
870 
871  int mid = int(_printer->width() / 2) -
872  int(paint.fontMetrics().horizontalAdvance(pDialog->_lineEditTete->text()) / 2);
873  paint.drawText(mid, 20, pDialog->_lineEditTete->text());
874  mid = int(_printer->width() / 2) -
875  int(paint.fontMetrics().horizontalAdvance(pDialog->_lineEditPied->text()) / 2);
876  paint.drawText(mid, _printer->height() - 20, pDialog->_lineEditPied->text());
877  paint.setFont(QFont("Helvetica", 15, QFont::Bold));
878  mid = int(_printer->width() / 2) -
879  int(paint.fontMetrics().horizontalAdvance(pDialog->_lineEditTitre->text()) / 2);
880  paint.drawText(mid, 45, pDialog->_lineEditTitre->text());
881  paint.setFont(QFont());
882 
883  int sizeX = 120, sizeY = 25;
884  int ymax = int(double(_printer->height()) * 4 / 5 / (_pTable->rowCount() + 1));
885  if (ymax < sizeY)
886  {
887  sizeY = ymax;
888  }
889  int x = int(double(_printer->width() - sizeX * (_pTable->columnCount())) / 2);
890  int y = int((double(_printer->height()) - sizeY * (_pTable->rowCount() + 3)));
891 
892  int i = 0;
893  for (i = 0; i < _pTable->horizontalHeader()->count(); i++)
894  {
895  paint.drawText(x, y, _pTable->horizontalHeaderItem(i)->text());
896  paint.translate(sizeX, 0);
897  }
898 
899  paint.translate(-_pTable->columnCount() * sizeX, 0);
900  paint.translate(0, sizeY);
901 
902  for (i = 0; i < _pTable->rowCount(); i++)
903  {
904  for (int j = 0; j < _pTable->columnCount(); j++)
905  {
906  if (_pTable->item(i, j))
907  {
908  paint.drawText(x, y, _pTable->item(i, j)->text()); // paintCell(&paint, i, j, QRect(0,
909  // 0, sizeX, sizeY), false);
910  }
911  paint.translate(sizeX, 0);
912  }
913  paint.translate(0, sizeY);
914  paint.translate(-_pTable->columnCount() * sizeX, 0);
915  }
916  }
917  }
918 }
919 
921 {
922  switch (select)
923  {
924  case 1:
925  _choixAffichage = DBLIN; // Affichage dBLin
926  _comboBoxFreq->setEnabled(false);
927  break;
928  case 2:
929  _choixAffichage = DBFREQ; // Affichage par frequence
930  _comboBoxFreq->setEnabled(true);
931  break;
932  case 0:
933  default:
934  _choixAffichage = DBA; // Affichage dBA
935  _comboBoxFreq->setEnabled(false);
936  break;
937  }
938 
939  // Mets a jour le widget
941  updateTable();
942 }
943 
945 {
946  _choixOperation = select;
947 
948  if (_choixOperation == 0)
949  {
950  _comboBoxSubstCalcul->setEnabled(false);
951  _pButtonExport->setEnabled(true);
952  _pButtonExportSpectre->setEnabled(true);
953  }
954  else
955  {
956  _comboBoxSubstCalcul->setEnabled(true);
957  _pButtonExport->setEnabled(false);
958  _pButtonExportSpectre->setEnabled(false);
959  }
960 
961  // Mets a jour le widget
962  updateTable();
963 }
964 
966 {
967  // On commence par remplir la premiere colonne avec les noms des sources
968  QString titre = TR("id_entete_synthese");
969  _pTable->setItem(0, 0, new QTableWidgetItem(titre));
970  _pTable->setRowHeight(0, 30);
971  _pTable->setColumnWidth(0, 140);
972 
973  for (unsigned int row = 1; row < _nbLignes; row++) // On commence apres la ligne synthese
974  {
975  TYElement* pSource = getElement()->getSource(_tabSortedRes[row - 1].indice);
976  if (pSource == nullptr)
977  {
978  continue;
979  }
980 
981  QString titre = pSource->getName();
982  _pTable->setItem(row, 0, new QTableWidgetItem(titre));
983  _pTable->setRowHeight(row, 30);
984  }
985 
986  // Boucle sur les colonnes pour afficher le tableau
987  TYCalcul* pCalcOp = getSelectedSubstCalcul(); // Calcul à comparer
988  TYCalcul* pCalcul = TYCalcul::safeDownCast(_pElement->getParent()); // Calcul sélectionné
989 
990  for (unsigned int col = 1; col < _nbColonnes; col++)
991  {
992  displayColumn(pCalcul, pCalcOp, col);
993  }
994 }
995 
996 void TYResultatWidget::displayColumn(TYCalcul* pCalcul, TYCalcul* pCalcOp, const int& col)
997 {
998  std::vector<int> couleur = calcCumulatedContribution(col, pCalcul, pCalcOp);
999 
1000  for (unsigned int row = 0; row < _nbLignes; row++)
1001  {
1002  OSpectre spectre1 = getSpectre(row, col, pCalcul);
1003  OSpectre spectre2 = getSpectre(row, col, pCalcOp);
1004 
1005  QTableWidgetItem* pItem = nullptr;
1006  QString msg;
1007  double valeur = 0.0;
1008  bool valid = true;
1009 
1010  if (row == 0)
1011  {
1012  if (col > 1) // La case (0,1) est vide
1013  {
1014  valeur = resuAffichage(spectre1, spectre2, valid, CELL_SYNTH);
1015  msg = QString("%1").arg(valeur, 7, 'f', 1);
1016  pItem = new QTableWidgetItem(msg);
1017  decorsSynthese(pItem, row, col, valid, spectre1, spectre2);
1018  _pTable->setItem(row, col, pItem);
1019  _pTable->setRowHeight(row, 30);
1020  }
1021  }
1022  else if (col > 1) // Tout sauf ligne de synthese ou puissance de source
1023  {
1024  valeur = resuAffichage(spectre1, spectre2, valid, CELL_CONTRIB);
1025  msg = QString("%1").arg(valeur, 7, 'f', 1);
1026  pItem = new QTableWidgetItem(msg);
1027  decorsContributions(pItem, row, col, valid, couleur);
1028  _pTable->setItem(row, col, pItem);
1029  _pTable->setRowHeight(row, 30);
1030  }
1031  else // A priori, il ne reste que la puissance de la source
1032  {
1033  spectre2 = OSpectre(); // La puissance affichee correspond a la puissance de la source du
1034  // calcul courant
1035  valeur = resuAffichage(spectre1, spectre2, valid, CELL_LW);
1036  msg = QString("%1").arg(valeur, 7, 'f', 1);
1037  pItem = new QTableWidgetItem(msg);
1038  decorsContributions(pItem, row, col, valid, couleur);
1039  _pTable->setItem(row, col, pItem);
1040  _pTable->setRowHeight(row, 30);
1041  }
1042  }
1043  if (col >= 1)
1044  {
1045  _pTable->setColumnWidth(col, 50);
1046  }
1047 }
1048 
1049 OSpectre TYResultatWidget::getSpectre(const int& row, const int& col, TYCalcul* pCalcul)
1050 {
1051  OSpectre spectre;
1052  spectre.setValid(false);
1053 
1054  if ((!pCalcul) || (col == 0))
1055  {
1056  return spectre;
1057  } // Cas de la colonne des noms de source
1058 
1059  if (col == 1) // Spectre de puissance d'une source
1060  {
1061  if (row > 0)
1062  {
1063  spectre = getPuissanceElem(_tabSortedRes[row - 1].indice);
1064  }
1065  else
1066  {
1067  spectre.setValid(false);
1068  }
1069  }
1070  else
1071  {
1072  if (row == 0) // Ligne synthese
1073  {
1074  TYPointCalcul* pPoint = getElement()->getRecepteur(col - 2);
1075  if (pPoint)
1076  {
1077  spectre = *pCalcul->getSpectre(pPoint->getID());
1078  }
1079  }
1080  else // Contribution d'une source en un point
1081  {
1082  // Recuperation du resultat courant
1083  TYResultat* pThisRes = getElement();
1084  // Recuperation de pointeurs sur la source et du recepteur
1085  TYElement* pSource = pThisRes->getSource(_tabSortedRes[row - 1].indice);
1086  TYPointCalcul* pRecepteur = pThisRes->getRecepteur(col - 2);
1087 
1088  // Puis on recupere le spectre correspondant dans le calcul passe en parametre
1089  TYResultat* pResultat = pCalcul->getResultat();
1090  spectre = pResultat->getSpectre(pRecepteur, pSource);
1091  spectre = spectre.toDB();
1092  }
1093  }
1094 
1095  return spectre;
1096 }
1097 
1099 {
1100  int row = 1; // Numero de 1ere ligne (ligne 0 = synthese)
1101 
1102  TYCalcul* pCalcul = TYCalcul::safeDownCast(getElement()->getParent());
1103  TYCalcul* pSubstCalcul = getSelectedSubstCalcul();
1104 
1105  OSpectre spectre1;
1106  OSpectre spectre2;
1107 
1108  bool valid = true;
1109 
1110  for (unsigned int i = 0; i < getElement()->getNbOfSources(); i++)
1111  {
1112  _tabSortedRes[i].indice = i;
1113  row = i + 1;
1114 
1115  if (getElement() && getElement()->getSource(i))
1116  {
1117  _tabSortedRes[i].name = getElement()->getSource(i)->getName().toStdString();
1118  }
1119 
1120  spectre1 = getSpectre(row, col, pCalcul);
1121  spectre2 = getSpectre(row, col, pSubstCalcul);
1122 
1123  _tabSortedRes[i].resultat = resuAffichage(spectre1, spectre2, valid, 1);
1124  }
1125 }
1126 
1128 {
1129  if (col < 0)
1130  {
1131  return;
1132  }
1133  else if (col == 0)
1134  {
1135  sortName();
1136  }
1137  else
1138  {
1139  sortRes(col);
1140  // Dans ce cas, on reaffiche car on a reorganise les resultats
1141  }
1142 
1143  updateTable();
1144 }
1145 
1147 {
1148  // On commence par remplir le tableau des resultats
1149  // (la synthese est supposee etre toujours la plus forte valeur et "surnager" en haut du tableau)
1150  initTabSort(col);
1151 
1152  // Tri
1153  qsort(_tabSortedRes, getElement()->getNbOfSources(), sizeof(TYStructIndiceResultat), compareRes);
1154 }
1155 
1157 {
1158  // On commence par remplir le tableau des resultats
1159  // (la synthese est supposee etre toujours la plus forte valeur et "surnager" en haut du tableau)
1160  initTabSort(1);
1161 
1162  // Tri
1163  qsort(_tabSortedRes, getElement()->getNbOfSources(), sizeof(TYStructIndiceResultat), compareName);
1164 }
1165 
1167 {
1168  TYElement* pElement = getElement()->getSource(i);
1169 
1170  return getPuissanceElem(pElement);
1171 }
1172 
1174 {
1175  assert(pElement);
1176  TYSpectre spectre;
1177 
1178  std::map<TYElement*, LPTYSpectre>& mapElementSpectre = getElement()->getMapElementSpectre();
1179  TYSpectre* puissance = mapElementSpectre[pElement];
1180 
1181  if (puissance)
1182  {
1183  spectre = *puissance;
1184  }
1185 
1186  return spectre;
1187 }
1188 
1190 {
1191  TYResultatTreeDialog* pDlg = new TYResultatTreeDialog(this);
1192 
1193  // Recuperation du point de contrOle
1194  LPTYPointCalcul pPoint = getElement()->getRecepteur(col - 2);
1195  pDlg->set(getElement(), pPoint);
1196  pDlg->exec();
1197 }
1198 
1200 {
1201  return spectre.isTonalite();
1202 }
1203 
1205 {
1206  _seuilContributionBas = _pContributionLineEditBas->text().toDouble();
1207  _seuilContributionMoy = _pContributionLineEditMoy->text().toDouble();
1209 
1210  _pLabelLeqBas->setText(QString("Leq - ") + QString::number(_seuilContributionBas) + QString(" dB"));
1211  _pLabelLeqMoy->setText(QString("Leq - ") + QString::number(_seuilContributionMoy) + QString(" dB"));
1212  _pLabelLeqHaut->setText(QString("Leq - ") + QString::number(_seuilContributionHaut) + QString(" dB"));
1213 
1214  _pLabelPctBas->setText(QString::number(calcPct(_seuilContributionBas)) + QString(" %"));
1215  _pLabelPctMoy->setText(QString::number(calcPct(_seuilContributionMoy)) + QString(" %"));
1216  _pLabelPctHaut->setText(QString::number(calcPct(_seuilContributionHaut)) + QString(" %"));
1217 
1218  updateTable();
1219 }
1220 
1221 double TYResultatWidget::calcPct(double val)
1222 {
1223  double dummy = 100;
1224  double seuil = dummy - val;
1225  double dummyEner = pow(10, dummy / 10);
1226  double seuilEner = pow(10, seuil / 10);
1227  return int(100 * seuilEner / dummyEner);
1228 }
1229 
1236 {
1237  std::pair<double, double> data;
1239  inline bool operator<(dataPoint a)
1240  {
1241  return data.second < a.data.second;
1242  }
1243 };
1244 
1245 std::vector<int> TYResultatWidget::calcCumulatedContribution(const int& col, TYCalcul* pCalcul,
1246  TYCalcul* pCalcOp)
1247 {
1248  size_t nbSources = getElement()->getNbOfSources();
1249 
1250  std::vector<dataPoint> values = std::vector<dataPoint>(nbSources);
1251  std::vector<int> couleur = std::vector<int>(nbSources);
1252  if (nbSources == 0)
1253  return couleur;
1254 
1255  bool valid = true;
1256 
1257  // On ne s'occupe que des lignes correspondant à des sources, pas à la synthèse
1258  for (int row = 1; row <= nbSources; row++)
1259  {
1260  OSpectre spectre1 = getSpectre(row, col, pCalcul);
1261  OSpectre spectre2 = getSpectre(row, col, pCalcOp);
1262 
1263  if (col > 1)
1264  values[row - 1].data =
1265  std::pair<double, double>(row, resuAffichage(spectre1, spectre2, valid, CELL_CONTRIB));
1266  else
1267  values[row - 1].data =
1268  std::pair<double, double>(row, resuAffichage(spectre1, spectre2, valid, CELL_LW));
1269  }
1270  // on trie par valeur décroissante
1271  std::sort(values.begin(), values.end());
1272  std::reverse(values.begin(), values.end());
1273 
1274  // on calcul les contributions cumulées
1275  double cum = 0;
1276  for (int i = 0; i < nbSources; i++)
1277  {
1278  double val = values[i].data.second;
1279  val = pow(10, val * 0.1);
1280  cum += val;
1281  double res = 10 * log10(cum);
1282  values[i].data.second = res;
1283  if (col > 1) // Pas de cumul des puissances
1284  {
1285  _cumulatedContribs[int(values[i].data.first) - 1][col - 2] = res;
1286  }
1287  }
1288 
1289  // on détermine le code couleur de chaque contribution
1290  OSpectre spectre1 = getSpectre(0, col, pCalcul);
1291  OSpectre spectre2 = getSpectre(0, col, pCalcOp);
1292  double synthese = resuAffichage(spectre1, spectre2, valid, CELL_CONTRIB);
1293  double previousVal = values[0].data.second;
1294  for (int i = 0; i < nbSources; i++)
1295  {
1296  if (i > 0)
1297  {
1298  double currentVal = values[i].data.second;
1299  // La contribution max est toujours en rouge
1300  if (previousVal < (synthese - _seuilContributionBas) || i == 0)
1301  values[i].data.second = RED;
1302  else if (previousVal < (synthese - _seuilContributionMoy))
1303  values[i].data.second = ORANGE;
1304  else if (previousVal < (synthese - _seuilContributionHaut))
1305  values[i].data.second = YELLOW;
1306  else
1307  values[i].data.second = WHITE;
1308  previousVal = currentVal;
1309  }
1310  else
1311  values[i].data.second = RED;
1312 
1313  // on swap les pairs pour trier le vecteur selon l'ordre initial
1314  std::swap(values[i].data.first, values[i].data.second);
1315  }
1316 
1317  // on reprend l'ordre initial
1318  std::sort(values.begin(), values.end());
1319 
1320  for (int i = 0; i < nbSources; i++)
1321  {
1322  couleur[i] = values[i].data.first;
1323  }
1324 
1325  return couleur;
1326 }
1327 
1328 double TYResultatWidget::resuAffichage(OSpectre& spectre1, OSpectre& spectre2, bool& valid,
1329  const int& typeCase)
1330 {
1331  double val1 = 0.0, val2 = 0.0;
1332 
1333  switch (_choixAffichage)
1334  {
1335  case DBLIN:
1336  val1 = spectre1.valGlobDBLin();
1337  val2 = spectre2.valGlobDBLin();
1338  break;
1339  case DBFREQ:
1340  val1 = spectre1.getValueReal(_freq);
1341  val2 = spectre2.getValueReal(_freq);
1342  break;
1343  case DBA:
1344  default:
1345  val1 = spectre1.valGlobDBA();
1346  val2 = spectre2.valGlobDBA();
1347  break;
1348  }
1349 
1350  if (_choixOperation != 0)
1351  {
1352  if ((!spectre2.isValid()) || (typeCase == CELL_LW))
1353  {
1354  val2 = 0.0;
1355  }
1356  if ((!spectre2.isValid()) && ((typeCase == CELL_SYNTH) || (typeCase == CELL_CONTRIB)))
1357  {
1358  valid = false;
1359  }
1360  }
1361 
1362  switch (_choixOperation)
1363  {
1364  case 0: // Pas d'operation
1365  return val1;
1366  case 1: // difference entre deux resultats
1367  return val1 - val2;
1368  case 2: // emergence (uniquement pour la ligne synthese)
1369  if (typeCase == CELL_SYNTH)
1370  {
1371  return (TYResultat::safeDownCast(_pElement))->getEmergence(val1, val2);
1372  }
1373  else
1374  {
1375  return val1;
1376  }
1377  case 3: // bruit ambiant (uniquement pour la ligne synthese)
1378  default:
1379  if (typeCase == CELL_SYNTH)
1380  {
1381  return (TYResultat::safeDownCast(_pElement))->getAmbiant(val1, val2);
1382  }
1383  else
1384  {
1385  return val1;
1386  }
1387  }
1388 }
1389 
1390 OSpectre TYResultatWidget::resuSpectre(OSpectre& spectre1, OSpectre& spectre2, const int& typeCase)
1391 {
1392  switch (_choixOperation)
1393  {
1394  case 0: // Pas d'operation
1395  return spectre1;
1396  break;
1397  case 1: // difference entre deux resultats
1398  return spectre1.subst(spectre2);
1399  break;
1400  case 2: // emergence
1401  return (TYResultat::safeDownCast(_pElement))->getEmergence(spectre1, spectre2);
1402  break;
1403  case 3: // bruit ambiant
1404  default:
1405  return (TYResultat::safeDownCast(_pElement))->getAmbiant(spectre1, spectre2);
1406  break;
1407  }
1408 
1409  return OSpectre();
1410 }
1411 
1412 void TYResultatWidget::decorsSynthese(QTableWidgetItem* pItem, const int& row, const int& col,
1413  const bool& valid, OSpectre& spectre1, OSpectre& spectre2)
1414 {
1415  if (!valid)
1416  {
1417  pItem->setBackground(QBrush(QColor(127, 127, 127))); // Gris uni
1418  return;
1419  }
1420 
1421  if ((_choixAffichage == DBFREQ) || (_choixOperation == 1) || (_choixOperation == 2))
1422  {
1423  pItem->setBackground(QBrush(QColor(255, 255, 255))); // Blanc uni ?
1424  return; // Rien si affichage sur une frequence ou difference ou emergence
1425  }
1426 
1427  OSpectre spectre;
1429 
1430  if (_choixOperation == 3) // Bruit ambiant
1431  {
1432  spectre = getElement()->getAmbiant(spectre1, spectre2);
1433  }
1434  else if (_choixOperation == 0) // Pas d'operation
1435  {
1436  spectre = getSpectre(row, col, pCalcul);
1437  }
1438 
1439  if (isPresenceTonaliteMarquee(spectre)) // Coloration en jaune
1440  {
1441  pItem->setBackground(QBrush(QColor(255, 255, 0)));
1442  }
1443 }
1444 
1445 void TYResultatWidget::decorsContributions(QTableWidgetItem* pItem, const int& row, const int& col,
1446  bool& isColored, std::vector<int> couleurs)
1447 {
1448  double codeCoul = couleurs[row - 1];
1449  // Les cellules sont decorees sauf dans le cas ou on affiche l'ecart entre deux resultats
1450  if (!isColored)
1451  {
1452  pItem->setBackground(QBrush(QColor(127, 127, 127))); // Gris uni
1453  return;
1454  }
1455 
1456  if ((_choixOperation == 1) || (col == 1))
1457  {
1458  pItem->setBackground(QBrush(QColor(255, 255, 255))); // Blanc uni ?
1459  }
1460  else
1461  {
1462  // Affichage en couleur pour les cellules qui contribuent a plus que contribution cumulée -
1463  // seuil Uniquement dansle cas ou aucune operation n'a ete faite sur le resultat.
1464  if ((_choixOperation == 0) && (codeCoul == RED))
1465  {
1466  pItem->setBackground(QBrush(QColor(255, 0, 0)));
1467  }
1468  else if ((_choixOperation == 0) && (codeCoul == ORANGE))
1469  {
1470  pItem->setBackground(QBrush(QColor(255, 204, 0)));
1471  }
1472  else if ((_choixOperation == 0) && (codeCoul == YELLOW))
1473  {
1474  pItem->setBackground(QBrush(QColor(255, 255, 0)));
1475  }
1476  }
1477 }
1478 
1480 {
1482  for (unsigned int i = 0; i < tabFreq.size(); i++)
1483  {
1484  QString str;
1485  str.setNum(tabFreq[i], 'f', 1);
1486  _comboBoxFreq->insertItem(i, str);
1487  }
1488 }
1489 
1491 {
1492  _freq = _comboBoxFreq->currentText().toFloat();
1494  updateTable();
1495 }
1496 
1497 int compareRes(const void* elem1, const void* elem2)
1498 {
1501 
1502  double res = Res2->resultat - Res1->resultat;
1503  int sgn = int(res / fabs(res));
1504  return (sgn);
1505 }
1506 
1507 int compareName(const void* elem1, const void* elem2)
1508 {
1511 
1512  if (Res1->name > Res2->name)
1513  {
1514  return 1;
1515  }
1516 
1517  return (-1);
1518 }
1519 
1520 void TYResultatWidget::sortColumnsByHeaderText(Qt::SortOrder order /*= Qt::AscendingOrder*/,
1521  Qt::CaseSensitivity cs /*= Qt::CaseInsensitive*/,
1522  bool localeAware /*= true*/)
1523 {
1524  struct Col
1525  {
1526  QString text;
1527  int logical;
1528  };
1529  std::vector<Col> cols;
1530  cols.reserve(_nbRecepteurs);
1531 
1532  // Récupérer les libellés d'en-tête
1533  for (int c = 2; c < _nbRecepteurs + 2; ++c)
1534  {
1535  QString txt;
1536  if (auto* it = _pTable->horizontalHeaderItem(c))
1537  txt = it->text();
1538  else
1539  txt = _pTable->model()->headerData(c, Qt::Horizontal).toString();
1540  cols.push_back({txt, c});
1541  }
1542 
1543  // Trier par libellé
1544  auto cmp = [&](const Col& a, const Col& b)
1545  {
1546  int r =
1547  localeAware ? QString::localeAwareCompare(a.text, b.text) : QString::compare(a.text, b.text, cs);
1548  return (order == Qt::AscendingOrder) ? (r < 0) : (r > 0);
1549  };
1550  std::stable_sort(cols.begin(), cols.end(), cmp);
1551 
1552  // Appliquer l'ordre en déplaçant les sections
1553  QHeaderView* hh = _pTable->horizontalHeader();
1554  hh->setSectionsMovable(true);
1555  _pTable->setUpdatesEnabled(false);
1556  QSignalBlocker blockHeader(hh);
1557 
1558  for (int target = 2; target < _nbRecepteurs + 2; ++target)
1559  {
1560  int from = hh->visualIndex(cols[target - 2].logical);
1561  if (from != target)
1562  hh->moveSection(from, target);
1563  }
1564 
1565  _pTable->setUpdatesEnabled(true);
1566  hh->setSectionsMovable(false);
1567 }
NxReal c
Definition: NxVec3.cpp:317
std::vector< LPTYCalcul > TYTabLPCalcul
Collection de pointeurs de TYCalcul.
Definition: TYDefines.h:394
outil IHM pour une entrée utilisateur (fichier header)
Boite de dialogue des parametres d'impression (fichier header)
Boite de dialogue pour la representation par une arborescence des elements contribuant au resultat d'...
#define IMG(id)
#define TR(id)
outil IHM pour un resultat (fichier header)
const std::vector< double > tabFreq
OTabFreq TYTabFreq
Collection des frequences.
Definition: TYSpectre.h:27
static OPrototype * safeDownCast(OPrototype *pObject)
Definition: TYElement.cpp:71
bool isA(const char *className) const
Definition: TYElement.cpp:65
OSpectreAbstract & subst(const OSpectreAbstract &spectre) const
Arithmetic subtraction of two spectrums in one-third Octave.
Definition: spectre.cpp:321
double valGlobDBA() const
Compute the global value dB[A] of a one-third Octave spectrum.
Definition: spectre.cpp:691
double valGlobDBLin() const
Compute the global value dB[Lin] of a one-third Octave spectrum.
Definition: spectre.cpp:679
void setType(TYSpectreType type)
Set the spectrum type.
Definition: spectre.h:153
void setValid(const bool &valid=true)
Definition: spectre.h:142
OSpectreAbstract & toDB() const
Converts to dB.
Definition: spectre.cpp:595
bool isValid() const
Check the spectrum validity. Invalidity is caused by: corrupted data, impossible calculation.
Definition: spectre.h:134
bool isTonalite() const
Existence d'une tonalite marquee.
Definition: spectre.cpp:1091
double getValueReal(double freq)
Definition: spectre.cpp:974
static int getIndice(const double &freq)
Return the index associated to a frequency.
Definition: spectre.h:398
Calculation program.
Definition: TYCalcul.h:50
int getState()
Get calculation state.
Definition: TYCalcul.h:416
@ Locked
Definition: TYCalcul.h:62
@ Actif
Definition: TYCalcul.h:63
LPTYSpectre getSpectre(const TYUUID &id_pt)
Definition: TYCalcul.cpp:1224
const LPTYResultat getResultat() const
Get result.
Definition: TYCalcul.h:367
TYElement * getParent() const
Definition: TYElement.h:706
const TYUUID & getID() const
Definition: TYElement.cpp:176
virtual QString getName() const
Definition: TYElement.h:691
Classe de definition d'un point de calcul.C'est une classe derivee a TYPoint avec en plus un spectrep...
Definition: TYPointCalcul.h:33
classe pour une boite de dialogue des parametres d'impression.
Definition: TYPrintDialog.h:51
QGroupBox * _groupBoxCalcul
Definition: TYPrintDialog.h:66
QLineEdit * _lineEditPied
Definition: TYPrintDialog.h:83
QLineEdit * _lineEditTete
Definition: TYPrintDialog.h:84
QGroupBox * _groupBoxProjet
Definition: TYPrintDialog.h:61
QLineEdit * _lineEditTitre
Definition: TYPrintDialog.h:86
classe de definition d'un projet.
Definition: TYProjet.h:45
TYTabLPCalcul & getListCalcul()
Set/Get de la liste des Calcul.
Definition: TYProjet.h:366
Boite de dialogue pour la representation par une arborescence des elements contribuant au resultat d'...
void set(LPTYResultat pResultat, LPTYPointCalcul pPtCalcul)
void slotContributionLineEditChanged()
double calcPct(double val)
OSpectre resuSpectre(OSpectre &spectre1, OSpectre &spectre2, const int &typeCase)
Calcul du spectre en fonction du contexte (option de calcul)
QRadioButton * _radioButtonDelta
unsigned int _nbLignes
Nombre de ligne, de colonnes.
virtual void updateContent()
QRadioButton * _radioButtonDBLIN
QGridLayout * _resultatLayout
void adjustXlsxDocumentColumnWidths(int columnCount, QXlsx::Document &documentQXlsx)
Ajuste automatique les largeurs des colonnes du fichier Excel.
void writeCumulatedContributionsTableRow(int columnCount, int row, QXlsx::Document &documentQXlsx)
Ecrit une ligne du cumul des contributions des sources aux récepteurs dans un fichier Excel au forma...
int _choixOperation
Type d'operation choisie.
virtual void setFrequency(int freq)
CHangement de la frequence de travail.
double _freq
Frequence de travail.
TYLineEdit * _pContributionLineEditHaut
QPushButton * _pButtonExportXlsx
void writeColHeadersToSheet(QXlsx::Document &xlsx, int columnCount)
Ecrit les en-têtes des colonnes dans la feuille Excel sélectionnée.
unsigned int _nbColonnes
void exportCumulatedContributionsTableToSheet(QXlsx::Document &xlsx)
Enregistre le cumul des contributions des sources aux récepteurs dans un fichier Excel au format xls...
double resuAffichage(OSpectre &spectre1, OSpectre &spectre2, bool &valid, const int &typeCase)
Calcul du contenu de la cellule en fonction du contexte (option de calcul)
QRadioButton * _radioButtonAmbiant
void updateFreqList()
Remplissage du combo des frequences.
QWidget * _pHorizontalLineWidget
void changeAffichage(int select)
QTableWidget * _pTable
QRadioButton * _radioButtonNoOp
TYCalcul * getSelectedSubstCalcul()
void changeSubstCalcul(int calcul)
QPushButton * _pButtonExportSpectre
TYResultatWidget(TYResultat *pElement, QWidget *_pParent=nullptr)
QRadioButton * _radioButtonEmergence
QPushButton * _pButtonExport
void decorsContributions(QTableWidgetItem *pItem, const int &row, const int &col, bool &isColored, std::vector< int > couleurs)
void sortColumnsByHeaderText(Qt::SortOrder order=Qt::AscendingOrder, Qt::CaseSensitivity cs=Qt::CaseInsensitive, bool localeAware=true)
Classe les récepteurs par ordre alphabétique dans la vue. Le modèle n'est pas modifié
void initTabSort(int col=1)
TYLineEdit * _pContributionLineEditBas
void writeRowHeadersToSheet(int row, QXlsx::Document &xlsx)
Ecrit les en-têtes des lignes dans la feuille Excel sélectionnée.
void decorsSynthese(QTableWidgetItem *pItem, const int &row, const int &col, const bool &isColored, OSpectre &spectre1, OSpectre &spectre2)
Coloration de la cellule en fonction du contexte pour la synthese, pour le reste du tableau.
TYSpectre getPuissanceElem(const unsigned int &i)
int _choixAffichage
Mode d'affichage (dBA, dBLin, dB(f))
OSpectre getSpectre(const int &row, const int &col, TYCalcul *pCalcul)
Recherche du spectre associe a une ligne et une colonne pour un calcul.
virtual void contextMenuEvent(QContextMenuEvent *e)
void showContribTreeDialog(int col)
TYStructIndiceResultat * _tabSortedRes
void writeContributionsTableRow(int columnCount, int row, QXlsx::Document &documentQXlsx)
Ecrit une ligne des contributions partielles des sources au récepteur dans un fichier Excel au forma...
unsigned int _nbRecepteurs
void displayColumn(TYCalcul *pCalcul, TYCalcul *pCalcOp, const int &col)
bool isPresenceTonaliteMarquee(const OSpectre &spectre)
int getXlsxRow(int row)
Renvoie l'index de ligne dans Excel en fonction de l'index de ligne dans la table des résultats.
QRadioButton * _radioButtonDBFRQ
std::vector< int > calcCumulatedContribution(const int &col, TYCalcul *pCalcul, TYCalcul *pCalcOp)
void exportContributionsTableToSheet(QXlsx::Document &documentQXlsx)
Enregistre les contributions partielles des sources aux récepteurs dans un fichier Excel au format x...
unsigned int _nbSources
Nombre de sources, de recepteurs.
QComboBox * _comboBoxFreq
Combo pour le choix de la frequence de travail.
void getFormatFromContributionsTable(QTableWidgetItem *item, QXlsx::Format &format)
Récupère le format de la cellule Ã&#160; partir de la table de résultats.
QComboBox * _comboBoxSubstCalcul
TYLineEdit * _pContributionLineEditMoy
std::vector< std::vector< double > > _cumulatedContribs
QRadioButton * _radioButtonDBA
virtual void apply()
QButtonGroup * _buttonGroupOperation
Choix du type de calcul.
void changeOperation(int select)
Changement du type d'operation.
Classe qui Permet de centraliser les resultats d'un calcul acoustique.
Definition: TYResultat.h:48
LPTYPointCalcul getRecepteur(const int &indexRecepteur)
Retourne le recepteur corresponadnt a l'indice passe.
Definition: TYResultat.cpp:546
void saveValue(const QString &filename, const int &affichage, double freq=100)
Sauvegarde des valeurs dans un fichier affichage : false -> dBA et true -> dBLin.
Definition: TYResultat.cpp:707
LPTYElement getSource(const int &indexSource)
Retourne la source correspondant a l'indice passe.
Definition: TYResultat.cpp:504
void saveSpectre(const QString &filename, TYCalcul *pSubstCalcul=NULL)
Sauvegarde des spectres dans un fichier.
Definition: TYResultat.cpp:567
OSpectre getSpectre(TYElement *pRecepteur, TYElement *pSource)
Retourne un spectre pour un couple S-R.
Definition: TYResultat.cpp:458
virtual void setIsReadOnly(bool flag)
Set/Get du flag _isReadOnly.
Definition: TYSpectre.h:141
static const TYTabFreq getTabFreqNorm(TYSpectreForm form=SPECTRE_FORM_TIERS)
Definition: TYSpectre.cpp:419
classe de l'objet IHM pour un objet metier de type TYElement
Definition: TYWidget.h:43
TYElement * _pElement
Definition: TYWidget.h:114
@ SPECTRE_TYPE_LP
Definition: spectre.h:31
bool operator<(dataPoint a)
std::pair< double, double > data