home products news downloads documentation support gallery online maps resellers search
TNTmips Downloads Menu

HOME

CONTACT US

CURRENT RELEASE
  TNT 2013

DEVELOPMENT VERSION
  TNT 2014

TNTmips Pro
PRIOR RELEASES
  TNT 2012

FREE SOFTWARE
  TNTmips Free
  TNTatlas
  TNTsdk

MORE DOWNLOADS
  HASP Key Driver
  Screen Recorder
  TNT Language Kits
  Sample Geodata
  TNT Scripts

DOCUMENTATION
  TNTmips Tutorials
  Tutorial Datasets
  Technical Guides
  Scripts
  Quick Guides

MORE INFO
  Download FAQs
  FTP
  Download Managers
  Find Reseller

SITE MAP


SRTMfill.sml


######################################################################################################
#
# SRTMfill.sml ("Stand Alone" Script)
#
######################################################################################################
#
# Authors:
#   Dave Breitwisch, MicroImages, Inc
#
# Started: 07 April 2005
# Updated: 28 March 2006
#
# Requires: TNTmips2005:71 or later
#
numeric version = round(_context.Version * 10);
if (version < 71) {
	PopupMessage("This version requires that you are using TNTmips2005:71 or later");
	Exit();
}
#
######################################################################################################
#
# Description of Script:
#
#   This is a "Stand Alone" script whose purpose is to fill in null cell values in the released data  
#   from the Shuttle Radar Topography Mission flown in February of 2000.  
#   This current version of the script: 
#        fills single cells by interpolation,
#        fills null voids that are bounded by a constant value, and 
#        fills voids using elevation data from reference DEM rasters provided by the user.
#   
#
#   Void Filling Procedures:
#
#     Single Cell Interpolation - The user can specify the number of surrounding cells that are
#        required (minimum = 6) to be present for the single cell to be filled.  If the single null 
#        cell passes this test, the average of all the surrounding non-null cells is used.  This procedure 
#        is called multiple times until there are no remaining single null cells that pass the test.
#
#     Constant Boundary Filling - The algorithm used for this procedure searches for null voids that
#        have a constant value around their edges.  When a null void is found, the algorithm 
#        traverses around the boundary of the void.  If all the surrounding values are the same, 
#        the algorithm fills in it's traversed path with that constant value.  The remaining cells
#        inside of this path are filled in when the algorithm detects this new null void.  This
#        is especially useful for filling in voids within a water surface.
#        NOTE:  If a null void covers a real area of different elevation, but the surrouding cells
#               are the same value, the void is filled in with the constant value.  This is the
#               case when an SRTM void includes an island within a horizontal water body.
#
#     Reference DEM Filling - This allows the user to use multiple reference DEMs, assumed to be 
#        accurate and properly georeferenced, to fill the null voids.  The DEM data is assumed to be
#        in meters unless the proper cell value scale is set for the raster.  Additional options such
#        as a maximum elevation difference and blending are available.
#
#        Maximum Elevation Difference - For each reference DEM, the values of the SRTM cells are 
#           compared to the matching georeferenced values of the DEM.  If the differnece between the
#           values is greater then specified by the user, the SRTM cell is replaced by null and will
#           eventually be filled in with the reference DEM value. This is done under the assumption
#           that the reference DEMs are more accurate.
#
#        Blending - This procedure uses the value specified by the user to blend the areas around
#           the null voids filled in by the reference DEMs.  The value represents the distance away
#           from the boundary of the null void (in number of cells) over which to blend.  Blending
#           is performed using nested 1-cell-wide buffer zones.  The final SRTM cell values in each 
#           buffer zone are linear weighted averages of the original SRTM cell value and the reference 
#           DEM cell value with the weighting factors determined by the number of buffer zones and
#           the position of the current buffer zone in the nesting sequence.  
#           
#           Example:  blending over 4 nested buffer zones around each void
#              Zone 1 : cell = SRTM value + 4/5 * diffence between the values (Boundary of void)
#              Zone 2 : cell = SRTM value + 3/5 * diffence between the values
#              Zone 3 : cell = SRTM value + 2/5 * diffence between the values
#              Zone 4 : cell = SRTM value + 1/5 * diffence between the values (Furthest from void)
#
#           An additional option is given to the user to save the raster and vector objects created 
#           by this filling process.  These can be used for data verification.  These objects are made
#           after the Single Cell Interpolation and Constant Boundry Filling operations are done, if
#           chosen by the user.  The following objects are created:
#              BinNullVoids (Binary Raster): 1 = Matching cell to be filled in by reference DEM value
#              BufferR# (Binary Raster): 1 = Matching cell is in Zone number #
#              NullVoids (Vector): Shows boundaries of BinNullVoids Raster
#              BufferV# (Vector): Shows outer boundaries of the matching BufferR# Raster
#
######################################################################################################


######################################################################################################
# Global Variable Declarations
######################################################################################################
class XMLDOC mainDOC, progressDOC;
class XMLNODE mainNODE, progressNODE;
class GUI_DLG mainDLG, progressDLG;

numeric errXML, errDLG;

string mainxmlCODE$, progressxmlCODE$;

string InputRasterFilename$, InputRasterObjectName$;
string OutputRasterFilename$, OutputRasterObjectName$;
string LogFilename$;
class STRINGLIST RefDEMFilenames$, RefDEMObjectNames$;

class RASTER inR;
class RASTER outR;
numeric rows, cols;
string initType;
numeric numValidNulls;

class RASTER RefR;
numeric RefDataScale;
class RASTER binVoidR;
class VECTOR nullVoidsV;

array numeric element[1,1];
array numeric buffinodes[1];

###########################
# User Selected Values
###########################
numeric cellBufferDist;
numeric threshold;
numeric numRequiredAround;
numeric numReferenceDEMs;
string TempSRTMfile;
######################################################################################################


######################################################################################################
# Dialog specification in XML
######################################################################################################
mainxmlCODE$ = '

	
		
		
			
			
		
		
			
			
		
		
			
				
					
					
				
				
					
						
						
					
				
			
		
		
			
				
					
				
				
					
						
						
						
					
				
			
			
				
			
			
				
					
					
				
				
					
						
						
					
					
						
						
					
				
			
		
		
			
				
			
			
				
					
					
				
			
		
		
			
			
			
		
	
';
######################################################################################################

######################################################################################################
# Dialog specification in XML
######################################################################################################
progressxmlCODE$ = '

	
		
	
	
		
	
';
######################################################################################################



######################################################################################################
# Start of the Script
######################################################################################################
clear();
proc OnCreateDialog(); #Function Prototype
OnCreateDialog();
######################################################################################################


######################################################################################################
#	Script Functions and Procedures
######################################################################################################


