[Xulu-commits] r62 - in trunk: dist src/edu/bonn/xulu/plugin/model/sleuth

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Wed Oct 21 10:43:44 CEST 2009


Author: rgoetzke
Date: 2009-10-21 10:43:39 +0200 (Wed, 21 Oct 2009)
New Revision: 62

Modified:
   trunk/dist/xulu-doc.zip
   trunk/src/edu/bonn/xulu/plugin/model/sleuth/MultipleResolutionValidation.java
   trunk/src/edu/bonn/xulu/plugin/model/sleuth/UrbanGrowthModel.java
   trunk/src/edu/bonn/xulu/plugin/model/sleuth/UrbanGrowthModelContentManager.java
Log:


Modified: trunk/dist/xulu-doc.zip
===================================================================
(Binary files differ)

Modified: trunk/src/edu/bonn/xulu/plugin/model/sleuth/MultipleResolutionValidation.java
===================================================================
--- trunk/src/edu/bonn/xulu/plugin/model/sleuth/MultipleResolutionValidation.java	2009-10-14 08:31:55 UTC (rev 61)
+++ trunk/src/edu/bonn/xulu/plugin/model/sleuth/MultipleResolutionValidation.java	2009-10-21 08:43:39 UTC (rev 62)
@@ -11,7 +11,7 @@
 import edu.bonn.xulu.plugin.data.grid.MultiGrid;
 
 /**
- * <b>MULTIPLE RESOLUTION COMPARISON</b>
+ * <b>MULTIPLE RESOLUTION COMPARISON</b><br>
  * The Multiple Resolution Comparison is a Xulu-plugin that can be used in order to validate modelling results.
  * In general, the Multiple Resolution Comparison is a method to quantify the agreement between two maps, 
  * whereby it averages neighbouring pixels of both maps into coarser pixels in order to quantify the agreement between maps at coarser resolutions.
@@ -19,12 +19,28 @@
  * a Multiple Resolution Comparison of a NULL-Model (no change has taken place between t1 and t2), the NULL-Resolution can be identified,
  * which indicates the resolution at which the modelling result is more accurate than the NULL-Model.<br>
  * For details refer to:<br>
- * Costanza,R. (1989): Model Goodness of Fit - A Multiple Resolution Procedure. In: Ecological Modelling, vol. 47, no. 3-4, pp. 199-215.<br>
- * Pontius Jr, R.G. (2002): Statistical Methods to Partition Effects of Quantity and Location During Comparison of Categorical Maps at Multiple Resolutions. 
+ * <i>Costanza,R. (1989)</i>: Model Goodness of Fit - A Multiple Resolution Procedure. In: Ecological Modelling, vol. 47, no. 3-4, pp. 199-215.<br>
+ * <i>Pontius Jr, R.G. (2002)</i>: Statistical Methods to Partition Effects of Quantity and Location During Comparison of Categorical Maps at Multiple Resolutions. 
  * In: Photogrammetric Engineering &amp; Remote Sensing, vol. 68, no. 10,  pp. 1041-1049.<br>
- * Pontius Jr, R.G., Huffaker, D. &amp; K. Denman (2004): Useful Techniques of Validation for Spatially Explicit Land-Change Models. 
+ * <i>Pontius Jr, R.G., Huffaker, D. &amp; K. Denman (2004)</i>: Useful Techniques of Validation for Spatially Explicit Land-Change Models. 
  * In: Ecological Modelling, vol. 179, no. 4, pp. 445-461.<br>
  * 
+ * The following input parameters/images are required:<br>
+ * <ul>
+ *  <li><b>Number of Steps ({@code steps})</b>: Because this plugin is built as a step model, the number of (time) steps always has to be 1.</li>
+ *  <li><b>Reference Map ({@code referenceMap})</b>: A raster containing the reference (observed) land cover.</li>
+ *  <li><b>Simulation Map ({@code simulationMap})</b>: A raster containing the simulated land cover.</li>
+ * </ul>
+ * 
+ * Furthermore the following outputs are created:<br>
+ * <ul>
+ *  <li><b>Actual Validation (@code actualValidation)</b>: A raster containing the actual resolution grid with the fraction correct in every cell</li>
+ *  <li><b>Out Step ({@code outStep})</b>: A Grid List containing a grid (Actual Validation) for every resolution.</li>
+ *  <li><b>Out Results ({@code outResults})</b>: A list containing the total agreement for every resolution.</li>
+ * </ul>
+ * 
+ * Other important values are written to the status output window!<br>
+ * 
  * @see MultipleResolutionValidationContentManager
  * @author <a href="mailto:goetzke at uni-bonn.de">Roland Goetzke</a>
  * @version 1.0
@@ -42,14 +58,14 @@
 	private float[][] resultArray;
 	
 	/**
-	 * Speichert den ContentManager fuer das Modell.
+	 * Saves the ContentManager for the model.
 	 * 
 	 * @see MultipleResolutionValidationContentManager
 	 */
 	protected MultipleResolutionValidationContentManager contManager;
 
-	// ********** Lese/Schreibrechte, die fuer den gesamten ***********
-	// ********** Modellanlauf gehalten werden muessen ***********
+	// ********** Read/Write access, that has to be maintained ***
+	// ********** through the whole model run ********************
 	private PropertyReadAccess RA_steps = null;	//Number of Steps
 	private PropertyReadAccess RA_referenceMap = null; // Reference Map
 	private PropertyReadAccess RA_simulationMap = null;	//Simulation Map
@@ -57,7 +73,7 @@
 	private PropertyWriteAccess WA_outStep = null;	// Step Results
 	private ListPropertyWriteAccess WA_outResults = null;	//Output Validation Results
 
-	// **************** Variablen mit denen gearbeitet wird *******************
+	// **************** Variables to work with *******************
 	private PropertyReadAccess steps = null; // Number of steps
 	private WritableGrid referenceMap = null; // Reference Map
 	private WritableGrid simulationMap = null;	// Simulation Map
