######################
#
# 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()