flowpathXML.sml

  Download

More scripts: Display Toolbar

Syntax Highlighing:

comments, key words, predefined symbols, class members & methods, functions & classes
            
######################
#
# FLOWPATHxml.SML
#
# Demonstration SML ToolScript using an XML specification to create the
# toolscript dialog window.
#
# Requires TNTmips Version 7.4 or later.
# Get the lastest version of this toolscript from our website www.microimages.com
#####################
# View ToolScript
#
# The following symbols are predefined
#    class VIEW View            {use to access the view the tool script is attached to}
#    class GROUP Group          {use to access the group being viewed if the script is run from a group view}
#    class LAYOUT Layout        {use to access the layout being viewed if the script is run from a layout view}
#    number ToolIsActive        Will be 0 if tool is inactive or 1 if tool is active
#
# The following values are also predefined and are valid when the various On...()
# functions are called which deal with pointer and keyboard events.
#    numeric PointerX               Pointer X coordinate within view in pixels
#    numeric PointerY               Pointer Y coordinate within view in pixels
#    numeric ShiftPressed           1 if <shift> key being pressed or 0 if not
#    numeric CtrlPressed            1 if <ctrl> key being pressed or 0 if not
#    numeric LeftButtonPressed      1 if left pointer button pressed or 0 if not
#    numeric RightButtonPressed     1 if right pointer button pressed or 0 if not
#    numeric MiddleButtonPressed    1 if middle pointer button pressed or 0 if not
# To use this ToolScript add one or more DEM's to your Group Display
# The DEM you actually want to use in the watershed process should be the first layer in the group
# i.e. the layer at the bottom of the Group Controls window if you want to change the DEM that you were using
# switch from the ToolScript tool to some other tool and move that DEM to the bottom of the Group Controls
# and reactivate the Toolscript it will ask if you want to switch the input DEM
# you can run several successive flowpaths and buffer zones keeping the same DEM
array numeric seedx[10];
array numeric seedy[10];
class WATERSHED w;
numeric numpts, i;
class RVC_RASTER DEM;
class RVC_GEOREFERENCE rGeoref;
class TRANS2D_MAPGEN transparm;
class RECT3D extentsDEM;
numeric firstpass;
class GRE_LAYER_VECTOR VecBuf;
class GRE_LAYER_VECTOR VecFlow;
class GRE_LAYER_VECTOR BasinLayer;
class GRE_LAYER_VECTOR BoundaryLayer;
class GRE_LAYER_RASTER DEMLayer;
numeric haslayers;
class XMLDOC doc;
class XMLNODE dlgnode;
class GUI_DLG dlgform;
class GUI_CTRL_COLORBUTTON bocolorbtn, fcolorbtn, bacolorbtn, bucolorbtn;
numeric setDefaultWhenClose;
class RVC_VECTOR VectIn;
class RVC_VECTOR VecBoundary;
class POINT2D pt;
array numeric xPoints[10],yPoints[10];
numeric xMax,yMax,xMin,yMin;
array numeric xhold[10], yhold[10];
class PromptNum PromptDistance;
class RVC_VECTOR VECFLOW, VECFLOW2;
string tempfilename$, demFilename$, demObjname$;
string flowpathFilename$, flowpathObjname$;
string userflowpathFilename$, userflowpathObjname$;
string userBasinFilename$, userBasinObjname$;
numeric tempinode, demInode, flowpathInode;
string tempobjname$;
class Color bocolor;
class Color fcolor;
class Color bucolor;
class Color bacolor;
# function to create a status to attach popup messages to
# the advantage is that if the process is quick dialog won't pop in/out
# requires tntdisp 20001012 or later
proc StatusStart() {
	class StatusHandle status;
	class StatusContext context;
	status = StatusDialogCreate();
	context = StatusContextCreate(status);
}
proc StatusStop() {
		StatusContextDestroy(context);
		StatusDialogDestroy(status);
}
# called when user presses save button on dialog
# if something wasn't calculated by choice output object is empty
proc DoSave() {
	local numeric answer, destParentInode, userflowpathInode, userbasinInode;
	local string destFilename$;
	local vector Buffer2;
	if (haslayers) {
		answer = PopupYesNo("Save Output Objects?");
		if (answer) {
			#Get output Filename
			destFilename$ = GetOutputFileName(" ","Watershed output","rvc");
			CreateProjectFile(destFilename$,"Watershed output");
			destParentInode = 0;
			userflowpathInode = ObjectNumber(userflowpathFilename$,userflowpathObjname$,"VECTOR");
			CopyObject(userflowpathFilename$,userflowpathInode,destFilename$,destParentInode);
			CreateVector(Buffer2,destFilename$,"Buffer","Flow path buffer zone","Polygonal");
			Buffer2 = VectorToBufferZone(VectIn,"line",PromptDistance.value,"meters");
			userbasinInode = ObjectNumber(userBasinFilename$,userBasinObjname$,"VECTOR");
			CopyObject(userBasinFilename$,userbasinInode,destFilename$,destParentInode);
		}
	}
}
# function to remove layers from display
proc DoRemove() {
	if (haslayers) {
		View.DisableRedraw = 1;
		#save user's changes to colors;
		fcolor.red = VecFlow.Line.NormalStyle.Color.red;
		fcolor.green = VecFlow.Line.NormalStyle.Color.green;
		fcolor.blue = VecFlow.Line.NormalStyle.Color.blue;
		bucolor.red = VecBuf.Line.NormalStyle.Color.red;
		bucolor.green = VecBuf.Line.NormalStyle.Color.green;
		bucolor.blue = VecBuf.Line.NormalStyle.Color.blue;
		bacolor.red = BasinLayer.Line.NormalStyle.Color.red;
		bacolor.green = BasinLayer.Line.NormalStyle.Color.green;
		bacolor.blue = BasinLayer.Line.NormalStyle.Color.blue;
		bocolor.red = BoundaryLayer.Line.NormalStyle.Color.red;
		bocolor.green = BoundaryLayer.Line.NormalStyle.Color.green;
		bocolor.blue = BoundaryLayer.Line.NormalStyle.Color.blue;
		VecFlow = LayerDestroy(VecFlow);
		VecBuf = LayerDestroy(VecBuf);
		BasinLayer = LayerDestroy(BasinLayer);
		View.DisableRedraw = 0;
		haslayers = 0;
		}
}
# called when user presses remove button on dialog
proc cbDoRemove() {
	DoRemove();
	ViewRedrawIfNeeded(View);
}
# called when the user presses the set button on dialog
# sets the number of seedpoints to use
proc DoSet() {
	numpts = PopupNum("Enter number of seed points", numpts,1,10);
	i = 1;
	}
