Hexbased CA Script-Kokkugia

From scripting
Jump to: navigation, search

http://www.kokkugia.com/wiki/scriptLibrary/mel/CA_Script.mel

https://web-beta.archive.org/web/20100401000000*/http://www.kokkugia.com/wiki/scriptLibrary/mel/CA_Script.mel



/*	this series of scripts creates a hex-grid cellular automaton and a springs net which can be driven by the 'brains'
	of the cellular automaton.  these two things were created in order to then act as an input for the distortion of
	far more complex geometries in the formation of a facade or screen wall element.

	created by roland snooks and dave pigram fall 2005
	(parts of the code use the logic of cory clarke's - life.mel - nthd.org)
	
	this version last modified: 28 october 2005

	procedures:
		
	there are four main procedures which can be run independantly.
	each of these main procedures calls a second series of procedures shown indented below (a full description of all
	procedures follws):
	
	- hexCA_create
	- hexCA_run
			- hexCA_check
			- life_keyframe
			- hexCA_status
	- springCA_create
			- springCA_attach
	- hex_associate
			
	example of appropriate inputs: 

	hexCA_create		20 10 1 30;			(int $xSize, int $ySize, float $hexSize, float $randCut)
	hexCA_run			20 10 20 1;			(int $xSize, int $ySize, int $steps, int $proliferate)
	springCA_create 	20 10 1;			(int $xSize, int $ySize, float $hexSize)
	hex_associate		0.08;				(float $scale)

	description of input variables:
	
	$xSize 			= the number of hexagons in the x-axis numbered left to right
	$ySize 			= the number of hexagons in the y-axis numbered top to bottom
	$hexSize		= the shortest distance from edge to edge of the chosen hexagon size
	$randCut		= the percentage (as an integer between 1 and 100) of the hex-grid that starts at full size
					  (the remainding cells start at the minimum size)
	$proliferate	= 0 or 1 switches between modes of proliferation (of copies of generations):
					  0 = no proliferation (any other integer besides 1 will also result in no proliferation)
					  1 = proliferation in a stack along the z axis (perpendicular to the 2 CA dimensions x and y)
	$scale			= a scale factor to tune the spring length inputs of the hex_associate procedure to the particular
					  characteristics of the springs net

	full descriptions of all procedures:
	
	- hexCA_create
	creates a hex-grid $xSize by $ySize with each hexagon $hexSize wide and numbers all the cells logically.  an initial
	state is also generated by randomly switching a percentage ($randCut) of cells to the maximum size.
	this procedure must be run before the hexCA_run or the life_keyframe, or else these procedures will have no meaning.
	
	- hexCA_run
	as the name indicates, this procedure uses a pre-determined rule-set to calculate and represent future generational
	states for the the hex-grid (from its initial state) generated by the hexCA_create procedure.  for each hex-cell in
	turn this procedure calls the hexCA_check procedure which checks the size of all adjacent cells (its 'neigbours' - 
	including itself) the average size is returned and then compared against a series of axiomatic conditions. if the 
	average of the result is too high the cell 'dies' due to 'overcrowding'; if it is too low the cell 'dies' of 
	'loneliness'.  in this case 'dying' means becoming zero scale, there is nothing to prevent the cell being 're-born'
	in a future generation. if the cell survives the initial culling process it then adopts the average size of its
	neighbours and itself.
	
	all calculations are done on a per-generation basis i.e the calcualtions for all cells are completed before any
	size changes are made, then the process is repeated after all scaling is complete.
	
	lastly, as the above described system has a tendency towards an even distribution of middle-sized cells, an additional
	'switch' has been added as a means of re-injecting 'energy' or disequilibrium into the system.  when the average size
	of a hex-cells neighbours approaches the middle of the possible range that cell is either given a maximum or minimum
	scale in the next generation.  if the avaerage is slightly less than the middle the cell gets a maximum size; when the 
	average is slightly higher it receives a minimum scale.
	
			- hexCA_check
			as described above this procedure is called by the hexCA-run procedure, with the average of all neighbouring cell sizes
			returned (becoming $tmp) to the the hexCA_run script. 
			
			- life_keyframe
			this procedure is also called by the hexCA-run procedure, it adds keyframes so that the CA can be watched changing
			states as an animation.  the keyframes occur at set intervals and represent each complete generation.  the set interval
			between keyfames is equal to the $frameNoPerCalc variable which can be found at the beginning of the hexCA_run procedure.
			
			- hexCA_status
			a very simple procedure which literally returns the value of the .status attribute for a particular hex-cell when called
			by the hexCA_run procedure.
	
	- springCA_create
	this procedure creates a cube on every node of an $xSize x $ySize hex-grid.  each cube is named according to the
	adjacent hex-cells from top to bottom and from left to right.  the hex-cells are also named from top to bottom and
	from left to right in the form: hex_$y_$x  where $y is the row number and $x is the cell number within that row.
		
	example:
	the cube named:	"cube1_1__1_2__2_1"	is between hec-cells: "hex_1_1" , "hex_1_2" and "hex_2_1"
		
			- springCA_attach
			this procedure is called by the springCA_create procedure and attaches springs to cubes that represent each vertex
			of a $xSize x $ySize hex-grid the cubes are created by the springCA_create script - the inputs are $xSize and $ySize.
			for every spring a line is drawn in the same place for later use in diagrams and animations.
		
	- hex_associate
	this procedure calculates the average scale of the two hexes which are adjacent to all internal springs and then uses this value
	to set that springs rest length.  when the simulation is played the springs attempt to find the new equilibrium state for network
	thus distorting the previously regular hex-grid geometry.
	through experience this operation is most successful when the cubes on the outside edge of the springs net are set to active = 0 (off).
					  
					  
	note: the programming style adopted priveledges readablility and maintainability rather than pure code efficiency
	this approach was selected both because the script is being created and edited by two people and because the 
	intention is that certain sections of code can be cut out as modules for use in future projects.
*/


