#include "cprocess_halfcutkerf.h"
#include "logic.h"
#include "cproductside.h"
#include "cmproduct.h"
#include "cprocess_level.h"
#include "cmproduct.h"
#include "cmworktabledriver.h"
#include "cakerfcheck_h.h"
CProcess_HalfCutKerf::CProcess_HalfCutKerf(const QString &name, int32_t id)
    :CMProcess(name,id)
{
    m_Variants.add_Variant(Var_Process_Kerf_BeforeSearchSleep_ID,
                           QObject::trUtf8("BeforeSearchSleep"),int(0),false,
                           Variant::TOXML);
    m_Variants.add_Variant(Var_Process_Kerf_AfterSearchSleep_ID,
                           QObject::trUtf8("AfterSearchSleep"),int(0),false,
                           Variant::TOXML);
    m_Variants.add_Variant(Var_Process_Kerf_PosOffset_ID,
                           QObject::trUtf8("PosOffset"),double(0),false,
                           Variant::TOXML);
    m_Variants.add_Variant(Var_Process_Kerf_EnableAutoThres_ID,
                           QObject::trUtf8("EnableAutoThres"),false,false,
                           Variant::TOXML);
    m_Variants.add_Variant(Var_Process_Kerf_AutoThresRange_ID,
                           QObject::trUtf8("AutoThresRange"),int(0),false,
                           Variant::TOXML);
    m_Variants.add_Variant(Var_Process_Kerf_AutoThresStep_ID,
                           QObject::trUtf8("AutoThresStep"),int(0),false,
                           Variant::TOXML);

    m_Variants.add_Variant(Var_Process_Kerf_MinOffsetThres_ID,
                           QObject::trUtf8("HalfcutMinOffsetThres"), double(0.001), false,
                           Variant::TONONE);

    m_Variants.add_Variant(Var_Process_Kerf_MaxOffsetThres_ID,
                           QObject::trUtf8("HalfcutMaxOffsetThres"), double(0.02), false,
                           Variant::TONONE);

    m_Variants.add_Variant(Var_Process_Kerf_EnableAutoCompensation,
                           QObject::trUtf8("EnableAutoCompensation"), bool(false), false,
                           Variant::TONONE);
    

	m_imageContainer[0] = nullptr;
	m_imageContainer[1] = nullptr;
	
    m_iKerfCamID=CAM6X;
	m_dKerfPower = 1.5;
	m_dKerfWidth = 2;
	m_bHasSet = false;
	m_iCurLineId = -1;
	m_bAlignCheck = false;
}


int CProcess_HalfCutKerf::CalcuKerfPos(int iSideID, int iLineID)
{
    if (iSideID!=SIDE_A&&iSideID!=SIDE_B)
    {
        MQT_THROW_CODESTR(ALARM_MAIN_HALFKERF_ERROR, (QObject::trUtf8("Halfcut:")+ QObject::trUtf8("Calcu kerf pos err. In no Side")));
    }
    CProductSide* pSide=GET_CHDIRECT(iSideID,CProductSide);
    int iSizeLine=pSide->m_CutLineVector.size();
    if (OUTOFRANGE(iLineID,0,iSizeLine))
    {
        MQT_THROW_CODESTR(ALARM_MAIN_HALFKERF_ERROR , (QObject::trUtf8("Halfcut:") + QObject::trUtf8("Calcu kerf pos err. In no Line")));
    }
    const CUTLINE* pLine=pSide->GetCutLine(iLineID);

    KERFPARAM* pKerfParam=GetKerfParam(iSideID);
    double dPosOffset=pKerfParam->dSpecKerfPos;
    //mparams[PosOffset]->getDataDirect();
    if(pKerfParam->ikerfPos==CENTER_KERF)
    {
		//中心位置加偏移
        m_CheckPos.tX=pLine->m_BasePt.tX+dPosOffset;
        m_CheckPos.tY=pLine->m_BasePt.tY;
    }
    else if(pKerfParam->ikerfPos == SPEC_KERF)
    {
        //hack:特定位置如何计算来的
		//设定时=当前位置-中心点的偏移，可正可负
        double dKerflengX=pKerfParam->dSpecKerfPos;
        double dKerflengY=pLine->m_BasePt.tY-pSide->m_realCenter.tY;

        CMProduct* pProduct=GET_CHDIRECT(PRODUCT,CMProduct);
        double dDiameter=pProduct->m_Variants.get_VData(Var_Product_Diameter_ID)
                ->toDouble();
        if(sqrtf(pow(dKerflengX,2)+pow(dKerflengY,2))>dDiameter/2)
        {
            m_bHasSet=true;
            return 0;
        }
        m_CheckPos.tX=pKerfParam->dSpecKerfPos+pSide->m_realCenter.tX;
        m_CheckPos.tY=pLine->m_BasePt.tY;
    }else{
		//中心位置加偏移
		m_CheckPos.tX=pLine->m_BasePt.tX+dPosOffset;
		m_CheckPos.tY=pLine->m_BasePt.tY;
	}
    m_bHasSet=false;
	m_iCurLineId = iLineID;
    return 0;
}

