#ifndef CPROCESS_LEVEL_H
#define CPROCESS_LEVEL_H
#include "cimagecontainer.h"
#include "cmprocess.h"
#include "cprecisetime.h"
#include "camatchncc_h.h"
typedef struct _AlignPoint {
    double dAngle;
    CMPointd Pt;
    bool bHasSet;
    bool bHasMatch;
    _AlignPoint()
    {
        StateReset();
    }
    void StateReset()
    {
        dAngle = 0;
        bHasSet = false;
        bHasMatch = false;
    }

}AlignPoint;
/*!
 * \brief The CProcess_Level class
 * 调平操作
 */
class CProcess_Level : public CMProcess {
public:
    enum msg_id {
        PROCESS_LEVEL_MSG_ID = MAX_PROCESS_MSG_ID,
        CHANGE_TO_LEVEL_SIDE,   //切换面
        CALCU_PT_BY_CELL,
        CALCU_PT_BY_LINE,
        CALCU_PT_BY_POS,
        MOVE_PT,
        SEARCH_ROTATE,
        SEARCH_ALIGN,
        SEARCH_BASE,
        TURN_ANGLE,
        SETPT_MANUAL,
        TEST_MODEL,
        SETLEVELLIGHT,
        LOADLEVELMODEL,
        LOADCALIBRATIONMODEL,
        FINDMODEL_ONCE,
        MAX_PROCESS_LEVEL_MSG_ID,
    };
    CProcess_Level(const QString& name, int32_t id);
    virtual ~CProcess_Level();
    virtual void do_msg(int iID, QVariantList& vlInput, V_MsgOutput* pvlOutput) override;
#if 0
    virtual void Serialize(QDataStream &stream, bool bwrite, int iVersion) override;
#endif

public:
    enum pt_type {
        TYPE_PT1 = 1,   //!点1
        TYPE_PTMID,     //!点1偏移后的点
        TYPE_PT2,       //!点2
        TYPE_PTBASE,    //!点基准
        TYPE_PTROTATE,  //!点旋转
    };

    AlignPoint m_AlignPt1;	    //!点1,近点
    AlignPoint m_AlignPtMid;	//!点中间，
    AlignPoint m_AlignPt2;      //!点2，远点
    AlignPoint m_AlignPtBase;   //!基准点，最靠近中心的定位点
    AlignPoint m_AlignPtRotate; //!旋转定位的点，默认使用的点1

    //上面两个调平，共两组
    CImageContainer m_imageContainerAlign[2][2];
    //下面左边的调平显示，共两个
    CImageContainer m_imageContainerBase[2];

    void ClearContainer();
    ModelData m_ModelData[2][2];
    ModelData m_CalibrationModelData[3];
    ModelData *GetModelData(int iSideID, int iCamID);
    void LoadLevelModel(QString& sFilePath);
    void LoadCalibrationModel(QString& sFilePath);
public:
    int32_t m_iLocateCamID; //!定位关联的相机id
    int32_t m_iMatchCamID;//! 调平关联的相机id
public:
    /*!
    * \brief ChangeToLevelSide
    * 切换面
    *
    * \param iSideID SIDA, SIDB
    * \warning 必须先调用
    * \note 小心使用
    * \attention 切换的时候会调用ChangeSide
    */
    void ChangeToLevelSide(int iSideID);

    /*!
    * \brief 计算并生成某一面的点
    *
    * \param iSideID 面ID SIDE_A SIDE_B
    * \param baseposX  X基准点
    * \param baseposY  Y基准点
    * \param dStartTopPos    开始die的X位置
    * \param dEndBottomPos   结束die的X位置
    * \return
    */
    virtual int32_t calcuPt(int32_t iSideID,
                            double baseposX, double baseposY,
                            double  dStartTopPos, double  dEndBottomPos);
    /*!
    * \brief 生成默认的定位点
    *
    * \param iSideID
    */
    virtual void CalcuPtByCell(int iSideID);
    /*!
    * \brief 生成某条线的定位点
    *
    * \param iSideID
    * \param iLineID
    */
    virtual void CalcuPtByLine(int iSideID, int iLineID);
    /*!
    * \brief 按基准点生成定位点
    *
    * \param iSideID
    * \param baseposX
    * \param baseposY
    * \param dStartPos
    * \param dEndPos
    */
    virtual void CalcuPtByPos(int iSideID, double baseposX, double baseposY,
                              double  dStartPos, double  dEndPos);

    /*!
    * \brief 移到Wafer关联点的位置
    *
    * \param iSideID
    * \param WPDP
    * \param iCamID 关联的相机id
    */
    void posMove(int iSideID, const CMPointd& WPDP, int iCamID);
    //adjustToTemplatePt 调整到模板位置
    /*!
    * \brief 移动到ptstyle关联的点
    *
    * \param iSideID
    * \param iCamID
    * \param ptstyle \sa pt_type
    * \param adjustToTemplatePt 是否偏移到模板位置
    * \param iXAdjust  X方向调整次数
    * \param iYAdjust  Y方向调整次数
    */
    void MovePt(int iSideID, int iCamID, int ptstyle,
                bool adjustToTemplatePt, int iXAdjust, int iYAdjust);

    /*!
    * \brief 设定相机参数，并执行模板匹配查找特征
    *
    * \param iSideID
    * \param[out] WTResult 模板中心点的坐标
    * \param[out] dAngle   模板角度，顺时针为正
    * \param iCamID        搜索的相机ID
    * \param benableROI    是否在ROI中查找
    * \param pContainer    显示的位置
    * \param adjustToRefPt 调整到切割道位置
    * \return
    */
    virtual bool search_pt(int iSideID, CMPointd& WTResult, double& dAngle,
                           int iCamID, bool benableROI, CImageContainer *pContainer,
                           bool adjustToRefPt);