######################################################################################################
# Returns the number of NULL cells that are in the raster
func NumNullCellsInRaster(class RASTER rast) {
	local numeric i, j, nullCount = 0;

	for i = 1 to NumLins(rast) {
		for j = 1 to NumCols(rast) {
			if (IsNull(rast[i,j])) {
				nullCount++;
			}
		}
	}
	return nullCount;
}

######################################################################################################
# Return the number of cells surrounding the location of the cell passed that are null.
func NumNullsAround(numeric i, numeric j) {

	local numeric count = 0;
	# Add 1 to count if specified neighboring cell is a valid Raster cell and is Null
	if ((i != 1)    && (j != cols) && IsNull(outR[i-1,j+1]))  count++;
	if ((i != 1)                   && IsNull(outR[i-1,j  ]))  count++;
	if ((i != 1)    && (j != 1)    && IsNull(outR[i-1,j-1]))  count++;
	if (               (j != cols) && IsNull(outR[i  ,j+1]))  count++;
	if (               (j != 1)    && IsNull(outR[i  ,j-1]))  count++;
	if ((i != rows) && (j != cols) && IsNull(outR[i+1,j+1]))  count++;
	if ((i != rows)                && IsNull(outR[i+1,j  ]))  count++;
	if ((i != rows) && (j != 1)    && IsNull(outR[i+1,j-1]))  count++;

	return count;
}

######################################################################################################
# Returns the average value of all surrounding cells that are not null
func InterpCellValue(numeric i, numeric j) {

	local numeric sumvalue = 0;
	local numeric numCells = 0;
    
	# Check if the neighboring cell is valid and not null.  If ok, add to sum and increment the count 
	if ((i != 1) && (j != cols) && (!IsNull(outR[i-1,j+1]))) {
		sumvalue += outR[i-1,j+1];
		numCells++;  
	} 
	if ((i != 1) && (!IsNull(outR[i-1,j]))) {
		sumvalue += outR[i-1,j];
		numCells++;  
	}
	if ((i != 1) && (j != 1) && (!IsNull(outR[i-1,j-1]))) {
		sumvalue += outR[i-1,j-1];
		numCells++;  
	}
	if ((j != cols) && (!IsNull(outR[i,j+1]))) {
		sumvalue += outR[i,j+1];
		numCells++;  
	}
	if ((j != 1) && (!IsNull(outR[i,j-1]))) {
		sumvalue += outR[i,j-1];
		numCells++;  
	}
	if ((i != rows) && (j != cols) && (!IsNull(outR[i+1,j+1]))) {
		sumvalue += outR[i+1,j+1];
		numCells++;  
	}
	if ((i != rows) && (!IsNull(outR[i+1,j]))) {
		sumvalue += outR[i+1,j];
		numCells++;  
	}
	if ((i != rows) && (j != 1) && (!IsNull(outR[i+1,j-1]))) {
		sumvalue += outR[i+1,j-1];
		numCells++;
	}
  
	# Return the average of the sum
	return sumvalue/numCells;
}

######################################################################################################
# This process traverses through the SRTM raster and looks for single null cells that have less then
# the allowed number of nulls surrounding them.  For these cells the function interpolates a value 
# based on the average of the surrounding real cell values.
func CheckNegligibleNulls( numeric allowedNulls ) {

	local numeric cellsChanged = 0;

	SetStatusMessage("Interpolating Negligible Null Cells");

	local numeric i, j;
	# Traverse through the raster
	for i = 1 to rows {
		SetStatusBar(i, rows);
		for j = 1 to cols {

			# Check if the cell is null
			if (IsNull(outR[i, j])) {

				# Check if it has less then the number of surrounding null cells allowed
				if ( NumNullsAround(i, j) <= allowedNulls ) {

					# Interpolate the cell value and update the report counter
					outR[i, j] = InterpCellValue(i, j);
					cellsChanged++;
				}          
			}
		} 
	} 

	print("   Number of single null cells changed in this pass: " + NumToStr(cellsChanged) + "\n");
	return cellsChanged;
}

######################################################################################################
# This procedure creates a binary raster that symbolizes the overlap of the input SRTM raster and the
# reference DEM.  The value of 1 indicates that the SRTM has a null cell.  A vector is also created
# that contains the boundaries of the null cells (value of 1) in the binary raster.
proc CreateNullRasterVector( ) {

	print("Creating Void Mask and Void Boundries\n");

	CreateRaster(binVoidR, TempSRTMfile, "BinNullVoids", "Binary Raster showing Null Voids", rows, cols, "binary");
	CopySubobjects(outR, binVoidR, "GEOREF");
	SetNull(binVoidR, 0);

	# Set the cell to 1 if the matching SRTM raster cell is null, else set it to 0.
	local numeric i, j, I = 1, J = 1;
	for i = 1 to rows {
		for j = 1 to cols {
			# Offset the line and column counters to match the two rasters
			if ( IsNull(outR[i, j]) ) {
				binVoidR[I,J] = 1;
			} else {
				binVoidR[I,J] = 0;
			}
			J++;
		}
		I++;
		J = 1;
	}

	# Create the vector with boundaries around the 1's in the binary raster
	CreateVector(nullVoidsV, TempSRTMfile, "NullVoids", "Boundary of Null Voids (after single cell pass)");
	nullVoidsV = RasterToVectorBound(binVoidR, "DoImpliedGeoref");

	# Save the object numbers so they can be reopened later
	ResizeArrayClear(buffinodes, (cellBufferDist+1)*2);
	buffinodes[1] = GetObjectNumber(binVoidR);
	buffinodes[2] = GetObjectNumber(nullVoidsV);

	CloseRaster(binVoidR);
	CloseVector(nullVoidsV);
}


######################################################################################################
# This procedure traverses through the SRTM raster and replaces any null values with the corresponding
# cell value from the reference DEM.  The SRTM cell will remain null if the current reference DEM does  
# not overlap or if the corresponding reference DEM cell is null.
proc FillWithRefRaster() {

	print("Filling Voids with Reference Data\n");

	local class GEOREF outG, refG;
	local class POINT2D point;

	outG = GetLastUsedGeorefObject(outR);
	refG = GetLastUsedGeorefObject(RefR);

	# create a transparm if the CRS's are different
	local numeric same = 1;
	if (outG.CoordRefSys.Name != refG.CoordRefSys.Name) {
		same = 0;

		local class TRANSPARM trans;
		trans.InputCoordRefSys = outG.CoordRefSys;
		trans.OutputCoordRefSys = refG.CoordRefSys;
	}

	SetStatusMessage("Filling holes with Reference Data");

	# traverse through the overlapping area
	local numeric i, j;
	for i = 1 to rows {
		SetStatusBar(i, rows);
		for j = 1 to cols {

			# If the cell is null, find the matching cell in the reference DEM
			if ( IsNull(outR[i,j]) ) {
				point = ObjectToMap(outR, j, i, outG);

				# Convert to the correct CRS if they are not the same
				if (!same) {
					point = trans.ConvertPoint2DFwd(point);
				}

				# convert map coordinates to SRTM raster line/column
				point = MapToObject(refG, point.x, point.y, RefR);
				point.x = round(point.x);
				point.y = round(point.y);

				# Check to make sure the point is valid, then replace it
				if ( point.x >= 1 and point.x <= RefR.$Info.NumCols) {
					if ( (point.y >= 1) && (point.y <= RefR.$Info.NumLins) ) {
						outR[i,j] = RefR[point.y, point.x] * RefDataScale;
					}
				}
 			}
		}
	}
}

