/*---------------------------------------------------------------------------------------------------

Hit ctrl-enter to execute.

Description:

	Spherize will take a square image, wrap it around a sphere, and return the resulting image.
	
	Copyright © 1995 Gatan Inc.
	All rights reserved.
	Written by Jacob Wilbrink.
	Modified for RGB by Chris Meyer 3/23/95.
	Annotated by Paul Thomas March 2001
	
	Note: the RGB version doesn't work that well because the range of the data changes
	as its spherized - I make an OK approximation but there are better spherizing algorithms.

------------------------------------------------------------------------------------------------*/

/*	This method performs the spherize function.
	It is passed a source image, it returns the spherized image		*/

Image Spherize( Image patternImage )
{
	// Get the width and height of the source, and ensure it is square
	number width, height
	GetSize( patternImage, width, height )
	if ( width != height )
	{
		Throw( "Spherize: The image has to be square." )
	}
	
	// Create intermediate images
	Image Spherized	   := RealImage( "Spherized",		 4, width, width )
	Image illumination := RealImage( "Illumination", 4, width, width )
	Image warped	   := RealImage( "Warped",		 4, width, width )
	Image zsurface	   := RealImage( "zSurface",	 4, width, width )

	// Find the centre of the source image and determine the sphere radius
	number center = width / 2	
	number radius = center * 0.7
	
	// Specify the lighting vector components, find the resultant magnitude, and normalise
	number xlight = 500
	number ylight = -500
	number zlight = 1000
	number rlight = sqrt( xlight * xlight + ylight * ylight + zlight * zlight )
	xlight /= rlight
	ylight /= rlight
	zlight /= rlight

	// Warp the image into an evenly illuminated sphere 
	warped =	warp(	patternImage, \
						(icol - center) * asin(iradius/radius) * radius / (iradius + .001) + center, \
						(irow - center) * asin(iradius/radius) * radius / (iradius + .001) + center )
	
	// Now generate the z-surface i.e. as if illuminated solely from the z-direction (into the screen)		
	zsurface =	warped > 0 ? \
				sqrt( radius * radius - (icol - center) * (icol -center) - (irow - center) * (irow - center)) : \
				0																							// 

	// Generate the illumination by taking the z-surface and incorporating the x and y illumination
	illumination =	warped > 0 ? \
				(icol - center) * xlight + (irow - center) * ylight + zlight * zsurface : \
				0
	
	// Now combine the lighting and the warped image
	Spherized = illumination > 0 ? illumination * warped : 0

	// normalize the result to 1
	Spherized =	Spherized - min( Spherized )
	Spherized =	Spherized / max( Spherized )

	// And return the image
	return Spherized
}


/*	This method allows Spherize to be applied to an RGB image.  
	It is passed an RGB image and returns the spherized image, calling on the Spherize method as required */

RGBImage SpherizeRGB( RGBImage patternImage )
{
	// Extract the red component of the RGB image source image and call spherize, 
	// scaling the result wrt the red source image and placing in the red channel
	// of an RGB image 'Spherized'
	RealImage temp
	temp = red( patternImage )
	RGBImage Spherized := Spherize( temp ) * ( max( temp ) - min( temp ) ) + min( temp )

	// Repeat for the green component...
	temp = green( patternImage )
	green( Spherized ) = Spherize( temp ) * ( max( temp ) - min( temp ) ) + min( temp )

	//  and again for the blue component. 
	temp = blue( patternImage )
	blue( Spherized ) = Spherize( temp ) * ( max( temp ) - min( temp ) ) + min( temp )

	// Return the RGB image 
	return Spherized
}


// Example of use.
// We use this track to determine the type of the front image.

// Get front image
Image frontImage := GetFrontImage()

// Check if RGB - if so, call SperizeRGB
IF (IsRGBDataType(frontimage, 4))
	ShowImage( SpherizeRGB( frontImage ) )

// Else, call Spherize
ELSE
	ShowImage( Spherize( frontImage ) )
