ATLAS Offline Software
Loading...
Searching...
No Matches
PhiSectionWidget.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <QMouseEvent>
8#include <QGraphicsEllipseItem>
9#include <QCursor>
10#include <QDrag>
11#include <QMenu>
12#include <QDragEnterEvent>
13#include <QDropEvent>
14#include <QApplication>
15#include <QBuffer>
16#include <QClipboard>
17#include <QInputDialog>
18#include <QVector>
19#include <QMimeData>
20#include <QDebug>
21
22#include <cmath>
23#include <iostream>
24
26// //
27// Implementation of class PhiSectionWidget //
28// //
29// Author: Thomas Kittelmann <Thomas.Kittelmann@cern.ch> //
30// //
31// Initial VP1 version: September 2007 //
32// Major update: January 2009 //
33// Riccardo-Maria BIANCHI <rbianchi@cern.ch>: March 2013 //
34// Riccardo-Maria BIANCHI <rbianchi@cern.ch>: March 2023 //
35// //
37
38//____________________________________________________________________
40public:
42
43 //Sectors status and mapping to graphics:
44 QVector<bool> sectorstatus;
45 std::map<QGraphicsEllipseItem*,int> item2sector;
46
47 void approximateSectorStatusFromRanges( const QList<VP1Interval>& oldEnabledRanges, QVector<bool>& target );
48
50
51 //Styles:
52 QPen pen_on;
53 QPen pen_off;
54 QBrush brush_on;
55 QBrush brush_off;
56
57 //Update colours based on current sectorstatus vector:
58 void updateColors();
59
60 //Cache:
62 QList<VP1Interval> cachedRanges;//this also serves as the cache
63 bool cachedAllOn;//part of the cache
64 bool cachedAllOff;//part of the cache
65
66 //Convenience:
67 static void wrap(QList<VP1Interval>&);
68
69 //Allowed sectors:
71 QList<int> allowedNSectors;
72
73 //Menu:
74 QMenu * popup_menu;
81 QList<QAction*> popuplist_setNPhi;
83 void ensureMenuInit();
85
86 //Decoding the current phi-ranges and checking for changes:
87 QList<VP1Interval> enabledPhiRangesNoCache(const QVector<bool>& secstatus,
88 bool& allOn, bool& allOff) const;
89 void checkForChanges();
90
91};
92
93
94//____________________________________________________________________
96 : QGraphicsView(parent),
97 VP1HelperClassBase(sys,"PhiSectionWidget"),
98 m_d(new Imp)
99{
100 if(VP1Msg::verbose()){
101 messageVerbose("PhiSectionWidget constr");
102 }
103
104 m_d->theclass = this;
105 m_d->popup_menu = 0;
106 m_d->popup_enableAllAction = 0;
107 m_d->popup_disableAllAction = 0;
108 m_d->popup_invertAction = 0;
109 m_d->popup_copyAction = 0;
110 m_d->popup_pasteAction = 0;
111 m_d->popup_setNPhiSubMenu = 0;
112
113 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
114 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
115 setRenderHint(QPainter::Antialiasing,true);
116
117 m_d->pen_on.setWidth(0);
118 m_d->pen_on.setBrush(Qt::red);
119 m_d->pen_off.setWidth(0);
120 m_d->pen_off.setBrush(Qt::gray);
121 m_d->brush_on.setColor(Qt::red);
122 m_d->brush_on.setStyle(Qt::SolidPattern);
123 m_d->brush_off.setColor(Qt::gray);
124 m_d->brush_off.setStyle(Qt::SolidPattern);
125
126 m_d->cacheValid = false;
127
128 setFocusPolicy(Qt::NoFocus);
129 setAcceptDrops(true);
130
131 //The following is the way to init N sectors:
132 m_d->allowCustomNSectors = true;
133 QList<int> defaultAllowedNSectors;
134 defaultAllowedNSectors << 4 << 5 << 6 << 8 << 9 << 10
135 << 12 << 16 << 24 << 32 << 36 << 48 << 64;
136 m_d->allowedNSectors << 12; // default number of sectors, at start
137 setNumberOfSectors(12,true);
138 setAllowedNumberOfSectors(std::move(defaultAllowedNSectors),true);
139}
140
141//____________________________________________________________________
143{
144 QGraphicsScene * oldscene = scene();
145 if (oldscene) {
146 setScene(0);
147 delete oldscene;
148 }
149 delete m_d;
150}
151
152//____________________________________________________________________
153void PhiSectionWidget::setNumberOfSectors(int nsectors,bool forceAllEnabled)
154{
155 if(VP1Msg::debug()){
156 messageDebug("setNumberOfSectors()");
157 }
158
159
160 if (nsectors<4||nsectors>99) {
161 if(VP1Msg::debug()){
162 messageDebug("nsectors<4||nsectors>99. Returning.");
163 }
164 return;
165 }
166
167 if (!m_d->allowedNSectors.contains(nsectors) && !m_d->allowCustomNSectors) {
168 //Oups! Let us try first to pick something among the allowed
169 //values which would allow us to preserve the ranges exactly;
170 int n(-1);
171 for(int i = 2; i < 100; ++i) {
172 if (m_d->allowedNSectors.contains(i*nsectors)) {
173 n = i*nsectors;
174 break;
175 }
176 }
177 nsectors = n>0 ? n : m_d->allowedNSectors.back();
178 } else if (!m_d->sectorstatus.isEmpty() && nsectors==static_cast<int>(m_d->sectorstatus.count())) {
179 if(VP1Msg::debug()){
180 messageDebug("!sectorstatus.isEmpty() && nsectors==sectorstatus.count(). Returning...");
181 }
182 return;
183 }
184
185 if ( m_d->sectorstatus.isEmpty() ) {
186 if(VP1Msg::debug()){
187 messageDebug("m_d->sectorstatus is Empty.");
188 }
189 }
190
191 // check if sectors have already been defined
192 QList<VP1Interval> oldEnabledRanges;
193 if ( !m_d->sectorstatus.isEmpty() ) {
194 oldEnabledRanges = enabledPhiRanges();
195 }
196
197 //Update new graphics objects with the new settings
198
199 // first clear everything...
200 m_d->item2sector.clear();
201 m_d->sectorstatus.clear();
202 QGraphicsScene * oldscene = scene();
203 setScene(new QGraphicsScene);
204 delete oldscene;
205
206 // ...then build new variables with the new settings of 'nsectors'
207 const double R = 10.0;
208 const double r = (2*M_PI)*R / nsectors / 1.2;
209
210 for (int isector = 0; isector < nsectors; ++isector) {
211 double phi = (isector+0.5)*(2*M_PI)/nsectors;
212 double x(R*cos(phi)), y(-R*sin(phi));
213 QGraphicsEllipseItem * ellipse = scene()->addEllipse(x,y,r,r);
214 m_d->item2sector[ellipse]=isector;
215 }
216
217 m_d->sectorstatus.fill(forceAllEnabled,m_d->item2sector.size());
218
219 if (!forceAllEnabled)
220 m_d->approximateSectorStatusFromRanges(oldEnabledRanges,m_d->sectorstatus);
221 m_d->updateColors();
222 fitInView(scene()->sceneRect());
223 m_d->checkForChanges();
224
225
226 // resize the widget based on the number of sectors
227 // we need to make it larger as the number of sectors increases
228 // otherwise the 'red dots' are difficult to see and pick with the mouse
229 // Note: numbers of sectors are not continuos: after 12, 16 comes, then 24, ...
230 if (nsectors <= 12) {
231 setFixedSize(60,60);
232 } else if(nsectors >= 16 && nsectors < 24) {
233 setFixedSize(120,120);
234 } else if(nsectors >= 24 && nsectors < 32) {
235 setFixedSize(200,200);
236 } else if (nsectors >= 32 && nsectors <= 36) {
237 setFixedSize(300,300);
238 } else if (nsectors > 36) {
239 setFixedSize(400,400);
240 }
241
242
243 if ( m_d->sectorstatus.isEmpty() ) {
244 if(VP1Msg::debug()){
245 messageDebug("WARNING. m_d->sectorstatus is still Empty...");
246 }
247 }
248}
249
250
251//____________________________________________________________________
253{
254 return m_d->sectorstatus.count();
255}
256
257//____________________________________________________________________
259{
260 std::map<QGraphicsEllipseItem*,int>::iterator it, itE = item2sector.end();
261 for (it = item2sector.begin();it!=itE;++it) {
262 if (sectorstatus[it->second]) {
263 it->first->setPen(pen_on);
264 it->first->setBrush(brush_on);
265 } else {
266 it->first->setPen(pen_off);
267 it->first->setBrush(brush_off);
268 }
269 }
270}
271
272//____________________________________________________________________
273void PhiSectionWidget::setSectorStatus(int isector, bool status)
274{
275 if (isector<0||isector>=static_cast<int>(m_d->sectorstatus.count()))
276 return;
277 if (m_d->sectorstatus.at(isector)==status)
278 return;
279 m_d->sectorstatus[isector]=status;
280 m_d->cacheValid=false;
281 m_d->checkForChanges();
282}
283
284//____________________________________________________________________
286{
287 if (popup_menu)
288 return;
289 popup_menu = new QMenu(theclass);
290 popup_copyAction = popup_menu->addAction("&Copy");
291 popup_pasteAction = popup_menu->addAction("&Paste");
292 popup_menu->addSeparator();
293 popup_enableAllAction = popup_menu->addAction("&Enable all sectors");
294 popup_disableAllAction = popup_menu->addAction("&Disable all sectors");
295 popup_invertAction = popup_menu->addAction("&Invert");
296 popup_menu->addSeparator();
297 popup_setNPhiSubMenu = popup_menu->addMenu("&Set number of phi sectors");
299}
300
301//____________________________________________________________________
303{
304 if (!popup_menu)
305 return;
306 if (!popuplist_setNPhi.isEmpty()) {
307 for(QAction * setNPhiAct : popuplist_setNPhi)
308 delete setNPhiAct;
309 }
310 popuplist_setNPhi.clear();
311
312 for(int nSectors : allowedNSectors) {
313 QAction * a = popup_setNPhiSubMenu->addAction(QString::number(nSectors));
314 a->setData(nSectors);
316 }
318 popup_setNPhiSubMenu->addSeparator();
319 popup_setCustomNPhi = popup_setNPhiSubMenu->addAction("&Custom...");
320 }
321}
322
323//____________________________________________________________________
325{
326 //Prepare:
327 m_d->ensureMenuInit();
328 m_d->popup_enableAllAction->setEnabled(!allSectorsOn());
329 m_d->popup_disableAllAction->setEnabled(!allSectorsOff());
330
331 QClipboard * clipboard = QApplication::clipboard();
332 m_d->popup_pasteAction->setEnabled(clipboard
333 &&clipboard->mimeData()->hasFormat("vp1/enabledphisectors"));
334
335 for(QAction * setNPhiAct : m_d->popuplist_setNPhi) {
336 bool ok;
337 int nSectors = setNPhiAct->data().toInt(&ok);
338 setNPhiAct->setEnabled(ok&&nSectors!=m_d->sectorstatus.count());
339 }
340
341 //Launch
342 QAction * selAct = m_d->popup_menu->exec(p);
343
344 //React
345 if (selAct==m_d->popup_copyAction) {
346 QMimeData *mimeData = new QMimeData;
347 mimeData->setData("vp1/enabledphisectors", state());
348 mimeData->setText(enabledRangesToString());
349 clipboard->setMimeData(mimeData);
350 return;
351 }
352 if (selAct==m_d->popup_pasteAction) {
353 QByteArray data = clipboard->mimeData()->data("vp1/enabledphisectors");
354 setState(std::move(data));
355 return;
356 }
357 if (selAct==m_d->popup_enableAllAction) {
358 for (int i = 0; i < m_d->sectorstatus.count(); ++i)
359 m_d->sectorstatus[i] = true;
360 m_d->cacheValid = false;
361 m_d->checkForChanges();
362 return;
363 }
364 if (selAct==m_d->popup_disableAllAction) {
365 for (int i = 0; i < m_d->sectorstatus.count(); ++i)
366 m_d->sectorstatus[i] = false;
367 m_d->cacheValid = false;
368 m_d->checkForChanges();
369 return;
370 }
371 if (selAct==m_d->popup_invertAction) {
372 for (int i = 0; i < m_d->sectorstatus.count(); ++i)
373 m_d->sectorstatus[i] = !m_d->sectorstatus[i];
374 m_d->cacheValid = false;
375 m_d->checkForChanges();
376 return;
377 }
378 if (selAct==m_d->popup_setCustomNPhi) {
379 bool ok;
380 // int nCustomSectors = QInputDialog::getInteger(this, "Set number of phi sectors",
381 int nCustomSectors = QInputDialog::getInt(this, "Set number of phi sectors",
382 "Set number of phi sectors", m_d->sectorstatus.count(),4,99,1,&ok);
383 if (ok && nCustomSectors >= 4 && nCustomSectors <= 99 )
384 setNumberOfSectors(nCustomSectors);
385 return;
386 }
387 if (m_d->popuplist_setNPhi.contains(selAct)) {
388 bool ok;
389 int nSectors = selAct->data().toInt(&ok);
390 if (ok)
391 setNumberOfSectors(nSectors);
392 return;
393 }
394}
395
396//____________________________________________________________________
397void PhiSectionWidget::mousePressEvent(QMouseEvent *event)
398{
399 if (event->buttons()==Qt::RightButton) {
400 launchContextMenu(QCursor::pos());
401 return;
402 }
403
404 if (event->button() == Qt::LeftButton)
405 m_d->dragStartPosition = event->pos();
406
407 if (event->buttons()!=Qt::LeftButton) {
408 QGraphicsView::mousePressEvent(event);
409 return;
410 }
411 QGraphicsItem *item_ = itemAt(event->pos());
412 QGraphicsEllipseItem * item = static_cast<QGraphicsEllipseItem*>(item_);
413 if (!item||m_d->item2sector.find(item)==m_d->item2sector.end()) {
414 QGraphicsView::mousePressEvent(event);
415 return;
416 }
417 int isector = m_d->item2sector[item];
418 if (isector<0||isector>=static_cast<int>(m_d->sectorstatus.count())) {
419 QGraphicsView::mousePressEvent(event);
420 return;
421 }
422 m_d->sectorstatus[isector]=!(m_d->sectorstatus.at(isector));
423 if(VP1Msg::verbose()){
424 messageVerbose("Turning on sector"+QString::number(isector));
425 }
426 m_d->cacheValid=false;
427 m_d->checkForChanges();
428}
429
430//____________________________________________________________________
431void PhiSectionWidget::mouseMoveEvent(QMouseEvent *event)
432{
433 if (!(event->buttons() & Qt::LeftButton))
434 return;
435 if ((event->pos() - m_d->dragStartPosition).manhattanLength()
436 < QApplication::startDragDistance())
437 return;
438
439 QDrag *drag = new QDrag(this);
440 QMimeData *mimeData = new QMimeData;
441
443 // For dragging state onto other phi section widgets: //
445
446 mimeData->setData("vp1/enabledphisectors", state());
447
449 // For dragging a readable version of the enabled phi-ranges //
450 // into e.g. an editor or email program: //
452
453 mimeData->setText(enabledRangesToString());
454
455 //Execute drag:
456 drag->setMimeData(mimeData);//drag assumes ownership of mimeData
457 drag->exec(Qt::CopyAction | Qt::MoveAction);
458}
459
460//____________________________________________________________________
461void PhiSectionWidget::dragEnterEvent(QDragEnterEvent *event)
462{
463 if (event->source()!=this && event->mimeData()->hasFormat("vp1/enabledphisectors"))
464 event->acceptProposedAction();
465}
466
467//____________________________________________________________________
468void PhiSectionWidget::dropEvent(QDropEvent *event)
469{
470 QByteArray data = event->mimeData()->data("vp1/enabledphisectors");
471 event->acceptProposedAction();
472 setState(std::move(data));
473}
474
475//____________________________________________________________________
477{
478 if (scene())
479 fitInView(scene()->sceneRect());
480}
481
482//____________________________________________________________________
484{
485 if (!m_d->cacheValid)
486 m_d->checkForChanges();
487 return m_d->cachedAllOn;
488}
489
490
491//____________________________________________________________________
493{
494 if (!m_d->cacheValid)
495 m_d->checkForChanges();
496 return m_d->cachedAllOff;
497}
498
499//____________________________________________________________________
500void PhiSectionWidget::Imp::wrap(QList<VP1Interval>& l)
501{
502 if (l.count()<2||l.front().lower()!=0.0||l.back().upper()!=(2*M_PI))
503 return;
504 l.front().setLower(l.back().lower()-(2*M_PI));
505 l.removeLast();
506}
507
508
509//____________________________________________________________________
510QList<VP1Interval> PhiSectionWidget::Imp::enabledPhiRangesNoCache(const QVector<bool>& secstatus, bool& allOn, bool& allOff) const
511{
512 if(VP1Msg::verbose()){
513 theclass->messageVerbose("enabledPhiRangesNoCache()");
514 }
515 QList<VP1Interval> l;
516 allOn = true;
517 allOff = true;
518
519 const unsigned int n = secstatus.count();
520
521 const double dphi = (2*M_PI)/n;
522 if(VP1Msg::debug()){
523 qDebug() << "n: " << n << " - dphi:" << dphi;
524 }
525
526 bool open(false);
527 double tmp(-999);
528
529 for (unsigned i = 0; i < n; ++i) {
530 const bool status = secstatus[i];
531 if (status) {
532 allOff = false;
533 }
534 else {
535 allOn = false;
536 }
537 if (status!=open) {
538 if (!open) {
539 tmp = i*dphi;
540 open = true;
541 } else {
542 l << VP1Interval(tmp,i*dphi);
543 open = false;
544 }
545 }
546 }
547 if (open)
548 l << VP1Interval(tmp,(2*M_PI));
549 wrap(l);
550
551 if(VP1Msg::debug()){
552 theclass->messageDebug("exiting enabledPhiRangesNoCache()...");
553 }
554
555 return l;
556}
557
558
559//____________________________________________________________________
560QList<VP1Interval> PhiSectionWidget::enabledPhiRanges() const
561{
562 if(VP1Msg::debug()){
563 messageDebug("enabledPhiRanges()");
564 }
565
566 if (!m_d->cacheValid) {
567 if(VP1Msg::debug()){
568 messageDebug("Cache not valid. Checking for changes...");
569 }
570 m_d->checkForChanges();
571 }
572 return m_d->cachedRanges;
573}
574
575//____________________________________________________________________
576QList<VP1Interval> PhiSectionWidget::enabledPhiRanges(double phi_min,double phi_max) const
577{
578 if(VP1Msg::debug()){
579 messageDebug("enabledPhiRanges(double phi_min,double phi_max)");
580 }
581
582 if (phi_min>=phi_max)
583 return QList<VP1Interval>();
584 if (phi_max-phi_min>=(2*M_PI))
585 return enabledPhiRanges();
586 while (phi_min<0) {
587 phi_min += (2*M_PI);
588 phi_max += (2*M_PI);
589 }
590
591 //For ranges such as -310deg->10deg, phi_max might now be larger
592 //than 2pi. We handle this as a special case, merging the result of
593 //two calls to this method:
594 if (phi_max>(2*M_PI)) {
595 QList<VP1Interval> l1 = enabledPhiRanges(phi_min,(2*M_PI));
596 QList<VP1Interval> l2 = enabledPhiRanges(0,phi_max-(2*M_PI));
597 // if (!l1.empty()&&!l2.empty()&&l1.front()
598 l2 << l1;
599 Imp::wrap(l2);
600 return l2;
601 }
602
603 QList<VP1Interval> l = enabledPhiRanges();
604 if (l.empty())
605 return l;
606
607 //In case one of the ranges wraps around at phi=0, we first unwrap
608 //the list:
609 if (l.front().lower()<0.0) {
610 l.append(VP1Interval(l.front().lower()+(2*M_PI),(2*M_PI)));
611 l.front().setLower(0.0);
612 }
613
614
615 //Now, phi_min<phi_max and both are in [0,2pi]. Now, loop over all
616 //ranges and constrain them to [phi_min,phi_max], removing those
617 //that fall outside:
618 double a,b;
619 for ( int i = 0; i < l.count(); ) {
620 a = l[i].lower();
621 b = l[i].upper();
622 if (b <= phi_min||a >= phi_max) {
623 l.removeAt(i);
624 } else {
625 if (a<phi_min)
626 l[i].setLower(phi_min);
627 if (b>phi_max)
628 l[i].setUpper(phi_max);
629 ++i;
630 }
631 }
632
633 Imp::wrap(l);
634
635 return l;
636}
637
638//____________________________________________________________________
640{
641 if (!m_d->cacheValid)
642 m_d->checkForChanges();
643 QString s;
644 for(int i=0;i<m_d->cachedRanges.count();++i)
645 s+= m_d->cachedRanges.at(i).toString()+(i==m_d->cachedRanges.count()-1?"":", ");
646 return s;
647}
648
649//____________________________________________________________________
651{
652 if(VP1Msg::debug()){
653 theclass->messageDebug("checkForChanges()");
654 }
655
656 //Ensure caches are updated, and emit signal in case of any change:
657 cacheValid = true;
658
660 if (cachedRanges == r) {
661 return;
662 }
663 updateColors();
664 cachedRanges = r;
665
666 if(VP1Msg::verbose()){
667 QString s;
668 for(int i=0;i<r.count();++i)
669 s+= r.at(i).toString()+(i==r.count()-1?"":", ");
670 theclass->messageVerbose("Emitting enabledPhiRangesChanged("
671 +theclass->enabledRangesToString()+")");
672 }
673 emit theclass->enabledPhiRangesChanged(r);
674}
675
676//____________________________________________________________________
677bool PhiSectionWidget::virtualSectorEnabled(int iSector,int nSectors) const
678{
679// this->messageDebug("virtualSectorEnabled()");
680
681 if (iSector<0||iSector>=nSectors||nSectors<1)
682 return false;
683 if (!m_d->cacheValid)
684 m_d->checkForChanges();
685 if (m_d->cachedAllOn)
686 return true;
687 if (m_d->cachedAllOff)
688 return false;
689
690 //Phi-range of virtual sector:
691 const double dphi = (2*M_PI)/nSectors;
692 const double epsilon(dphi*1.0e-9);
693 VP1Interval phirange(dphi*iSector+epsilon,dphi*(iSector+1)-epsilon);
694
695 //Compare with enabled ranges:
696 for(const VP1Interval& enabledrange : m_d->cachedRanges) {
697 if (phirange.hasOverlap(enabledrange,2*M_PI))
698 return true;
699 }
700 return false;
701}
702
703//____________________________________________________________________
704QVector<bool> PhiSectionWidget::virtualSectorsEnabled(int nSectors) const
705{
706 if (nSectors<1)
707 return QVector<bool>();
708 QVector<bool> v(nSectors,false);
709 for (int i = 0; i < nSectors; ++i)
710 if (virtualSectorEnabled(i,nSectors))
711 v[i] = true;
712 return v;
713}
714
715//____________________________________________________________________
717{
718 //Constrain phi to [0,2*pi[
719 while (phi<0) phi+=(2*M_PI);
720 while (phi>=(2*M_PI)) phi-=(2*M_PI);
721 if (phi<0.0) phi=0.0;
722
723 int iphi = static_cast<int>(nSectors*phi/((2*M_PI)));
724 return iphi;
725}
726
727//____________________________________________________________________
728QByteArray PhiSectionWidget::state() const
729{
730 // ===> Setup stream writing to a byteArray:
731 QByteArray byteArray;
732 QBuffer buffer(&byteArray);
733 buffer.open(QIODevice::WriteOnly);
734 QDataStream out(&buffer);
735 out << qint32(0);//version
736 out << m_d->sectorstatus;//This is all the data we output,
737 //allowing for applicability of the data
738 //between different widgets, even if they are
739 //being used differently.
740 buffer.close();
741 return byteArray;
742
743
744}
745
746//____________________________________________________________________
747void PhiSectionWidget::setState(QByteArray ba)
748{
749 if(VP1Msg::verbose()){
750 this->messageVerbose("setState()");
751 }
752 // ===> Setup stream for getting the contents of the byteArray:
753 QBuffer buffer(&ba);
754 buffer.open(QIODevice::ReadOnly);
755 QDataStream state(&buffer);
756
757 qint32 version;
758 state >> version;
759 if (version!=0)
760 return;
761
762 QVector<bool> restored_sectorstatus;
763 state >> restored_sectorstatus;
764 buffer.close();
765
766 bool save = blockSignals(true);
767 if (restored_sectorstatus.count()!=m_d->sectorstatus.count())
768 setNumberOfSectors(restored_sectorstatus.count(),true);
769 if (restored_sectorstatus.count()==m_d->sectorstatus.count()) {
770 m_d->sectorstatus = std::move(restored_sectorstatus);
771 } else {
772 bool allon, alloff;
773 QList<VP1Interval> r = m_d->enabledPhiRangesNoCache(restored_sectorstatus,allon, alloff);
774 if (allon) {
775 m_d->sectorstatus.fill(true);
776 }
777 else if (alloff) {
778 m_d->sectorstatus.fill(true);
779 }
780 else {
781 m_d->approximateSectorStatusFromRanges(r,m_d->sectorstatus);
782 }
783 }
784 if (!save)
785 blockSignals(false);
786 m_d->cacheValid=false;
787 m_d->checkForChanges();
788}
789
790//____________________________________________________________________
791void PhiSectionWidget::Imp::approximateSectorStatusFromRanges( const QList<VP1Interval>& oldEnabledRanges,
792 QVector<bool>& target )
793{
794 if (oldEnabledRanges.isEmpty()) {
795 target.fill(false);
796 return;
797 }
798 if (oldEnabledRanges.count()==1&&oldEnabledRanges.first().length()>=2*M_PI*(1.0-1.0e-10)) {
799 target.fill(true);
800 return;
801 }
802 const unsigned n = target.size();
803 target.fill(false);
804 const double dphi = (2*M_PI)/n;
805 const double epsilon(dphi*1.0e-9);
806 for (unsigned i = 0; i < n; ++i) {
807 VP1Interval phirange(dphi*i+epsilon,dphi*(i+1)-epsilon);
808 for(const VP1Interval& oldrange : oldEnabledRanges) {
809 if (phirange.hasOverlap(oldrange,2*M_PI)) {
810 target[i]=true;
811 break;
812 }
813 }
814 }
815}
816
817//____________________________________________________________________
818void PhiSectionWidget::dragMoveEvent ( QDragMoveEvent * event )
819{
820 //Reimplement to avoid interference by the QGraphicsView implementation.
821 event->acceptProposedAction();
822}
823
824//____________________________________________________________________
825void PhiSectionWidget::dragLeaveEvent ( QDragLeaveEvent * )
826{
827 //Reimplement to avoid interference by the QGraphicsView implementation.
828}
829
830//____________________________________________________________________
831void PhiSectionWidget::setAllowedNumberOfSectors(QList<int> allowedNSectors, bool allowCustom)
832{
833 if(VP1Msg::verbose()){
834 messageVerbose("setAllowedNumberOfSectors()");
835 }
836
837 //Check validity:
838 if (allowedNSectors.isEmpty()) {
839 if(VP1Msg::verbose()){
840 messageVerbose("allowedNSectors empty. Returning.");
841 }
842 return;
843 }
844 for(int s : allowedNSectors) {
845 if (s<4) {
846 if(VP1Msg::verbose()){
847 messageVerbose("allowedNSectors s < 4. Returning.");
848 }
849 return;
850 }
851 }
852
853 if (allowCustom&&!allowedNSectors.contains(m_d->sectorstatus.count())) {
854 allowedNSectors << m_d->sectorstatus.count();
855 }
856
857 m_d->allowCustomNSectors = allowCustom;
858
859 std::sort(allowedNSectors.begin(), allowedNSectors.end());
860 if (m_d->allowedNSectors==allowedNSectors) {
861 return;
862 }
863 m_d->allowedNSectors=std::move(allowedNSectors);
864 if (m_d->popup_menu) {
865 m_d->addMenuEntriesForSetNPhi();
866 }
867
868 if (!m_d->allowedNSectors.contains(m_d->sectorstatus.count())) {
869 setNumberOfSectors(m_d->sectorstatus.count());
870 }
871
872 int checkA = m_d->sectorstatus.isEmpty();
873 int checkB = m_d->sectorstatus.count();
874 if(VP1Msg::debug()){
875 messageDebug("check - sectorstatus.isEmpty? " + str(checkA + checkB) );
876 }
877
878}
#define M_PI
Scalar phi() const
phi method
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
static Double_t a
#define y
#define x
static void wrap(QList< VP1Interval > &)
QList< QAction * > popuplist_setNPhi
std::map< QGraphicsEllipseItem *, int > item2sector
void approximateSectorStatusFromRanges(const QList< VP1Interval > &oldEnabledRanges, QVector< bool > &target)
PhiSectionWidget * theclass
QList< VP1Interval > cachedRanges
QList< VP1Interval > enabledPhiRangesNoCache(const QVector< bool > &secstatus, bool &allOn, bool &allOff) const
QVector< bool > sectorstatus
bool virtualSectorEnabled(int iSector, int nSectors) const
void setAllowedNumberOfSectors(QList< int > allowedNSectors, bool allowCustom=false)
static int phiToVirtualSectorIndex(double phi, int nSectors)
void dragLeaveEvent(QDragLeaveEvent *event)
void mouseMoveEvent(QMouseEvent *event)
bool allSectorsOn() const
void setNumberOfSectors(int, bool forceAllEnabled=false)
QList< VP1Interval > enabledPhiRanges() const
bool allSectorsOff() const
void launchContextMenu(QPoint)
void setSectorStatus(int, bool)
QString enabledRangesToString() const
void setState(QByteArray)
void resizeEvent(QResizeEvent *)
int numberOfSectors() const
void dragEnterEvent(QDragEnterEvent *event)
QVector< bool > virtualSectorsEnabled(int nSectors) const
void dropEvent(QDropEvent *event)
void mousePressEvent(QMouseEvent *)
void dragMoveEvent(QDragMoveEvent *event)
PhiSectionWidget(QWidget *parent, IVP1System *sys=0)
QByteArray state() const
VP1HelperClassBase(IVP1System *sys=0, QString helpername="")
void messageVerbose(const QString &) const
void messageDebug(const QString &) const
static bool debug()
Definition VP1Msg.h:32
static bool verbose()
Definition VP1Msg.h:31
int r
Definition globals.cxx:22
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.