############################################################################ # Fragtool.sml # Created by: Mark Smith # Most recent revision: 5-2001 # This toolscript allows the user to draw a region using a region tool. It # then uses the region to mask the active layer (provided it is an integer- # value raster) to extract a raster usable by fragstats. It writes the # output raster to a text file and calls fragstats using a set of default # parameters after querying the user for the edge distance value. # # The active layer must be an integer-value, single raster with square cells. # Later versions may support more formats. # # This script requires the fragstats executable which is installed in the TNT # mips win32 directory and that the temporary folder path specified by mips # have folder names no greater than 8 characters long or have spaces in them. # Variable declarations class XmForm form, buttonRow; class PushButtonItem closeButton; class MdispRegionTool tool; class Raster targetRaster; class GRE_LAYER rasterLayer; string rasterName$, frag$; class XmDrawingArea da; class GC gc; class GRE_GROUP group; class FILE outFile; numeric setDefaultWhenClose = false; # Checks layer to see if it is valid. func checkLayer() { local numeric valid = false; # Get name of active layer if it is usable. If not output an error message. if (group.ActiveLayer.Type == "") { rasterName$ = "Group has no layers!"; } else { if (group.ActiveLayer.Type == "Raster") { rasterLayer = group.ActiveLayer; DispGetRasterFromLayer(targetRaster, rasterLayer); if (targetRaster.$Info.Type == "32-bit floating-point" or targetRaster.$Info.Type == "64-bit floating-point") { rasterName$ = "Raster type not supported!"; } else { rasterName$ = rasterLayer.Name; valid = true; } } else rasterName$ = "Not a raster!"; } return valid; } # Callback for drawing area expose. Draws text. proc cbRedraw() { if (gc == 0) return; ActivateGC(gc); # Clear the drawing area and redraw text. SetColorName("gray75"); FillRect(0, 0, da.width, da.height); SetColorName("black"); DrawInterfaceText(rasterName$, 0, 12); } # Callback for when the active layer changes. proc cbLayer() { checkLayer(); cbRedraw(); } # Callback for when the active group changes. proc cbGroup() { group = Layout.ActiveGroup; WidgetAddCallback(group.LayerSelectedCallback, cbLayer); cbLayer(); } # Callback for when user clicks the right mouse button on the polygon tool # (or clicks apply). proc cbToolApply(class RegionTool tool) { # If the selected layer is not valid, don't do anything. if (checkLayer()) { # Set local variables local region MyRgn; local class StatusHandle status; local class StatusContext context; local numeric lins, cols, csize, edist, value; string type$, tempFile$, fragout$, realout$; # Create a status bar so user knows the script is doing something. status = StatusDialogCreate(form); context = StatusContextCreate(status); StatusSetMessage(context, "Running fragstats..."); # Get region. MyRgn = tool.Region; MyRgn = RegionTrans(MyRgn, ViewGetTransViewToScreen(View, 1)); MyRgn = RegionTrans(MyRgn, ViewGetTransLayerToView(View, rasterLayer, 1)); lins = NumLins(targetRaster); cols = NumCols(targetRaster); tempFile$ = CreateTempFileName(); realout$ = ""; fragout$ = GetToken(GetOutputFileName(_context.ScriptDir, "Where would you like the results?", ""), ".", 0); local numeric i; local string temp$; for i = 1 to NumberTokens(fragout$, "\\") { temp$ = GetToken(fragout$, "\\", i); if (strlen(temp$)>8 or NumberTokens(temp$, " ")>1) { realout$ = fragout$; fragout$ = FileNameGetPath(tempFile$)+"\\"+FileNameGetName(tempFile$); break; } } if (FileNameGetName(fragout$)=="") goto cleanup; csize = (LinScale(targetRaster) + ColScale(targetRaster)) / 2; edist = PopupNum("Enter the edge distance in meters:"); # Write to text file outFile = fopen(tempFile$); # Apply the region for fragstats' use IgnoreNull(targetRaster); value = 32071; # Fragstats won't use anything larger than this value local numeric row, column; for row = 1 to lins step 1 { for column = 1 to cols step 1 { if (PointInRegion(column, row, MyRgn)) { fprintf(outFile, "%d ", targetRaster[row, column]); } else fprintf(outFile, "%d ", -value); } if (row != lins) fprintf(outFile, "\n"); } # Close output file fclose(outFile); # Run fragstats run(sprintf("%s %s %s %d %d 2 %d %d %d $ $ $ $ $ y y y y y", frag$, tempFile$, fragout$, csize, edist, lins, cols, value), 1); if (realout$ != "") { CopyFile(fragout$+".cla", realout$+".cla"); DeleteFile(fragout$+".cla"); CopyFile(fragout$+".ful", realout$+".ful"); DeleteFile(fragout$+".ful"); CopyFile(fragout$+".lnd", realout$+".lnd"); DeleteFile(fragout$+".lnd"); CopyFile(fragout$+".pat", realout$+".pat"); DeleteFile(fragout$+".pat"); } cleanup: # Cleanup #DeleteFile(Rout.$Info.Filename); DeleteFile(tempFile$); # Destroy the status bar StatusContextDestroy(context); StatusDialogDestroy(status); } else PopupMessage(rasterName$); } # Called when the close button is pressed. Closes the dialogs. proc cbClose() { tool.Managed = 0; DialogClose(form); if (setDefaultWhenClose) { setDefaultWhenClose = false; View.SetDefaultTool(); } } # Called the first time the tool is activated. # If the tool implements a dialog it should be created (but not displayed) here. func OnInitialize () { if (Layout!=null) { WidgetAddCallback(Layout.GroupSelectedCallback, cbGroup); group = Layout.ActiveGroup; } else group = Group; WidgetAddCallback(group.LayerSelectedCallback, cbLayer); # Set up tool dialog. form = CreateFormDialog("Fragstat"); form.marginHeight = 2; form.marginWidth = 2; WidgetAddCallback(form.Shell.PopdownCallback, cbClose); # Drawing area for displaying text. da = CreateDrawingArea(form, 15, 400); da.topWidget = form; da.leftWidget = form; da.rightWidget = form; WidgetAddCallback(da.ExposeCallback, cbRedraw); # Separator between drawing area and close button. class XmSeparator line; line = CreateHorizontalSeparator(form); line.topWidget = da; line.leftWidget = form; line.rightWidget = form; line.topOffset = 2; # Closes the dialog. closeButton = CreatePushButtonItem("Close", cbClose); # Row of buttons. buttonRow = CreateButtonRow(form, closeButton); buttonRow.topWidget = line; buttonRow.leftWidget = form; buttonRow.rightWidget = form; buttonRow.bottomWidget = form; # Add create polygon tool. tool = ViewCreatePolygonTool(View); ToolAddCallback(tool.ActivateCallback, cbToolApply); frag$ = GetInputFileName("c:/tnt/win32/fragstat.exe", "Please locate the fragstat executable.", "exe"); } # end of OnInitialize # Called when tool is to be destroyed, will not be called if tool was never activated. func OnDestroy () { tool.Managed = 0; DestroyGC(gc); DestroyWidget(form); } # end of OnDestroy # Called when tool is activated. func OnActivate () { checkLayer(); tool.Managed = 1; tool.HasPosition = 0; DialogOpen(form); if (gc == 0) gc = CreateGCForDrawingArea(da); cbRedraw(); setDefaultWhenClose = true; } # end of OnActivate # Called when tool is deactivated (usually when switching to another tool). func OnDeactivate () { setDefaultWhenClose = false; cbClose(); } # end of OnDeactivate