YSRESULT YsShellExt_RoundUtil3d::SetUpForVertexSequence( const YsShellExt &shl, YSSIZE_T nVt,const YsShellVertexHandle vtHdArray[]) { CleanUp(); if(2>nVt || YSTRUE!=shl.IsSearchEnabled()) { return YSERR; } YSSIZE_T nEdPl; const YsShellPolygonHandle *edPlHd; if(YSOK==shl.FindPolygonFromEdgePiece(nEdPl,edPlHd,vtHdArray[0],vtHdArray[1]) && 2==nEdPl) { YsArray <YsShellPolygonHandle> sideAPolygonArray=YsShellExt_TrackingUtil::TrackPolygonOneSideOfVertexSequence( shl,nVt,vtHdArray,1,edPlHd); YsArray <YsShellPolygonHandle> sideBPolygonArray=YsShellExt_TrackingUtil::TrackPolygonOneSideOfVertexSequence( shl,nVt,vtHdArray,1,edPlHd+1); if(0==sideAPolygonArray.GetN() || 0==sideBPolygonArray.GetN()) { return YSERR; } YsArray <YsArray <YsShellVertexHandle> > allBoundary(1,NULL); allBoundary[0].Set(nVt,vtHdArray); return YsShellExt_RoundUtil3d::SetUpForVertexSequenceAndPolygonArray(shl,allBoundary,sideAPolygonArray,sideBPolygonArray); } return YSERR; }
/* static */ void FsLazyWindowApplication::YsShellToVtxNom(std::vector <float> &vtx,std::vector <float> &nom,std::vector <float> &col,const YsShellExt &shl) { vtx.clear(); nom.clear(); col.clear(); for(auto plHd : shl.AllPolygon()) { auto plVtHd=shl.GetPolygonVertex(plHd); if(3<=plVtHd.GetN()) { auto plNom=shl.GetNormal(plHd); for(auto vtHd : plVtHd) { auto vtPos=shl.GetVertexPosition(vtHd); vtx.push_back(vtPos.xf()); vtx.push_back(vtPos.yf()); vtx.push_back(vtPos.zf()); nom.push_back(plNom.xf()); nom.push_back(plNom.yf()); nom.push_back(plNom.zf()); col.push_back(0); col.push_back(0); col.push_back(1); col.push_back(0.5); } } } }
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_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_SweepInfo::MakeInfo( const YsShellExt &shl, YSSIZE_T nPl,const YsShellPolygonHandle plHdArray[], YSSIZE_T nCe,const YsShellExt::ConstEdgeHandle ceHdArray[]) { CleanUp(); YsShellExt_BoundaryInfo::MakeInfo(*(const YsShell *)&shl,nPl,plHdArray); allSrcVtHd.SetShell((const YsShell &)shl); for(YSSIZE_T idx=0; idx<nPl; ++idx) { YsArray <YsShellVertexHandle,4> plVtHd; shl.GetPolygon(plVtHd,plHdArray[idx]); for(auto vtHd : plVtHd) { allSrcVtHd.AddVertex(vtHd); } } for(YSSIZE_T idx=0; idx<nCe; ++idx) { YsArray <YsShellVertexHandle,4> ceVtHd; YSBOOL isLoop; shl.GetConstEdge(ceVtHd,isLoop,ceHdArray[idx]); for(auto vtHd : ceVtHd) { allSrcVtHd.AddVertex(vtHd); } } for(YSSIZE_T ceIdx=0; ceIdx<nCe; ++ceIdx) { YSBOOL isLoop; YsArray <YsShellVertexHandle,16> ceVtHd; shl.GetConstEdge(ceVtHd,isLoop,ceHdArray[ceIdx]); if(2<=ceVtHd.GetN()) { if(YSTRUE==isLoop) { YsShellVertexHandle first=ceVtHd[0]; ceVtHd.Append(first); } for(int edIdx=0; edIdx<ceVtHd.GetN()-1; ++edIdx) { if(YSTRUE!=visited.IsIncluded(ceVtHd[edIdx],ceVtHd[edIdx+1])) { visited.AddEdge(ceVtHd[edIdx],ceVtHd[edIdx+1]); srcEdVtHd.Append(ceVtHd[edIdx]); srcEdVtHd.Append(ceVtHd[edIdx+1]); } } } } }
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; }
/*static*/ YsArray <double> YsShellExt_SweepInfoMultiStep::CalculateScalingForParallelSweepWithPathAndGuideLine( const YsShellExt &shl,const YsVec3 &sweepDir,const YsArray <YsShellVertexHandle> &pathVtHdArray,const YsArray <YsShellVertexHandle> &guideVtHdArray) { YsArray <YsVec3> pathVtPosArray,guideVtPosArray; for(auto vtHd : pathVtHdArray) { pathVtPosArray.Append(shl.GetVertexPosition(vtHd)); } for(auto vtHd : guideVtHdArray) { guideVtPosArray.Append(shl.GetVertexPosition(vtHd)); } return CalculateScalingForParallelSweepWithPathAndGuideLine(sweepDir,pathVtPosArray,guideVtPosArray); }
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(); } } }
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; }
void FsLazyWindowApplication::VtxNomToYsShell(YsShellExt &shl,const std::vector <float> &vtx,const std::vector <float> &nom) { PrepareLatticeForConnection(ltc,vtx); shl.CleanUp(); for(int i=0; i<vtx.size()/9; ++i) { const YsVec3 plNom(nom[i*9],nom[i*9+1],nom[i*9+2]); const YsVec3 vtPos[3]= { YsVec3(vtx[i*9 ],vtx[i*9+1],vtx[i*9+2]), YsVec3(vtx[i*9+3],vtx[i*9+4],vtx[i*9+5]), YsVec3(vtx[i*9+6],vtx[i*9+7],vtx[i*9+8]), }; YsShell::VertexHandle vtHd[3]; for(int i=0; i<3; ++i) { vtHd[i]=nullptr; auto idx=ltc.GetBlockIndex(vtPos[i]); if(true==ltc.IsInRange(idx)) { for(auto tstVtHd : ltc.Elem(idx.x(),idx.y(),idx.z())) { if(shl.GetVertexPosition(tstVtHd)==vtPos[i]) { vtHd[i]=tstVtHd; break; } } } if(nullptr==vtHd[i]) { vtHd[i]=shl.AddVertex(vtPos[i]); if(true==ltc.IsInRange(idx)) { ltc.Elem(idx.x(),idx.y(),idx.z()).push_back(vtHd[i]); } } } YsShell::PolygonHandle plHd; plHd=shl.AddPolygon(3,vtHd); shl.SetPolygonNormal(plHd,plNom); } }
YSRESULT YsShellExt_SewingInfo::MakeInfo(const YsShellExt &shl,YSSIZE_T nVt,const YsShellVertexHandle vtHd[]) { if(0<nVt) { YsArray <YsVec3> pathPnt(nVt,NULL); for(YSSIZE_T idx=0; idx<nVt; ++idx) { pathPnt[idx]=shl.GetVertexPosition(vtHd[idx]); } return MakeInfoWithVertexHandle(shl,vtHd[0],nVt,pathPnt,vtHd); } return YSERR; }
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; }
YSRESULT YsShellExt_SewingInfo::MakeInfoWithVertexHandle( const YsShellExt &shl,YsShellVertexHandle vtHdFrom, YSSIZE_T nPathIn,const YsVec3 pathPntIn[],const YsShellVertexHandle pathVtHdIn[]) { // if(NULL!=goalVtHd), goalVtHd must be at path[nPath-1]. if(0>=nPathIn) { return YSERR; } if(0<nPathIn && pathPntIn[0]==shl.GetVertexPosition(vtHdFrom)) { return MakeInfoWithVertexHandle(shl,vtHdFrom,nPathIn-1,pathPntIn+1,pathVtHdIn+1); } YsConstArrayMask <YsVec3> pathPnt(nPathIn,pathPntIn); YsConstArrayMask <YsShellVertexHandle> pathVtHd(nPathIn,pathVtHdIn); CleanUp(); YsShellVertexHandle currentVtHd=vtHdFrom; YsShell::Edge currentEdge(NULL,NULL); YsShellPolygonHandle currentPlHd=NULL; YsVec3 currentPos=shl.GetVertexPosition(vtHdFrom); for(YSSIZE_T idx=0; idx<pathPnt.GetN(); ++idx) { if(YSOK!=CrawlOneSegment( currentVtHd,currentEdge,currentPlHd,currentPos,shl,pathPnt[idx],pathVtHd[idx])) { return YSERR; } } return YSOK; }
YsShell::PolygonHandle FsLazyWindowApplication::PickedTriangle(int mx,int my) const { YsVec3 o,v; drawEnv.TransformScreenCoordTo3DLine(o,v,mx,my); YsShell::PolygonHandle picked=nullptr; double pickedDist=0.0; for(auto plHd : shl.AllPolygon()) { auto plVtHd=shl.GetPolygonVertex(plHd); const YsVec3 tri[3]= { shl.GetVertexPosition(plVtHd[0]), shl.GetVertexPosition(plVtHd[1]), shl.GetVertexPosition(plVtHd[2]), }; YsPlane pln; pln.MakePlaneFromTriangle(tri[0],tri[1],tri[2]); YsVec3 itsc; if(YSOK==pln.GetIntersection(itsc,o,v)) { auto side=YsCheckInsideTriangle3(itsc,tri); if(YSINSIDE==side || YSBOUNDARY==side) { auto dist=(itsc-o)*v; // Gives distance if(0.0<dist && (picked==nullptr || dist<pickedDist)) { picked=plHd; pickedDist=dist; } } } } return picked; }
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_SewingInfo::MakeInfo(const YsShellExt &shl,YsShellVertexHandle vtHdFrom,YsShellVertexHandle vtHdTo) { const YsVec3 pathPnt[1]={shl.GetVertexPosition(vtHdTo)}; const YsShellVertexHandle pathVtHd[1]={vtHdTo}; return MakeInfoWithVertexHandle(shl,vtHdFrom,1,pathPnt,pathVtHd); }
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_RoundUtil3d::SetUpForAroundPolygonGroup( const YsShellExt &shl, YSSIZE_T nPl,const YsShellPolygonHandle plHdArray[]) { CleanUp(); if(YSTRUE!=shl.IsSearchEnabled()) { YsPrintf("%s\n",__FUNCTION__); YsPrintf(" This function requires a search table.\n"); return YSERR; } YsShellExt_BoundaryInfo boundary; boundary.MakeInfo((const YsShell &)shl,nPl,plHdArray); if(YSOK!=boundary.CacheContour((const YsShell &)shl)) { return YSERR; } YsShellPolygonStore sideAPolygon((const YsShell &)shl),sideBPolygon((const YsShell &)shl); sideAPolygon.AddPolygon(nPl,plHdArray); YsArray <YsShellPolygonHandle> sideAPolygonArray(nPl,plHdArray),sideBPolygonArray; YsShellEdgeStore boundaryEdge((const YsShell &)shl); for(YSSIZE_T contourIdx=0; contourIdx<boundary.GetNumContour(); ++contourIdx) { YsArray <YsShellVertexHandle> contourVtHd; boundary.GetContour(contourVtHd,contourIdx); if(3<=contourVtHd.GetN()) { if(contourVtHd[0]!=contourVtHd.Last()) { const YsShellVertexHandle vtHd0=contourVtHd[0]; contourVtHd.Append(vtHd0); } for(YSSIZE_T vtIdx=0; vtIdx<contourVtHd.GetN()-1; ++vtIdx) { boundaryEdge.AddEdge(contourVtHd[vtIdx],contourVtHd[vtIdx+1]); YSSIZE_T nVtPl; const YsShellPolygonHandle *vtPlHd; shl.FindPolygonFromVertex(nVtPl,vtPlHd,contourVtHd[vtIdx]); for(YSSIZE_T plIdx=0; plIdx<nVtPl; ++plIdx) { if(YSTRUE!=sideAPolygon.IsIncluded(vtPlHd[plIdx]) && YSTRUE!=sideBPolygon.IsIncluded(vtPlHd[plIdx])) { sideBPolygon.AddPolygon(vtPlHd[plIdx]); sideBPolygonArray.Append(vtPlHd[plIdx]); } } } } } return SetUpForVertexSequenceAndPolygonArray( shl, boundary.GetContourAll(), sideAPolygonArray, sideBPolygonArray); }
void FsLazyWindowApplication::CacheBoundingBox(void) { shl.GetBoundingBox(min,max); }
YSRESULT YsShellExt_SweepInfoMultiStep::SetUpNonParallelSweepWithPath(const YsShellExt &shl,YSSIZE_T nPathVt,const YsShellVertexHandle pathVtHdArrayIn[],YSBOOL isLoop,const double scaling[],ORIENTATION_CONTROL_TYPE oriconTypeMid,ORIENTATION_CONTROL_TYPE oriconTypeLast) { YsArray <YsShellVertexHandle> pathVtHd(nPathVt,pathVtHdArrayIn); for(auto idx=pathVtHd.GetN()-1; 0<idx; --idx) { if(pathVtHd[idx]==pathVtHd[idx-1]) { pathVtHd.Delete(idx); } } if(0<pathVtHd.GetN() && pathVtHd.Last()==pathVtHd[0]) { pathVtHd.DeleteLast(); isLoop=YSTRUE; } if(2>pathVtHd.GetN() || (YSTRUE==isLoop && 3>pathVtHd.GetN())) { return YSERR; } const auto &allVtHd=GetVertexAll(); YsArray <YsVec3> iniPos; for(auto vtHd : allVtHd) { iniPos.Append(shl.GetVertexPosition(vtHd)); } YsVec3 lfpNom; if(YSOK!=YsFindLeastSquareFittingPlaneNormal(lfpNom,iniPos)) { return YSERR; } if(0.0>lfpNom*(shl.GetVertexPosition(pathVtHd[1])-shl.GetVertexPosition(pathVtHd[0]))) { lfpNom=-lfpNom; } YsArray <YsVec3> nomArray(nPathVt,NULL); nomArray[0]=lfpNom; for(YSSIZE_T idx=1; idx<nPathVt-1; ++idx) { switch(oriconTypeMid) { case ORICON_PREVIOUS_SEGMENT: nomArray[idx]=YsUnitVector(shl.GetVertexPosition(pathVtHd[idx])-shl.GetVertexPosition(pathVtHd[idx-1])); break; case ORICON_NEXT_SEGMENT: nomArray[idx]=YsUnitVector(shl.GetVertexPosition(pathVtHd[idx+1])-shl.GetVertexPosition(pathVtHd[idx])); break; case ORICON_AVERAGE_ANGLE: { auto v1=YsUnitVector(shl.GetVertexPosition(pathVtHd[idx])-shl.GetVertexPosition(pathVtHd[idx-1])); auto v2=YsUnitVector(shl.GetVertexPosition(pathVtHd[idx+1])-shl.GetVertexPosition(pathVtHd[idx])); nomArray[idx]=YsUnitVector(v1+v2); } break; case ORICON_FROMPREVPOINT_TO_NEXTPOINT: nomArray[idx]=YsUnitVector(shl.GetVertexPosition(pathVtHd[idx+1])-shl.GetVertexPosition(pathVtHd[idx-1])); break; } } switch(oriconTypeLast) { case ORICON_PREVIOUS_SEGMENT: case ORICON_NEXT_SEGMENT: nomArray.Last()=YsUnitVector(shl.GetVertexPosition(pathVtHd[nPathVt-1])-shl.GetVertexPosition(pathVtHd[nPathVt-2])); break; case ORICON_AVERAGE_ANGLE: // There's no next point case ORICON_FROMPREVPOINT_TO_NEXTPOINT: // There's no next point if(YSTRUE==isLoop) { YsVec3 v1=YsUnitVector(shl.GetVertexPosition(pathVtHd[0])-shl.GetVertexPosition(pathVtHd[nPathVt-1])); YsVec3 v2=YsUnitVector(shl.GetVertexPosition(pathVtHd[nPathVt-1])-shl.GetVertexPosition(pathVtHd[nPathVt-2])); v1.Normalize(); v2.Normalize(); nomArray.Last()=YsUnitVector(v1+v2); } else { nomArray.Last()=YsUnitVector(shl.GetVertexPosition(pathVtHd[nPathVt-1])-shl.GetVertexPosition(pathVtHd[nPathVt-2])); } break; } return SetUpNonParallelSweepWithPath(shl,nPathVt,pathVtHd,isLoop,nomArray,scaling); }
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; }
YSRESULT YsShellExt_SewingInfo::MakeInfo(const YsShellExt &shl,YsShellVertexHandle fromVtHd,const YsVec3 &passPnt,YsShellVertexHandle toVtHd) { YsVec3 p[2]={passPnt,shl.GetVertexPosition(toVtHd)}; YsShellVertexHandle v[2]={NULL,toVtHd}; return MakeInfoWithVertexHandle(shl,fromVtHd,2,p,v); }