FractalWidget.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #include "FractalWidget.h"
  2. #include <QMouseEvent>
  3. Q_DECLARE_METATYPE(mnd::MandelViewport)
  4. ViewportAnimation::ViewportAnimation(QObject* parent) :
  5. QPropertyAnimation{ parent }
  6. {
  7. }
  8. QVariant ViewportAnimation::interpolated(const QVariant& from, const QVariant& to,
  9. qreal progress) const
  10. {
  11. const mnd::MandelViewport& a = from.value<mnd::MandelViewport>();
  12. const mnd::MandelViewport& b = to.value<mnd::MandelViewport>();
  13. auto retVal = mnd::MandelViewport {
  14. a.x * (1 - progress) + b.x * progress,
  15. a.y * (1 - progress) + b.y * progress,
  16. a.width * (1 - progress) + b.width * progress,
  17. a.height * (1 - progress) + b.height * progress,
  18. };
  19. return QVariant::fromValue(retVal);
  20. }
  21. FractalWidget::FractalWidget(QWidget* parent) :
  22. FractalZoomWidget{ parent }
  23. {
  24. }
  25. void FractalWidget::mousePressEvent(QMouseEvent* me)
  26. {
  27. QOpenGLWidget::mousePressEvent(me);
  28. if (me->button() == Qt::RightButton) {
  29. rubberbanding = true;
  30. rubberband.setCoords(me->x(), me->y(), me->x(), me->y());
  31. update();
  32. me->accept();
  33. }
  34. else if (me->button() == Qt::LeftButton) {
  35. dragging = true;
  36. dragX = me->x();
  37. dragY = me->y();
  38. me->accept();
  39. }
  40. }
  41. void FractalWidget::mouseMoveEvent(QMouseEvent* me)
  42. {
  43. QOpenGLWidget::mouseMoveEvent(me);
  44. if (rubberbanding) {
  45. QRectF& rect = rubberband;
  46. double aspect = double(geometry().width()) / geometry().height();
  47. rect.setBottomRight(QPoint(me->x(), me->y()));
  48. if (rect.width() > rect.height() * aspect)
  49. rect.setHeight(rect.width() / aspect);
  50. else
  51. rect.setWidth(rect.height() * aspect);
  52. update();
  53. }
  54. else if (selectingPoint) {
  55. pointX = me->x();
  56. pointY = me->y();
  57. update();
  58. }
  59. else if (dragging) {
  60. double deltaX = me->x() - dragX;
  61. double deltaY = me->y() - dragY;
  62. auto& viewport = mandelInfo.view;
  63. viewport.x -= deltaX * viewport.width / this->width();
  64. viewport.y -= deltaY * viewport.height / this->height();
  65. targetViewport = viewport;
  66. dragX = me->x(); dragY = me->y();
  67. update();
  68. }
  69. me->accept();
  70. }
  71. void FractalWidget::mouseReleaseEvent(QMouseEvent* me)
  72. {
  73. QOpenGLWidget::mouseReleaseEvent(me);
  74. if (rubberbanding) {
  75. QRect rect = rubberband.toRect();
  76. if(rect.width() != 0 && rect.height() != 0) {
  77. QRect full = this->geometry();
  78. auto& viewport = targetViewport;
  79. viewport.x += mnd::Real(rect.left()) * viewport.width / full.width();
  80. viewport.y += mnd::Real(rect.top()) * viewport.height / full.height();
  81. viewport.width *= mnd::Real(rect.width()) / full.width();
  82. viewport.height *= mnd::Real(rect.height()) / full.height();
  83. viewport.normalize();
  84. viewport.adjustAspectRatio(getResolutionX(), getResolutionY());
  85. newAnimation();
  86. //currentViewport = viewport;
  87. }
  88. update();
  89. rubberbanding = false;
  90. }
  91. else if (selectingPoint) {
  92. selectingPoint = false;
  93. this->setMouseTracking(false);
  94. /*mnd::Real x = currentViewport.x + currentViewport.width * mnd::convert<mnd::Real>(float(me->x()) / width());
  95. mnd::Real y = currentViewport.y + currentViewport.height * mnd::convert<mnd::Real>(float(me->y()) / height());
  96. emit pointSelected(x, y);*/
  97. update();
  98. }
  99. dragging = false;
  100. }
  101. void FractalWidget::wheelEvent(QWheelEvent* we)
  102. {
  103. QOpenGLWidget::wheelEvent(we);
  104. float x = float(we->x()) / this->width();
  105. float y = float(we->y()) / this->height();
  106. float scale = ::powf(0.9975f, we->angleDelta().y());
  107. //mandelInfo.view.zoom(scale, x, y);
  108. zoom(scale, x, y);
  109. //if (!we->pixelDelta().isNull())
  110. // this->currentViewport = this->viewport;
  111. we->accept();
  112. }
  113. void FractalWidget::zoom(float factor)
  114. {
  115. targetViewport.zoomCenter(factor);
  116. newAnimation();
  117. update();
  118. }
  119. void FractalWidget::zoom(float factor, float fx, float fy)
  120. {
  121. targetViewport.zoom(factor, fx, fy);
  122. newAnimation();
  123. update();
  124. /*viewportSmoother = new ViewportAnimation(this);
  125. viewportSmoother->setStartValue(QVariant::fromValue(getViewport()));
  126. viewportSmoother->setEndValue(QVariant::fromValue(newVp));
  127. viewportSmoother->setTargetObject(this);
  128. viewportSmoother->setPropertyName("viewport");
  129. viewportSmoother->setDuration(200);
  130. viewportSmoother->setEasingCurve(QEasingCurve::OutExpo);
  131. viewportSmoother->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped);*/
  132. }
  133. void FractalWidget::setViewport(const mnd::MandelViewport& viewport)
  134. {
  135. FractalZoomWidget::setViewport(viewport);
  136. targetViewport = mandelInfo.view;
  137. update();
  138. }
  139. const mnd::MandelViewport& FractalWidget::getViewport(void) const
  140. {
  141. return mandelInfo.view;
  142. }
  143. void FractalWidget::resizeGL(int w, int h)
  144. {
  145. FractalZoomWidget::resizeGL(w, h);
  146. targetViewport.adjustAspectRatio(w, h);
  147. }
  148. void FractalWidget::paintGL(void)
  149. {
  150. FractalZoomWidget::paintGL();
  151. updateAnimations();
  152. }
  153. void FractalWidget::newAnimation(void)
  154. {
  155. auto now = std::chrono::high_resolution_clock::now();
  156. lastAnimUpdate = now;
  157. }
  158. void FractalWidget::updateAnimations(void)
  159. {
  160. auto& currentViewport = mandelInfo.view;
  161. if (mnd::abs(currentViewport.width / targetViewport.width - 1.0) < 1e-3
  162. && mnd::abs(currentViewport.height / targetViewport.height - 1.0) < 1e-3) {
  163. // animation finished
  164. currentViewport = targetViewport;
  165. }
  166. else {
  167. auto now = std::chrono::high_resolution_clock::now();
  168. auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastAnimUpdate).count();
  169. const mnd::Real factor = mnd::Real(::pow(0.97, millis));
  170. const mnd::Real one(1.0);
  171. currentViewport.x = currentViewport.x * factor + targetViewport.x * (one - factor);
  172. currentViewport.y = currentViewport.y * factor + targetViewport.y * (one - factor);
  173. currentViewport.width = currentViewport.width * factor + targetViewport.width * (one - factor);
  174. currentViewport.height = currentViewport.height * factor + targetViewport.height * (one - factor);
  175. lastAnimUpdate = now;
  176. emit update();
  177. }
  178. }