//____________________________________________________________________________________________________________________
global proc hexCA_create (int $xSize, int $ySize, float $hexSize, float $randCut){

	// if uncommented these lines select and delete all objects and keyframes remaining from previous iterations
/*
	select -all;
	delete;
*/
	//loop for each cell row following $ySize

	int $y = 0;
	while ($y < $ySize){

		//loop for each cell column following $xSize		

		int $x = 0;
		while ($x < $xSize){

			// set up values for moving each created hex-grid object to its correct place in the hex-grid
			// a check of oddness, fascilitates the staggering of every second row to the right
			// $stagger will equal zero for the even rows, and half $hexSize for the odd rows 
			
			int $isOdd 	= $y%2;
			float $stagger	= $isOdd * $hexSize/2;
			float $moveX 	= $x*$hexSize + $stagger;
			float $moveY	= $y*$hexSize*-cosd(30);

			//create a unique name for each object that refers to its position

			$name 		= "hex_" + $y + "_" + $x;

			//create the object, give it the unique name and then move it into position

			float $radius 	= abs(($hexSize/2)/cosd(30));
 
			$tmp 		= `circle -n $name -c 0 0 0 -nr 0 0 1 -sw 360 -r $radius -d 1 -ut 0 -tol 0.1 -s 6 -ch 1`;

			move $moveX $moveY 0;

			// add custom attributes that will store information about the hex-grid object

			addAttr -ln status 	-at double  $name; 
			addAttr -ln oncount -at double  $name;
 
			// the following section of code was used to connect the CA to different geometry based on clusters earlier
			// in the project - it remains (commented out) to facilitate a possible renewal of the exploration into that
			// type of geometry 
				
			// set driven keys - assign the scale of the hex cell to the scale of the clusters
/*
			setAttr ($name + ".scaleX") 1;
			setAttr ("cluster_" + $y + "_" + $x + ".scaleX") 1;
			setAttr ("cluster_" + $y + "_" + $x + ".scaleY") 1;
			setAttr ("cluster_" + $y + "_" + $x + ".scaleZ") 1;

			setDrivenKeyframe -cd ($name + ".scaleX") ("cluster_" + $y + "_" + $x + ".scaleX");
			setDrivenKeyframe -cd ($name + ".scaleX") ("cluster_" + $y + "_" + $x + ".scaleY");
			setDrivenKeyframe -cd ($name + ".scaleX") ("cluster_" + $y + "_" + $x + ".scaleZ");

			setAttr ($name + ".scaleX") 0;
			setAttr ("cluster_" + $y + "_" + $x + ".scaleX") 0;
			setAttr ("cluster_" + $y + "_" + $x + ".scaleY") 0;
			setAttr ("cluster_" + $y + "_" + $x + ".scaleZ") 0;

			setDrivenKeyframe -cd ($name + ".scaleX") ("cluster_" + $y + "_" + $x + ".scaleX");
			setDrivenKeyframe -cd ($name + ".scaleX") ("cluster_" + $y + "_" + $x + ".scaleY"); 
			setDrivenKeyframe -cd ($name + ".scaleX") ("cluster_" + $y + "_" + $x + ".scaleZ"); 
*/ 
 			//randomly turn some on
 
 			$random = rand(0,100); 
			if($random < $randCut) {     
  
 				//setAttr 	($tmp[0] + ".visibility") on; 
				setAttr 		($tmp[0] + ".status")   1;
				setAttr 		($tmp[0] + ".scale")    1 1 1;
				setAttr 		($tmp[0] + ".oncount") 1;
				setKeyframe 	($tmp[0] + ".scale");
				setKeyframe 	($tmp[0] + ".status");

			}else{
				//setAttr 	($tmp[0] + ".visibility") off;
				setAttr 		($tmp[0] + ".status")  0;
				setAttr 		($tmp[0] + ".scale")   0 0 0;
				setAttr 		($tmp[0] + ".oncount") 0;
				setKeyframe 	($tmp[0] + ".scale");
				setKeyframe 	($tmp[0] + ".status");

			}

			$x++;

		}

		$y++;

	}

	//keyframe all at 0
	
	currentTime 0;
	//life_keyframe();

}

