YSRESULT YsShellExt_SweepInfoMultiStep::SetUpSolidOfRevolution( const YsShellExt &shl,const YsVec3 &axiso,const YsVec3 &axisv,int nStep,const double stepAngle,const YsVec3 &stepOffset,YSBOOL closeSolid) { if(0<nStep) { const auto &allVtHd=GetVertexAll(); // Need the original normal. const YSSIZE_T nMidLayer=(YSTRUE==closeSolid ? nStep-1 : nStep); SetUpNLayer(shl,nStep+1); // 2015/03/05 I think I ended up making the second parameter to be (number of layers)+1.... for(auto layerIdx=0; layerIdx<nMidLayer; ++layerIdx) { const double angle=(double)(layerIdx+1)*stepAngle; YsRotation rot(axisv,angle); for(auto vtHd : allVtHd) { YSSIZE_T indexInLayer; if(YSOK==srcVtKeyToMidPointIndex.FindElement(indexInLayer,shl.GetSearchKey(vtHd))) { auto &point=layerArray[layerIdx].pointArray[indexInLayer]; point.pos=rot*shl.GetVertexPosition(vtHd)+stepOffset*(double)(layerIdx+1); if(point.pos==shl.GetVertexPosition(vtHd)) // Vertex on axis { point.vtHd=vtHd; } else { point.vtHd=NULL; } } } } if(YSTRUE==closeSolid) { for(auto vtHd : allVtHd) { YSSIZE_T indexInLayer; if(YSOK==srcVtKeyToMidPointIndex.FindElement(indexInLayer,shl.GetSearchKey(vtHd))) { auto &point=layerArray[nStep-1].pointArray[indexInLayer]; point.vtHd=vtHd; point.pos=shl.GetVertexPosition(vtHd); } } } return YSOK; } return YSERR; }
YSRESULT YsShellExt_RoundUtil::SetUpRoundConstEdge(const YsShellExt &shl,YsShellExt::ConstEdgeHandle ceHd,const YsShellVertexStore *roundVtx) { YsArray <YsShellVertexHandle> ceVtHd; YSBOOL isLoop; shl.GetConstEdge(ceVtHd,isLoop,ceHd); if(YSTRUE==isLoop && 3>ceVtHd.GetN()) { return YSERR; } else if(YSTRUE!=isLoop && 2>ceVtHd.GetN()) { return YSERR; } if(YSTRUE==isLoop) { ceVtHd.Append(ceVtHd[0]); ceVtHd.Append(ceVtHd[1]); } for(YSSIZE_T idx=1; idx<ceVtHd.GetN()-1; ++idx) { if(NULL==roundVtx || YSTRUE==roundVtx->IsIncluded(ceVtHd[idx])) { const YsShellVertexHandle toVtHd[2]={ceVtHd[idx-1],ceVtHd[idx+1]}; AddRoundCorner((const YsShell &)shl,ceVtHd[idx],toVtHd); } } targetCeKeyArray.Append(shl.GetSearchKey(ceHd)); return YSOK; }
void YsShellExt_SweepInfoMultiStep::SetUpNLayer(const YsShellExt &shl,YSSIZE_T nLayer) { // For nLayers, layerArray needs to be nLayer-1 long. layerArray.Set(nLayer-1,NULL); for(auto &layer : layerArray) { layer.Initialize(); } for(auto srcVtHd : allSrcVtHd) { const YSSIZE_T nextIdx=layerArray[0].pointArray.GetN(); layerArray[0].pointArray.Increment(); srcVtKeyToMidPointIndex.UpdateElement(shl.GetSearchKey(srcVtHd),nextIdx); } for(auto idx : layerArray.AllIndex()) { if(0<idx) { layerArray[idx].pointArray.Set(layerArray[0].pointArray.GetN(),NULL); } for(auto &point : layerArray[idx].pointArray) { point.Initialize(); } } }
YsArray <YsShellExt_SweepInfoMultiStep::Quad> YsShellExt_SweepInfoMultiStep::MakeSideFaceAndFirstToLastVertexMapping(const YsShellExt &shl) { YsShellExt_Mapping <YsShellVertexHandle,YsShellVertexHandle>::CleanUp(); YsArray <Quad> quadArray; for(YSSIZE_T edIdx=0; edIdx<=srcEdVtHd.GetN()-2; edIdx+=2) { YSSIZE_T idxInLayer[2]; if(YSOK==srcVtKeyToMidPointIndex.FindElement(idxInLayer[0],shl.GetSearchKey(srcEdVtHd[edIdx])) && YSOK==srcVtKeyToMidPointIndex.FindElement(idxInLayer[1],shl.GetSearchKey(srcEdVtHd[edIdx+1]))) { YsShellVertexHandle curEdVtHd[2]={srcEdVtHd[edIdx],srcEdVtHd[edIdx+1]}; for(auto &layer : layerArray) { YsShellVertexHandle nxtEdVtHd[2]={layer.pointArray[idxInLayer[0]].vtHd,layer.pointArray[idxInLayer[1]].vtHd}; quadArray.Increment(); quadArray.Last().quadVtHd[0]=curEdVtHd[1]; quadArray.Last().quadVtHd[1]=curEdVtHd[0]; quadArray.Last().quadVtHd[2]=nxtEdVtHd[0]; quadArray.Last().quadVtHd[3]=nxtEdVtHd[1]; curEdVtHd[0]=nxtEdVtHd[0]; curEdVtHd[1]=nxtEdVtHd[1]; } if(YSTRUE!=YsShellExt_VertexToVertexMapping::CheckMappingExist(shl,srcEdVtHd[edIdx])) { YsShellExt_VertexToVertexMapping::AddMapping(shl,srcEdVtHd[edIdx], curEdVtHd[0]); } if(YSTRUE!=YsShellExt_VertexToVertexMapping::CheckMappingExist(shl,srcEdVtHd[edIdx+1])) { YsShellExt_VertexToVertexMapping::AddMapping(shl,srcEdVtHd[edIdx+1],curEdVtHd[1]); } } } return quadArray; }
YSBOOL YsShellExt_RoundUtil3d::IsPolygonOnTheSameContour(const YsShellExt &shl,YsShellPolygonHandle plHd,const YsHashTable <YSSIZE_T> &vtKeyToBoundaryIdx) { auto plVtHd=shl.GetPolygonVertex(plHd); if(0<plVtHd.GetN()) { YSSIZE_T boundaryIdx0; if(YSOK!=vtKeyToBoundaryIdx.FindElement(boundaryIdx0,shl.GetSearchKey(plVtHd[0]))) { return YSFALSE; } for(auto vtHd : plVtHd) { YSSIZE_T boundaryIdx; if(YSOK!=vtKeyToBoundaryIdx.FindElement(boundaryIdx,shl.GetSearchKey(vtHd)) || boundaryIdx!=boundaryIdx0) { return YSFALSE; } } return YSTRUE; } return YSFALSE; }
YSRESULT YsShellExt_SweepInfoMultiStep::SetUpParallelSweepWithPath(const YsShellExt &shl,YSSIZE_T nPathVt,const YsShellVertexHandle pathVtHdArray[],const double scaling[]) { CleanUpLayer(); if(2<=nPathVt) { YsArray <YsVec3> pathPnt(nPathVt,NULL); for(YSSIZE_T idx=0; idx<nPathVt; ++idx) { pathPnt[idx]=shl.GetVertexPosition(pathVtHdArray[idx]); } SetUpNLayer(shl,nPathVt); for(auto vtHd : allSrcVtHd) { YSSIZE_T indexInLayer; if(YSOK==srcVtKeyToMidPointIndex.FindElement(indexInLayer,shl.GetSearchKey(vtHd))) { if(vtHd==pathVtHdArray[0]) { for(auto idx : layerArray.AllIndex()) { auto &point=layerArray[idx].pointArray[indexInLayer]; point.vtHd=pathVtHdArray[idx+1]; point.pos=shl.GetVertexPosition(pathVtHdArray[idx+1]); } } else { for(auto idx : layerArray.AllIndex()) { auto &point=layerArray[idx].pointArray[indexInLayer]; point.pos=(shl.GetVertexPosition(vtHd)-pathPnt[0])*scaling[idx+1]+pathPnt[idx+1]; } } } } return YSOK; } return YSERR; }
YSRESULT YsShellExt_SweepInfoMultiStep::SetUpNonParallelSweepWithPath(const YsShellExt &shl,YSSIZE_T nPathVt,const YsShellVertexHandle pathVtHdArrayIn[],YSBOOL isLoop,const YsVec3 nom[],const double scaling[]) { const auto &allVtHd=GetVertexAll(); // Need the original normal. CleanUpLayer(); if(2<=nPathVt) { YsConstArrayMask <YsShellVertexHandle> pathVtHd(nPathVt,pathVtHdArrayIn); YsArray <YsVec3> pathPnt(nPathVt,NULL); for(YSSIZE_T idx=0; idx<pathVtHd.GetN(); ++idx) { pathPnt[idx]=shl.GetVertexPosition(pathVtHd[idx]); } const YSSIZE_T nLayer=(YSTRUE==isLoop ? nPathVt : nPathVt-1); SetUpNLayer(shl,nLayer+1); // First set of vertices are not counted as a layer. Number of layers will be nPathVt-1. // Rotation must be progressive. Why? Assume nom[0] and nom[5] are 180 degrees opposite. // If the rotation is calculated for each layer by YsRotation::MakeAtoB(nom[0],nom[layerIndex]), // rotational axis for nom[5] may become different from other layers, and thus the continuity is lost. // The solution is calculating the rotation for each step progressively. YsArray <YsMatrix3x3> rot(nPathVt-1,NULL); YsMatrix3x3 prevRot; for(int layerIdx=0; layerIdx<nPathVt-1; ++layerIdx) { YsRotation thisRot; thisRot.MakeAtoB(nom[layerIdx],nom[layerIdx+1]); prevRot*=thisRot; rot[layerIdx]=prevRot; } for(auto layerIdx=0; layerIdx<nPathVt-1; ++layerIdx) { YsMatrix4x4 tfm; tfm.Translate(pathPnt[layerIdx+1]); tfm*=rot[layerIdx]; tfm.Scale(scaling[layerIdx+1],scaling[layerIdx+1],scaling[layerIdx+1]); tfm.Translate(-pathPnt[0]); for(auto vtHd : allVtHd) { YSSIZE_T indexInLayer; if(YSOK==srcVtKeyToMidPointIndex.FindElement(indexInLayer,shl.GetSearchKey(vtHd))) { auto &point=layerArray[layerIdx].pointArray[indexInLayer]; if(vtHd==pathVtHd[0]) { point.vtHd=pathVtHd[layerIdx+1]; point.pos=shl.GetVertexPosition(pathVtHd[layerIdx+1]); } else { point.vtHd=NULL; point.pos=tfm*shl.GetVertexPosition(vtHd); } } } } if(YSTRUE==isLoop) { for(auto vtHd : allVtHd) { YSSIZE_T indexInLayer; if(YSOK==srcVtKeyToMidPointIndex.FindElement(indexInLayer,shl.GetSearchKey(vtHd))) { auto &point=layerArray[nLayer-1].pointArray[indexInLayer]; point.vtHd=vtHd; point.pos=shl.GetVertexPosition(vtHd); } } } return YSOK; } return YSERR; }
YSRESULT YsShellExt_RoundUtil3d::SetUpForVertexSequenceAndPolygonArray( const YsShellExt &shl, const YsArray <YsArray <YsShellVertexHandle> > &allBoundary, const YsArray <YsShellPolygonHandle> &sideAPolygonArray, const YsArray <YsShellPolygonHandle> &sideBPolygonArray) { YsHashTable <YSSIZE_T> vtKeyToBoundaryIdx; YsShellEdgeStore boundaryEdge((const YsShell &)shl); for(auto idx : allBoundary.AllIndex()) { YsArray <YsShellVertexHandle> contourVtHd=allBoundary[idx]; for(YSSIZE_T vtIdx=0; vtIdx<contourVtHd.GetN()-1; ++vtIdx) { if(YSTRUE!=boundaryEdge.IsIncluded(contourVtHd[vtIdx],contourVtHd[vtIdx+1])) { boundaryEdge.AddEdge(contourVtHd[vtIdx],contourVtHd[vtIdx+1]); roundEdgeArray.Increment(); roundEdgeArray.Last().Initialize(); roundEdgeArray.Last().edVtHd[0]=contourVtHd[vtIdx]; roundEdgeArray.Last().edVtHd[1]=contourVtHd[vtIdx+1]; } } for(auto vtHd : contourVtHd) { vtKeyToBoundaryIdx.AddElement(shl.GetSearchKey(vtHd),idx); } } // Boundary edge hash and sideBPolygon store have been constructed. YsShellExt_OffsetUtil2d &sideAOffset=offsetUtil[0],&sideBOffset=offsetUtil[1]; YsShellPolygonStore sideAPolygon((const YsShell &)shl),sideBPolygon((const YsShell &)shl); sideAPolygon.AddPolygon(sideAPolygonArray); sideBPolygon.AddPolygon(sideBPolygonArray); YSBOOL sideAOffsetNecessary=YSFALSE,sideBOffsetNecessary=YSFALSE; if(YSTRUE==alwaysUseOffset) { sideAOffsetNecessary=YSTRUE; sideBOffsetNecessary=YSTRUE; } else { for(auto boundary : allBoundary) { YsArray <YsShellVertexHandle> contourVtHd=boundary; for(auto vtHd : contourVtHd) { YsArray <YsShellVertexHandle,16> connVtHdArray; shl.GetConnectedVertex(connVtHdArray,vtHd); YSBOOL sideAEdgePresent=YSFALSE,sideBEdgePresent=YSFALSE; for(auto connVtHd : connVtHdArray) { if(YSTRUE==boundaryEdge.IsIncluded(vtHd,connVtHd)) { continue; } if(YSTRUE==IsEdgeUsing(vtHd,connVtHd,shl.Conv(),sideAPolygon)) { sideAEdgePresent=YSTRUE; } else if(YSTRUE==IsEdgeUsing(vtHd,connVtHd,shl.Conv(),sideBPolygon)) { sideBEdgePresent=YSTRUE; } } if(YSTRUE!=sideAEdgePresent) { sideAOffsetNecessary=YSTRUE; } if(YSTRUE!=sideBEdgePresent) { sideBOffsetNecessary=YSTRUE; } } } } printf("%s %d\n",__FUNCTION__,__LINE__); printf("%d %d\n",sideAOffsetNecessary,sideBOffsetNecessary); if(YSTRUE==sideAOffsetNecessary) { if(YSOK!=sideAOffset.SetUpForOneSideOfVertexSequence(shl,allBoundary,sideAPolygonArray)) { return YSERR; } for(YSSIZE_T idx=0; idx<sideAOffset.newVtxArray.GetN(); ++idx) { auto newVtx=sideAOffset.newVtxArray[idx]; cornerArray.Increment(); cornerArray.Last().Initialize(); cornerArray.Last().fromVtHd=newVtx.fromVtHd; cornerArray.Last().toVtHd=NULL; cornerArray.Last().toPos=newVtx.fromPos+newVtx.dir*newVtx.maxDist; cornerArray.Last().offsetUtil=&sideAOffset; cornerArray.Last().offsetUtil_newVtxIdx=idx; cornerArray.Last().notReallyDistanceLimited=IsPolygonOnTheSameContour(shl,newVtx.limitingPlHd,vtKeyToBoundaryIdx); } } if(YSTRUE==sideBOffsetNecessary) { if(YSOK!=sideBOffset.SetUpForOneSideOfVertexSequence(shl,allBoundary,sideBPolygonArray)) { return YSERR; } for(YSSIZE_T idx=0; idx<sideBOffset.newVtxArray.GetN(); ++idx) { auto newVtx=sideBOffset.newVtxArray[idx]; cornerArray.Increment(); cornerArray.Last().Initialize(); cornerArray.Last().fromVtHd=newVtx.fromVtHd; cornerArray.Last().toVtHd=NULL; cornerArray.Last().toPos=newVtx.fromPos+newVtx.dir*newVtx.maxDist; cornerArray.Last().offsetUtil=&sideBOffset; cornerArray.Last().offsetUtil_newVtxIdx=idx; cornerArray.Last().notReallyDistanceLimited=IsPolygonOnTheSameContour(shl,newVtx.limitingPlHd,vtKeyToBoundaryIdx); } } printf("%s %d\n",__FUNCTION__,__LINE__); for(auto boundary : allBoundary) { YsArray <YsShellVertexHandle> contourVtHd=boundary; if(3<=contourVtHd.GetN()) { if(contourVtHd[0]==contourVtHd.Last()) { contourVtHd.DeleteLast(); } } for(auto vtHd : contourVtHd) { YsArray <YsShellVertexHandle,16> connVtHdArray; shl.GetConnectedVertex(connVtHdArray,vtHd); for(auto connVtHd : connVtHdArray) { if(YSTRUE==boundaryEdge.IsIncluded(vtHd,connVtHd)) { continue; } else if((YSTRUE!=sideAOffsetNecessary && YSTRUE==IsEdgeUsing(vtHd,connVtHd,(const YsShell &)shl,sideAPolygon)) || (YSTRUE!=sideBOffsetNecessary && YSTRUE==IsEdgeUsing(vtHd,connVtHd,(const YsShell &)shl,sideBPolygon))) { cornerArray.Increment(); cornerArray.Last().Initialize(); cornerArray.Last().fromVtHd=vtHd; cornerArray.Last().toVtHd=connVtHd; cornerArray.Last().toPos=shl.GetVertexPosition(connVtHd); } } } } printf("%s %d\n",__FUNCTION__,__LINE__); for(YSSIZE_T cornerIdx=0; cornerIdx<cornerArray.GetN(); ++cornerIdx) { if(NULL!=cornerArray[cornerIdx].offsetUtil) { cornerArray[cornerIdx].offsetUtil->newVtxArray[cornerArray[cornerIdx].offsetUtil_newVtxIdx].cornerIdx=cornerIdx; } } printf("%s %d\n",__FUNCTION__,__LINE__); if(YSOK==CalculateRoundingDirectionAll((const YsShell &)shl)) { printf("%s %d\n",__FUNCTION__,__LINE__); return YSOK; } printf("%s %d\n",__FUNCTION__,__LINE__); CleanUp(); return YSERR; }
YSRESULT YsShellExt_SewingInfo::CrawlOneSegment( YsShellVertexHandle ¤tVtHd, YsShell::Edge ¤tEdge, YsShellPolygonHandle ¤tPlHd, YsVec3 ¤tPos, const YsShellExt &shl, const YsVec3 &goalPos, YsShellVertexHandle goalVtHd) { auto startDir=YsUnitVector(goalPos-currentPos); YsShellCrawler crawler; crawler.crawlingMode=YsShellCrawler::CRAWL_TO_GOAL; crawler.goal=goalPos; YSRESULT started=YSERR; if(NULL!=currentVtHd) { started=crawler.Start(shl.Conv(),currentPos,startDir,currentVtHd); } else if(NULL!=currentEdge[0] && NULL!=currentEdge[1]) { started=crawler.Start(shl.Conv(),currentPos,startDir,currentEdge); } else if(NULL!=currentPlHd) { started=crawler.Start(shl.Conv(),currentPos,startDir,currentPlHd); } if(YSOK==started) { if(0==vtxSequence.GetN()) { vtxSequence.Increment(); vtxSequence.Last().Initialize(); vtxSequence.Last().vtHd=currentVtHd; vtxSequence.Last().plHd=crawler.currentPlHd; vtxSequence.Last().pos=crawler.currentPos; } else { vtxSequence.Last().plHd=crawler.currentPlHd; } // Debugging sphere.srf 371 276 375 // [Selected Vertices] // Vertex Id: 370 Internal Hash Key: 371 Position: -3.467600 -0.689748 3.535534 // Vertex Id: 275 Internal Hash Key: 276 Position: -4.530637 -1.876651 0.975452 // Vertex Id: 374 Internal Hash Key: 375 Position: -1.964237 -2.939689 3.535534 YSBOOL watch=YSFALSE; while(YSOK==crawler.Crawl(shl.Conv(),0.0,watch)) { if((crawler.currentState==YsShellCrawler::STATE_ON_VERTEX || crawler.currentEdVtHd[0]==crawler.currentEdVtHd[1]) && crawler.currentEdVtHd[0]==vtxSequence.Last().vtHd) { vtxSequence.Last().plHd=crawler.currentPlHd; } else { switch(crawler.currentState) { case YsShellCrawler::STATE_IN_POLYGON: if(crawler.currentPos==goalPos || ((NULL==goalVtHd || 0==shl.GetNumPolygonUsingVertex(goalVtHd)) && YSTRUE==crawler.reachedDeadEnd)) // Can happen in the end. { vtxSequence.Increment(); vtxSequence.Last().Initialize(); vtxSequence.Last().plHd=crawler.currentPlHd; vtxSequence.Last().vtHd=goalVtHd; vtxSequence.Last().pos=crawler.currentPos; if(NULL==goalVtHd) { vtxSequence.Last().vtxOnPlgIdx=(int)vtxOnPlg.GetN(); vtxOnPlg.Increment(); vtxOnPlg.Last().plHd=crawler.currentPlHd; vtxOnPlg.Last().vtHd=goalVtHd; vtxOnPlg.Last().pos=goalPos; } } break; case YsShellCrawler::STATE_ON_VERTEX: vtxSequence.Increment(); vtxSequence.Last().Initialize(); vtxSequence.Last().plHd=crawler.currentPlHd; vtxSequence.Last().vtHd=crawler.currentEdVtHd[0]; vtxSequence.Last().pos=crawler.currentPos; break; case YsShellCrawler::STATE_ON_EDGE: if(crawler.currentEdVtHd[0]==crawler.currentEdVtHd[1]) { vtxSequence.Increment(); vtxSequence.Last().Initialize(); vtxSequence.Last().plHd=crawler.currentPlHd; vtxSequence.Last().vtHd=crawler.currentEdVtHd[0]; vtxSequence.Last().pos=crawler.currentPos; } else { YsShellVertexHandle onThisVtHd=(crawler.currentPos==goalPos ? goalVtHd : NULL); vtxSequence.Increment(); vtxSequence.Last().Initialize(); vtxSequence.Last().plHd=crawler.currentPlHd; vtxSequence.Last().vtHd=onThisVtHd; vtxSequence.Last().vtxOnEdgeIdx=(int)vtxOnEdge.GetN(); vtxOnEdge.Increment(); vtxOnEdge.Last().edVtHd[0]=crawler.currentEdVtHd[0]; vtxOnEdge.Last().edVtHd[1]=crawler.currentEdVtHd[1]; vtxOnEdge.Last().createdVtHd=onThisVtHd; vtxOnEdge.Last().pos=crawler.currentPos; } break; } } if(YSTRUE==crawler.reachedDeadEnd || goalPos==crawler.currentPos) { break; } } currentPos=crawler.currentPos; switch(crawler.currentState) { case YsShellCrawler::STATE_IN_POLYGON: currentVtHd=NULL; currentEdge.edVtHd[0]=NULL; currentEdge.edVtHd[1]=NULL; currentPlHd=crawler.currentPlHd; break; case YsShellCrawler::STATE_ON_VERTEX: currentVtHd=crawler.currentEdVtHd[0]; currentEdge.edVtHd[0]=NULL; currentEdge.edVtHd[1]=NULL; currentPlHd=NULL; break; case YsShellCrawler::STATE_ON_EDGE: if(crawler.currentEdVtHd[0]!=crawler.currentEdVtHd[1]) { // Minor glitch that needs to be fixed. currentVtHd=NULL; currentEdge.edVtHd[0]=crawler.currentEdVtHd[0]; currentEdge.edVtHd[1]=crawler.currentEdVtHd[1]; currentPlHd=NULL; } else { currentVtHd=crawler.currentEdVtHd[0]; currentEdge.edVtHd[0]=NULL; currentEdge.edVtHd[1]=NULL; currentPlHd=NULL; } break; default: printf("%s %d\n",__FUNCTION__,__LINE__); printf("%d\n",crawler.currentState); return YSERR; } if(crawler.currentPos==goalPos) { if(NULL==vtxSequence.Last().vtHd) { if(0<=vtxSequence.Last().vtxOnEdgeIdx) { printf("%d %d\n",shl.GetSearchKey(vtxOnEdge[vtxSequence.Last().vtxOnEdgeIdx].edVtHd[0]),shl.GetSearchKey(vtxOnEdge[vtxSequence.Last().vtxOnEdgeIdx].edVtHd[1])); printf("Landed between %s %s\n", shl.GetVertexPosition(vtxOnEdge[vtxSequence.Last().vtxOnEdgeIdx].edVtHd[0]).Txt(), shl.GetVertexPosition(vtxOnEdge[vtxSequence.Last().vtxOnEdgeIdx].edVtHd[1]).Txt()); } else { printf("Nowhere to go.\n"); } } if(goalVtHd!=vtxSequence.Last().vtHd) { printf("Could not reach the goal vertex.\n"); return YSERR; } return YSOK; } // If crawler didn't reach the goal, it might mean the goal is slightly off the polygon. // It should be allowed because some polygons may be slightly off the plane. if((NULL==goalVtHd || 0==shl.GetNumPolygonUsingVertex(goalVtHd)) && YSTRUE==crawler.reachedDeadEnd) { // vtxSequence is supposed to be incremented in [case YsShellExt::STATE_IN_POLYGON] return YSOK; } } return YSERR; }