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); }