print("hexCA_create loaded ..... Enjoy!\n");


;



 //____________________________________________________________________________________________________________________
global proc hexCA_run(int $xSize, int $ySize, int $steps, int $proliferate){

	int   $step  			= 1;
	float $maxoncount 		= 1.0;
	int   $frameNoPerCalc 	= 20;

	while($step < $steps){

		//check each box and store in list to turn on or off

		int 	$x;
		int 	$y;
		int 	$check;
		string 	$onarray[];
		string 	$offarray[];
		string 	$onset;
		string 	$offset;
		select 	-cl;
		$onset 	= `sets`;
		select 	-cl;
		$offset = `sets`;


		$y =0;
		while($y < $ySize){

			$x = 0;
			while($x < $xSize){

				// this is where the axioms of the cellular automata appear and determine the behaviour of the system

				// the first rule determines if the cell being checked is 'lonely'
 								
				float $tmp = hexCA_check($x,$y,$xSize,$ySize);	
				print("this is the temp" + $tmp + "!");
				if($tmp > 0 && $tmp < 0.45){
				
					$string = "hex_" + $y + "_" + $x;
					print("on " + $string);
					sets -add $onset $string;
					setAttr 		("hex_" + $y + "_" + $x + ".status") $tmp;
					setAttr 		("hex_" + $y + "_" + $x + ".scale")  $tmp $tmp $tmp;
					setKeyframe 	("hex_" + $y + "_" + $x + ".scale");
					setKeyframe 	("hex_" + $y + "_" + $x + ".status");
				}

				else if ($tmp >= 0.45 && $tmp < 0.55){

					$string = "hex_" + $y + "_" + $x;
					print("middle " + $string);
					sets -add $onset $string;
					setAttr 		("hex_" + $y + "_" + $x + ".status") 1;
					setAttr 		("hex_" + $y + "_" + $x + ".scale")  1 1 1;
					setKeyframe 	("hex_" + $y + "_" + $x + ".scale") ;
					setKeyframe 	("hex_" + $y + "_" + $x + ".status");
				}

				else if ($tmp >= 0.55 && $tmp < 0.65){

					$string = "hex_" + $y + "_" + $x;
					sets -add $offset $string;
					setAttr 		("hex_" + $y + "_" + $x + ".status") 0;
					setAttr 		("hex_" + $y + "_" + $x + ".scale")  0 0 0;
					setKeyframe 	("hex_" + $y + "_" + $x + ".scale") ;
					setKeyframe 	("hex_" + $y + "_" + $x + ".status");
				}

				else if ($tmp >= 0.65 && $tmp <= 0.9){
				
					$string = "hex_" + $y + "_" + $x;
					print("on " + $string);
					sets -add $onset $string;
					setAttr 		("hex_" + $y + "_" + $x + ".status") $tmp;
					setAttr 		("hex_" + $y + "_" + $x + ".scale")  $tmp $tmp $tmp;
					setKeyframe 	("hex_" + $y + "_" + $x + ".scale") ;
					setKeyframe 	("hex_" + $y + "_" + $x + ".status");


				}else{
					
					$string = "hex_" + $y + "_" + $x;
					sets -add $offset $string;
					setAttr 		("hex_" + $y + "_" + $x + ".status") 0;
					setAttr 		("hex_" + $y + "_" + $x + ".scale")  0 0 0;
					setKeyframe 	("hex_" + $y + "_" + $x + ".scale") ;
					setKeyframe 	("hex_" + $y + "_" + $x + ".status");				
				}

			$x++;
			}
		$y++;
		}

		$onarray  = `sets -q $onset`;
		$offarray = `sets -q $offset`;
	
		print("Frame: " + ($step * 20) + "\n");
		currentTime ($step * 20);


		// this part of the script creates copies of each state/generation that are then distributed as a
		// layered history of the life of the CA - or in order to be laser cut if (and only if) $proliferate 
		// is set to 1 or 2 respectively.
		
		// check $proliferate state
		
		if($proliferate == 1 || $proliferate == 12){
		
			// first create a new group for each genaration ready to receive copies of each cell in that genearation

			string $genGroupName		= "gen_" + $step;
			group -n $genGroupName -em;

			// loop to select each hex-cell in turn,
			// then duplicate it and name its copy.
			// and then parent the copy to the group named according to its generation

			$y =0;
			while($y < $ySize){

				$x = 0;
				while($x < $xSize){

					string $hexCopyName = $genGroupName + "_hex_" + $y + "_" + $x;				
					select ("hex_" + $y + "_" + $x);
					duplicate -n $hexCopyName;
					parent $hexCopyName $genGroupName;

					$x++;
				}

				$y++;
			}

			// test which proliferation mode and move entire generation accordingly

			// first test is for direct proliferation of each generation along the z-axis
		
			if($proliferate == 1){
		
				nurbsSquare -c 9.6 -4 -2 -nr 0 0 1 -sl1 12 -sl2 24 -sps 1 -d 3 -ch 1 ;
				select -add $genGroupName;
				move 0 0 (2*$step);
			}
		
		}

	$step++;
	}

}