int CProcess_HalfCutKerf::MoveKerfPos()
{
    CMWorkTableDriver* pWorkTableDriver=GET_CARD(WORKTABLE_DRIVER,CMWorkTableDriver);
    Q_ASSERT(pWorkTableDriver);
    m_gSystem.changeChannel(m_iKerfCamID,false);
    CMPointd Axis;
    pWorkTableDriver->WtToAxis(m_iKerfCamID,m_CheckPos,Axis);
    m_gSystem.absmove_xy(Axis.tX,Axis.tY);

	//TODO:Z轴做一个偏移，以方便Kerf检查

    return 0;
}

int CProcess_HalfCutKerf::Kerf(int iSideID,int iLineID)
{
	if(m_bHasSet){
		m_bHasSet = false;
		return 0;
	}

    m_KerfTime.StartTime();
    SetKerfLight(iSideID);
    MSleep(m_Variants.get_VData(Var_Process_Kerf_BeforeSearchSleep_ID)->toInt());

    QString str=QObject::trUtf8("Halfcut Check");
	if(m_bAlignCheck){
		str=QObject::trUtf8("Align Check");
	}
    CaptureImage(iSideID,str);
    SetKerfParam(iSideID);
	CCam* pCam=GET_CHDIRECT(m_iKerfCamID,CCam);
    pCam->m_imageContainer.clearShape(-1);
    pCam->m_imageContainer.clearString(-1);

    SearchLine(iSideID, m_Variants.get_VData(Var_Process_Kerf_EnableAutoThres_ID)->toBool());
    MSleep(m_Variants.get_VData(Var_Process_Kerf_AfterSearchSleep_ID)->toInt());

	int index=iSideID==SIDE_A?0:1;

	CAKerfCheck_H* pAKerf=(CAKerfCheck_H*)pCam->Find_Algorithm(M_KERF_HALFCUT);
	Q_ASSERT(pAKerf);
	pAKerf->showresult(m_imageContainer[index]);
	if(m_bAlignCheck){
		m_imageContainer[index]->addString(QObject::trUtf8("Align Check Failed"));
	}
	//pAKerf->showragion_static(&m_imageContainer[index]);
	AnalyseKerfResult(  iSideID, iLineID, &pCam->m_imageContainer);
	m_gSystem.SetCutStreet(&pCam->m_imageContainer,iSideID,m_iKerfCamID);

    m_KerfTime.StopTime();
    return 0;
}

