
class MSArotateLuncher: MSA112_UIFrame
{
string RotMethod
number deviaSpecICA,MaxIttICA,contrastFunc,deviaSpecVRM,MaxIttVRM

string MSAlabel
number runningRot
number t

number enablingState

TagGroup CreateProgress(object self)
	{
	TagGroup Dialog = DLGCreatedialog("")
		TagGroup Upper = DLGCreatedialog("")
		Upper.DLGTableLayout(3,1,0)
	Upper.DLGAddElement(DLGcreateLabel("  "+MSA112_Version()+"    ").DLGIdentifier("Version"))
	Upper.DLGAddElement(self.InfoButton(20,210))
	Upper.DLGAddElement(self.settingsButton(20,210,"Settings"))
		TagGroup Lower = DLGCreatedialog("")
		Lower.DLGTableLayout(2,1,0)
	Lower.DLGAddElement(DLGcreateLabel("                    ").DLGAnchor("East").DLGIdentifier("Message"))
	Lower.DLGAddElement(DLGcreateLabel("hold ALT for info"))	

	Dialog.DLGAddElement(Upper)
	Dialog.DLGAddElement(Lower)
	Dialog.DLGAddElement(DLGcreateProgressBar("P bar").DLGfill("X"))
	
	return Dialog
	}
	
TagGroup CreateRotationBox(object self)
	{
	TagGroup Dialog = DLGCreateBox("Rotate PCA components").DLGTableLayout(3,4,0)
	
	Dialog.DLGAddElement(DLGCreatePushButton("   ICA    ","RunICA").DLGIdentifier("runICA").DLGanchor("West"))		
	Dialog.DLGAddElement(DLGCreateLabel("").DLGanchor("East"))
	Dialog.DLGAddElement(DLGCreatePushButton("stop","StopRot").DLGIdentifier("stopRotICA").DLGEnabled(0))
	
	Dialog.DLGAddElement(DLGCreatePushButton("varimax","RunVRM").DLGIdentifier("runVRM").DLGanchor("West"))		
	Dialog.DLGAddElement(DLGCreateCheckBox("recenter",0,"ChangeCenter").DLGIdentifier("recenter").DLGanchor("East"))
	Dialog.DLGAddElement(DLGCreatePushButton("stop","StopRot").DLGIdentifier("stopRotVRM").DLGEnabled(0))

	Dialog.DLGAddElement(DLGCreatePushButton("   free   ","RunFree").DLGIdentifier("runFree").DLGanchor("West"))
	Dialog.DLGAddElement(DLGCreatePushButton("erase","eraseFree").DLGanchor("West"))		
	Dialog.DLGAddElement(DLGCreateLabel("       ").DLGanchor("East"))
	


	return Dialog
	}

TagGroup CreateScatterPlot(object self)
	{
	TagGroup Dialog = DLGCreateDialog("Rotate PCA components").DLGTableLayout(5,1,0)

	Dialog.DLGAddElement(DLGCreateLabel("        ").DLGanchor("East"))
	Dialog.DLGAddElement(DLGCreateLabel("        ").DLGanchor("East"))
	Dialog.DLGAddElement(DLGCreateLabel("plot X-Y"))
	Dialog.DLGAddElement(DLGCreateIntegerField(1,3).DLGIdentifier("compF").DLGanchor("West"))
	Dialog.DLGAddElement(DLGCreateIntegerField(2,3).DLGIdentifier("compS").DLGanchor("West"))
	
	return Dialog
	}
	
TagGroup CreateAll(object self)
	{
	TagGroup Dialog = DLGCreatedialog("")
			
	TagGroup Head = DLGCreateDialog("")	
	Head.DLGTableLayout(5,1,0)
	Head.DLGAddElement(DLGCreateLabel("cluster").DLGanchor("East"))
	Head.DLGAddElement(DLGCreateIntegerField(0,3).DLGIdentifier("cluster").DLGanchor("West"))
	Head.DLGAddElement(DLGCreateLabel("max to rotate:").DLGAnchor("East"))
	number defMaxComp =5
	Head.DLGAddElement(DLGCreateIntegerField(defMaxComp,3).DLGIdentifier("maxComponents").DLGanchor("West"))

	Dialog.DLGAddElement(self.CreateProgress())		
	Dialog.DLGAddElement(Head)
	Dialog.DLGAddElement(self.CreateRotationBox())	
	Dialog.DLGAddElement(self.CreateScatterPlot())
	
	return dialog
	}

void EnablingButtons(object self,number state)
	{
	self.SetElementIsEnabled("stopRotICA",state)
	self.SetElementIsEnabled("stopRotVRM",state)	
	}
	
number EnablingAll(object self)	//This is needed for INFO-mode
	{
	self.SetElementIsEnabled("stopRotICA",1)
	self.SetElementIsEnabled("stopRotVRM",1)	
	
	return enablingState
	}

void ChangeCenter(object self, TagGroup tg)
	{
	self.MSA112_InfoBox(tg,"center",270,150,\
	"check this box"+\
	"\nif you desire" +\
	"\nto shift center" +\
	"\nof rotation" )	
	}
		
		
object init(object self,string Package,string Name,string MSAlabelP)
	{
	MSAlabel = MSAlabelP
	self.MSA112_initUIFrame(self.CreateAll(),Package,Name)
		