######################################################################################################
# This procedure blends the SRTM data with the Reference data that was used to fill the null cells
# based on the distance from the null voids that the user specifies.
proc BlendBufferZone( class RASTER zoneBufferR, numeric zoneNum ) {

	print("   Buffering in Zone " + NumToStr(zoneNum) + " of " + NumToStr(cellBufferDist) + "\n");
	local class POINT2D point;
	local class GEOREF outG, refG;
	local numeric I = 1, J = 1;

	outG = GetLastUsedGeorefObject(outR);
	refG = GetLastUsedGeorefObject(RefR);

	# create a transparm if the CRS's are different
	local numeric same = 1;
	if (outG.CoordRefSys.Name != refG.CoordRefSys.Name) {
		same = 0;

		local class TRANSPARM trans;
		trans.InputCoordRefSys = outG.CoordRefSys;
		trans.OutputCoordRefSys = refG.CoordRefSys;
	}

	SetStatusMessage("Computing new values in Buffer Zone");

	# traverse through the overlapping area
	local numeric m, n, buffFactor;
	for m = 1 to rows {
		SetStatusBar(m, rows);
		for n = 1 to cols {

			# Start the blending process if the cell is in the buffer zone
			if ( zoneBufferR[I, J] == 1 ) {
				point = ObjectToMap(outR, n, m, outG);

				# Convert point to the correct CRS if not the same
				if (!same) {
					point = trans.ConvertPoint2DFwd(point);
				}
				point = MapToObject(refG, point.x, point.y, RefR);
				point.x = round(point.x);
				point.y = round(point.y);

				# Make sure the matching cell in the DEM is valid
				if ( point.x >= 1 and point.x <= RefR.$Info.NumCols) {
					if ( (point.y >= 1) && (point.y <= RefR.$Info.NumLins) ) {

						# Assign the output cell the value of the SRTM plus the linear differnce based
						# on what zone the cells are in.
						buffFactor = (cellBufferDist - zoneNum + 1) * 1.0 / (cellBufferDist * 1.0 + 1);
						outR[m,n] = outR[m,n] + (buffFactor) * ((RefR[point.y, point.x] * RefDataScale) - outR[m,n]);
					}
				}
			}
			J++;
		}
		I++;
		J = 1;
	}
}

######################################################################################################
# This procedure uses the binVoidR raster created early along with the morphological functions to grow
# the voids larger based on the zone number.  A boundary vector is created with each new raster.
proc CreateVectRastBufferZoneInit(numeric zone) {

	SetStatusMessage("Computing initial void Vector and Raster");

	local string zone$ = NumToStr(zone);
	print("   Growing Buffer Raster " + zone$ + " of " + NumToStr(cellBufferDist) + "\n");

	# Create a raster the size of binVoidR and dilate the null void based on the zone value
	local class RASTER buffR;
	local numeric tempNumLins = NumLins(binVoidR);
	local numeric tempNumCols = NumCols(binVoidR);
	CreateRaster(buffR, TempSRTMfile, "BufferR"+zone$, "Buffer Zone "+zone$, tempNumLins, tempNumCols, "binary");
	CopySubobjects(binVoidR, buffR, "GEOREF");
	SetNull(buffR, 0);
	MorphDilation(binVoidR, buffR, element, (zone*2)+1, (zone*2)+1);

	# Create a vector that bounds each of the null voids
	local class VECTOR buffV;
	CreateVector(buffV, TempSRTMfile, "BufferV"+zone$, "Boundary of Buffer Zone "+zone$);
	buffV = RasterToVectorBound(buffR, "DoImpliedGeoref");

	# Save the inodes for future use
	buffinodes[(zone*2)+1] = GetObjectNumber(buffR);
	buffinodes[(zone*2)+2] = GetObjectNumber(buffV);

	CloseVector(buffV);
	CloseRaster(buffR);
} 

######################################################################################################
# This procedure compares each of the binary rasters with the raster that is "grown 1 size smaller" so
# the resulting raster will only contain the zone boundaries.  All else will be 0's.
proc ComputeBufferZoneRasters( numeric zone ) {

	print("   Creating Buffer Zone Raster " + NumToStr(zone) + " of " + NumToStr(cellBufferDist) + "\n");

	# Open the working raster and the "1 less grown" raster
	local string name;
	local class RASTER grownR;
	local class RASTER prevR;
	name = GetObjectName(TempSRTMfile, buffinodes[(zone*2)+1]);
	OpenRaster(grownR, TempSRTMfile, name);
	name = GetObjectName(TempSRTMfile, buffinodes[((zone-1)*2)+1]);
	OpenRaster(prevR, TempSRTMfile, name);

	local numeric tempNumLins = NumLins(grownR);
	local numeric tempNumCols = NumCols(grownR);

	SetStatusMessage("Computing Buffer Zone Raster");

	# Traverse through the working raster
	local numeric r, c;
	for r = 1 to tempNumLins {#rows {
		SetStatusBar(r, tempNumLins);
		for c = 1 to tempNumCols {#cols {

			# Do and XOR with the two rasters
			if ( (IsNull(prevR[r,c])) && (grownR[r,c] == 1) ) { 
				grownR[r,c] = 1;
			} else {
				grownR[r,c] = 0;
			}
		}
	}

	CloseRaster(grownR);
	if ( zone != 1 ) {    # Do not close binVoidR
		CloseRaster(prevR);
	}
}