//____________________________________________________________________________________________________________________
global proc life_keyframe(){
	
	select -all;
	$list = `ls -sl -tr`;

	$j = 0;
	while($j < size($list)){

		setKeyframe ($list[$j] + ".v");
		$j++;
	}
	
}





//____________________________________________________________________________________________________________________
global proc float hexCA_check(int $x, int $y,int $xSize, int $ySize){

	float $total;
	float $lowerLimit = 0.1;
	float $upperLimit = 0.9;
				
	$plusx = (($x+1) % $xSize);
	if($x >= 1)	$minusx = ($x-1);
	if($x < 1) 	$minusx = ($xSize-1);

		$plusy = (($y+1) % $ySize);
		if($y >= 1)	$minusy = ($y-1);
		if($y < 1) 	$minusy = ($ySize-1);
			
		// calculate the neighbours of the hex cell
 
		$a = "hex_" + $minusy + "_" + $plusx;
		$b = "hex_" + $y 	  + "_" + $plusx;
		$c = "hex_" + $plusy  + "_" + $plusx;
		$d = "hex_" + $plusy  + "_" + $x;
		$e = "hex_" + $y 	  + "_" + $minusx;
		$f = "hex_" + $minusy + "_" + $x;
		$g = "hex_" + $y 	  + "_" + $x;

		// rules for hex cell life

		// rule 01 - based on how many neighbours are on or off
			
		float $total = (hexCA_status($a) + hexCA_status($b) + hexCA_status($c) + hexCA_status($d) + hexCA_status($e) + hexCA_status($f) + hexCA_status($g))/7;
			
		if($total > $lowerLimit && $total < $upperLimit){
			//print("total" + ($total) + "\n");
			return $total;
				
		}else{

			return 0;
			
		}
		
	return 0;
	
}