    /*!
    * \brief 更新调平点的坐标
    *
    * \param iSideID
    * \param ptstyle \sa pt_type
    */
    virtual void adjustPt(int iSideID, int ptstyle);
    void SearchRotatePt(int iSideID, int iCamID);
    /*!
    * \brief 查找调平点
    * ssssss
    * \param iSideID
    * \param iCamID
    * \param ptstyle \sa pt_type
    * \return
    */
    virtual double SearchAlignPt(int iSideID, int iCamID, int ptstyle);
    /*!
    * \brief 查找基准点
    * 找到后，更新基准点的坐标
    * \param iSideID
    * \param iCamID
    * \param iLineID 0时更新基准点并生成切割线 非0时调用calcuSideVector更新切割线
    */
    virtual void SearchBasePt(int iSideID, int iCamID, int iLineID);

    /*!
    * \brief 计算目标点与点1(参考点)的旋转角度
    *
    * \param ptstyle \sa pt_type
    * \return
    */
    virtual double calcuAngle(int ptstyle);
    /*!
    * \brief 转到角度并更新点
    *
    * \param iSideID
    * \param ptstyle
    * \sa calcuAngle turn adjustPt
    */
    void Turn_Angle(int iSideID, int ptstyle);
    /*!
    * \brief 手动设置特定点，将向状态机发送退出特定状态消息
    *
    * \param iSideID
    * \param iCamID
    * \param ptstyle
    * \param iLineID
    */
    virtual void SetPtManual(int iSideID, int iCamID, int ptstyle, int iLineID, bool bManualSet=true);

    int Test_Model(int iSideID, int iCamID);
    int FindModelOnce(int iSideID, int iCamID);

    void SetLevelLight(int iSideID, int iCamID);
    void SetCamParam(int iSideID, int iCamID);

public:
    void CaptureImage(int iCamID, CImageContainer* pImageContainer,
                      QString str, bool bclearShape = true);

    void FreshImage(int iCamID, CMImage& img, CImageContainer* pImageContainer, QString str, bool bclearShape = true);
    virtual void calcuSideVector(int32_t iSideID, double dYOffset, int iLineID, bool manualSet = false);

    /*!
    * \brief X方向调整长度，
    *
    * \param iSideID
    * \param iCamID
    * \param bIndex true 按步长调整 false 按1/1.3视野调整
    * \return
    */
    double get_XAdjust_step(int iSideID, int iCamID, bool bIndex);
    /*!
    * \brief Y方向调整长度，
    *
    * \param iSideID
    * \param iCamID
    * \param bIndex true 按步长调整 false 按1/1.2视野调整
    * \return
    */
    double get_YAdjust_step(int iSideID, int iCamID, bool bIndex);

    int get_XAdjust_count(int iSideID, int iCamID);
    int get_YAdjust_count(int iSideID, int iCamID);
    /*!
    * \brief 返回当前面的步长
    * 从上往下切割，即每一道切割线的步长
    * \param iSideID
    * \return
    */
    double getCurSideStep(int iSideID);
    /*!
    * \brief 返回另一面的切割步长
    *
    * \param iSideID
    * \return
    */
    double getOtherSideStep(int iSideID);
    /*!
    * \brief 获取当前定位参数
    *
    * \param iSideID
    * \param iFirst 首道
    * \param iStep 步长
    */
    void getCurSideAlignParam(int iSideID, int& iFirst, int& iStep);

    /*!
    * \brief 获取X方向的起点和终点
    *
    * \param iSideID
    * \param Y
    * \param XStart
    * \param XEnd
    * \return
    */
    BOOL getX(int iSideID, double Y, double& XStart, double& XEnd);

    /*!
    * \brief 获取最大外接矩形
    *
    * \param iSideID
    * \param dLeft
    * \param dRight
    * \param dBottom
    * \param dTop
    */
    virtual void	getCircleBoundary(int iSideID, double& dLeft, double& dRight,
                                      double& dBottom, double& dTop);
    /*!
    * \brief 按角度旋转轴，并调整定位的4个点
    *
    * \param iSideID
    * \param dAngleRel
    * \return
    */
    int turn(int iSideID, double dAngleRel);

    //!按圆生成所有切割道
    virtual void calcuLineCircle(int iSideID);
    /*!
    * \brief 生成一条切割道
    *
    * \param Bottom
    * \param dLeft
    * \param dRight
    * \param iSideID 面ID
    * \param bsub      是否有子切割道
    * \param index     线号 0开始
    * \param baseY     Y向基准线
    */
    virtual void calculine(CMPointd Bottom, double dLeft, double dRight,
                           int iSideID, BOOL bsub, int index, double baseY);

    /*!
    * \brief 计算点1与点2之前的角度
    * 左点和右点
    * 根据X的位置交换左边位置为左点 右边位置为右点
    * \param Pt1
    * \param Pt2
    * \return -90~90度
    */
    virtual double calcuAngle(CMPointd Pt1, CMPointd Pt2);

    /*!
    * \brief 计算指定距离dDis规整化到步长
    *
    * \param dDis
    * \param dStep
    * \return
    */
    double numDis(double dDis, double dStep);
    int m_iCurLineId;

    CMPointd m_ModelTestPos;
};

#endif // CPROCESS_LEVEL_H