void CProcess_HalfCutKerf::AnalyseKerfResult(int iSideID, int iLineID, CImageContainer* pContainer)
{
    KERFPARAM* pKerfParam=GetKerfParam(iSideID);
    int iSizeResult=VectorResult.size();
    if (iSizeResult!=pKerfParam->iLineCount*2)
    {
		if(m_bAlignCheck){
			pContainer->addString(QObject::trUtf8("Align Check Failed"));
			MQT_THROW_CODESTR(ALARM_MAIN_ALIGNCHECK_ERROR, (QObject::trUtf8("Align Check:")+QObject::trUtf8("Can not Locate Each Cut Line")));
		}
		else{
			MQT_THROW_CODESTR(ALARM_MAIN_HALFKERF_ERROR, (QObject::trUtf8("Halfcut:")+QObject::trUtf8("Can not Locate Each Cut Line")));
		}
    }
    
    double dRealOffset=0,dRealHeight=0,dRealHeight1=0, dRealGAP=0;
    GetKerfResult( dRealOffset, dRealHeight , dRealHeight1 , dRealGAP);
	//偏移最大值
    if (fabs(dRealOffset)>pKerfParam->dOffsetMax)
    {
		if(m_bAlignCheck) {
			if(fabs(dRealOffset)>pKerfParam->dOffsetMax*1.5){
				MQT_THROW_CODESTR(ALARM_MAIN_ALIGNCHECK_ERROR, (QObject::trUtf8("Align Check:")+ QObject::trUtf8("Halfcut Kerf err. Offset: %1>Max Offset:%2*1.5")
					.arg(dRealOffset,0,'f',4)
					.arg(pKerfParam->dOffsetMax,0,'f',4)));
			}
		}
		else {
			MQT_THROW_CODESTR(ALARM_MAIN_HALFKERF_ERROR, (QObject::trUtf8("Halfcut:")+ QObject::trUtf8("Halfcut Kerf err. Offset: %1>Max Offset:%2")
                      .arg(dRealOffset,0,'f',4)
                      .arg(pKerfParam->dOffsetMax,0,'f',4)));
		}
    }
    
    if (iSizeResult==2)
    {
        if (dRealHeight>pKerfParam->dWidthMax)
        {
            MQT_THROW_STR(QObject::trUtf8("Halfcut Kerf err. Line "
                                          "Width: %1>Max Line Width:%2")
                          .arg(dRealHeight,0,'f',3)
                          .arg(pKerfParam->dWidthMax,0,'f',3));
        }
        if (dRealHeight<pKerfParam->dWidthMin)
        {
            MQT_THROW_STR(QObject::trUtf8("Halfcut Kerf err.  Line "
                                          "Width: %1<Min Line Width:%2")
                          .arg(dRealHeight,0,'f',3)
                          .arg(pKerfParam->dWidthMin,0,'f',3));
        }
    }
    else
    {
        Q_ASSERT(0);
    }
	QString str=QObject::trUtf8("Halfcut Check");
	if(m_bAlignCheck){
		QObject::trUtf8("Align Check");
	}
    CaptureImage(iSideID,str);

    ShowKerfResult( dRealOffset, dRealHeight , dRealHeight1 ,
                        dRealGAP,pContainer);

	int index=iSideID==SIDE_A?0:1;
	ShowKerfResult( dRealOffset, dRealHeight , dRealHeight1 ,
		dRealGAP,m_imageContainer[index]);

	//偏移大于最小值才补偿
    if(fabs(dRealOffset)>pKerfParam->dOffsetMin )
    {
		//如果偏移超过阈值，则自动校正刀痕
        CMPointd WPDP=m_CheckPos;
        WPDP.tY+=dRealOffset;
		bool bEnableOffset = false;

        //启用偏移补偿
        if (!m_gSystem.m_bDisableHairlineOffsetAutoCompensation)
        {
            if (!m_bAlignCheck)
            {
                bEnableOffset = true;
            }
        }

        SetHairLineOffset(  iSideID, iLineID,  WPDP, bEnableOffset);
      }

    str=QObject::trUtf8("TM:%1,CH:%2,Offset:%3,Height:%4")
            .arg(m_KerfTime.FormatTime())
            .arg(index+1)
            .arg(dRealOffset)
            .arg(dRealHeight);
	if(m_bAlignCheck){
		m_gSystem.EvtLog(QString::fromUtf8("ALIGN(CHECK)"),str);
	}
	else{
		m_gSystem.EvtLog(QString::fromUtf8("KERF(HALFCUT)"),str);
	}
}

int CProcess_HalfCutKerf::SetKerfPosManual(int iSideID, int iLineID)
{
    CMPointd WPDP;
    CMWorkTableDriver* pWorkTableDriver=GET_CARD(WORKTABLE_DRIVER,
                                                 CMWorkTableDriver);
    Q_ASSERT(pWorkTableDriver);
    pWorkTableDriver->CurAxisToWt(m_iKerfCamID,WPDP,true);

	if(iLineID==-1){
		iLineID = max(0, m_iCurLineId);
	}

	if(m_bAlignCheck){
		iLineID = 0;
	}

	//更新半切刀痕
    //手动执行时一定会进行纠偏，小于1um时不会进行纠偏
    if (m_bAlignCheck)
    {
        AddProductData("Manual Set Halfcut Kerf");
    }
    else
    {
        AddProductData("Manual Set Align(halfcut) Kerf");
    }
    double dOffset = SetHairLineOffset(iSideID, iLineID,  WPDP, true);

    QString str=QObject::trUtf8("Manual Halfcut Kerf Offset:%1mm").arg(dOffset,0,'f',3);
	if(m_bAlignCheck){
		str=QObject::trUtf8("\nManual Align(halfcut) Offset:%1mm").arg(dOffset,0,'f',3);
	}

    AddProductData(str);
    CaptureImage(  iSideID,  str);
    m_bHasSet=true;
    return 0;
}

