void YsShellExt_SewingInfo::MakeEdgeMidVertexInfo(const YsShellExt &shl) { edgeMidVtx.CleanUp(); edgeMidVtx.SetShell(shl.Conv()); for(auto &vone : vtxOnEdge) { YsShell_LocalOperation::EdgeMidVertex *midVtx=edgeMidVtx.FindAttrib(vone.edVtHd[0],vone.edVtHd[1]); if(NULL==midVtx) { YsShell_LocalOperation::EdgeMidVertex newEdgeMidVtx; newEdgeMidVtx.edge[0]=vone.edVtHd[0]; newEdgeMidVtx.edge[1]=vone.edVtHd[1]; newEdgeMidVtx.midVtHd.MakeUnitLength(vone.createdVtHd); edgeMidVtx.SetAttrib(vone.edVtHd,newEdgeMidVtx); } else { midVtx->midVtHd.Append(vone.createdVtHd); } } for(auto hd : edgeMidVtx.AllHandle()) { auto &edgVtxInfo=edgeMidVtx.GetAttrib(hd); if(1<edgVtxInfo.midVtHd.GetN()) { YsArray <double> dist(edgVtxInfo.midVtHd.GetN(),NULL); for(YSSIZE_T idx=0; idx<edgVtxInfo.midVtHd.GetN(); ++idx) { dist[idx]=shl.GetEdgeLength(edgVtxInfo.edge[0],edgVtxInfo.midVtHd[idx]); } YsQuickSort(dist.GetN(),dist.GetEditableArray(),edgVtxInfo.midVtHd.GetEditableArray()); } } }
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; }
void YsShellExt_SewingInfo::MakePolygonSplitInfo(const YsShellExt &shl) { // A concave polygon may be cut twice by one crawling. YsShellPolygonAttribTable <YsArray <YsArray <YsShellVertexHandle,2> > > plHdToDivider(shl.Conv()); for(auto &v : vtxSequence) { if(NULL==v.vtHd) { if(0<=v.vtxOnEdgeIdx) { v.vtHd=vtxOnEdge[v.vtxOnEdgeIdx].createdVtHd; } else if(0<=v.vtxOnPlgIdx) { v.vtHd=vtxOnPlg[v.vtxOnPlgIdx].vtHd; } } } { YsShellPolygonHandle currentPlHd=NULL; YsArray <YsShellVertexHandle,2> currentDivider; for(YSSIZE_T idx=0; idx<vtxSequence.GetN(); ++idx) { if(0==currentDivider.GetN()) { currentPlHd=vtxSequence[idx].plHd; currentDivider.Append(vtxSequence[idx].vtHd); } else { currentDivider.Append(vtxSequence[idx].vtHd); if(idx==vtxSequence.GetN()-1 || vtxSequence[idx].plHd!=currentPlHd) { if(2<=currentDivider.GetN()) { YsArray <YsArray <YsShellVertexHandle,2> > *pldv=plHdToDivider[currentPlHd]; if(NULL==pldv) { YsArray <YsArray <YsShellVertexHandle,2> > newDividerArray(1,NULL); newDividerArray[0].MoveFrom(currentDivider); plHdToDivider.SetAttrib(currentPlHd,newDividerArray); } else { pldv->Append(currentDivider); } } currentDivider.CleanUp(); currentDivider.Append(vtxSequence[idx].vtHd); } currentPlHd=vtxSequence[idx].plHd; } } } for(auto hashHd : plHdToDivider.AllHandle()) { auto plKey=plHdToDivider.GetKey(hashHd); auto plHd=shl.FindPolygon(plKey); auto ÷r=*plHdToDivider[plHd]; YsSegmentedArray <YsArray <YsShellVertexHandle,4>,4> plVtHd(1,NULL); plVtHd[0]=shl.GetPolygonVertex(plHd); for(auto d : divider) { YsArray <YsShellVertexHandle,4> fragment; for(auto &pl : plVtHd) { if(YSOK==YsShellExt_SplitLoopByHandleAndMidNode(pl,fragment,d)) { plVtHd.Append(fragment); break; } } } plgSplit.Increment(); plgSplit.Last().plHd=plHd; plgSplit.Last().plVtHdArray=plVtHd; } }
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; }