	//load parameters
	deviaSpecICA = self.MSA112P_ICAdev()
	MaxIttICA = self.MSA112P_ICAitt()
	contrastFunc = self.MSA112P_ICAcontr()
	deviaSpecVRM = self.MSA112P_VRMdev()
	MaxIttVRM = self.MSA112P_VRMitt()
		
	MSA112_reset()
	
	}


/*********************Setting****************************/
void Settings(object self)
	{
	number NumberLines = 5		//number of adjusted parameters
	TagGroup SettingList = DLGCreateBox("Settings").DLGTableLayout(1,NumberLines,1)

	taggroup tg1 =	self.AddSettingsLine_Real(SettingList,self.MSA112P_ICAdev(),7,5)
	taggroup tg2 =	self.AddSettingsLine_Int(SettingList,self.MSA112P_ICAitt(),5)
	taggroup tg3 =	self.AddSettingsLine_Menu(SettingList,self.MSA112P_ICAcontr(),"p3","tanh","exp")
	taggroup tg4 =	self.AddSettingsLine_Real(SettingList,self.MSA112P_VRMdev(),7,5)
	taggroup tg5 =	self.AddSettingsLine_Int(SettingList,self.MSA112P_VRMitt(),5)
	
	
	object SettingsFrame = Alloc(UIframe).init(SettingList)
	if(SettingsFrame.Pose())
		{
		deviaSpecICA = self.SettingNumberParameter(tg1)
		MaxIttICA = self.SettingNumberParameter(tg2)
		contrastFunc = self.SettingNumberParameter(tg3)
		deviaSpecVRM = self.SettingNumberParameter(tg4)
		MaxIttVRM = self.SettingNumberParameter(tg5)	
		}

	}


/*********************Rotation****************************/
void RunICA(object self)
	{
	self.MSA112_Info("ICA",20,120,\
	"rotate PCA"+\
	"\ncomponents" +\
	"\nusing ICA criteria"+\
	"\nin front-most" +\
	"\nMSA container")
	
	if(runningRot==0)
		{
		RotMethod = "ICA"
		
		self.RunThreadFromDLG("ProceedRotation",runningRot,"run"+RotMethod,"stopRot"+RotMethod)
		//Thread name (no parameters);GLOBAL thread running number;start/stop button IDENTIFIERS
		}
	}
	
void RunVRM(object self)
	{
	self.MSA112_Info("varimax",20,150,\
	"rotate PCA"+\
	"\ncomponents" +\
	"\nusing varimax"+\
	"\nin front-most" +\
	"\nMSA container")
	
	if(runningRot==0)
		{
		RotMethod = "VRM"
		number recent =self.LookUpElement("recenter").DLGgetValue()
		if(recent) self.RunThreadFromDLG("ReCenter",runningRot,"run"+RotMethod,"stopRot"+RotMethod)
		else self.RunThreadFromDLG("ProceedRotation",runningRot,"run"+RotMethod,"stopRot"+RotMethod)
		//Thread name (no parameters);GLOBAL thread running number;start/stop button IDENTIFIERS
		}
	}
	
void StopRot(object self)
	{
	self.MSA112_Info("stop",380,100,\
	"press this button"+\
	"\nif something goes" +\
	"\nwrong or if you"+\
	"\nfeel it takes" +\
	"\ntoo much time")
	
	self.StopThreadFromDLG(runningRot,"stopRot"+RotMethod)
	//GLOBAL thread running number; start/stop button IDENTIFIERS
	}	

void TerminateRot(object self,string RotMethod)
	{
	self.TerminateThreadFromDLG(runningRot,"run"+RotMethod,"stopRot"+RotMethod)
	//GLOBAL thread running number; start/stop button IDENTIFIERS
	}

//Both for "ICA" and "VRM"	
void ProceedRotation(object self)
{
number currCluster = self.LookUpElement("cluster").DLGgetValue()
number CompMax = self.LookUpElement("maxComponents").DLGgetValue()
number First = self.LookUpElement("compF").DLGgetValue()
number Second = self.LookUpElement("compS").DLGgetValue()
number sparsity = self.MSA112_LoadParameter(10,"sparsity in X-Y plot")
	
number deviaSpec,maxItt,attempts,Contrast
if(RotMethod=="ICA")
	{
	deviaSpec = deviaSpecICA
	maxItt = maxIttICA
	Contrast = contrastFunc
	}
if(RotMethod=="VRM")
	{
	deviaSpec = deviaSpecVRM
	maxItt = maxIttVRM
	}
	
self.MSA112_UpdateProgress("running",0)	
try
	{	
	//this is what should be done in background
	result("\nproceed "+RotMethod)

	image DataMatrix := getFrontImage()
	string DataName = dataMatrix.getName()
	
	TagGroup MatrixTags = MSA112_GetMatrixTags(dataMatrix,0)
	if(!MatrixTags.TagGroupIsValid()) throw("")
	
	number CompN = MSA112_ReadNumberComponents(MatrixTags,currCluster,"PCA")
	CompN = min(CompN,CompMax) //all availabe but not more than compMax
	
	number Edepth,Points
	number width,height
	MatrixTags.MSA112_GetSISizes(Points,Edepth,width,height)
	
	number origin,disp
	string units
	MatrixTags.MSA112_GetCalibration(disp,origin,units,"E")

	image Cluster:= MatrixTags.MSA112_GetCluster()

	image Components = MSA112_ConfirmComponents(currCluster,currCluster,compMax,MatrixTags,MSAlabel,"rotate")
//Components.showimage()
	
	string ClusterLabel = MSA112_GetClusterLabel(currCluster)
	
	if(!MSA112_CheckComponents(CompN)) throw("")
	
	number CompR = sum(components[0,currCluster,CompMax+1,currCluster+1])

	if(CompR>=2)
		{	
		number steps
		number stepped
	
		number PointsC =MatrixTags.MSA112_GetNumberPoints(currCluster)

		string ReadMethod 
		
		//check if it was recentered
		number recentered =MatrixTags.MSA112_getNumberFromTags(ClusterLabel+":"+RotMethod+":recentered","S") 

		if(recentered) 
			{
			ReadMethod = RotMethod
			result(" RECENTERED PCA")
			}
		else ReadMethod = "PCA"
					
		image Tall :=MatrixTags.MSA112_GetScores(ReadMethod,currCluster)
		image Pall :=MatrixTags.MSA112_GetLoadings(ReadMethod,currCluster)		
//Tall.showimage()
//Pall.showimage()
			
		//selecting rotated components
		image STall :=MSA112_Make2DImageOfRightType(Tall,"T-vectors select",CompR,PointsC)
		image SPall :=MSA112_Make2DImageOfRightType(Pall,"P-vectors select",CompR,Edepth)
			//selected
		image WTall :=MSA112_Make2DImageOfRightType(Tall,"T-vectors select",CompR,PointsC)
			//iterated 
		
		number j
		for(number i=0;i<CompN;i++)
			{	
			if(Components.getPixel(currCluster,i+1))
				{
				STall[0,j,PointsC,j+1] = Tall[0,i,PointsC,i+1]
				SPall[0,j,Edepth,j+1] = Pall[0,i,Edepth,i+1]
				WTall[0,j,PointsC,j+1] = Tall[0,i,PointsC,i+1]
				if(RotMethod=="ICA") WTall[0,j,PointsC,j+1] = WTall[0,j,PointsC,j+1]/mean(WTall[0,j,PointsC,j+1]**2).sqrt()
									//whitening
				j++	
				}				
			}

		image Wall := realimage("Cluster "+currCluster+" rotation",4,CompR,CompR)
			//rotation matrix
		image devia := realImage("",4,1,maxItt+1)
		image Values := realImage("Values",4,1,maxItt+1)			
		image allDevia := realImage("",4,CompR,maxItt+1)
		image allValues := realImage("",4,CompR,maxItt+1)
		image Itterations := integerimage("Iterations",1,0,CompR,1)
		image ValuesFin := realImage("Values",4,CompR,1)

		image ICAmatrix = MatrixTranspose(WTall) //only rotated components are there		
//ICAmatrix.showimage()

		Wall.showimage()

/* *******ICA******** */
		
		if(RotMethod=="ICA")
			{	
			steps = CompR+1
			stepped = 0
result("\nsteps "+steps)	
//result("\nk "+k)
			number p
			for(p=1;p<=CompR;p++)
				{
	self.MSA112_ThreadMarkStart(stepped/steps,""+currCluster+": rotated "+p,"\nrotated component "+p+"':",t)	
				number Nitt 
				devia=0
				Values =0

				Nitt = MSA112_FindICAcomponent(ICAmatrix,p,Wall,Values,devia,Contrast,deviaSpec,maxItt)
				number Kurt = Values.getPixel(0,Nitt)
	result(" itt:"+Nitt+", Kurtosis:"+Kurt+"; devia: "+devia.getPixel(0,Nitt))
					
				Itterations.setpixel(p-1,0,Nitt)
				allDevia[0,p-1,Nitt+1,p] = devia[0,0,NItt+1,1]	
				allValues[0,p-1,Nitt+1,p] = Values[0,0,Nitt+1,1]
	stepped++
	self.MSA112_ThreadMarkEnd(runningRot," ",t)
	
				ValuesFin.setPixel(p-1,0,Kurt)
				
				if(Nitt==MaxItt)		
					{
					result(" no convergence\nfurther component will be only orthogonilized")
					break;
					}			
				}	
			
			//if convergence broken, the rest component are only orthogonalized, not ICAed
			if(p<CompR)
				{
				//result("\np "+p)
				for(number pp=(p+1);pp<=CompR;pp++)
					{
	self.MSA112_ThreadMarkStart(stepped/steps,""+currCluster+": rotated "+pp,"\nrotated component "+pp+"':",t)	
	//result("\npp "+pp)
					image Wvec = MSA112_randomvector(CompR)
					MSA112_GramSchmidtStep(Wvec,Wall).MSA112_NormalizeVector()
					Wall[0,pp-1,CompR,pp] = Wvec

					number Kurt = MSA112_Kurtosis(MatrixMultiply(MatrixTranspose(Wvec),ICAMatrix)**2)
					ValuesFin.setPixel(pp-1,0,Kurt)
					result(" itt: #Kurtosis:"+Kurt)
						
	stepped++
	self.MSA112_ThreadMarkEnd(runningRot," ",t)
					}
				}			

			//reordering ICA
			image ValuesMod = modulus(ValuesFin)
			allDevia = MSA112_ResortDescending(allDevia,ValuesMod)
			allValues = MSA112_ResortDescending(allValues,ValuesMod)
			Itterations = MSA112_ResortDescending(Itterations,ValuesMod)
			Wall = MSA112_ResortDescending(Wall,ValuesMod)
			ValuesFin = MSA112_ResortDescending(ValuesFin,ValuesMod)
result("\nAll rotated components are reordered.")
			}


/* ****Varimax****** */
//result("\ndeviaSpecVRM "+deviaSpecVRM)
		if(RotMethod=="VRM")
			{	
			steps = MSA112_combination(CompR)*3 +1//3 iterations assumed
			stepped = 0 
			
			Wall = tert(icol==irow,1,0)
			number VRMold
			for(number iter=1;iter<=maxIttVRM;iter++)
				{
result("\niteration "+iter);
	
				number fimax
				for(number p=1;p<CompR;p++)
					{				
					for(number pp=(p+1);pp<=CompR;pp++)
						{
self.MSA112_ThreadMarkStart(stepped/steps,"iteration "+iter+": rotate "+p+"-"+pp,"\nrotate "+p+"-"+pp,t)						
						image score1 = WTall[0,p-1,PointsC,p]						
						image score2 = WTall[0,pp-1,PointsC,pp]				
					number fi = MSA112_VRMangle(score1,score2,deviaSpec)
					if(fi>pi()/4) fi -= pi()/2
					MSA112_rotate(fi,score1,score2)					
						WTall[0,p-1,PointsC,p] = score1
						WTall[0,pp-1,PointsC,pp] = score2
result(" angle "+fi*57.2958);	
			
						image Wrot1:= realimage("",4,1,2)
						image Wrot2:= realimage("",4,1,2)
						Wrot1.setPixel(0,0,Wall.getPixel(p-1,p-1))
			 			Wrot1.setPixel(0,1,Wall.getPixel(p-1,pp-1))
						Wrot2.setPixel(0,0,Wall.getPixel(pp-1,p-1))
						Wrot2.setPixel(0,1,Wall.getPixel(pp-1,pp-1))				
					MSA112_rotate(fi,Wrot1,Wrot2)									
						Wall.setPixel(p-1,p-1,Wrot1.getPixel(0,0))
						Wall.setPixel(p-1,pp-1,Wrot1.getPixel(0,1))
						Wall.setPixel(pp-1,p-1,Wrot2.getPixel(0,0))
						Wall.setPixel(pp-1,pp-1,Wrot2.getPixel(0,1))
						
						if(modulus(fi)>modulus(fimax)) fimax = fi	
	stepped++
	self.MSA112_ThreadMarkEnd(runningRot," ",t)					
						}										
					}
										
				allDevia.setPixel(0,iter,fimax)
				number VRMcrit = MSA112_VRMCriteria(MatrixMultiply(WTall,Wall))										
	result("\n  max angle "+fimax*57.2958+" simplicity "+ VRMcrit);
				AllValues.setPixel(0,iter,VRMcrit)					

				number diff = (VRMcrit-VRMold)/VRMold
				if(modulus(diff)<deviaSpecVRM)	
					{
					itterations.setpixel(0,0,iter)
					break
					}			
				VRMold = VRMcrit
				}
			}
		
		//restoring the full components
		image RPall:= realimage(RotMethod+"-vectors",4,CompN,Edepth)
		image RTall:= realimage(RotMethod+"-scores",4,CompN,PointsC)
		image RValues := realImage(" Kurtosis",4,CompN,1)
		j=0
		for(number i=0;i<CompN;i++)
			{
			if(Components.getPixel(currCluster,i+1))
				{
				RTall[0,i,Points,i+1] = MatrixMultiply(STall[0,0,Points,CompR],Wall[0,j,CompR,j+1]) 
				RPall[0,i,Edepth,i+1] = MatrixMultiply(SPall[0,0,Edepth,CompR],Wall[0,j,CompR,j+1]) 
				RValues.setPixel(i,0,ValuesFin.getPixel(j,0))
				j++
				}
			else
				{
				RTall[0,i,Points,i+1] = Tall[0,i,Points,i+1] 
				RPall[0,i,Edepth,i+1] = Pall[0,i,Edepth,i+1]
			 	if(RotMethod=="ICA")
					{
					number Kurt = MSA112_Kurtosis(Tall[0,i,Points,i+1]**2)
					result("\nfixed component "+i+" Kurtosis:"+Kurt)
					RValues.setPixel(i,0,Kurt)
					}			
				}
			}
//RTall[0,0,Nc,1].matrixtranspose().showimage()	
		
		image ClusterComponents = components[0,currCluster,CompN+1,currCluster+1]
		
		// store   tags
		MatrixTags.MSA112_setNumberInTags(ClusterLabel+":"+RotMethod+":required precision","F",deviaSpecICA)
		MatrixTags.MSA112_setNumberInTags(ClusterLabel+":"+RotMethod+":max iterations","I",maxItt)
		MatrixTags.MSA112_setNumberInTags(ClusterLabel+":"+RotMethod+":number components","S",CompN)
		MatrixTags.MSA112_setNumberInTags(ClusterLabel+":"+RotMethod+":number rot components","S",CompR)
		MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+RotMethod+":Components",ClusterComponents)
		MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+RotMethod+":Loadings",RPall)
		MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+RotMethod+":Scores",RTall)
		MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+RotMethod+":Valuesflow",allValues)
		MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+RotMethod+":Precisions",allDevia)
		MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+RotMethod+":Iterations",Itterations)
		MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+RotMethod+":Eigenvalues",RValues)
		MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+RotMethod+":Rotation",Wall)				
		MatrixTags.MSA112_setNumberInTags(ClusterLabel+":"+RotMethod+":recentered","S",0) 

		if(RotMethod=="ICA")
			{//show kurtosis
			MSA112_DisplayEigenValues(RValues,"Cluster "+currCluster+ " Kurtosis",RotMethod,ClusterComponents)
			}
				
		//Plot loadings
		image AvSpec :=MatrixTags.MSA112_GetAverageSpectrum(currCluster)
		AvSpec.ImageSetName("cluster "+currCluster)
		AvSpec.ImageSetDimensionCalibration(0,origin,disp,units,1)

		if(CompN>10)  CompN=10 //not overload display
		DataName = left(DataName,len(DataName)-4)	//remove MSA
	
		MSA112_DisplayLoads(AvSpec,RPall,1,CompN,DataName+" LOAD("+CurrCluster+")",RotMethod,ClusterComponents)