//____________________________________________________________________________________________________________________
global proc float hexCA_status(string $hexCell){
	
	// this global procedure returns the status of each hex-cell

	float $v = `getAttr ($hexCell + ".status")`;
	return $v;
	
}



	


//__________________________________________________________________________________________________________________
global proc springCA_create (int $xSize, int $ySize, float $hexSize){

	
	// if uncommented these lines select and delete all objects and keyframes remaining from previous iterations
/*
	select -all;
	delete;
*/
	// loop for each cell row following $ySize (note that the cell rows referred to here are the hex-cells
	// for this orientation of the hex-cells (point up) there are actually four rows of cubes (which make 
	// up the vertices of each hex) for each row of hex-cells, but because two overlap, after the first row
	// of hex-cells the rest have only two rows of cubes each 

	int $y = 1;
	while ($y <= $ySize) {

		//int $modulor = $y%2;
		//print("row" + $y + 
		
		//loop for each cell column following $xSize		

		int $x = 1;
		while ($x <= $xSize + 1) {

			// create a cube for each vertex of the hex grid and name it according to the three adjacent hex_cells
			// trigonometry is used to calculate the movement of each cube relative to the entered $hexSize
			
			// calculate trigonometric values for movement
			
			float $adj 		 = $hexSize * 0.5;
			float $hyp 		 = $adj / (cosd(30));
			float $opp 		 = $adj * tand(30);
			
			// calculate a stagger value (again for movement) that includes a test and allowance for odd rows
			
			float $stagger = (($y+1)%2) * 0.5 * $hexSize;
			
			// set up naming variables - minus signs will be represented by an underscore
			// as spacers: "_" appears between y and x, and "__" appears between hex-cell pairs 
			
			string $cellRef 				=  $y    + "_" +  $x;
			string $cellLeftRef				=  $y	 + "_" + ($x-1);
			string $cellRightRef			=  $y    + "_" + ($x+1);
			string $cellBelowLeftRef		= ($y+1) + "_" + ($x-1);
			string $cellBelowRightRef		= ($y+1) + "_" + $x;
			string $cellAboveLeftRef		= ($y-1) + "_" + ($x-1);
			string $cellAboveRightRef		= ($y-1) + "_" + $x;
			
			// the first two rows of cubes (occuring on hex-cell row zero) have no neighbouring cells
			// above and so are created first as special cases
			
			// make the first 'special' row - there is one less cube in this row so exclude x = $xSize
			
			if ($y == 1 && $x != $xSize + 1){

				string $cubeName = "cube" + $cellAboveLeftRef + "__" + $cellAboveRightRef + "__" + $cellRef;
				float  $moveX	 = $x * $hexSize - $hexSize;
				float  $moveY	= -$y * cosd(30) * $hexSize + $hyp + $hexSize;
					
				$tmp = `polyCube -n $cubeName -w .1 -h .1 -d .1`;
				move $moveX $moveY 0;
				
				
				print("first row" + $x + "\n");
				
			}
			
			// make the second 'special' row
			
			if ($y == 1){
											
				$cubeName = "cube" + $cellAboveLeftRef + "__" + $cellLeftRef + "__" + $cellRef;
				$moveX	 = ($x - 0.5) * $hexSize - $hexSize;
				$moveY	= -$y * cosd(30) * $hexSize + $opp + $hexSize;
						 
				$tmp   = `polyCube -n $cubeName -w .1 -h .1 -d .1`;
				move $moveX $moveY 0;
			}
					
			// now that the 'special cases' of the first two rows are done, make the rest of the rows of cubes
			
			// make the first standard row
			// the if stagger > 0 statement establishes whether the row is odd and changes the name if necessary
			
			$cubeName = "cube" + $cellLeftRef + "__" + $cellRef + "__" + $cellBelowLeftRef;
						
			if ($stagger > 0){
			
				print("row is even" + $y + "\n");
				$cubeName = "cube" + $cellLeftRef + "__" + $cellRef + "__" + $cellBelowRightRef;
			}
			$moveX	= ($x - 0.5) * $hexSize + $stagger - $hexSize;
			$moveY	= -$y * cosd(30) * $hexSize - $opp + $hexSize;
						
			$tmp	= `polyCube -n $cubeName -w .1 -h .1 -d .1`;
			move $moveX $moveY 0;		
			
			// next make the second standard row of cubes
			// the if/else statement prevents the additional cube that would be created in the last row

			int $lastRow = ($ySize);
			
			if(($y == $lastRow) && ($x == 1)){
			
				print ("skipping cube!\n");
			
			}else{
			
				$cubeName = "cube" + $cellRef + "__" + $cellBelowLeftRef + "__" + $cellBelowRightRef;
				
				if ($stagger > 0){
				
					print("row is even" + $y + "\n");
					$cubeName = "cube" + $cellLeftRef + "__" + $cellBelowLeftRef + "__" + $cellBelowRightRef;
				}
				$moveX	= $x * $hexSize - $stagger - $hexSize;
				$moveY	= -$y * cosd(30) * $hexSize - $hyp + $hexSize;
						
				$tmp	= `polyCube -n $cubeName -w .1 -h .1 -d .1`;
				move $moveX $moveY 0;
			
			}
			
			$x++;
			
		}
			
	$y++;
			
	}	
			
print ("springCA_create loaded ..... \n");
print ("\n");
print ("loading: springCA_attach .....\n");
print ("\n");

// call springCA_attach global procedure to attach springs to the cubes just created

springCA_attach $xSize $ySize;
}





