BQ_workpieceCornerExtraction ver 1.4.0

博清工件定位纠偏改进。算法上计算轮廓点的前向和后向角,进而计算拐角,识别直角结构,并补缺角。
This commit is contained in:
jerryzeng 2026-03-11 00:42:17 +08:00
parent 1b0df92eaa
commit 098caff171
4 changed files with 243 additions and 222 deletions

View File

@ -42,7 +42,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

View File

@ -42,7 +42,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

View File

@ -42,7 +42,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

View File

@ -773,23 +773,65 @@ void _searchPlusCornerPeaks(
}
}
//判断两个有序点之间是否是一条直线
bool checkIsLine(
SSG_dirCornerAngle& pt1, SSG_dirCornerAngle& pt2,
std::vector<SWD_polarPt>& polarPoints,
double angleTh, double cutLineDeviationTh)
{
int ringBuffSize = (int)polarPoints.size();
//偏离度判断
//计算两点连线
double a, b, c;
int idx1 = pt1.forward_pntIdx; //避开一个尺度
int idx2 = pt2.backward_pntIdx; //避开一个尺度
compute2ptLine_2(
polarPoints[idx1].x, polarPoints[idx1].y,
polarPoints[idx2].x, polarPoints[idx2].y,
&a, &b, &c);
double tmp = sqrt(a * a + b * b);
a = a / tmp;
b = b / tmp;
c = c / tmp;
double maxDist = 0;
int number = idx2 - idx1;
if (number < 0)
number += ringBuffSize;
for (int m = 0; m < number; m++)
{
int idx = (m + idx1) % ringBuffSize;
double dist = abs(a * polarPoints[idx].x + b * polarPoints[idx].y + c);
if (maxDist < dist)
maxDist = dist;
}
if (maxDist < cutLineDeviationTh) //判断为直线
return true;
else
return false;
}
//根据轮廓的角点计算Branch 并判断是否缺角。缺角时通过拟合方式补全
// std::vector<SWD_polarPt>& polarPoints: 点的循环对列
//branchCornerAngle: 支持寻找不同角度的Branch由branchCornerAngle指定。90度为直角。
//angleTh: 角度误差范围。比如名义为90的直角实际加工会有误差。
//cutLineDeviationTh:以截角两点连线,截角上点到直线的最大偏离。保证截角是直线
void _computeBranchesFromCornerPeaks(std::vector<SWD_polarPt>& polarPoints, std::vector< SSG_dirCornerAngle>& cornerPlusPeaks, std::vector<SWD_branchInfo>& branches, double branchCornerAngle, double angleTh, double cutLineDeviationTh)
void _computeBranchesFromCornerPeaks(
std::vector<SWD_polarPt>& polarPoints,
std::vector< SSG_dirCornerAngle>& cornerPlusPeaks,
std::vector<SWD_branchInfo>& branches,
SSX_BQworkpiecePara& workpieceParam,
#if _OUTPUT_DEBUG_DATA
std::vector<SSX_debugInfo>& branchDebugData,
#endif
double branchCornerAngle, double angleTh, double cutLineDeviationTh)
{
int ringBuffSize = (int)polarPoints.size();
//判断是否有缺角
int size_peaks = (int)cornerPlusPeaks.size();
std::vector<int> cutPairFlags;
cutPairFlags.resize(size_peaks);
std::fill(cutPairFlags.begin(), cutPairFlags.end(), 0);
int cutPairID = 1;
for (int i = 0; i < size_peaks; i++)
{
if (cutPairFlags[i] > 0)
if (cornerPlusPeaks[i].pntIdx < 0)
continue;
SSG_dirCornerAngle& corner_1 = cornerPlusPeaks[i];
@ -803,38 +845,182 @@ void _computeBranchesFromCornerPeaks(std::vector<SWD_polarPt>& polarPoints, std:
if (angleDiff < angleTh)
{
//偏离度判断
//计算两点连线
double a, b, c;
compute2ptLine_2(
corner_1.point.x, corner_1.point.y,
corner_2.point.x, corner_2.point.y,
&a, &b, &c);
double tmp = sqrt(a * a + b * b);
a = a / tmp;
b = b / tmp;
c = c / tmp;
//判断两个有序点之间是否是一条直线
bool isLine = checkIsLine( corner_1, corner_2, polarPoints, angleTh, cutLineDeviationTh);
if (true == isLine) //判断为截角
{
//拟合计算交点
//直线1
std::vector<SVzNL3DPoint> linePts_1;
int startIdx = corner_1.backward_pntIdx;
SWD_polarPt startPt = polarPoints[startIdx];
for (int m = 0; m < ringBuffSize; m++)
{
int idx = startIdx - m;
if (idx < 0)
idx += ringBuffSize;
double maxDist = 0;
int number = corner_2.pntIdx - corner_1.pntIdx;
if (number < 0)
number += ringBuffSize;
for (int m = 0; m < number; m++)
{
int idx = (m + corner_1.pntIdx) % ringBuffSize;
double dist = abs(a * polarPoints[idx].x + b * polarPoints[m].y + c);
if (maxDist < dist)
maxDist = dist;
}
if (maxDist < cutLineDeviationTh) //判断为截角
{
cutPairFlags[i] = cutPairID;
cutPairFlags[i+1] = cutPairID;
cutPairID++;
double dist = sqrt(pow(startPt.x - polarPoints[idx].x, 2) + pow(startPt.y - polarPoints[idx].y, 2));
if (dist > workpieceParam.lineLen)
break;
SVzNL3DPoint a_pt = { polarPoints[idx].x , polarPoints[idx].y, polarPoints[idx].z };
linePts_1.push_back(a_pt);
}
double _a1 = 0, _b1 = 0, _c1 = 0;
lineFitting_abc(linePts_1, &_a1, &_b1, &_c1);
//直线2
std::vector<SVzNL3DPoint> linePts_2;
startIdx = corner_2.forward_pntIdx;
startPt = polarPoints[startIdx];
for (int m = 0; m < ringBuffSize; m++)
{
int idx = (startIdx + m) % ringBuffSize;
double dist = sqrt(pow(startPt.x - polarPoints[idx].x, 2) + pow(startPt.y - polarPoints[idx].y, 2));
if (dist > workpieceParam.lineLen)
break;
SVzNL3DPoint a_pt = { polarPoints[idx].x , polarPoints[idx].y, polarPoints[idx].z };
linePts_2.push_back(a_pt);
}
double _a2 = 0, _b2 = 0, _c2 = 0;
lineFitting_abc(linePts_2, &_a2, &_b2, &_c2);
//求交点
SVzNL3DPoint crossPt = computeLineCrossPt_abs(_a1, _b1, _c1, _a2, _b2, _c2);
linePts_1.insert(linePts_1.end(), linePts_2.begin(), linePts_2.end());
crossPt.z = computeMeanZ(linePts_1);
corner_1.point.x = crossPt.x;
corner_1.point.y = crossPt.y;
corner_1.point.z = crossPt.z;
corner_2.pntIdx = -1;
//更新corner
corner_1.corner = sumCorner;
corner_1.forward_pntIdx = corner_2.forward_pntIdx;
}
}
}
//迭代一次对于循环Buff, 需要重新检查首尾结合部
//滤除错误的Corner, 并删除
for (int i = size_peaks-1; i >= 0; i--)
{
SSG_dirCornerAngle& a_corner = cornerPlusPeaks[i];
if (a_corner.pntIdx < 0)
{
cornerPlusPeaks.erase(cornerPlusPeaks.begin() + i);
}
else
{
double angleDiff = abs(a_corner.corner - branchCornerAngle);
if (angleDiff > angleTh)
{
cornerPlusPeaks.erase(cornerPlusPeaks.begin() + i);
}
}
}
//寻找branch: branch的特征相邻之间为直线
size_peaks = (int)cornerPlusPeaks.size();
int branchID = 1;
for (int i = 0; i < size_peaks; i++)
{
if (cornerPlusPeaks[i].pntIdx < 0)
continue;
SSG_dirCornerAngle& corner_1 = cornerPlusPeaks[i];
int tmpIdx = (i + 1) % size_peaks;
SSG_dirCornerAngle& corner_2 = cornerPlusPeaks[tmpIdx];
//判断两个有序点之间是否是一条直线
bool isBranch = checkIsLine(corner_1, corner_2, polarPoints, angleTh, cutLineDeviationTh);
if (true == isBranch) //判断为branch
{
//拟合三条直线
// 直线0两个角点之间的直线
std::vector<SVzNL3DPoint> linePts_0;
int ptSize = corner_2.backward_pntIdx - corner_1.forward_pntIdx;
if (ptSize < 0)
ptSize += ringBuffSize;
for (int m = 0; m <= ptSize; m++)
{
int idx = (corner_1.forward_pntIdx + m) % ringBuffSize;
SVzNL3DPoint a_pt = { polarPoints[idx].x , polarPoints[idx].y, polarPoints[idx].z };
linePts_0.push_back(a_pt);
}
double _a0 = 0, _b0 = 0, _c0 = 0;
lineFitting_abc(linePts_0, &_a0, &_b0, &_c0);
//直线1
std::vector<SVzNL3DPoint> linePts_1;
int startIdx = corner_1.backward_pntIdx;
SWD_polarPt startPt = polarPoints[startIdx];
for (int m = 0; m < ringBuffSize; m++)
{
int idx = startIdx - m;
if (idx < 0)
idx += ringBuffSize;
double dist = sqrt(pow(startPt.x - polarPoints[idx].x, 2) + pow(startPt.y - polarPoints[idx].y, 2));
if (dist > workpieceParam.lineLen)
break;
SVzNL3DPoint a_pt = { polarPoints[idx].x , polarPoints[idx].y, polarPoints[idx].z };
linePts_1.push_back(a_pt);
}
double _a1 = 0, _b1 = 0, _c1 = 0;
lineFitting_abc(linePts_1, &_a1, &_b1, &_c1);
//直线2
std::vector<SVzNL3DPoint> linePts_2;
startIdx = corner_2.forward_pntIdx;
startPt = polarPoints[startIdx];
for (int m = 0; m < ringBuffSize; m++)
{
int idx = (startIdx + m) % ringBuffSize;
double dist = sqrt(pow(startPt.x - polarPoints[idx].x, 2) + pow(startPt.y - polarPoints[idx].y, 2));
if (dist > workpieceParam.lineLen)
break;
SVzNL3DPoint a_pt = { polarPoints[idx].x , polarPoints[idx].y, polarPoints[idx].z };
linePts_2.push_back(a_pt);
}
double _a2 = 0, _b2 = 0, _c2 = 0;
lineFitting_abc(linePts_2, &_a2, &_b2, &_c2);
#if _OUTPUT_DEBUG_DATA
SSX_debugInfo a_branchDebug;
a_branchDebug.rgnIdx = branchID++;
a_branchDebug.edge_size = (int)linePts_0.size();
a_branchDebug.edgeLink1_size = (int)linePts_1.size();
a_branchDebug.edgeLink2_size = (int)linePts_2.size();
a_branchDebug.edge = (SVzNL3DPoint*)malloc(sizeof(SVzNL3DPoint) * a_branchDebug.edge_size);
a_branchDebug.edgeLink_1 = (SVzNL3DPoint*)malloc(sizeof(SVzNL3DPoint) * a_branchDebug.edgeLink1_size);
a_branchDebug.edgeLink_2 = (SVzNL3DPoint*)malloc(sizeof(SVzNL3DPoint) * a_branchDebug.edgeLink2_size);
for (int m = 0; m < a_branchDebug.edge_size; m++)
a_branchDebug.edge[m] = linePts_0[m];
for (int m = 0; m < a_branchDebug.edgeLink1_size; m++)
a_branchDebug.edgeLink_1[m] = linePts_1[m];
for (int m = 0; m < a_branchDebug.edgeLink2_size; m++)
a_branchDebug.edgeLink_2[m] = linePts_2[m];
branchDebugData.push_back(a_branchDebug);
#endif
linePts_1.insert(linePts_1.end(), linePts_0.begin(), linePts_0.end());
linePts_2.insert(linePts_2.end(), linePts_0.begin(), linePts_0.end());
//计算branch信息
SWD_branchInfo a_branchInfo;
a_branchInfo.corner[0] = computeLineCrossPt_abs(_a0, _b0, _c0, _a1, _b1, _c1);
a_branchInfo.corner[0].z = computeMeanZ(linePts_1);
a_branchInfo.corner[2] = computeLineCrossPt_abs(_a0, _b0, _c0, _a2, _b2, _c2);
a_branchInfo.corner[2].z = computeMeanZ(linePts_2);
a_branchInfo.corner[1].x = (a_branchInfo.corner[0].x + a_branchInfo.corner[2].x) / 2;
a_branchInfo.corner[1].y = (a_branchInfo.corner[0].y + a_branchInfo.corner[2].y) / 2;
a_branchInfo.corner[1].z = computeMeanZ(linePts_0);
//
a_branchInfo.angle = corner_1.point.angle;
a_branchInfo.line_a = _b0;
a_branchInfo.line_b = -_a0;
a_branchInfo.line_c = -(a_branchInfo.line_a * a_branchInfo.corner[1].x + a_branchInfo.line_b * a_branchInfo.corner[1].y);
branches.push_back(a_branchInfo);
corner_1.pntIdx = -1;
corner_2.pntIdx = -1;
}
}
}
SSX_BQworkpieceResult sx_BQ_getWorkpieceCorners(
@ -1135,8 +1321,19 @@ SSX_BQworkpieceResult sx_BQ_getWorkpieceCorners(
std::vector< SSG_dirCornerAngle> cornerPlusPeaks;
_searchPlusCornerPeaks(dirCornerAngles, cornerPlusPeaks);
//使用R过滤判断是否缺角
double branchCornerAngle = 90;
double angleTh = 10;
double cutLineDeviationTh = 5.0;
std::vector<SWD_branchInfo> branches;
_computeBranchesFromCornerPeaks(cornerPlusPeaks, branches);
_computeBranchesFromCornerPeaks(
polarPoints,
cornerPlusPeaks,
branches,
workpieceParam,
#if _OUTPUT_DEBUG_DATA
debug_contours,
#endif
branchCornerAngle, angleTh, cutLineDeviationTh);
//提取R极值点
double minR = -1, maxR = -1; //计算最小和最大的R用以区分有没有分支。minR和maxR相差小时为圆形或8角形没有分支
@ -1174,9 +1371,6 @@ SSX_BQworkpieceResult sx_BQ_getWorkpieceCorners(
polarRPeakPts.push_back(polarPoints[pi]);
}
double ratio_MaxMin = maxR / minR;
bool hasBranch = ratio_MaxMin < 1.25 ? false : true;
std::vector<SWD_polarPt> validPolarRPeakPts;
std::vector<SWD_polarPeakInfo> polarPeakInfo;
int pkId = 0;
@ -1251,192 +1445,19 @@ SSX_BQworkpieceResult sx_BQ_getWorkpieceCorners(
int workpieceType = -1;
bool partialScan = false; //当相机视野不能覆盖工件全部时partialScan为true
std::vector< SWD_branchInfo> branchInfo;
if (true == hasBranch)
if (branches.size() > 0) //有分支branch)
{
//计算分支90度范围内为同一分支。根据分支数量确定工件类型
int pkSize = (int)validPolarRPeakPts.size();
for (int m = 0; m < pkSize; m++)
{
if (validPolarRPeakPts[m].cptIndex < 0)
continue;
//if (polarPeakInfo[m].cornerDir == 2) //逆时针。
{
int nxtIdx = (m + 1)%pkSize;
bool isSameBranch = checkSameBranch(validPolarRPeakPts[m], validPolarRPeakPts[nxtIdx],
polarPoints, center_x, center_y);
double angleDiff = computeAngleDiff(validPolarRPeakPts[nxtIdx].angle, validPolarRPeakPts[m].angle);
if (angleDiff < 0)
angleDiff += 360;
if ( (angleDiff < 90) && (true == isSameBranch)) //为同一branch合并只保留一个
{
validPolarRPeakPts[nxtIdx].pkId = validPolarRPeakPts[m].pkId; //pair
validPolarRPeakPts[nxtIdx].cptIndex = -1;
}
}
}
std::vector<std::vector<SWD_polarPt>> branchPeaks; //每个branch最多两个极值点
branchPeaks.resize(pkId);
std::vector<std::vector<SWD_polarPeakInfo>> branchPeakInfo;
branchPeakInfo.resize(pkId);
for (int m = 0; m < pkSize; m++)
{
if (validPolarRPeakPts[m].cptIndex < 0)
validPolarRPeakPts[m].cptIndex = polarPeakInfo[m].cptIndex; //恢复
int pkId = validPolarRPeakPts[m].pkId;
branchPeaks[pkId].push_back(validPolarRPeakPts[m]);
branchPeakInfo[pkId].push_back(polarPeakInfo[m]);
}
for (int m = pkSize - 1; m >= 0; m--)
{
if (branchPeaks[m].size() == 0)
{
branchPeaks.erase(branchPeaks.begin() + m);
branchPeakInfo.erase(branchPeakInfo.begin() + m);
}
}
int branchNum = (int)branchPeaks.size();
int branchNum = (int)branches.size();
if (branchNum == 2)
{
workpieceType = 3; //节点3
SVzNL3DPoint pt1 = { polarPoints[minRPos].x, polarPoints[minRPos].y, 0 };
SVzNL3DPoint pt2 = { center_x, center_y, 0 };
double aux_a, aux_b, aux_c;
compute2ptLine(pt1, pt2, &aux_a, &aux_b, &aux_c);
double counterAngle = polarPoints[minRPos].angle + 180;
if (counterAngle > 360)
counterAngle = counterAngle - 360;
SVzNL3DPoint a_cross = computeEdgeCross(counterAngle, polarPoints, aux_a, aux_b, aux_c);
double refine_cx = (pt1.x + a_cross.x) / 2;
double refine_cy = (pt1.y + a_cross.y) / 2;
//确定cornerDir
for (int m = 0; m < branchNum; m++)
{
for (int n = 0; n < branchPeaks[m].size(); n++)
{
int cptIdx = branchPeakInfo[m][n].cptIndex;
int LL1 = branchPeakInfo[m][n].L1_ptIndex;
int LL2 = branchPeakInfo[m][n].L2_ptIndex;
double angle = atan2(polarPoints[cptIdx].y - refine_cy, polarPoints[cptIdx].x - refine_cx);
angle = (angle / PI) * 180 + 180.0;
double LL1_angle = atan2(polarPoints[LL1].y - refine_cy, polarPoints[LL1].x - refine_cx);
LL1_angle = (LL1_angle / PI) * 180 + 180.0;
double LL2_angle = atan2(polarPoints[LL2].y - refine_cy, polarPoints[LL2].x - refine_cx);
LL2_angle = (LL2_angle / PI) * 180 + 180.0;
double L1_angle = computeAngleDiff(angle, LL1_angle);
double L2_angle = computeAngleDiff(LL2_angle, angle);
if (L1_angle < L2_angle)
branchPeakInfo[m][n].cornerDir = 2; //逆时针
else
branchPeakInfo[m][n].cornerDir = 1; //顺时针
}
}
}
else if ((branchNum == 3) || (branchNum == 4))
{
if (branchNum == 3)
{
partialScan = true;
workpieceType = 2; //节点2
}
else
workpieceType = 1; //节点1
//确定cornerDir
for (int m = 0; m < branchNum; m++)
{
for(int n = 0; n < branchPeaks[m].size(); n++)
{
int cptIdx = branchPeakInfo[m][n].cptIndex;
int LL1 = branchPeakInfo[m][n].L1_ptIndex;
int LL2 = branchPeakInfo[m][n].L2_ptIndex;
double L1_angle = polarPoints[cptIdx].angle - polarPoints[LL1].angle;
if (L1_angle < 0)
L1_angle += 360;
double L2_angle = polarPoints[LL2].angle - polarPoints[cptIdx].angle;
if (L2_angle < 0)
L2_angle += 360;
if (L1_angle < L2_angle)
branchPeakInfo[m][n].cornerDir = 2; //逆时针
else
branchPeakInfo[m][n].cornerDir = 1; //顺时针
}
}
}
else if (branchNum == 3)
workpieceType = 2; //节点2
else if (branchNum == 4)
workpieceType = 1; //节点1
else
workpieceType = 0;
//计算各个branch的信息
for (int branchIdx = 0; branchIdx < branchNum; branchIdx++)
{
std::vector<SWD_polarPt>& a_branch = branchPeaks[branchIdx];
std::vector<SWD_polarPeakInfo>& a_branchInfo = branchPeakInfo[branchIdx];
//取固定长度垂直边
SWD_polarPt branchCorner;
SWD_polarPeakInfo branchCornerInfo;
if (a_branch.size() == 2) //取角度最接近90度的
{
double diff1 = abs(a_branchInfo[0].cornerAngle - 90);
double diff2 = abs(a_branchInfo[1].cornerAngle - 90);
branchCorner = diff1 < diff2 ? a_branch[0]: a_branch[1];
branchCornerInfo = diff1 < diff2 ? a_branchInfo[0] : a_branchInfo[1];
}
else
{
branchCorner = a_branch[0];
branchCornerInfo = a_branchInfo[0];
}
SWD_branchInfo resultBranchInfo;
std::vector<SVzNL3DPoint> branchLinePts; //用于显示和debug
std::vector< SVzNL3DPoint> branchEdgePt1;
std::vector< SVzNL3DPoint> branchEdgePt2;
int opOK = _getBranchInfo(
validStartLine, //开始扫描边界
validEndLine, //结束扫描边界
partialScan, //当相机视野不能覆盖工件全部时partialScan为true,
polarPoints,
branchCorner,
branchCornerInfo,
&resultBranchInfo,
branchLinePts,
branchEdgePt1,
branchEdgePt2);
if(opOK < 0)
{
*errCode = SX_ERR_ZERO_CONTOUR_PT;
return workpieceCorners;
}
branchInfo.push_back(resultBranchInfo);
#if _OUTPUT_DEBUG_DATA
SSX_debugInfo a_branchDebug;
a_branchDebug.rgnIdx = (int)branchInfo.size();
a_branchDebug.edge_size = (int)branchEdgePt1.size();
a_branchDebug.edgeLink1_size = (int)branchLinePts.size();
a_branchDebug.edgeLink2_size = (int)branchEdgePt2.size();
a_branchDebug.edge = (SVzNL3DPoint*)malloc(sizeof(SVzNL3DPoint) * a_branchDebug.edge_size);
a_branchDebug.edgeLink_1 = (SVzNL3DPoint*)malloc(sizeof(SVzNL3DPoint) * a_branchDebug.edgeLink1_size);
a_branchDebug.edgeLink_2 = (SVzNL3DPoint*)malloc(sizeof(SVzNL3DPoint) * a_branchDebug.edgeLink2_size);
for(int m = 0; m < a_branchDebug.edge_size; m ++)
a_branchDebug.edge[m] = branchEdgePt1[m];
for (int m = 0; m < a_branchDebug.edgeLink1_size; m++)
a_branchDebug.edgeLink_1[m] = branchLinePts[m];
for (int m = 0; m < a_branchDebug.edgeLink2_size; m++)
a_branchDebug.edgeLink_2[m] = branchEdgePt2[m];
debug_contours.push_back(a_branchDebug);
#endif
}
branchInfo.insert(branchInfo.end(), branches.begin(), branches.end());
workpieceCorners.workpieceType = workpieceType;
if (workpieceType == 1) //4个branch
{