void CProcess_HalfCutKerf::CaptureImage(int iSideID, QString& str)
{
    UNUSED(iSideID);
    CCamDriver* pCamDriver=GET_CARD(CAM_DRIVER,CCamDriver);
    Q_ASSERT(pCamDriver);
    int index=iSideID==SIDE_A?0:1;
    CImageContainer* pContainer=m_imageContainer[index];
    pContainer->clearString(-1);
    pContainer->clearShape(-1);

	if(iSideID == SIDE_A)
	{
		if(m_bAlignCheck){
			pContainer->SetName("CH1 AlignCheck");
		}
		else{
			pContainer->SetName("CH1 Halfcut");
		}
	}
	else if(iSideID == SIDE_B)
	{
		if(m_bAlignCheck){
			pContainer->SetName("CH2 AlignCheck");
		}
		else{
			pContainer->SetName("CH2 Halfcut");
		}
	}
	//{
	//	//TODO:这里不加锁，显示界面的时候图像内存错误
	//	QMutexLocker l(&pContainer->mutex);
	//	pCamDriver->grab_image(m_iKerfCamID,
 //                          &pContainer->m_Image);
	//}
	CMImage img;
	pCamDriver->grab_image(m_iKerfCamID, &img);
    pContainer->SetImage(img, false);
	
    if(!str.isEmpty())
    {pContainer->addString(str);}

    m_gSystem.SetCutStreet(pContainer,iSideID,m_iKerfCamID);

}

void CProcess_HalfCutKerf::TestKerf(int iSideID)
{
    MoveKerfPos();
    SetKerfParam(iSideID);
    SearchLine(  iSideID,false);
}

void CProcess_HalfCutKerf::ClearContainer()
{
    m_imageContainer[0]->ClearImage();
    m_imageContainer[1]->ClearImage();
}

int32_t CProcess_HalfCutKerf::init_Process()
{
	CProcess_Level* processLevel =  GET_PROCESS(PROCESS_LEVELING,
									SM_MAIN,
									CProcess_Level);
	
	 m_imageContainer[0] = &processLevel->m_imageContainerBase[0];
	 m_imageContainer[1] = &processLevel->m_imageContainerBase[1];
	
	return CMProcess::init_Process();
}

void CProcess_HalfCutKerf::SetKerfParam(int iSideID)
{
    CCam* pCam=GET_CHDIRECT(m_iKerfCamID,CCam);
    Q_ASSERT(pCam);
    CAKerfCheck_H* pAKerf=(CAKerfCheck_H*)pCam->Find_Algorithm(M_KERF_HALFCUT);
    Q_ASSERT(pAKerf);
    KERFPARAM *pKerfParam=  GetKerfParam(  iSideID);
    int iThreshold=pKerfParam->iPixelThres;
    double dResolutionY=pCam->m_CoordTrans.m_dresolution_Y;
    if(DEQUAL0(dResolutionY))
    {
        MQT_THROW_STR(QObject::trUtf8("Kerf process err. "
                                      "Cam resolution equal 0"));
    }
    int iRange=  pKerfParam->dRange/dResolutionY;
    int iRangeMin= pKerfParam->dRangeMin/dResolutionY;

    int iMinLength=pKerfParam->dWidthMin/dResolutionY;
    int iMaxLength=pKerfParam->dWidthMax/dResolutionY;
    pAKerf->m_Variants.get_VData(Var_KerfCheck_H_Rangemax)->setValue(iRange);
    pAKerf->m_Variants.get_VData(Var_KerfCheck_H_Rangemin)->setValue(iRangeMin);
    pAKerf->m_Variants.get_VData(Var_KerfCheck_H_Threshold)->setValue(iThreshold);
    pAKerf->m_Variants.get_VData(Var_KerfCheck_H_Minlength)->setValue(iMinLength);
    pAKerf->m_Variants.get_VData(Var_KerfCheck_H_Maxlength)->setValue(iMaxLength);
    pAKerf->m_Variants.get_VData(Var_KerfCheck_H_Direct_x)->setValue(true);

}


