void MaterialExpressionClasses::InitMaterialExpressionClasses()
{
	if( !bInitialized )
	{
		UMaterialEditorOptions* TempEditorOptions = NewObject<UMaterialEditorOptions>();
		UClass* BaseType = UMaterialExpression::StaticClass();
		if( BaseType )
		{
			TArray<UStructProperty*>	ExpressionInputs;
			const UStruct*				ExpressionInputStruct = GetExpressionInputStruct();

			for( TObjectIterator<UClass> It ; It ; ++It )
			{
				UClass* Class = *It;
				if( !Class->HasAnyClassFlags(CLASS_Abstract | CLASS_Deprecated) )
				{
					if( Class->IsChildOf(UMaterialExpression::StaticClass()) )
					{
						ExpressionInputs.Empty();

						// Exclude comments from the expression list, as well as the base parameter expression, as it should not be used directly
						if ( Class != UMaterialExpressionComment::StaticClass() 
							&& Class != UMaterialExpressionParameter::StaticClass() )
						{
							FMaterialExpression MaterialExpression;
							// Trim the material expression name and add it to the list used for filtering.
							static const FString ExpressionPrefix = TEXT("MaterialExpression");
							FString ClassName = *Class->GetName();
							if (ClassName.StartsWith(ExpressionPrefix, ESearchCase::CaseSensitive))
							{
								ClassName = ClassName.Mid(ExpressionPrefix.Len());
							}
							MaterialExpression.Name = ClassName;
							MaterialExpression.MaterialClass = Class;

							AllExpressionClasses.Add(MaterialExpression);

							// Initialize the expression class input map.							
							for( TFieldIterator<UStructProperty> InputIt(Class) ; InputIt ; ++InputIt )
							{
								UStructProperty* StructProp = *InputIt;
								if( StructProp->Struct == ExpressionInputStruct )
								{
									ExpressionInputs.Add( StructProp );
								}
							}

							// See if it is in the favorites array...
							for (int32 FavoriteIndex = 0; FavoriteIndex < TempEditorOptions->FavoriteExpressions.Num(); FavoriteIndex++)
							{
								if (Class->GetName() == TempEditorOptions->FavoriteExpressions[FavoriteIndex])
								{
									FavoriteExpressionClasses.AddUnique(MaterialExpression);
								}
							}

							// Category fill...
							UMaterialExpression* TempObject = Cast<UMaterialExpression>(Class->GetDefaultObject());
							if (TempObject)
							{
								if (TempObject->MenuCategories.Num() == 0)
								{
									UnassignedExpressionClasses.Add(MaterialExpression);
								}
								else
								{
									for (int32 CategoryIndex = 0; CategoryIndex < TempObject->MenuCategories.Num(); CategoryIndex++)
									{
										FCategorizedMaterialExpressionNode* CategoryNode = GetCategoryNode(TempObject->MenuCategories[CategoryIndex], true);
										check(CategoryNode);

										CategoryNode->MaterialExpressions.AddUnique(MaterialExpression);
									}
								}
							}
						}
					}
				}
			}
		}

		struct FCompareFMaterialExpression
		{
			FORCEINLINE bool operator()( const FMaterialExpression& A, const FMaterialExpression& B ) const
			{
				return A.Name < B.Name;
			}
		};
		AllExpressionClasses.Sort(FCompareFMaterialExpression());
		struct FCompareFCategorizedMaterialExpressionNode
		{
			FORCEINLINE bool operator()( const FCategorizedMaterialExpressionNode& A, const FCategorizedMaterialExpressionNode& B ) const
			{
				return A.CategoryName.CompareTo(B.CategoryName) < 0;
			}
		};
		CategorizedExpressionClasses.Sort( FCompareFCategorizedMaterialExpressionNode() );

		bInitialized = true;
	}
}
void CUnitVolumeMakerDlg::GetImage(int iWidth, int iLength, int iHeight, int iZ,
								 EZoomOut eZoomOutLevel)
{
	int nCol;
	int nX, nY, nZ;
	int nRibbonWidth;
	int nImageWidth;
	int nRightWidth;
	int nTotalWidth;
	QString strPathName, strImageFileName, strImageVolPathName, strImage4VolFileName;
	
	nRibbonWidth = qRound(float(m_TissueBlock.m_Ribbon.m_nWidth)/eZoomOutLevel);
	nCol = (int)((m_TissueBlock.m_UnitCube.m_nWidth*iWidth)/nRibbonWidth);
	nX = nRibbonWidth - (nRibbonWidth*(nCol+1)-(iWidth*m_TissueBlock.m_UnitCube.m_nWidth));
	nY = iLength*m_TissueBlock.m_UnitCube.m_nLength;
	nZ = iHeight*m_TissueBlock.m_UnitCube.m_nHeight;
	strPathName = QString(tr("%1%2%3/%4/")
			.arg(sINIT_DATA_DIR).arg(sZOOM_OUT_DIR_PREFIX).arg(eZoomOutLevel).arg(nCol));
	strImageFileName.sprintf("%05d%s", nZ+eZoomOutLevel*iZ, sDATA_FILE_FORMAT);
		
	nRightWidth = nRibbonWidth - nX;
	
	if(nRightWidth > m_TissueBlock.m_UnitCube.m_nWidth)
	{
		nImageWidth = qMin(m_TissueBlock.m_UnitCube.m_nWidth, nRibbonWidth);
	}
	else
	{
		nImageWidth = nRightWidth;
	}
	
	// extract nX, nY, nImageWidth, m_TissueBlock.m_UnitCube.m_nLength
	//...
	qDebug() << "nX: " << nX << ", nY: " << nY << ", nImageWidth: " << nImageWidth << "\n";
	ui.listWidgetResult->addItem(tr("nCol: %1, nX: %2, nY: %3, nImageWidth: %4").arg(nCol).arg(nX).arg(nY).arg(nImageWidth));
	ui.listWidgetResult->addItem(strPathName);
	ui.listWidgetResult->addItem(strImageFileName);
	
	// source image filename (full path)
	QString strFileName = strPathName + strImageFileName;
	
	/////////////////////////
	// read an image
	// typedef
	
	typedef unsigned char PixelType;
	const unsigned int nDimension = 2;
	typedef itk::Image<PixelType, nDimension> ImageType;
	typedef itk::ImageFileReader<ImageType> ReaderType;
	typedef itk::ImageFileWriter<ImageType> WriterType;
	//typedef itk::RegionOfInterestImageFilter<ImageType, ImageType> ROIFilterType;
	typedef itk::ImageRegionConstIterator< ImageType > ConstIteratorType;
	typedef itk::ImageRegionIterator< ImageType>       IteratorType;

	/////////////////////////////////////
	// input: a region of a source image 
	ImageType::RegionType InputRegion;
	ImageType::RegionType::IndexType InputStart;
	ImageType::RegionType::SizeType  InputSize;
	
	InputStart[0] = nX;
	InputStart[1] = nY;
	
	InputSize[0]  = nImageWidth;
	InputSize[1]  = m_TissueBlock.m_UnitCube.m_nLength;
	
	InputRegion.SetSize( InputSize );
	InputRegion.SetIndex( InputStart );
	
	/////////////////////////////////////
	// output: a region of a output image 
	ImageType::RegionType OutputRegion, OutputSubRegion;
	ImageType::RegionType::IndexType OutputStart;
	ImageType::RegionType::SizeType  OutputSize;

	OutputStart[0] = 0;
	OutputStart[1] = 0;
	OutputSize[0]  = m_TissueBlock.m_UnitCube.m_nWidth; //InputSize[0];
	OutputSize[1]  = m_TissueBlock.m_UnitCube.m_nLength; //InputSize[1];

	OutputRegion.SetSize( OutputSize );
	OutputRegion.SetIndex( OutputStart );

	OutputSize[0]  = InputSize[0];
	OutputSize[1]  = InputSize[1];

	OutputSubRegion.SetSize( OutputSize );
	OutputSubRegion.SetIndex( OutputStart );

	bool bErrorInSourceImage = false;

	/////////////////////////////////////
	// read the source image
	ReaderType::Pointer pReader = ReaderType::New();
	pReader->SetFileName(strFileName.toStdString());
	try
	{
	    pReader->Update();
	}
	catch ( itk::ExceptionObject &err)
	{
	    std::cerr << "ExceptionObject caught !" << std::endl; 
	    std::cerr << err << std::endl; 
	    bErrorInSourceImage = true;
	    //return; // -1;
	}

	// Check that the region is contained within the input image.
	if(!pReader->GetOutput()->GetRequestedRegion().IsInside( InputRegion ) )
	{
	    std::cerr << "Error" << std::endl;
	    std::cerr << "The region " << InputRegion << "is not contained within the input image region "
	              << pReader->GetOutput()->GetRequestedRegion() << std::endl;
	    bErrorInSourceImage = true;
	    //return; // -1;
	}
	
	////////////////////////////////////
	// prepare the output
	ImageType::Pointer pOutputImage = ImageType::New();
	pOutputImage->SetRegions( OutputRegion );
	pOutputImage->Allocate();

	///////////////////////////////////
	// fill buffer with initial value
	ImageType::PixelType  InitialValue = nDEF_BG_COLOR;
	pOutputImage->FillBuffer( InitialValue );
	
	/////////////////////////////////////////////////////////////////////////
	// get pixels from the source image file and put them into the output image file
	if(bErrorInSourceImage != true)
	{
		ConstIteratorType InputIt(   pReader->GetOutput(), InputRegion  );
		IteratorType      OutputIt(  pOutputImage,         OutputSubRegion );
	
		for(InputIt.GoToBegin(), OutputIt.GoToBegin(); !InputIt.IsAtEnd(); ++InputIt, ++OutputIt)
		{
		    OutputIt.Set(InputIt.Get());
		}
	}

	nTotalWidth = nImageWidth;

	while(nTotalWidth < m_TissueBlock.m_UnitCube.m_nWidth)
	{
		nCol++;
		if(nCol == m_TissueBlock.m_nNumCol)
			break;
		nX = 0;
		nImageWidth = m_TissueBlock.m_UnitCube.m_nWidth - nTotalWidth;
		if(nImageWidth > nRibbonWidth)
		{
			nImageWidth = nRibbonWidth;
		}
	
		strPathName = QString(tr("%1%2%3/%4/")
				.arg(sINIT_DATA_DIR).arg(sZOOM_OUT_DIR_PREFIX).arg(eZoomOutLevel).arg(nCol));
		strImageFileName.sprintf("%05d%s", nZ+eZoomOutLevel*iZ, sDATA_FILE_FORMAT);

		// extract nX, nY, nImageWidth, m_TissueBlock.m_UnitCube.m_nLength
		// for display
		qDebug() << "nX: " << nX << ", nY: " << nY << ", nImageWidth: " << nImageWidth << "\n";
		ui.listWidgetResult->addItem(tr("nCol: %1, nX: %2, nY: %3, nImageWidth: %4").arg(nCol).arg(nX).arg(nY).arg(nImageWidth));
		ui.listWidgetResult->addItem(strPathName);
		ui.listWidgetResult->addItem(strImageFileName);
		// source image filename (full path)
		strFileName = strPathName + strImageFileName;
		
		// set input size
		InputStart[0] = nX;
		InputStart[1] = nY;
		
		InputSize[0]  = nImageWidth;
		InputSize[1]  = m_TissueBlock.m_UnitCube.m_nLength;
		
		InputRegion.SetSize( InputSize );
		InputRegion.SetIndex( InputStart );
		
		OutputSize[0]  = InputSize[0];
		OutputSize[1]  = InputSize[1];

		ImageType::RegionType::IndexType OutputStartSub;
		OutputStartSub[0] = nTotalWidth;
		OutputStartSub[1] = 0;
		OutputSubRegion.SetSize( OutputSize );
		OutputSubRegion.SetIndex( OutputStartSub );

		bErrorInSourceImage = false;
		/////////////////////////////////////
		// read the source image
		//ReaderType::Pointer pReader = ReaderType::New();
		pReader->SetFileName(strFileName.toStdString());
		try
		{
		    pReader->Update();
		}
		catch ( itk::ExceptionObject &err)
		{
		    std::cerr << "ExceptionObject caught !" << std::endl; 
		    std::cerr << err << std::endl; 
		    bErrorInSourceImage = true;
		    //return; // -1;
		}

		// Check that the region is contained within the input image.
		if(!pReader->GetOutput()->GetRequestedRegion().IsInside( InputRegion ) )
		{
		    std::cerr << "Error" << std::endl;
		    std::cerr << "The region " << InputRegion << "is not contained within the input image region "
		              << pReader->GetOutput()->GetRequestedRegion() << std::endl;
		    bErrorInSourceImage = true;
		    //return; // -1;
		}
		
		////////////////////////////////////
		// prepare the output
		//ImageType::Pointer pOutputImage = ImageType::New();
		//pOutputImage->SetRegions( OutputRegion );
		//pOutputImage->Allocate();
		if(bErrorInSourceImage != true)
		{
			ConstIteratorType InputIt(   pReader->GetOutput(), InputRegion  );
			IteratorType      OutputIt(  pOutputImage,         OutputSubRegion );
	
			for(InputIt.GoToBegin(), OutputIt.GoToBegin(); !InputIt.IsAtEnd(); ++InputIt, ++OutputIt)
			{
			    OutputIt.Set(InputIt.Get());
			}
		}
		
		nTotalWidth += nImageWidth;

	}
	
	/////////////////////////////////////////////////////////
	// get an output image file name (full path)
	strImageVolPathName = QString(tr("%1%2%3/%4/")
			.arg(sINIT_DATA_DIR).arg(sZOOM_OUT_DIR_PREFIX).arg(eZoomOutLevel).arg(sVOL_DIR_PREFIX));
	QString strVolDir;
	strVolDir.sprintf("%03d_%03d_%03d", iWidth, iLength, iHeight);
	strVolDir = strImageVolPathName + strVolDir;
	QDir dir;
	dir.mkdir(strImageVolPathName);
	dir.mkdir(strVolDir);
	strImage4VolFileName.sprintf("%03d_%03d_%03d/%05d%s", 
			iWidth, iLength, iHeight, nZ+eZoomOutLevel*iZ, sDATA_FILE_FORMAT);
	strImage4VolFileName = strImageVolPathName + strImage4VolFileName;

	/////////////////////////////////
	// write an output image
	WriterType::Pointer pWriter = WriterType::New();
	pWriter->SetFileName(strImage4VolFileName.toStdString());
	pWriter->SetInput( pOutputImage );

	try
	{
		pWriter->Update();
	}
	catch ( itk::ExceptionObject &err)
	{
	    std::cerr << "ExceptionObject caught !" << std::endl; 
	    std::cerr << err << std::endl; 
	    return; // -1;   
	}

}