self.MSA112_ThreadMarkStart(stepped/steps,"making scatterplot","\nscatterplot ",t)							
		//make scatterplot 	
		image scatter := MSA112_PlotXY(MatrixTags,CurrCluster,RotMethod,First,Second,sparsity)
		scatter.showimage()
		scatter.setName(DataName+" SP "+First+"-"+Second+"("+currCluster+") "+RotMethod)
						
		}
	else 
		{
result("\ncluster "+currCLuster+":no enough components to rotate")
		throw("")
		}
			
self.MSA112_UpdateProgress(RotMethod+" performed",0)
	}
catch 
	{
	self.MSA112_UpdateProgress("stopped",0)
	self.TerminateRot(RotMethod)
	break
	}

self.TerminateRot(RotMethod)
}
	
void ReWriteLoadingsAndScores(object self,taggroup MatrixTags,string ReadMethod,string writeMethod,string MSAlabel\
,number CurrCluster,number First,number Second,number ShiftX,number ShiftY,number fi)
	{
	string 	clusterLabel = MSA112_GetClusterLabel(currCluster)
	
	number kPoints =MatrixTags.MSA112_GetNumberPoints(currCluster)
	number Depth =MatrixTags.MSA112_getNumberFromTags(MSAlabel+":energy depth","L")
	
	number CompN = MSA112_ReadNumberComponents(MatrixTags,currCluster,ReadMethod)
result("\nkPoints "+kPoints+" m "+CompN+" depth "+depth+ " method "+ReadMethod+" shift ("+ShiftX+" "+ShiftY+")"+" fi "+fi)
	//load score and loadings	
	image Tall :=MatrixTags.MSA112_getScores(ReadMethod,currCluster)
	image Pall :=MatrixTags.MSA112_getLoadings(ReadMethod,currCluster)
	image AverSpec := MSA112_GetAverageSpectrum(MatrixTags,CurrCluster,ReadMethod)

	image Score1 = Tall[0,First-1,kPoints,First] - ShiftX
	image Score2 = Tall[0,Second-1,kPoints,Second] - ShiftY
	
	if((fi!=0))
		{
		image Score11 = Score1.imageclone()	
		Score1 = Score1*cos(fi) + Score2*sin(fi)
		Score2 = -Score11*sin(fi)+Score2*cos(fi)	
		}
		
	image Load1 = Pall[0,First-1,depth,First]
	image Load2 = Pall[0,Second-1,depth,Second]
	image Load11 = Load1.imageclone()		
	AverSpec += ShiftX*Load1.MatrixTranspose()
	AverSpec += ShiftY*Load2.MatrixTranspose()
	Load1 = Load1*cos(fi) + Load2*sin(fi)
	Load2 = -Load11*sin(fi)+ Load2*cos(fi)

	Tall[0,First-1,kPoints,First] = Score1 
	Tall[0,Second-1,kPoints,Second] = Score2 
	Pall[0,First-1,depth,First] = Load1
	Pall[0,Second-1,depth,Second] = Load2
	
	MatrixTags.MSA112_setNumberInTags(ClusterLabel+":"+writeMethod+":number components","S",CompN)	
	MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+writeMethod+":Scores",Tall)	
	MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+writeMethod+":Loadings",Pall)
	MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+writeMethod+":Average Spectrum",AverSpec)
	}