# Close the window, switching to default tool
# called when user presses close button and when clicks x in dialog
proc DoClose() {
	if (setDefaultWhenClose) {
		setDefaultWhenClose = false;
		View.SetDefaultTool();
	}
}
# Called when new flow path color is selected from toolscript dialog
proc OnChangefcolor () {
	fcolor = fcolorbtn.GetColor();
	if (GroupGetLayerByName(Group,VecFlow.Name) != 0) {
		View.DisableRedraw = 1;
		VecFlow.Line.NormalStyle.Color.red = fcolor.red;
		VecFlow.Line.NormalStyle.Color.green = fcolor.green;
		VecFlow.Line.NormalStyle.Color.blue = fcolor.blue;
		View.DisableRedraw = 0;
		ViewRedraw(View);
		}
	}
# Called when new basin color is selected from toolscript dialog
proc OnChangebacolor () {
	bacolor = bacolorbtn.GetColor();
	if (GroupGetLayerByName(Group,BasinLayer.Name) != 0) {
		View.DisableRedraw = 1;
		BasinLayer.Line.NormalStyle.Color.red = bacolor.red;
		BasinLayer.Line.NormalStyle.Color.green = bacolor.green;
		BasinLayer.Line.NormalStyle.Color.blue = bacolor.blue;
		View.DisableRedraw = 0;
		ViewRedraw(View);
		}
	}
