####################################### # BOXCAR2.SML Demonstration Script # Sample script for Building Dialogs in SML # # Keith Ghormley, MicroImages, Inc. # Revised for TNTmips SML version 6.80 # by Randy Smith, MicroImages, Inc. # Script shows steps needed to create a sample application # with a dialog window incorporating a view of geospatial # data. # Example is an interactive "boxcar" classification of # a set of three input rasters. The user specifies a # range of raster values for each input raster, and the # script identifies cells whose value sets fall within # the specified ranges. # The three input rasters (identified as Red, Green, and # Blue) are used to make a color composite for display. # A dialog window incorporates the view and prompt fields # for entering limit values for the boxcar classification # ranges. A temporary binary classification raster is # used to hold the result of the classification and is # displayed over the input composite with "0" cells # transparent and "1" cells in yellow. This raster is # computed and display when the user presses the Process # button. Pressing the Clear button or entering any new # limit values removes the class layer from the view and # resets all values to 0. The Save button allows the # user to save the temporary class raster in a project file. # The close button closes the dialog and frees all resources. clear(); ######################################################## # Class instances needed in procedures class GRE_GROUP gp; # spatial group for display. class GRE_VIEW view; # view that displays the group. class XmForm bcwin; # parent form for window. class GRE_LAYER_RASTER templayer; # layer handle for class raster. class RVC_COLORMAP cPalette; # handle for color palette for # class raster. class PROMPTNUM redHI, redLO, greenHI, greenLO, blueHI, blueLO; # class instances for the editable numeric fields in the dialog ######################################################## # Global Variables numeric numlins, numcols; string rasttype$; numeric gmRed, maxRed, minRed; numeric gmGreen, maxGreen, minGreen; numeric gmBlue, maxBlue, minBlue; numeric rLO, rHI, gLO, gHI, bLO, bHI; numeric count, templayerexists; class RASTER Red, Green, Blue; # variables for input rasters class RASTER TempRed, TempGreen, TempBlue; # temporary rasters for contrast- # adjusted versions of input rasters class RASTER TempComp; # variable for temporary composite raster for display class RASTER TempClass; # variable for temporary class raster class RASTER ClassRast; # variable for saved class raster ######################################################## # Define procedures. # Called when Clear button is pressed or when # range values are changed. proc OnClear() { if (templayerexists == 1) { LayerDestroy(templayer); ViewRedraw(view,0); templayerexists = 0; for each TempClass { if (TempClass == 1) then TempClass = 0; } } } # Called when new Red High value is input. proc OnR_HI() { rHI = redHI.value; OnClear(); } # Called when new Red Low value is input. proc OnR_LO() { rLO = redLO.value; OnClear(); } # Called when new Green High value is input. proc OnG_HI() { gHI = greenHI.value; OnClear(); } # Called when new Green Low value is input. proc OnG_LO() { gLO = greenLO.value; OnClear(); } # Called when new Blue High value is input. proc OnB_HI() { bHI = blueHI.value; OnClear(); } # Called when new Blue Low value is input. proc OnB_LO() { bLO = blueLO.value; OnClear(); } # Called when Process button is pressed. proc OnProcess() { count = 0; ViewSetMessage(view,"Processing..."); for each TempClass { if ( (Red <= rHI) and (Red >= rLO) and (Green <= gHI) and (Green >= gLO) and (Blue <= bHI) and (Blue >= bLO) ) then { TempClass = 1; count = count + 1; } } if (count == 0) { OnClear(); ViewSetMessage(view,"No cells fall in specified ranges."); PopupMessage("No cells fall in specified ranges. Adjust ranges and process again."); } else { templayer = GroupQuickAddRasterVar(gp,TempClass); templayer.NullCellsTransparent = 1; templayer.ColorMap = cPalette; ViewRedraw(view,0); templayerexists = 1; } } # Called when Save button is pressed. proc OnSave() { GetOutputRaster(ClassRast,numlins,numcols,"binary"); for each ClassRast { ClassRast = TempClass; } CopySubobjects(TempClass,ClassRast,"ALL"); } # Called when Close button is pressed or when the "X" close # button on the title bar is pressed. proc OnClose() { DestroyWidget(bcwin); GroupDestroy(gp); CloseRaster(TempComp); CloseRaster(TempClass); CloseRaster(Red); CloseRaster(Green); CloseRaster(Blue); } # Called when dialog is destroyed. # Can be either by the "Close" menu item or by us # calling DestroyWidget() above. proc OnDestroy() { Exit(); } ########################################################## # Main program ########################################################## # Get input rasters. PopupMessage("Select three processing bands for boxcar classification."); GetInputRaster(Red); numlins = NumLins(Red); numcols = NumCols(Red); rasttype$ = RastType(Red); GetInputRaster(Green,numlins,numcols,rasttype$); GetInputRaster(Blue,numlins,numcols,rasttype$); # Create temporary composite raster from input for display. # (There is currently no SML function to display an RGB raster set). # The function that creates a composite raster requires an output filename, # object name, and description. We will use the class information from # the temporary raster to provide the filename, object name, and object # description to the conversion function. # The conversion function also ignores contrast tables, so we will first # create contrast-enhanced versions of the input rasters by applying # the last-used contrast subobject for each raster. class RASTER TempComp; CreateTempRaster(TempComp,numlins,numcols,"24-bit color RGB"); CreateTempRaster(TempRed,numlins,numcols,"8-bit unsigned"); CreateTempRaster(TempGreen,numlins,numcols,"8-bit unsigned"); CreateTempRaster(TempBlue,numlins,numcols,"8-bit unsigned"); RasterApplyContrast2(Red,TempRed,"Subobject"); RasterApplyContrast2(Green,TempGreen,"Subobject"); RasterApplyContrast2(Blue,TempBlue,"Subobject"); RasterRGBToComposite(TempRed,TempGreen,TempBlue,TempComp,TempComp.$Info.Filename, TempComp.$Info.Name,TempComp.$Info.Desc); CopySubobjects(Red,TempComp,"georef"); CreatePyramid(TempComp,0); # Create temporary binary raster for boxcar class. # Will be displayed over the composite. CreateTempRaster(TempClass,numlins,numcols,"binary"); CopySubobjects(Red,TempClass,"georef"); # Create color palette subobject for binary class raster. # Define one palette color with transparency. class Color clsclr; clsclr.red = 100; clsclr.green = 100; clsclr.blue = 0; clsclr.transp = 0; # Set index color 1 and write color palette to temporary raster. ColorMapSetColor(cPalette,1,clsclr); ColorMapWriteToRastVar(TempClass,cPalette,"Color Palette",""); ########################################################## # Get mean, max, and min values from input rasters. gmRed = int(GlobalMean(Red)); maxRed = GlobalMax(Red); minRed = GlobalMin(Red); gmGreen = int(GlobalMean(Green)); maxGreen = GlobalMax(Green); minGreen = GlobalMin(Green); gmBlue = int(GlobalMean(Blue)); maxBlue = GlobalMax(Blue); minBlue = GlobalMin(Blue); # Set initial cell value ranges for boxcar classification. rLO = gmRed - 10; rHI = gmRed + 10; gLO = gmGreen - 10; gHI = gmGreen + 10; bLO = gmBlue - 10; bHI = gmBlue + 10; ######################################################### # Create dialog window for boxcar classification. ######################################################### gp = GroupCreate(); bcwin = CreateFormDialog("Boxcar Classification"); WidgetAddCallback(bcwin.Shell.PopdownCallback, OnClose); WidgetAddCallback(bcwin.DestroyCallback, OnDestroy); # Create pushbutton items for Process, Clear, Save, and Close. class PUSHBUTTONITEM btnItemProcess; class PUSHBUTTONITEM btnItemClear; class PUSHBUTTONITEM btnItemSave; class PUSHBUTTONITEM btnItemClose; btnItemProcess = CreatePushButtonItem("Process",OnProcess); btnItemClear = CreatePushButtonItem("Clear",OnClear); btnItemSave = CreatePushButtonItem("Save",OnSave); btnItemClose = CreatePushButtonItem(" Close ",OnClose); # Create button row for pushbuttons and attach to bottom # of dialog window. class XmForm btnrow; btnrow = CreateButtonRow(bcwin,btnItemProcess,btnItemClear,btnItemSave,btnItemClose); btnrow.BottomWidget = bcwin; btnrow.RightWidget = bcwin; btnrow.LeftWidget = bcwin; # Create separator line above button row. class XmSeparator sepline; sepline = CreateHorizontalSeparator(bcwin); sepline.TopOffset = 4; sepline.LeftWidget = bcwin; sepline.RightWidget = bcwin; sepline.BottomWidget = btnrow; # Create RowColumn widget with to hold min-max labels # and prompt fields for hi-lo values. Set orientation # to horizontal so the column parameter sets the number of # rows to 4 and to fill in the row direction first. class XmRowColumn promptrc; promptrc = CreateRowColumn(bcwin,4); promptrc.Orientation = "HORIZONTAL"; promptrc.BottomWidget = sepline; # Create labels in RowColumn widget for Min and Max raster values. class XmLabel redMin, greenMin, blueMin; class XmLabel redMax, greenMax, blueMax; redMin = CreateLabel(promptrc, sprintf(" Min. Red: %d",minRed) ); greenMin = CreateLabel(promptrc, sprintf(" Min. Green: %d",minGreen) ); blueMin = CreateLabel(promptrc, sprintf(" Min. Blue: %d",minBlue) ); redMax = CreateLabel(promptrc, sprintf(" Max. Red: %d",maxRed) ); greenMax = CreateLabel(promptrc, sprintf(" Max. Green: %d",maxGreen) ); blueMax = CreateLabel(promptrc, sprintf(" Max. Blue: %d",maxBlue) ); # Create prompt fields in the same RowColumn widget. # Add callbacks for change in value. redLO = CreatePromptNum(promptrc," Red Low: ",3,0,gmRed-10,minRed,maxRed); WidgetAddCallback(redLO.ValueChangedCallback,OnR_LO); greenLO = CreatePromptNum(promptrc," Green Low: ",3,0,gmGreen-10,minGreen,maxGreen); WidgetAddCallback(greenLO.ValueChangedCallback,OnG_LO); blueLO = CreatePromptNum(promptrc," Blue Low: ",3,0,gmBlue-10,minBlue,maxBlue); WidgetAddCallback(blueLO.ValueChangedCallback,OnB_LO); redHI = CreatePromptNum(promptrc," Red High: ",3,0,gmRed+10,minRed,maxRed); WidgetAddCallback(redHI.ValueChangedCallback,OnR_HI); greenHI = CreatePromptNum(promptrc," Green High: ",3,0,gmGreen+10,minGreen,maxGreen); WidgetAddCallback(greenHI.ValueChangedCallback,OnG_HI); blueHI = CreatePromptNum(promptrc," Blue High: ",3,0,gmBlue+10,minBlue,maxBlue); WidgetAddCallback(blueHI.ValueChangedCallback,OnB_HI); # Adjust widths of prompt labels to align them better. redLO.label.width = redHI.label.width; redLO.label.Alignment = "ALIGNMENT_END"; greenLO.label.width = greenHI.label.width; greenLO.label.Alignment = "ALIGNMENT_END"; blueLO.label.width = blueHI.label.width; blueLO.label.Alignment = "ALIGNMENT_END"; # Create view in bcwin to display input rasters and class overlay. # A view has its own XmForm widget accessed as a class member "Form". # We add the view last because the last widget added is the only one # that resizes automatically if the parent dialog is resized. # If the view were added earlier, the last button row added would # be the widget that would automatically resize. view = GroupCreateView(gp,bcwin,"",500,400,"DestroyOnClose,NoStatusLine,NoScalePosLine"); bcwin.BottomWidget = promptrc; ########################################################## # Open window and add composite from input rasters to view. DialogOpen(bcwin); GroupQuickAddRasterVar(gp,TempComp); ViewRedrawFull(view); WaitForExit(); # End of main process.