void CProcess_HalfCutKerf::do_msg(int iID, QVariantList &vlInput, V_MsgOutput *pvlOutput)
{
    int32_t isize=vlInput.size();
    switch(iID)
    {
    case CALCUKERFPOS:
        if(isize>=3)
        {
            CalcuKerfPos(vlInput[0].toInt(),
                    vlInput[1].toInt());
        }
        break;
    case MOVEKERFPOS:
        if(isize>=0)
        {
            MoveKerfPos();
        }
        break;
    case KERF:
        if(isize>=2)
        {
			if(isize>=3){
				m_bAlignCheck = vlInput[2].toBool();
			}

			Kerf(vlInput[0].toInt(),
				vlInput[1].toInt());
        }
        break;
    case TESTKERF:
        if(isize>=2)
        {
            TestKerf(vlInput[0].toInt());
        }
        break;
	case SETKERFPOSMANUAL:
		if(isize>=2)
		{
			SetKerfPosManual(vlInput[0].toInt(), vlInput[1].toInt());
		}
		break;
    }
    CMProcess::do_msg(iID, vlInput,pvlOutput);
}

void CProcess_HalfCutKerf::Serialize(QDataStream &stream, bool bwrite, int iVersion)
{
	if(false == bwrite){
		int isize=0;
		stream>>isize;
		m_vKerfParam.resize(isize);
		QMutexLocker locker(&m_vKerfParam.mutex);
		for(int i=0;i<isize;i++)
		{
			stream>>m_vKerfParam[i];
		}
		return;

		m_vKerfParam.resize(2);
		KERFPARAM param1;
		param1.iLight1 = 30;
		param1.iLight2 = 250;
		param1.iExposure = 20000;
		param1.iGain = 1;
		param1.iLineCount = 1;
		param1.dOffsetMax = 0.01;
		param1.dOffsetMin = 0.001;
		param1.dRangeMin = 0;
		param1.dRange = 0.2;
		param1.dWidthMin= 0.008;
		param1.dWidthMax = 0.06;
		param1.dGAPMax=0;
		param1.dGAPMin=0;
		param1.iBinaryThres = 35;
		param1.iPixelThres = 145;
		param1.ikerfPos = CENTER_KERF;
		m_vKerfParam[0] = param1;
		m_vKerfParam[1] = param1;


	}else{
		QMutexLocker locker(&m_vKerfParam.mutex);
		int isize=m_vKerfParam.size();
#if 0 //生成序列化文件时使用
        if (isize <= 0) {


            KERFPARAM param;
            //更新参数
            m_vKerfParam.push_back(param);
            m_vKerfParam.push_back(param);
            isize = m_vKerfParam.size();
        }
#endif
		stream<<isize;
		for(int i=0;i<isize;i++)
		{
			stream<<m_vKerfParam[i];
		}
	}
	return;

    int isize=0;
    if(bwrite)
    {
        QMutexLocker locker(&m_vKerfParam.mutex);
        isize=m_vKerfParam.size();
        stream<<isize;
        for(int i=0;i<isize;i++)
        {
            stream<<m_vKerfParam[i];
        }
    }
    else
    {
        stream>>isize;
        m_vKerfParam.resize(isize);
        QMutexLocker locker(&m_vKerfParam.mutex);
        for(int i=0;i<isize;i++)
        {
            stream>>m_vKerfParam[i];
        }

    }
}
void CProcess_HalfCutKerf::ReadRecipe(ConfigStreamReader& streamReader, int iVersion)
{
    CMProcess::ReadRecipe(streamReader, iVersion);
    streamReader.readNextStartElement();
    int iSize = streamReader.attributes().value("value").toInt();
    m_vKerfParam.resize(iSize);
    QMutexLocker locker(&m_vKerfParam.mutex);
    for (int i = 0; i < iSize; i++) {
        streamReader >> m_vKerfParam[i];
    }
    streamReader.skipCurrentElement();
}

void CProcess_HalfCutKerf::WriteRecipe(ConfigStreamWriter& streamWriter, int iVersion)
{
    CMProcess::WriteRecipe(streamWriter, iVersion);
    streamWriter.writeStartElement("halfcut-count");
    int isize = m_vKerfParam.size();
    streamWriter.writeAttribute("value", QString::number(isize));
    for (int i = 0; i < isize; i++) {
        streamWriter << m_vKerfParam[i];
    }
    streamWriter.writeEndElement();
}
KERFPARAM *CProcess_HalfCutKerf::GetKerfParam(int iSideID)
{
	if(iSideID != SIDE_A && iSideID != SIDE_B)
	{
		MQT_THROW_STR(QObject::trUtf8("Get kerf param err. In no side"));
	}

    CProductSide* pSide=GET_CHDIRECT(iSideID,CProductSide);
    Q_ASSERT(pSide);
    
    int iKerfIndex=iSideID==SIDE_A?0:1;
    int iSize=m_vKerfParam.size();
    if (OUTOFRANGE(iKerfIndex,0,iSize))
    {
        MQT_THROW_STR(QObject::trUtf8("Get kerf param err. In no Kerf param"));
    }
    return &m_vKerfParam[iKerfIndex];
}

