# Soil_Info.sml # Randy Smith, MicroImages, Inc. # 28 September 2007 # View ToolScript # Requires version 2007:73 of the TNT products, 26 September 2007 or later ######################################################## # # Tool Script for use with a Group or Layout that includes a vector soil map with a standard # SSURGO soil database provided by the Natural Resource Conservation Service. # Specificially, the polygon database must include a table named "mapunit". # # The tool script provides a polygon tool to allow the user to outline a desired area of # the soil vector in the View. The soil vector layer must be the active layer # in the active group when the tool is in use. # # The tool determines the soil types within this area, the cumulative area for each soil type # within the area, and creates a CSV (Comma-Separated Values) text file containing a list # of soil types, their areas, soil name, and soil kind. The CSV file is then used to open and # run the software program that is associated with the CSV file type on the user's computer. # # This sample script can be modified to work with other types of vector data or with soil vector # objects containing a different database structure. # ############################################################## # # The following symbols are predefined # class GRE_VIEW View {use to access the view the tool script is attached to} # class GRE_GROUP Group {use to access the group being viewed if the script is run from a group view} # class GRE_LAYOUT Layout {use to access the layout being viewed if the script is run from a layout view} # numeric 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 key being pressed or 0 if not # numeric CtrlPressed 1 if 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 # # The following script functions will be called (if used in the script) when # the appropriate action or event occurs as described in the comments before each. # To use a function, uncomment the lines containing the 'func' definition # and ending brace '}' by removing the leftmost '#' on the line and add the # function code between the two lines. ### Declarations of global variables class GRE_GROUP aGroup; # use non-predefined class instance to handle use with Layouts class GRE_LAYER_VECTOR soilLayer; # the layer containing the soil vector object class RVC_VECTOR soilVec; # the soil vector object class MDISPREGIONTOOL tool; # class instance for the polygon tool that returns a region numeric areaScale = GetUnitConvArea("square meters", "acres"); # scale for converting areas to acres ####################################################### # function to check active layer to see if it is valid for use with tool. func checkLayer () { local numeric valid = false; local numeric i; local string tblName$; local class RVC_DBASE_POLYGON polyRVC_DB; if (aGroup.ActiveLayer.TypeID == "") # check for empty group View.SetMessage("Group has no layers!"); else if (aGroup.ActiveLayer.TypeID == "Vector") { # check that active layer is a vector soilLayer = aGroup.ActiveLayer; DispGetVectorFromLayer(soilVec, soilLayer); if (soilVec.$Info.NumPolys == 0) # check that the vector has polygons View.SetMessage("Vector must contain polygon elements to use this tool!"); else { # check if polygon table "mapunit" exists. polyRVC_DB.OpenAsSubobject(soilVec, "Read"); if (polyRVC_DB.IsTableValid(mapunit) ) { # mapunit table exists valid = true; View.SetMessage("Vector is valid."); } else # no mapunit table View.SetMessage("Active layer vector object must include a polygon table named 'mapunit'!"); } } else # active layer is not a vector object View.SetMessage("Active layer must be a vector object to use this tool!."); return valid; } ############################################## # Callback for when the active layer changes. proc cbLayer() { checkLayer(); } ############################################### # Callback for when the active group changes. proc cbGroup() { aGroup = Layout.ActiveGroup; WidgetAddCallback(aGroup.LayerSelectedCallback, cbLayer); cbLayer(); } ######################################################## # Called when user presses 'right' pointer/mouse button. proc OnRightButtonPress () { if ( checkLayer() ) { local class REGION2D toolRegion; # region gotten from tool and transformed to map coordinates local class RVC_GEOREFERENCE vGeoref; # default georeference for the soil vector object local class RVC_VECTOR regionVec, xSoilVec; local numeric i; # loop counter local numeric polyarea; # area of polygon from Polystats table. local string key$; # key to hash entries local numeric soilAreaHash[]; # hash to store areas for different soil types local numeric polyNumHash[]; # hash to store element number of first polygon for each soil type local numeric polynum; # polygon element number local class STRINGLIST keyList; # list of soil types (keys) gotten from hash local string musym$, muname$, mukind$; # values to be written as formatted text to CSV file local class FILE outfile; # handle for open text file local string dfltName$ = _context.ScriptDir + "/outfile.csv"; local string outfileName$; # name of output CSV file # get the georeference for the soil vector soilVec.GetDefaultGeoref(vGeoref); # region created by tool has screen coordinates; # must translate to map coordinates of the view (view coordinates) and # then to map coordinates of the vector object in the active layer. toolRegion = RegionTrans(tool.RegionData, View.GetTransViewToScreen(1)); # inverse, screen to view toolRegion = RegionTrans(toolRegion, View.GetTransMapToView(vGeoref.GetCoordRefSys(), 1) ); # inverse, view to map # convert region to temporary vector object to use for extraction CreateTempVector(regionVec); regionVec = ConvertRegionToVect(toolRegion); View.SetMessage("Extracting area..."); # extract the area of the soil vector object to a temporary vector for processing CreateTempVector(xSoilVec); xSoilVec = VectorExtract(regionVec, soilVec, "InsideClip", "AddBorder,RemExRecords"); CloseVector(regionVec); View.SetMessage("Making CSV file..."); # prompt user for name of output CSV file; open file and write header line outfileName$ = GetOutputFileName(dfltName$, "Choose output CSV file:", "csv"); outfile = fopen(outfileName$, "w"); fprint(outfile, "musym,acres,muname,mukind"); # loop through extracted polygons to get areas from POLYSTATS table; # use HASH to keep track of soil types and add areas for polygons of same type for i = 1 to xSoilVec.$Info.NumPolys { key$ = xSoilVec.Poly[i].mapunit.musym$; polyarea = xSoilVec.Poly[i].POLYSTATS.Area; if (soilAreaHash.Exists(key$) ) { # soil type is already in the soil area hash # add area of current polygon to value already stored in soil area hash for that soil soilAreaHash[key$] = soilAreaHash[key$] + polyarea; } else { # new soil type soilAreaHash[key$] = polyarea; # assign area of polygon to soil area hash key polyNumHash[key$] = i; # assign element number of polygon to polynum hash key } } # get list of hash keys as a stringlist to loop through them keylist = soilAreaHash.GetKeys(); # loop through keys by numeric position in stringlist (starting with 0) for i = 0 to keylist.GetNumItems() - 1 { musym$ = keylist.GetString(i); # soil identifier polyarea = soilAreaHash[musym$]; # area for soil type polyarea = polyarea * areaScale; # convert area from square meters to acres # get soil name and kind from fields in mapunit table using polygon numbers stored in polynum hash polynum = polyNumHash[musym$]; muname$ = "\"" +xSoilVec.Poly[polynum].mapunit.muname$ + "\""; # field contains commas, so must be quoted for use in CSV file mukind$ = xSoilVec.Poly[polynum].mapunit.mukind$; # write values to a line in the output CSV file fprintf(outfile, "%s,%.2f,%s,%s\n", musym$, polyarea, muname$, mukind$); } View.SetMessage("Done."); fclose(outfile); RunAssociatedApplication(outfileName$); # launch application associated with the CSV file type (e.g. Excel) CloseVector(xSoilVec); } } # end of OnRightButtonPress # Called the first time the tool is activated. # If the tool implements a dialog it should be created (but not displayed) here. proc OnInitialize () { if (Layout) { WidgetAddCallback(Layout.GroupSelectedCallback, cbGroup); aGroup = Layout.ActiveGroup; } else aGroup = Group; WidgetAddCallback(aGroup.LayerSelectedCallback, cbLayer); # Create polygon tool. tool = ViewCreatePolygonTool(View); ToolAddCallback(tool.ApplyCallback, OnRightButtonPress); } # end of OnInitialize # 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. proc OnDestroy () { tool.Managed = 0; } # end of OnDestroy # Called when tool is activated. # If the tool implements a dialog it should be "managed" (displayed) here. proc OnActivate () { tool.Managed = 1; tool.HasPosition = 0; } # 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. proc OnDeactivate () { tool.Managed = 0; } # end of OnDeactivate # Called when tool is to be 'suspended' during a redraw operation. # proc OnSuspend () { # } # end of OnSuspend # Called when tool is to be 'resumed' after a redraw operation. # If the tool displays any graphics they should be updated by this function. # proc OnResume () { # } # end of OnResume # Called when user presses 'left' pointer/mouse button. # proc OnLeftButtonPress () { # } # end of OnLeftButtonPress # Called when user presses 'middle' pointer/mouse button. # proc OnMiddleButtonPress () { # } # end of OnMiddleButtonPress # Called when user releases 'left' pointer/mouse button. # proc OnLeftButtonRelease () { # } # end of OnLeftButtonRelease # Called when user releases 'right' pointer/mouse button. # proc OnRightButtonRelease () { # } # end of OnRightButtonRelease # Called when user releases 'middle' pointer/mouse button. # proc OnMiddleButtonRelease () { # } # end of OnMiddleButtonRelease # Called when user moves cursor if no button being pressed # proc OnPointerMoveNoButton () { # } # end of OnPointerMoveNoButton # Called when user moves cursor while holding down button # proc OnPointerMoveWithButton () { # } # end of OnPointerMoveWithButton # Called when cursor enters window associated with view. # proc OnEnterWindow () { # } # end of OnEnterWindow # Called when cursor leaves window associated with view. # proc OnLeaveWindow () { # } # end of OnLeaveWindow # Called when user presses 'key' on keyboard. # proc OnKeyPress (key) { # } # end of OnKeyPress