/*static*/ YsArray <double> YsShellExt_SweepInfoMultiStep::CalculateScalingForParallelSweepWithPathAndGuideLine(
    const YsVec3 &sweepDir,const YsArray <YsVec3> &pathArray,const YsArray <YsVec3> &guideArray)
{
	if(1>=pathArray.GetN() || 1>=guideArray.GetN())
	{
		YsArray <double> empty;
		return empty;
	}

	YsArray <double> scaling(pathArray.GetN(),NULL);
	for(auto &s : scaling)
	{
		s=1.0;
	}

	for(auto pathIndex : pathArray.AllIndex())
	{
		auto &s=scaling[pathIndex];
		auto &pathPnt=pathArray[pathIndex];

		const YsPlane cutPln(pathPnt,sweepDir);
		YSBOOL done=YSFALSE;
		for(auto &guidePos : guideArray)
		{
			if(YSTRUE==cutPln.CheckOnPlane(guidePos))
			{
				s=(guidePos-pathPnt).GetLength();
				done=YSTRUE;
				break;
			}
		}

		if(YSTRUE!=done)
		{
			for(auto guideIndex : guideArray.AllIndex())
			{
				if(guideIndex<guideArray.GetN()-1)
				{
					auto &pos0=guideArray[guideIndex];
					auto &pos1=guideArray[guideIndex+1];

					YsVec3 itsc;
					if(YSOK==cutPln.GetPenetrationHighPrecision(itsc,pos0,pos1))
					{
						s=(itsc-pathPnt).GetLength();
						done=YSTRUE;
						break;
					}
					else if(0==guideIndex)
					{
						if(YSOK==cutPln.GetIntersection(itsc,pos0,pos1-pos0) &&
						   (0.0<(itsc-pos0)*(pos0-pos1) || 2==guideArray.GetN()))  // If guideArray consists of only two points, which side of line doesn't matter.
						{
							s=(itsc-pathPnt).GetLength();
							done=YSTRUE;
							break;
						}
					}
					else if(guideArray.GetN()-2==guideIndex)
					{
						if(YSOK==cutPln.GetIntersection(itsc,pos0,pos1-pos0) &&
						   0.0<(itsc-pos1)*(pos1-pos0))
						{
							s=(itsc-pathPnt).GetLength();
							done=YSTRUE;
							break;
						}
					}
				}
			}
		}
	}

	const double ref=scaling[0];
	for(auto &s : scaling)
	{
		s/=ref;
	}
	scaling[0]=1.0;

	return scaling;
}
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;
}