# Called when new buffer zone color is selected from toolscript dialog
proc OnChangebucolor () {
	bucolor = bucolorbtn.GetColor();
	if (GroupGetLayerByName(Group,VecBuf.Name) != 0) {
		View.DisableRedraw = 1;
		VecBuf.Line.NormalStyle.Color.red = bucolor.red;
		VecBuf.Line.NormalStyle.Color.green = bucolor.green;
		VecBuf.Line.NormalStyle.Color.blue = bucolor.blue;
		View.DisableRedraw = 0;
		ViewRedraw(View);
		}
	}
# Called when new extents box color is selected from toolscript dialog
proc OnChangebocolor () {
	bocolor = bocolorbtn.GetColor();
	# PopupMessage(sprintf("Extents box red = %d, green = %d, blue = %d",bocolor.red,bocolor.green,bocolor.blue))
	View.DisableRedraw = 1;
	BoundaryLayer.Poly.Select.Mode = "None";
	BoundaryLayer.Line.NormalStyle.Color.red = bocolor.red;
	BoundaryLayer.Line.NormalStyle.Color.green = bocolor.green;
	BoundaryLayer.Line.NormalStyle.Color.blue = bocolor.blue;
	View.DisableRedraw = 0;
	ViewRedraw(View);
	}
# Called the first time the tool is activated.
# If the tool implements a dialog it should be created (but not displayed) here.
func OnInitialize () {
	local numeric err;
	# set up initial colors for vector layers
	bocolor.red = 100;	bocolor.green = 0;		bocolor.blue = 0;
	fcolor.red = 0;		fcolor.green = 0;			fcolor.blue = 100;
	bucolor.red = 100;	bucolor.green = 100;		bucolor.blue = 0;
	bacolor.red = 0;		bacolor.green = 100;		bacolor.blue = 0;
	StatusStart();
		# get the raster input DEM
		if (Group.FirstLayer.Type == "Raster") {
			DispGetRasterFromLayer(DEM,Group.FirstLayer);
			DEMLayer = Group.FirstLayer;
			# get georeference and extents for the DEM
			DEM.GetDefaultGeoref(rGeoref);
			rGeoref.GetTransParm(transparm, 0, rGeoref.GetCalibModel() );
			extentsDEM = DEMLayer.Extents;		# extents in object coordinates
			extentsDEM = transparm.ConvertRectFwd(extentsDEM);		# convert to map coordinates
			}
		else {
			PopupString("First Layer must be a raster object for Watershed Toolscript");
			WaitForExit();
			}
		demFilename$ = GetObjectFileName(DEM);
		demInode = GetObjectNumber(DEM);
		demObjname$ = GetObjectName(demFilename$,demInode);
		# Initialize watershed object (assigns object handle)
		w = WatershedInit(demFilename$,demObjname$);
		# Fill all depressions in DEM and compute watersheds.
		# a depressionless version of the DEM is automatically created
		# as a temporary internal object associated with watershed handle w
		WatershedCompute(w,"FillAllDepressions,FlowPath");
		# get the Flow Paths for the entire raster
		WatershedGetObject(w,"VectorFlowPath",flowpathFilename$,flowpathObjname$);
		flowpathInode = ObjectNumber(flowpathFilename$,flowpathObjname$,"VECTOR");
		CreateTempVector(VECFLOW);
		tempfilename$ = GetObjectFileName(VECFLOW);
		tempinode = GetObjectNumber(VECFLOW);
		tempobjname$ = GetObjectName(tempfilename$,tempinode);
		tempinode = CopyObject(flowpathFilename$,flowpathInode,tempfilename$);
		tempfilename$ = GetObjectFileName(VECFLOW);
		tempobjname$ = GetObjectName(tempfilename$,tempinode);
		CloseVector(VECFLOW);
		OpenVector(VECFLOW2,tempfilename$,tempobjname$);
		firstpass = 1;
		haslayers = 0;
		numpts = 1;
		# read and parse into memory the XML text describing the dialog; return an error code
		#  if there are syntax errors in the dialog specification.
		err = doc.Parse(
		'<?xml version="1.0"?>
			<root>
				<dialog id="dlgform" title="Flow Path and Buffer Zone" OnApply="OnApply()" OnOK="OnApply()" OnClose="DoClose()">
					<book>
						<page Name="Controls">
							<pane Orientation="horizontal">
								<pushbutton Name="Save" Icon="FILE_SAVE" ToolTip="Save Output Layers..." OnPressed="DoSave()"/>
								<pushbutton Name="Remove" Icon="CONTROL_SUBTRACT_CYAN" ToolTip="Remove Output Layers" OnPressed="cbDoRemove()"/>
								<pushbutton Name="Number of Seedpoints..." OnPressed="DoSet()"/>
							</pane>
							<pane Orientation="vertical">
								<togglebutton id="btnSnap"		Name="Move Seed Point to Flow Path"	Selected="false"/>
								<togglebutton id="btnFlow"		Name="Compute Flow Path" 				Selected="true"/>
								<togglebutton id="btnBasin"	Name="Compute Upstream Basin" 		Selected="true"/>
								<togglebutton id="btnBuffer"	Name="Compute Buffer Zone" 			Selected="false"/>
							</pane>
							<pane Orientation="horizontal">
								<label>Buffer Distance: </label>
								<editnumber id="buffDist" Width ="5" Default="100" Precision="0" MinVal="0"/>
							</pane>
						</page>
						<page Name="Colors" Orientation ="vertical">
							<pane Orientation ="horizontal">
								<colorbutton id="fcolor" OnChangeColor="OnChangefcolor()"/>
								<label>  Flow path color</label>
							</pane>
							<pane Orientation = "horizontal">
								<colorbutton id="bacolor" OnChangeColor="OnChangebacolor()"/>
								<label>  Basin color</label>
							</pane>
							<pane Orientation = "horizontal">
								<colorbutton id="bucolor" OnChangeColor="OnChangebucolor()"/>
								<label>  Buffer zone color</label>
							</pane>
							<pane Orientation = "horizontal">
								<colorbutton id="bocolor" OnChangeColor="OnChangebocolor()"/>
								<label>  Extents box color</label>
							</pane>
						</page>
					</book>
				</dialog>
			</root>' );
		if (err < 0 ) {		# pop up a dialog to report XML syntax errors
			PopupError(err);
			Exit();
			}
		# get the dialog element from the parsed XML structure and show error
		# message if the dialog element can't be found
		dlgnode = doc.GetElementByID("dlgform");
		if (dlgnode == 0) {
			PopupMessage("Could not find dialog node in XML document");
			Exit();
			}
		# set the XML dialog element as the source for the GUI_DLG class instance
		# we are using for the main dialog window, and open as a modeless dialog
		dlgform.SetXMLNode(dlgnode);
		dlgform.CreateModeless();
		# Assign initial colors to color buttons on dialog
		fcolorbtn = dlgform.GetCtrlByID("fcolor");
		fcolorbtn.SetColor(fcolor);
		bacolorbtn = dlgform.GetCtrlByID("bacolor");
		bacolorbtn.SetColor(bacolor);
		bucolorbtn = dlgform.GetCtrlByID("bucolor");
		bucolorbtn.SetColor(bucolor);
		bocolorbtn = dlgform.GetCtrlByID("bocolor");
		bocolorbtn.SetColor(bocolor);
	StatusStop();
	}	# end of OnInitialize
# procedure to move seed point(s) to nearest flow path(s) before computing
# new watershed vectors
proc DoSnapSeed () {
	class RVC_VECTOR tempflowvector, TempFlowBuffer;
	class RVC_VECTOR stub;
	numeric linenumber;
	numeric a;
	numeric b;
	numeric returndistance;
	numeric tempx;
	numeric tempy;
	array tempseedx[1];
	array tempseedy[1];
	CreateTempVector(stub,"VectorToolkit");
	tempseedx[1] = seedx[i];
	tempseedy[1] = seedy[i];
#	StatusStart();
		WatershedComputeElements(w,tempseedx,tempseedy,1,"FlowPath");
#	StatusStop();
	WatershedGetObject(w,"VectorUserFlowPath",userflowpathFilename$,userflowpathObjname$);
	OpenVector(tempflowvector,userflowpathFilename$,userflowpathObjname$);
	CreateTempVector(TempFlowBuffer);
	TempFlowBuffer = VectorToBufferZone(tempflowvector,"line",1,"meters");
	stub = VectorExtract(TempFlowBuffer,VECFLOW2,"InsideClip");
	# if this vector has no lines then the user defined flowpath runs straight off DEM
	# and doesn't connect with the flowpath so skip these calculations, thus leaving
	# the seedpoint where it was originally
	if (NumVectorLines(stub) > 0)	{
		pt.x = xhold[i];
		pt.y = yhold[i];
		pt = TransPoint2D(pt,ViewGetTransLayerToScreen(View,DEMLayer,1));
		pt = TransPoint2D(pt,ViewGetTransLayerToView(View,DEMLayer));
		pt = TransPoint2D(pt,ViewGetTransMapToView(View,DEMLayer.projection,1));
		MapToObject(GetLastUsedGeorefObject(stub), pt.x, pt.y, stub, tempx, tempy);
		linenumber = FindClosestLine(stub,pt.x,pt.y,GetLastUsedGeorefObject(stub),9999999.9,returndistance);
		ClosestPointOnLine(stub,linenumber,tempx,tempy,a,b);
		ObjectToMap(stub,a,b,GetLastUsedGeorefObject(stub),tempx,tempy);
		MapToObject(GetLastUsedGeorefObject(DEM),tempx,tempy,DEM,a,b);
		seedx[i] = a;
		seedy[i] = b;
		CloseVector(tempflowvector);
		CloseVector(TempFlowBuffer);
		CloseVector(stub);
		}
	} # End of DoSnapSeed()
# compute and display flowpath,buffer and buffer zone if chosen by user
proc DoFlowPath() {
#	StatusStart();
	# compute vector flow paths originating at seed point location.
	# This step requires the previous computation of the depressionless DEM
	#don't draw view until we are done
	View.DisableRedraw = 1;
	#only calculate what we have to
	local btnFlowSet;
	local btnBasinSet;
	local btnBufferSet;
	class GUI_CTRL_TOGGLEBUTTON btnFlow, btnBasin, btnBuffer;		# this method works!
	btnFlow = dlgform.GetCtrlByID("btnFlow");
	btnBasin = dlgform.GetCtrlByID("btnBasin");
	btnBuffer = dlgform.GetCtrlByID("btnBuffer");
	btnFlowSet = btnFlow.GetValue();
	btnBasinSet = btnBasin.GetValue();
	btnBufferSet = btnBuffer.GetValue();
	########## Popup message for testing data retrieval from  dialog
	# PopupMessage( sprintf("Flow= %s, Basin= %s, Buffer = %s",btnFlowSet$,btnBasinSet$,btnBufferSet$) )
	if ((btnFlowSet == 0) and (btnBufferSet == 0) and (btnBasinSet == 0)) {
		return;
	}
	local string wsopt$;
	wsopt$ = "";
	if ( (btnFlowSet == 1) or (btnBufferSet ==1)) then wsopt$ = "FlowPath";
	if (btnBasinSet == 1) {
		if (wsopt$ != "") then wsopt$ = wsopt$ + ",";
		wsopt$ = wsopt$ + "Basin";
		}
	WatershedComputeElements(w,seedx,seedy,numpts,wsopt$);
	if  ((btnFlowSet == 1) or (btnBufferSet == 1)) {
	WatershedGetObject(w,"VectorUserFlowPath",userflowpathFilename$,userflowpathObjname$);
	OpenVector(VectIn,userflowpathFilename$,userflowpathObjname$);
	}
	if (btnFlowSet == 1) { # had to calculate it for buffer now add it if they want it
		VecFlow = GroupQuickAddVectorVar(Group,VectIn);
		#change the displayed color according to user (previous) choice
		VecFlow.Line.NormalStyle.Color.red = fcolor.red;
		VecFlow.Line.NormalStyle.Color.green = fcolor.green;
		VecFlow.Line.NormalStyle.Color.blue = fcolor.blue;
	}
	# Compute Buffer zone around flow path
	if (btnBufferSet == 1) {
		class VECTOR Buffer, TempBuffer;
		class GUI_CTRL_EDIT_NUMBER buffDist;
		buffDist = dlgform.GetCtrlByID("buffDist");
		CreateTempVector(Buffer);
		CreateTempVector(TempBuffer);
		TempBuffer = VectorToBufferZone(VectIn,"line",buffDist.GetValueNum(),"meters");
		Buffer = VectorExtract(VecBoundary,TempBuffer,"InsideClip");
		VecBuf = GroupQuickAddVectorVar(Group,Buffer);
		VecBuf.Line.NormalStyle.Color.red = bucolor.red;
		VecBuf.Line.NormalStyle.Color.green = bucolor.green;
		VecBuf.Line.NormalStyle.Color.blue = bucolor.blue;
		}
	# Display basin if selected
	if (btnBasinSet == 1) {
		class VECTOR BasinVector;
		WatershedGetObject(w,"VectorUserBasin",userBasinFilename$,userBasinObjname$);
		OpenVector(BasinVector,userBasinFilename$,userBasinObjname$);
		BasinLayer = GroupQuickAddVectorVar(Group,BasinVector);
		BasinLayer.Poly.Select.Mode = "None";
		BasinLayer.Line.NormalStyle.Color.red = bacolor.red;
		BasinLayer.Line.NormalStyle.Color.green = bacolor.green;
		BasinLayer.Line.NormalStyle.Color.blue = bacolor.blue;
	}
	View.DisableRedraw = 0;
	ViewRedrawIfNeeded(View);
	haslayers = 1;
#	StatusStop();
	}  # end of DoFlowPath
# Called when tool is to be destroyed, will not be called if tool was never activated.
# If the tool implements a dialog it should be destroyed here.
# don't destroy added layers here since they are already destroyed before this gets called
func OnDestroy () {
	# WatershedClose(w);
	}  # end of OnDestroy
# Called when tool is activated.
# If the tool implements a dialog it should be "managed" (displayed) here.
func OnActivate () {
#	StatusStart();
	if (!firstpass) {
		local numeric answer;
		answer = PopupYesNo("Keep Same Input DEM?");
		if (!answer) {
			CloseRaster(DEM);
			if (Group.FirstLayer.Type == "Raster") {
				DispGetRasterFromLayer(DEM,Group.FirstLayer);
				DEMLayer = Group.FirstLayer;
				}
		else {
			PopupString("First Layer must be a raster object for Watershed Toolscript");
			WaitForExit();
			}
		demFilename$ = GetObjectFileName(DEM);
		demInode = GetObjectNumber(DEM);
		demObjname$ = GetObjectName(demFilename$,demInode);
		# Initialize watershed object (assigns object handle)
		w = WatershedInit(demFilename$,demObjname$);
		# Fill all depressions in DEM and compute watersheds.
		# a depressionless version of the DEM is automatically created
		# as a temporary internal object associated with watershed handle w
		WatershedCompute(w,"FillAllDepressions,FlowPath");
		# get the Flow Paths for the entire raster
		WatershedGetObject(w,"VectorFlowPath",flowpathFilename$,flowpathObjname$);
		flowpathInode = ObjectNumber(flowpathFilename$,flowpathObjname$,"VECTOR");
		CreateTempVector(VECFLOW);
		tempfilename$ = GetObjectFileName(VECFLOW);
		tempinode = GetObjectNumber(VECFLOW);
		tempobjname$ = GetObjectName(tempfilename$,tempinode);
		tempinode = CopyObject(flowpathFilename$,flowpathInode,tempfilename$);
		tempfilename$ = GetObjectFileName(VECFLOW);
		tempobjname$ = GetObjectName(tempfilename$,tempinode);
		CloseVector(VECFLOW);
		OpenVector(VECFLOW2,tempfilename$,tempobjname$);
		}
	}
	# draw vector box around DEM so can show and clip buffer zone to it
	CreateTempVector(VecBoundary,"VectorToolkit", "", extentsDEM);
	class RVC_GEOREFERENCE boxGeoref;
	boxGeoref.SetCoordRefSys(rGeoref.GetCoordRefSys());
	boxGeoref.SetImplied();
	boxGeoref.Make(VecBoundary);
	VectorToolkitInit(VecBoundary);
	xPoints[1] = extentsDEM.x1;
	yPoints[1] = extentsDEM.y1;
	xPoints[2] = extentsDEM.x2;
	yPoints[2] = extentsDEM.y1;
	xPoints[3] = extentsDEM.x2;
	yPoints[3] = extentsDEM.y2;
	xPoints[4] = extentsDEM.x1;
	yPoints[4] = extentsDEM.y2;
	xPoints[5] = extentsDEM.x1;
	yPoints[5] = extentsDEM.y1;
	VectorAddLine(VecBoundary, 5, xPoints, yPoints);
	VectorValidate(VecBoundary);
	View.DisableRedraw = 1;
	BoundaryLayer.Poly.Select.Mode = "None";
	BoundaryLayer = GroupQuickAddVectorVar(Group,VecBoundary);
	BoundaryLayer.IgnoreExtents = 1;
	BoundaryLayer.Line.NormalStyle.Color.red = bocolor.red;
	BoundaryLayer.Line.NormalStyle.Color.green = bocolor.green;
	BoundaryLayer.Line.NormalStyle.Color.blue = bocolor.blue;
	View.DisableRedraw = 0;
	ViewRedrawIfNeeded(View);
	# set i
	i = 1;
	dlgform.Open();
	setDefaultWhenClose = true;
#	StatusStop();
	} # end of OnActivate
# Called when tool is deactivated (usually when switching to another tool).
# If the tool implements a dialog it should be "unmanaged" (hidden) here.
func OnDeactivate () {
	DoRemove();
	View.DisableRedraw = 1;
	BoundaryLayer = LayerDestroy(BoundaryLayer);
	View.DisableRedraw = 0;
	ViewRedrawIfNeeded(View);
	firstpass = 0;
	setDefaultWhenClose = false;
	dlgform.Close(0);
	}  # end of OnDeactivate
# Called when Apply button on dialog is pressed.
proc OnApply () {
	DoRemove();
	if (i <= numpts) {
		# make sure seed points are within bounds of raster
		if (seedx[i] > (DEM.$Info.NumCols-1))
			seedx[i] = (DEM.$Info.NumCols-1);
		if (seedx[i] < 0)
			seedx[i] = 0;
		if (seedy[i] > (DEM.$Info.NumLins-1))
			seedy[i] = (DEM.$Info.NumLins-1);
		if (seedy[i] < 0)
			seedy[i] = 0;
		# if user wants to move seedpoint to flowpath
		if (dlgform.GetCtrlValueNum("btnSnap") == 1) {
			DoSnapSeed();
			}
		i = i + 1;
		}
	if (i > numpts) {
		DoFlowPath();
		i = 1;
		}
	}
# Called when user releases 'left' pointer/mouse button.
func OnLeftButtonPress() {
	DoRemove();
	if (i <= numpts) {
		pt.x = PointerX;
		pt.y = PointerY;
		xhold[i] = PointerX;
		yhold[i] = PointerY;
		pt = TransPoint2D(pt,ViewGetTransLayerToScreen(View, DEMLayer, 1));
		seedx[i] = pt.x;
		seedy[i] = pt.y;
		# make sure seed points are within bounds of raster
		if (seedx[i] > (DEM.$Info.NumCols-1))
			seedx[i] = (DEM.$Info.NumCols-1);
		if (seedx[i] < 0)
			seedx[i] = 0;
		if (seedy[i] > (DEM.$Info.NumLins-1))
			seedy[i] = (DEM.$Info.NumLins-1);
		if (seedy[i] < 0)
			seedy[i] = 0;
		#if user wants to move seedpoint to flowpath
		if (dlgform.GetCtrlValueNum("btnSnap") == 1) {
			DoSnapSeed();
			}
		i = i + 1;
		}
	if (i > numpts) {
		DoFlowPath();
		i = 1;
		}
	} # end of OnLeftButtonPress()