void RunFreeRotation(object self)
	{
	self.SetElementIsEnabled("runFree",0)
	
	number CurrCluster = self.LookUpElement("cluster").DLGgetValue()
	number First = self.LookUpElement("compF").DLGgetValue()
	number Second = self.LookUpElement("compS").DLGgetValue()
	number sparsity = self.MSA112_LoadParameter(10,"sparsity in X-Y plot")
	
	image MSAimage := getFrontImage()
	string DataName = MSAimage.getName()
	TagGroup MatrixTags = MSA112_GetMatrixTags(MSAimage,0)	
	if(!MatrixTags.TagGroupIsValid()) 
		{
		self.SetElementIsEnabled("runFree",1)
		exit(0)
		}
	
	string 	clusterLabel = MSA112_GetClusterLabel(currCluster)
	
	//fresh rotation or tune previous
	string readMethod = "free"
	number CompN = MSA112_ReadNumberComponents(MatrixTags,currCluster,readMethod)
	if(CompN<=0)
		{
		readMethod = "PCA"
		CompN = MSA112_ReadNumberComponents(MatrixTags,currCluster,readMethod)
		if(!MSA112_CheckComponents(CompN)) 
			{
			self.SetElementIsEnabled("runFree",1)
			throw("")
			}
		}
		
	//make scatterplot 	
	image scatter := MSA112_PlotXY(MatrixTags,CurrCluster,ReadMethod,First,Second,sparsity)
	scatter.showimage()
	DataName = left(DataName,len(DataName)-4)	//remove MSA
	scatter.setName(DataName+" SP "+First+"-"+Second+"("+currCluster+") "+ReadMethod)
	//MSA112_StoreGlobalID(MSAimage,Scatter,MSAlabel)	
	imagedisplay disp = scatter.ImageGetImageDisplay(0)	
	number width,height
	scatter.getSize(width,height)
	number scale,originX,originY
	string unit
	scatter.ImageGetDimensionCalibration(0,originX,scale,unit,1)
	scatter.ImageGetDimensionCalibration(1,originY,scale,unit,1)
		
	//make arrow
		number top = originY
		number left = originX
		number bottom = top
		number right = left+width/4
		number AxisID = CreateArrowAnnotation(scatter,top,left,bottom,right)
		component Axis = disp.ComponentGetChildbyID(AxisID)
		Axis.ComponentSetFillMode(1)
		Axis.ComponentSetForegroundColor(256,0,0)
		Axis.ComponentSetBackgroundColor(256,0,0)

	//make loading viewer
	number depth =	MatrixTags.MSA112_getNumberFromTags(MSAlabel+":energy depth","L") 
	
	number dispersion,OriginE
	string units
	MatrixTags.MSA112_GetCalibration(dispersion,originE,units,"E")

//result("\ndispersion"+dispersion+" OriginE "+OriginE)
	image Pall :=MatrixTags.MSA112_getLoadings(ReadMethod,currCluster)
	image Load1 = matrixTranspose(Pall[0,First-1,depth,First])
	image Load2 = matrixTranspose(Pall[0,Second-1,depth,Second])
	Load1.ImageSetDimensionCalibration(0,OriginE,dispersion,units,1)
	object Viewer = alloc(MSA_LoadingViewer).init(scatter,AxisID,Load1,Load2);
	scatter.ImageGetOrCreateImageDocument().ImageDocumentGetWindow().WindowSelect()
	
			TagGroup RecenterDialog = DLGCreateDialog("")
			TagGroup MessageT = DLGCreateLabel("Orient the arrow along the\ndesired direction of new axis !\nArrow's starting point will\nmark the rotation center.")		
			RecenterDialog.DLGAddElement(MessageT)
	number Dleft =-50
	number Dtop	 =280	
	if(!MSA112_Confirm(self,RecenterDialog,"choose direction","Rotate","Cancel",Dleft,Dtop))
		{
		//scatter.deleteimage();
		self.SetElementIsEnabled("runFree",1)
		exit(0);
		}		
	//get new axis 
	scatter.getannotationrect(AxisID, top, left, bottom, right)
	number fi = atan2(bottom-top,right-left)
	number shiftX = (left-originX)*scale
	number shiftY = (top -originY)*scale

result("\nfi "+fi*57.2958+" shiftX "+shiftX+" shiftY "+shiftY)
	scatter.deleteimage()
	
	//rewrite score and loadings
	string writeMethod = "free"
	self.ReWriteLoadingsAndScores(MatrixTags,readMethod,writeMethod,MSALabel,CurrCluster,First,Second,shiftX,ShiftY,fi)
	
	//write components
	image Components := integerimage("Components",1,0,1,CompN+1)
	Components.setPixel(0,First,1)
	Components.setPixel(0,Second,1)
	MatrixTags.MSA112_setImageInTags(ClusterLabel+":"+writeMethod+":Components",Components)

	//make new scatterplot
	scatter := MSA112_PlotXY(MatrixTags,CurrCluster,WriteMethod,First,Second,sparsity)
	scatter.setName(DataName+" SP "+First+"-"+Second+"("+currCluster+") "+" free")
	scatter.showimage()
	
	
	self.SetElementIsEnabled("runFree",1)
//MatrixTags.TagGroupDeleteTagWithLabel(ClusterLabel+":"+Method)
	}