//__________________________________________________________________________________________________________________
global proc springCA_attach (int $xSize, int $ySize){

	float $damping		= 40;
	float $stiffness	= 50;

	int $y = 1;
	while ($y <= $ySize) {

		//loop for each cell column following $xSize		

		int $x = 1;
		while ($x <= $xSize+1) {

			// set up naming variables - minus signs will be represented by an underscore
			// as spacers: "_" appears between y and x, and "__" appears between hex-cell pairs 

			string $cellRef 				=  $y    + "_" +  $x;
			string $cellLeftRef				=  $y	 + "_" + ($x-1);
			string $cellRightRef			=  $y    + "_" + ($x+1);
			string $cellBelowLeftRef		= ($y+1) + "_" + ($x-1);
			string $cellBelowRightRef		= ($y+1) + "_" +  $x;
			string $cellAboveLeftRef		= ($y-1) + "_" + ($x-1);
			string $cellAboveRightRef		= ($y-1) + "_" +  $x;
			string $cellBelowFarRightRef	= ($y-1) + "_" + ($x+1);
			
			int	$oddness					= $y%2;
			
						
			// the first row of springs has no neighbours above it and so is added first as a special case
			
			// attach first special row of springs to existing cubes
			// there are two springs per cell in the first special row so exclude last loop ($x = $xSize + 1)
			
			if ($y == 1 && $x != $xSize + 1){
			
				 // in each loop connect spring for top left side of hex until all springs are added for the row
				
				string $cube01 			= "cube" + $cellAboveLeftRef  + "__" + $cellLeftRef 		+ "__" + $cellRef;
				string $cube02 			= "cube" + $cellAboveLeftRef  + "__" + $cellAboveRightRef 	+ "__" + $cellRef;
				string $cube03 			= "cube" + $cellAboveRightRef + "__" + $cellRef 			+ "__" + $cellRightRef;
				
				string $springName01	= "spring_" + $cellAboveLeftRef  + "__" + $cellRef;
				string $springName02	= "spring_" + $cellAboveRightRef + "__" + $cellRef;
				
				select -r $cube01 $cube02;
				constrain -spring -st $stiffness -d $damping -i 0 -n $springName01;


				 // do the same for the top right side of each hex
				
				select -r $cube02 $cube03;
				constrain -spring -st $stiffness -d $damping -i 0 -n $springName02;
				
			}

			// now attach the first standard row of springs
			// they run vertically and there is one more spring than there are hexes in each row (loop $x = $xSize remains)

			// reference names following conventions for odd rows
			
			$cube01 		= "cube" + $cellAboveLeftRef + "__" + $cellLeftRef 	+ "__" + $cellRef;
			$cube02 		= "cube" + $cellLeftRef 	 + "__" + $cellRef 		+ "__" + $cellBelowLeftRef;
			
			$springName01	= "spring_" + $cellLeftRef  + "__" + $cellRef;
			
			// test if row is even and if so rename cube references so that the right cubes are joined by the springs
			
			if($oddness == 0){
				
				$cube01 	= "cube" + $cellAboveRightRef + "__" + $cellLeftRef + "__" + $cellRef;
				$cube02 	= "cube" + $cellLeftRef 	  + "__" + $cellRef 	+ "__" + $cellBelowRightRef;
			}
			select -r $cube01 $cube02;
			constrain -spring -st $stiffness -d $damping -i 0 -n $springName01;
			

			// now attach the second standard row of springs
			// there are two springs per cell this row so again exclude last loop ($x = $xSize)
			
			if($x != $xSize + 1){
				
				// references for cubes in odd rows
				
				$cube01 		= "cube" + $cellLeftRef + "__" + $cellRef 			+ "__" + $cellBelowLeftRef;
				$cube02 		= "cube" + $cellRef 	+ "__" + $cellBelowLeftRef 	+ "__" + $cellBelowRightRef;
				$cube03 		= "cube" + $cellRef 	+ "__" + $cellRightRef 		+ "__" + $cellBelowRightRef;
				
				$springName01	= "spring_" + $cellRef  + "__" + $cellBelowLeftRef;
				$springName02	= "spring_" + $cellRef  + "__" + $cellBelowRightRef;
				
				// test if row is even and if so rename cube references so that the right cubes are joined by the springs
			
				if($oddness == 0){
			
					$cube01 		= "cube" + $cellLeftRef + "__" + $cellRef 			+ "__" + $cellBelowRightRef;
					$cube02 		= "cube" + $cellRef 	+ "__" + $cellBelowRightRef + "__" + ($y+1) + "_" + ($x+1);
					$cube03 		= "cube" + $cellRef 	+ "__" + $cellRightRef 		+ "__" + ($y+1) + "_" + ($x+1);
					
					$springName01	= "spring_" + $cellRef  + "__" + $cellBelowRightRef;
					$springName02	= "spring_" + $cellRef  + "__" + $cellBelowFarRightRef;
				}
				select -r $cube01 $cube02;
				constrain -spring -st $stiffness -d $damping -i 0 -n $springName01;
				
				select -r $cube02 $cube03;
				constrain -spring -st $stiffness -d $damping -i 0 -n $springName02;
				
			}
			// there is one spring that is not added at either end depending on whether the row is even or odd
			// add this spring
			
			if($oddness == 1 && $x == $xSize + 1){
				
				$cube01 	= "cube" + $cellLeftRef + "__" + $cellRef 			+ "__" + $cellBelowLeftRef;
				$cube02 	= "cube" + $cellRef 	+ "__" + $cellBelowLeftRef 	+ "__" + $cellBelowRightRef;
				
				$springName01 = "spring_" + $cellRef  + "__" + $cellBelowLeftRef;
				
				select -r $cube01 $cube02;
				constrain -spring -st $stiffness -d $damping -i 0 -n $springName01;
				
			}
			if($oddness == 0 && $x == 1 && $y != $ySize){
				
				$cube01 	= "cube" + $cellLeftRef + "__" + $cellBelowLeftRef 	+ "__" + $cellBelowRightRef;
				$cube02 	= "cube" + $cellLeftRef + "__" + $cellRef + "__" + $cellBelowRightRef;
				
				$springName01 = "spring_" + $cellLeftRef  + "__" + $cellBelowRightRef;
				
				select -r $cube01 $cube02;
				constrain -spring -st $stiffness -d $damping -i 0 -n $springName01;
				
			}
			
			$x++; 
			 
		}
			
	$y++;
			
	}	
select -r "cluster*";
group -n allClusters;

select -r "curve*";
group -n allCurves;


			
print ("springCA_attach loaded ..... Enjoy!\n");
}





