YSRESULT YsShellExt_RoundUtil3d::CalculateRoundingDirectionAll(const YsShell &shl)
{
	YsArray <HalfRoundCorner *> cornerPtrArray=MakeSortedHalfRoundCorner(shl);

	YsArray <HalfRoundCorner *> cornerPerVertex;
	for(YSSIZE_T idx=0; idx<cornerPtrArray.GetN(); ++idx)
	{
		cornerPerVertex.Append(cornerPtrArray[idx]);
		if(cornerPtrArray.GetN()-1==idx || cornerPtrArray[idx]->fromVtHd!=cornerPtrArray[idx+1]->fromVtHd)
		{
			const YsVec3 roundDir=CalculateRoundingDirction(shl,cornerPerVertex);
			if(YsOrigin()==roundDir)
			{
				return YSERR;
			}
			for(auto ptr : cornerPerVertex)
			{
				ptr->roundDir=roundDir;
			}
			cornerPerVertex.CleanUp();
		}
	}

	return YSOK;
	
}
YSRESULT YsShellExt_RoundUtil3d::CalculateRoundingAll(const YsShell &shl,const double radius)
{
	YsArray <unsigned int> vtKeyArray;
	YsArray <HalfRoundCorner *> cornerPtrArray;
	for(auto &corner : cornerArray)
	{
		vtKeyArray.Append(shl.GetSearchKey(corner.fromVtHd));
		cornerPtrArray.Append(&corner);
	}

	YsQuickSort <unsigned int,HalfRoundCorner *> (vtKeyArray.GetN(),vtKeyArray,cornerPtrArray);

	YsArray <HalfRoundCorner *> cornerPerVertex;
	for(YSSIZE_T idx=0; idx<cornerPtrArray.GetN(); ++idx)
	{
		cornerPerVertex.Append(cornerPtrArray[idx]);
		if(cornerPtrArray.GetN()-1==idx || vtKeyArray[idx]!=vtKeyArray[idx+1])
		{
			if(YSOK!=CalculateRoundingPerVertex(shl,cornerPerVertex,radius))
			{
				return YSERR;
			}
			cornerPerVertex.CleanUp();
		}
	}

	return YSOK;
}
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 &divider=*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;
	}
}