Qt 重写QGraphicItem实现拖动缩放旋转斜切矩形,即VisionPro中的卡尺的功能

在这里插入图片描述

如上图所示,绘制矩形之后,可以按住中间缩放、然后按住右侧中间进行旋转,按住右下角进行缩放,按住下方中间进行斜切矩形。
整体都是仿照visionpro里面的矩形卡尺制作的。
至于拖动、缩放、旋转功能可详见我的博客:https://blog.csdn.net/weixin_43935474/article/details/107033591
这里主要讲一下切变,和切变之后的缩放功能。
注:我的切变暂时只支持宽度方向切变!

首先,切变主要使用qt里面的
QTransform &QTransform::shear(qreal sh, qreal sv)
Shears the coordinate system by sh horizontally and sv vertically, and returns a reference to the matrix.
QTransform::shear的参数关系为:
假设矩形正中央为坐标原点(0,0),矩形边上某一点坐标在切变之前为(x1,y1),切变之后为(x2,y2),则x2=x1+sh*y1

用法如下:

1 QTransform trans;
2 trans.translate(m_RECT.center().x(),m_RECT.center().y());//QRectF m_RECT为切变前的矩形
3 trans.shear(m_fShearX,0);
4 trans.translate(-m_RECT.center().x(),-m_RECT.center().y());
5 m_RECTShear = trans.map(m_RECTShear);//m_RECT斜切之后成了多边形QPolygonF m_RECTShear 

拖动和缩放时候需要用下面这张图来解释:
在这里插入图片描述
因为要考虑到旋转之后依然支持切变,拖动鼠标进行切变时,切变参数sh的计算是根据鼠标在矩形横向的偏移量来计算的:
假设点pCross3和pCross5的距离dis1,点pc到pCross3的距离为h1(因为制作横向切变,所以h1=矩形高度的一半),则

sh = dis1/h1;

然后在paint()函数里面就可以根据sh这个参数来绘制切变后的矩形。

切变之后的的缩放需要保持原有的切变参数以及旋转角度,所以拖动鼠标进行缩放时,矩形的宽高的偏移量是根据如下方式计算得到的:
假设pos到直线pc pCross1的距离为h2,点pc到pCross1的距离为w2,则缩放后的新矩形参数为:

QRectF newRECT = QRectF(pc.x()-w2,pc.y()-h2,w2*2,h2*2);

核心代码如下:
头文件:

  1 #ifndef MYGRAPHICCALIPERITEM_H
  2 #define MYGRAPHICCALIPERITEM_H
  3 #include <QObject>
  4 #include <QWidget>
  5 #include <QMouseEvent>
  6 #include <QGraphicsScene>
  7 #include <QGraphicsRectItem>
  8 #include <QGraphicsSceneMouseEvent>
  9 #include <QRect>
 10 #include <QPainter>
 11 #include <QPolygon>
 12 #include <QList>
 13 #include <QTransform>
 14 #include <QMap>
 15 enum CALIPER_STATE_FLAG{
 16     CALI_DEFAULT=0,
 17     CALI_RECT_TL,//标记当前为用户按下矩形的左上角
 18     CALI_RECT_TR,//标记当前为用户按下矩形的右上角
 19     CALI_RECT_BL,//左下角
 20     CALI_RECT_BR,//右下角
 21     CALI_RECT_SHEAR,//标记当前为用户按下矩形的下边中点的切变矩形
 22     CALI_RECT_MOVE,//标记当前为鼠标拖动矩形移动状态
 23     CALI_RECT_ROTATE,//标记当前为旋转状态
 24     CALIMOV_POLYGON_POINT//移动多边形的某个点
 25 };
 26 enum CALIPER_SHAPE_TYPE{
 27     CALIPER_RECT,//矩形
 28     CALIPER_LINE,
 29     CALIPER_CIRCLE,
 30     CALIPER_ELLIPSE
 31 };
 32 
 33 class mygraphicCaliperitem:public QObject,public QGraphicsItem
 34 {
 35     Q_OBJECT
 36 public:
 37     CALIPER_SHAPE_TYPE m_ShapeType;
 38     mygraphicCaliperitem(QGraphicsItem *parent = nullptr);
 39     ~mygraphicCaliperitem();
 40     //mygraphicCaliperitem(QRectF m_OriginRect = QRectF(0,0,100,100));
 41     QRectF          boundingRect() const;
 42     QPainterPath    shape() const;
 43     QPainterPath    getCollideShape();
 44     QPainterPath    getCollideShapeTopLeftAsOriginPoint();
 45     void setRectSize(QRectF mrect,bool bResetRotateCenter = true);
 46     void setShearRectSize(QRectF mrect);
 47     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
 48     void mousePressEvent(QGraphicsSceneMouseEvent *event);
 49     void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
 50     void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
 51     int type() const;
 52     void SetRotate(qreal RotateAngle);
 53     void SetSideCursorByRotateAngle(qreal RotateAngle);
 54     //计算两点距离
 55     double CalDis(const double x1, const double y1,const double x2, const double y2);
 56     //计算点(ptx,pty)到线段(x1y1,x2y2)的距离
 57     double CalDis(const double ptx, const double pty,const double x1, const double y1,const double x2, const double y2);
 58     double CalDisPoint2longLine(const double ptx, const double pty,const double x1, const double y1,const double x2, const double y2);
 59     //计算斜切后分别经过中心点和鼠标所在点的两平行线的2个焦点
 60     bool get2CrossPt(QPointF p0, QPointF p1, QPointF p2, QPointF pc, QPointF pos, QPointF &pCross1, QPointF &pCross2);
 61     QPointF pCross1,pCross2,pCross3,pCross5;
 62     QPointF         getRotatePoint(QPointF ptCenter, QPointF ptIn, qreal angle);//获取旋转后的点
 63     QList<QPointF>  getRotatePoints(QPointF ptCenter,QList<QPointF> ptIns,qreal angle);//获取多个旋转后的点
 64     QPolygonF       getRotatePolygonFromRect(QPointF ptCenter,QRectF rectIn,qreal angle);//将矩形旋转之后返回多边形
 65     QPolygonF       getRotatePolygonFromPolygon(QPointF ptCenter,QPolygonF polyIn,qreal angle);//将多边形旋转之后返回多边形
 66     QRectF          getBoundedRectToSceen();
 67     QPolygonF       getCrtPolygonToScreen();
 68     QPointF getSmallRotateRectCenter(QPointF ptA,QPointF ptB);//获取旋转时候矩形正上方的旋转标记矩形
 69     QRectF  getSmallRotateRect(QPointF ptA,QPointF ptB);
 70     qreal   m_RotateAngle;
 71     QPointF m_RotateCenter;    
 72     bool        m_bKeepShadowLength;//保持投影长度不变
 73 private:
 74     //CALIPER_RECT矩形卡尺使用
 75     QRectF      m_RECT;
 76     QRectF      m_newShearRECT;
 77     QPolygonF   m_RECTShear;//矩形斜切后
 78     QPolygonF   m_RECT_Pol;//矩形旋转后
 79     QPolygonF   m_RECT_TL_Pol;//左上角顶点旋转后
 80     QRectF      m_RECT_TL;//左上角顶点
 81     QPolygonF   m_RECT_TR_Pol;//右上角顶点旋转后
 82     QRectF      m_RECT_TR;//右上角顶点
 83     QPolygonF   m_RECT_BL_Pol;//左下角顶点旋转后
 84     QRectF      m_RECT_BL;//左下角顶点
 85     QPolygonF   m_RECT_BR_Pol;//右下角顶点旋转后
 86     QRectF      m_RECT_BR;//右下角顶点
 87     QPolygonF   m_RECT_Inside_Pol;//内部区域旋转后
 88     QPolygonF   m_RECT_InsideShear;//内部区域斜切后
 89     QRectF      m_RECT_Inside;//内部区域
 90     QPolygonF   m_RECT_Scan_Dir_Pol;//扫描方向标记旋转后
 91     QRectF      m_RECT_Scan_Dir;//扫描方向标记
 92     QPolygonF   m_RECT_Shadow_Dir_Pol;//投影方向标记旋转后
 93     QRectF      m_RECT_Shadow_Dir;//投影方向标记
 94     qreal       m_fShadowLength;//投影长度
 95     QPolygonF   m_RECT_Rotate_Pol;//旋转的标记的矩形旋转后形成的多边形
 96     QRectF      m_RECT_Rotate;//旋转的标记的矩形
 97     QPolygonF   m_RECT_Shear_Pol;//切变矩形标记旋转后
 98     QRectF      m_RECT_Shear;//切变矩形标记
 99     qreal       m_fShearX;//切变矩形x方向参数
100 
101     //
102     QPointF     m_startPos;
103     CALIPER_STATE_FLAG  m_StateFlag;
104     QMenu       *pMenu;//弹出菜单
105     QPolygonF   m_oldPolygon;
106     QMap<qreal,int> m_MapDis2Line;//记录鼠标右击时的坐标离m_oldPolygon中每一条线段的距离
107     qreal       m_MinDis;//记录鼠标右击时,离m_oldPolygon最近一条线段的距离;
108     int         m_nPolygonMovePointIndex;//移动多边形顶点的索引
109     int         m_nPolyRemoveIndex;
110 
111     bool        m_bResize;
112 protected:
113 private slots:
114     void onMenuEvent();//弹出菜单点击后响应函数
115 };
116 
117 #endif // MYGRAPHICCALIPERITEM_H