@@ -120,7 +136,7 @@
 	 */
 	public void performModelDispose() {
 
-		// Ressourcen wieder freigeben
+		// free resources
 		releaseAccess(RA_steps);
 		releaseAccess(RA_referenceMap);
 		releaseAccess(RA_simulationMap);

Modified: trunk/src/edu/bonn/xulu/plugin/model/sleuth/UrbanGrowthModel.java
===================================================================
--- trunk/src/edu/bonn/xulu/plugin/model/sleuth/UrbanGrowthModel.java	2009-10-14 08:31:55 UTC (rev 61)
+++ trunk/src/edu/bonn/xulu/plugin/model/sleuth/UrbanGrowthModel.java	2009-10-21 08:43:39 UTC (rev 62)
@@ -1,10 +1,7 @@
 package edu.bonn.xulu.plugin.model.sleuth;
 
-import java.awt.Rectangle;
 import java.util.HashMap;
 
-import org.geotools.feature.Feature;
-
 import edu.bonn.xulu.model.AbstractStepModel;
 import edu.bonn.xulu.model.XuluModel;
 import edu.bonn.xulu.plugin.data.grid.MultiGrid;
@@ -15,42 +12,71 @@
 import schmitzm.data.property.ScalarProperty;
 
 /**
- *  This very simple model looks at every grid cell and takes the average 
- *  over a the surrounding cells in a specified neighborhood. It was implemented
- *  as demonstration of the Xulu / V functionality. You can see the parallel version
- *  of this model in {@link AverageNeighborhoodParallelDemoModel} and also a tuned
- *  version using late-merging support in {@link AVNTuned}. Beachte die Methode {@link #calculateNeighbors(int, int, float)}.
+ *  <b>Urban Growth Model</b><br>
+ *  This Model simulates urban growth. It is based on the algorithm of the SLEUTH-Model, which has originally been written in C code and could
+ *  be run under UNIX. The SLEUTH-Model has been developed by Keith Clarke at the UC Santa Barbara, CA, within the Gigalopolis Project, funded by the
+ *  USGS. Therefore it is under public domain. The name SLEUTH has been derived from the image input requirements of the model:
+ *  Slope, Land cover, Exclusion, Urbanization, Transportation, and Hillshade.<br>
+ *  In the original SLEUTH-Model the core Urban Growth Model (UGM) calls and drives an additional land cover deltatron model (LCD). Both models are
+ *  tightly coupled, but the UGM can be run separately. Here, only the UGM part of the SLEUTH-Model has been translated into JAVA. Minor changes
+ *  in the code have been necessary. Those changes are explained within the code. In general, the UGM is a Cellular Automaton (CA). All CA elements 
+ *  in the code have been untouched and are the same as in the original UGM.<br>
+ *  This is the basic UGM code, a plain Cellular Automaton. Additional functions are implemented in other models, like:<br>
+ *  <ul>
+ *   <li><b>UGM Calibration ({@link UrbanGrowthModelCalibration})</b>: The same model algorithm like this, but in order to calibrate the model by finding the correct parameter values with the method of Multiple Resolution Comparison (@link MultipleResolutionValidation)</li>
+ *   <li><b>UGM SelfModifying({@link UrbanGrowthModelSelfModifying})</b>: The same model algorithm like this, but with the possibility of self-modification of the parameter values.</li>
+ *   <li><b>UGM CalibrationSelfModifying({@link UrbanGrowthModelCalibrationSelfModification})</b>: The same model algorithm like this, but in order to calibrate the model by finding the correct parameter values with the method of Multiple Resolution Comparison (@link MultipleResolutionValidation)
+ *    While calibrating the model modifies the parameter values.</li>
+ *  </ul>
+ *  <br>
+ *  The original SLEUTH-Model can be downloaded via the <a href="http://www.ncgia.ucsb.edu/projects/gig/">Gigalopolis Website</a>. To run it, a
+ *  UNIX environment with the GNU C compiler (gcc) are required.<br>
+ *  For details refer to:<br>
+ *  <i>Clarke, K.C., Hoppen, S. & L.J. Gaydos (1997)</i>: A self-modifying cellular automaton model of historical urbanization in the San Francisco Bay area.
+ *  In: Environment and Planning B: Planning and Design, vol. 24, pp. 247-261.<br>
+ *  <i>Clarke, K.C. & L.J. Gaydos (1998)</i>: Loose-coupling a cellular automaton model and GIS: long-term urban growth prediction for San Francisco
+ *  and Washington/Baltimore. In: International Journal of Geographical Information Science, vol. 12, no. 7, pp. 699-714.<br>
+ *  <i>Jantz, C.A., Goetz, S.J. & M.K. Shelley (2003)</i>: Using the SLEUTH urban growth model to simulate the impacts of future policy scenarios
+ *  on urban land use in the Baltimore-Washington metropolitan area. In: Environment and Planning B: Planning and Design, vol: 30, pp. 251-271.<br>
  *  
- *  
- * <ol>
- * <li><b>Input Grid ({@code inputGrid}):</b> A grid with input values </li>
- * <li><b>Output Grid ({@code outputGrid}):</b> A grid where the output is
- * stored </li>
- * <li><b>Number of steps ({@code steps}):</b> the number of steps to
- * compute. </li>
- * </ol>
+ *  <br>
+ *  The following input parameters/images are required:<br>
+ * <ul>
+ *  <li><b>Input Grid ({@code inputGrid})</b>: A grid containing the input (initial) urban land cover.</li>
+ *  <li><b>Area Restriction ({@code areaRestr})</b>: A grid containing the area restrictions (e.g. water, natural reserves, areas with lower probability, etc.).</li>
+ *  <li><b>Transportation Grid ({@code roadGrid})</b>: A grid containing the road network.</li>
+ *  <li><b>Slope Grid ({@code slopeGrid})</b>: A grid containing the slope.</li>
+ *  <li><b>Number of steps ({@code steps})</b>: The number of time steps to compute.</li>
+ *  <li><b>Spread ({@code spread})</b>: The Spread-Coefficient.</li>
+ *  <li><b>Disp ({@code disp})</b>: The Dispersion(Diffusion)-Coefficient.</li>
+ *  <li><b>Breed ({@code breed})</b>: The Breed-Coefficient.</li>
+ *  <li><b>Road Gravity ({@code roadGravity})</b>: The Road Gravity-Coefficient.</li>
+ *  <li><b>Slope ({@code slope})</b>: The Slope-Coefficient.</li>
+ *  <li><b>Critical Slope ({@code criticalSlope})</b>: The Percentage at which urbanization on steep slopes is not possible.</li>
+ * </ul>
  * 
- * @see AverageNeighborhoodContentManager
- * @author Dominik Appl
+ * <br>
+ * Furthermore the following outputs are created:<br>
+ * <ul>
+ *  <li><b>Output Grid ({@code outputGrid})</b>: A grid containing the output, that is actualized in every time step.</li>
+ *  <li><b>outStep ({@code outStep})</b>: A Grid List containing the results for every time step.</li>
+ * </ul>
+ * 
+ * @see UrbanGrowthModelContentManager
+ * @author <a href="mailto:goetzke at uni-bonn.de">Roland Goetzke</a>
  * @version 1.0
  */
 public class UrbanGrowthModel extends AbstractStepModel {
 
 	/**
-	 * the width/height of the neighborhood region over which the algorithm takes 
-	 * the average
-	 */
-//	private int neighborhoodRange = 1;
-
-	/**
-	 * Speichert den ContentManager fuer das Modell.
+	 * Saves the ContentManager for the model.
 	 * 
-	 * @see AverageNeighborhoodContentManager
+	 * @see UrbanGrowthModelContentManager
 	 */
 	protected UrbanGrowthModelContentManager contManager;
 
-	// ********** Lese/Schreibrechte, die fuer den gesamten ***********
-	// ********** Modellanlauf gehalten werden muessen ***********
+	// ********** Read/Write access, that has to be maintained ***
+	// ********** through the whole model run ********************
 	private PropertyReadAccess RA_inputGrid = null; // Input Grid
 	private PropertyWriteAccess WA_outputGrid = null; // Output Grid
 	private PropertyReadAccess RA_steps = null; // Number of steps
@@ -80,16 +106,34 @@
 	private WritableGrid slopeGrid = null;	//Slope Grid
 	private MultiGrid outStep = null;	//Step Results
 		
+	/**
+	 * Moore Neighborhood as a two dimensional array. It's the central element of a Cellular Automaton.
+	 */
 	private  static final int[][] NEIGHBOR = new int[][] {
 	      {-1,-1}, {0,-1}, {1,-1},
 	      {-1, 0},         {1, 0},
 	      {-1, 1}, {0, 1}, {1, 1}
 	  };
 	
+	/**
+	 * A Lookup-Table which relates actual slope values to slope coefficient influenced probabilities.
+	 */
 	protected  HashMap<Number,Number> slopeLUT;
 	
+	protected int areaMinX = 0;
+	protected int areaMinY = 0;
+	protected int areaMaxX = 0;
+	protected int areaMaxY = 0;
+	protected int areaWidth = 0;
+	protected int areaHeight = 0;
+	
+	protected double disp_value = 0;	//Dispersion Value
+	protected double max_RG_value = 0;	//Maximum RoadGravity Value
+	protected double rg_value = 0;		//RoadGravity Value
+	protected double max_search_index = 0;	//Maximum search index for road
+	
 	/**
-	 * Erzeugt eine neue Instanz des Modells.
+	 * Creates a new model instance.
 	 */
 	public UrbanGrowthModel() {
 		super(new UrbanGrowthModelContentManager());
@@ -102,9 +146,10 @@
 	 * the resources are initalized. 
 	 */
 	public void performModelInit() {
+		
 		if (contManager == null)
 			return;
-		// Zugriffsrechte aus Ressourcen/Propertys holen
+		// Get access authorisation of resource/properties
 		RA_inputGrid = null;
 		if (contManager.getResource(0).getData() != null)
 			RA_inputGrid = ((ScalarProperty) contManager.getResource(0)
@@ -154,14 +199,12 @@
 			RA_slopeGrid = ((ScalarProperty) contManager.getResource(11)
 					.getData()).getReadAccess(this);
 
-		// Variablen belegen mit denen gearbeitet wird
+		// Assign variables to work with
 		inputGrid = (WritableGrid) RA_inputGrid.getValue();
 		outputGrid = (WritableGrid) WA_outputGrid.getValue();
 		steps = RA_steps;
+		this.stepCount = steps.getValueAsInt();
 		areaRestr = (WritableGrid) RA_areaRestr.getValue();
-		
-		this.stepCount = steps.getValueAsInt();
-	   // this.spread = RA_spread.getValueAsFloat();
 	    spread  = RA_spread.getValueAsDouble();
 	    disp	= RA_disp.getValueAsDouble();
 	    breed	= RA_breed.getValueAsDouble();
@@ -172,47 +215,30 @@
 	    slopeGrid = (WritableGrid) RA_slopeGrid.getValue();
 	    outStep = (MultiGrid)contManager.getResource(12).getData();
 	    
-
-		int startAnz = 0;
-		for (int i = 0; i < inputGrid.getWidth();i++ ) {
-			for (int ii = 0; ii < inputGrid.getHeight(); ii++ ) {
-				//if (inputGrid.getRasterSampleAsFloat(i,ii) == 1f);
-				float val = inputGrid.getRasterSampleAsFloat(i,ii);
-				if (val == 1.0 ) {
-					val = 1f;
-					startAnz++;
-				}
-					else val = 0f;
-				
-				//inputGrid.setRasterSample(val, inputGrid.getMinX() + i, inputGrid.getMinY() + ii);
-				outputGrid.setRasterSample(val, inputGrid.getMinX() + i, inputGrid.getMinY() + ii);
-			}
-		}
-		statusOut.println("Anzahl der startenden Individuen: "+startAnz);
-		statusOut.println(NEIGHBOR.length);
+	    //count the number of starting individuals
+	    int startAnz = 0;
+		startAnz = countIndividuals();
 		
+		statusOut.println("Number of starting cells: "+startAnz);
+		statusOut.println("Neighborhood size: "+NEIGHBOR.length);
+		
+		//calculate the maximum slope
 		int slopeMax = 0;
-		for (int s = 0; s < inputGrid.getWidth();s++){
-			for(int ss = 0; ss < inputGrid.getHeight();ss++){
-				float slopeVal = slopeGrid.getRasterSampleAsFloat(s,ss);
-				if (slopeVal > slopeMax){
-					slopeMax = (int) slopeVal;
-				} 
-			}
-		}
-		statusOut.println("Maximale Hangneigung: "+slopeMax);
+		slopeMax = getSlopeMax();
 		
-		
-		//Erstellt einen Lookup-Table
+		statusOut.println("Max. Slope: "+slopeMax+" %");
+				
+		//Creates a new Lookup-table
 		slopeLUT = new HashMap<Number,Number>();
 		
+		//assigns for every slope value between 0 and the maximum slope that is below the critical slope the value calculated for the variable "lookup".
+		//all values higher than the critical slope become 1
 		int MaxSlopeResistance = 0;
 		double exp = 0.0;
-		MaxSlopeResistance = 100;
-		exp = (slope / (MaxSlopeResistance / 2));
+		MaxSlopeResistance = 100;	//Max slope resistance is 100%
+		exp = (slope / (MaxSlopeResistance / 2.0));
 		double[] lookup = new double[slopeMax+1];
 		Number key = 0;
-		
 		for (int i = 0;i <= slopeMax;i++){
 			if (i <= criticalSlope){
 				double val = (criticalSlope - i) / criticalSlope;
@@ -223,8 +249,24 @@
 				key = i;
 			}
 			slopeLUT.put(key,lookup[i]);
-			statusOut.println(slopeLUT.get(key));
 		}	
+		
+		//raster dimensions
+		areaMinX = inputGrid.getMinX();
+		areaMinY = inputGrid.getMinY();
+		areaMaxX = inputGrid.getMinX() + inputGrid.getWidth() - 1;
+		areaMaxY = inputGrid.getMinY() + inputGrid.getHeight() - 1;
+		areaWidth = inputGrid.getWidth();
+		areaHeight = inputGrid.getHeight();
+		
+		//coefficient calculations of for growth rules
+		disp_value = Math.round((disp*0.005)* Math.sqrt(Math.pow(inputGrid.getWidth(), 2)+(Math.pow(inputGrid.getHeight(), 2))));	//Dispersion value (Number of cells to select spontaneously)
+		statusOut.println("Dispersion-Value: "+disp_value);
+		max_RG_value = 100.0;			//Maximum possible road gravity value
+		rg_value = Math.round((roadGravity/max_RG_value)*((areaWidth + areaHeight)/16)); 	//calculation of the road gravity value
+		statusOut.println("RoadGravity-Value: "+rg_value);
+		max_search_index = Math.round(4*((int)rg_value*(1+(int)rg_value)));	//area in which to look for a road cell
+		statusOut.println("MaxSearchIndex: "+max_search_index);
 	}
 
 	/**
@@ -232,7 +274,7 @@
 	 */
 	public void performModelDispose() {
 
-		// Ressourcen wieder freigeben
+		// free resources
 		releaseAccess(RA_inputGrid);
 		releaseAccess(WA_outputGrid);
 		releaseAccess(RA_steps);
@@ -247,406 +289,437 @@
 		releaseAccess(RA_slopeGrid);
 		releaseAccess(WA_outStep);
 	}
-
+	
 	/**
-	 * This very simple model looks at every grid cell and takes the average
-	 * over a the surrounding cells in a specified neighborhood.
-	 * @exception IllegalArgumentException wenn das dadad  
+	 * This is the main run of the Urban Growth Model. Depending on the input parameters the cellular automaton looks in the neighborhood of individual cells for specific conditions
+	 * and turns them from non-urban into urban, following certain growth rules. Those growth rules are:<br>
+	 *  <ol>
+	 *   <li><b>spontaneous growth</b>: controlled by dispersion (@code disp): Randomly selects potential new growth cells.</li>
+	 *   <li><b>new spreading centers</b>: controlled by breed (@code breed): Growing urban centers from spontaneous growth.</li>
+	 *   <li><b>edge</b>: controlled by spread (@code spread): Old or new urban centers spawn additional growth.</li>
+	 *   <li><b>road influenced</b>: controlled by road-gravity(@code roadGravity), dispersion (@code disp), breed (@code breed): Newly urbanized cell spawns growth along transportation network.</li>
+	 *  </ol>
+	 * @exception IllegalArgumentException 
 	 * @param stepNo
-	 *            zu modellierender Schritt (beginnend bei 1!)
 	 */
 	public void performModelStep(int stepNo) {
 		
 		statusOut.println("Starting step " + stepNo + "...");
-		Number number = slopeLUT.get(79);
-		statusOut.println(number);
-
-		int areaMinX = inputGrid.getMinX();								//Dimensionen des Rasters
-		int areaMinY = inputGrid.getMinY();
-		int areaMaxX = inputGrid.getMinX() + inputGrid.getWidth() - 1;
-		int areaMaxY = inputGrid.getMinY() + inputGrid.getHeight() - 1;
-		int areaWidth = inputGrid.getWidth();
-		int areaHeight = inputGrid.getHeight();
 		
+		//time measure
 		long localStartTime = System.currentTimeMillis();
-		boolean anyBodyAlive = false;
 		
-		boolean[][] tmpGrid = new boolean[inputGrid.getWidth()][inputGrid.getHeight()];
-		Float actUrb = null;
+		//cells to be created
+		boolean[][] tmpGrid = new boolean[inputGrid.getWidth()][inputGrid.getHeight()];	//a temporary raster
+		Float actUrb = null;	//urban cell in the raster
+
+	
+		/*****************************************************************
+		 * DISPERSION and BREED (Growth Phase 1 and 2)
+		 *****************************************************************/
+		boolean[][] tmpGridDisp = new boolean[inputGrid.getWidth()][inputGrid.getHeight()];	//a temporary raster
+		tmpGridDisp = DispersionGrowth();	//calls the method "DispersionBreed" to perform the Dispersion and Breed Growth Phase
+		int anzDispBreed = 0;	//number of cells urbanized by Dispersion and Breed
+		for (int x = 0; x < inputGrid.getWidth();x++)
+			for(int y = 0; y < inputGrid.getHeight();y++){
+				int X = inputGrid.getMinX() + x;
+				int Y = inputGrid.getMinY() + y;
+				if (tmpGridDisp[X][Y]==true){
+					anzDispBreed++;
+					tmpGrid[X][Y] = true;	//write the temporary Dispersion and Breed Cells to the overall temporary Cell array
+				}		
+			}
+		statusOut.println("Number of Spontaneous and New Spreading Center Cells: "+anzDispBreed);
+		writeToGrid(tmpGrid);	//calls the method "writeToGrid" to write the new urbanized cells to the output grid
 		
-		int nbX = 0; // X-Koordinate einer Nachbarzelle
-	    int nbY = 0; // Y-Koordinate einer Nachbarzelle
-	    int[] nbCell = null;
-	    
-		int anzSpreadTreffer = 0;
-		int anzDispTreffer = 0;
-		int anzBreedTreffer = 0;
-		
-		//DISPERSION
-		double disp_value = Math.round((disp*0.005)* Math.sqrt(Math.pow(inputGrid.getWidth(), 2)+(Math.pow(inputGrid.getHeight(), 2))));
 				
-		int dispRandX = 0;
-		int dispRandY = 0;
-		float slopeRandDisp = 0;
+		/*********************************************************************
+		 * EDGE
+		 *********************************************************************/
+		boolean[][] tmpGridSpread = new boolean[inputGrid.getWidth()][inputGrid.getHeight()];	//a temporary raster
+		tmpGridSpread = EdgeGrowth();	//calls the method "EdgeGrowth" to perform the Spread (Edge Growth) Phase
+		int anzSpread = 0;	//number of cells urbanized by Spread
+		for (int x = 0; x < inputGrid.getWidth();x++)
+			for(int y = 0; y < inputGrid.getHeight();y++){
+				int X = inputGrid.getMinX() + x;
+				int Y = inputGrid.getMinY() + y;
+				if (tmpGridSpread[X][Y]==true){
+					anzSpread++;
+					tmpGrid[X][Y] = true;	//write the temporary Spread cells to the overall temporary Cell array
+				}		
+			}
+		statusOut.println("Number of Edge Growth Cells: "+anzSpread);
+		writeToGrid(tmpGrid);	//calls the method "writeToGrid" to write the new urbanized cells to the output grid
+	
+		/*********************************************************************
+		 * ROAD
+		 *********************************************************************/
 		
-		//ROAD GRAVITY
-		double max_RG_value = 100.0;
-		double rg_value = Math.round((roadGravity/max_RG_value)*((areaWidth + areaHeight)/16)); 
-		double max_search_index = Math.round(4*((int)rg_value*(1+(int)rg_value)));
-		statusOut.println("RG-Value:"+rg_value);
-		statusOut.println("Max-SearchIndex"+max_search_index);
+		boolean[][] tmpGridRoad = new boolean[inputGrid.getWidth()][inputGrid.getHeight()];	//a temporary raster
+		tmpGridRoad = RoadGrowth(tmpGrid);	//calls the method "RoadGrowth" to perform the Road weighted growth
+		int anzRoad = 0;	//number of cells urbanized by Road Growth
+		for (int x = 0; x < inputGrid.getWidth();x++)
+			for(int y = 0; y < inputGrid.getHeight();y++){
+				int X = inputGrid.getMinX() + x;
+				int Y = inputGrid.getMinY() + y;
+				if (tmpGridRoad[X][Y]==true){
+					anzRoad++;
+					tmpGrid[X][Y] = true;	//write the temporary Road Growth cells to the overall temporary Cell array
+				}		
+			}
+		statusOut.println("Number of Road Growth Cells: "+anzRoad);
+		writeToGrid(tmpGrid);	//calls the method "writeToGrid" to write the new urbanized cells to the output grid
 		
+		
+		outStep.addGrid();
+		int anzGesamt = 0;
+		
+		// Write the temporary Grid to the Output Grid
+		for (int y = 1; y < inputGrid.getHeight()-1;y++ ) {
+			for (int x = 1; x < inputGrid.getWidth()-1; x++ ) {
+				
+				int X = inputGrid.getMinX() + x;
+				int Y = inputGrid.getMinY() + y;
+				
+				if (tmpGrid[x][y] == true)
+					anzGesamt++;
+				
+				boolean lebt = outputGrid.getRasterSampleAsFloat(X , Y ) > 0f;	//a cell is alive, when it is 1
+				if (tmpGrid[x][y] == false)	//if there is nothing in the temporary raster
+					tmpGrid[x][y] = lebt;	//take the values from the current output raster
+				
 
-		/*****************************************************************
-		 * DISPERSION and BREED
-		 *****************************************************************/
+				outputGrid.setRasterSample( tmpGrid[x][y] ? 1f : 0f ,X ,Y);	//write the results in the output raster
+				actUrb  = (Float)outputGrid.getRasterSample(x,y);	//the actual urban extent
+				outStep.getGrid(stepNo-1).setRasterSample(actUrb,x,y);	//put the layer in the raster list containing the step results
+			}
+		}
 		
-		int p = 0;	//Verteile soviel neue Pixel zufällig in geeigneten Bereichen, bis disp_value erreicht ist
+		statusOut.println("Urban pixels at step "+stepNo+": "+anzGesamt);
+	
+		System.out.println("Finished step " + (stepNo) + " in "
+				+ ((System.currentTimeMillis() - localStartTime)) + " ms\n");
+		localStartTime = System.currentTimeMillis();
+	}
+	
+	/**
+	 * This function counts the starting individual cells for the urban growth model run.<br>
+	 * It only works for a binary classification with urban cells having the value 1 and non-urban
+	 * cells the value 0.
+	 * @return startAnz
+	 */
+	public int countIndividuals(){
+		int startAnz = 0;
+		for (int i = 0; i < inputGrid.getWidth();i++ ) {
+			for (int ii = 0; ii < inputGrid.getHeight(); ii++ ) {
+				float val = inputGrid.getRasterSampleAsFloat(i,ii);
+				if (val == 1.0 ) {
+					val = 1f;
+					startAnz++;		//count if value is 1
+				}
+			else val = 0f;
+			}
+		}
+		return startAnz;
+	}
+	
+	/**
+	 * Calculates the maximum slope from the Slope Raster.
+	 * @return slopeMax
+	 */
+	public int getSlopeMax(){
+		int slopeMax = 0;
+		for (int s = 0; s < inputGrid.getWidth();s++){
+			for(int ss = 0; ss < inputGrid.getHeight();ss++){
+				float slopeVal = slopeGrid.getRasterSampleAsFloat(s,ss);
+				if (slopeVal > slopeMax){
+					slopeMax = (int) slopeVal;	//if the actual slope is larger than the highest measured slope up to now, increase the maximum value to that point
+				} 
+			}
+		}
+		return slopeMax;
+		
+	}
+	
+	/**
+	 * Takes a slope value from the slope lookup-table depending on the given cell in the slope raster.
+	 * @return slopeDoubleNb
+	 */
+	public double getSlopeValue(int X,int Y){
+		int getSlopeNb = (int) slopeGrid.getRasterSampleAsFloat(X, Y);	//takes a slope value from the slope raster
+		Double doubleObjNb = (Double)slopeLUT.get(getSlopeNb);	//looks for that slope value in the Lookup-Table and takes it as a double number
+		double slopeDoubleNb = doubleObjNb.doubleValue();	//converts the double object into a double value.
+		return slopeDoubleNb;		//returns the slope value
+	}
+	
+	/**
+	 * This is phase 1 of the growth cycle, where spontaneous growth occurs (DISPERSION). Those new cells can turn out to be
+	 * new spreading centers by urbanizing neighboring pixels (BREED {@link BreedGrowth}).
+	 * @return tmpGridDispBreed
+	 */
+	public boolean[][] DispersionGrowth(){
+		//DISPERSION
+		int dispRandX = 0;	//x-coordinate for randomly created cell
+		int dispRandY = 0;	//y-coordinate for randomly created cell
+		float slopeRandDisp = 0;	//random value in order to compare the selected dispersion cell with the slope in that cell
+		int anzDispTreffer = 0;		//Dispersion
+		int anzBreedTreffer = 0;
+		boolean[][] tmpGridDispBreed = new boolean[inputGrid.getWidth()][inputGrid.getHeight()];	//a temporary raster
+		int p = 0;	//Distribute so many new cells randomly in suitable places, until disp_value is reached.
 		do{
-			dispRandX = Math.round((float) Math.random()*areaWidth);	//Zufallsposition in X-Richtung
-			dispRandY = Math.round((float) Math.random()*areaHeight);	//Zufallsposition in Y-Richtung
+			dispRandX = Math.round((float) Math.random()*areaWidth);	//Random position in x-direction
+			dispRandY = Math.round((float) Math.random()*areaHeight);	//Random position in y-direction
 			if ( dispRandX < areaMinX || dispRandY < areaMinY || dispRandX > areaMaxX || dispRandY > areaMaxY ||
-		            Float.isNaN(outputGrid.getRasterSampleAsFloat(dispRandX,dispRandY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-		             continue;
-		        if (areaRestr.getRasterSampleAsFloat(dispRandX,dispRandY) != 0 || outputGrid.getRasterSampleAsFloat(dispRandX,dispRandY) == 1)
-		        	continue;	//wenn in Area Restriction oder wenn schon Siedlung da ist, mach weiter
-		        slopeRandDisp = (float) Math.random();						//Zufallszahl zum Abgleich mit Slope-Koeffizient
-		        int getSlope = (int) slopeGrid.getRasterSampleAsFloat(dispRandX,dispRandY);	//holt sich den Slope-Wert aus dem Slope-Raster
-		        Double doubleObj = (Double)slopeLUT.get(getSlope);		//holt den Slope-Wert aus dem Lookup-Table (get) und konvertiert in Double
-		        double slopeDouble = doubleObj.doubleValue();			//konvertiert Double-Objekt in double-Wert
-		        statusOut.println(getSlope+","+slopeDouble+"----Random: "+slopeRandDisp);
-		        if(slopeDouble < slopeRandDisp){
-		        	tmpGrid[dispRandX][dispRandY] = true;	//true wird ins temporäre Raster geschrieben
-		        	anzDispTreffer++;
-		        	//BREED
-		        	float breedRnd = (float) Math.random()*100;
-		        	int nbBreedX  = 0;
-		        	int nbBreedY  = 0;
-		        	int breedNb	  = 0;
-		        	float NbValue = 0f;
-		        	if (tmpGrid[dispRandX][dispRandY] == true && breedRnd < breed)
-		        		breedNb = calculateNeighbors(dispRandX,dispRandY,NbValue);
-		        			       
-		        	int RNBreed1 = 0;
-		        	int RNBreed2 = 0;
-		        	float RNBreedSlope = 0f;
-		        
-		        	if (breedNb >= 2 && tmpGrid[dispRandX][dispRandY] == true){
-		        		int anzBreedTemp = 0;
-		        		int[] nbPossibleBreedUrban = null;
-		        		RNBreed1 = 1 + Math.round((float)Math.random()*(breedNb-1));
-		        		RNBreed2 = 1 + Math.round((float)Math.random()*(breedNb-1));
-		        		if (RNBreed2 == RNBreed1)
-		        			RNBreed2 = 1 + Math.round((float)Math.random()*(breedNb-1));	
-		        		for (int cellBreed = 0; cellBreed < NEIGHBOR.length; cellBreed++){
-		        			nbBreedX = dispRandX+NEIGHBOR[cellBreed][0];
-		        			nbBreedY = dispRandY+NEIGHBOR[cellBreed][1];
-		        			if ( nbBreedX < areaMinX || nbBreedY < areaMinY || nbBreedX > areaMaxX || nbBreedY > areaMaxY ||
-		        					Float.isNaN(outputGrid.getRasterSampleAsFloat(nbBreedX,nbBreedY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-		        				continue;
-		        			if (areaRestr.getRasterSampleAsFloat(nbBreedX,nbBreedY) != 0)
-		        				continue;
-		        			RNBreedSlope = (float)Math.random();
-		        			int getSlopeNb = (int) slopeGrid.getRasterSampleAsFloat(nbBreedX,nbBreedY);
-		        			Double doubleObjNb = (Double)slopeLUT.get(getSlopeNb);
-		        			double slopeDoubleNb = doubleObjNb.doubleValue();
-		        			float breedSample = outputGrid.getRasterSampleAsFloat(nbBreedX,nbBreedY);
-		        			if (breedSample == 0f){
-		        				anzBreedTemp++;
-		        				nbPossibleBreedUrban = new int[] {nbBreedX,nbBreedY,anzBreedTemp};
-		        				if (nbPossibleBreedUrban[2] == RNBreed1 || nbPossibleBreedUrban[2] == RNBreed2 && slopeDoubleNb < RNBreedSlope){
-		        					tmpGrid[nbBreedX][nbBreedY] = true;
-		        					anzBreedTreffer++;
-		        				}
-		        			}
-		        		}
-		        	} 
-				}
-		        p++;
-		       
-		} while (p < disp_value);	//while, statt for-Schleife, da Überprüfung erst am Ende vorgenommen werden kann
-									//am Anfang der Schleife ist noch nicht klar, ob alle Pixel verteilt werden können
-									//da ein Teil in Ausschlussflächen etc. landen würde
+					Float.isNaN(outputGrid.getRasterSampleAsFloat(dispRandX,dispRandY)) ) 
+				continue;		//if a cell is outside the raster (NaN), break and continue loop from the beginning
+			if (areaRestr.getRasterSampleAsFloat(dispRandX,dispRandY) != 0 || outputGrid.getRasterSampleAsFloat(dispRandX,dispRandY) == 1)
+	        	continue;		//if a cell is inside an excluded area or already exists, break and continue loop from the beginning
+	        slopeRandDisp = (float) Math.random();	//a random slope value between 0.0 and 1.0
+	        double slopeDouble = getSlopeValue(dispRandX,dispRandY);	//returns the slope value for the cell
+	        if(slopeDouble < slopeRandDisp){	//if the slope value of the pixel is smaller than the slope value
+	        	tmpGridDispBreed[dispRandX][dispRandY] = true;	//true is written in the temporary raster
+	        	anzDispTreffer++;		//count number of dispersion cells
+	        	
+	        	//BREED
+	        	float breedRnd = (float) Math.random()*100;		//Breed Random value
+	        	if (tmpGridDispBreed[dispRandX][dispRandY] == true && breedRnd < breed){	//if there is a new dispersion cell and you pass the Breed-Test
+	        		int[][] tmpBreedArray = new int[2][2];	//an array containing the two x and y coordinates of two urbanized cells by breed
+	        		tmpBreedArray = BreedGrowth(dispRandX,dispRandY);	//perform a breed for this cell
+	        		int x1 = tmpBreedArray[0][0];	//x-coordinate of first cell
+	        		int y1 = tmpBreedArray[0][1];	//y-coordinate of first cell
+	        		int x2 = tmpBreedArray[1][0];	//x-coordinate of second cell
+	        		int y2 = tmpBreedArray[1][1];	//y-coordinate of second cell
+	        		tmpGridDispBreed[x1][y1] = true;	//make the temporary grid true at that position
+	        		tmpGridDispBreed[x2][y2] = true;
+	        		anzBreedTreffer += 2;	//count the hits
+	        	}
+			} p++;
+		} while (p < disp_value);	//while instead of for-loop, because it can only be checked in the end
+									//if all cells could be distributed, which is not known at the beginning of the loop.
+									//a part of the cells falls in excluded areas, etc.
+		statusOut.println("Dispersion-Treffer: "+anzDispTreffer);
+		statusOut.println("Breed-Treffer: "+anzBreedTreffer);
+		return tmpGridDispBreed;	//returns a temporary Array containing the newly urbanized cells by the dispersion and breed growth rules
+	}
 	
-		/*********************************************************************
-		 * EDGE
-		 *********************************************************************/
+	/**
+	 * This is phase 2 of the growth cycle. New spreading centers can induce new growth right in the neighborhood,
+	 * which is calles "breed". This method is fired by new dispersion cells (@link DispersionGrowth), as well as
+	 * by new road cells ({@link RoadGrowth}).
+	 * @param X
+	 * @param Y
+	 * @return tmpBreedArray
+	 */
+	public int[][] BreedGrowth(int X,int Y){
+		boolean[][] tmpGridBreed = new boolean[inputGrid.getWidth()][inputGrid.getHeight()];	//a temporary raster
+		int[][] tmpBreedArray = new int[2][2];	//an array containing the x and y coordinates of two cells
+		int anzBreedTreffer = 0;	//Breed
+    	int breedNb = calculateNeighbors(X,Y,0f);	//calculate number of neighbors of a new spreading center cell
+    	int nbBreedX  = 0;	//x-coordinate of neighbouring cells of new spreading center cell
+    	int nbBreedY  = 0;	//y-coordinate of neighbouring cells of new spreading center cell
+    	int RNBreed1 = 0;	//1st Random number for breed
+    	int RNBreed2 = 0;	//2nd Random number for breed
+    	float RNBreedSlope = 0f;	//Slope value of the randomly selected breed cell
+    	if (breedNb >= 2){		//if 2 or more neighbor cells are available around a new dispersion cell
+    		int anzBreedTemp = 0;	//number of temporary breed cells
+    		int[] nbPossibleBreedUrban = null;	//Array of possible breed cells
+    		RNBreed1 = 1 + Math.round((float)Math.random()*(breedNb-1));	//take the first neighbor cell by random (between 1 and the Sum of neighbor cells)
+    		RNBreed2 = 1 + Math.round((float)Math.random()*(breedNb-1));	//take the second neighbor cell by random (between 1 and the Sum of neighbor cells)
+    		do{
+    			RNBreed2 = 1 + Math.round((float)Math.random()*(breedNb-1));
+    		} while (RNBreed2 == RNBreed1);//if the second cell is the same as the first cell try again until the second random number is different from the first
+    		
+    		for (int cellBreed = 0; cellBreed < NEIGHBOR.length; cellBreed++){	//for every cell in the neighborhood...
+    			nbBreedX = X+NEIGHBOR[cellBreed][0];
+    			nbBreedY = Y+NEIGHBOR[cellBreed][1];
+    			if ( nbBreedX < areaMinX || nbBreedY < areaMinY || nbBreedX > areaMaxX || nbBreedY > areaMaxY ||
+    					Float.isNaN(outputGrid.getRasterSampleAsFloat(nbBreedX,nbBreedY)) ) 
+    				continue;	//if a cell is outside the raster (NaN), break and continue loop from the beginning
+    			if (areaRestr.getRasterSampleAsFloat(nbBreedX,nbBreedY) != 0)
+    				continue;	//if a cell is inside an excluded area, break and continue loop from the beginning
+    			RNBreedSlope = (float)Math.random();	//a random slope value between 0.0 and 1.0
+    			double slopeDoubleNb = getSlopeValue(nbBreedX,nbBreedY);	//returns the slope value for the neighboring cells which are available for breed
+    			float breedSample = outputGrid.getRasterSampleAsFloat(nbBreedX,nbBreedY);	//takes the value from the input grid
+    			if (breedSample == 0f){		//if it is free for urbanization...
+    				anzBreedTemp++;		//increase the number of temporary breed cells
+    				nbPossibleBreedUrban = new int[] {nbBreedX,nbBreedY,anzBreedTemp};	//create a new array containing the x and y coordinates and the number of the breed pixel
+    				if (nbPossibleBreedUrban[2] == RNBreed1 || nbPossibleBreedUrban[2] == RNBreed2 && slopeDoubleNb < RNBreedSlope){	//if the cell has the same value as the first or second random value and its slope value is smaller than the random slope value...
+    					tmpBreedArray[anzBreedTreffer][0] = nbBreedX;	//x-coordinate
+    					tmpBreedArray[anzBreedTreffer][1] = nbBreedY;	//y-coordinate
+    					tmpGridBreed[nbBreedX][nbBreedY] = true;	//urbanize the cell in the temporary grid
+    					anzBreedTreffer++;		//and increase the number of breed cells
+    				}
+    			}
+    		}
+    	}
+		return tmpBreedArray; 
+	}
+	
+	
+	/**
+	 * This is phase 3 of the growth cycle, where edge growth appears based on the urban pixels that exist at 
+	 * this time (including the new spontaneous and spreading center pixels).
+	 * @return tmpGridSpread
+	 */
+	public boolean[][] EdgeGrowth(){
 		
+		boolean[][] tmpGridSpread = new boolean[inputGrid.getWidth()][inputGrid.getHeight()];	//a temporary raster
+		//definitions for neighborhood cells
+		int nbX = 0; // X-Coordinate of a neighboring cell
+	    int nbY = 0; // Y-Coordinate of a neighboring cell
+	    
+		int anzSpreadTreffer = 0;	//Number of Spread cells
+		
 		//iterate over all cells
 		for (int x = 0; x < inputGrid.getWidth(); x++)
-			for (int y = 0; y < inputGrid.getHeight(); y++) {		//für jede Zelle in x/y-Richtung
+			for (int y = 0; y < inputGrid.getHeight(); y++) {		//for every cell in x/y direction...
 				
-				int areaMinXadd = areaMinX + x;								//Dimensionen des Rasters
-				int areaMinYadd = areaMinY + y;
+				int areaMinXadd = areaMinX + x;		//x-coordinate cell in the raster
+				int areaMinYadd = areaMinY + y;		//y-coordinate cell in the raster
 				
-				int anzNachbarn = 0;
-				int noNachbarn = 0;
-			
+				int anzNachbarn = calculateNeighbors(x,y,1f);	//number of urban neighbors
 				
-				for (int nbCellIdx = 0; nbCellIdx < NEIGHBOR.length; nbCellIdx++) {
-					checkBreakingCommands();
-					nbX = x+NEIGHBOR[nbCellIdx][0];		//Nachbarschaft der Zellen
-			        nbY = y+NEIGHBOR[nbCellIdx][1];
-			        nbCell = new int[] {nbX,nbY};		//jede Nachbarzelle
-			        if ( nbX < areaMinX || nbY < areaMinY || nbX > areaMaxX || nbY > areaMaxY ||
-			               Float.isNaN(outputGrid.getRasterSampleAsFloat(nbX,nbY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-			             continue;
-			        if (areaRestr.getRasterSampleAsFloat(nbX,nbY) != 0)
-			        	continue;
-					float rasterSample = outputGrid.getRasterSampleAsFloat(nbX,nbY);
-					if (rasterSample > 0f)		//ist Nachbarzelle urban (1), wird sie gezählt
-						anzNachbarn++;
-					if (rasterSample == 0f)
-						noNachbarn++;
-				}
+				boolean lebt = outputGrid.getRasterSampleAsFloat(areaMinXadd, areaMinYadd ) > 0f;	//a cell is alive if it is 1
 				
-				boolean lebt = outputGrid.getRasterSampleAsFloat(areaMinXadd , areaMinYadd ) > 0f;	//eine Zelle lebt, wenn sie 1 ist
-				
-				//hier ist die Abfrage wieviele Nachbarzellen am Leben sind
-				//daraus ergibt sich, ob im tmpGrid die entsprechende Zelle
-				//true oder false ist
-				
-				float SpR = (float) Math.random()*100;						//eine Zufallszahl zwischen 0 und 1
-				int RN = 0; 	//hier wird eine Integer-Zufallszahl reingeschrieben
-				
-				if (lebt && (anzNachbarn>=2) && (SpR < spread) && (noNachbarn >=1)) {	//wenn eine Zelle lebt, mindestens 2 lebende Nachbarzellen hat, der Spread-Koeffizient größer als die für die Zelle berechnete Zufallszahl und mindestens einen nicht lebenden Nachbarn hat
-					int anzTemp = 0;
-					int[] nbPossibleUrban = null;
-					RN = 1 + Math.round((float)Math.random()*(noNachbarn-1));
+				int SpR = Math.round((float) Math.random()*100);				//a random number to compare with the spread coefficient
+				if (lebt && (anzNachbarn>=2) && (SpR < spread) && (anzNachbarn < 8)) {	//if a cell is alive, it has more or equal than two urban neighbors and less than 8 urban neighbors (at least 1 non-urban neighbor) and we pass the spread coefficient test...
+					int anzTemp = 0;		//temporary possible cells for urbanization
+					int[] nbPossibleUrban = null;	//array with coordinates of possible cells for urbanization
+					//int RN = 1 + Math.round((float)Math.random()*(8-anzNachbarn-1));	//this is an option to distribute the ranom number only between the possible cells for urbanization
+					int RN = (int) Math.round(8*Math.random());	//a random number between 0 and 8
 					float RNEdgeSlope = 0;
-					int nbUrbanX = 0;
-					int nbUrbanY = 0;
-					for (int nbCellChange = 0; nbCellChange < NEIGHBOR.length; nbCellChange++){	//dann starte eine Schleife
+					for (int nbCellChange = 0; nbCellChange < NEIGHBOR.length; nbCellChange++){	//loop over all neighbor cells
 						checkBreakingCommands();
 						nbX = x+NEIGHBOR[nbCellChange][0];
 						nbY = y+NEIGHBOR[nbCellChange][1];
 						if ( nbX < areaMinX || nbY < areaMinY || nbX > areaMaxX || nbY > areaMaxY ||
-					               Float.isNaN(outputGrid.getRasterSampleAsFloat(nbX,nbY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-					             continue;
+					               Float.isNaN(outputGrid.getRasterSampleAsFloat(nbX,nbY)))
+					             continue;	//if a cell is outside the raster (NaN), break and continue loop from the beginning
 						if (areaRestr.getRasterSampleAsFloat(nbX,nbY) != 0)
-				        	continue;
-						RNEdgeSlope = (float)Math.random();
-	        			int getSlopeNb = (int) slopeGrid.getRasterSampleAsFloat(nbX,nbY);
-	        			Double doubleObjNb = (Double)slopeLUT.get(getSlopeNb);
-	        			double slopeDoubleNb = doubleObjNb.doubleValue();
-						float rasterSample = outputGrid.getRasterSampleAsFloat(nbX,nbY);	//holt die Werte aus den jeweiligen Nachbarzellen
-						if (rasterSample == 0f){	//wenn der Wert 0 ist
-							anzTemp++;				//wird Anzahl der möglichen Zellen erhöht
-							nbPossibleUrban = new int[] {nbX,nbY,anzTemp};	//Koordinaten und Nummern dieser Zellen werden in Array geschrieben 
-							int urbanNbTemp = 0;
-							float NbValueEdge = 1f;
-							if (nbPossibleUrban[2] == RN){	//wenn Nummer im "PossibleUrban"-Array der Zufallszahl entspricht, die zwischen 1 und Anzahl der möglichen Zellen liegt...
-								//damit die Städte nicht zu sehr "ausfransen" steht eine Zelle nur zur Umwandlung zur Verfügung, wenn auch sie mind. 2 urbane Nachbarn hat
-								urbanNbTemp = calculateNeighbors(nbX,nbY,NbValueEdge);
-								if (urbanNbTemp >= 2 && tmpGrid[nbX][nbY]==false && slopeDoubleNb < RNEdgeSlope){
-									tmpGrid[nbX][nbY] = true;	//wird true ins temporäre Raster geschrieben
-									anzSpreadTreffer++;
+				        	continue;	//if a cell is inside an excluded area, break and continue loop from the beginning
+						RNEdgeSlope = (float)Math.random();		//a random number to be compared with the slope value
+						double slopeDoubleNb = getSlopeValue(nbX,nbY);	//returns the slope value for the neighboring cells which are available for breed
+	        			float rasterSample = outputGrid.getRasterSampleAsFloat(nbX,nbY);	//takes the value from the input gridn
+						if (rasterSample == 0f){	//if the value is 0 and thus is possible for urbanization
+							anzTemp++;				//count it
+							nbPossibleUrban = new int[] {nbX,nbY,anzTemp};	//write it with its coordinates in an array
+							//float NbValueEdge = 1f;
+							if (nbPossibleUrban[2] == RN){	//if the number in the "possible for urbanization" array is the same as the random number...
+								//int urbanNbTemp = calculateNeighbors(nbX,nbY,NbValueEdge);	//to reduce the effect of edge growth here could be included an option that allows only growth when a new urban cell has at least 2 urban neighbors
+								if (tmpGridSpread[nbX][nbY]==false && slopeDoubleNb < RNEdgeSlope){	// if the cell is non-urban and it passes the slope test //urbanNbTemp >= 2 && 
+									tmpGridSpread[nbX][nbY] = true;	//write it in the temporary raster
+									anzSpreadTreffer++;	//count the hits
 								}
 							} 
 						}
-						nbCell = new int[] {nbX,nbY,(int) rasterSample};	
 					}
 				}
-				if (anzNachbarn>0) anyBodyAlive = true;		
 			}
+		return tmpGridSpread;	//returns the temporary array
+	}
+	
+	/**
+	 * This is phase 4 of the growth cycle, where growth along roads appears. Every newly developed cell can induce road growth.
+	 * Therefore for a defined number of new cells (by the breed-coeffient) the algorithm looks for a road in the neighborhood.
+	 * If the new cell is located directly on a road, the algorithm starts a "road walk" ({@link roadWalk}), and moves a new cell along the road
+	 * to a defined distance. If the new cell is not on a road, it looks for a road in a defined neighborhood (by {@code rg_value}). 
+	 * If a road is found, it starts a "road walk" from there.
+	 * @param tmpGrid
+	 * @return tmpGridRoad
+	 */
+	public boolean[][] RoadGrowth(boolean[][] tmpGrid){
+		boolean[][] tmpGridRoad = new boolean[inputGrid.getWidth()][inputGrid.getHeight()];	//a temporary raster
+		int anzGesamt = countTempUrbanCells(tmpGrid);	//number of urban cells in the temporary cell array
+		int anzRoadTreffer = 0;
+		int[] cellValue = null;	//array of cell values
+		int RSearchRoad = 0;	//Random Road Search Index
+		int r = 1;	//number between 1 and the disp-Value, whih is increased during the follwing while-loop. It determines how many pixels are selected randomly for a possible road trip
 		
-		/*********************************************************************
-		 * ROAD
-		 *********************************************************************/
-		
-		int anzGesamt = 0;
-		int[] cellValue = null;
-		
-		//For-Schleife zählt alle als true markierten Zellen im Temp-Raster
-		for (int x = 0; x < inputGrid.getWidth();x++)
-			for(int y = 0; y < inputGrid.getHeight();y++){
-				int X = inputGrid.getMinX() + x;
-				int Y = inputGrid.getMinY() + y;
-				if (tmpGrid[X][Y]==true){
-					anzGesamt++;
-				}		
-			}
-		
-		int RSearchRoad = 0;
-		int r = 1;	//Verteile soviel neue Pixel zufällig in geeigneten Bereichen, bis disp_value erreicht ist
-		
-		Rectangle gridBounds = new Rectangle(0, 0, inputGrid.getWidth(), inputGrid.getHeight()); //ein Rechteck wird definiert
 		do{
-			RSearchRoad = Math.round((float)Math.random()*anzGesamt);	//Zufallszahl zwischen 1 und Anzahl aller bisher neu hinzugekommener Pixel
-			int anzTruePixels = 0;
+			RSearchRoad = Math.round((float)Math.random()*anzGesamt);	//a random value between 1 and the total amount of newly urbanized pixels
+			int anzTruePixels = 0;	
 			int roadNeighborhoodRange = 0;
 			int RSearchNbRoad = 0;
-			for (int x = 0; x < inputGrid.getWidth();x++){		//gesamtes Raster wird durchsucht
+			for (int x = 0; x < inputGrid.getWidth();x++){		//for every cell in the raster...
 				for(int y = 0; y < inputGrid.getHeight();y++){
-					int X = inputGrid.getMinX() + x;
-					int Y = inputGrid.getMinY() + y;
-					if (tmpGrid[X][Y]==true){
-						anzTruePixels++;		//wird true-Pixel gefunden, wird anzTruePixels hochgezählt
-						cellValue = new int[] {X,Y,anzTruePixels};	//und Koordinaten in Array geschrieben
-						int tempRoadCell[] = null;
-						int tempNbRoadCell[] = null;
-						if (cellValue[2] == RSearchRoad){
-							//statusOut.println(cellValue[0]+","+cellValue[1]+","+cellValue[2]);
-							//statusOut.println(r+","+RSearchRoad);
-							r++;
-							//JETZT NACH STRAßE SUCHEN!!
-							float roadValue = roadGrid.getRasterSampleAsFloat(X,Y);
-							statusOut.println(roadValue);
-							if (roadValue > 0.0){
-								tempRoadCell = new int[] {X,Y};
-								statusOut.println("Strasse in Entfernung 0: "+tempRoadCell[0]+","+tempRoadCell[1]);
-								//roadWalk(tempRoadCell[0],tempRoadCell[1]);
-								int nbCellNew[] = roadWalk(tempRoadCell[0],tempRoadCell[1]);
-								if(nbCellNew != null){
-									tmpGrid[nbCellNew[0]][nbCellNew[1]] = true;
-									statusOut.println(nbCellNew.length);
-									statusOut.println("Neue Zelle: "+nbCellNew[0]+","+nbCellNew[1]);
-									statusOut.println("++++++++++++++++++++++++++++++++++++++++");
-									float nbRoadBreed = 0f;
-									int nbRoadBreedNeighbors = 0;
-									nbRoadBreedNeighbors = calculateNeighbors(nbCellNew[0],nbCellNew[1],nbRoadBreed);
-									int RNRoadBreed1 = 0;
-							        int RNRoadBreed2 = 0;
-							        int nbRoadBreedX = 0;
-							        int nbRoadBreedY = 0;
-							        int anzRoadBreedTreffer = 0;
-							        
-									if (nbRoadBreedNeighbors >= 2){
-										int anzBreedTemp = 0;
-										int[] nbPossibleBreedUrban = null;
-										RNRoadBreed1 = 1 + Math.round((float)Math.random()*(nbRoadBreedNeighbors-1));
-										RNRoadBreed2 = 1 + Math.round((float)Math.random()*(nbRoadBreedNeighbors-1));
-										float RNRoadBreedSlope = 0f;
-										
-										if (RNRoadBreed2 == RNRoadBreed1)
-											RNRoadBreed2 = 1 + Math.round((float)Math.random()*(nbRoadBreedNeighbors-1));	
-										for (int cellBreed = 0; cellBreed < NEIGHBOR.length; cellBreed++){
-							        		nbRoadBreedX = nbCellNew[0]+NEIGHBOR[cellBreed][0];
-											nbRoadBreedY = nbCellNew[1]+NEIGHBOR[cellBreed][1];
-											if ( nbRoadBreedX < areaMinX || nbRoadBreedY < areaMinY || nbRoadBreedX > areaMaxX || nbRoadBreedY > areaMaxY ||
-										               Float.isNaN(outputGrid.getRasterSampleAsFloat(nbRoadBreedX,nbRoadBreedY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-										             continue;
-											if (areaRestr.getRasterSampleAsFloat(nbRoadBreedX,nbRoadBreedY) != 0)
-									        	continue;
-											RNRoadBreedSlope = (float)Math.random();
-						        			int getSlopeNb = (int) slopeGrid.getRasterSampleAsFloat(nbRoadBreedX,nbRoadBreedY);
-						        			Double doubleObjNb = (Double)slopeLUT.get(getSlopeNb);
-						        			double slopeDoubleNb = doubleObjNb.doubleValue();
-											float breedSample = outputGrid.getRasterSampleAsFloat(nbRoadBreedX,nbRoadBreedY);
-											if (breedSample == 0f){
-												anzBreedTemp++;
-												nbPossibleBreedUrban = new int[] {nbRoadBreedX,nbRoadBreedY,anzBreedTemp};
-												if (nbPossibleBreedUrban[2] == RNRoadBreed1 || nbPossibleBreedUrban[2] == RNRoadBreed2 && slopeDoubleNb < RNRoadBreedSlope){
-													tmpGrid[nbRoadBreedX][nbRoadBreedY] = true;
-													anzRoadBreedTreffer++;
-													statusOut.println("Road-Breed-Treffer: "+anzRoadBreedTreffer);
-												}
-											}
-										}
-							        	
-							        
-									}
-									
+					int X = inputGrid.getMinX() + x;	//x-coordinate cell in the raster
+					int Y = inputGrid.getMinY() + y;	//y-coordinate cell in the raster
+					if (tmpGrid[X][Y]==true){	//if a new urbanized cell is found
+						anzTruePixels++;		//count the number of urban pixels, and...(and this is different to "countTempUrbanCells")
+						cellValue = new int[] {X,Y,anzTruePixels};	//write them with their coordinates in an array
+						int tempRoadCell[] = null;		//an array of temporary road cells
+						int tempNbRoadCell[] = null;	//an array of temporary neighboring cells of these road cells
+						if (cellValue[2] == RSearchRoad){	//randomly select a growth pixel to start search for road (by comparing the cell number with the generated random number between 1 and total amount of new cells)
+							r++;	//increase r, because a potential road trip pixel has been selected
+							float roadValue = roadGrid.getRasterSampleAsFloat(X,Y);	//take the value from the road map for that pixel
+							if (roadValue > 0.0){		//if the value is greater than 0 and thus is a road...
+								tempRoadCell = new int[] {X,Y};		//add its coordinates to the temporary road grid
+								//statusOut.println("Strasse in Entfernung 0: "+tempRoadCell[0]+","+tempRoadCell[1]);
+								int nbCellNew[] = roadWalk(tempRoadCell[0],tempRoadCell[1]);	//perform a road walk
+								if(nbCellNew != null){	//if the result of the road walk is positive,...
+									tmpGridRoad[nbCellNew[0]][nbCellNew[1]] = true;		//place a new urban pixel in the temporary Grid
+									anzRoadTreffer++;
+									int[][] tmpBreedArray = new int[2][2];	//an array containing the x and y coordinates of two breed cells
+									tmpBreedArray = BreedGrowth(nbCellNew[0],nbCellNew[1]);	//this new urban cell can act as a new spreading center:
+									int x1 = tmpBreedArray[0][0];	//x-coordinate of first cell
+					        		int y1 = tmpBreedArray[0][1];	//y-coordinate of first cell
+					        		int x2 = tmpBreedArray[1][0];	//x-coordinate of second cell
+					        		int y2 = tmpBreedArray[1][1];	//y-coordinate of second cell
+					        		tmpGridRoad[x1][y1] = true;	//make the temporary grid true at that position
+					        		tmpGridRoad[x2][y2] = true;
+									anzRoadTreffer += 2;
 								} else{
-									statusOut.println("Keine neue Zelle gefunden");
+							//		statusOut.println("No new RoadBreedCells found directly");
 								}
-							} else{
+							} else{		//if the selected pixel has not been a road pixel search in the neighborhood for a road
 								int anzRoadNb = 0;
 								
-								//HIER MIT FOR SCHLEIFE RECHTECK WACHSEN LASSEN!!!
+								//With a loop look in the neighborhood for a road in an increasing radius until you reach the road gravity value
 								for (int roadSearch = 0; roadSearch <= rg_value; roadSearch++){
-									if (anzRoadNb > 0)
+									if (anzRoadNb > 0)	//if a road is found break and continue from the beginning (the next loops will end here as well until it stops when rg_value ist reached)
 										continue;
 									for (int nbRoadCellsX = X - roadNeighborhoodRange; nbRoadCellsX <= X + roadNeighborhoodRange; nbRoadCellsX++){
-										for (int nbRoadCellsY = Y - roadNeighborhoodRange; nbRoadCellsY <= Y + roadNeighborhoodRange; nbRoadCellsY++){
-											if (gridBounds.contains(nbRoadCellsX, nbRoadCellsY))
-												if ( nbRoadCellsX < areaMinX || nbRoadCellsY < areaMinY || nbRoadCellsX > areaMaxX || nbRoadCellsY > areaMaxY ||
-														Float.isNaN(outputGrid.getRasterSampleAsFloat(nbRoadCellsX,nbRoadCellsY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-													continue;
-												if (areaRestr.getRasterSampleAsFloat(nbRoadCellsX,nbRoadCellsY) != 0)
-													continue;
-												float roadValueNb = roadGrid.getRasterSampleAsFloat(nbRoadCellsX,nbRoadCellsY);
-												if (roadValueNb > 0f){
-													anzRoadNb++;
-												}
-												//statusOut.println("Strasse in Entfernung 1: "+anzRoadNb+","+nbRoadCellsX+","+nbRoadCellsY);
+										for (int nbRoadCellsY = Y - roadNeighborhoodRange; nbRoadCellsY <= Y + roadNeighborhoodRange; nbRoadCellsY++){	//increase the neighborhood in every loop
+											if ( nbRoadCellsX < areaMinX || nbRoadCellsY < areaMinY || nbRoadCellsX > areaMaxX || nbRoadCellsY > areaMaxY ||
+													Float.isNaN(outputGrid.getRasterSampleAsFloat(nbRoadCellsX,nbRoadCellsY)) )
+												continue;	//if a cell is outside the raster (NaN), break and continue loop from the beginning
+											float roadValueNb = roadGrid.getRasterSampleAsFloat(nbRoadCellsX,nbRoadCellsY);		//take the value from the road map for that pixel
+											if (roadValueNb > 0f){	//if the value is greater than 0 and thus is a road...
+												anzRoadNb++;	//increase the number of road neighbors
+											}
 										}
 									}
-									roadNeighborhoodRange++;
-									RSearchNbRoad = Math.round((float)Math.random()*anzRoadNb);
-									//statusOut.println("--> Zyklus "+roadNeighborhoodRange+"Nachbarn: "+anzRoadNb);
-									//statusOut.println(RSearchNbRoad);
-									int anzTempRoadNb = 0;
+									roadNeighborhoodRange++;	//increase the road neighborhood range
+									RSearchNbRoad = Math.round((float)Math.random()*anzRoadNb);		//a random value between 0 and the number of road neighbors
+									int anzTempRoadNb = 0;	//number of temporary road neighbors
 									for (int nbRoadCellsX = X - roadNeighborhoodRange; nbRoadCellsX <= X + roadNeighborhoodRange; nbRoadCellsX++){
-										for (int nbRoadCellsY = Y - roadNeighborhoodRange; nbRoadCellsY <= Y + roadNeighborhoodRange; nbRoadCellsY++){
-						        			statusOut.println("TEST-ROAD: "+nbRoadCellsX+","+nbRoadCellsY);
-											if (gridBounds.contains(nbRoadCellsX, nbRoadCellsY))
+										for (int nbRoadCellsY = Y - roadNeighborhoodRange; nbRoadCellsY <= Y + roadNeighborhoodRange; nbRoadCellsY++){	//again increase the neighborhood in every loop
+						        		//	statusOut.println("TEST-ROAD: "+nbRoadCellsX+","+nbRoadCellsY);
 											if ( nbRoadCellsX < areaMinX || nbRoadCellsY < areaMinY || nbRoadCellsX > areaMaxX || nbRoadCellsY > areaMaxY ||
 													Float.isNaN(outputGrid.getRasterSampleAsFloat(nbRoadCellsX,nbRoadCellsY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-												continue;
-											if (areaRestr.getRasterSampleAsFloat(nbRoadCellsX,nbRoadCellsY) != 0)
-												continue;
-											float roadValueNbTemp = roadGrid.getRasterSampleAsFloat(nbRoadCellsX,nbRoadCellsY);
-											if (roadValueNbTemp > 0f){
-												anzTempRoadNb++;
-												tempNbRoadCell = new int[] {nbRoadCellsX,nbRoadCellsY,anzTempRoadNb};
-												if (tempNbRoadCell[2]==RSearchNbRoad){
-													//statusOut.println("Treffer: "+tempNbRoadCell[0]+","+tempNbRoadCell[1]+","+tempNbRoadCell[2]);
-													tempRoadCell = tempNbRoadCell;
-													statusOut.println("Strasse in Entfernung "+roadSearch+": "+tempRoadCell[0]+","+tempRoadCell[1]+","+tempRoadCell[2]);
-													//roadWalk(tempRoadCell[0],tempRoadCell[1]);
-													int nbCellNew[] = roadWalk(tempRoadCell[0],tempRoadCell[1]);
-													if(nbCellNew != null){
-														tmpGrid[nbCellNew[0]][nbCellNew[1]] = true;
-														statusOut.println(nbCellNew.length);
-														statusOut.println("Neue Zelle: "+nbCellNew[0]+","+nbCellNew[1]);
-														statusOut.println("++++++++++++++++++++++++++++++++++++++++");
-														
-														float nbRoadBreed = 0f;
-														int nbRoadBreedNeighbors = 0;
-														nbRoadBreedNeighbors = calculateNeighbors(nbCellNew[0],nbCellNew[1],nbRoadBreed);
-														int RNRoadBreed1 = 0;
-												        int RNRoadBreed2 = 0;
-												        int nbRoadBreedX = 0;
-												        int nbRoadBreedY = 0;
-												        int anzRoadBreedTreffer = 0;
-												        
-														if (nbRoadBreedNeighbors >= 2){
-															int anzBreedTemp = 0;
-															int[] nbPossibleBreedUrban = null;
-															RNRoadBreed1 = 1 + Math.round((float)Math.random()*(nbRoadBreedNeighbors-1));
-															RNRoadBreed2 = 1 + Math.round((float)Math.random()*(nbRoadBreedNeighbors-1));
-															float RNRoadBreedSlope = 0f;
-															if (RNRoadBreed2 == RNRoadBreed1)
-																RNRoadBreed2 = 1 + Math.round((float)Math.random()*(nbRoadBreedNeighbors-1));	
-															for (int cellBreed = 0; cellBreed < NEIGHBOR.length; cellBreed++){
-												        		nbRoadBreedX = nbCellNew[0]+NEIGHBOR[cellBreed][0];
-																nbRoadBreedY = nbCellNew[1]+NEIGHBOR[cellBreed][1];
-																if ( nbRoadBreedX < areaMinX || nbRoadBreedY < areaMinY || nbRoadBreedX > areaMaxX || nbRoadBreedY > areaMaxY ||
-															               Float.isNaN(outputGrid.getRasterSampleAsFloat(nbRoadBreedX,nbRoadBreedY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-															             continue;
-																if (areaRestr.getRasterSampleAsFloat(nbRoadBreedX,nbRoadBreedY) != 0)
-														        	continue;
-																RNRoadBreedSlope = (float)Math.random();
-											        			int getSlopeNb = (int) slopeGrid.getRasterSampleAsFloat(nbRoadBreedX,nbRoadBreedY);
-											        			Double doubleObjNb = (Double)slopeLUT.get(getSlopeNb);
-											        			double slopeDoubleNb = doubleObjNb.doubleValue();
-																float breedSample = outputGrid.getRasterSampleAsFloat(nbRoadBreedX,nbRoadBreedY);
-																if (breedSample == 0f){
-																	anzBreedTemp++;
-																	nbPossibleBreedUrban = new int[] {nbRoadBreedX,nbRoadBreedY,anzBreedTemp};
-																	if (nbPossibleBreedUrban[2] == RNRoadBreed1 || nbPossibleBreedUrban[2] == RNRoadBreed2 && slopeDoubleNb < RNRoadBreedSlope){
-																		tmpGrid[nbRoadBreedX][nbRoadBreedY] = true;
-																		anzRoadBreedTreffer++;
-																		statusOut.println("Road-Breed-Treffer: "+anzRoadBreedTreffer);
-																	}
-																}
-															}
-												        	
-												        
-														}
+												continue;	//if a cell is outside the raster (NaN), break and continue loop from the beginning
+											float roadValueNbTemp = roadGrid.getRasterSampleAsFloat(nbRoadCellsX,nbRoadCellsY);	//take the road value from that pixel
+											if (roadValueNbTemp > 0f){	//if the value is greater than 0 and thus is a road... 
+												anzTempRoadNb++;	//increase the number of temporary road neighbors
+												tempNbRoadCell = new int[] {nbRoadCellsX,nbRoadCellsY,anzTempRoadNb};	//build an array of neighboring road cells with its coordinates
+												if (tempNbRoadCell[2]==RSearchNbRoad){	//check the position in that array with the random number
+													tempRoadCell = tempNbRoadCell;	//the main temporary road cell is moved to this position
+													//statusOut.println("Strasse in Entfernung "+roadSearch+": "+tempRoadCell[0]+","+tempRoadCell[1]+","+tempRoadCell[2]);
+													int nbCellNew[] = roadWalk(tempRoadCell[0],tempRoadCell[1]);	//perform a road walk
+													if(nbCellNew != null){	//if the result of the road walk is positive,...
+														tmpGridRoad[nbCellNew[0]][nbCellNew[1]] = true;	//place a new urban cell in the temporary grid
+														anzRoadTreffer++;
+														int[][] tmpBreedArray = new int[2][2];
+														tmpBreedArray = BreedGrowth(nbCellNew[0],nbCellNew[1]);
+														int x1 = tmpBreedArray[0][0];
+										        		int y1 = tmpBreedArray[0][1];
+										        		int x2 = tmpBreedArray[1][0];
+										        		int y2 = tmpBreedArray[1][1];
+										        		tmpGridRoad[x1][y1] = true;
+										        		tmpGridRoad[x2][y2] = true;
+														anzRoadTreffer += 2;
 													} else{
-														statusOut.println("Keine neue Zelle gefunden");
+											//			statusOut.println("No new road cell found after road search.");
 													}
 												}
 											}
@@ -660,142 +733,98 @@
 			}
 			
 		} while (r <= breed);
-		
-		statusOut.println("Spread-Treffer: "+anzSpreadTreffer);
-		statusOut.println("Dispersion-Treffer: "+anzDispTreffer);
-		statusOut.println("Breed-Treffer: "+anzBreedTreffer);
-		statusOut.println("Treffer gesamt: "+anzGesamt);
-		
-		outStep.addGrid();
-		
-		
-		// TempGrid auf das echte Grid schreiben
-		for (int y = 1; y < inputGrid.getHeight()-1;y++ ) {
-			for (int x = 1; x < inputGrid.getWidth()-1; x++ ) {
-				
-				int X = inputGrid.getMinX() + x;
-				int Y = inputGrid.getMinY() + y;
-				
-				boolean lebt = outputGrid.getRasterSampleAsFloat(X , Y ) > 0f;	//eine Zelle lebt, wenn sie 1 ist
-				if (tmpGrid[x][y] == false)	//wenn im temporären Raster nichts drinsteht...
-					tmpGrid[x][y] = lebt;	//wird der Wert aus dem Ausgangsraster übernommen
-					
-
-				outputGrid.setRasterSample( tmpGrid[x][y] ? 1f : 0f ,X ,Y);	
-				actUrb  = (Float)outputGrid.getRasterSample(x,y);
-				outStep.getGrid(stepNo-1).setRasterSample(actUrb,x,y);
-			}
-		}
-		
-		
-		if (!anyBodyAlive) {
-			stepCount = stepNo;
-			statusOut.println("Lebt keiner mehr... höre hier auf!");
-		}
-		
-		
-		System.out.println("Finished step " + (stepNo) + " in "
-				+ ((System.currentTimeMillis() - localStartTime)) + " ms\n");
-		localStartTime = System.currentTimeMillis();
+		statusOut.println("Road-Treffer: "+anzRoadTreffer);
+		return tmpGridRoad;
 	}
 	
-	private int[] roadWalk(int X,int Y){
-//		statusOut.println(X+","+Y);
-		boolean end_of_road;
-		end_of_road = false;
-		int run = 0;
-		int run_value = 0;
-		int[] nbCellNew = null;
-		int[] nbCellTemp = null;
-		while(!end_of_road){
-			end_of_road = true;
-			int nbRoadX = 0;
+	/**
+	 * This method performs a walk along a road starting from an initial cell with the coordinates X, Y.
+	 * It returns the position of the final cell after the road walk, which than can start a new urbanization.
+	 * @param X
+	 * @param Y
+	 * @return nbCellNew
+	 */
+	public int[] roadWalk(int X,int Y){
+		boolean end_of_road = false;	//start with the assumption that the end of the road trip is not completed yet	
+		int run = 0;	//distance a cell is moving
+		int run_value = 0;	//maximum moving distance
+		int[] nbCellNew = null;	 //Array containing the coordinates of the new urbanized cells after the road walk
+		int[] nbCellTemp = null;	//Array containing the neighbors of the end cell
+		while(!end_of_road){	//until the end of the road is not reached...
+			end_of_road = true;		//say that this is so
+			int nbRoadX = 0;	//neighborhood of the cell
 			int nbRoadY = 0;
-			int areaMinX = inputGrid.getMinX();								//Dimensionen des Rasters
+			int areaMinX = inputGrid.getMinX();								//raster dimensions
 			int areaMinY = inputGrid.getMinY();
 			int areaMaxX = inputGrid.getMinX() + inputGrid.getWidth() - 1;
 			int areaMaxY = inputGrid.getMinY() + inputGrid.getHeight() - 1;
-			int roadNb = 0;
-			int roadNbTemp = 0;
-			int RN = 0;
+			int roadNb = 0;		//number of neighboring cells
+			int roadNbTemp = 0;	//number of neighboring cells
+			int RN = 0;	//a random number
 						
-			int[] nbCell = null;
-			for (int nbRoadCells = 0; nbRoadCells < NEIGHBOR.length; nbRoadCells++){
-				nbRoadX = X+NEIGHBOR[nbRoadCells][0];
+			int[] nbCell = null;	//Array containing a neighboring cell
+			for (int nbRoadCells = 0; nbRoadCells < NEIGHBOR.length; nbRoadCells++){	//for every neighbor of the starting cell...
+				nbRoadX = X+NEIGHBOR[nbRoadCells][0];	
 				nbRoadY = Y+NEIGHBOR[nbRoadCells][1];
 				if ( nbRoadX < areaMinX || nbRoadY < areaMinY || nbRoadX > areaMaxX || nbRoadY > areaMaxY ||
-			               Float.isNaN(outputGrid.getRasterSampleAsFloat(nbRoadX,nbRoadY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-			             continue;
-				//if (areaRestr.getRasterSampleAsFloat(nbRoadX,nbRoadY) != 0)
-		        //	continue;
-				float roadSample = roadGrid.getRasterSampleAsFloat(nbRoadX,nbRoadY);
-				if (roadSample > 0f)
-					roadNb++;
+			               Float.isNaN(outputGrid.getRasterSampleAsFloat(nbRoadX,nbRoadY)) ) 
+			             continue;	//if a cell is outside the raster (NaN), break and continue loop from the beginning
+				float roadSample = roadGrid.getRasterSampleAsFloat(nbRoadX,nbRoadY);	//take the value
+				if (roadSample > 0f)	//if a road is present (>1),
+					roadNb++;			//count it
 			}
-	//		statusOut.println("Nachbarn von temporaerer Strassenzelle: "+roadNb);
 			
-			if (roadNb > 0){
-				RN = 1 + Math.round((float)Math.random()*(roadNb-1));
+			if (roadNb > 0){	//if neighbors are available
+				RN = 1 + Math.round((float)Math.random()*(roadNb-1));	//select a random one
 			
-				for (int nbRoadCells = 0; nbRoadCells < NEIGHBOR.length; nbRoadCells++){
+				for (int nbRoadCells = 0; nbRoadCells < NEIGHBOR.length; nbRoadCells++){	//for every neighbor of the starting cell...
 					nbRoadX = X+NEIGHBOR[nbRoadCells][0];
 					nbRoadY = Y+NEIGHBOR[nbRoadCells][1];
 					if ( nbRoadX < areaMinX || nbRoadY < areaMinY || nbRoadX > areaMaxX || nbRoadY > areaMaxY ||
-							Float.isNaN(outputGrid.getRasterSampleAsFloat(nbRoadX,nbRoadY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-			             	continue;
-					float roadSample = roadGrid.getRasterSampleAsFloat(nbRoadX,nbRoadY);
-					if (roadSample > 0f){
-						roadNbTemp++;
-						nbCell = new int[] {nbRoadX,nbRoadY,roadNbTemp};
-						if (nbCell[2] == RN){
-							statusOut.println("Nachbarzelle gefunden: "+nbCell[0]+","+nbCell[1]+","+nbCell[2]);
-							end_of_road = false;
-							run++;
+							Float.isNaN(outputGrid.getRasterSampleAsFloat(nbRoadX,nbRoadY)) ) 
+			             	continue;	//if a cell is outside the raster (NaN), break and continue loop from the beginning
+					float roadSample = roadGrid.getRasterSampleAsFloat(nbRoadX,nbRoadY);	//take the value
+					if (roadSample > 0f){	//if a road is present (>1),
+						roadNbTemp++;		//count it
+						nbCell = new int[] {nbRoadX,nbRoadY,roadNbTemp};	//write it in an array
+						if (nbCell[2] == RN){	//if the number in the array is the same as the randomly selected number
+							end_of_road = false;	//the end of the road is not reached
+							run++;	//increase the run value
 							X = nbRoadX;
 							Y = nbRoadY;
-							float roadSample2 = roadGrid.getRasterSampleAsFloat(X,Y);
-							run_value = (int) (roadSample2 / 100 * disp);
-					//		statusOut.println("Run: "+run);
-					//		statusOut.println("Run_Value: "+run_value);
-					//		statusOut.println(X+","+Y+","+roadSample2);
-							if (run > run_value){
-								end_of_road = true;
-					//			statusOut.println("Endzelle erreicht!! Run:"+run+"RunValue: "+run_value);
-								float NbValue = 0f; 
-								int Nb = calculateNeighbors(X,Y,NbValue);
-					//			statusOut.println("moegliche Nachbarzellen nach RoadWalk: "+Nb);
-								RN = 1 + Math.round((float)Math.random()*(Nb-1));
-				//				statusOut.println("Random: "+RN);
-								if (Nb > 0){
+							float roadSample2 = roadGrid.getRasterSampleAsFloat(X,Y);	//take the value of the road
+							run_value = (int) (roadSample2 / 100 * disp);	//calculate how far the cell can be moved along the road
+							if (run > run_value){	//if the run-value exceeds the maximum value...
+								end_of_road = true;	//end the road walk
+								int Nb = calculateNeighbors(X,Y,0f);	//find the neighbors of the cell found
+								RN = 1 + Math.round((float)Math.random()*(Nb-1));	//select a random number between 1 and the number of neighbors
+								if (Nb > 0){	//if a neighbor is found...
 									int nbUrbanizeX = 0;
 									int nbUrbanizeY = 0;
 									int NbTemp = 0;
 									float RNRoadSlope = 0f;
-						//			statusOut.println(X+","+Y);
-									for (int urbanizeCells = 0; urbanizeCells < NEIGHBOR.length; urbanizeCells++){
+									for (int urbanizeCells = 0; urbanizeCells < NEIGHBOR.length; urbanizeCells++){	//look at every neighbor cell
 										nbUrbanizeX = X+NEIGHBOR[urbanizeCells][0];
 										nbUrbanizeY = Y+NEIGHBOR[urbanizeCells][1];
 										if ( nbUrbanizeX < areaMinX || nbUrbanizeY < areaMinY || nbUrbanizeX > areaMaxX || nbUrbanizeY > areaMaxY ||
-												Float.isNaN(outputGrid.getRasterSampleAsFloat(nbUrbanizeX,nbUrbanizeY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-											continue;
+												Float.isNaN(outputGrid.getRasterSampleAsFloat(nbUrbanizeX,nbUrbanizeY)) ) 
+											continue;	//if a cell is outside the raster (NaN), break and continue loop from the beginning
 										if (areaRestr.getRasterSampleAsFloat(nbUrbanizeX,nbUrbanizeY) != 0)
-											continue;
-										float rasterSample = outputGrid.getRasterSampleAsFloat(nbUrbanizeX,nbUrbanizeY);
-										RNRoadSlope = (float)Math.random();
-					        			int getSlopeNb = (int) slopeGrid.getRasterSampleAsFloat(nbUrbanizeX,nbUrbanizeY);
-					        			Double doubleObjNb = (Double)slopeLUT.get(getSlopeNb);
-					        			double slopeDoubleNb = doubleObjNb.doubleValue();
-										if (rasterSample == 0f){
-											NbTemp++;
-											nbCellTemp = new int[] {nbUrbanizeX,nbUrbanizeY,NbTemp};
-											if (nbCellTemp[2] == RN && slopeDoubleNb < RNRoadSlope){
-												nbCellNew = new int[] {nbCellTemp[0],nbCellTemp[1],nbCellTemp[2]};
+											continue;	//if a cell is inside an excluded area, break and continue loop from the beginning
+										float rasterSample = outputGrid.getRasterSampleAsFloat(nbUrbanizeX,nbUrbanizeY);	//take the raster value
+										RNRoadSlope = (float)Math.random();	//generate a random number in order to compare it with the slope
+										double slopeDoubleNb = getSlopeValue(nbUrbanizeX,nbUrbanizeY);	//returns the slope value for the neighboring cells which are available for breed
+										if (rasterSample == 0f){	//if the raster sample is available for urbanization...
+											NbTemp++;	//count it
+											nbCellTemp = new int[] {nbUrbanizeX,nbUrbanizeY,NbTemp};	//create an array holding the coordinates and the number of that neighbor cell
+											if (nbCellTemp[2] == RN && slopeDoubleNb < RNRoadSlope){	//if its number is the same as the random number and it passes the slope-test..
+												nbCellNew = new int[] {nbCellTemp[0],nbCellTemp[1],nbCellTemp[2]};	//write its coordinates in the array to be returned
 											}
 										}	
 									}
 								
 							} else{
-								nbCellNew = null;
+								nbCellNew = null;	
 							}	break;
 						}
 						
@@ -806,13 +835,22 @@
 			
 			}
 		}
-		return nbCellNew;
+		return nbCellNew;	//return the result array
 		}
 	
-	private int calculateNeighbors(int X, int Y, float NbValue){
+	/**
+	 * This method returns the number of neighbors of a cell X/Y. The input for this method are the coordinates of the center cell
+	 * and the value that the neighboring cells must have in order to be counted. In general this is 0 for non-urban cells and 1 
+	 * for urban cells.
+	 * @param X
+	 * @param Y
+	 * @param NbValue
+	 * @return Nb
+	 */
+	public int calculateNeighbors(int X, int Y, float NbValue){
 		int nbX = 0;
 		int nbY = 0;
-		int areaMinX = inputGrid.getMinX();								//Dimensionen des Rasters
+		int areaMinX = inputGrid.getMinX();								//raster dimensions
 		int areaMinY = inputGrid.getMinY();
 		int areaMaxX = inputGrid.getMinX() + inputGrid.getWidth() - 1;
 		int areaMaxY = inputGrid.getMinY() + inputGrid.getHeight() - 1;
@@ -821,19 +859,52 @@
 			nbX = X+NEIGHBOR[nbCells][0];
 			nbY = Y+NEIGHBOR[nbCells][1];
 			if ( nbX < areaMinX || nbY < areaMinY || nbX > areaMaxX || nbY > areaMaxY ||
-		               Float.isNaN(outputGrid.getRasterSampleAsFloat(nbX,nbY)) ) //wenn Nachbarzelle außerhalb des Rasters (NaN) --> ignorieren
-		             continue;
+		               Float.isNaN(outputGrid.getRasterSampleAsFloat(nbX,nbY)))
+		             continue;	//if a cell is outside the raster (NaN), break and continue loop from the beginning
 			if (areaRestr.getRasterSampleAsFloat(nbX,nbY) != 0)
-	        	continue;
-			float rasterSample = outputGrid.getRasterSampleAsFloat(nbX,nbY);
-			if (rasterSample == NbValue)
-				Nb++;
+	        	continue;	//if a cell is inside an excluded area, break and continue loop from the beginning
+			float rasterSample = outputGrid.getRasterSampleAsFloat(nbX,nbY);	//take the raster value
+			if (rasterSample == NbValue)	//if it is the same as the value we look for...
+				Nb++;	//count it
 		}
-	//	statusOut.println("..."+Nb+"...");
 		return Nb;
 	}
 	
-	protected static boolean checkNoData(int x, int y, WritableGrid grid) {
-	    return Float.isNaN(grid.getRasterSampleAsFloat(x,y));
-	  }
+	/**
+	 * Returns the number of urban cells in the temporary cell array.
+	 * @return anzGesamt
+	 */
+	public int countTempUrbanCells(boolean[][] tmpGrid){
+		int anzGesamt = 0;
+		for (int x = 0; x < outputGrid.getWidth();x++)
+			for(int y = 0; y < outputGrid.getHeight();y++){
+				if (tmpGrid[x][y]==true){
+					anzGesamt++;
+				}		
+			}
+		return anzGesamt;
+	}
+	
+	/**
+	 * Writes a temporary grid array with boolean values to the outputGrid.
+	 * @param tmpGrid
+	 */
+	public void writeToGrid(boolean tmpGrid[][]){
+		int t = 0;
+		for (int y = 1; y < inputGrid.getHeight()-1;y++ ) {
+			for (int x = 1; x < inputGrid.getWidth()-1; x++ ) {
+			
+				int X = inputGrid.getMinX() + x;
+				int Y = inputGrid.getMinY() + y;
+			
+				boolean lebt = outputGrid.getRasterSampleAsFloat(X , Y ) > 0f;	//a cell is alive when it is 1
+				if (tmpGrid[x][y] == false)	//if there is nothing in the temporary raster
+					tmpGrid[x][y] = lebt;	//take the information from the current output grid
+				if(tmpGrid[x][y] == true)
+					t++;
+				outputGrid.setRasterSample( tmpGrid[x][y] ? 1f : 0f ,X ,Y);	//write the result to the output grid
+			}
+		}
+		statusOut.println("Temporary Urban Cells: "+t);
+	}
 }

Modified: trunk/src/edu/bonn/xulu/plugin/model/sleuth/UrbanGrowthModelContentManager.java
===================================================================
--- trunk/src/edu/bonn/xulu/plugin/model/sleuth/UrbanGrowthModelContentManager.java	2009-10-14 08:31:55 UTC (rev 61)
+++ trunk/src/edu/bonn/xulu/plugin/model/sleuth/UrbanGrowthModelContentManager.java	2009-10-21 08:43:39 UTC (rev 62)
@@ -11,9 +11,12 @@
 
 
 public class UrbanGrowthModelContentManager extends AbstractModelContentManager {
+	public UrbanGrowthModelContentManager() {
+		this(13);
+	}
 	
-	public UrbanGrowthModelContentManager() {
-		super(13);
+	protected UrbanGrowthModelContentManager(int resourceCount) {
+		super(resourceCount);
 
 		resource[0] = new ValuePropertyResource(ModelResource.CATEGORY_INPUT,"Input Grid",ScalarProperty.class,WritableGrid.class,false);
 		resource[1] = new ValuePropertyResource(ModelResource.CATEGORY_OUTPUT,"Output Grid",ScalarProperty.class,WritableGrid.class,false);



More information about the Xulu-commits mailing list