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;
}
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;
	
}
YSSIZE_T YsShellExt_DuplicateUtil::AddFaceGroup(YsShellExt::FaceGroupHandle fgHd,YSBOOL derived)
{
	const YSSIZE_T newIdx=faceGroupArray.GetN();

	auto &last=faceGroupArray.New();
	last.srcFgHd=fgHd;

	YsArray <YsShellPolygonHandle,4> plHdArray;
	srcShl->GetFaceGroup(plHdArray,fgHd);
	last.polygonArray.Set(plHdArray.GetN(),NULL);
	for(YSSIZE_T plIdx=0; plIdx<plHdArray.GetN(); ++plIdx)
	{
		YsArray <YSSIZE_T> found;
		plHdMap.FindMapping(found,*srcShl,plHdArray[plIdx]);
		if(0<found.GetN())
		{
			last.polygonArray[plIdx]=found[0];
		}
		else
		{
			last.polygonArray[plIdx]=AddPolygon(plHdArray[plIdx],YSTRUE);
		}
	}

	last.attrib=srcShl->GetFaceGroupAttrib(fgHd);
	last.derived=derived;

	fgHdMap.AddMapping(*srcShl,fgHd,newIdx);

	return newIdx;
}
YSSIZE_T YsShellExt_DuplicateUtil::AddVolume(YsShellExt::VolumeHandle vlHd,YSBOOL derived)
{
	const YSSIZE_T newIdx=volumeArray.GetN();

	auto &last=volumeArray.New();
	last.srcVlHd=vlHd;

	YsArray <YsShellExt::FaceGroupHandle,4> fgHdArray;
	srcShl->GetVolume(fgHdArray,vlHd);
	last.faceGroupArray.Set(fgHdArray.GetN(),NULL);
	for(YSSIZE_T plIdx=0; plIdx<fgHdArray.GetN(); ++plIdx)
	{
		YsArray <YSSIZE_T> found;
		fgHdMap.FindMapping(found,*srcShl,fgHdArray[plIdx]);
		if(0<found.GetN())
		{
			last.faceGroupArray[plIdx]=found[0];
		}
		else
		{
			last.faceGroupArray[plIdx]=AddFaceGroup(fgHdArray[plIdx],YSTRUE);
		}
	}

	last.attrib=srcShl->GetVolumeAttrib(vlHd);
	last.derived=derived;

	vlHdMap.AddMapping(*srcShl,vlHd,newIdx);

	return newIdx;
}
YSSIZE_T YsShellExt_DuplicateUtil::AddConstEdge(YsShellExt::ConstEdgeHandle ceHd,YSBOOL derived)
{
	const YSSIZE_T newIdx=constEdgeArray.GetN();

	auto &last=constEdgeArray.New();
	last.srcCeHd=ceHd;

	YsArray <YsShellVertexHandle,4> vtHdArray;
	srcShl->GetConstEdge(vtHdArray,last.isLoop,ceHd);
	last.vertexArray.Set(vtHdArray.GetN(),NULL);
	for(YSSIZE_T vtIdx=0; vtIdx<vtHdArray.GetN(); ++vtIdx)
	{
		YsArray <YSSIZE_T> found;
		vtHdMap.FindMapping(found,*srcShl,vtHdArray[vtIdx]);
		if(0<found.GetN())
		{
			last.vertexArray[vtIdx]=found[0];
		}
		else
		{
			last.vertexArray[vtIdx]=AddVertex(vtHdArray[vtIdx],YSTRUE);
		}
	}

	last.attrib=srcShl->GetConstEdgeAttrib(ceHd);
	last.derived=derived;

	ceHdMap.AddMapping(*srcShl,ceHd,newIdx);

	return newIdx;
}
YSSIZE_T YsShellExt_DuplicateUtil::AddPolygon(YsShellPolygonHandle plHd,YSBOOL derived)
{
	const YSSIZE_T newIdx=polygonArray.GetN();

	auto &last=polygonArray.New();
	last.srcPlHd=plHd;

	YsArray <YsShellVertexHandle,4> plVtHd;
	srcShl->GetPolygon(plVtHd,plHd);
	last.vertexArray.Set(plVtHd.GetN(),NULL);
	for(YSSIZE_T vtIdx=0; vtIdx<plVtHd.GetN(); ++vtIdx)
	{
		YsArray <YSSIZE_T> found;
		vtHdMap.FindMapping(found,*srcShl,plVtHd[vtIdx]);
		if(0<found.GetN())
		{
			last.vertexArray[vtIdx]=found[0];
		}
		else
		{
			last.vertexArray[vtIdx]=AddVertex(plVtHd[vtIdx],YSTRUE);
		}
	}

	last.attrib=(*srcShl->GetPolygonAttrib(plHd));
	srcShl->GetColor(last.col,plHd);
	srcShl->GetNormal(last.nom,plHd);
	last.derived=derived;

	plHdMap.AddMapping(*srcShl,plHd,newIdx);

	return newIdx;
}
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;
}
/* static */ void PolyCreFileName::MakeDirectoryForFile(const wchar_t wfn[])
{
	YsWString ful(wfn),pth,fil;
	ful.SeparatePathFile(pth,fil);
	ful=pth;
	YsArray <YsWString> backTrack;
	for(;;)
	{
		if(ful.LastChar()=='\\' || ful.LastChar()=='/')
		{
			ful.BackSpace();
		}

		printf("%ls\n",ful.Txt());
		backTrack.Append(ful);

		YsWString pth,fil;
		ful.SeparatePathFile(pth,fil);

		if(0<pth.Strlen() && 0<fil.Strlen())
		{
			ful=pth;
		}
		else
		{
			break;
		}
	}

	for(YSSIZE_T idx=backTrack.GetN()-1; 0<=idx; --idx)
	{
		printf("MkDir %ls\n",backTrack[idx].Txt());
		YsFileIO::MkDir(backTrack[idx]);
	}
}
YSRESULT YsThreadController::RunParallel(int nTask,YsThreadTask *task[])
{
	if(0>=nTask)
	{
		return YSOK;
	}

	int i;
	for(i=0; i<nTask; i++)
	{
		task[i]->taskId=i;
		task[i]->sta=YSTHREADTASKSTATE_IDLE;
	}

	if(1==nTask)
	{
		task[0]->EntryPoint();
		return YSOK;
	}

	YsArray <pthread_t,16> hThread;
	hThread.Set(nTask,0);
	for(i=0; i<nTask; i++)
	{
		pthread_create(&hThread[i],NULL,YsPthreadLaunch,(void *)task[i]);
	}
	for(i=0; i<nTask; i++)
	{
		pthread_join(hThread[i],NULL);
	}

	// Do I have to clean threads?  Does pthread_destory exist?

	return YSOK;
}
YSRESULT YsShell::LoadSrf(
    FILE *fp,YsArray <YsShellPolygonHandle> *noShadingPolygon,YsArray <YsShellVertexHandle> *roundVtx)
{
	if(NULL!=fp)
	{
		YsArray <YsString,16> args;

		if(noShadingPolygon!=NULL)
		{
			noShadingPolygon->Set(0,NULL);
		}
		if(roundVtx!=NULL)
		{
			roundVtx->Set(0,NULL);
		}
		if(BeginReadSrf()==YSOK)
		{
			YsString str;
			while(str.Fgets(fp)!=NULL)
			{
				if(ReadSrfOneLine(str,noShadingPolygon,roundVtx)!=YSOK)
				{
					str.Arguments <16> (args);
					if(args.GetN()>0)
					{
						YSBOOL srmExtension;
						srmExtension=YSFALSE;

						args[0].Capitalize();

						switch(args[0][0])
						{
						case 'G':  // GE, GL, GF
						case 'Z':  // ZE, ZF, ZNBE,ZNBF, ZT, ZA, ZZ, ZH, ZU
						case 'Y':  // YE, YF, YN, Y1
						case 'M':  // M
						case 'C':  // CV
						case 'X':  // X
						case 'L':  // LF, LE, LL
							srmExtension=YSTRUE;
							break;
						}

						if(srmExtension!=YSTRUE)
						{
							return YSERR;
						}
					}
				}
			}
			EndReadSrf();
			return YSOK;
		}
	}

	return YSERR;
}
YsArray <YsShellVertexHandle> YsShellExt_SweepInfo::GetVertexAll(void) const
{
	YsArray <YsShellVertexHandle> vtHdArray;
	for(auto vtHd : allSrcVtHd)
	{
		vtHdArray.Append(vtHd);
	}
	return vtHdArray;
}
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]);
				}
			}
		}
	}
}
/* virtual */ void FsLazyWindowApplication::GetOpenWindowOption(FsOpenWindowOption &opt) const
{
	opt.x0=96;
	opt.y0=0;
	opt.wid=1200;
	opt.hei=640;

	auto *cfg=PolyCreConfig::Create();
	auto *fileAndDirName=PolyCreFileName::Create();

	cfg->Load(fileAndDirName->GetOptionFileName());
	if(YSTRUE==cfg->saveWindowPositionAndSize)
	{
		auto wposFn=fileAndDirName->GetLastWindowPositionFileName();

		FILE *fp=YsFileIO::Fopen(wposFn,"r");
		if(NULL!=fp)
		{
			YsString str;
			while(NULL!=str.Fgets(fp))
			{
				YsArray <YsString> args;
				str.Arguments(args);
				if(0==strcmp(args[0],"POS") && 5<=args.GetN())
				{
					opt.x0=atoi(args[1]);
					opt.y0=atoi(args[2]);
					opt.wid=atoi(args[3]);
					opt.hei=atoi(args[4]);
					if(0>opt.x0)
					{
						opt.x0=0;
					}
					if(0>opt.y0)
					{
						opt.y0=0;
					}
					if(120>opt.wid)
					{
						opt.wid=120;
					}
					if(120>opt.hei)
					{
						opt.hei=120;
					}
				}
			}
			fclose(fp);
		}
	}

	PolyCreConfig::Delete(cfg);
	PolyCreFileName::Delete(fileAndDirName);
}
YsArray <YsShellExt::FaceGroupHandle> YsShellExt_DuplicateUtil::GetNonDerivedNewFaceGroup(void) const
{
	YsArray <YsShellExt::FaceGroupHandle> ary;
	for(auto elem : faceGroupArray)
	{
		if(YSTRUE!=elem.derived)
		{
			ary.Append(elem.newFgHd);
		}
	}
	return ary;
}
YsArray <YsShellPolygonHandle> YsShellExt_DuplicateUtil::GetNonDerivedNewPolygon(void) const
{
	YsArray <YsShellPolygonHandle> ary;
	for(auto elem : polygonArray)
	{
		if(YSTRUE!=elem.derived)
		{
			ary.Append(elem.newPlHd);
		}
	}
	return ary;
}
YsArray <YsShellVertexHandle> YsShellExt_DuplicateUtil::GetNonDerivedNewVertex(void) const
{
	YsArray <YsShellVertexHandle> ary;
	for(auto elem : vertexArray)
	{
		if(YSTRUE!=elem.derived)
		{
			ary.Append(elem.newVtHd);
		}
	}
	return ary;
}
YsArray <YsShellExt::VolumeHandle> YsShellExt_DuplicateUtil::GetNonDerivedNewVolume(void) const
{
	YsArray <YsShellExt::VolumeHandle> ary;
	for(auto elem : volumeArray)
	{
		if(YSTRUE!=elem.derived)
		{
			ary.Append(elem.newVlHd);
		}
	}
	return ary;
}
示例#18
0
void YsBoundingBoxMaker2::Make(const YsArray <YsVec2> &ary)
{
	if(ary.GetNumItem()>0)
	{
		Begin(ary.GetItem(0));
	}
	int i;
	for(i=0; i<ary.GetNumItem(); i++)
	{
		Add(ary.GetItem(i));
	}
}
示例#19
0
int YsString::Printf(const char *fom,...)
{
	const int trialBufSize=256;

	char buf[trialBufSize];
	va_list arg_ptr;

	va_start(arg_ptr,fom);
	const int n=vsnprintf(buf,trialBufSize,fom,arg_ptr);
	va_end(arg_ptr);

	if(n<0)
	{
		// This compiler s**ks!  It's not C99 compliant!  (I'm talking about Visual C++ 2008)
		int bufSize=trialBufSize*2;
		YsArray <char> buf;
		for(;;)
		{
			buf.Set(bufSize,NULL);

			va_start(arg_ptr,fom);
			const int n=vsnprintf(buf,bufSize,fom,arg_ptr);
			va_end(arg_ptr);

			if(0<=n && n<bufSize)
			{
				YsArray <char,16>::Set(n+1,buf);
				return n;
			}

			bufSize*=2;
		}
	}
	else if(n<trialBufSize)
	{
		YsArray <char,16>::Set(n+1,buf);
		return n;
	}
	else
	{
		// Good compiler!  It is C99 Compliant.
		char *buf=new char [n+1];
		va_start(arg_ptr,fom);
		vsnprintf(buf,n+1,fom,arg_ptr);
		va_end(arg_ptr);

		YsArray <char,16>::Set(n+1,buf);

		delete [] buf;
		return n;
	}
}
YsArray <const YsShellExt_RoundUtil3d::HalfRoundCorner *> YsShellExt_RoundUtil3d::MakeSortedHalfRoundCorner(const YsShell &shl) const
{
	YsArray <unsigned int> vtKeyArray;
	YsArray <const HalfRoundCorner *> cornerPtrArray;
	for(auto &corner : cornerArray)
	{
		vtKeyArray.Append(shl.GetSearchKey(corner.fromVtHd));
		cornerPtrArray.Append(&corner);
	}

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

	return cornerPtrArray;
}
YSRESULT FsGuiCopyStringFromClipBoard(YsString &str)
{
	const int bufLen=FsGuiGetStringLengthInClipBoardC();
	if(0<bufLen)
	{
		YsArray <char> copyBuf;
		copyBuf.Set(bufLen+1,NULL);
		FsGuiCopyStringFromClipBoardC(copyBuf);
		str.Set(copyBuf);
	}
	else
	{
		str.Set("");
	}
	return YSOK;
}
YsArray <YSSIZE_T> YsShellExt_RoundUtil3d::FindHalfRoundCornerFromPolygon(const YsShell &shl,YsShellPolygonHandle plHd) const
{
	YsArray <YsShellVertexHandle,4> plVtHd;
	shl.GetPolygon(plVtHd,plHd);

	YsArray <YSSIZE_T> idxArray;
	for(YSSIZE_T i=0; i<plVtHd.GetN(); ++i)
	{
		for(YSSIZE_T j=0; j<cornerArray.GetN(); ++j)
		{
			if(plVtHd[i]==cornerArray[j].fromVtHd && YSTRUE==plVtHd.IsIncluded(cornerArray[j].toVtHd))
			{
				idxArray.Append(j);
			}
		}
	}

	return idxArray;
}
YSRESULT YsShellExt_RoundUtil::SetUpRoundPolygon(const YsShell &shl,YsShellPolygonHandle plHd,const YsShellVertexStore *roundVtx)
{
	YsArray <YsShellVertexHandle> plVtHd;
	shl.GetPolygon(plVtHd,plHd);
	for(YSSIZE_T idx=0; idx<plVtHd.GetN(); ++idx)
	{
		const YsShellVertexHandle fromVtHd=plVtHd[idx];
		if(NULL==roundVtx || YSTRUE==roundVtx->IsIncluded(fromVtHd))
		{
			const YsShellVertexHandle toVtHd[2]=
			{
				plVtHd.GetCyclic(idx-1),
				plVtHd.GetCyclic(idx+1)
			};
			AddRoundCorner(shl,fromVtHd,toVtHd);
		}
	}
	targetPlKeyArray.Append(shl.GetSearchKey(plHd));

	return YSOK;
}
/*static*/ void YsShellExtEdit_OrientationUtil::FixOrientationOfClosedSolid(YsShellExtEdit &shl)
{
	YsShellExt_OrientationUtil orientationUtil;
	orientationUtil.CleanUp();
	orientationUtil.FixOrientationOfClosedSolid(shl.Conv());
	auto plHdNeedFip=orientationUtil.GetPolygonNeedFlip();

	for(auto plHd : plHdNeedFip)
	{
		YsArray <YsShellVertexHandle,4> plVtHd;
		shl.GetPolygon(plVtHd,plHd);
		plVtHd.Invert();
		shl.SetPolygonVertex(plHd,plVtHd);
	}

	orientationUtil.RecalculateNormalFromCurrentOrientation(shl.Conv());
	auto plNomPairNeedNormalReset=orientationUtil.GetPolygonNormalPair();
	for(auto plNomPair : plNomPairNeedNormalReset)
	{
		shl.SetPolygonNormal(plNomPair.plHd,plNomPair.nom);
	}
}
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_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);
}
/*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;
}
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);
}
YsArray <YsShellExt_RoundUtil::VertexPositionPair> YsShellExt_RoundUtil::MakeRoundedVertexSequence(const YsShell &shl,YSSIZE_T nVt,const YsShellVertexHandle vtHdArrayIn[],YSBOOL isLoop) const
{
	YsArray <YsShellVertexHandle> orgVtHdArray(nVt,vtHdArrayIn);
	YsArray <VertexPositionPair> newVtHdArray;

	for(YSSIZE_T orgVtIdx=0; orgVtIdx<orgVtHdArray.GetN(); ++orgVtIdx)
	{
		YSBOOL rounded=YSFALSE;
		for(const auto &roundCorner : cornerArray)
		{
			if(roundCorner.fromVtHd==orgVtHdArray[orgVtIdx])
			{
				int forward=0,backward=1;

				if(roundCorner.toVtHd[0]==orgVtHdArray.GetCyclic(orgVtIdx-1))
				{
					forward=1;
					backward=0;
				}
				else if(roundCorner.toVtHd[1]==orgVtHdArray.GetCyclic(orgVtIdx-1))
				{
					forward=0;
					backward=1;
				}
				else
				{
					continue;
				}

				YSBOOL skipFirst=YSFALSE;

				if(0<newVtHdArray.GetN() && newVtHdArray.Last().pos==roundCorner.subDiv[backward].Last().pos)
				{
					skipFirst=YSTRUE;
				}

				newVtHdArray.Append(roundCorner.subDiv[backward]);

				newVtHdArray.Increment();
				newVtHdArray.Last().vtHd=orgVtHdArray[orgVtIdx];
				newVtHdArray.Last().pos=roundCorner.roundedCornerPos;

				for(YSSIZE_T i=roundCorner.subDiv[forward].GetN()-1; 0<=i; --i)
				{
					if(YSTRUE==skipFirst)
					{
						skipFirst=YSFALSE;
						continue;
					}
					newVtHdArray.Append(roundCorner.subDiv[forward][i]);
				}

				rounded=YSTRUE;
			}
		}
		if(YSTRUE!=rounded)
		{
			newVtHdArray.Increment();
			newVtHdArray.Last().vtHd=orgVtHdArray[orgVtIdx];
			newVtHdArray.Last().pos=shl.GetVertexPosition(newVtHdArray.Last().vtHd);
		}
	}

	if(2<=newVtHdArray.GetN() && YSTRUE==isLoop && newVtHdArray[0].pos==newVtHdArray.Last().pos)
	{
		newVtHdArray.DeleteLast();
	}

	return newVtHdArray;
}