//找线算法
void CProcess_HalfCutKerf::SearchLine(int iSideID, bool_t bAutoThres)
{
    CCam* pCam=GET_CHDIRECT(m_iKerfCamID,CCam);
    Q_ASSERT(pCam);
    CAKerfCheck_H* pAKerf=(CAKerfCheck_H*)pCam->Find_Algorithm(M_KERF_HALFCUT);
    Q_ASSERT(pAKerf);
    KERFPARAM *pKerfParam=  GetKerfParam(  iSideID);
    int iThreshold=pKerfParam->iPixelThres;
    int iBinaryThres=pKerfParam->iBinaryThres;
    double dResolutionY=pCam->m_CoordTrans.m_dresolution_Y;
    if(DEQUAL0(dResolutionY))
    {
        MQT_THROW_STR(QObject::trUtf8("Kerf process err. "
                                      "Cam resolution equal 0"));
    }
    int iLineNum=pKerfParam->iLineCount;

    pAKerf->showragion(&pCam->m_imageContainer);

    QMutexLocker locker1(&pAKerf->m_lMorphology.mutex);
    int isizemorphology= pAKerf->m_lMorphology.size();
    if(isizemorphology)
    {
        CAMorphology* pMorphology=pAKerf->GetMorphology(CAMorphology::IMG_BINARY);
        if(pMorphology)
        {
            pMorphology->m_Variants.get_VData(Var_Morphology_Thres_ID)->setValue((double)iBinaryThres);

        }
    }
    locker1.unlock();

    CMImage Img;

    CCamDriver* pCamDriver=GET_CARD(CAM_DRIVER,CCamDriver);
    pCamDriver->grab_image(m_iKerfCamID, &Img);
    pAKerf->exe(&Img);
    pAKerf->showresult(&pCam->m_imageContainer);
	
	//pAKerf->showragion_static(&pCam->m_imageContainer);

    VectorResult.clear();
    int isize= pAKerf->lcenters.size();
    for(int i=0;i<isize;i++)
    {
        VectorResult.push_back((int)pAKerf->lcenters[i].tY);
    }

    if(iLineNum==1&&VectorResult.size()==2)
    {
        return;
    }
    if(iLineNum==2&&VectorResult.size()==4)
    {
        return;
    }

    if(bAutoThres)
    {
        int iThresRange=abs(m_Variants.get_VData(Var_Process_Kerf_AutoThresRange_ID)->toInt());
        int iThresMax=min(iThreshold+iThresRange,255);
        int iThresMin=max(iThreshold-iThresRange,0);
        int iStep=max(abs(m_Variants.get_VData(Var_Process_Kerf_AutoThresStep_ID)->toInt()),1);
        for(int i=iThresMax;i>iThresMin;i-=iStep)
        {
            pAKerf->m_Variants.get_VData(Var_KerfCheck_H_Threshold)->setValue(i);

            CCamDriver* pCamDriver=GET_CARD(CAM_DRIVER,CCamDriver);

            pCamDriver->grab_image(m_iKerfCamID, &Img);
            pAKerf->exe(&Img);
            pAKerf->showresult(&pCam->m_imageContainer);
            VectorResult.clear();
            int isize= pAKerf->lcenters.size();
            for(int i=0;i<isize;i++)
            {
                VectorResult.push_back((int)pAKerf->lcenters[i].tY);
            }
            if(iLineNum==1&&VectorResult.size()==2)
            {
                break;
            }
            if(iLineNum==2&&VectorResult.size()==4)
            {
                break;
            }
        }
    }
}