######################################################################################################
# This procedure controls the process of blending the reference raster data that was used to fill the 
# null voids in the SRTM data.
proc BlendWithRefRaster() {

	# Create an element large enough to satisfy the users number of blending zones.  This is used in 
	# the morphological dilation procedures
	ResizeArrayClear(element, (cellBufferDist*2)+1, (cellBufferDist*2)+1);
	numeric k, i;
	for k = 1 to (cellBufferDist*2)+1 {
		for i = 1 to (cellBufferDist*2)+1 {
			element[k,i] = 1;
		}
	}

	# Create the initial binary rastes and grow them according the the zone value
	print("Using Raster Dilation to produce buffer Rasters \n");
	for k = 1 to cellBufferDist {
		CreateVectRastBufferZoneInit(k);
	}

	# Do an XOR with each of the raster with the "1 lesser grown" raster.  Produces binary zones.
	print("Using buffer Rasters to create Buffer Zones \n");
	for k = cellBufferDist to 1 step -1 {
		ComputeBufferZoneRasters(k);
	}

	print("Buffering around Voids to match data\n");

	# Call the procedure that will blend the reference DEM and SRTM data using the zone rasters
	local class RASTER blendR;
	local string name;
	for k = 1 to cellBufferDist {
		name = GetObjectName(TempSRTMfile, buffinodes[(k*2)+1]);
		OpenRaster(blendR, TempSRTMfile, name);
		BlendBufferZone(blendR, k);
		CloseRaster(blendR);
	}
}

######################################################################################################
# This procedure scans through the overlapping SRTM and reference DEM rasters and removes the SRTM 
# value if the elevation difference is greater then the threshold specified by the user.  It is then
# replaced with the reference DEM data in a later procedure.
proc RemoveThresholdViolations( ) {

	local class POINT2D point;
	local class GEOREF outG, refG;

	print("Removing Threshold Violations to Referance Raster \n");

	outG = GetLastUsedGeorefObject(outR);
	refG = GetLastUsedGeorefObject(RefR);

	# Create a transparm if the CRSs are not the same
	local numeric same = 1;
	if (outG.CoordRefSys.Name != refG.CoordRefSys.Name) {
		same = 0;

		local class TRANSPARM trans;
		trans.InputCoordRefSys = outG.CoordRefSys;
		trans.OutputCoordRefSys = refG.CoordRefSys;
	}

	SetStatusMessage("Removing values that violate the specified Threshold to the reference data\n");

	# Traverese the SRTM raster
	local numeric numViolations = 0;
	local numeric m, n;
	for m = 1 to rows {
		SetStatusBar(m, rows);
		for n = 1 to cols {
			point = ObjectToMap(outR, n, m, outG);

			# Convert the point to the SRTM CRS if not the same
			if (!same) {
				point = trans.ConvertPoint2DFwd(point);
			}
			point = MapToObject(refG, point.x, point.y, RefR);
			point.x = round(point.x);
			point.y = round(point.y);

			# Check if the point is valid
			if ( point.x >= 1 and point.x <= RefR.$Info.NumCols) {
				if ( (point.y >= 1) && (point.y <= RefR.$Info.NumLins) ) {

					# Check if the difference in elevation values is greater then the threshold
					if ( abs(outR[m,n] - (RefR[point.y, point.x] * RefDataScale)) > threshold) {

						# Set the cell value to null and update the count
						if (HasNullValue(outR)) {
							outR[m,n] = NullValue(outR);
						}
						if (HasNullMask(outR)) {
							outR[m,n] = null;
						}
						numViolations++;
					}
				}
			}
		}
	}
	print("   Total violations replaced with null: " + NumToStr(numViolations) + "\n");
}

######################################################################################################
# Is true if all the surrouding cells from the specified cell are null or equal to the passed value.
func AreAllSurroundingSameAsValueOrNull(numeric i, numeric j, numeric value) {
 
	local numeric valid = true;
	# Checks if cell exists.  Returns false if the existing cell is Null
	if ((outR[i-1,j+1] != value) & !IsNull(inR[i-1,j+1]))  valid = false;
	if ((outR[i-1,j  ] != value) & !IsNull(inR[i-1,j  ]))  valid = false;
	if ((outR[i-1,j-1] != value) & !IsNull(inR[i-1,j-1]))  valid = false;
	if ((outR[i  ,j+1] != value) & !IsNull(inR[i  ,j+1]))  valid = false;
	if ((outR[i  ,j-1] != value) & !IsNull(inR[i  ,j-1]))  valid = false;
	if ((outR[i+1,j+1] != value) & !IsNull(inR[i+1,j+1]))  valid = false;
	if ((outR[i+1,j  ] != value) & !IsNull(inR[i+1,j  ]))  valid = false;
	if ((outR[i+1,j-1] != value) & !IsNull(inR[i+1,j-1]))  valid = false;

	return valid;
}

######################################################################################################
# Is true if all the surrounding cells from the specified cell are equal to the passed value.
func AreAllSurroundingSameAsValue(numeric i, numeric j, numeric value) {

	# Check each surrouding cell 
	if ( IsNull(outR[i-1,j-1]) ) {
		return false;
	} else if ( outR[i-1,j-1] != value ) {
		return false;
	}
	if ( IsNull(outR[i-1,j  ]) ) {
		return false;
	} else if ( outR[i-1,j  ] != value ) {
		return false;
	}
	if ( IsNull(outR[i-1,j+1]) ) {
		return false;
	} else if ( outR[i-1,j+1] != value ) {
		return false;
	}
	if ( IsNull(outR[i  ,j-1]) ) {
		return false;
	} else if ( outR[i  ,j-1] != value ) {
		return false;
	}
	if ( IsNull(outR[i  ,j+1]) ) {
		return false;
	} else if ( outR[i  ,j+1] != value ) {
		return false;
	}
	if ( IsNull(outR[i+1,j-1]) ) {
		return false;
	} else if ( outR[i+1,j-1] != value ) {
		return false;
	}
	if ( IsNull(outR[i+1,j  ]) ) {
		return false;
	} else if ( outR[i+1,j  ] != value ) {
		return false;
	}
	if ( IsNull(outR[i+1,j+1]) ) {
		return false;
	} else if ( outR[i+1,j+1] != value ) {
		return false;
	}

	return true;
}

