// 检查深孔特征
BOOL CSDMdlMachDeepHoleCheck::CheckDeepHole(ProFeature *pFeature, DeepHoleFeaVisitData* pDeepHolepara)
{
	ProError status;
	status = ProFeatureGeomitemVisit(pFeature,PRO_SURFACE,
		DeepHoleGeomitemVisitAction,
		NULL,pDeepHolepara);

	return TRUE;
}
// 单侧放量
void OnOffsetSingleActFn()
{
	/*if (!QuickCheckValidLicense(SMART_PROFESSIONAL))
		return;*/

	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	DestroyAllDialog();
	CancelSelectDialog();
	Sleep(50);

	ProMdl pMdl = GetCurrentMdl();
	if (pMdl == NULL)
	{
		MessageBox(NULL, L"当前环境未发现模型!", L"提示", MB_OK|MB_ICONWARNING);
		return;
	}

	// 选择面
	vector<ProSelection> arrSelQlt;
	ShowMessageTip(L"Tips.选择要偏移的面...");
	if (SelectObject(arrSelQlt, "surface"))
	{
		// 输入偏离值
		double dOffset;
		ShowMessageTip(L"输入偏移量,不能为0,但可以为负值:");
		if (ProMessageDoubleRead(NULL, &dOffset) == PRO_TK_NO_ERROR)
		{
			// 判断面的方向
			ProModelitem itemSurf;
			ProSelectionModelitemGet(arrSelQlt[0], &itemSurf);
			ProSurface surf;
			ProGeomitemToSurface(&itemSurf, &surf);
			ProGeomitemdata* psrfdata;
			ProSurfaceDataGet(surf, &psrfdata);
			if (psrfdata->data.p_surface_data->orient == PRO_SURF_ORIENT_IN)
				dOffset = dOffset*(-1);
			ProGeomitemdataFree(&psrfdata);
			// 创建偏移特征
			int nOffsetID = OffsetSurfaceWithSide(pMdl, arrSelQlt[0], dOffset);
			if (nOffsetID > 0)
			{
				// 修改面颜色
				ProFeature feat;
				feat.id = nOffsetID;
				feat.type = PRO_FEATURE;
				feat.owner = pMdl;
				vector<ProModelitem> arrQuilts;
				ProFeatureGeomitemVisit(&feat, PRO_QUILT, FeatureGeomsGetAction, NULL, &arrQuilts);
				for (int i=0; i<arrQuilts.size(); i++)
					SetSurfColor(arrQuilts[i], 255, 215, 0);
			}
		}
	}
	InvalidateDrawing();
	ProMessageClear();
}
/**
For different feature types different geometries are appropriate:
DTM_PLN : PRO_TYPE_SURFACE
DTM_AXIS : PRO_TYPE_AXIS

Rather than ProModelitemByNameInit() maybe one of the following would be a better choice:
ProGeomitemFeatureGet();
ProGeomitemToSurface();
ProSurfaceDataGet();
ProFeatureSelectionGet();
ProFeatureGeomitemVisit();  // *I think this is the correct approach*
ProSurfaceDataGet();
*/
Selector::Selector( ProMdl in_model, ProFeature in_feature, ProType in_geom_type )
	: m_log_f(log4cpp::Category::getInstance(LOGCAT_LOGFILEONLY)),
	  m_log_cf(log4cpp::Category::getInstance(LOGCAT_CONSOLEANDLOGFILE))
{
	ProError status;
	ProModelitem model_item;
	if (in_geom_type == PRO_TYPE_UNUSED) {
		model_item = static_cast<ProModelitem>(in_feature);
	} else {
		ProAppData select_geom_data = static_cast<ProAppData>(&model_item);
		switch( status = ProFeatureGeomitemVisit(&in_feature, in_geom_type, 
			select_geom_action, NULL, select_geom_data) ) 
		{
		case PRO_TK_NO_ERROR: break;
		case PRO_TK_BAD_INPUTS:
			m_log_cf.warnStream() << "one or more arguments was invalid.";
			break;
		default:
			m_log_cf.warnStream() 
				<< "the action function returned a value other than PRO_TK_NO_ERROR and visiting stopped. " 
				<< status;
		}
	}
	m_log_cf.infoStream() << "model selected: "
		<< " id = " << model_item.id << " type = " << model_item.type;

    switch( status = ProSelectionAlloc(NULL, &model_item, &m_self) ) {
	case PRO_TK_NO_ERROR: break;
    case PRO_TK_BAD_INPUTS:
		m_log_cf.errorStream() << "the allocation failed due to bad inputs.";
		m_log_cf.errorStream() << " component-path: NULL " 
		          << " model-item: " << model_item.id;
		throw std::runtime_error("selector allocation failed");
	default: 
		m_log_cf.errorStream() << "could not allocate selection: " << status;
		throw std::runtime_error("selector allocation failed");
	}
}
ProError CSDMdlMachFeaMinSizeCheck::GeoFeaVisitAction(ProFeature *pFeature, ProError status, ProAppData data)
{
	FeaMinSizeVisitData& VisitData = *(FeaMinSizeVisitData*)data;
	double dProp = VisitData.dMinSizeRatio;

	ProSolid CheckedSolid;
	status = ProFeatureSolidGet(pFeature, &CheckedSolid);

	double dMdlMaxSize;
	GetSolidMaxSize(CheckedSolid, dMdlMaxSize);

	vector<vector<double>>arrValues;

	status = ProFeatureGeomitemVisit(pFeature,PRO_SURFACE,
		FeaMinSizeGeomitemVisitAction,
		NULL,&arrValues);

	int nPointCount = (int)arrValues.size();

	vector<double>arrDimValuesL;
	vector<double>arrDimValuesW;
	vector<double>arrDimValuesH;

	if (nPointCount == 0)
	{
		return PRO_TK_NO_ERROR;
	}

	for (int i = 0; i < nPointCount; i++)
	{
		arrDimValuesL.push_back(arrValues[i][0]);
		arrDimValuesW.push_back(arrValues[i][1]);
		arrDimValuesH.push_back(arrValues[i][2]);
	}

	double BoundValueL[2];
	double BoundValueW[2];
	double BoundValueH[2];
	GetMaxMinValues(arrDimValuesL, BoundValueL);
	GetMaxMinValues(arrDimValuesW, BoundValueW);
	GetMaxMinValues(arrDimValuesH, BoundValueH);
	
	vector<double>arrDimValues;
	arrDimValues.push_back(BoundValueL[0] - BoundValueL[1]);
	arrDimValues.push_back(BoundValueW[0] - BoundValueW[1]);
	arrDimValues.push_back(BoundValueH[0] - BoundValueH[1]);

	if ((arrDimValues[0]/dMdlMaxSize) < dProp && (arrDimValues[1]/dMdlMaxSize) < dProp && 
		(arrDimValues[2]/dMdlMaxSize) < dProp)
	{
		VisitData.nFeaMinSizeResultType = CHECK_RESULT_INVALID_VALUE;

		int nErrorSize = (int)VisitData.arrFeaMinSizeErrorIDs.GetSize();

		if (0 != nErrorSize)
		{
			for (int k=0; k<nErrorSize; k++)
			{
				if (VisitData.arrFeaMinSizeErrorIDs[k] == (*pFeature).id)
				return PRO_TK_NO_ERROR;
			}
		}
		VisitData.arrFeaMinSizeErrorIDs.Add((*pFeature).id);
	}
	return PRO_TK_NO_ERROR;
}
// 草绘裁剪
void OnTrimBySketchActFn()
{
	/*if (!QuickCheckValidLicense(SMART_PROFESSIONAL))
		return;*/

	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	DestroyAllDialog();
	CancelSelectDialog();
	Sleep(50);

	ProError status;
	ProMdl pMdl = GetCurrentMdl();
	if (pMdl == NULL)
	{
		MessageBox(NULL, L"当前环境未发现模型!", L"提示", MB_OK|MB_ICONWARNING);
		return;
	}
	
	// 选择草绘
	vector<ProSelection> arrSel;
	ShowMessageTip(L"Tips.选择草绘特征...");
	while (SelectObject(arrSel, "feature"))
	{
		// 检查是否为草绘曲线
		ProFeature featSketch;
		status = ProSelectionModelitemGet(arrSel[0], &featSketch);
		ProFeattype featType;
		status = ProFeatureTypeGet(&featSketch, &featType);
		if (featType == PRO_FEAT_CURVE)
		{
			ProAsmcomppath acomppath;
			ProSelectionAsmcomppathGet(arrSel[0], &acomppath);

			ProSelection selQuilt;	// 待裁剪的平面
			BOOL bGetQuilt = FALSE;

			// 获取草绘曲线所在的平面
			ProElement elemTreeCurve = NULL;
			ProFeatureElemtreeExtract(&featSketch, NULL, PRO_FEAT_EXTRACT_NO_OPTS, &elemTreeCurve);
			ProElempathItem pathItemType[1];
			pathItemType[0].type = PRO_ELEM_PATH_ITEM_TYPE_ID;
			pathItemType[0].path_item.elem_id = PRO_E_CURVE_TYPE;
			ProElempath elemPathCurveType;
			ProElempathAlloc(&elemPathCurveType);
			ProElempathDataSet(elemPathCurveType, pathItemType, 1);
			ProElement elemType;
			status = ProElemtreeElementGet(elemTreeCurve, elemPathCurveType, &elemType);
			if (status == PRO_TK_NO_ERROR)
			{
				ProValue valType;
				status = ProElementValueGet(elemType, &valType);
				ProValueData valdataType;
				status = ProValueDataGet(valType, &valdataType);
				if (valdataType.v.i == PRO_CURVE_TYPE_SKETCHED)
				{
					// 确定为草绘曲线,进而获取草绘平面
					ProElempathItem pathItemSketchPlane[3];
					pathItemSketchPlane[0].type = PRO_ELEM_PATH_ITEM_TYPE_ID;
					pathItemSketchPlane[0].path_item.elem_id = PRO_E_STD_SECTION;
					pathItemSketchPlane[1].type = PRO_ELEM_PATH_ITEM_TYPE_ID;
					pathItemSketchPlane[1].path_item.elem_id = PRO_E_STD_SEC_SETUP_PLANE;
					pathItemSketchPlane[2].type = PRO_ELEM_PATH_ITEM_TYPE_ID;
					pathItemSketchPlane[2].path_item.elem_id = PRO_E_STD_SEC_PLANE;
					ProElempath elemPathPlane;
					ProElempathAlloc(&elemPathPlane);
					ProElempathDataSet(elemPathPlane, pathItemSketchPlane, 3);
					ProElement elemPlane;
					status = ProElemtreeElementGet(elemTreeCurve, elemPathPlane, &elemPlane);
					if (status == PRO_TK_NO_ERROR)
					{
						ProValue valPlane;
						status = ProElementValueGet(elemPlane, &valPlane);
						ProValueData valdataPlane;
						status = ProValueDataGet(valPlane, &valdataPlane);
						ProGeomitem itemSurf;
						ProSelectionModelitemGet(valdataPlane.v.r, &itemSurf);
						ProSurface surf;
						ProGeomitemToSurface(&itemSurf, &surf);

						// 获取面所在面组
						ProQuilt quilt;
						status = ProSurfaceQuiltGet(ProMdlToSolid(pMdl), surf, &quilt);
						if (status == PRO_TK_NO_ERROR)
						{
							ProGeomitem itemQuilt;
							status = ProQuiltToGeomitem(ProMdlToSolid(pMdl), quilt, &itemQuilt);
							status = ProSelectionAlloc(&acomppath, &itemQuilt, &selQuilt);
							bGetQuilt = TRUE;
						}
					}
				}
			}
			
			if (!bGetQuilt)
			{
				ShowMessageTip(L"Tips.草绘的放置面非可裁剪面,请手动选择需裁剪的面...");
				// 手动选取待裁剪的面
				vector<ProSelection> arrSelSrf;
				if (SelectObject(arrSelSrf, "dtmqlt"))
				{
					ProSelectionCopy(arrSelSrf[0], &selQuilt);
				}
				else
				{
					break;
				}
			}
	
			// 遍历特征,获取特征中的全部复合曲线
			vector<ProGeomitem> arrItemCurves;
			status = ProFeatureGeomitemVisit(&featSketch, PRO_CURVE, FeatureGeomsGetAction, NULL, &arrItemCurves);
			vector<int> arrFeatID;
			for (int i=0; i<arrItemCurves.size(); i++)
			{
				ProCurve curve;
				status = ProGeomitemToCurve(&arrItemCurves[i], &curve);
				// 检查是否为复合曲线
				ProEnttype curveType;
				status = ProCurveTypeGet(curve, &curveType);
				if (curveType == PRO_ENT_CMP_CRV)
				{
					// 进行裁剪
					ProSelection selCurve;
					status = ProSelectionAlloc(&acomppath, &arrItemCurves[i], &selCurve);
					int nFeatID = TrimQuiltByCurve(pMdl, selQuilt, selCurve, PRO_EDGE_SAME_DIRECTION);
					if (nFeatID > 0)
					{
						// 创建成功,记录特征ID
						arrFeatID.push_back(nFeatID);

						// 第8步:提示是否反向或继续修剪
						CDlgConfirm dlg;
						while (1)
						{
							int nResult = (int)dlg.DoModal();
							if (nResult == IDOK)
							{
								break;
							}
							else if (nResult == IDRETRY) 
							{
								// 修改裁剪方向
								ProFeature feat;
								feat.id = nFeatID;
								feat.type = PRO_FEATURE;
								feat.owner = pMdl;
								ReverseTrimDirection(feat);
							}
							else
							{
								InvalidateDrawing();
								ProMessageClear();
								return;
							}
						}
					}
				}
			}
			// 合并成组
			CreateFeatGroup(pMdl, arrFeatID, L"包覆面_裁剪");
			break;
		}
		else
		{
			// 
			MessageBox(NULL, L"所选特征非草绘特征,请重新选择!", L"提示", MB_OK);
		}
	}

	InvalidateDrawing();
	ProMessageClear();
}
ProError CSDMdlMachFlatBottomHoleCheck::HoleFeaVisitAction(ProFeature *pFeature, ProError status, ProAppData data)
{
	data;
	int nSurfCheckResult = -1;

	status = ProFeatureGeomitemVisit(pFeature,PRO_SURFACE,
		SurfGeomitemVisitAction,
		NULL,&nSurfCheckResult);

	if (nSurfCheckResult == CHECK_RESULT_NO_ERROR)
	{
		return PRO_TK_NO_ERROR;
	}

	CArray<ProSurface>arrSurf;
	ProSurface HolePrimSurf;
	GetHolePrimSurf(pFeature, HolePrimSurf);
	arrSurf.Add(HolePrimSurf);
	
	status = ProFeatureGeomitemVisit(pFeature,PRO_SURFACE,
		HoleGeomitemVisitAction,
		NULL,&arrSurf);					//获得特征的柱面和平面

	int nSurfNum = (int)arrSurf.GetSize();

	if (nSurfNum == 1)
	{
		return PRO_TK_NO_ERROR;
	}

	ProSrftype SurfType;
	ProSurface CylSurf;
	for (int i = 1; i < nSurfNum; i++)
	{
		status = ProSurfaceTypeGet(arrSurf.GetAt(i), &SurfType);
		if(SurfType == PRO_SRF_CYL)
		{
			CylSurf = arrSurf.GetAt(i);
			break;
		}
	}

	CArray<ProSurface>arrVisit;
	arrVisit.Add(HolePrimSurf);
	arrVisit.Add(CylSurf);

	status = ProSurfaceContourVisit(CylSurf, SurfContourVisitAction, NULL, &arrVisit);	//获得孔底环非柱面的邻面arrVisit.GetAt(2)

	if (arrVisit.GetSize() != 3)
	{
		return PRO_TK_NO_ERROR;
	}

	status = ProSurfaceTypeGet(arrVisit.GetAt(2), &SurfType);

	if (SurfType != PRO_SRF_PLANE)
	{
		return PRO_TK_NO_ERROR;
	}

	double dPlanAxis[3];
	GetPlaneSurfAxis(arrVisit.GetAt(2), dPlanAxis);

	ProSurface HoleCylSurf;
	ProVector dHoleAxis;
	Pro3dPnt origin;
	double dRadius;
	GetHoleCylSurf(pFeature, HoleCylSurf, dHoleAxis, origin, dRadius);

 	double Values[3];

 	Values[0] = dPlanAxis[1]*dHoleAxis[2] - dPlanAxis[2]*dHoleAxis[1];
 	Values[1] = dPlanAxis[2]*dHoleAxis[0] - dPlanAxis[0]*dHoleAxis[2];
 	Values[2] = dPlanAxis[0]*dHoleAxis[1] - dPlanAxis[1]*dHoleAxis[0];
 	if (DEQUAL(Values[0], 0.0) && DEQUAL(Values[1], 0.0) && DEQUAL(Values[2], 0.0))
 	{
 		m_FlatBottomHoleVisitData.nFlatBottomHoleResultType = CHECK_RESULT_INVALID_VALUE;
 	}
 
 	if (m_FlatBottomHoleVisitData.nFlatBottomHoleResultType == CHECK_RESULT_INVALID_VALUE)
 	{
 		int arrHoleCutDirPrepUpErrorSize = (int)m_FlatBottomHoleVisitData.arrFlatBottomHoleErrorIDs.GetSize();
 		if (0 != arrHoleCutDirPrepUpErrorSize)
 		{
 			for (int k=0; k<arrHoleCutDirPrepUpErrorSize; k++)
 			{
 				if (m_FlatBottomHoleVisitData.arrFlatBottomHoleErrorIDs[k] == (*pFeature).id)
 					return PRO_TK_NO_ERROR;
 			}
 		}
 		m_FlatBottomHoleVisitData.arrFlatBottomHoleErrorIDs.Add((*pFeature).id);
 	}
	return PRO_TK_NO_ERROR;
}