void CProcess_HalfCutKerf::GetKerfResult(double &dRealOffset, double &dRealHeight,
                              double &dRealHeight1, double &dRealGAP)
{
    CCam* pCam=GET_CHDIRECT(m_iKerfCamID,CCam);
    Q_ASSERT(pCam);
    int iwidth,iheight;
    pCam->GetPixelSize(iwidth,iheight);
    double dResolutionY=pCam->m_CoordTrans.m_dresolution_Y;
    if(DEQUAL0(dResolutionY))
    {
        MQT_THROW_STR(QObject::trUtf8("Kerf process err. "
                                      "Cam resolution equal 0"));
    }
    double dPixelHeight=0,dPixelGap=0 ;
    CMPointd Real,Pixel;

    Pixel.tX=iwidth/2.0;
    int iSizeResult=VectorResult.size();
    if (iSizeResult==4)
    {
        Pixel.tY=(VectorResult[3]+VectorResult[2]+VectorResult[1]+VectorResult[0])/4.0;
        dPixelHeight=(VectorResult[1]-VectorResult[0]);
        dRealHeight=fabs(dPixelHeight*dResolutionY);

        dPixelHeight=(VectorResult[3]-VectorResult[2]);
        dRealHeight1=fabs(dPixelHeight*dResolutionY);
        dPixelGap=(VectorResult[3]+VectorResult[2]-VectorResult[1]-VectorResult[0])/2.0;
        dRealGAP=fabs(dPixelGap*dResolutionY);
    }
    else if (iSizeResult==2)
    {
        Pixel.tY=(VectorResult[1]+VectorResult[0])/2.0;
        dPixelHeight=(VectorResult[1]-VectorResult[0]);
        dRealHeight=fabs(dPixelHeight*dResolutionY);	//实际测量 切割道的高度
    }
    else
    {
        Q_ASSERT(0);

    }
    Real=pCam->DPTOLP(Pixel);
#if FILPCAM_XY
    CMPointd ptConveterd(Real.tY, Real.tX);
    ptConveterd.tY = -ptConveterd.tY;

    Real = ptConveterd;
#endif
    dRealOffset=Real.tY;
}

void CProcess_HalfCutKerf::ShowKerfResult(double dRealOffset, double dRealHeight,
                                    double dRealHeight1, double dRealGAP,
                                    CImageContainer* pContainer)
{
    CCam* pCam=GET_CHDIRECT(m_iKerfCamID,CCam);
    Q_ASSERT(pCam);
    int iSizeResult=VectorResult.size();
    double dPixelHeight=0;
    double dResolutionY=pCam->m_CoordTrans.m_dresolution_Y;
	if(m_bAlignCheck){
		pContainer->addString(QObject::trUtf8("Align Check"));
	}
    if (iSizeResult==4)
    {
        pContainer->addString(QObject::trUtf8("Offset:%1mm")
                              .arg(dRealOffset,0,'f',3));
        pContainer->addString(QObject::trUtf8("Bottom Height:%1mm")
                              .arg(dRealHeight,0,'f',3));
        pContainer->addString(QObject::trUtf8("Top Height:%1mm")
                              .arg(dRealHeight1,0,'f',3));
        pContainer->addString(QObject::trUtf8("Gap:%1")
                              .arg(dRealGAP,0,'f',3));

        dPixelHeight=fabs(dRealGAP/dResolutionY);
    }
    else if (iSizeResult==2)
    {
        pContainer->addString(QObject::trUtf8("Offset:%1mm")
                              .arg(dRealOffset,0,'f',4));
        pContainer->addString(QObject::trUtf8("Height:%1mm")
                              .arg(dRealHeight,0,'f',3));
        dPixelHeight=fabs(dRealHeight/dResolutionY);
    }
    else
    {
        Q_ASSERT(0);
    }

    CAKerfCheck_H* pAKerf=(CAKerfCheck_H*)pCam->Find_Algorithm(M_KERF_HALFCUT);
    Q_ASSERT(pAKerf);
    pAKerf->showresult_shape(pContainer);
}


void CProcess_HalfCutKerf::SetKerfLight(int iSideID)
{
    KERFPARAM *pkerf=GetKerfParam(iSideID);
    m_gSystem.SetCamLight(m_iKerfCamID,pkerf->iLight1,true,false);
    m_gSystem.SetCamLight(m_iKerfCamID,pkerf->iLight2,false,false);
    CCamDriver* pCamDriver=GET_CARD(CAM_DRIVER,CCamDriver);
    pCamDriver->set_cam_property(m_iKerfCamID,
                                 Var_Cam_Exposure_ID,
                                 pkerf->iExposure,
                                 false);

    pCamDriver->set_cam_property(m_iKerfCamID,
                                 Var_Cam_Gain_ID,
                                 pkerf->iGain,
                                 false);
}

