123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- /*=========================================================================
- Library: CTK
- Copyright (c) Kitware Inc.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.commontk.org/LICENSE
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- =========================================================================*/
- // Qt includes
- #include <QDebug>
- #include <QBrush>
- #include <QGridLayout>
- #include <QLine>
- #include <QMouseEvent>
- #include <QPainter>
- // CTK includes
- #include "ctkAxesWidget.h"
- // STD includes
- #include <cmath>
- #include <math.h>
- static const double goldenRatio = 1.6180339887;
- static const double PI = 3.14159265358979323846;
- //ctkAxesWidgetPrivate
- //-----------------------------------------------------------------------------
- class ctkAxesWidgetPrivate
- {
- Q_DECLARE_PUBLIC(ctkAxesWidget);
- protected:
- ctkAxesWidget* const q_ptr;
- public:
- ctkAxesWidgetPrivate(ctkAxesWidget& object);
- QList<QPoint> extremities(QPoint center, int radius)const;
- QList<QRect> labelRects(const QList<QPoint>& extremities, QSize offset)const;
- ctkAxesWidget::Axis axisAtPos(QPoint pos)const;
- ctkAxesWidget::Axis CurrentAxis;
- ctkAxesWidget::Axis HighlightAxis;
- bool AutoReset;
-
- QStringList AxesLabels;
- QVector<double> AxesAngles;
-
- };
- //-----------------------------------------------------------------------------
- ctkAxesWidgetPrivate::ctkAxesWidgetPrivate(ctkAxesWidget& object)
- :q_ptr(&object)
- {
- qRegisterMetaType<ctkAxesWidget::Axis>("ctkAxesWidget::Axis");
- this->CurrentAxis = ctkAxesWidget::None;
- this->HighlightAxis = ctkAxesWidget::None;
- this->AutoReset = false;
- this->AxesLabels << "R" << "L" << "S" << "I" << "A" << "P";
- this->AxesAngles << 0 << 3.14159265 << 1.57079633 << 4.71238898 << 5.49778714 << 2.35619449;
- }
- //-----------------------------------------------------------------------------
- QList<QPoint> ctkAxesWidgetPrivate::extremities(QPoint center, int radius)const
- {
- QList<QPoint> pos;
- for (int i = 0; i < 6 ; ++i)
- {
- pos << center + QPoint(radius * cos(this->AxesAngles[i]),
- -radius * sin(this->AxesAngles[i]));
- }
- return pos;
- }
- //-----------------------------------------------------------------------------
- QList<QRect> ctkAxesWidgetPrivate::labelRects(const QList<QPoint>& extremities, QSize offset)const
- {
- Q_Q(const ctkAxesWidget);
- QFontMetrics fm = q->fontMetrics();
- QSize letterSize = fm.size(Qt::TextShowMnemonic, "X") + QSize(1,1);
- QSize halfLetterSize = letterSize / 2;
- QList<QRect> rects;
- for (int i = 0; i < 6; ++i)
- {
- rects << QRect(extremities[i]
- + QPoint(cos(this->AxesAngles[i]) * (offset.width()+halfLetterSize.width()),
- -sin(this->AxesAngles[i]) * (offset.height()+halfLetterSize.height()))
- - QPoint(halfLetterSize.width(), halfLetterSize.height()),
- letterSize);
- }
- return rects;
- }
- //-----------------------------------------------------------------------------
- ctkAxesWidget::Axis ctkAxesWidgetPrivate::axisAtPos(QPoint pos)const
- {
- Q_Q(const ctkAxesWidget);
- QPoint center = QPoint(q->width(), q->height()) / 2;
- int length = qMin(q->width(), q->height());
- int diameter = length / goldenRatio;
- int blankSize = (length - diameter) / 2;
- QSize sphereRadius((blankSize / 2) / 1.6180339887,
- (blankSize / 2) / 1.6180339887);
- QPointF mousePos = pos - center;
- double distance2 =
- mousePos.x() * mousePos.x() + mousePos.y() * mousePos.y();
- if (distance2 < sphereRadius.width()*sphereRadius.width())
- {
- return ctkAxesWidget::None;
- }
-
- double mouseAngle = atan2(-mousePos.y(), mousePos.x());
- // mouseAngle is in the interval [-pi,+pi] radians
- // change it to be in [-pi/8, 7/8 * pi]
- double PI_8 = 0.392699082;
- if (mouseAngle < -PI_8)
- {
- mouseAngle += 2. * PI;
- }
-
- for (int i = 0; i < 6; ++i)
- {
- if (mouseAngle >= (this->AxesAngles[i] - PI_8) &&
- mouseAngle <= (this->AxesAngles[i] + PI_8))
- {
- // the mouse is over the axis
- return static_cast<ctkAxesWidget::Axis>(i+1);
- }
- }
- return ctkAxesWidget::None;
- }
- //ctkAxesWidget
- //-----------------------------------------------------------------------------
- ctkAxesWidget::ctkAxesWidget(QWidget *newParent)
- : QWidget(newParent)
- , d_ptr(new ctkAxesWidgetPrivate(*this))
- {
- }
- //-----------------------------------------------------------------------------
- ctkAxesWidget::~ctkAxesWidget()
- {
- }
- // ----------------------------------------------------------------------------
- ctkAxesWidget::Axis ctkAxesWidget::currentAxis() const
- {
- Q_D(const ctkAxesWidget);
- return d->CurrentAxis;
- }
- //-----------------------------------------------------------------------------
- void ctkAxesWidget::setCurrentAxis(ctkAxesWidget::Axis newAxis)
- {
- Q_D(ctkAxesWidget);
- d->HighlightAxis = newAxis;
- if (newAxis == d->CurrentAxis)
- {
- return;
- }
- d->CurrentAxis = newAxis;
- this->repaint();
- emit currentAxisChanged(d->CurrentAxis);
- }
- //-----------------------------------------------------------------------------
- void ctkAxesWidget::setCurrentAxisToNone()
- {
- this->setCurrentAxis(ctkAxesWidget::None);
- }
- // ----------------------------------------------------------------------------
- bool ctkAxesWidget::autoReset() const
- {
- Q_D(const ctkAxesWidget);
- return d->AutoReset;
- }
- // ----------------------------------------------------------------------------
- void ctkAxesWidget::setAutoReset(bool newAutoReset)
- {
- Q_D(ctkAxesWidget);
- if (d->AutoReset == newAutoReset)
- {
- return;
- }
- d->AutoReset = newAutoReset;
- if (d->AutoReset)
- {
- connect(this, SIGNAL(currentAxisChanged(ctkAxesWidget::Axis)),
- this, SLOT(setCurrentAxisToNone()));
- setCurrentAxisToNone();
- }
- else
- {
- disconnect(this, SIGNAL(currentAxisChanged(ctkAxesWidget::Axis)),
- this, SLOT(setCurrentAxisToNone()));
- }
- }
- //-----------------------------------------------------------------------------
- void ctkAxesWidget::paintEvent(QPaintEvent *)
- {
- Q_D(ctkAxesWidget);
- // init
- QPainter painter(this);
-
- //painter.setRenderHint(QPainter::Antialiasing);
-
- QPoint center = QPoint(this->width(), this->height()) / 2;
- int length = qMin(this->width(), this->height());
- int diameter = length / goldenRatio;
- int radius = diameter / 2;
- QStringList axesLabels;
-
- QList<QPoint> positions = d->extremities(center, radius);
-
-
- QFontMetrics fm = this->fontMetrics();
- QSize letterSize = fm.size(Qt::TextShowMnemonic, "X") + QSize(1,1);
- QSize halfLetterSize = letterSize / 2;
- int blankSize = (length - diameter) / 2;
- QSize betweenLetterSpace = QSize(blankSize - letterSize.width(), blankSize - letterSize.height()) / 2;
- QList<QRect> labelRects = d->labelRects(positions, betweenLetterSpace);
-
- for (int i = 0; i < 6; ++i)
- {
- //QRect rect(positions[i] + QPoint(cos(d->AxesAngles[i]) * (betweenLetterSpace.width()+halfLetterSize.width()),
- // -sin(d->AxesAngles[i]) * (betweenLetterSpace.height()+halfLetterSize.height()))
- // - QPoint(halfLetterSize.width(), halfLetterSize.height()), letterSize);
- QRect rect = labelRects[i];
- //if (d->HighlightAxes)
- {
- QFont font = painter.font();
- font.setBold(d->HighlightAxis == (i + 1));
- painter.setFont(font);
- }
- painter.drawText(rect, Qt::AlignCenter, d->AxesLabels[i]);
- }
-
- // Drawing the lines
- for (int i = 0; i < 6; ++i)
- {
- //if (d->HighlightAxes)
- {
- QPen pen;
- if (d->HighlightAxis == (i + 1)) // axes start at 1
- {
- pen.setWidth(3);
- //pen.setColor(QColor(64, 64, 72)); // Payne's grey
- pen.setColor(this->palette().color(QPalette::Highlight));
- }
- painter.setPen(pen);
- }
- painter.drawLine(center, positions[i]);
- }
-
- QSize sphereRadius((blankSize / 2) / 1.6180339887,
- (blankSize / 2) / 1.6180339887);
- // Draw the center sphere
- QRadialGradient rg(QPointF(0.3333, 0.3333),0.7);
- rg.setCoordinateMode(QGradient::ObjectBoundingMode);
- if (//d->HighlightAxes &&
- d->HighlightAxis == ctkAxesWidget::None)
- {
- rg.setColorAt(0., this->palette().color(QPalette::Highlight));
- }
- else
- {
- rg.setColorAt(0., this->palette().color(QPalette::Light));
- }
- rg.setColorAt(1., QColor(64, 64, 72));
- painter.setBrush(QBrush(rg));
- painter.setPen(QPen(Qt::NoPen));
- painter.drawEllipse(QPointF(center), sphereRadius.width(), sphereRadius.height());
- }
- // ----------------------------------------------------------------------------------
- void ctkAxesWidget::mousePressEvent(QMouseEvent *mouseEvent)
- {
- Q_D(ctkAxesWidget);
- d->HighlightAxis = d->axisAtPos(mouseEvent->pos());
- this->update();
- }
- // ----------------------------------------------------------------------------------
- void ctkAxesWidget::mouseMoveEvent(QMouseEvent *mouseEvent)
- {
- Q_D(ctkAxesWidget);
- d->HighlightAxis = d->axisAtPos(mouseEvent->pos());
- this->update();
- }
- // ----------------------------------------------------------------------------------
- void ctkAxesWidget::mouseReleaseEvent(QMouseEvent *mouseEvent)
- {
- Q_D(ctkAxesWidget);
- this->setCurrentAxis(d->axisAtPos(mouseEvent->pos()));
- }
- // --------------------------------------------------------------------------
- QSize ctkAxesWidget::minimumSizeHint()const
- {
- // Pretty arbitrary size.
- return QSize(100, 100);
- }
- // --------------------------------------------------------------------------
- QSize ctkAxesWidget::sizeHint()const
- {
- // Pretty arbitrary size
- return QSize(100, 100);
- }
- //----------------------------------------------------------------------------
- bool ctkAxesWidget::hasHeightForWidth()const
- {
- return true;
- }
- //----------------------------------------------------------------------------
- int ctkAxesWidget::heightForWidth(int width)const
- {
- // Tends to be square
- return width;
- }
|