######################################################################################################
# This is a recursive function.  It is called when a null cell is found.  It uses the sequence of 
# travel specified below when traversing around the raster.  As it travels around the boundry of the
# null void, it checks to see if the surrounding cells are the same constant value as the cell value
# to the left of the initial null cell.  If the function ends up at the same point it started and did
# not fail any of it's surrounding cell checks, it goes back through the same path that it traveled
# and replaces each cell with the constant value.  If a void still exists within this traversed path,
# it will be filled in as the original function that calls this recursive function traverses the SRTM
# raster.
func RecursiveBorderCheck(numeric i, numeric j, numeric start_i, start_j, string traveled, numeric value, numeric firstCall) {

	# If the current position one cell to the right of starting cell and it is not the first call of
	# the function, it means that it has gone all the way around the border and each border cell has
	# the same constant value.  Returns true so it recusively fills in each of the cells that the
	# function was called on with the constant value.
	if (( i == start_i) & (j-1 == start_j) & (!firstCall)) {
		return true;
	}

	# Check if the surrounding cells pass the constant value or null test
	if (AreAllSurroundingSameAsValueOrNull(i, j, value)) {

		# Determine which direction to try and travel based on the sequence below:
		#
		# Sequence of travel:  
		# If the function was called by traveling to the:
		#  RIGHT - try in order of - UP,    RIGHT, DOWN,  LEFT
		#  DOWN  - try in order of - RIGHT, DOWN,  LEFT,  UP
		#  LEFT  - try in order of - DOWN,  LEFT,  UP,    RIGHT
		#  UP    - try in order of - LEFT,  UP,    RIGHT, DOWN

		# Check which direction the calling funtion traveled to the current cell
		if (traveled == "RIGHT") {

			# If the cell UP is null, go that way
			if (IsNull(outR[i-1, j])) {

				# Call this function and go that way
				if (RecursiveBorderCheck(i-1, j, start_i, start_j, "UP", value, 0)) {

					# If it returned true, it is traversing back after passing the constant border test
					outR[i,j] = value;
					return true;
				} else {

					# Failed the constant border test, just exit out of the function
					return false;
				}

			# If the cell RIGHT is null, go that way
			} else if (IsNull(outR[i,j+1])) {
				if (RecursiveBorderCheck(i, j+1, start_i, start_j, "RIGHT", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}

			# If the cell DOWN is null, go that way
			} else if (IsNull(outR[i+1,j])) {
				if (RecursiveBorderCheck(i+1, j, start_i, start_j, "DOWN", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}

			# If the cell LEFT is null, go that way
			} else if (IsNull(outR[i,j-1])) {
				if (RecursiveBorderCheck(i, j-1, start_i, start_j, "LEFT", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			} 
		}

		# Comments similar to the above
		if (traveled == "DOWN") {
			if (IsNull(outR[i, j+1])) {
				if (RecursiveBorderCheck(i, j+1, start_i, start_j, "RIGHT", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			} else if (IsNull(outR[i+1,j])) {
				if (RecursiveBorderCheck(i+1, j, start_i, start_j, "DOWN", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			} else if (IsNull(outR[i,j-1])) {
				if (RecursiveBorderCheck(i, j-1, start_i, start_j, "LEFT", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			} else if (IsNull(outR[i-1,j])) {
				if (RecursiveBorderCheck(i-1, j, start_i, start_j, "UP", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			}
		}

		# Comments similar to the above
		if (traveled == "LEFT") {
			if (IsNull(outR[i+1, j])) {
				if (RecursiveBorderCheck(i+1, j, start_i, start_j, "DOWN", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			} else if (IsNull(outR[i,j-1])) {
				if (RecursiveBorderCheck(i, j-1, start_i, start_j, "LEFT", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			} else if (IsNull(outR[i-1,j])) {
				if (RecursiveBorderCheck(i-1, j, start_i, start_j, "UP", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			} else if (IsNull(outR[i,j+1])) {
				if (RecursiveBorderCheck(i, j+1, start_i, start_j, "RIGHT", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			}
		}

		# Comments similar to the above
		if (traveled == "UP") {
			if (IsNull(outR[i, j-1])) {
				if (RecursiveBorderCheck(i, j-1, start_i, start_j, "LEFT", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			} else if (IsNull(outR[i-1,j])) {
				if (RecursiveBorderCheck(i-1, j, start_i, start_j, "UP", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			} else if (IsNull(outR[i,j+1])) {
				if (RecursiveBorderCheck(i, j+1, start_i, start_j, "RIGHT", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			} else if (IsNull(outR[i+1,j])) {
				if (RecursiveBorderCheck(i+1, j, start_i, start_j, "DOWN", value, 0)) {
					outR[i,j] = value;
					return true;
				} else {
					return false;
				}
			}
		}
	} else {

		# Failed the constant surrounding values check, exit out.
		return false;
	}
}

######################################################################################################
# This procedure traverses through the SRTM raster, and if it finds a null value, it calls a recursive
# function to travel around the border and fill in the void if all surrouding cells have the same
# cell value.
proc FillVoidsWithConstantBoundaryValues( ) {

	local numeric i, j;
	local numeric value, total = 0;

	print("Filling null voids that have a constant value on all borders\n");
	SetStatusMessage("Filling null voids with constant boundaries");

	# Fill any voids that have a constant boundary surrouding.  Will "errode" in one pixel.
	# Continuing passes through the raster will keep filling in one pixel at a time.  This
	# may leave a single cell remaining null based on original shape of the void.
	# WARNING:  This may partialy or completely cover an island with water if the bounding
	#           value around the island (void) is constant.

	# Traverse through the SRTM raster, except for the outside edge.  The algorighm can't determine if
	# the "real world elevation" value beyond the raster has the same value since the data does not 
	# exist in this raster.
	for i = 2 to rows-1 {
		SetStatusBar(i, rows-1);
		for j = 2 to cols-1 {
			if (IsNull(outR[i,j])) {

				# If the cell to the left and up are not null, get the value and start the processes
				if ((!IsNull(outR[i,j-1])) & (!IsNull(outR[i-1,j]))) {
					value = outR[i,j-1];

					# Do an initial check of the surrouding cells and call the function if it passes
					if (AreAllSurroundingSameAsValueOrNull(i, j, value)) {

						# Keep a report for each successful filling.  (multiple sucesses may be recorded
						# since the void is filled in one boudary ring at a time)
						total += RecursiveBorderCheck(i, j, i, j-1, "RIGHT", value, 1);
					}
				}
			}
		}
	}
	print("   Number of null voids filled: " + NumToStr(total) + "\n");

	total = 0;

	# Fill any single cells remaining that have constant values surrounding it.  This is done to fill
	# in any single cells that the previous recursive function missed since it cannot return true on
	# the first call to itself.
	for i = 1 to rows-1 {
		SetStatusBar(i, rows-1);
		for j = 1 to cols-1 {

			# Check if the cell is null and the cell to the left is not null
			if ( (IsNull(outR[i,j])) & (!IsNull(outR[i,j-1])) ) {
				value = outR[i,j-1];

				# Check if all surrounding cells have the same value
				if (AreAllSurroundingSameAsValue(i, j, value)) {

					# Fill in the cell and update the count
					outR[i,j] = value;
					total++;
				}
			}
		}
	}
	print("   Number of single null cells filled: " + NumToStr(total) + "\n");

}

######################################################################################################
# Assign the global variables the values set by the user in the dialog
proc SetUserSpecifiedGlobalValues( ) {

	numRequiredAround = mainDLG.GetCtrlByID("id_NUM_REQUIRED_SURROUNDING").GetValueNum();
	numReferenceDEMs = mainDLG.GetCtrlByID("id_NUM_REF_DEM").GetValueNum();
	cellBufferDist = mainDLG.GetCtrlByID("id_NUM_BUFFER_ZONE").GetValueNum();
	threshold = mainDLG.GetCtrlByID("id_THRESHOLD_VALUE").GetValueNum();
}

######################################################################################################
# This is the main procedure that is called when the user presses RUN with the appropriate settings
# set in the main dialog.  It calls functions based on the processes that the user has requested be
# run on the data provided.
proc RunVoidFillingProcess( ) {

	local numeric nullCellsExist = 1;
	local class GUI_CTRL_TOGGLEBUTTON saveToggle = mainDLG.GetCtrlByID("id_SAVE_TEMP_FILE_TOGGLE");
	SetUserSpecifiedGlobalValues();

	print("Starting...\n");

	# Check input SRTM raster to see if it has any null cells
	OpenRaster(inR, InputRasterFilename$, InputRasterObjectName$);
	if (!HasNull(inR)) {
		PopupMessage("This raster does not have any recognized Null values");
		print("Done!\n");
		return;
	}

	# If the temporary working project file is not specified by the user, create one
	if (!saveToggle.GetValue()) {
		TempSRTMfile = _context.ScriptDir + "/SRTMvoidfillingTempFile.rvc";
		if (fexists(TempSRTMfile)) {
			DeleteFile(TempSRTMfile);
		}
		CreateProjectFile(TempSRTMfile, "Temporary working directory for SRTM void filling SML script");
	}

	OpenRaster(outR, OutputRasterFilename$, OutputRasterObjectName$);

	# Make a copy of the input raster.  All procedures will only modify this copy
	DeleteSubobjects(outR);
	CopySubobjects(inR, outR, "ALL");
	if(HasNullValue(inR)) {
		SetNull(outR, NullValue(inR));
	}
	outR = inR;

	# Flush the raster object to recognize the null mask if it has one
	CloseRaster(outR);
	OpenRaster(outR, OutputRasterFilename$, OutputRasterObjectName$);

	# Call the procedure to fill single null cells if selected
	if (mainDLG.GetCtrlByID("id_FILL_SINGLE_NULLS_TOGGLE").GetValueNum()) {
		local numeric negNullTotal = 0;
		local numeric temp = 0;
		print("Filling single null cells\n");

		# Traverse the SRTM raster until no changes are made
		while ( (temp = CheckNegligibleNulls(8 - numRequiredAround )) > 0 ) {
			negNullTotal = negNullTotal + temp;
		}
		print("       Total number changed: " + NumToStr(negNullTotal) + "\n");

		# Check to see if there are any remaining null cells in the raster
		if (NumNullCellsInRaster(outR) == 0) {
			print("There are no remaining null cells in the raster.  Remaining filling methods will be skipped.\n");
			nullCellsExist = 0;
		}
	}

	# Call the procedure to fill null voids with constant boundaries if selected
	if (mainDLG.GetCtrlByID("id_FILL_CONSTANT_NULL_VOIDS_TOGGLE").GetValueNum() and nullCellsExist) {
		FillVoidsWithConstantBoundaryValues();

		# Check to see if there are any remaining null cells in the raster
		if (NumNullCellsInRaster(outR) == 0) {
			print("There are no remaining null cells in the raster.  Remaining filling methods will be skipped.\n");
			nullCellsExist = 0;
		}
	}

	# Call the procedure to fill null voids with additional data if selected
	if (mainDLG.GetCtrlByID("id_FILL_VOIDS_WITH_REF_DEM_TOGGLE").GetValueNum() and nullCellsExist) {
		local numeric i;

		# For each reference raster that was selected
		for i = 0 to numReferenceDEMs-1 {
			if (nullCellsExist) {
				OpenRaster(RefR, RefDEMFilenames$[i], RefDEMObjectNames$[i]);
				RefDataScale = RefR.$Info.DataScale;

				# Call the procedure to replace cells that violate the maximum elevation difference
				if (mainDLG.GetCtrlByID("id_USE_THRESHOLD_TOGGLE").GetValueNum()) {
					RemoveThresholdViolations();
				}

				# Create working raster and vectors and fill holes with reference data
				CreateNullRasterVector();
				FillWithRefRaster();

				# Call the procedure to blend around the null voids if selected
				if (mainDLG.GetCtrlByID("id_USE_BUFFER_ZONE_TOGGLE").GetValueNum()) {
					BlendWithRefRaster();
				}

				CloseRaster(RefR);

				# Check to see if there are any remaining null cells in the raster
				if (NumNullCellsInRaster(outR) == 0) {
					print("There are no remaining null cells in the raster.  Remaining filling methods will be skipped.\n");
					nullCellsExist = 0;
				}
			}
		}
	}

	# Update subobjects for new SRTM raster
	CreateHistogram(outR);
	CreatePyramid(outR);

	print("Void-filled SRTM Raster saved as: " + outR.$Info.Name);
	print("Located in project file: " + outR.$Info.Filename + "\n"); 

	CloseRaster(inR);
	CloseRaster(outR);

	# Delete the working directory if not selected to save
	if (!saveToggle.GetValue()) {
		DeleteFile(TempSRTMfile);
	}

	print("Done!\n");
	return;
}
######################################################################################################


######################################################################################################
# Dialog Related Functions
######################################################################################################

######################################################################################################
# Called when status dialog is created to start the void filling processes
proc OnProgressOpen( ) {

	RunVoidFillingProcess();
	progressDLG.Close(0);
}

######################################################################################################
# Called when status dialog is created to check if the selected input has any valid null cells
proc OnVerifyOpen( ) {

	# Check to see if there are any null cells in the raster
	local class RASTER checkR;
	OpenRaster(checkR, InputRasterFilename$, InputRasterObjectName$);
	numValidNulls = NumNullCellsInRaster(checkR);
	CloseRaster(checkR);
	progressDLG.Close(0);
}

######################################################################################################
# Called when "Run..." is pressed.  Checks to make sure settings are valid before starting the filling
# procedures.
proc OnRunPressed( ) {

	local class GUI_CTRL_PUSHBUTTON buttonRun = mainDLG.GetCtrlByID("id_RUN_BUTTON");
	buttonRun.SetEnabled(0);

	local class GUI_CTRL_TOGGLEBUTTON toggleSingle = mainDLG.GetCtrlByID("id_FILL_SINGLE_NULLS_TOGGLE");
	local class GUI_CTRL_TOGGLEBUTTON toggleConst = mainDLG.GetCtrlByID("id_FILL_CONSTANT_NULL_VOIDS_TOGGLE");
	local class GUI_CTRL_TOGGLEBUTTON toggleDEM = mainDLG.GetCtrlByID("id_FILL_VOIDS_WITH_REF_DEM_TOGGLE");

	if (!toggleSingle.GetValue() and !toggleConst.GetValue() and !toggleDEM.GetValue()) {
		string msg = "Error:  Please select at least one void filling procedure: \n\n";
		msg = msg + "   1) Interpolate single null cells\n";
		msg = msg + "   2) Fill null voids surrounded by constant value\n";
		msg = msg + "   3) Fill null voids using reference DEM rasters";
		PopupMessage(msg);
		buttonRun.SetEnabled(1);
		return;
	}

	# If using reference rasters, make sure the correct number have been selected
	if ( toggleDEM.GetValue() ) {
		local class GUI_CTRL_LISTBOX list = mainDLG.GetCtrlByID("id_REF_DEM_LIST");
		local class GUI_CTRL_EDIT_NUMBER number = mainDLG.GetCtrlByID("id_NUM_REF_DEM");

		if ( list.GetCount() != number.GetValue() ) {
			PopupMessage("Please select the correct number of DEMs you wish to use as reference");
			buttonRun.SetEnabled(1);
			return;
		}
	}

	errXML = progressDOC.Parse(progressxmlCODE$);
	if ( errXML < 0 ) {
		PopupError( errXML );	# pop up an error dialog
		mainDLG.Close(1);
		Exit( );
	}

	progressNODE = progressDOC.GetElementByID( "VERIFY_DIALOG" );
	if ( progressNODE == 0 ) {
		PopupMessage( "Could not find progress dialog node in XML document" );
		mainDLG.Close(1);
		Exit();
	}
	progressDLG.SetXMLNode(progressNODE);
	progressDLG.DoModal( mainDLG.GetWidget() );

	if (numValidNulls == 0) {
		print("There are no recognized null cells in the raster.\n");
		PopupMessage("There are no recognized null cells in the raster.");
		buttonRun.SetEnabled(1);
		return;
	}

	progressNODE = progressDOC.GetElementByID( "PROGRESS_DIALOG" );
	if ( progressNODE == 0 ) {
		PopupMessage( "Could not find progress dialog node in XML document" );
		mainDLG.Close(1);
		Exit();
	}
	progressDLG.SetXMLNode(progressNODE);

	# Set up a timer to record completion time
	local class TIMER time;
	time.Running = 0;
	time.Value = 0;
	time.Running = 1;

	progressDLG.DoModal( mainDLG.GetWidget() );

	time.Running = 0;
	printf("Time to complete: %2d minutes %0.2d seconds", floor(time.Value / 60), floor(time.Value % 60));

	mainDLG.Close(1);
}

######################################################################################################
# Called when "Canel" is pressed.  Closes dialog and exits script.
proc OnCancelPressed( ) {

	mainDLG.Close(1);
}

######################################################################################################
# Called when "Input SRTM raster" is pressed.  Opens dialog to select raster.
proc OnGetInputSRTMPressed( ) {

	local class RASTER R;

	GetInputRaster(R);

	InputRasterFilename$ = R.$Info.Filename;
	InputRasterObjectName$ = R.$Info.Name;
	rows = NumLins(R);
	cols = NumCols(R);
	initType = RastType(R);

	# Update the dialog
	local class GUI_CTRL_EDIT_STRING text = mainDLG.GetCtrlByID("id_INPUT_SRTM_RASTER");
	text.SetValue(InputRasterFilename$ + " / " + InputRasterObjectName$, 0);
	mainDLG.GetCtrlByID("id_GET_OUTPUT_SRTM_BUTTON").SetEnabled(1);

	CloseRaster(R);
}

######################################################################################################
# Called when "Output SRTM raster" is pressed.  Opens dialog to select/create output raster.
proc OnGetOutputSRTMPressed( ) {

	local class RASTER Rin, Rout;

	# Get the raster to save result too
	GetOutputRaster(Rout, rows, cols, initType);
	OutputRasterFilename$ = Rout.$Info.Filename;
	OutputRasterObjectName$ = Rout.$Info.Name;
	CloseRaster(Rout);

	# Update the dialog
	local class GUI_CTRL_EDIT_STRING text = mainDLG.GetCtrlByID("id_OUTPUT_SRTM_RASTER");
	text.SetValue(OutputRasterFilename$ + " / " + OutputRasterObjectName$, 0);
	mainDLG.GetCtrlByID("id_RUN_BUTTON").SetEnabled(1);
}

######################################################################################################
# Called when toggle is changed.  Updates dialog settings.
proc OnUseSingleCellToggleChanged( ) {

	local class GUI_CTRL_TOGGLEBUTTON toggle = mainDLG.GetCtrlByID("id_FILL_SINGLE_NULLS_TOGGLE");
	mainDLG.GetCtrlByID("id_NUM_REQUIRED_SURROUNDING_LABEL").SetEnabled(toggle.GetValue());
	mainDLG.GetCtrlByID("id_NUM_REQUIRED_SURROUNDING").SetEnabled(toggle.GetValue());
}

######################################################################################################
# Called when toggle is changed.  Updates dialog settings.
proc OnUseRefDemToggleChanged( ) {

	local class GUI_CTRL_TOGGLEBUTTON toggle = mainDLG.GetCtrlByID("id_FILL_VOIDS_WITH_REF_DEM_TOGGLE");
	local class GUI_CTRL_EDIT_NUMBER number = mainDLG.GetCtrlByID("id_NUM_REF_DEM");
	local class GUI_CTRL_LISTBOX list = mainDLG.GetCtrlByID("id_REF_DEM_LIST");

	# Manage the listbox
	mainDLG.GetCtrlByID("id_NUM_REF_DEM_LABEL").SetEnabled(toggle.GetValue());
	number.SetEnabled(toggle.GetValue());
	number.ClearValue(0);
	list.DeleteAllItems();
	mainDLG.GetCtrlByID("id_GET_REF_DEM_BUTTON").SetEnabled(0);

	# Manage the sub-procedure settings for using reference rasters
	if (toggle.GetValue() == 0) {
		local class GUI_CTRL_TOGGLEBUTTON threshToggle = mainDLG.GetCtrlByID("id_USE_THRESHOLD_TOGGLE");
		threshToggle.SetValue(0,1);
		threshToggle.SetEnabled(0);

		local class GUI_CTRL_TOGGLEBUTTON bufferToggle = mainDLG.GetCtrlByID("id_USE_BUFFER_ZONE_TOGGLE");
		bufferToggle.SetValue(0,1);
		bufferToggle.SetEnabled(0);
	}
}

######################################################################################################
# Called when "Get DEMs..." is pressed.  Allows user to select the number of reference DEMs that they
# specified in the number box.
proc OnGetRefDEMRastersPressed( ) {

	local class GUI_CTRL_EDIT_NUMBER number = mainDLG.GetCtrlByID("id_NUM_REF_DEM");
	local class GUI_CTRL_LISTBOX list = mainDLG.GetCtrlByID("id_REF_DEM_LIST");

	list.DeleteAllItems();
	RefDEMFilenames$.Clear();
	RefDEMObjectNames$.Clear();

	local class RASTER R;
	local numeric i;
	local numeric numRefDems = number.GetValue();

	# For the number of reference DEMs the user specified they want to use
	for i = 0 to numRefDems-1 {
		GetInputRaster(R);
		RefDEMFilenames$.AddToEnd(R.$Info.Filename);
		RefDEMObjectNames$.AddToEnd(R.$Info.Name);
		CloseRaster(R);

		list.AddItem(RefDEMFilenames$[i] + " / " + RefDEMObjectNames$[i]);
	}

	# Update sub-procedures
	local class GUI_CTRL_TOGGLEBUTTON threshToggle = mainDLG.GetCtrlByID("id_USE_THRESHOLD_TOGGLE");
	threshToggle.SetEnabled(1);
	threshToggle.SetValue(0,1);

	local class GUI_CTRL_TOGGLEBUTTON bufferToggle = mainDLG.GetCtrlByID("id_USE_BUFFER_ZONE_TOGGLE");
	bufferToggle.SetEnabled(1);
	bufferToggle.SetValue(0,1);
}

######################################################################################################
# Called after user changes value of the number of reference DEMs they wish to use.
proc OnNumDEMChanged ( ) {

	local class GUI_CTRL_EDIT_NUMBER number = mainDLG.GetCtrlByID("id_NUM_REF_DEM");
	mainDLG.GetCtrlByID("id_GET_REF_DEM_BUTTON").SetEnabled(1);
	local class GUI_CTRL_LISTBOX list = mainDLG.GetCtrlByID("id_REF_DEM_LIST");

	list.DeleteAllItems();
	RefDEMFilenames$.Clear();
	RefDEMObjectNames$.Clear();

	# Call procedure to start selecting reference DEMs
	OnGetRefDEMRastersPressed();
}


######################################################################################################
# Called when toggle is changed.  Updates dialog settings.
proc OnUseThresholdToggleChanged( ) {

	local class GUI_CTRL_TOGGLEBUTTON toggle = mainDLG.GetCtrlByID("id_USE_THRESHOLD_TOGGLE");
	mainDLG.GetCtrlByID("id_THRESHOLD_VALUE_LABEL").SetEnabled(toggle.GetValue());
	mainDLG.GetCtrlByID("id_THRESHOLD_VALUE").SetEnabled(toggle.GetValue());
}

######################################################################################################
# Called when toggle is changed.  Updates dialog settings.
proc OnUseBufferZoneToggleChanged( ) {

	local class GUI_CTRL_TOGGLEBUTTON toggle = mainDLG.GetCtrlByID("id_USE_BUFFER_ZONE_TOGGLE");
	mainDLG.GetCtrlByID("id_NUM_BUFFER_ZONE_LABEL").SetEnabled(toggle.GetValue());
	mainDLG.GetCtrlByID("id_NUM_BUFFER_ZONE").SetEnabled(toggle.GetValue());
}

######################################################################################################
# Called when "Project File..." is pressed.  Opens dialog to select project file in which to save the
# temporary working vectors and rasters.
proc OnGetTempFilePressed( ) {

	local class GUI_CTRL_EDIT_STRING text = mainDLG.GetCtrlByID("id_TEMP_FILE");

	TempSRTMfile = GetOutputFileName(_context.ScriptDir, "Select project file to save temp files to:", "rvc");

	# Check if the user pressed "Cancel" in the dialog
	if (TempSRTMfile == _context.ScriptDir) {
		local class GUI_CTRL_TOGGLEBUTTON toggle = mainDLG.GetCtrlByID("id_SAVE_TEMP_FILE_TOGGLE");
		mainDLG.GetCtrlByID("id_SAVE_TEMP_FILE_BUTTON").SetEnabled(0);
		toggle.SetValue(0, 0);
		text.ClearValue(0);
		text.SetEnabled(0);
		return;
	} 

	# Delete the file if it exists.  The user would have recieved a "Overwrite this file?" warning.
	if (fexists(TempSRTMfile)) {
		DeleteFile(TempSRTMfile);
	}

	CreateProjectFile(TempSRTMfile, "Created by SRTM Void Filling Script to save temporary files");
	text.SetValue(TempSRTMfile,0);
} 

######################################################################################################
# Called when toggle is changed.  Updates dialog settings.
proc OnSaveTempFileToggleChanged( ) {

	local class GUI_CTRL_TOGGLEBUTTON toggle = mainDLG.GetCtrlByID("id_SAVE_TEMP_FILE_TOGGLE");
	if (toggle.GetValue()) {
		OnGetTempFilePressed();
	}
	mainDLG.GetCtrlByID("id_SAVE_TEMP_FILE_BUTTON").SetEnabled(toggle.GetValue());
	mainDLG.GetCtrlByID("id_TEMP_FILE").SetEnabled(toggle.GetValue());
}

######################################################################################################
# Procedure called to set up the dialog using the XML code specified in this script.  Dialog is made
# using a Modal function call.  When the dialog closes, the script will end.
proc OnCreateDialog( ) {

	errXML = mainDOC.Parse(mainxmlCODE$);
	if ( errXML < 0 ) {
		PopupError( errXML );	# pop up an error dialog
		Exit( );
	}

	mainNODE = mainDOC.GetElementByID( "MAIN_DIALOG" );
	if ( mainNODE == 0 ) {
		PopupMessage( "Could not find main dialog node in XML document" );
		Exit();
	}

	mainDLG.SetXMLNode(mainNODE);

	errDLG = mainDLG.DoModal();
	if ( errDLG == -1 ) {
		Exit();
	}
}
######################################################################################################












Back Home ©MicroImages, Inc. 2013 Published in the United States of America
11th Floor - Sharp Tower, 206 South 13th Street, Lincoln NE 68508-2010   USA
Business & Sales: (402)477-9554  Support: (402)477-9562  Fax: (402)477-9559
Business info@microimages.com  Support support@microimages.com  Web webmaster@microimages.com

25 March 2009

page update: 26 May 11