double CProcess_HalfCutKerf::SetHairLineOffset(int iSideID, int iLineID,
                                      const CMPointd &WPDP, bool bApplyOffset, bool bManualSet/*=false*/)
{
    CProductSide* pSide=GET_CHDIRECT(iSideID,CProductSide);
    Q_ASSERT(pSide);
    double dOffset=m_CheckPos.tY-WPDP.tY;
	//如果太小了则不偏移
    //手动时会出现这种情况
	if(fabs(dOffset) < 0.0008)
	{
		LOG_WARN(fmt::format("Ignore SetHairLineOffset offset:{}", dOffset));
		QString info = QString("Kerf(HALFCUT) Ignore too small CH:%3 Offset:%1mm LineID:%2")
			.arg(dOffset,0,'f',4)
			.arg(iLineID+1)
			.arg(iSideID==SIDE_A?"CH1":"CH2");
		
        if (m_bAlignCheck)
        {
            AddProductData("Align Check" + info, true);
        }
        else
        {
            AddProductData(info, true);
        }
		
		dOffset = 0;
		if(true == bApplyOffset){
			QString str_Offset=QObject::trUtf8("Offset:%1mm LineID:%2")
				.arg(dOffset,0,'f',4)
				.arg(iLineID);
			if(m_bAlignCheck)
				m_gSystem.EvtLog(QString::fromUtf8("HA(ALIGN)"),str_Offset);
			else
				m_gSystem.EvtLog(QString::fromUtf8("HA(HALFCUT)"),str_Offset);
		}
		return dOffset;
	}

	//纠偏阈值
    double dHairOffsetThres = m_Variants.get_VData(Var_Process_Kerf_MaxOffsetThres_ID)->toDouble();
	//double dHairOffsetThres = 0.01;
    if (fabs(dOffset)>dHairOffsetThres)
    {
        MQT_THROW_STR(QObject::trUtf8("Halfcut Kerf err. Hairline Offset: "
                                        "%1>Max Offset:%2 iLineID:%3")
                        .arg(dOffset,0,'f',3)
                        .arg(dHairOffsetThres,0,'f',3)
						.arg(iLineID));
    }

	//TODO:这里要纠偏切割道
	//使用调平纠正切割道
	if(true == bApplyOffset)
	{
		CProductSide* pSide=GET_CHDIRECT(iSideID,CProductSide);
		int iLineSize=pSide->m_CutLineVector.size();
		if(iLineSize<=0)
		{
			LOG_WARN("Not has cut line vector, ignore Halfcut SetHairLineOffset");
			return 0;
		}

		QString info = QString("Kerf(HALFCUT) CH:%3 Offset:%1mm LineID:%2")
			.arg(dOffset,0,'f',4)
			.arg(iLineID+1)
			.arg(iSideID==SIDE_A?"1":"2");
		
        if (m_bAlignCheck)
        {
            AddProductData(info, true);
        }
        else
        {
            AddProductData("Align Check" + info, true);
        }

		CProcess_Level* pLevel=GET_PROCESS(PROCESS_LEVELING,SM_MAIN,CProcess_Level);
		pLevel->SetPtManual(iSideID, m_iKerfCamID, CProcess_Level::TYPE_PTBASE, iLineID, bManualSet);

	}else{
		LOG_WARN(fmt::format("Ignore Halfcut Offset LineID:{} Offset:{}", iLineID+1, dOffset));

		QString info = QString("Kerf(HALFCUT) Ignore CH:%3 Offset:%1mm LineID:%2")
			.arg(dOffset,0,'f',4)
			.arg(iLineID+1)
			.arg(iSideID==SIDE_A?"1":"2");

        if (m_bAlignCheck)
        {
            AddProductData("Align Check " + info, true);
        }
        else
        {
            AddProductData(info, true);
        }
	}

	m_CheckPos=WPDP;
    
	if(bApplyOffset){
		QString str_Offset=QObject::trUtf8("Offset:%1mm,LineID:%2")
			.arg(dOffset,0,'f',4)
			.arg(iLineID);

        if (bManualSet)
        {
            str_Offset += ",Manual";
        }

		if(m_bAlignCheck)
			m_gSystem.EvtLog(QString::fromUtf8("HA(ALIGN)"),str_Offset);
		else
			m_gSystem.EvtLog(QString::fromUtf8("HA(HALFCUT)"),str_Offset);
	}
    return dOffset;
}