源文件:

  1 #include "myGraphicCaliperItem.h"
  2 #include <QtMath>
  3 #include <QDebug>
  4 #include <QMenu>
  5 
  6 #pragma execution_character_set("utf-8")//让能够正常显示中文字符串
  7 
  8 mygraphicCaliperitem::mygraphicCaliperitem(QGraphicsItem *parent):
  9     m_ShapeType(CALIPER_RECT),
 10     m_bResize(false),
 11     m_RECT(-100,-200,200,400),
 12     m_RotateAngle(0),
 13     m_bKeepShadowLength(false),
 14     m_fShearX(0),
 15     m_StateFlag(CALI_DEFAULT)
 16 {
 17     //setParent(parent);
 18     m_newShearRECT.setWidth(0);
 19     setRectSize(m_RECT);
 20     //setToolTip("Click and drag me!");  //提示
 21     setCursor(Qt::ArrowCursor);   //改变光标形状,手的形状
 22     setFlag(QGraphicsItem::ItemIsMovable);
 23     //SetRotate(0);
 24     //setFlag(QGraphicsItem::ItemIsSelectable);//
 25     setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
 26 //    //创建菜单对象
 27 //    pMenu = new QMenu();//((QWidget*)this);
 28 //    QAction *pActionAddPt = new QAction("添加顶点", pMenu);
 29 //    QAction *pActionDelPt = new QAction("删除顶点", pMenu);
 30 //    //1:添加多边形顶点 2:删除多边形顶点
 31 //    pActionAddPt->setData(1);
 32 //    pActionDelPt->setData(2);
 33 
 34 //    //把QAction对象添加到菜单上
 35 //    pMenu->addAction(pActionAddPt);
 36 //    pMenu->addAction(pActionDelPt);
 37 
 38 //    //连接鼠标右键点击信号
 39 //    connect(pActionAddPt, SIGNAL(triggered()), this, SLOT(onMenuEvent()));
 40 //    connect(pActionDelPt, SIGNAL(triggered()), this, SLOT(onMenuEvent()));
 41 }
 42 void mygraphicCaliperitem::onMenuEvent()
 43 {
 44 //    QAction *pEven = qobject_cast<QAction *>(this->sender()); //this->sender()就是发信号者 QAction
 45 //    //获取发送信息类型 //1:添加多边形顶点 2:删除多边形顶点
 46 //    int iType = pEven->data().toInt();
 47 //    switch (iType)
 48 //    {
 49 //        case 1://添加多边形顶点
 50 //            m_oldPolygon.insert(m_MapDis2Line.value(m_MinDis)+1,m_startPos);
 51 //        break;
 52 //        case 2://删除多边形顶点
 53 //            if(m_oldPolygon.count()>3)
 54 //            {
 55 //                m_oldPolygon.remove(m_nPolyRemoveIndex);
 56 //            }
 57 //            break;
 58 //        default:
 59 //            break;
 60 //    }
 61 //    scene()->update();
 62 }
 63 QRectF mygraphicCaliperitem::boundingRect() const//用来控制本item绘制区域
 64 {
 65     QPainterPath path;
 66     if(m_ShapeType == CALIPER_RECT)
 67     {
 68         path.setFillRule(Qt::WindingFill);
 69         path.addPolygon(m_RECT_Pol);
 70         path.addPolygon(m_RECT_Rotate_Pol);
 71         path.addPolygon(m_RECT_TL_Pol);
 72         path.addPolygon(m_RECT_TR_Pol);
 73         path.addPolygon(m_RECT_BL_Pol);
 74         path.addPolygon(m_RECT_BR_Pol);
 75         path.addPolygon(m_RECT_Shadow_Dir_Pol);
 76         path.addPolygon(m_RECT_Shear_Pol);
 77     }
 78     return path.boundingRect();
 79 }
 80 
 81 QPainterPath mygraphicCaliperitem::shape() const//用来控制检测碰撞collide和鼠标点击hit响应区域
 82 {
 83     QPainterPath path;
 84     if(m_ShapeType == CALIPER_RECT)
 85     {
 86         path.setFillRule(Qt::WindingFill);
 87         path.addPolygon(m_RECT_Pol);
 88         path.addPolygon(m_RECT_Rotate_Pol);
 89         path.addPolygon(m_RECT_TL_Pol);
 90         path.addPolygon(m_RECT_TR_Pol);
 91         path.addPolygon(m_RECT_BL_Pol);
 92         path.addPolygon(m_RECT_BR_Pol);
 93         path.addPolygon(m_RECT_Shadow_Dir_Pol);
 94         path.addPolygon(m_RECT_Shear_Pol);
 95     }
 96     return path;
 97 }
 98 
 99 QPainterPath mygraphicCaliperitem::getCollideShape()