//____________________________________________________________________________________________________________________
global proc hex_associate(float $scale){

	// this procedure associates the scale of the adjacent hexes to the spring length
	
	int $numOfTokens;
	string $springName[];
	string $springNameArray[];
	float $hexScale01;
	float $hexScale02;
	float $hexValue;
	string $hex01;
	string $hex02;
	
	// get an array of the springs 
	
	select -r "spring*";
	$springName = `ls -sl`;
	print $springName;
	$i = 0;
	
	while( $i < size($springName)){
	
		// tokenise

		$numOfTokens = tokenize ($springName[$i], "_", $springNameArray);
		print $springNameArray;

		// if it isn't on the edge then assign a rest length
		
		$hex01 = ("hex_" + $springNameArray[1] + "_" + $springNameArray[2]);
		$hex02 = ("hex_" + $springNameArray[3] + "_" + $springNameArray[4]);
		
		if(`objExists $hex01` && `objExists $hex02`){

			// get hex scales

			$hexScale01 = `getAttr ("hex_" + $springNameArray[1] + "_" + $springNameArray[2] + ".scaleX")`;
			$hexScale02 = `getAttr ("hex_" + $springNameArray[3] + "_" + $springNameArray[4] + ".scaleX")`;
			
			$hexValue = ($scale*(($hexScale01 + $hexScale02) / 2));
			
			// assign hex scale to spring rest length
			setAttr ($springName[$i] + ".springRestLength") $hexValue;
			
		}

	$i++;

	}

print ("hex_associate loaded ..... Enjoy!\n");	

}

print ("hex_CA suite loaded ..... Enjoy!\n");



//____________________________________________________________________________________________________________________
// uncomment the next lines to allow the scripts to run automatically
/*
	hexCA_create 20 10 1 35;
	hexCA_run 20 10 50 0;
*/
	//or
/*	
	springCA_create 20 10 1;
*/	
	//or
/*	
	hex_associate 1;
*/