Seamly2D
Code documentation
vgrainlineitem.cpp
Go to the documentation of this file.
1 /************************************************************************
2  **
3  ** @file vgrainlineitem.cpp
4  ** @author Bojan Kverh
5  ** @date September 10, 2016
6  **
7  ** @brief
8  ** @copyright
9  ** This source code is part of the Valentine project, a pattern making
10  ** program, whose allow create and modeling patterns of clothing.
11  ** Copyright (C) 2013-2015 Seamly2D project
12  ** <https://github.com/fashionfreedom/seamly2d> All Rights Reserved.
13  **
14  ** Seamly2D is free software: you can redistribute it and/or modify
15  ** it under the terms of the GNU General Public License as published by
16  ** the Free Software Foundation, either version 3 of the License, or
17  ** (at your option) any later version.
18  **
19  ** Seamly2D is distributed in the hope that it will be useful,
20  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
21  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  ** GNU General Public License for more details.
23  **
24  ** You should have received a copy of the GNU General Public License
25  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
26  **
27  *************************************************************************/
28 
29 #include <math.h>
30 
31 #include <QApplication>
32 #include <QPainter>
33 #include <QGraphicsSceneMouseEvent>
34 #include <QStyleOptionGraphicsItem>
35 #include <QDebug>
36 #include <QGraphicsScene>
37 #include <QGraphicsView>
38 
39 #include "../vmisc/def.h"
40 #include "../vmisc/vmath.h"
41 #include "../vmisc/vcommonsettings.h"
42 #include "../vmisc/vabstractapplication.h"
43 
44 #include "vgrainlineitem.h"
45 
46 #define ARROW_ANGLE M_PI/9
47 #define ARROW_LENGTH 15
48 #define RECT_WIDTH 30
49 #define RESIZE_RECT_SIZE 10
50 #define ROTATE_CIRC_R 7
51 #define ACTIVE_Z 10
52 #define LINE_PEN_WIDTH 3
53 
54 //---------------------------------------------------------------------------------------------------------------------
55 /**
56  * @brief VGrainlineItem::VGrainlineItem constructor
57  * @param painterarent pointer to the parent item
58  */
59 VGrainlineItem::VGrainlineItem(QGraphicsItem* painterarent)
60  : VPieceItem(painterarent),
61  m_dRotation(0),
62  m_dStartRotation(0),
63  m_dLength(0),
64  m_polyBound(),
65  m_ptStartPos(),
66  m_ptStartMove(),
67  m_dScale(1),
68  m_polyResize(),
69  m_dStartLength(0),
70  m_ptStart(),
71  m_ptFinish(),
72  m_ptCenter(),
73  m_dAngle(0),
74  m_eArrowType(ArrowType::atBoth),
75  m_penWidth(LINE_PEN_WIDTH)
76 {
77  setAcceptHoverEvents(true);
78  m_inactiveZ = 5;
79  Reset();
81 }
82 
83 //---------------------------------------------------------------------------------------------------------------------
84 QPainterPath VGrainlineItem::shape() const
85 {
86  if (m_eMode == mNormal)
87  {
88  return MainShape();
89  }
90  else
91  {
92  QPainterPath path;
93  path.addPolygon(m_polyBound);
94  return path;
95  }
96 }
97 
98 //---------------------------------------------------------------------------------------------------------------------
99 /**
100  * @brief VGrainlineItem::paint paints the item content
101  * @param painter pointer to the painter object
102  * @param option not used
103  * @param widget not used
104  */
105 void VGrainlineItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
106 {
107  Q_UNUSED(option)
108  Q_UNUSED(widget)
109 
110  painter->save();
111  QColor color = QColor(qApp->Settings()->getDefaultGrainlineColor());
112  m_penWidth = ToPixel(qApp->Settings()->getDefaultGrainlineLineweight(), Unit::Mm) * 3;
113  painter->setPen(QPen(color, m_penWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
114 
115  painter->setRenderHints(QPainter::Antialiasing);
116  // line
117  const QLineF mainLine = MainLine();
118  painter->drawLine(mainLine.p1(), mainLine.p2());
119 
120  painter->setBrush(color);
121 
122  m_dScale = GetScale();
123  qreal dArrLen = ARROW_LENGTH*m_dScale;
125  {
126  // first arrow
127  painter->drawPolygon(FirstArrow(dArrLen));
128  }
130  {
131  // second arrow
132  painter->drawPolygon(SecondArrow(dArrLen));
133  }
134 
135  if (m_eMode != mNormal)
136  {
137  painter->setPen(QPen(Qt::black, 2, Qt::DashLine));
138  painter->setBrush(Qt::NoBrush);
139  // bounding polygon
140  painter->drawPolygon(m_polyBound);
141 
142  if (m_eMode != mRotate)
143  {
144  painter->setPen(QPen(Qt::black, 3));
145  painter->setBrush(Qt::black);
147  painter->drawPolygon(m_polyResize);
148  }
149 
150  painter->setBrush(Qt::NoBrush);
151  if (m_eMode == mResize)
152  {
153  painter->setPen(Qt::black);
154  painter->drawLine(m_polyBound.at(0), m_polyBound.at(2));
155  painter->drawLine(m_polyBound.at(1), m_polyBound.at(3));
156  }
157 
158  if (m_eMode == mRotate)
159  {
160  QPointF ptC = (m_polyBound.at(0) + m_polyBound.at(2))/2;
161  qreal dRad = m_dScale * ROTATE_CIRC_R;
162  painter->setBrush(Qt::black);
163  painter->drawEllipse(ptC, dRad, dRad);
164 
165  painter->setBrush(Qt::NoBrush);
166  painter->save();
167  painter->translate(ptC);
168  painter->rotate(qRadiansToDegrees(-m_dRotation));
169  int iX = int(qRound(m_dLength/2 - 0.5*dRad));
170  int iY = int(qRound(RECT_WIDTH - 0.5*dRad));
171  int iR = int(qRound(dRad*3));
172  painter->drawArc(iX - iR, iY - iR, iR, iR, 0*16, -90*16);
173  painter->drawArc(-iX, iY - iR, iR, iR, 270*16, -90*16);
174  painter->drawArc(-iX, -iY, iR, iR, 180*16, -90*16);
175  painter->drawArc(iX - iR, -iY, iR, iR, 90*16, -90*16);
176  painter->restore();
177  }
178  }
179  painter->restore();
180 }
181 
182 //---------------------------------------------------------------------------------------------------------------------
183 /**
184  * @brief VGrainlineItem::UpdateGeometry updates the item with grainline parameters
185  * @param ptPos position of one grainline's end
186  * @param dRotation rotation of the grainline in [degrees]
187  * @param dLength length of the grainline in user's units
188  */
189 void VGrainlineItem::UpdateGeometry(const QPointF& ptPos, qreal dRotation, qreal dLength, ArrowType eAT)
190 {
191  m_dRotation = qDegreesToRadians(dRotation);
192  m_dLength = dLength;
193 
194  qreal dX;
195  qreal dY;
196  QPointF pt = ptPos;
197  if (isContained(pt, m_dRotation, dX, dY) == false)
198  {
199  pt.setX(pt.x() + dX);
200  pt.setY(pt.y() + dY);
201  }
202  setPos(pt);
203  m_eArrowType = eAT;
204 
205  UpdateRectangle();
206  Update();
207 }
208 
209 //---------------------------------------------------------------------------------------------------------------------
210 /**
211  * @brief VGrainlineItem::isContained checks, if both ends of the grainline, starting at pt, are contained in
212  * parent widget.
213  * @param pt starting point of the grainline.
214  * @param dRot rotation of the grainline in [rad]
215  * @param dX horizontal translation needed to put the arrow inside parent item
216  * @param dY vertical translation needed to put the arrow inside parent item
217  * @return true, if both ends of the grainline, starting at pt, are contained in the parent widget and
218  * false otherwise.
219  */
220 bool VGrainlineItem::isContained(const QPointF& pt, qreal dRot, qreal &dX, qreal &dY) const
221 {
222  dX = 0;
223  dY = 0;
224  QPointF apt[2];
225  apt[0] = pt;
226  apt[1].setX(pt.x() + m_dLength * cos(dRot));
227  apt[1].setY(pt.y() - m_dLength * sin(dRot));
228  // single point differences
229  qreal dPtX;
230  qreal dPtY;
231  bool bInside = true;
232 
233  QRectF rectParent = parentItem()->boundingRect();
234  for (int i = 0; i < 2; ++i)
235  {
236  dPtX = 0;
237  dPtY = 0;
238  if (rectParent.contains(apt[i]) == false)
239  {
240  if (apt[i].x() < rectParent.left())
241  {
242  dPtX = rectParent.left() - apt[i].x();
243  }
244  else if (apt[i].x() > rectParent.right())
245  {
246  dPtX = rectParent.right() - apt[i].x();
247  }
248  if (apt[i].y() < rectParent.top())
249  {
250  dPtY = rectParent.top() - apt[i].y();
251  }
252  else if (apt[i].y() > rectParent.bottom())
253  {
254  dPtY = rectParent.bottom() - apt[i].y();
255  }
256 
257  if (fabs(dPtX) > fabs(dX))
258  {
259  dX = dPtX;
260  }
261  if (fabs(dPtY) > fabs(dY))
262  {
263  dY = dPtY;
264  }
265 
266  bInside = false;
267  }
268  }
269  return bInside;
270 }
271 
272 //---------------------------------------------------------------------------------------------------------------------
273 /**
274  * @brief VGrainlineItem::mousePressEvent handles left button mouse press events
275  * @param pME pointer to QGraphicsSceneMouseEvent object
276  */
277 void VGrainlineItem::mousePressEvent(QGraphicsSceneMouseEvent* pME)
278 {
279  if (pME->button() == Qt::LeftButton && pME->type() != QEvent::GraphicsSceneMouseDoubleClick
280  && (flags() & QGraphicsItem::ItemIsMovable))
281  {
282  if (m_moveType == NotMovable)
283  {
284  pME->ignore();
285  return;
286  }
287 
288  m_ptStartPos = pos();
289  m_ptStartMove = pME->scenePos();
292  m_dAngle = GetAngle(mapToParent(pME->pos()));
294 
296  {
297  allUserModifications(pME->pos());
298  setZValue(ACTIVE_Z);
299  Update();
300  }
301  else if (m_moveType & IsRotatable)
302  {
303  if (m_moveType & IsResizable)
304  {
305  allUserModifications(pME->pos());
306  }
307  else if (m_moveType & IsMovable)
308  {
310  }
311  else
312  {
313  m_eMode = mRotate;
315  }
316  setZValue(ACTIVE_Z);
317  Update();
318  }
319  else if (m_moveType & IsResizable)
320  {
321  if (m_moveType & IsRotatable)
322  {
323  allUserModifications(pME->pos());
324  }
325  else if (m_moveType & IsMovable)
326  {
327  userMoveAndResize(pME->pos());
328  }
329  setZValue(ACTIVE_Z);
330  Update();
331  }
332  else if (m_moveType & IsMovable)
333  {
334  if (m_moveType & IsRotatable)
335  {
337  }
338  else if (m_moveType & IsResizable)
339  {
340  userMoveAndResize(pME->pos());
341  }
342  else
343  {
344  m_eMode = mMove;
346  }
347 
348  setZValue(ACTIVE_Z);
349  Update();
350  }
351  else
352  {
353  pME->ignore();
354  return;
355  }
356  }
357 }
358 
359 //---------------------------------------------------------------------------------------------------------------------
360 /**
361  * @brief VGrainlineItem::mouseMoveEvent handles mouse move events, making sure that the item is moved properly
362  * @param pME pointer to QGraphicsSceneMouseEvent object
363  */
364 void VGrainlineItem::mouseMoveEvent(QGraphicsSceneMouseEvent* pME)
365 {
366  QPointF ptDiff = pME->scenePos() - m_ptStartMove;
367  qreal dX;
368  qreal dY;
369  if (m_eMode == mMove && m_moveType & IsMovable)
370  {
371  QPointF pt = m_ptStartPos + ptDiff;
372  if (isContained(pt, m_dRotation, dX, dY) == false)
373  {
374  pt.setX(pt.x() + dX);
375  pt.setY(pt.y() + dY);
376  }
377  setPos(pt);
378  Update();
379  }
380  else if (m_eMode == mResize && m_moveType & IsResizable)
381  {
382  qreal dLen = qSqrt(ptDiff.x()*ptDiff.x() + ptDiff.y()*ptDiff.y());
383  qreal dAng = qAtan2(-ptDiff.y(), ptDiff.x());
384  dLen = -dLen*qCos(dAng - m_dRotation);
385  qreal dPrevLen = m_dLength;
386  // try with new length
387  if (not (m_moveType & IsMovable))
388  {
389  dLen *= 2;
390  }
391  m_dLength = m_dStartLength + dLen;
392 
393  QPointF pos;
394 
395  if (m_moveType & IsMovable)
396  {
397  QLineF grainline(this->pos().x(), this->pos().y(),
398  this->pos().x() + dPrevLen, this->pos().y());
399  grainline.setAngle(qRadiansToDegrees(m_dRotation));
400  grainline = QLineF(grainline.p2(), grainline.p1());
401  grainline.setLength(m_dLength);
402  pos = grainline.p2();
403  }
404  else
405  {
406  QLineF grainline(m_ptCenter.x(), m_ptCenter.y(),
407  m_ptCenter.x() + m_dLength / 2.0, m_ptCenter.y());
408 
409  grainline.setAngle(qRadiansToDegrees(m_dRotation));
410  grainline = QLineF(grainline.p2(), grainline.p1());
411  grainline.setLength(m_dLength);
412 
413  pos = grainline.p2();
414  }
415 
416  qreal dX;
417  qreal dY;
418  if (isContained(pos, m_dRotation, dX, dY) == false)
419  {
420  m_dLength = dPrevLen;
421  }
422  else
423  {
424  setPos(pos);
425  }
426 
427  UpdateRectangle();
428  Update();
429  }
430  else if (m_eMode == mRotate && m_moveType & IsRotatable)
431  {
432  // prevent strange angle changes due to singularities
433  qreal dLen = qSqrt(ptDiff.x()*ptDiff.x() + ptDiff.y()*ptDiff.y());
434  if (dLen < 2)
435  {
436  return;
437  }
438 
439  if (fabs(m_dAngle) < 0.01)
440  {
441  m_dAngle = GetAngle(mapToParent(pME->pos()));
442  return;
443  }
444 
445  qreal dAng = GetAngle(mapToParent(pME->pos())) - m_dAngle;
446  QPointF ptNewPos = Rotate(m_ptStartPos, m_ptRotCenter, dAng);
447  if (isContained(ptNewPos, m_dStartRotation + dAng, dX, dY) == true)
448  {
449  setPos(ptNewPos);
450  m_dRotation = m_dStartRotation + dAng;
451  UpdateRectangle();
452  Update();
453  }
454  }
455 }
456 
457 //---------------------------------------------------------------------------------------------------------------------
458 /**
459  * @brief VGrainlineItem::mouseReleaseEvent handles mouse release events and emits the proper signal if the item was
460  * moved
461  * @param pME pointer to QGraphicsSceneMouseEvent object
462  */
463 void VGrainlineItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* pME)
464 {
465  if (pME->button() == Qt::LeftButton)
466  {
467  if ((m_eMode == mMove || m_eMode == mRotate || m_eMode == mResize) && (flags() & QGraphicsItem::ItemIsMovable))
468  {
470  }
471 
472  QPointF ptDiff = pME->scenePos() - m_ptStartMove;
473  qreal dLen = qSqrt(ptDiff.x()*ptDiff.x() + ptDiff.y()*ptDiff.y());
474  bool bShort = (dLen < 2);
475 
476  if (m_eMode == mMove || m_eMode == mResize)
477  {
478  if (bShort == true)
479  {
480  if (m_bReleased == true && m_moveType & IsRotatable)
481  {
482  m_eMode = mRotate;
483  Update();
484  }
485  }
486  else
487  {
488  if (m_eMode == mMove && m_moveType & IsMovable)
489  {
490  emit itemMoved(pos());
491  }
492  else if (m_moveType & IsResizable)
493  {
494  emit itemResized(m_dLength);
495  }
496  Update();
497  }
498  }
499  else
500  {
501  if (bShort == true)
502  {
503  m_eMode = mMove;
504  }
505  else if (m_moveType & IsRotatable)
506  {
508  }
509  Update();
510  }
511  m_bReleased = true;
512  }
513 }
514 
515 //---------------------------------------------------------------------------------------------------------------------
516 void VGrainlineItem::hoverEnterEvent(QGraphicsSceneHoverEvent *pME)
517 {
518  m_penWidth = m_penWidth + 1;
519  VPieceItem::hoverEnterEvent(pME);
520 }
521 
522 //---------------------------------------------------------------------------------------------------------------------
523 void VGrainlineItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *pME)
524 {
525  m_penWidth = m_penWidth - 1;
526  VPieceItem::hoverLeaveEvent(pME);
527 }
528 
529 //---------------------------------------------------------------------------------------------------------------------
530 /**
531  * @brief VGrainlineItem::Update updates the item
532  */
534 {
535  update(m_rectBoundingBox);
536 }
537 
538 //---------------------------------------------------------------------------------------------------------------------
539 /**
540  * @brief VGrainlineItem::UpdateRectangle updates the polygon for the box around active item
541  * and the bounding rectangle
542  */
544 {
545  QPointF pt1(0, 0);
546  QPointF pt2(pt1.x() + m_dLength * cos(m_dRotation), pt1.y() - m_dLength * sin(m_dRotation));
547 
548  m_ptStart = mapToParent(pt1);
549  m_ptFinish = mapToParent(pt2);
551 
552  m_polyBound.clear();
553  m_polyBound << QPointF(pt1.x() + RECT_WIDTH*cos(m_dRotation + M_PI/2),
554  pt1.y() - RECT_WIDTH*sin(m_dRotation + M_PI/2));
555  m_polyBound << QPointF(pt1.x() + RECT_WIDTH*cos(m_dRotation - M_PI/2),
556  pt1.y() - RECT_WIDTH*sin(m_dRotation - M_PI/2));
557  m_polyBound << QPointF(pt2.x() + RECT_WIDTH*cos(m_dRotation - M_PI/2),
558  pt2.y() - RECT_WIDTH*sin(m_dRotation - M_PI/2));
559  m_polyBound << QPointF(pt2.x() + RECT_WIDTH*cos(m_dRotation + M_PI/2),
560  pt2.y() - RECT_WIDTH*sin(m_dRotation + M_PI/2));
561  m_rectBoundingBox = m_polyBound.boundingRect().adjusted(-2, -2, 2, 2);
562  setTransformOriginPoint(m_rectBoundingBox.center());
563 
565  prepareGeometryChange();
566 }
567 
568 //---------------------------------------------------------------------------------------------------------------------
569 double VGrainlineItem::GetAngle(const QPointF &pt) const
570 {
571  return -VPieceItem::GetAngle(pt);
572 }
573 
574 //---------------------------------------------------------------------------------------------------------------------
575 /**
576  * @brief VGrainlineItem::Rotate rotates point pt around ptCenter by angle dAng [rad]
577  * and returns the resulting point
578  * @param pt point to rotate
579  * @param ptCenter center of rotation
580  * @param dAng angle of rotation
581  * @return point, which is a result of rotating pt around ptCenter by angle dAng
582  */
583 QPointF VGrainlineItem::Rotate(const QPointF& pt, const QPointF& ptCenter, qreal dAng) const
584 {
585  QPointF ptRel = pt - ptCenter;
586  QPointF ptFinal;
587  ptFinal.setX(ptRel.x()*qCos(dAng) + ptRel.y()*qSin(dAng));
588  ptFinal.setY(-ptRel.x()*qSin(dAng) + ptRel.y()*qCos(dAng));
589  ptFinal += ptCenter;
590  return ptFinal;
591 }
592 
593 //---------------------------------------------------------------------------------------------------------------------
594 /**
595  * @brief VGrainlineItem::GetInsideCorner calculates a point inside the bounding polygon,
596  * dDist away of i-th point in each direction
597  * @param i index of corner
598  * @param dDist distance
599  * @return resulting point
600  */
601 QPointF VGrainlineItem::GetInsideCorner(int i, qreal dDist) const
602 {
603  QPointF pt1 = m_polyBound.at((i + 1) % m_polyBound.count()) - m_polyBound.at(i);
604  QPointF pt2 = m_polyBound.at((i + m_polyBound.count() - 1) % m_polyBound.count()) - m_polyBound.at(i);
605 
606  pt1 = dDist*pt1/qSqrt(pt1.x()*pt1.x() + pt1.y()*pt1.y());
607  pt2 = dDist*pt2/qSqrt(pt2.x()*pt2.x() + pt2.y()*pt2.y());
608 
609  return m_polyBound.at(i) + pt1 + pt2;
610 }
611 
612 //---------------------------------------------------------------------------------------------------------------------
613 /**
614  * @brief GetScale gets the scale for keeping the arrows of constant size
615  */
617 {
618  if (scene()->views().count() > 0)
619  {
620  const QPoint pt0 = scene()->views().at(0)->mapFromScene(0, 0);
621  const QPoint pt = scene()->views().at(0)->mapFromScene(0, 100);
622  const QPoint p = pt - pt0;
623  qreal dScale = qSqrt(QPoint::dotProduct(p, p));
624  dScale = 100.0/dScale;
625  if (dScale < 1.0)
626  {
627  dScale = 1.0;
628  }
629  return dScale;
630  }
631 
632  return 1.0;
633 }
634 
635 //---------------------------------------------------------------------------------------------------------------------
637 {
638  QPointF pt1;
639  QPointF pt2(pt1.x() + m_dLength * cos(m_dRotation), pt1.y() - m_dLength * sin(m_dRotation));
640  return QLineF(pt1, pt2);
641 }
642 
643 //---------------------------------------------------------------------------------------------------------------------
644 QPolygonF VGrainlineItem::FirstArrow(qreal dArrLen) const
645 {
646  QPointF pt2 = MainLine().p2();
647  QPolygonF poly;
648  poly << pt2;
649  poly << QPointF(pt2.x() + dArrLen*cos(M_PI + m_dRotation + ARROW_ANGLE),
650  pt2.y() - dArrLen*sin(M_PI + m_dRotation + ARROW_ANGLE));
651  poly << QPointF(pt2.x() + dArrLen*cos(M_PI + m_dRotation - ARROW_ANGLE),
652  pt2.y() - dArrLen*sin(M_PI + m_dRotation - ARROW_ANGLE));
653  return poly;
654 }
655 
656 //---------------------------------------------------------------------------------------------------------------------
657 QPolygonF VGrainlineItem::SecondArrow(qreal dArrLen) const
658 {
659  QPointF pt1 = MainLine().p1();
660  QPolygonF poly;
661  poly << pt1;
662  poly << QPointF(pt1.x() + dArrLen*cos(m_dRotation + ARROW_ANGLE),
663  pt1.y() - dArrLen*sin(m_dRotation + ARROW_ANGLE));
664  poly << QPointF(pt1.x() + dArrLen*cos(m_dRotation - ARROW_ANGLE),
665  pt1.y() - dArrLen*sin(m_dRotation - ARROW_ANGLE));
666  return poly;
667 }
668 
669 //---------------------------------------------------------------------------------------------------------------------
670 QPainterPath VGrainlineItem::MainShape() const
671 {
672  QPainterPath path;
673  const QLineF mainLine = MainLine();
674  QPainterPath linePath;
675  linePath.moveTo(mainLine.p1());
676  linePath.lineTo(mainLine.p2());
677  linePath.closeSubpath();
678 
679  QPainterPathStroker stroker;
680  stroker.setWidth(m_penWidth);
681  path.addPath((stroker.createStroke(linePath) + linePath).simplified());
682  path.closeSubpath();
683 
684  const qreal dArrLen = ARROW_LENGTH*GetScale();
686  {
687  // first arrow
688  QPainterPath polyPath;
689  polyPath.addPolygon(FirstArrow(dArrLen));
690  path.addPath((stroker.createStroke(polyPath) + polyPath).simplified());
691  path.closeSubpath();
692  }
693 
695  {
696  // second arrow
697  QPainterPath polyPath;
698  polyPath.addPolygon(SecondArrow(dArrLen));
699  path.addPath((stroker.createStroke(polyPath) + polyPath).simplified());
700  path.closeSubpath();
701  }
702  return path;
703 }
704 
705 //---------------------------------------------------------------------------------------------------------------------
706 void VGrainlineItem::allUserModifications(const QPointF &pos)
707 {
708  if (m_eMode != mRotate)
709  {
710  userMoveAndResize(pos);
711  }
712  else
713  {
715  }
716 }
717 
718 //---------------------------------------------------------------------------------------------------------------------
720 {
721  if (m_eMode != mRotate)
722  {
723  m_eMode = mMove;
724  }
726 }
727 
728 //---------------------------------------------------------------------------------------------------------------------
729 void VGrainlineItem::userMoveAndResize(const QPointF &pos)
730 {
731  if (m_polyResize.containsPoint(pos, Qt::OddEvenFill) == true)
732  {
733  m_eMode = mResize;
734  setCursor(Qt::SizeFDiagCursor);
735  }
736  else
737  {
738  m_eMode = mMove; // block later if need
740  }
741 }
742 
743 //---------------------------------------------------------------------------------------------------------------------
745 {
746  m_polyResize.clear();
747  QPointF ptA = m_polyBound.at(1);
748  m_polyResize << ptA;
749  const double dSize = m_dScale * RESIZE_RECT_SIZE;
750 
751  ptA.setX(ptA.x() - dSize*cos(m_dRotation - M_PI/2));
752  ptA.setY(ptA.y() + dSize*sin(m_dRotation - M_PI/2));
753  m_polyResize << ptA;
754 
755  ptA.setX(ptA.x() + dSize*cos(m_dRotation));
756  ptA.setY(ptA.y() - dSize*sin(m_dRotation));
757  m_polyResize << ptA;
758 
759  ptA.setX(ptA.x() - dSize*cos(m_dRotation + M_PI/2));
760  ptA.setY(ptA.y() + dSize*sin(m_dRotation + M_PI/2));
761  m_polyResize << ptA;
762 }
bool isContained(const QPointF &pt, qreal dRot, qreal &dX, qreal &dY) const
VGrainlineItem::isContained checks, if both ends of the grainline, starting at pt,...
void itemResized(qreal dLength)
QPolygonF m_polyBound
void UpdateRectangle()
VGrainlineItem::UpdateRectangle updates the polygon for the box around active item and the bounding r...
QPointF m_ptStartPos
void UpdateGeometry(const QPointF &ptPos, qreal dRotation, qreal dLength, ArrowType eAT)
VGrainlineItem::UpdateGeometry updates the item with grainline parameters.
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *pME) Q_DECL_OVERRIDE
VGrainlineItem::mouseReleaseEvent handles mouse release events and emits the proper signal if the ite...
QPolygonF m_polyResize
QLineF MainLine() const
void allUserModifications(const QPointF &pos)
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *pME) Q_DECL_OVERRIDE
VGrainlineItem::mouseMoveEvent handles mouse move events, making sure that the item is moved properly...
virtual void paint(QPainter *pP, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget) Q_DECL_OVERRIDE
VGrainlineItem::paint paints the item content.
virtual void mousePressEvent(QGraphicsSceneMouseEvent *pME) Q_DECL_OVERRIDE
VGrainlineItem::mousePressEvent handles left button mouse press events.
QPainterPath MainShape() const
QPolygonF SecondArrow(qreal dArrLen) const
void itemRotated(qreal dRot, const QPointF &ptNewPos)
void userMoveAndResize(const QPointF &pos)
virtual void Update() Q_DECL_OVERRIDE
VGrainlineItem::Update updates the item.
QPointF GetInsideCorner(int i, qreal dDist) const
VGrainlineItem::GetInsideCorner calculates a point inside the bounding polygon, dDist away of i-th po...
qreal GetScale() const
GetScale gets the scale for keeping the arrows of constant size.
qreal m_dStartRotation
virtual QPainterPath shape() const Q_DECL_OVERRIDE
QPointF m_ptFinish
QPointF m_ptCenter
QPolygonF FirstArrow(qreal dArrLen) const
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *pME) Q_DECL_OVERRIDE
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *pME) Q_DECL_OVERRIDE
QPointF m_ptStartMove
VGrainlineItem(QGraphicsItem *pParent=nullptr)
VGrainlineItem::VGrainlineItem constructor.
QPointF Rotate(const QPointF &pt, const QPointF &ptCenter, qreal dAng) const
VGrainlineItem::Rotate rotates point pt around ptCenter by angle dAng [rad] and returns the resulting...
ArrowType m_eArrowType
virtual double GetAngle(const QPointF &pt) const Q_DECL_OVERRIDE
GetAngle calculates the angle between the line, which goes from rotation center to pt and x axis.
@ AllModifications
Definition: vpieceitem.h:70
QRectF m_rectBoundingBox
Definition: vpieceitem.h:102
VPieceItem::MoveTypes m_moveType
Definition: vpieceitem.h:106
qreal m_inactiveZ
Definition: vpieceitem.h:108
bool m_bReleased
Definition: vpieceitem.h:104
virtual double GetAngle(const QPointF &pt) const
GetAngle calculates the angle between the line, which goes from rotation center to pt and x axis.
Definition: vpieceitem.cpp:118
void itemMoved(const QPointF &ptPos)
void Reset()
Reset resets the item, putting the mode and z coordinate to normal and redraws it.
Definition: vpieceitem.cpp:90
QPointF m_ptRotCenter
Definition: vpieceitem.h:105
Mode m_eMode
Definition: vpieceitem.h:103
const QString cursorArrowOpenHand
Definition: def.cpp:191
double ToPixel(double val, const Unit &unit)
Definition: def.cpp:231
void SetItemOverrideCursor(QGraphicsItem *item, const QString &pixmapPath, int hotX, int hotY)
Definition: def.cpp:206
const QString cursorArrowCloseHand
Definition: def.cpp:192
ArrowType
Definition: floatitemdef.h:60
#define qApp
Definition: vapplication.h:67
#define ROTATE_CIRC_R
#define ACTIVE_Z
#define ARROW_ANGLE
#define RECT_WIDTH
#define LINE_PEN_WIDTH
#define RESIZE_RECT_SIZE
#define ARROW_LENGTH