void RunFree(object self) 
	{
	self.MSA112_Info("free",20,170,\
	"rotate PCA"+\
	"\ncomponents" +\
	"\nfreely by hand"+\
	"\nusing indicated"+\
	"\nscatter plot"+\
	"\nin front-most" +\
	"\nMSA container")
	
	self.startThread("RunFreeRotation")
	}
	
void eraseFree(object self) 
	{
	self.MSA112_Info("erase",320,170,\
	"erase previously"+\
	"\nfound free directions" +\
	"\nto start from scratch"+\
	"\nin front-most" +\
	"\nMSA container")
	
	image MSAimage := getFrontImage()
	//string DataName = MSAimage.getName()
	TagGroup MatrixTags = MSA112_GetMatrixTags(MSAimage,0)
	if(!MatrixTags.TagGroupIsValid()) exit(0)
		
	if(OkCancelDialog("Do you really want to delete the free rotation info ?"))
		{
		number CurrCluster = self.LookUpElement("cluster").DLGgetValue()
		string 	clusterLabel = MSA112_GetClusterLabel(currCluster)
		
		MatrixTags.TagGroupDeleteTagWithLabel(ClusterLabel+":free")
		}
	}

	
void ReCenter(object self)
	{
	number CurrCluster = self.LookUpElement("cluster").DLGgetValue()
	number First = self.LookUpElement("compF").DLGgetValue()
	number Second = self.LookUpElement("compS").DLGgetValue()
	number sparsity = self.MSA112_LoadParameter(10,"sparsity in X-Y plot")

	image MSAimage := getFrontImage()
	string DataName = MSAimage.getName()
	TagGroup MatrixTags = MSA112_GetMatrixTags(MSAimage,0)
	
	if(!MatrixTags.TagGroupIsValid()) 
		{
		self.SetElementIsEnabled("stopRot"+RotMethod,1)
		exit(0)
		}
	string 	clusterLabel = MSA112_GetClusterLabel(currCluster)
	
	//fresh rotation or tune previous
	string ReadMethod = "PCA"
	number CompN = MSA112_ReadNumberComponents(MatrixTags,currCluster,ReadMethod)
	if(!MSA112_CheckComponents(CompN)) throw("")
	//make scatterplot 	
	image  scatter := MSA112_PlotXY(MatrixTags,CurrCluster,ReadMethod,First,Second,sparsity)
	scatter.showimage()
	DataName = left(DataName,len(DataName)-4)	//remove MSA
	scatter.setName(DataName+" SP "+First+"-"+Second+"("+currCluster+") "+ReadMethod)
	//MSA112_StoreGlobalID(MSAimage,Scatter,MSAlabel)	
	imagedisplay disp = scatter.ImageGetImageDisplay(0)	
	number width,height
	scatter.getSize(width,height)
	number scale,originX,originY
	string unit
	scatter.ImageGetDimensionCalibration(0,originX,scale,unit,1)
	scatter.ImageGetDimensionCalibration(1,originY,scale,unit,1)
	
	//make oval
	number radius = 5
	number top = originY - radius
	number left = originX - radius
	number bottom = originY +radius
	number right = originX + radius
	number CentID = CreateOvalAnnotation(scatter,top,left,bottom,right)
	component Cent = disp.ComponentGetChildbyID(CentID)
	Cent.ComponentSetFillMode(1)
	Cent.ComponentSetForegroundColor(256,0,0)
	Cent.ComponentSetBackgroundColor(256,0,0)
	Cent.ComponentSetResizable(0)
	
			TagGroup RecenterDialog = DLGCreateDialog("")
			TagGroup MessageT = DLGCreateLabel("Place the oval where you want\nthe new rotation center.")		
			RecenterDialog.DLGAddElement(MessageT)
	number Dleft =-50
	number Dtop	 =250	
	if(!MSA112_Confirm(self,RecenterDialog,"recenter","New center","Cancel",Dleft,Dtop))
		{
		scatter.deleteimage();
		self.TerminateRot("VRM")
		exit(0);
		}	
	
	//get new Center
	scatter.getannotationrect(CentID, top, left, bottom, right)
	number shiftX = ((left+right)/2-originX)*scale
	number shiftY = ((top+bottom)/2 -originY)*scale

result("\nshiftX "+shiftX+" shiftY "+shiftY)
	scatter.deleteimage()

	//rewrite score and loadings	
	string WriteMethod = rotMethod

	self.ReWriteLoadingsAndScores(MatrixTags,ReadMethod,WriteMethod,MSALabel,CurrCluster,First,Second,shiftX,ShiftY,0)
	MatrixTags.MSA112_setNumberInTags(ClusterLabel+":"+WriteMethod+":recentered","S",1) 

	//call rotation thread
	self.ProceedRotation()
	} 

number MSA112_AboutToCloseUIFrame(object self,number verify) 
	{
	self.SetInfoMode(0)

	try{self.TerminateRot(RotMethod);}
	catch{break;}

	return 1
	}	
	
}



void createAll()
{
alloc(MSArotateLuncher).init(MSA112_MSApath(),"MSA rotation","temDM MSA") 
}

createAll()