int CMeshCutting::GetFacetsWithBorderEdge(KW_Mesh& Mesh,vector<Facet_handle>& fhWithBorderEdge,
											vector<Facet_handle> ExemptionTri)
{
	for (Facet_iterator FIter=Mesh.facets_begin();FIter!=Mesh.facets_end();FIter++)
	{
		Halfedge_around_facet_circulator Hafc=FIter->facet_begin();
		do 
		{
			if (Hafc->is_border_edge())
			{
				vector<Facet_handle>::iterator FhIter=find(ExemptionTri.begin(),ExemptionTri.end(),FIter);
				if (FhIter==ExemptionTri.end())
				{
					fhWithBorderEdge.push_back(FIter);
				}
				break;
			}
			else
			{
				Hafc++;
			}
		} while(Hafc!=FIter->facet_begin());
	}
	int iResult=fhWithBorderEdge.size();
	return iResult;
}
void KW_CS2Surf::SJStretchCylin(KW_Mesh& InOutCylin,Point_3 NewFaceCenter)
{
    //don't fotget to judge if the stretched cylinder intersects with the subspace
    //omit it temporarily




    //shrink to the original face point gradually if intersects with subspace






    Vector_3 VectToMove=NewFaceCenter-InOutCylin.GetExtruCenter();
    for (Vertex_iterator VerIter=InOutCylin.vertices_begin(); VerIter!=InOutCylin.vertices_end(); VerIter++)
    {
        if (VerIter->GetReserved()==1)//the extruded vertices
        {
            VerIter->point()=VerIter->point()+VectToMove;
        }
    }
    //don't fotget to update extruded center
    InOutCylin.SetExtruCenter(NewFaceCenter);
    OBJHandle::UnitizeCGALPolyhedron(InOutCylin,false,false);
}
//sketch to join the originally irrelevant components (cylinders)
bool KW_CS2Surf::SketchJoin(vector<CPoint> UserScrPoint,GLdouble* modelview,GLdouble* projection,GLint* viewport)
{
    //get the cylinders selected
    vector<int> vecSelCylin;
    int iSSId=-1;
    Point_3 DstPoint;
    bool bResult=SJGetSelCylin(UserScrPoint,modelview,projection,viewport,vecSelCylin,iSSId,DstPoint);
    if (!bResult)
    {
        return false;
    }
    //stretch the first selected cylinder
    SJStretchCylin(this->vecSinglePoly.at(vecSelCylin.front()),DstPoint);
    //collect the cylinders in this subspace
    vector<KW_Mesh> vecCurrCylin;
    for (unsigned int i=0; i<this->vecSinglePoly.size(); i++)
    {
        if (vecSinglePoly.at(i).GetReserved()==iSSId)
        {
            vecCurrCylin.push_back(vecSinglePoly.at(i));
        }
    }
    //compute the union
    KW_Mesh ResultPolyh;
    ComputeUnionInSubspace(vecCurrCylin,ResultPolyh);
    ResultPolyh.SetReserved(iSSId);
    OBJHandle::UnitizeCGALPolyhedron(ResultPolyh,false,false);
    //update the cylinders stored in vecUnionPoly
    for (unsigned int i=0; i<this->vecUnionPoly.size(); i++)
    {
        if (this->vecUnionPoly.at(i).GetReserved()==iSSId)
        {
            this->vecUnionPoly.at(i)=ResultPolyh;
            break;
        }
    }
    //remove face points
    vector<int>::iterator IntIter=find(this->vecSubSurfSSId.begin(),this->vecSubSurfSSId.end(),iSSId);
    assert(IntIter!=this->vecSubSurfSSId.end());
    int iIndex=distance(this->vecSubSurfSSId.begin(),IntIter);
    vector<Point_3> vecNewSubPoint;
    vector<vector<int>> vecNewSubSurf;
    RemoveFaceTriangles(iSSId,ResultPolyh,this->vecvecvecFacePoint.at(iIndex),vecNewSubPoint,vecNewSubSurf);
    //update the points and triangles
    this->vecvecSubPoint.at(iIndex)=vecNewSubPoint;
    this->vecvecSubSurf.at(iIndex)=vecNewSubSurf;
    //stitch surface
    //stitch the submeshes together
    StitchMesh(this->vecvecSubPoint,this->vecvecSubSurf,this->InitPolyh);
    PostProcMesh();

    return true;
}
void CSmoothingAlgorithm::BilateralSmooth(KW_Mesh& Mesh,vector<Vertex_handle>& vecVertexToSmooth,double dSigmaC,double dKernelSize,double dSigmaS,int iNormalRingNum)
{
	//calculate the normal,just one-ring involved at present
	OBJHandle::UnitizeCGALPolyhedron(Mesh,false,false);
	
	if (dSigmaC==0)
	{
		dSigmaC=0.05;
		dKernelSize=dSigmaC*2;
	}

	assert(dKernelSize==2*dSigmaC);

	vector<Point_3> vecNewPos;

	for (unsigned int iVertex=0;iVertex<vecVertexToSmooth.size();iVertex++)
	{
		//get kernel vertices and their distances to the current vertex
		vector<Vertex_handle> vecKernelVertex;
		vector<double> vecDistance;
		GetKernelVertex(Mesh,vecVertexToSmooth.at(iVertex),dKernelSize,vecKernelVertex,vecDistance);

		//get offsets and derivation
		vector<double> vecOffset;
		GetOffsets(vecVertexToSmooth.at(iVertex),vecKernelVertex,vecOffset);
		double dDerivation=GeometryAlgorithm::GetDerivation(vecOffset);
		dSigmaS=dDerivation;
		//compute new positions
		double dSum,dNormalizer;
		dSum=dNormalizer=0;
		for (unsigned int iKernelVertex=0;iKernelVertex<vecKernelVertex.size();iKernelVertex++)
		{
			double dWC=exp(-vecDistance.at(iKernelVertex)*vecDistance.at(iKernelVertex)/(2*dSigmaC*dSigmaC));
			double dWS=exp(-vecOffset.at(iKernelVertex)*vecOffset.at(iKernelVertex)/(2*dSigmaS*dSigmaS));
			dSum=dSum+dWC*dWS*vecOffset.at(iKernelVertex);
			dNormalizer=dNormalizer+dWC*dWS;
		}
		Vector_3 VectorToMove=vecVertexToSmooth.at(iVertex)->normal()*(dSum/dNormalizer);
		if (dSum==0)
		{
			VectorToMove=Vector_3(0,0,0);
		}
		//DBWindowWrite("vertex: %d  VectorToMove: %f %f %f\n",iVertex,VectorToMove.x(),VectorToMove.y(),VectorToMove.z());
		Point_3 NewPos=vecVertexToSmooth.at(iVertex)->point()+VectorToMove;
		vecNewPos.push_back(NewPos);
	}

	//update vertex position
	for (unsigned int i=0;i<vecNewPos.size();i++)
	{
		//DBWindowWrite("old pos: %f %f %f\n",vecVertexToSmooth.at(i)->point().x(),vecVertexToSmooth.at(i)->point().y(),vecVertexToSmooth.at(i)->point().z());
		//DBWindowWrite("new pos: %f %f %f\n",vecNewPos.at(i).x(),vecNewPos.at(i).y(),vecNewPos.at(i).z());
		vecVertexToSmooth.at(i)->point()=vecNewPos.at(i);
	}

	OBJHandle::UnitizeCGALPolyhedron(Mesh,false,false);
	Mesh.SetRenderInfo(true,true,false,false,false);
}
void ImplicitMesher::ImpSurfToMeshMarCub(KW_Mesh& Mesh)
{
//	//transfer data from inside of class to global
//	RadialBasisFunc::CopyRadialBasisFunction(this->Weights,this->PolyNom,this->InterpoPoints);
//
//	MarCubRBF McRbf;
//	Polygonizer pol(&McRbf,.05, 30);//.05, 30
//	pol.march(false, 0.,0.,0.);//dotet
////	pol.march(true, this->InterpoPoints.front().x(),this->InterpoPoints.front().y(),
////		this->InterpoPoints.front().z());//dotet

	//transfer data from inside of class to global
	HermiteRBF::CopyHRBF(this->WeightsAlpha,this->WeightsBeta,this->PolyNomA,this->PolyNomB,this->InterpoPoints);

	MarCubHRBF McHRbf;
	Polygonizer pol(&McHRbf,.05, 30);//.05, 30
	pol.march(false, 0.,0.,0.);//dotet
	//	pol.march(true, this->InterpoPoints.front().x(),this->InterpoPoints.front().y(),
	//		this->InterpoPoints.front().z());//dotet

	Convert_MarCubPoly_To_CGALPoly<HalfedgeDS> triangle(&pol);
	Mesh.delegate(triangle);
}
int CMeshCutting::FillHole(KW_Mesh& Mesh,vector<Halfedge_handle> hhClosedCurve)
{
	//fill the hole of hhClosedCurve 
	Mesh.fill_hole(hhClosedCurve.front());
	Mesh.normalize_border();
	int test00=Mesh.size_of_border_edges();
	assert(test00==0);

	//create a center vertex
	vector<Point_3> EdgePoints;
	for (unsigned int i=0;i<this->hCuttingClosedCurveVertex3d.size();i++)
	{
		EdgePoints.push_back(this->hCuttingClosedCurveVertex3d.at(i)->point());
	}
	Point_3 CentroidPoint=CGAL::centroid(EdgePoints.begin(),EdgePoints.end());

	Halfedge_handle hhToCenterPoint=Mesh.create_center_vertex(hhClosedCurve.front());
	hhToCenterPoint->vertex()->point()=CentroidPoint;

	//Halfedge_handle hhStart=hhClosedCurve.front();
	//while (true)
	//{
	//	int iFacetDegree=hhStart->facet()->facet_degree();
	//	if (iFacetDegree==3)
	//	{
	//		break;
	//	}
	//	Halfedge_handle hhNewStart;
	//	if (iFacetDegree%2==0)
	//	{
	//		hhNewStart=Mesh.split_facet(hhStart->next(),hhStart->prev());
	//	} 
	//	else
	//	{
	//		hhNewStart=Mesh.split_facet(hhStart,hhStart->prev()->prev());
	//	}
	//	hhStart=hhNewStart->opposite();
	//}

	Mesh.normalize_border();
	assert(Mesh.size_of_border_edges()==0);

	return 0;
}
int CMeshCutting::DeleteFacets(KW_Mesh& Mesh,vector<Halfedge_handle> hhClosedCurve)
{
	//triangle incident to hhClosedCurve->opposite(outside the closed curve)
	vector<Facet_handle> fhCurveOutTri;
	//triangle incident to hhClosedCurve(inside the closed curve)
	vector<Facet_handle> fhCurveInTri;
	for (unsigned int i=0;i<hhClosedCurve.size();i++)
	{
		Halfedge_handle hhCurrent=hhClosedCurve.at(i);
		Halfedge_handle hhOpp=hhCurrent->opposite();
		fhCurveInTri.push_back(hhCurrent->facet());
		fhCurveOutTri.push_back(hhOpp->facet());
	}
	assert(fhCurveInTri.size()==fhCurveOutTri.size());

	int test10=Mesh.size_of_facets();
	//delete fhCurveInTri first
	for (unsigned int i=0;i<fhCurveInTri.size();i++)
	{
		Mesh.erase_facet(fhCurveInTri.at(i)->halfedge());
	}
	Mesh.normalize_border();
	int test11=Mesh.size_of_facets();
	assert(fhCurveInTri.size()+test11==test10);

	vector<Facet_handle> fhWithBorderEdge;
	while (GetFacetsWithBorderEdge(Mesh,fhWithBorderEdge,fhCurveOutTri))
	{
		for (unsigned int i=0;i<fhWithBorderEdge.size();i++)
		{
			Mesh.erase_facet(fhWithBorderEdge.at(i)->halfedge());
		}
		fhWithBorderEdge.clear();
		Mesh.normalize_border();
	}
	return 0;
}
bool KW_CS2Surf::SketchSplit(vector<CPoint> UserScrPoint,GLdouble* modelview,GLdouble* projection,GLint* viewport)
{
    //first filter to reduce the num of points on input curve
    GeometryAlgorithm compute;
    compute.ProcessCurverPoint(UserScrPoint,20.0);//15.0
    //get the cylinders selected
    vector<int> vecSelCylin;
    int iSSId=-1;
    bool bResult=SSGetSelCylin(UserScrPoint,modelview,projection,viewport,vecSelCylin,iSSId);
    if (!bResult)
    {
        return false;
    }
    //collect the cylinders in this subspace
    vector<KW_Mesh> vecSplitPoly,vecOtherPoly;
    for (unsigned int i=0; i<vecSelCylin.size(); i++)
    {
        vecSplitPoly.push_back(this->vecSinglePoly.at(vecSelCylin.at(i)));
    }
    for (unsigned int i=0; i<this->vecSinglePoly.size(); i++)
    {
        if (vecSinglePoly.at(i).GetReserved()==iSSId)
        {
            vector<int>::iterator IntIter=find(vecSelCylin.begin(),vecSelCylin.end(),i);
            if (IntIter==vecSelCylin.end())
            {
                vecOtherPoly.push_back(this->vecSinglePoly.at(i));
            }
        }
    }
    //compute the union
    KW_Mesh ResultPolyh;
    ComputeUnionInSubspace(vecSplitPoly,vecOtherPoly,ResultPolyh);
    ResultPolyh.SetReserved(iSSId);
    OBJHandle::UnitizeCGALPolyhedron(ResultPolyh,false,false);
    //update the cylinders stored in vecUnionPoly
    for (unsigned int i=0; i<this->vecUnionPoly.size(); i++)
    {
        if (this->vecUnionPoly.at(i).GetReserved()==iSSId)
        {
            this->vecUnionPoly.at(i)=ResultPolyh;
            break;
        }
    }

    //kw debug test
    if (this->CtrName=="skull.contour")
    {
        return true;
    }


    //remove face points
    vector<int>::iterator IntIter=find(this->vecSubSurfSSId.begin(),this->vecSubSurfSSId.end(),iSSId);
    assert(IntIter!=this->vecSubSurfSSId.end());
    int iIndex=distance(this->vecSubSurfSSId.begin(),IntIter);
    vector<Point_3> vecNewSubPoint;
    vector<vector<int>> vecNewSubSurf;
    RemoveFaceTriangles(iSSId,ResultPolyh,this->vecvecvecFacePoint.at(iIndex),vecNewSubPoint,vecNewSubSurf);
    //update the points and triangles
    this->vecvecSubPoint.at(iIndex)=vecNewSubPoint;
    this->vecvecSubSurf.at(iIndex)=vecNewSubSurf;
    //stitch surface
    //stitch the submeshes together
    StitchMesh(this->vecvecSubPoint,this->vecvecSubSurf,this->InitPolyh);
    PostProcMesh();

    return true;
}
void CMeshCutting::Conver2DCurveTo3D(KW_Mesh& Mesh)
{
	if (this->CurvePoint2D.empty())
	{
		return;
	}

	CKWResearchWorkView* pView=(CKWResearchWorkView*)this->pDoc->GetView(RUNTIME_CLASS(CKWResearchWorkView));
	GLdouble* modelview=pView->GetModelview();
	GLdouble* projection=pView->GetProjection();
	GLint* viewport=pView->GetViewport();

	if (!this->hCuttingClosedCurveVertex3d.empty())
	{
		this->iDrawingCurveType=CUTTING_BITE_CURVE;
	}
	else
	{
		this->iDrawingCurveType=CUTTING_ACROSS_CURVE;
	}

	if (iDrawingCurveType==CUTTING_ACROSS_CURVE)
	{
		GeometryAlgorithm compute;
		compute.ProcessCurverPoint(this->CurvePoint2D,10.0);

		//convert UCP into opengl coordinate(on Znear) 
		vector<Point_3> UserCurvePoint;
		for (unsigned int i=0;i<this->CurvePoint2D.size();i++)
		{
			GLdouble  winX, winY, winZ; 
			GLdouble posX, posY, posZ; 

			winX =this->CurvePoint2D.at(i).x;
			winY = viewport[3] - (float)this->CurvePoint2D.at(i).y;
			glReadPixels((int)winX, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ); 
			gluUnProject(winX, winY, 0.0, modelview, projection, viewport, &posX, &posY, &posZ);
			Point_3 CurrentPoint(posX,posY,posZ);
			UserCurvePoint.push_back(CurrentPoint);
		}

		vector<Vertex_handle> CuttingClosedCurveVertex3d;
		CPaintingOnMesh Painting;
		if(Painting.PaintingClosedStrokeOnFrontalAndRearMesh(Mesh,UserCurvePoint,modelview,
			CuttingClosedCurveVertex3d))
		{
			this->hCuttingClosedCurveVertex3d=CuttingClosedCurveVertex3d;
			//get the plane for judging which part to cut
			Point_3 Point0=UserCurvePoint.front();
			Point_3 Point1=this->hCuttingClosedCurveVertex3d.front()->point();
			Point_3 Point2=this->hCuttingClosedCurveVertex3d.back()->point();
			this->SidePlane=Plane_3(Point0,Point1,Point2);
		}
	}
	else if (iDrawingCurveType==CUTTING_BITE_CURVE)
	{
		if (this->hCuttingClosedCurveVertex3d.empty())
		{
			this->CurvePoint2D.clear();
			return;
		}
		//convert UCP into opengl coordinate(on Znear) 
		GLdouble  winX, winY, winZ; 
		GLdouble posX, posY, posZ; 
		winX =this->CurvePoint2D.front().x;
		winY = viewport[3] - (float)this->CurvePoint2D.front().y;
		glReadPixels((int)winX, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ); 
		gluUnProject(winX, winY, 0.0, modelview, projection, viewport, &posX, &posY, &posZ);
		this->SidePoint=Point_3(posX,posY,posZ);

		CPaintingOnMesh Painting;
		Facet_handle temp;
		if(Painting.PaintingPointOnFrontalMesh(Mesh,this->SidePoint,temp,modelview))
		{
			CutMesh(Mesh);
			OBJHandle::UnitizeCGALPolyhedron(Mesh,false,false);
			Mesh.SetRenderInfo(true,true,true,true,true);
			this->hCuttingClosedCurveVertex3d.clear();
		}
		else
		{
			AfxMessageBox("Invalid Curve,could not judge which part to cut!");
		}
	}
	//else if (iDrawingCurveType==3)
	//{
	//	if (this->Tunel.GetTunVer().size()<2)
	//	{
	//		GeometryAlgorithm compute;
	//		compute.ProcessCurverPoint(this->CurvePoint2D);
	//		compute.MakeClosedStroke2d(this->CurvePoint2D);

	//		//convert UCP into opengl coordinate(on Znear) 
	//		vector<Point_3> UserCurvePoint;
	//		for (unsigned int i=0;i<this->CurvePoint2D.size();i++)
	//		{
	//			GLdouble  winX, winY, winZ; 
	//			GLdouble posX, posY, posZ; 

	//			winX =this->CurvePoint2D.at(i).x;
	//			winY = viewport[3] - (float)this->CurvePoint2D.at(i).y;
	//			glReadPixels((int)winX, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ); 
	//			gluUnProject(winX, winY, 0.0, modelview, projection, viewport, &posX, &posY, &posZ);
	//			Point_3 CurrentPoint(posX,posY,posZ);
	//			UserCurvePoint.push_back(CurrentPoint);
	//		}

	//		vector<Vertex_handle> TunnelCurve3d;
	//		CPaintingOnMesh Painting;
	//		if(Painting.PaintingClosedStrokeOnFrontalMesh(Mesh,UserCurvePoint,modelview,TunnelCurve3d))
	//		{
	//			if (this->Tunel.GetTunVer().size()==0)
	//			{
	//				this->Tunel.InputTunVer(TunnelCurve3d);
	//			}
	//			else if (this->Tunel.GetTunVer().size()==1)//remesh to get the two sketched circles
	//			{
	//				//the result curve is always ccw on screen,so reverse the second curve
	//				//and make it the same direction with the first one
	//				reverse(TunnelCurve3d.begin(),TunnelCurve3d.end());
	//				this->Tunel.InputTunVer(TunnelCurve3d);
	//				this->Tunel.CorrespondTunCircles();
	//				this->Tunel.SetRefPlane(this->BestFittingPlane,this->PlaneBoundaryPoints,
	//					this->RotateXAxisStartPoint,this->RotateXAxisEndPoint);
	//			}
	//			OBJHandle::UnitizeCGALPolyhedron(Mesh,false,false);
	//			Mesh.SetRenderInfo(true,true,true,true,true);
	//		}
	//	}
	//	else if (this->Tunel.GetTunVer().size()==2)//make tunnel along the sketched curve
	//	{
	//		GeometryAlgorithm compute;
	//		compute.ProcessCurverPoint(this->CurvePoint2D,15.0);

	//		vector<Point_3> vecTempPoints;
	//		CPaintingOnMesh PaintingOnMesh;
	//		int iResult=PaintingOnMesh.PaintingOnBFPlane(this->BestFittingPlane,modelview,projection,viewport,
	//			this->CurvePoint2D,vecTempPoints);
	//		if (iResult)
	//		{
	//			this->Tunel.SetTunnelDirectCurve(vecTempPoints);
	//		}

	//		//dig the hole
	//		this->Tunel.Tunnel(pDoc->GetMesh(),this->vecTestPoint);
	//		this->Tunel.clear();

	//		OBJHandle::UnitizeCGALPolyhedron(Mesh,false,false);
	//		Mesh.SetRenderInfo(true,true,true,true,true);
	//	}
	//}
	else
	{
		//do nothing
	}

	this->iDrawingCurveType=NONE_SELECTED;
	this->CurvePoint2D.clear();
}
void KW_CS2Surf::GetSSMesh()
{
	//faces in each subspace,each vector<int> represents a face composed of vertices with indices <int>
	vector<vector<vector<int>>> vecTotalFaceVer;
	//faces in each subspace,each int represents the face id of the facet in a subspace (a face may contain many facets(eg,triangles))
	vector<vector<int>> vecTotalFace;
	//the order of each element in vecTotalFaceVer&vecTotalFace is consistent with the order of subspaces
	vecTotalFaceVer.resize(this->iSSspacenum);
	vecTotalFace.resize(this->iSSspacenum);
	for (unsigned int i=0;i<this->vecResortFace.size();i++)
	{
		ResortedFace currFace=vecResortFace.at(i);
		vector<int> currFaceVertexInd=currFace.vecFaceVertexInd;
		//the two subspace this face belongs to
		for (unsigned int j=0;j<currFace.vecOrient.size();j++)
		{
			int icurrSSId=currFace.vecSubspaceId.at(j);
			if (!currFace.vecOrient.at(j))
			{
				reverse(currFaceVertexInd.begin(),currFaceVertexInd.end());
			}
			vecTotalFaceVer.at(icurrSSId).push_back(currFaceVertexInd);
			vecTotalFace.at(icurrSSId).push_back(i);
			//reverse back to the originally saved order
			if (!currFace.vecOrient.at(j))
			{
				reverse(currFaceVertexInd.begin(),currFaceVertexInd.end());
			}
		}
	}

	//id of vertices stored in vecTotalFaceVer is the global vertex id,need to convert it 
	//to the id within each subspace mesh
	//all the vertices are collected from the faces, so isolated vertices caused by the 
	//subspace combination will not be taken account into consideration

	//subspace number after combination
	int iSSNumAfterComb=0;
	for (unsigned int i=0;i<vecTotalFaceVer.size();i++)
	{
		set<int> setSSVer;
		vector<vector<set<int>::iterator>> vecFaceSetIter;
		//put all vertex indices in, store the iterator
		for (unsigned int j=0;j<vecTotalFaceVer.at(i).size();j++)
		{
			vector<set<int>::iterator> currFaceSetIter;
			for (unsigned int k=0;k<vecTotalFaceVer.at(i).at(j).size();k++)
			{
				pair<set<int>::iterator, bool> pairResult=setSSVer.insert(vecTotalFaceVer.at(i).at(j).at(k));
				currFaceSetIter.push_back(pairResult.first);
			}
			vecFaceSetIter.push_back(currFaceSetIter);
		}
		//get the id within the subspace according to the iterator
		vector<vector<int>> vecLocalVerInd;
		for (unsigned int j=0;j<vecFaceSetIter.size();j++)
		{
			vector<int> LocalFace;
			for (unsigned int k=0;k<vecFaceSetIter.at(j).size();k++)
			{
				int iLocalId=distance(setSSVer.begin(),vecFaceSetIter.at(j).at(k));
				LocalFace.push_back(iLocalId);
			}
			vecLocalVerInd.push_back(LocalFace);
		}
		//convert to triangular mesh
		//a simple method (012345->012 023 034 045),may have bug 
		vector<vector<int>> vecTriLocalVerInd;
		vector<int> vecTriFaceId;//the subspace face id of each triangle
		for (unsigned int j=0;j<vecLocalVerInd.size();j++)
		{
			vector<int> vecCurrFace=vecLocalVerInd.at(j);
			int iSecondVerLocalId=1;
			int iFacetFaceId=vecTotalFace.at(i).at(j);
			for (unsigned int k=0;k<vecCurrFace.size()-2;k++)
			{
				vector<int> vecTriFace;
				vecTriFace.push_back(vecCurrFace.at(0));
				vecTriFace.push_back(vecCurrFace.at(iSecondVerLocalId));
				vecTriFace.push_back(vecCurrFace.at(iSecondVerLocalId+1));
				iSecondVerLocalId++;
				vecTriLocalVerInd.push_back(vecTriFace);
				vecTriFaceId.push_back(iFacetFaceId);
			}
		}
		//store all the points
		vector<Point_3> vecAllPoint;
		for (set<int>::iterator SetIter=setSSVer.begin();SetIter!=setSSVer.end();SetIter++)
		{
			vecAllPoint.push_back(Point_3(vecSSver.at(3*(*SetIter)),
				vecSSver.at(3*(*SetIter)+1),
				vecSSver.at(3*(*SetIter)+2)));
		}
		KW_Mesh currSSMesh;
		//if a subspace has been combined into others,still save it as an empty one,
		//in order to keep the order of subspaces
		if (!vecAllPoint.empty() && !vecTriLocalVerInd.empty())
		{
			//Convert_Array_To_KW_Mesh<HalfedgeDS> triangle(vecAllPoint,vecLocalVerInd);
			Convert_Array_To_KW_Mesh<HalfedgeDS> triangle(vecAllPoint,vecTriLocalVerInd);
			currSSMesh.delegate(triangle);
			//record the face id of each triangle
			assert(currSSMesh.size_of_facets()==vecTriFaceId.size());
			Facet_iterator FaceIter=currSSMesh.facets_begin();
			for (unsigned int j=0;j<vecTriFaceId.size();j++)
			{
				FaceIter->SetReserved(vecTriFaceId.at(j));
				FaceIter++;
			}
		}
		//save the subspace mesh
		if (!currSSMesh.empty())
		{
			iSSNumAfterComb++;
			OBJHandle::UnitizeCGALPolyhedron(currSSMesh,false,false);
		}
		this->vecSSMesh.push_back(currSSMesh);
		////test
		//if (!currSSMesh.empty())
		//{
		//	OBJHandle::UnitizeCGALPolyhedron(currSSMesh,false,false);
		//	this->vecSinglePoly.push_back(currSSMesh);
		//}
	}
	DBWindowWrite("initial subzone no.: %d\n",this->iSSspacenum);
	DBWindowWrite("subzone no. after combination: %d\n",iSSNumAfterComb);
}