#include "graphicsItem/graphicsPolygonItem.h"
#include "graphicsItem/itemControlHandle.h"

#include <QPainter>
#include <QStyleOption>

GraphicPolygonItem::GraphicPolygonItem(QGraphicsItem *parent)
    : GraphicsBaseItem(parent)
{
    m_pen = QPen(Qt::black);
    m_brush = QBrush(Qt::NoBrush);
}

GraphicPolygonItem::~GraphicPolygonItem()
{

}

QPainterPath GraphicPolygonItem::shape()
{
    QPainterPath path;
    path.addPolygon(m_points);
    path.closeSubpath(); //将路径闭合
    return path;
}

QRectF GraphicPolygonItem::boundingRect()
{
    //m_boundingRect = shape().controlPointRect(); //返回路径中所有点和控制点的矩形，文档介绍比返回精确边界框的boundingRect()函数计算要快
    return m_boundingRect;
}

void GraphicPolygonItem::updateHandles()
{
    GraphicsBaseItem::updateHandles();
    for(int i = 0; i < m_points.size(); i++)
    {
        m_vecHanle[H_edit + i -1]->move(m_points[i].x(), m_points[i].y());
    }
}

void GraphicPolygonItem::updateCoordinate() //当执行了resie和editShape函数后，boundingRect发生了变换，需要将item的原点(以中心点为原点)校准至boundingRect.center()
{
    if (!parentItem())
    {
        QPointF pt1, pt2, delta;
        pt1 = mapToScene(QPointF(0, 0));
        pt2 = mapToScene(m_boundingRect.center());
        delta = pt1 - pt2;

        prepareGeometryChange();
        //更改图形绘制节点坐标，让图形中心和原点对齐
        QPolygonF ptsOnScene = mapToScene(m_points); //所有操作都在scene坐标系下进行，然后在还原至item坐标系，否则会有跳转
        for(int i=0; i<m_points.count(); i++)
            ptsOnScene[i] += delta; //一定要在scene坐标系下执行操作，不能直接m_points += delta;因为缩放以后item自身的内部坐标系也会同步缩放，单位刻度和scene下的单位刻度不再一致，所以所有相关计算一定要在同一个坐标系下完成
        m_points = mapFromScene(ptsOnScene);
        m_boundingRect = m_points.boundingRect();
        //移动整体图形，消除节点坐标更后的绘制跳转
        moveBy(-delta.x(), -delta.y());
        updateHandles();
    }

    m_lastPoints = m_points;
}

void GraphicPolygonItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    painter->setPen(m_pen);
    painter->setBrush(m_brush);
    painter->drawPolygon(m_points);

    if (option->state & QStyle::State_Selected) //是选中状态,绘制选中框
    {
        int nPenWidth = 1;
        painter->setPen(QPen(QColor(70,70,70), nPenWidth, Qt::DashLine)); //蓝色的外框
        painter->setBrush(Qt::NoBrush);
        painter->drawRect(m_boundingRect_selected);

        //绘制变换原点
        QPointF originPoint = transformOriginPoint();
        painter->setBrush(Qt::red);
        painter->drawEllipse(originPoint, 4, 4);
    }
}

void GraphicPolygonItem::resize(int nHandle,double dSX, double dSY, const QPointF& basePoint)
{
    switch (nHandle)
    {
    case H_left:
    case H_right:
        dSY = 1; //拖拽的是左点右点，为水平缩放，忽略垂直变化
        break;
    case H_top:
    case H_bottom:
        dSX = 1; //拖拽的是顶点底点，为垂直缩放，忽略水平变化
        break;
    default:
        break;
    }

    QTransform trans;
    //缩放是以图元原点（中心）位置为基准，所以每帧都先移动移动到想要的基准点，缩放之后再移回
    trans.translate(basePoint.x(), basePoint.y());
    trans.scale(dSX, dSY);
    trans.translate(-basePoint.x(), -basePoint.y());

    prepareGeometryChange();
    m_points = trans.map(m_lastPoints);
    m_boundingRect = m_points.boundingRect();
    m_dWidth = m_boundingRect.width();
    m_dHeight = m_boundingRect.height();
    updateHandles();
}

void GraphicPolygonItem::move(const QPointF& point)
{
    moveBy(point.x(), point.y());
}

void GraphicPolygonItem::editShape(int nHandle,const QPointF& ptMouse)
{
    QPointF pt = mapFromScene(ptMouse);
    m_points[nHandle - H_rotate_leftBottom - 1] = pt;
    prepareGeometryChange();
    m_boundingRect = m_points.boundingRect();
    m_dWidth = m_boundingRect.width();
    m_dHeight = m_boundingRect.height();
    m_lastPoints = m_points;
    updateHandles();
}

void GraphicPolygonItem::addPoint(const QPointF& point)
{
    m_points.append(mapFromScene(point));
    int nCount = m_points.count();
    //每个顶点都可以编辑，所以一个顶点需要编辑handle
    ItemControlHandle* pHandle = new ItemControlHandle(this);
    pHandle->setType(T_editShape);
    pHandle->setTag(H_edit + nCount - 1);
    m_vecHanle.push_back(pHandle);
}

bool GraphicPolygonItem::endDrawing()
{
    bool bSuccess = true;
    int nPointCount = m_points.count();
    if(nPointCount < 3)
        bSuccess = false;

    return bSuccess;
}
