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  // It is not very explicit in Qt's QTableView documentation, but coordinates given to itemAt must be
745  // in the viewport's coordinate system (viewport = cells displayed on screen -- headers excluded)
746  QPoint resPoint = _pTable->viewport()->mapFrom(_pTable, point);
747  QTableWidgetItem* item = _pTable->itemAt(resPoint);
748  if (item)
749  {
750  int row = _pTable->indexAt(resPoint).row();
751  row = row >= 0 ? row : 0; // Securite
752  int col = _pTable->indexAt(resPoint).column();
753  col = col >= 0 ? col : 0; // Securite
754  int ligne = row > 0 ? _tabSortedRes[row - 1].indice : 0;
755 
756  OSpectre spectre1 = getSpectre(row, col, pCalcul);
757  OSpectre spectre2 = getSpectre(row, col, pSubstCalcul);
758 
759  TYSpectre spectre = resuSpectre(spectre1, spectre2, 1);
760 
761  spectre.setType(SPECTRE_TYPE_LP);
762  spectre = spectre.toDB();
763 
764  QAction *editSource = nullptr, *editRecepteur = nullptr, *editSpectre = nullptr,
765  *editContrib = nullptr;
766 
767  QMenu* pPopup = new QMenu(this);
768  if ((row == 0) && (col > 1)) // Ligne de synthese
769  {
770  if (_choixOperation == 0) // pas d'operation
771  {
772  editRecepteur = pPopup->addAction(TR("id_popup_see_recepteur"));
773  pPopup->addSeparator();
774  }
775  else
776  {
777  editSpectre = pPopup->addAction(TR("id_popup_see_spectre"));
778  }
779 
780  // Si on a conserve la matrice des resultats bruts
781  if (getElement()->getPartialState())
782  {
783  editContrib = pPopup->addAction(TR("id_popup_see_contrib"));
784  }
785  }
786  else if ((row > 0) && (col > 1)) // Si on selectionne une contribution par source (!= synthese)
787  {
788  editSpectre = pPopup->addAction(TR("id_popup_see_spectre"));
789  pPopup->addSeparator();
790  editSource = pPopup->addAction(TR("id_popup_see_source"));
791  pPopup->addSeparator();
792  editRecepteur = pPopup->addAction(TR("id_popup_see_recepteur"));
793  }
794  else if ((row > 0) && (col == 0))
795  {
796  editSource = pPopup->addAction(TR("id_popup_see_source"));
797  }
798  else if ((row > 0) && (col == 1))
799  {
800  editSource = pPopup->addAction(TR("id_popup_see_source"));
801  }
802 
803  QAction* ret = pPopup->exec(_pTable->mapToGlobal(point));
804 
805  if (ret)
806  {
807  if (ret == editSource)
808  {
809  getElement()->getSource(ligne)->edit(this);
810  }
811  else if (ret == editRecepteur)
812  {
813  TYCalcul* pCalcul = static_cast<TYCalcul*>(getElement()->getParent());
814  TYPointCalcul* pPoint = getElement()->getRecepteur(col - 2);
815  LPTYSpectre pSpectre = nullptr;
816 
817  if (pPoint)
818  {
819  pSpectre = pCalcul->getSpectre(pPoint->getID());
820  }
821  if (pSpectre == nullptr)
822  {
823  return;
824  }
825 
826  // Si c'est un resultat calcule, on ne peut pas changer les valeurs
827  if (pCalcul && (pCalcul->getState() == TYCalcul::Actif))
828  {
829  pSpectre->setIsReadOnly(true);
830  }
831  else
832  {
833  pSpectre->setIsReadOnly(false);
834  }
835 
836  pSpectre->edit(this);
837 
838  // Si c'est une mesure, on actualise le tableau resultat
839  if (pCalcul && (pCalcul->getState() == TYCalcul::Locked))
840  {
841  updateTable();
842  }
843  }
844  else if (ret == editSpectre)
845  {
846  spectre.setIsReadOnly(true);
847  spectre.edit(this);
848  spectre.setIsReadOnly(false);
849  }
850  else if (ret == editContrib)
851  {
853  }
854  }
855  }
856  }
857 }
858 
860 {
861  TYPrintDialog* pDialog = new TYPrintDialog(this);
862  pDialog->_groupBoxProjet->setEnabled(false);
863  pDialog->_groupBoxCalcul->setEnabled(false);
864  if (pDialog->exec() == QDialog::Accepted)
865  {
866  QPrintDialog dialog(_printer, this);
867  if (dialog.exec())
868  {
869  QPainter paint(_printer);
870 
871  QPixmap tmpPix;
872 
873  int mid = int(_printer->width() / 2) -
874  int(paint.fontMetrics().horizontalAdvance(pDialog->_lineEditTete->text()) / 2);
875  paint.drawText(mid, 20, pDialog->_lineEditTete->text());
876  mid = int(_printer->width() / 2) -
877  int(paint.fontMetrics().horizontalAdvance(pDialog->_lineEditPied->text()) / 2);
878  paint.drawText(mid, _printer->height() - 20, pDialog->_lineEditPied->text());
879  paint.setFont(QFont("Helvetica", 15, QFont::Bold));
880  mid = int(_printer->width() / 2) -
881  int(paint.fontMetrics().horizontalAdvance(pDialog->_lineEditTitre->text()) / 2);
882  paint.drawText(mid, 45, pDialog->_lineEditTitre->text());
883  paint.setFont(QFont());
884 
885  int sizeX = 120, sizeY = 25;
886  int ymax = int(double(_printer->height()) * 4 / 5 / (_pTable->rowCount() + 1));
887  if (ymax < sizeY)
888  {
889  sizeY = ymax;
890  }
891  int x = int(double(_printer->width() - sizeX * (_pTable->columnCount())) / 2);
892  int y = int((double(_printer->height()) - sizeY * (_pTable->rowCount() + 3)));
893 
894  int i = 0;
895  for (i = 0; i < _pTable->horizontalHeader()->count(); i++)
896  {
897  paint.drawText(x, y, _pTable->horizontalHeaderItem(i)->text());
898  paint.translate(sizeX, 0);
899  }
900 
901  paint.translate(-_pTable->columnCount() * sizeX, 0);
902  paint.translate(0, sizeY);
903 
904  for (i = 0; i < _pTable->rowCount(); i++)
905  {
906  for (int j = 0; j < _pTable->columnCount(); j++)
907  {
908  if (_pTable->item(i, j))
909  {
910  paint.drawText(x, y, _pTable->item(i, j)->text()); // paintCell(&paint, i, j, QRect(0,
911  // 0, sizeX, sizeY), false);
912  }
913  paint.translate(sizeX, 0);
914  }
915  paint.translate(0, sizeY);
916  paint.translate(-_pTable->columnCount() * sizeX, 0);
917  }
918  }
919  }
920 }
921 
923 {
924  switch (select)
925  {
926  case 1:
927  _choixAffichage = DBLIN; // Affichage dBLin
928  _comboBoxFreq->setEnabled(false);
929  break;
930  case 2:
931  _choixAffichage = DBFREQ; // Affichage par frequence
932  _comboBoxFreq->setEnabled(true);
933  break;
934  case 0:
935  default:
936  _choixAffichage = DBA; // Affichage dBA
937  _comboBoxFreq->setEnabled(false);
938  break;
939  }
940 
941  // Mets a jour le widget
943  updateTable();
944 }
945 
947 {
948  _choixOperation = select;
949 
950  if (_choixOperation == 0)
951  {
952  _comboBoxSubstCalcul->setEnabled(false);
953  _pButtonExport->setEnabled(true);
954  _pButtonExportSpectre->setEnabled(true);
955  }
956  else
957  {
958  _comboBoxSubstCalcul->setEnabled(true);
959  _pButtonExport->setEnabled(false);
960  _pButtonExportSpectre->setEnabled(false);
961  }
962 
963  // Mets a jour le widget
964  updateTable();
965 }
966 
968 {
969  // On commence par remplir la premiere colonne avec les noms des sources
970  QString titre = TR("id_entete_synthese");
971  _pTable->setItem(0, 0, new QTableWidgetItem(titre));
972  _pTable->setRowHeight(0, 30);
973  _pTable->setColumnWidth(0, 140);
974 
975  for (unsigned int row = 1; row < _nbLignes; row++) // On commence apres la ligne synthese
976  {
977  TYElement* pSource = getElement()->getSource(_tabSortedRes[row - 1].indice);
978  if (pSource == nullptr)
979  {
980  continue;
981  }
982 
983  QString titre = pSource->getName();
984  _pTable->setItem(row, 0, new QTableWidgetItem(titre));
985  _pTable->setRowHeight(row, 30);
986  }
987 
988  // Boucle sur les colonnes pour afficher le tableau
989  TYCalcul* pCalcOp = getSelectedSubstCalcul(); // Calcul à comparer
990  TYCalcul* pCalcul = TYCalcul::safeDownCast(_pElement->getParent()); // Calcul sélectionné
991 
992  for (unsigned int col = 1; col < _nbColonnes; col++)
993  {
994  displayColumn(pCalcul, pCalcOp, col);
995  }
996 }
997 
998 void TYResultatWidget::displayColumn(TYCalcul* pCalcul, TYCalcul* pCalcOp, const int& col)
999 {
1000  std::vector<int> couleur = calcCumulatedContribution(col, pCalcul, pCalcOp);
1001 
1002  for (unsigned int row = 0; row < _nbLignes; row++)
1003  {
1004  OSpectre spectre1 = getSpectre(row, col, pCalcul);
1005  OSpectre spectre2 = getSpectre(row, col, pCalcOp);
1006 
1007  QTableWidgetItem* pItem = nullptr;
1008  QString msg;
1009  double valeur = 0.0;
1010  bool valid = true;
1011 
1012  if (row == 0)
1013  {
1014  if (col > 1) // La case (0,1) est vide
1015  {
1016  valeur = resuAffichage(spectre1, spectre2, valid, CELL_SYNTH);
1017  msg = QString("%1").arg(valeur, 7, 'f', 1);
1018  pItem = new QTableWidgetItem(msg);
1019  decorsSynthese(pItem, row, col, valid, spectre1, spectre2);
1020  _pTable->setItem(row, col, pItem);
1021  _pTable->setRowHeight(row, 30);
1022  }
1023  }
1024  else if (col > 1) // Tout sauf ligne de synthese ou puissance de source
1025  {
1026  valeur = resuAffichage(spectre1, spectre2, valid, CELL_CONTRIB);
1027  msg = QString("%1").arg(valeur, 7, 'f', 1);
1028  pItem = new QTableWidgetItem(msg);
1029  decorsContributions(pItem, row, col, valid, couleur);
1030  _pTable->setItem(row, col, pItem);
1031  _pTable->setRowHeight(row, 30);
1032  }
1033  else // A priori, il ne reste que la puissance de la source
1034  {
1035  spectre2 = OSpectre(); // La puissance affichee correspond a la puissance de la source du
1036  // calcul courant
1037  valeur = resuAffichage(spectre1, spectre2, valid, CELL_LW);
1038  msg = QString("%1").arg(valeur, 7, 'f', 1);
1039  pItem = new QTableWidgetItem(msg);
1040  decorsContributions(pItem, row, col, valid, couleur);
1041  _pTable->setItem(row, col, pItem);
1042  _pTable->setRowHeight(row, 30);
1043  }
1044  }
1045  if (col >= 1)
1046  {
1047  _pTable->setColumnWidth(col, 50);
1048  }
1049 }
1050 
1051 OSpectre TYResultatWidget::getSpectre(const int& row, const int& col, TYCalcul* pCalcul)
1052 {
1053  OSpectre spectre;
1054  spectre.setValid(false);
1055 
1056  if ((!pCalcul) || (col == 0))
1057  {
1058  return spectre;
1059  } // Cas de la colonne des noms de source
1060 
1061  if (col == 1) // Spectre de puissance d'une source
1062  {
1063  if (row > 0)
1064  {
1065  spectre = getPuissanceElem(_tabSortedRes[row - 1].indice);
1066  }
1067  else
1068  {
1069  spectre.setValid(false);
1070  }
1071  }
1072  else
1073  {
1074  if (row == 0) // Ligne synthese
1075  {
1076  TYPointCalcul* pPoint = getElement()->getRecepteur(col - 2);
1077  if (pPoint)
1078  {
1079  spectre = *pCalcul->getSpectre(pPoint->getID());
1080  }
1081  }
1082  else // Contribution d'une source en un point
1083  {
1084  // Recuperation du resultat courant
1085  TYResultat* pThisRes = getElement();
1086  // Recuperation de pointeurs sur la source et du recepteur
1087  TYElement* pSource = pThisRes->getSource(_tabSortedRes[row - 1].indice);
1088  TYPointCalcul* pRecepteur = pThisRes->getRecepteur(col - 2);
1089 
1090  // Puis on recupere le spectre correspondant dans le calcul passe en parametre
1091  TYResultat* pResultat = pCalcul->getResultat();
1092  spectre = pResultat->getSpectre(pRecepteur, pSource);
1093  spectre = spectre.toDB();
1094  }
1095  }
1096 
1097  return spectre;
1098 }
1099 
1101 {
1102  int row = 1; // Numero de 1ere ligne (ligne 0 = synthese)
1103 
1104  TYCalcul* pCalcul = TYCalcul::safeDownCast(getElement()->getParent());
1105  TYCalcul* pSubstCalcul = getSelectedSubstCalcul();
1106 
1107  OSpectre spectre1;
1108  OSpectre spectre2;
1109 
1110  bool valid = true;
1111 
1112  for (unsigned int i = 0; i < getElement()->getNbOfSources(); i++)
1113  {
1114  _tabSortedRes[i].indice = i;
1115  row = i + 1;
1116 
1117  if (getElement() && getElement()->getSource(i))
1118  {
1119  _tabSortedRes[i].name = getElement()->getSource(i)->getName().toStdString();
1120  }
1121 
1122  spectre1 = getSpectre(row, col, pCalcul);
1123  spectre2 = getSpectre(row, col, pSubstCalcul);
1124 
1125  _tabSortedRes[i].resultat = resuAffichage(spectre1, spectre2, valid, 1);
1126  }
1127 }
1128 
1130 {
1131  if (col < 0)
1132  {
1133  return;
1134  }
1135  else if (col == 0)
1136  {
1137  sortName();
1138  }
1139  else
1140  {
1141  sortRes(col);
1142  // Dans ce cas, on reaffiche car on a reorganise les resultats
1143  }
1144 
1145  updateTable();
1146 }
1147 
1149 {
1150  // On commence par remplir le tableau des resultats
1151  // (la synthese est supposee etre toujours la plus forte valeur et "surnager" en haut du tableau)
1152  initTabSort(col);
1153 
1154  // Tri
1155  qsort(_tabSortedRes, getElement()->getNbOfSources(), sizeof(TYStructIndiceResultat), compareRes);
1156 }
1157 
1159 {
1160  // On commence par remplir le tableau des resultats
1161  // (la synthese est supposee etre toujours la plus forte valeur et "surnager" en haut du tableau)
1162  initTabSort(1);
1163 
1164  // Tri
1165  qsort(_tabSortedRes, getElement()->getNbOfSources(), sizeof(TYStructIndiceResultat), compareName);
1166 }
1167 
1169 {
1170  TYElement* pElement = getElement()->getSource(i);
1171 
1172  return getPuissanceElem(pElement);
1173 }
1174 
1176 {
1177  assert(pElement);
1178  TYSpectre spectre;
1179 
1180  std::map<TYElement*, LPTYSpectre>& mapElementSpectre = getElement()->getMapElementSpectre();
1181  TYSpectre* puissance = mapElementSpectre[pElement];
1182 
1183  if (puissance)
1184  {
1185  spectre = *puissance;
1186  }
1187 
1188  return spectre;
1189 }
1190 
1192 {
1193  TYResultatTreeDialog* pDlg = new TYResultatTreeDialog(this);
1194 
1195  // Recuperation du point de contrOle
1196  LPTYPointCalcul pPoint = getElement()->getRecepteur(col - 2);
1197  pDlg->set(getElement(), pPoint);
1198  pDlg->exec();
1199 }
1200 
1202 {
1203  return spectre.isTonalite();
1204 }
1205 
1207 {
1208  _seuilContributionBas = _pContributionLineEditBas->text().toDouble();
1209  _seuilContributionMoy = _pContributionLineEditMoy->text().toDouble();
1211 
1212  _pLabelLeqBas->setText(QString("Leq - ") + QString::number(_seuilContributionBas) + QString(" dB"));
1213  _pLabelLeqMoy->setText(QString("Leq - ") + QString::number(_seuilContributionMoy) + QString(" dB"));
1214  _pLabelLeqHaut->setText(QString("Leq - ") + QString::number(_seuilContributionHaut) + QString(" dB"));
1215 
1216  _pLabelPctBas->setText(QString::number(calcPct(_seuilContributionBas)) + QString(" %"));
1217  _pLabelPctMoy->setText(QString::number(calcPct(_seuilContributionMoy)) + QString(" %"));
1218  _pLabelPctHaut->setText(QString::number(calcPct(_seuilContributionHaut)) + QString(" %"));
1219 
1220  updateTable();
1221 }
1222 
1223 double TYResultatWidget::calcPct(double val)
1224 {
1225  double dummy = 100;
1226  double seuil = dummy - val;
1227  double dummyEner = pow(10, dummy / 10);
1228  double seuilEner = pow(10, seuil / 10);
1229  return int(100 * seuilEner / dummyEner);
1230 }
1231 
1238 {
1239  std::pair<double, double> data;
1241  inline bool operator<(dataPoint a)
1242  {
1243  return data.second < a.data.second;
1244  }
1245 };
1246 
1247 std::vector<int> TYResultatWidget::calcCumulatedContribution(const int& col, TYCalcul* pCalcul,
1248  TYCalcul* pCalcOp)
1249 {
1250  size_t nbSources = getElement()->getNbOfSources();
1251 
1252  std::vector<dataPoint> values = std::vector<dataPoint>(nbSources);
1253  std::vector<int> couleur = std::vector<int>(nbSources);
1254  if (nbSources == 0)
1255  return couleur;
1256 
1257  bool valid = true;
1258 
1259  // On ne s'occupe que des lignes correspondant à des sources, pas à la synthèse
1260  for (int row = 1; row <= nbSources; row++)
1261  {
1262  OSpectre spectre1 = getSpectre(row, col, pCalcul);
1263  OSpectre spectre2 = getSpectre(row, col, pCalcOp);
1264 
1265  if (col > 1)
1266  values[row - 1].data =
1267  std::pair<double, double>(row, resuAffichage(spectre1, spectre2, valid, CELL_CONTRIB));
1268  else
1269  values[row - 1].data =
1270  std::pair<double, double>(row, resuAffichage(spectre1, spectre2, valid, CELL_LW));
1271  }
1272  // on trie par valeur décroissante
1273  std::sort(values.begin(), values.end());
1274  std::reverse(values.begin(), values.end());
1275 
1276  // on calcul les contributions cumulées
1277  double cum = 0;
1278  for (int i = 0; i < nbSources; i++)
1279  {
1280  double val = values[i].data.second;
1281  val = pow(10, val * 0.1);
1282  cum += val;
1283  double res = 10 * log10(cum);
1284  values[i].data.second = res;
1285  if (col > 1) // Pas de cumul des puissances
1286  {
1287  _cumulatedContribs[int(values[i].data.first) - 1][col - 2] = res;
1288  }
1289  }
1290 
1291  // on détermine le code couleur de chaque contribution
1292  OSpectre spectre1 = getSpectre(0, col, pCalcul);
1293  OSpectre spectre2 = getSpectre(0, col, pCalcOp);
1294  double synthese = resuAffichage(spectre1, spectre2, valid, CELL_CONTRIB);
1295  double previousVal = values[0].data.second;
1296  for (int i = 0; i < nbSources; i++)
1297  {
1298  if (i > 0)
1299  {
1300  double currentVal = values[i].data.second;
1301  // La contribution max est toujours en rouge
1302  if (previousVal < (synthese - _seuilContributionBas) || i == 0)
1303  values[i].data.second = RED;
1304  else if (previousVal < (synthese - _seuilContributionMoy))
1305  values[i].data.second = ORANGE;
1306  else if (previousVal < (synthese - _seuilContributionHaut))
1307  values[i].data.second = YELLOW;
1308  else
1309  values[i].data.second = WHITE;
1310  previousVal = currentVal;
1311  }
1312  else
1313  values[i].data.second = RED;
1314 
1315  // on swap les pairs pour trier le vecteur selon l'ordre initial
1316  std::swap(values[i].data.first, values[i].data.second);
1317  }
1318 
1319  // on reprend l'ordre initial
1320  std::sort(values.begin(), values.end());
1321 
1322  for (int i = 0; i < nbSources; i++)
1323  {
1324  couleur[i] = values[i].data.first;
1325  }
1326 
1327  return couleur;
1328 }
1329 
1330 double TYResultatWidget::resuAffichage(OSpectre& spectre1, OSpectre& spectre2, bool& valid,
1331  const int& typeCase)
1332 {
1333  double val1 = 0.0, val2 = 0.0;
1334 
1335  switch (_choixAffichage)
1336  {
1337  case DBLIN:
1338  val1 = spectre1.valGlobDBLin();
1339  val2 = spectre2.valGlobDBLin();
1340  break;
1341  case DBFREQ:
1342  val1 = spectre1.getValueReal(_freq);
1343  val2 = spectre2.getValueReal(_freq);
1344  break;
1345  case DBA:
1346  default:
1347  val1 = spectre1.valGlobDBA();
1348  val2 = spectre2.valGlobDBA();
1349  break;
1350  }
1351 
1352  if (_choixOperation != 0)
1353  {
1354  if ((!spectre2.isValid()) || (typeCase == CELL_LW))
1355  {
1356  val2 = 0.0;
1357  }
1358  if ((!spectre2.isValid()) && ((typeCase == CELL_SYNTH) || (typeCase == CELL_CONTRIB)))
1359  {
1360  valid = false;
1361  }
1362  }
1363 
1364  switch (_choixOperation)
1365  {
1366  case 0: // Pas d'operation
1367  return val1;
1368  case 1: // difference entre deux resultats
1369  return val1 - val2;
1370  case 2: // emergence (uniquement pour la ligne synthese)
1371  if (typeCase == CELL_SYNTH)
1372  {
1373  return (TYResultat::safeDownCast(_pElement))->getEmergence(val1, val2);
1374  }
1375  else
1376  {
1377  return val1;
1378  }
1379  case 3: // bruit ambiant (uniquement pour la ligne synthese)
1380  default:
1381  if (typeCase == CELL_SYNTH)
1382  {
1383  return (TYResultat::safeDownCast(_pElement))->getAmbiant(val1, val2);
1384  }
1385  else
1386  {
1387  return val1;
1388  }
1389  }
1390 }
1391 
1392 OSpectre TYResultatWidget::resuSpectre(OSpectre& spectre1, OSpectre& spectre2, const int& typeCase)
1393 {
1394  switch (_choixOperation)
1395  {
1396  case 0: // Pas d'operation
1397  return spectre1;
1398  break;
1399  case 1: // difference entre deux resultats
1400  return spectre1.subst(spectre2);
1401  break;
1402  case 2: // emergence
1403  return (TYResultat::safeDownCast(_pElement))->getEmergence(spectre1, spectre2);
1404  break;
1405  case 3: // bruit ambiant
1406  default:
1407  return (TYResultat::safeDownCast(_pElement))->getAmbiant(spectre1, spectre2);
1408  break;
1409  }
1410 
1411  return OSpectre();
1412 }
1413 
1414 void TYResultatWidget::decorsSynthese(QTableWidgetItem* pItem, const int& row, const int& col,
1415  const bool& valid, OSpectre& spectre1, OSpectre& spectre2)
1416 {
1417  if (!valid)
1418  {
1419  pItem->setBackground(QBrush(QColor(127, 127, 127))); // Gris uni
1420  return;
1421  }
1422 
1423  if ((_choixAffichage == DBFREQ) || (_choixOperation == 1) || (_choixOperation == 2))
1424  {
1425  pItem->setBackground(QBrush(QColor(255, 255, 255))); // Blanc uni ?
1426  return; // Rien si affichage sur une frequence ou difference ou emergence
1427  }
1428 
1429  OSpectre spectre;
1431 
1432  if (_choixOperation == 3) // Bruit ambiant
1433  {
1434  spectre = getElement()->getAmbiant(spectre1, spectre2);
1435  }
1436  else if (_choixOperation == 0) // Pas d'operation
1437  {
1438  spectre = getSpectre(row, col, pCalcul);
1439  }
1440 
1441  if (isPresenceTonaliteMarquee(spectre)) // Coloration en jaune
1442  {
1443  pItem->setBackground(QBrush(QColor(255, 255, 0)));
1444  }
1445 }
1446 
1447 void TYResultatWidget::decorsContributions(QTableWidgetItem* pItem, const int& row, const int& col,
1448  bool& isColored, std::vector<int> couleurs)
1449 {
1450  double codeCoul = couleurs[row - 1];
1451  // Les cellules sont decorees sauf dans le cas ou on affiche l'ecart entre deux resultats
1452  if (!isColored)
1453  {
1454  pItem->setBackground(QBrush(QColor(127, 127, 127))); // Gris uni
1455  return;
1456  }
1457 
1458  if ((_choixOperation == 1) || (col == 1))
1459  {
1460  pItem->setBackground(QBrush(QColor(255, 255, 255))); // Blanc uni ?
1461  }
1462  else
1463  {
1464  // Affichage en couleur pour les cellules qui contribuent a plus que contribution cumulée -
1465  // seuil Uniquement dansle cas ou aucune operation n'a ete faite sur le resultat.
1466  if ((_choixOperation == 0) && (codeCoul == RED))
1467  {
1468  pItem->setBackground(QBrush(QColor(255, 0, 0)));
1469  }
1470  else if ((_choixOperation == 0) && (codeCoul == ORANGE))
1471  {
1472  pItem->setBackground(QBrush(QColor(255, 204, 0)));
1473  }
1474  else if ((_choixOperation == 0) && (codeCoul == YELLOW))
1475  {
1476  pItem->setBackground(QBrush(QColor(255, 255, 0)));
1477  }
1478  }
1479 }
1480 
1482 {
1484  for (unsigned int i = 0; i < tabFreq.size(); i++)
1485  {
1486  QString str;
1487  str.setNum(tabFreq[i], 'f', 1);
1488  _comboBoxFreq->insertItem(i, str);
1489  }
1490 }
1491 
1493 {
1494  _freq = _comboBoxFreq->currentText().toFloat();
1496  updateTable();
1497 }
1498 
1499 int compareRes(const void* elem1, const void* elem2)
1500 {
1503 
1504  double res = Res2->resultat - Res1->resultat;
1505  int sgn = int(res / fabs(res));
1506  return (sgn);
1507 }
1508 
1509 int compareName(const void* elem1, const void* elem2)
1510 {
1513 
1514  if (Res1->name > Res2->name)
1515  {
1516  return 1;
1517  }
1518 
1519  return (-1);
1520 }
1521 
1522 void TYResultatWidget::sortColumnsByHeaderText(Qt::SortOrder order /*= Qt::AscendingOrder*/,
1523  Qt::CaseSensitivity cs /*= Qt::CaseInsensitive*/,
1524  bool localeAware /*= true*/)
1525 {
1526  struct Col
1527  {
1528  QString text;
1529  int logical;
1530  };
1531  std::vector<Col> cols;
1532  cols.reserve(_nbRecepteurs);
1533 
1534  // Récupérer les libellés d'en-tête
1535  for (int c = 2; c < _nbRecepteurs + 2; ++c)
1536  {
1537  QString txt;
1538  if (auto* it = _pTable->horizontalHeaderItem(c))
1539  txt = it->text();
1540  else
1541  txt = _pTable->model()->headerData(c, Qt::Horizontal).toString();
1542  cols.push_back({txt, c});
1543  }
1544 
1545  // Trier par libellé
1546  auto cmp = [&](const Col& a, const Col& b)
1547  {
1548  int r =
1549  localeAware ? QString::localeAwareCompare(a.text, b.text) : QString::compare(a.text, b.text, cs);
1550  return (order == Qt::AscendingOrder) ? (r < 0) : (r > 0);
1551  };
1552  std::stable_sort(cols.begin(), cols.end(), cmp);
1553 
1554  // Appliquer l'ordre en déplaçant les sections
1555  QHeaderView* hh = _pTable->horizontalHeader();
1556  hh->setSectionsMovable(true);
1557  _pTable->setUpdatesEnabled(false);
1558  QSignalBlocker blockHeader(hh);
1559 
1560  for (int target = 2; target < _nbRecepteurs + 2; ++target)
1561  {
1562  int from = hh->visualIndex(cols[target - 2].logical);
1563  if (from != target)
1564  hh->moveSection(from, target);
1565  }
1566 
1567  _pTable->setUpdatesEnabled(true);
1568  hh->setSectionsMovable(false);
1569 }
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