100 {
101     QPainterPath path;
102     if(m_ShapeType == CALIPER_RECT)
103     {
104         path.addPolygon(m_RECT_Pol);
105     }
106     return path;
107 }
108 
109 QPainterPath mygraphicCaliperitem::getCollideShapeTopLeftAsOriginPoint()//返回左上角移动到item的(0,0)位置的collide区域
110 {
111     QPainterPath path;
112     if(m_ShapeType == CALIPER_RECT)
113     {
114         QTransform trans;
115         path.addPolygon(m_RECT_Pol);
116         trans.translate(-path.boundingRect().x(),-path.boundingRect().y());
117         path = trans.map(path);
118     }
119     return path;
120 }
121 
122 mygraphicCaliperitem::~mygraphicCaliperitem()
123 {
124 
125 }
126 
127 void mygraphicCaliperitem::setRectSize(QRectF mrect, bool bResetRotateCenter)
128 {
129     m_RECT = mrect;
130 //    if(m_newShearRECT.width() == 0)
131 //    {
132         m_newShearRECT = m_RECT;
133 //    }
134     if(bResetRotateCenter)
135     {
136         m_RotateCenter.setX(m_RECT.x()+m_RECT.width()/2);
137         m_RotateCenter.setY(m_RECT.y()+m_RECT.height()/2);
138     }
139     //test 扭曲
140     m_RECTShear = QPolygonF(m_RECT);
141     QTransform trans;
142     trans.translate(m_RECT.center().x(),m_RECT.center().y());
143     trans.shear(m_fShearX,0);
144     trans.translate(-m_RECT.center().x(),-m_RECT.center().y());
145     m_RECTShear = trans.map(m_RECTShear);//斜切之后的矩形
146     //test
147     m_RECT_Pol = getRotatePolygonFromPolygon(m_RotateCenter,m_RECTShear,m_RotateAngle);
148 
149     //m_RECT_Inside = QRectF(m_RECTShear[0].x()+5,m_RECTShear[0].y()+5,m_RECT.width()-10,m_RECT.height()-10);
150     m_RECT_InsideShear.clear();
151     m_RECT_InsideShear.append(QPointF(m_RECTShear[0].x()+5,m_RECTShear[0].y()+5));
152     m_RECT_InsideShear.append(QPointF(m_RECTShear[1].x()-5,m_RECTShear[1].y()+5));
153     m_RECT_InsideShear.append(QPointF(m_RECTShear[2].x()-5,m_RECTShear[2].y()-5));
154     m_RECT_InsideShear.append(QPointF(m_RECTShear[3].x()+5,m_RECTShear[3].y()-5));
155     m_RECT_InsideShear.append(QPointF(m_RECTShear[0].x()+5,m_RECTShear[0].y()+5));
156     m_RECT_Inside_Pol = getRotatePolygonFromPolygon(m_RotateCenter,m_RECT_InsideShear,m_RotateAngle);
157 
158     m_RECT_TL = QRectF(m_RECTShear[0].x()-5,m_RECTShear[0].y()-5,10,10);//左上角顶点
159     m_RECT_TL_Pol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_TL,m_RotateAngle);
160 
161     m_RECT_TR = QRectF(m_RECTShear[1].x()-5,m_RECTShear[1].y()-5,10,10);//右上角顶点
162     m_RECT_TR_Pol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_TR,m_RotateAngle);
163 
164     m_RECT_BL = QRectF(m_RECTShear[3].x()-5,m_RECTShear[3].y()-5,10,10);//左下角顶点
165     m_RECT_BL_Pol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_BL,m_RotateAngle);
166 
167     m_RECT_BR = QRectF(m_RECTShear[2].x()-5,m_RECTShear[2].y()-5,10,10);//右下角顶点
168     m_RECT_BR_Pol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_BR,m_RotateAngle);
169 
170     m_RECT_Rotate = QRectF((m_RECTShear[1].x()+m_RECTShear[2].x())/2-10,(m_RECTShear[1].y()+m_RECTShear[2].y())/2-10,20,20);//矩形右侧旋转标记矩形
171     m_RECT_Rotate_Pol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_Rotate,m_RotateAngle);
172 
173     m_RECT_Scan_Dir = QRectF((m_RECTShear[0].x()+m_RECTShear[1].x())/2-5,(m_RECTShear[0].y()+m_RECTShear[1].y())/2-5,10,10);
174     QPolygonF tempPol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_Scan_Dir,m_RotateAngle);
175     QVector<QPointF> tempv;
176     tempv.append(QPointF(tempPol[0]));
177     tempv.append(QPointF((tempPol[1].x()+tempPol[2].x())/2,(tempPol[1].y()+tempPol[2].y())/2));
178     tempv.append(QPointF(tempPol[3]));
179     m_RECT_Scan_Dir_Pol = QPolygonF(tempv);//扫描方向的三角形
180 
181     m_RECT_Shadow_Dir = QRectF(m_RECT.x()-5,m_RECT.bottomLeft().y()-15,10,10);//投影方向的三角形标记
182     QPolygonF tempShadow = QPolygonF(m_RECT_Shadow_Dir);
183     tempShadow = trans.map(tempShadow);
184     m_RECT_Shadow_Dir_Pol = getRotatePolygonFromPolygon(m_RotateCenter,tempShadow,m_RotateAngle);
185 
186     m_RECT_Shear = QRectF((m_RECTShear[2].x()+m_RECTShear[3].x())/2-5,(m_RECTShear[2].y()+m_RECTShear[3].y())/2-5,10,10);
187 //    tempPol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_Shear,m_RotateAngle);
188 //    tempv.clear();
189 //    tempv.append(QPointF((tempPol[0].x()+tempPol[1].x())/2,(tempPol[0].y()+tempPol[1].y())/2));
190 //    tempv.append(tempPol[1]);
191 //    tempv.append(QPointF((tempPol[2].x()+tempPol[3].x())/2,(tempPol[2].y()+tempPol[3].y())/2));
192 //    tempv.append(tempPol[3]);
193 //    m_RECT_Shear_Pol = QPolygonF(tempv);//切变矩形标记
194     QPolygonF tempShear = QPolygonF(m_RECT_Shear);
195     QTransform transShear;
196     transShear.translate(m_RECT_Shear.center().x(),m_RECT_Shear.center().y());//先把中心移动到m_RECT_Shear中心
197     transShear.shear(1,0);
198     transShear.translate(-m_RECT_Shear.center().x(),-m_RECT_Shear.center().y());//先把中心移动到m_RECT_Shear中心
199     tempShear = transShear.map(tempShear);//斜切之后的矩形
200     m_RECT_Shear_Pol = getRotatePolygonFromPolygon(m_RotateCenter,tempShear,m_RotateAngle);
201 
202 }
203 
204 void mygraphicCaliperitem::setShearRectSize(QRectF mrect)
205 {
206     m_newShearRECT = mrect;
207     m_RotateCenter.setX(m_newShearRECT.x()+m_newShearRECT.width()/2);
208     m_RotateCenter.setY(m_newShearRECT.y()+m_newShearRECT.height()/2);
209     //test 扭曲
210     m_RECTShear = QPolygonF(m_newShearRECT);
211     QTransform trans;
212     trans.translate(m_newShearRECT.center().x(),m_newShearRECT.center().y());
213     trans.shear(m_fShearX,0);
214     trans.translate(-m_newShearRECT.center().x(),-m_newShearRECT.center().y());
215     m_RECTShear = trans.map(m_RECTShear);//斜切之后的矩形
216     //test
217     m_RECT_Pol = getRotatePolygonFromPolygon(m_RotateCenter,m_RECTShear,m_RotateAngle);
218 
219     //m_RECT_Inside = QRectF(m_RECTShear[0].x()+5,m_RECTShear[0].y()+5,m_RECT.width()-10,m_RECT.height()-10);
220     m_RECT_InsideShear.clear();
221     m_RECT_InsideShear.append(QPointF(m_RECTShear[0].x()+5,m_RECTShear[0].y()+5));
222     m_RECT_InsideShear.append(QPointF(m_RECTShear[1].x()-5,m_RECTShear[1].y()+5));
223     m_RECT_InsideShear.append(QPointF(m_RECTShear[2].x()-5,m_RECTShear[2].y()-5));
224     m_RECT_InsideShear.append(QPointF(m_RECTShear[3].x()+5,m_RECTShear[3].y()-5));
225     m_RECT_InsideShear.append(QPointF(m_RECTShear[0].x()+5,m_RECTShear[0].y()+5));
226     m_RECT_Inside_Pol = getRotatePolygonFromPolygon(m_RotateCenter,m_RECT_InsideShear,m_RotateAngle);
227 
228     m_RECT_TL = QRectF(m_RECTShear[0].x()-5,m_RECTShear[0].y()-5,10,10);//左上角顶点
229     m_RECT_TL_Pol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_TL,m_RotateAngle);
230 
231     m_RECT_TR = QRectF(m_RECTShear[1].x()-5,m_RECTShear[1].y()-5,10,10);//右上角顶点
232     m_RECT_TR_Pol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_TR,m_RotateAngle);
233 
234     m_RECT_BL = QRectF(m_RECTShear[3].x()-5,m_RECTShear[3].y()-5,10,10);//左下角顶点
235     m_RECT_BL_Pol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_BL,m_RotateAngle);
236 
237     m_RECT_BR = QRectF(m_RECTShear[2].x()-5,m_RECTShear[2].y()-5,10,10);//右下角顶点
238     m_RECT_BR_Pol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_BR,m_RotateAngle);
239 
240     m_RECT_Rotate = QRectF((m_RECTShear[1].x()+m_RECTShear[2].x())/2-10,(m_RECTShear[1].y()+m_RECTShear[2].y())/2-10,20,20);//矩形右侧旋转标记矩形
241     m_RECT_Rotate_Pol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_Rotate,m_RotateAngle);
242 
243     m_RECT_Scan_Dir = QRectF((m_RECTShear[0].x()+m_RECTShear[1].x())/2-5,(m_RECTShear[0].y()+m_RECTShear[1].y())/2-5,10,10);
244     QPolygonF tempPol = getRotatePolygonFromRect(m_RotateCenter,m_RECT_Scan_Dir,m_RotateAngle);
245     QVector<QPointF> tempv;
246     tempv.append(QPointF(tempPol[0]));
247     tempv.append(QPointF((tempPol[1].x()+tempPol[2].x())/2,(tempPol[1].y()+tempPol[2].y())/2));
248     tempv.append(QPointF(tempPol[3]));
249     m_RECT_Scan_Dir_Pol = QPolygonF(tempv);//扫描方向的三角形
250 
251     m_RECT_Shadow_Dir = QRectF(m_newShearRECT.x()-5,m_newShearRECT.bottomLeft().y()-15,10,10);//投影方向的三角形标记
252     QPolygonF tempShadow = QPolygonF(m_RECT_Shadow_Dir);
253     tempShadow = trans.map(tempShadow);
254     m_RECT_Shadow_Dir_Pol = getRotatePolygonFromPolygon(m_RotateCenter,tempShadow,m_RotateAngle);
255 
256     m_RECT_Shear = QRectF((m_RECTShear[2].x()+m_RECTShear[3].x())/2-5,(m_RECTShear[2].y()+m_RECTShear[3].y())/2-5,10,10);
257     QPolygonF tempShear = QPolygonF(m_RECT_Shear);
258     QTransform transShear;
259     transShear.translate(m_RECT_Shear.center().x(),m_RECT_Shear.center().y());//先把中心移动到m_RECT_Shear中心
260     transShear.shear(1,0);
261     transShear.translate(-m_RECT_Shear.center().x(),-m_RECT_Shear.center().y());//先把中心移动到m_RECT_Shear中心
262     tempShear = transShear.map(tempShear);//斜切之后的矩形
263     m_RECT_Shear_Pol = getRotatePolygonFromPolygon(m_RotateCenter,tempShear,m_RotateAngle);
264 
265 }
266 
267 void mygraphicCaliperitem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
268 {
269     QPen mPen;
270     mPen= QPen(Qt::yellow);
271     painter->setPen(mPen);
272     if(m_ShapeType == CALIPER_RECT)
273     {        
274         //绘制旋转后的矩形
275         painter->drawPolygon(m_RECT_Pol);
276         //绘制旋转圆形
277         mPen.setWidth(2);
278         mPen.setColor(Qt::green);
279         painter->setPen(mPen);
280         QPointF pf = QPointF((m_RECT_Pol[1].x()+m_RECT_Pol[2].x())/2,(m_RECT_Pol[1].y()+m_RECT_Pol[2].y())/2);
281         QRectF rect = QRectF(pf.x()-10,pf.y()-10,20,20);
282         painter->drawEllipse(rect);//绘制圆形
283         painter->drawPoint(pf);//绘制点
284         //绘制4个顶点矩形
285         mPen.setWidth(1);
286         painter->setPen(mPen);
287 //        painter->drawPolygon(m_RECT_TL_Pol);
288 //        painter->drawPolygon(m_RECT_TR_Pol);
289 //        painter->drawPolygon(m_RECT_BL_Pol);
290         painter->drawPolygon(m_RECT_BR_Pol);
291         //绘制投影标记
292         QPointF pt0 = m_RECT_Shadow_Dir_Pol[0];
293         QPointF pt1 = QPointF((m_RECT_Shadow_Dir_Pol[2].x()+m_RECT_Shadow_Dir_Pol[3].x())/2,(m_RECT_Shadow_Dir_Pol[2].y()+m_RECT_Shadow_Dir_Pol[3].y())/2);
294         QPointF pt2 = m_RECT_Shadow_Dir_Pol[1];
295         painter->drawLine(pt0,pt1);
296         painter->drawLine(pt2,pt1);
297         //绘制扫描方向标记
298         painter->drawPolygon(m_RECT_Scan_Dir_Pol);
299         //绘制切变矩形标记
300         painter->drawPolygon(m_RECT_Shear_Pol);
301 
302         //painter->drawPolygon(m_RECT_Inside_Pol);
303 //        mPen.setColor(Qt::red);
304 //        mPen.setWidth(5);
305 //        painter->setPen(mPen);
306 //        painter->drawPoint(pCross1);
307 //        painter->drawPoint(pCross2);
308 //        painter->drawPoint(pCross3);
309 //        painter->drawPoint(m_RECT.center());
310     }
311 }
312 
313 double mygraphicCaliperitem::CalDis(const double x1, const double y1, const double x2, const double y2)
314 {
315     return sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
316 }
317 
318 double mygraphicCaliperitem::CalDis(const double ptx, const double pty, const double x1, const double y1, const double x2, const double y2)
319 {
320     double f = (x2-x1)*(ptx-x1) + (y2-y1)*(pty-y1);
321     if (f<=0)
322         return CalDis(ptx, pty, x1, y1);
323     double d = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
324     if (f>d)
325         return CalDis(ptx, pty, x2, y2);
326     f = f/d;
327     double projX = (x1 + (x2 - x1)*f);
328     double projY = (y1 + (y2 - y1)*f);
329     return CalDis(ptx, pty, projX, projY);
330 }
331 
332 double mygraphicCaliperitem::CalDisPoint2longLine(const double ptx, const double pty, const double x1, const double y1, const double x2, const double y2)
333 {
334 //    double f = (x2-x1)*(ptx-x1) + (y2-y1)*(pty-y1);
335     if (f<=0)
336         return CalDis(ptx, pty, x1, y1);
337 //    double d = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
338     if (f>d)
339         return CalDis(ptx, pty, x2, y2);
340 //    f = f/d;
341 //    double projX = (x1 + (x2 - x1)*f);
342 //    double projY = (y1 + (y2 - y1)*f);
343 //    return CalDis(ptx, pty, projX, projY);
344 
345     //求点(ptx,pty)到直线(x1,y1)(x2,y2)的距离
346     //直线(x1,y1)(x2,y2)的方程为y=kx+b;
347     //过点(ptx,pty)的直线(x1,y1)(x2,y2)的中垂线方程为y=k2x+b2;两线交点为pCross(x0,y0)
348     qreal k,b,k2,b2,x0,y0;
349     if(x1==x2)
350     {
351         //直线方程为:x=x1
352         if(y1==y2)
353         {
354             //垂线方程为:x=ptx
355             //该情况异常,返回-1
356             return -1;
357         }
358         else
359         {
360             k2 = (x2-x1)/(y1-y2);
361             b2 = pty-k2*ptx;
362             x0=x1;
363             y0 = k2*x0+b2;
364         }
365     }
366     else
367     {
368         k = (y1-y2)/(x1-x2);
369         b = y1-k*x1;
370         if(y1==y2)
371         {
372             //垂线方程为:x=ptx
373             x0=ptx;
374             y0=k*x0+b;
375         }
376         else
377         {
378             k2 = (x2-x1)/(y1-y2);
379             b2 = pty-k2*ptx;
380             if(k==k2)
381                 return -1;
382             else
383             {
384                 x0=(b-b2)/(k2-k);
385                 y0=k*x0+b;
386             }
387         }
388     }
389     return CalDis(x0,y0,ptx,pty);
390 }
391 
392 bool mygraphicCaliperitem::get2CrossPt(QPointF p0, QPointF p1, QPointF p2, QPointF pc, QPointF pos, QPointF &pCross1, QPointF &pCross2)
393 {
394     qreal k1,k2,b1,b2;
395     //假设经过pc的平行于p0p1的直线方程为:y=k1*x+b1;
396     if(p1.x()!=p0.x())
397     {
398         k1 = (p1.y()-p0.y())/(p1.x()-p0.x());
399         b1 = pc.y()-k1*pc.x();
400     }
401     //假设经过pos的平行于p1p2的直线方程为:y=k2*x+b2;
402     if(p1.x()!=p2.x())
403     {
404         k2 = (p2.y()-p1.y())/(p2.x()-p1.x());
405         b2 = pos.y()-k2*pos.x();
406     }
407     //假设两线交点为(x,y)
408     qreal x,y;
409     if(p1.x()==p0.x())
410     {
411         //则k1不存在,直线1为x=pc.x()
412         if(p1.x()==p2.x())
413         {
414             //k2不存在,直线2为x=pos.x()
415             //则两线焦点不存在,直接return
416             return false;
417         }
418         else
419         {
420             x=pc.x();
421             y = k2*x+b2;
422         }
423     }
424     else
425     {
426         if(p1.x()==p2.x())
427         {
428             //k2不存在,直线2为x=pos.x()
429             x = pos.x();
430             y = k1*x+b1;
431         }
432         else
433         {
434             if(k1==k2)
435                 return false;
436             x=(b1-b2)/(k2-k1);
437             y = k1*x+b1;
438         }
439     }
440     pCross1=QPointF(x,y);//经过pc的平行于p0p1的直线 与 经过Pos的平行于p1p2的直线 的焦点
441 
442     //假设经过pos的平行于p0p1的直线方程为:y=k3*x+b3;
443     //假设两线交点为(x2,y2)
444     qreal k3,k4,b3,b4,x2,y2;
445     if(p1.x()!=p0.x())
446     {
447         k3 = (p1.y()-p0.y())/(p1.x()-p0.x());
448         b3 = pos.y()-k3*pos.x();
449     }
450     //假设经过pc的平行于p1p2的直线方程为:y=k4*x+b4;
451     if(p1.x()!=p2.x())
452     {
453         k4 = (p2.y()-p1.y())/(p2.x()-p1.x());
454         b4 = pc.y()-k4*pc.x();
455     }
456     if(p1.x()==p0.x())
457     {
458         //则k3不存在,直线1为x=pos.x()
459         if(p1.x()==p2.x())
460         {
461             //k4不存在,直线2为x=pc.x()
462             //则两线焦点不存在,直接return
463             return false;
464         }
465         else
466         {
467             x2=pos.x();
468             y2 = k4*x2+b4;
469         }
470     }
471     else
472     {
473         if(p1.x()==p2.x())
474         {
475             //k4不存在,直线2为x=pc.x()
476             x2=pc.x();
477             y2 = k3*x2+b3;
478         }
479         else
480         {
481             if(k3==k4)
482                 return false;
483             x2=(b3-b4)/(k4-k3);
484             y2 = k3*x2+b3;
485         }
486     }
487     pCross2=QPointF(x2,y2);//经过pc的平行于p0p1的直线 与 经过Pos的平行于p1p2的直线 的焦点
488     return true;
489 }
490 
491 void mygraphicCaliperitem::mousePressEvent(QGraphicsSceneMouseEvent *event)
492 {
493     if(event->button()== Qt::LeftButton)
494     {
495         //setSelected(true);
496         m_startPos = event->pos();//鼠标左击时,获取当前鼠标在图片中的坐标,
497         if(m_ShapeType == CALIPER_RECT)//矩形卡尺
498         {
499             if(m_RECT_Rotate_Pol.containsPoint(m_startPos,Qt::WindingFill))//旋转矩形
500             {
501                 m_StateFlag = CALIPER_STATE_FLAG::CALI_RECT_ROTATE;
502                 setCursor(Qt::PointingHandCursor);
503             }
504 //            else if(m_RECT_TL_Pol.containsPoint(m_startPos,Qt::WindingFill))
505 //            {
506 //                m_StateFlag = CALI_RECT_TL;//标记当前为用户按下矩形的左上角顶点矩形区域
507 //                setCursor(Qt::SizeAllCursor);
508 //                //SetSideCursorByRotateAngle(m_RotateAngle);
509 //            }
510 //            else if(m_RECT_TR_Pol.containsPoint(m_startPos,Qt::WindingFill))
511 //            {
512 //                m_StateFlag = CALI_RECT_TR;//标记当前为用户按下矩形的右上角顶点矩形区域
513 //                setCursor(Qt::SizeAllCursor);
514 //                //SetSideCursorByRotateAngle(m_RotateAngle);
515 //            }
516             else if(m_RECT_BR_Pol.containsPoint(m_startPos,Qt::WindingFill))
517             {
518                 m_StateFlag = CALI_RECT_BR;//标记当前为用户按下矩形的右下角顶点矩形区域
519                 setCursor(Qt::SizeAllCursor);
520                 //SetSideCursorByRotateAngle(m_RotateAngle);
521             }
522 //            else if(m_RECT_BL_Pol.containsPoint(m_startPos,Qt::WindingFill))
523 //            {
524 //                m_StateFlag = CALI_RECT_BL;//标记当前为用户按下矩形的左下角顶点矩形区域
525 //                setCursor(Qt::SizeAllCursor);
526 //                //SetSideCursorByRotateAngle(m_RotateAngle);
527 //            }
528             else if(m_RECT_Shear_Pol.containsPoint(m_startPos,Qt::WindingFill))//在矩形内框区域时按下鼠标,则可拖动图片
529             {
530                 m_StateFlag = CALIPER_STATE_FLAG::CALI_RECT_SHEAR;//标记当前为鼠标拖动图片移动状态
531                 setCursor(Qt::PointingHandCursor);   //改变光标形状,手指的形状
532             }
533             else if(m_RECT_Inside_Pol.containsPoint(m_startPos,Qt::WindingFill))//在矩形内框区域时按下鼠标,则可拖动图片
534             {
535                 m_StateFlag = CALIPER_STATE_FLAG::CALI_RECT_MOVE;//标记当前为鼠标拖动图片移动状态
536                 setCursor(Qt::ClosedHandCursor);   //改变光标形状,手的形状
537             }
538             else
539             {
540                 m_StateFlag = CALI_DEFAULT;
541             }
542         }
543     }
544     else if(event->button()== Qt::RightButton)
545     {
546         m_startPos = event->pos();
547         //pMenu->exec(event->screenPos());//弹出菜单
548     }
549     else
550     {
551         QGraphicsItem::mousePressEvent(event);
552     }
553 }
554 
555 void mygraphicCaliperitem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
556 {
557     if(m_ShapeType == CALIPER_RECT)//矩形
558     {
559         if(m_StateFlag == CALI_RECT_ROTATE)
560         {
561            int nRotateAngle = atan2((event->pos().x()-m_RotateCenter.x()),(event->pos().y()-m_RotateCenter.y()))*180/M_PI;
562            SetRotate(90-nRotateAngle);
563            //qDebug()<<nRotateAngle;
564         }
565         else if(m_StateFlag == CALI_RECT_MOVE)
566         {
567             QPointF point = (event->pos() - m_startPos);
568             moveBy(point.x(), point.y());
569             scene()->update();
570         }
571         else if(m_StateFlag == CALI_RECT_SHEAR)//控制矩形斜切
572         {
573             QPointF pc,p0,p1,p2,p3;//,pCross1,pCross2;
574             pc = m_RotateCenter;
575             p0 = m_RECT_Pol[0];
576             p1 = m_RECT_Pol[1];
577             p2 = m_RECT_Pol[2];
578             p3 = m_RECT_Pol[3];
579             if(!get2CrossPt(p0,p1,p2,pc,event->pos(),pCross1,pCross2))
580                 return;
581             //过pc做p2p3的垂线line3,line3方程为y=k3x+b3,line3与p2,p3交点为pCross3
582             qreal k3,b3,k4,b4;
583             qreal x3,y3;//pCross3(x3,y3),//y3=k3x3+b3,y3=k4x3+b4,求x3,y3
584             if(p3.y()==p2.y())
585             {
586                 //k3不存在,lin3为x=pc.x()
587                 //直线p2p3为y=k4x+b4
588                 if(p3.x()==p2.x())
589                 {
590                     //k4不存在,直线p2p3为x=p2.x()
591                     return;
592                 }
593                 else
594                 {
595                     k4=(p3.y()-p2.y())/(p3.x()-p2.x());
596                     b4 = p2.y()-k4*p2.x();
597                     //TODO:求(x3,y3)
598                     x3 = pc.x();
599                     y3 = k4*x3+b4;
600                 }
601             }
602             else
603             {
604                 k3 = (p2.x()-p3.x())/(p3.y()-p2.y());
605                 b3=pc.y()-k3*pc.x();
606                 //直线p2p3为y=k4x+b4
607                 if(p3.x()==p2.x())
608                 {
609                     //k4不存在,直线p2p3为x=p2.x()
610                     //TODO:求(x3,y3)
611                     x3 = p2.x();
612                     y3 = k3*x3+b3;
613                 }
614                 else
615                 {
616                     k4=(p3.y()-p2.y())/(p3.x()-p2.x());
617                     b4 = p2.y()-k4*p2.x();
618                     //TODO:求(x3,y3)
619                     if(k3!=k4)
620                     {
621                         x3 = (b4-b3)/(k3-k4);
622                         y3 = k3*x3+b3;
623                     }
624                 }
625             }
626             pCross3= QPointF(x3,y3);
627 
628             //过pos做p2p3的垂线line5,line5方程为y=k5x+b5,line5与p2,p3交点为pCross5
629             qreal k5,b5;
630             qreal x5,y5;//pCross5(x5,y5),//y5=k5x5+b5,y5=k4x5+b4,求x5,y5
631             if(p3.y()==p2.y())
632             {
633                 //k3不存在,lin5为x=event->pos().x()
634                 //直线p2p3为y=k4x+b4
635                 if(p3.x()==p2.x())
636                 {
637                     //k4不存在,直线p2p3为x=p2.x()
638                     return;
639                 }
640                 else
641                 {
642                     k4=(p3.y()-p2.y())/(p3.x()-p2.x());
643                     b4 = p2.y()-k4*p2.x();
644                     //TODO:求(x5,y5)
645                     x5 = event->pos().x();
646                     y5 = k4*x5+b4;
647                 }
648             }
649             else
650             {
651                 k5 = (p2.x()-p3.x())/(p3.y()-p2.y());
652                 b5=event->pos().y()-k5*event->pos().x();
653                 //直线p2p3为y=k4x+b4
654                 if(p3.x()==p2.x())
655                 {
656                     //k4不存在,直线p2p3为x=p2.x()
657                     //TODO:求(x5,y5)
658                     x5 = p2.x();
659                     y5 = k5*x5+b5;
660                 }
661                 else
662                 {
663                     k4=(p3.y()-p2.y())/(p3.x()-p2.x());
664                     b4 = p2.y()-k4*p2.x();
665                     //TODO:求(x5,y5)
666                     if(k5!=k4)
667                     {
668                         x5 = (b4-b5)/(k5-k4);
669                         y5 = k5*x5+b5;
670                     }
671                 }
672             }
673             pCross5= QPointF(x5,y5);
674 
675             //求pos到垂线line3的距离为disShear
676             double disShear = CalDisPoint2longLine(event->pos().x(),event->pos().y(),pc.x(),pc.y(),pCross3.x(),pCross3.y());
677             //            double disp3pos = CalDis(p3.x(),p3.y(),event->pos().x(),event->pos().y());
678             //            double disp2pos = CalDis(p2.x(),p2.y(),event->pos().x(),event->pos().y());
679             //            double disp3pCross3 = CalDis(p3.x(),p3.y(),pCross3.x(),pCross3.y());
680             //            double disp2pCross3 = CalDis(p2.x(),p2.y(),pCross3.x(),pCross3.y());
681             //            double disVertical2RightLine = CalDisPoint2longLine(event->pos().x(),event->pos().y(),p1.x(),p1.y(),p2.x(),p2.y());
682             //            double disVertical2LeftLine = CalDisPoint2longLine(event->pos().x(),event->pos().y(),p0.x(),p0.y(),p3.x(),p3.y());
683             double newHalfHeight;
684             if(m_bKeepShadowLength)
685             {
686                 if(disShear>m_RECT.height()/2-1)
687                     disShear = m_RECT.height()/2-1;
688                 newHalfHeight = sqrt(qPow(m_RECT.height()/2,2)-disShear*disShear);
689                 m_fShearX = disShear/newHalfHeight;
690             }
691             else
692             {
693                 m_fShearX = disShear/(m_RECT.height()/2);
694             }
695             //确定往左斜切还是往右斜切
696             if(((-90<m_RotateAngle)&&(m_RotateAngle<90))||(m_RotateAngle>270 &&m_RotateAngle<360)||m_RotateAngle==360)
697             {
698                 if(pCross5.x()<pCross3.x())
699                     m_fShearX = -m_fShearX;
700             }
701             else if(m_RotateAngle == 90)
702             {
703                 if(pCross5.y()<pCross3.y())
704                     m_fShearX = -m_fShearX;
705             }
706             else if(m_RotateAngle>90&&m_RotateAngle<270)
707             {
708                 if(pCross5.x()>pCross3.x())
709                     m_fShearX = -m_fShearX;
710             }
711             else if(m_RotateAngle==270 ||m_RotateAngle == -90)
712             {
713                 if(pCross5.y()>pCross3.y())
714                     m_fShearX = -m_fShearX;
715             }
716             if(m_bKeepShadowLength)
717             {
718                 setShearRectSize(QRectF(pc.x()-m_RECT.width()/2,pc.y()-newHalfHeight,m_newShearRECT.width(),newHalfHeight*2));//这个函数不会重置原始矩形的大小
719             }
720             else
721             {
722                 setRectSize(m_RECT);
723             }
724             scene()->update();
725 //            //如果是要保持投影长度不变,则矩形需要重新及计算切变前矩形的高度
726 //            if(m_bKeepShadowLength)
727 //            {
728 //                double newHalfHeight = sqrt(qPow(m_RECT.height()/2,2)/(m_fShearX*m_fShearX+1));
729 //                setShearRectSize(QRectF(pc.x()-m_RECT.width()/2,pc.y()-newHalfHeight,m_RECT.width(),newHalfHeight*2));//这个函数不会重置原始矩形的大小
730 //            }
731 //            else
732 //            {
733 //                setRectSize(m_RECT);
734 //            }
735         }
736         else if(m_StateFlag == CALI_RECT_BR)//右下角顶点
737         {
738             QPointF pc,p0,p1,p2,p3;//,pCross1,pCross2;
739             pc = m_RotateCenter;
740             p0 = m_RECT_Pol[0];
741             p1 = m_RECT_Pol[1];
742             p2 = m_RECT_Pol[2];
743             p3 = m_RECT_Pol[3];
744             if(!get2CrossPt(p0,p1,p2,pc,event->pos(),pCross1,pCross2))
745                 return;
746 //            //该段代码可禁止矩形被反向拉伸!!!
747 //            double disVertical2RightLine = CalDisPoint2longLine(event->pos().x(),event->pos().y(),p1.x(),p1.y(),p2.x(),p2.y());
748 //            double disVertical2LeftLine = CalDisPoint2longLine(event->pos().x(),event->pos().y(),p0.x(),p0.y(),p3.x(),p3.y());
749 //            if(disVertical2RightLine>disVertical2LeftLine)
750 //                return;
751 //            double disVertical2BottomLine = CalDisPoint2longLine(event->pos().x(),event->pos().y(),p2.x(),p2.y(),p3.x(),p3.y());
752 //            double disVertical2TopLine = CalDisPoint2longLine(event->pos().x(),event->pos().y(),p0.x(),p0.y(),p1.x(),p1.y());
753 //            if(disVertical2BottomLine>disVertical2TopLine)
754 //                return;
755 //            //该段代码可禁止矩形被反向拉伸!!!
756             if(m_bKeepShadowLength && m_fShearX!=0)//保证投影长度不变
757             {
758                 double disp2pc = CalDis(m_RECTShear[2].x(),m_RECTShear[2].y(),pc.x(),pc.y());
759                 double dispospc = CalDis(event->pos().x(),event->pos().y(),pc.x(),pc.y());
760                 double newHeight = dispospc/disp2pc*m_newShearRECT.height();
761                 double newWidth = dispospc/disp2pc*m_newShearRECT.width();
762                 setShearRectSize(QRectF(pc.x()-newWidth/2,pc.y()-newHeight/2,newWidth,newHeight));
763                 double newHeightOld = dispospc/disp2pc*m_RECT.height();
764                 double newWidthOld = dispospc/disp2pc*m_RECT.width();
765                 m_RECT = QRectF(pc.x()-newWidthOld/2,pc.y()-newHeightOld/2,newWidthOld,newHeightOld);
766             }
767             else//投影长度可变
768             {
769                 //新矩形宽度一半:
770                 double dispcpCross1 = CalDis(pc.x(),pc.y(),pCross1.x(),pCross1.y());
771                 if(dispcpCross1<10)
772                     return;//矩形宽度不能小于20
773                 //新矩形高度一半:
774                 double disVertical = CalDisPoint2longLine(event->pos().x(),event->pos().y(),pc.x(),pc.y(),pCross1.x(),pCross1.y());
775                 if(disVertical<10)
776                     return;//矩形高度不能小于20
777                 setRectSize(QRectF(pc.x()-dispcpCross1,pc.y()-disVertical,dispcpCross1*2,disVertical*2));
778 
779             }
780             scene()->update();
781         }
782     }
783 }
784 
785 void mygraphicCaliperitem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
786 {
787     setCursor(Qt::ArrowCursor);
788     m_StateFlag = CALI_DEFAULT;
789 //    if(m_StateFlag == CALI_RECT_MOVE)
790 //    {
791 //        m_StateFlag = CALI_DEFAULT;
792 //    }
793 //    else {
794 //        QGraphicsItem::mouseReleaseEvent(event);
795 //    }
796     QGraphicsItem::mouseReleaseEvent(event);
797     //setSelected(false);
798 }
799 
800 int mygraphicCaliperitem::type() const
801 {
802     return UserType+1;//表示mygraphicCaliperitem
803 }
804 
805 void mygraphicCaliperitem::SetRotate(qreal RotateAngle)
806 {
807     m_RotateAngle = RotateAngle;
808     if(m_bKeepShadowLength && m_newShearRECT.width() != 0)
809     {
810         setShearRectSize(m_newShearRECT);
811     }
812     else
813     {
814         setRectSize(m_RECT);
815     }
816     if(this->scene()!=nullptr)
817         this->scene()->update();
818 }
819 
820 void mygraphicCaliperitem::SetSideCursorByRotateAngle(qreal RotateAngle)
821 {
822     if((RotateAngle>45&&RotateAngle<135) ||(RotateAngle>225&&RotateAngle<315))
823     {
824         if(m_StateFlag==CALI_RECT_TR ||m_StateFlag==CALI_RECT_BL)
825         {
826             setCursor(Qt::SizeFDiagCursor);
827         }
828         else if(m_StateFlag==CALI_RECT_TL ||m_StateFlag==CALI_RECT_BR)
829         {
830             setCursor(Qt::SizeBDiagCursor);
831         }
832     }
833     else
834     {
835         if(m_StateFlag==CALI_RECT_TR ||m_StateFlag==CALI_RECT_BL)
836         {
837             setCursor(Qt::SizeBDiagCursor);
838         }
839         else if(m_StateFlag==CALI_RECT_TL ||m_StateFlag==CALI_RECT_BR)
840         {
841             setCursor(Qt::SizeFDiagCursor);
842         }
843     }
844 }
845 
846 QPointF mygraphicCaliperitem::getRotatePoint(QPointF ptCenter, QPointF ptIn, qreal angle)
847 {
848     double dx = ptCenter.x();
849     double dy = ptCenter.y();
850     double x = ptIn.x();
851     double y = ptIn.y();
852     double xx,yy;
853     xx = (x-dx)*cos(angle*M_PI/180)-(y-dy)*sin(angle*M_PI/180)+dx;
854     yy = (x-dx)*sin(angle*M_PI/180)+(y-dy)*cos(angle*M_PI/180)+dy;
855 
856     return QPointF(xx,yy);
857 }
858 
859 QList<QPointF> mygraphicCaliperitem::getRotatePoints(QPointF ptCenter, QList<QPointF> ptIns, qreal angle)
860 {
861     QList<QPointF> lstPt;
862     for(int i = 0;i<ptIns.count();i++)
863     {
864         lstPt.append(getRotatePoint(ptCenter,ptIns.at(i),angle));
865     }
866     return lstPt;
867 }
868 
869 QPolygonF mygraphicCaliperitem::getRotatePolygonFromRect(QPointF ptCenter, QRectF rectIn, qreal angle)
870 {
871     QVector<QPointF> vpt;
872     QPointF pf = getRotatePoint(ptCenter,rectIn.topLeft(),angle);
873     vpt.append(pf);
874     pf = getRotatePoint(ptCenter,rectIn.topRight(),angle);
875     vpt.append(pf);
876     pf = getRotatePoint(ptCenter,rectIn.bottomRight(),angle);
877     vpt.append(pf);
878     pf = getRotatePoint(ptCenter,rectIn.bottomLeft(),angle);
879     vpt.append(pf);
880     pf = getRotatePoint(ptCenter,rectIn.topLeft(),angle);
881     vpt.append(pf);
882     return QPolygonF(vpt);
883 }
884 
885 QPolygonF mygraphicCaliperitem::getRotatePolygonFromPolygon(QPointF ptCenter, QPolygonF polyIn, qreal angle)
886 {
887     QVector<QPointF> vpt;
888     for(int i = 0;i<polyIn.count();i++)
889     {
890         QPointF pf = getRotatePoint(ptCenter,polyIn[i],angle);
891         vpt.append(pf);
892     }
893     return QPolygonF(vpt);
894 }
895 
896 QRectF mygraphicCaliperitem::getBoundedRectToSceen()
897 {
898     return QRectF(m_RECT_Pol.boundingRect().x()+pos().x(),m_RECT_Pol.boundingRect().y()+pos().y(),m_RECT_Pol.boundingRect().width(),m_RECT_Pol.boundingRect().height());
899 }
900 
901 QPolygonF mygraphicCaliperitem::getCrtPolygonToScreen()
902 {
903     QVector<QPointF> vpt;
904     if(m_ShapeType == CALIPER_ELLIPSE)
905     {
906         for(int i = 0;i<m_RECT_Pol.length();i++)
907         {
908             vpt.append(QPointF(m_RECT_Pol[i].x()+pos().x(),m_RECT_Pol[i].y()+pos().y()));
909         }
910     }
911     return QPolygonF(vpt);
912 }
913 QRectF mygraphicCaliperitem::getSmallRotateRect(QPointF ptA,QPointF ptB)
914 {
915     QPointF pt = getSmallRotateRectCenter(ptA,ptB);
916     return QRectF(pt.x()-10,pt.y()-10,20,20);
917 }
918 
919 QPointF mygraphicCaliperitem::getSmallRotateRectCenter(QPointF ptA,QPointF ptB)
920 {
921     QPointF ptCenter = QPointF((ptA.x()+ptB.x())/2,(ptA.y()+ptB.y())/2);//A,B点的中点C
922     //中垂线方程式为 y=x*k + b;
923     qreal x,y;//旋转图标矩形的中心
924     if(abs(ptB.y()-ptA.y())<0.1)
925     {
926         if(ptA.x()<ptB.x())//矩形左上角在上方
927         {
928             x = ptCenter.x();
929             y = ptCenter.y()-20;
930         }
931         else//矩形左上角在下方
932         {
933             x = ptCenter.x();
934             y = ptCenter.y()+20;
935         }
936     }
937     else if(ptB.y()>ptA.y())//顺时针旋转0-180
938     {
939         qreal k = (ptA.x()-ptB.x())/(ptB.y()-ptA.y());//中垂线斜率
940         qreal b = (ptA.y()+ptB.y())/2-k*(ptA.x()+ptB.x())/2;
941         //求AB线中垂线上离AB中点20个像素的点C的坐标
942         x = 20*cos(atan(k))+ptCenter.x();
943         y = k*x+b;
944     }
945     else if(ptB.y()<ptA.y())//顺时针旋转180-360
946     {
947         qreal k = (ptA.x()-ptB.x())/(ptB.y()-ptA.y());//中垂线斜率
948         qreal b = (ptA.y()+ptB.y())/2-k*(ptA.x()+ptB.x())/2;
949         //求AB线中垂线上离AB中点20个像素的点C的坐标
950         x = -20*cos(atan(k))+ptCenter.x();
951         y = k*x+b;
952     }
953     return QPointF(x,y);
954 }
原文地址:https://www.cnblogs.com/ybqjymy/p/13862397.html