############################################################
#
# ReconStrikeDipTool.sml (Tool Script)
#
############################################################
# Started: April 2008
# Author: Randy Smith, MicroImages, Inc.
# Version April 2013
# Requires TNTmips version 2010 or later
# Updated to use new SML tool classes and associated functions
# added in TNTmips 2010.
# Added code to the OnModeChange, OnAccept, and OnCancel functions to properly
# manage the "ScriptGadget" and associated tool. Fixes a problem with
# selecting an existing point in Edit and Delete modes.
# Version 1 May 2008
# Requires TNTmips version 2007:73 or later
##############################################################
#
# PURPOSE:
#
# This script provides a tool to enable geologists to record estimates
# of Strike and Dip of bedding determined from a georeferenced aerial or
# satellite image. Station locations are recorded as points in a
# Strike/Dip vector object. A CartoScript included within this Tool Script
# is used to display appropriately-oriented estimated strike/dip symbols.
# The display parameters are automatically saved for the output vector so
# that the CartoScript styling is retained when the Strike/Dip vector is
# used later. The script creates and displays a control dialog for
# display and selecting measurement criteria.
# A two-point line tool is provided for drawing the strike direction at any
# desired locality in the image. The station location is recorded at the
# center point of the strike line. The dip angle is recorded as a category
# selected by pressing a radiobutton on the scripts control dialog.
# The dip categories are:
# horizontal: 0 degrees
# gentle: 1 to 30 degrees
# moderate: 30 to 60 degrees
# steep: over 60 degrees
# vertical: 90 degrees
# A strike/dip measurement can be marked as overturned by pressing the
# Overturned toggle button.
# ASSUMPTIONS:
# Dip direction is determined by the right-hand rule, so the strike line
# should be drawn so that the dip direction is to the right when facing in
# the strike direction. A push-button on the control dialog reverses the
# start and end points of the line and thus the strike direction when needed.
# For overturned beds, the strike line should also be drawn so that the dip
# direction is to the right, but pressing the Overturned toggle reverses
# the strike direction so that the facing direction (top of beds) is to the
# right rather than the overturned dip direction.
# The tool script dialog provides separate modes to VIEW, ADD, EDIT, and
# DELETE points in the Strike/Dip vector object.
# ADD - the two-point line tool is active for drawing a new strike line.
# Draw (and reposition if needed) the strike line, then right-click to
# set the line position. Choose a dip category and set Overturned if
# needed, then press ACCEPT to record the point and attached measurements
# or CANCEL.
# VIEW - left-click to select the nearest station point and show its
# recorded values in the control dialog. Selecting a new station
# deselects the previous one. Press CANCEL to deselect the last selected
# station and reactivate the Mode radiobuttons.
# EDIT - left-click to select the nearest station point and show its recorded
# values in the control dialog. Press ACCEPT to edit the point (or CANCEL to
# deselect it). When editing, the two-point line tool is restored at its
# position for the station; further actions are the same as for ADD.
# DELETE - left-click to select the nearest station point and show its recorded
# values in the control dialog. Press DELETE to delete the point, or CANCEL.
# Estimated strike / dip symbols created by the CartoScript follow
# guidelines set by the Geologic Data Subcommittee, U.S. Federal Geographic
# Data Committee.
#
# 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 <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
##################################################################################
# ToolScript Global Variables
##################################################################################
class GUI_DLG dlg; # the control dialog
class GUI_CTRL_LABEL promptString; # handles for dialog controls
class GUI_CTRL_TOGGLEBUTTON togOVERTURNED;
class GUI_CTRL_EDIT_NUMBER strikeFld, dipDirFld;
class GUI_CTRL_TOGGLEBUTTON togGENTLE, togMODERATE, togSTEEP, togHORIZONTAL, togVERTICAL;
class GUI_CTRL_PUSHBUTTON btnACCEPT, btnCANCEL, btnDELETE, btnCLOSE;
class GUI_CTRL_PUSHBUTTON btnREVERSE;
class GUI_FORM_RADIOGROUP idMODE;
class GUI_GADGET_SEGMENT tool; # two-point line tool
class RVC_RASTER RAST; # the raster that is the first layer in the group
class RVC_VECTOR StrikeDipVector; # vector object containing station location points
class RVC_OBJITEM SDvectObjItem; # ObjItem for the strike/dip vector object
class GEOREF SDgeoref; # georeference for the strike/dip vector object
class RVC_GEOREFERENCE rvcGeorefRAST; # georeference from the background raster
class TRANSMODEL rastCalibModel; # geometric transformation model from the DEM georeference
class TRANS2D_MAPGEN transRASTobjToMap; # coordinate transformation from DEM object to its map coordinates
class SR_COORDREFSYS rastCRS, utmCRS; # coordinate reference system for background raster and an equivalent UTM CRS
class TRANS2D_MAPGEN transGeogUTM; # coordinate transformation from geographic to UTM coordinates
class STRING coordUnit$; # id of map coordinate unit used in the raster CRS
class GRE_GROUP activegroup, firstGroup;
class GRE_LAYER activeLayer;
class GRE_LAYER_RASTER rasterLayer;
class GRE_LAYER_VECTOR SDvectorLayer;
class GRE_VECTOR_POINTS SDpoints;
class DATABASE SDdb;
class DBTABLEINFO SDtable;
class DBFIELDINFO SDstationfield;
class STRING dipCategory$; # category of dip angle: gentle 0-30, moderate 30-60, or steep 60-90
numeric dipDir; # azimuth of dip direction (0 to 360 degrees clockwise from north)
numeric strikeAng; # azimuth of strike line
numeric station, overturned;
numeric setDefaultWhenClose;
numeric selectedElementNum;
numeric currentlyEditing = 0;
numeric toolApplied;
numeric waitingForAddConfirmation = 0;
numeric deletedStation;
numeric transGeogCoords; # flag to indicate map coordinates need to be transformed from
# geographic to UTM
class POINT3D ctrPt;
string Current_Mode = "ADD";
string genericQuery = "(Outcrop.Station == ";
string currentQuery;
array numeric records[1];
# CartoScript used to draw the strike/dip symbols
class STRING reconSDqry$ = '# reconBedding.qry
# This is a sample script for drawing geologic point
# symbols for strike and dip of bedding, including
# special cases of horizontal, vertical, overturned bedding.
# The dip value is shown as a text label, except in the
# cases of horizontal and vertical bedding.
# Information required for each point includes the strike
# value (degrees), dip value (degrees), and whether the bed is
# overturned. Each of these values is read from a particular
# field in an attached database table. To use the script you
# will need to edit the statements that include database references
# to conform to your table name and field names.
# Strike angle must be specified as azimuth (0 to 360 degrees
# clockwise from north). Dip direction is defined by the
# strike azimuth using the right hand rule: of the two possible
# azimuths for a given strike line, choose the azimuth the
# strike line points toward with the dip direction on the right hand
# side of the strike line. (For overturned beds, substitute facing
# direction [stratigraphic top] for dip direction in the rule).
# The script assumes that the database field for overturned
# bedding is a Logical field, with Yes indicating overturned bed
# and No (default value) indicating upright bedding.
# Modified for Legend samples August 2002.
# Modified to declare all variables October 2005;
# Modified to correct for angle between grid north and true north May 2006.
# Version Nov. 2007
# Requires TNTmips 2007:73 or later
# Modified to adjust scale based on georeference map units.
numeric azStrike, overturned1, red, green, blue;
class STRING dipCat$;
numeric scale, lineWidthMap, lineWidth;
numeric tickLengthMap, tickLength, tickSpaceMap, tickSpace;
numeric horizSizeMap, horizSize, horizTick, horizSpace;
numeric strikeDashMap, strikeDash, halfDash, strikeSpaceMap, strikeSpace;
#numeric halfLength, tickLength, doubTick, halfTick, heightMap, height, offset;
string fontName$, label$;
numeric direction, oppStrike, dipDir, oppDip;
numeric next_x ,next_y, labelLength, shift1, shift2;
class RVC_GEOREFERENCE vGeoref;
class SR_COORDREFSYS vectCRS;
numeric northAng;
class POINT2D point;
string coordUnit$;
###################### Set Parameters ##############################
# Read strike azimuth and dip value from table.field
azStrike = Bedding.StrikeAngle #### change to fit your data ####
dipCat$ = Bedding.DipCategory; #### change to fit your data ####
# This variable defines the denominator of the intended map scale.
# It is used as the basis for defining line width and symbol size.
# Example: for 1:24,000 map scale, Scale = 24000
scale = 150000;
# Check if vector has geographic coordinates (units of degrees instead of meters)
# and if so adjust scale factor to draw symbols of appropriate size.
Vect.GetDefaultGeoref(vGeoref);
vectCRS = vGeoref.GetCoordRefSys();
if (vectCRS.IsProjected() <> 1) {
if (vectCRS.IsLocal() <> 1) {
scale = scale * 0.00001;
}
}
else { # CRS is projected; check coordinate units to adjust scale
# get coordinate unit from the first axis of the planar coordinate system
coordUnit$ = vectCRS.Coordsys.GetAxis(1).Unit.GetSymbol();
scale = scale * GetUnitConvDist("m", coordUnit$);
}
# find angle to north at the current point\'s map coordinates
class TRANS2D_MAPGEN transObjToMap;
class TRANSMODEL model;
model = vGeoref.GetCalibModel();
vGeoref.GetTransParm(transObjToMap, 0, model);
point.x = Vect.Point.Internal.x; # object coordinates of current point
point.y = Vect.Point.Internal.y;
point = transObjToMap.ConvertPoint2DFwd(point); # convert to map coordinates
northAng = vectCRS.ComputeAngleToNorth(point);
# subtract angle to north from stored strike value for display
azStrike = azStrike - northAng;
# red, green, blue variables define the color of the symbols and label
red = 0; green = 0; blue = 0;
# These variables define the dimensions and line widths of the
# symbol. LineWidthMap is the desired line width in mm, assuming
# vector coordinates are in meters.
lineWidthMap = 0.15;
strikeDashMap = 1.375;
strikeSpaceMap = 0.5;
tickLengthMap = 0.875;
tickSpaceMap = 0.5;
horizSizeMap = 2.125;
if (DrawingLegendView == 1) {
# strikeLength = 0.5 * SampleRect.GetWidth();
lineWidth = 0.08 * strikeLength;
}
else {
lineWidth = lineWidthMap * scale / 1000;
strikeDash = strikeDashMap * scale / 1000;
halfDash = strikeDash * 0.5;
strikeSpace = strikeSpaceMap * scale / 1000;
tickLength = tickLengthMap * scale / 1000;
tickSpace = tickSpaceMap * scale / 1000;
horizSize = horizSizeMap * scale / 1000;
horizTick = horizSize * .35;
horizSpace = horizSize * .15;
}
######################### Process ############################
# Convert strike azimuth to internal coordinate system.
direction = -(azStrike - 90);
if (direction < 0)
direction = direction + 360;
oppStrike = direction -180;
dipDir = direction - 90;
oppDip = dipDir - 180;
# Set line color, width, and end type
LineStyleSetColor(red, green, blue); # set symbol color
LineStyleSetLineWidth(lineWidth);
LineStyleSetCapJoinType(1,1); # square ends of lines
########### Draw symbol
LineStyleDropAnchor(0); # drop anchor at point location
# Special symbol for horizontal bedding (cross in circle)
if (dipCat$ == "HORIZONTAL")
{
LineStyleMoveTo(0, horizSpace);
LineStyleLineTo(0, horizTick);
LineStyleMoveToAnchor(0);
LineStyleMoveTo(90, horizSpace);
LineStyleLineTo(90, horizTick);
LineStyleMoveToAnchor(0);
LineStyleMoveTo(180, horizSpace);
LineStyleLineTo(180, horizTick);
LineStyleMoveToAnchor(0);
LineStyleMoveTo(270, horizSpace);
LineStyleLineTo(270, horizTick);
}
else
{
# draw dashed strike line with center at point
LineStyleMoveTo(oppStrike, (1.5 * strikeDash) + strikeSpace);
LineStyleLineTo(direction, strikeDash);
LineStyleMoveTo(direction, strikeSpace);
LineStyleLineTo(direction, strikeDash);
LineStyleMoveTo(direction, strikeSpace);
LineStyleLineTo(direction, strikeDash);
LineStyleMoveToAnchor(0);
if (Bedding.Overturned)
{
LineStyleMoveTo(oppStrike, halfDash);
LineStyleDrawArc(0, 0, halfDash, halfDash, direction, -180, 0);
LineStyleMoveToAnchor(0);
dipDir = oppDip;
}
if (dipCat$ == "GENTLE") # draw symbol with single tick mark
{
LineStyleLineTo(dipDir, tickLength);
}
else if (dipCat$ == "MODERATE") # draw symbol with two tick marks, centered, tick length apart
{
LineStyleMoveTo(direction, tickSpace * 0.5);
LineStyleLineTo(dipDir, tickLength);
LineStyleMoveToAnchor(0);
LineStyleMoveTo(oppStrike, tickSpace * 0.5);
LineStyleLineTo(dipDir, tickLength);
}
else if (dipCat$ == "STEEP") # draw symbol with three tick marks
{
LineStyleLineTo(dipDir, tickLength); # draw center tick mark
LineStyleMoveToAnchor(0);
LineStyleMoveTo(direction, tickSpace); # draw second tick mark
LineStyleLineTo(dipDir, tickLength);
LineStyleMoveToAnchor(0);
LineStyleMoveTo(oppStrike, tickSpace);
LineStyleLineTo(dipDir, tickLength);
}
else if (dipCat$ == "VERTICAL")
{
LineStyleLineTo(dipDir, tickLength);
LineStyleMoveToAnchor(0);
LineStyleLineTo(oppDip, tickLength);
}
}';
# Basic ToolScript procedures
##################################################################################
proc OnRightButtonPress();
proc OnLeftButtonPress();
proc OnInitialize ();
proc OnDestroy ();
proc OnActivate ();
proc OnDeactivate ();
# Procedures called from interaction with the dialog
##################################################################################
proc OnModeChange();
proc OnGentlePressed();
proc OnModeratePressed();
proc OnSteepPressed();
proc OnHorizontalPressed();
proc OnVerticalPressed();
proc OnOverturnedChanged();
proc OnReverseStrikeLine(class LINETOOL tool);
proc OnAccept();
proc OnCancel();
proc OnDelete();
proc OnClose();
# Functions used to manage the Strike and Dip data
##################################################################################
func addPointToVector(class POINT3D pt);
proc addRecordToDatabase( numeric pointElemNumAdded );
proc UpdateQuery();
proc deleteStation();
# Functions used to initialize or maintain the display layers and databases
##################################################################################
func checkLayer();
proc checkGeoref();
proc createDestVectors();
func createVectorGeoreference();
func vectorLayerExists(string name);
proc addVectorsToDisplay();
proc initializeBeddingDatabaseTable();
# Functions used to manage callbacks
##################################################################################
proc OnLineSet();
proc cbToolApply();
proc cbLayer();
proc cbGroup();
proc cbClose();
##################################################################################
#### Callback for when the active layer changes
proc cbLayer( ) {
if (!checkLayer() ) {
string message$ = "The First Layer: "+activeLayer.Name+" is not a raster.";
PopupMessage(message$);
}
else
checkGeoref();
}
##################################################################################
#### Callback for when the active group changes
proc cbGroup( ) {
activegroup = Layout.ActiveGroup;
WidgetAddCallback(activegroup.LayerSelectedCallback, cbLayer);
cbLayer();
}
###########################################################
### Procedure to check georeference of background raster; if it uses a geographic coordinate
### system, set up a coordinate transformation to the appropriate UTM zone
### to transform map coordinates used to determine strike values.
### Called by onInitialize() and by cbLayer()
proc checkGeoref () {
local class RECT3D extentsObj;
local class POINT2D center;
transGeogCoords = 0;
rvcGeorefRAST.OpenLastUsed(RAST);
rastCRS = rvcGeorefRAST.GetCoordRefSys();
rastCalibModel = rvcGeorefRAST.GetCalibModel();
rvcGeorefRAST.GetTransParm(transRASTobjToMap, 0, rastCalibModel);
if (rastCRS.IsProjected() <> 1) { # raster CRS is not projected
if (rastCRS.IsLocal() <> 1) { # raster CRS also is not local, then must be geographic (lat/lon)
transGeogCoords = 1;
RAST.GetExtents(extentsObj);
center = extentsObj.center;
center = transRASTobjToMap.ConvertPoint2DFwd(center); # raster center point in map coordinates, used to set UTM zone
# variables for setting up UTM CRS for transforming raster map coordinates in tool
local class SR_COORDSYS utmCoordSys; # coordinate system
local class SR_COORDOPDEF projectDef; # projection parameters and method
local class SR_COORDOPMETHOD method;
local class SR_DATUM datum;
datum = rastCRS.Datum; # get datum from the raster
utmCoordSys.Assign("Projected2D_EN_m"); # assign projected coordinate system
method.Assign("1909"); # assign using numeric ID for Transverse Mercator projection
projectDef.Method = method; # assign method to projection
# assign projection parameters that are the same for all UTM zones
projectDef.SetParmValueNum("LatitudeOfNaturalOrigin", 0);
projectDef.SetParmValueNum("ScaleFactorAtNaturalOrigin", 0.9996);
projectDef.SetParmValueNum("FalseEasting", 500000);
# assign false northing based on whether north or south of equator
if ( center.y < 0) then
projectDef.SetParmValueNum("FalseNorthing", 10000);
else
projectDef.SetParmValueNum("FalseNorthing", 0);
# assign longitude of natural origin (central meridian of UTM zone) based on longitude
local numeric zoneNum, centMerid; # UTM zone and longitude of central meridian
zoneNum = ceil( (180 + center.x) / 6 );
centMerid = (zoneNum * 6) - 183;
projectDef.SetParmValueNum("LongitudeOfNaturalOrigin", centMerid);
# create defined UTM coordinate reference system
utmCRS.Create(utmCoordSys, datum, projectDef);
# setup coordinate transformation from raster's geographic CRS to the defined UTM CRS.
transGeogUTM.InputCoordRefSys = rastCRS;
transGeogUTM.OutputCoordRefSys = utmCRS;
}
}
}
##################################################################################
#### Checks the first layer to see if it is valid raster
func checkLayer( )
{
local numeric valid = false;
local class GRE_LAYER layer = firstGroup.FirstLayer;
if (layer.TypeID == "Surface") then
layer = layer.NextLayer;
# If layer is a raster, get the object from the layer and check its datatype.
if (layer.TypeID != "")
{
if (layer.TypeID == "Raster")
{
DispGetRasterFromLayer(RAST, layer);
rasterLayer = layer;
valid = true;
}
}
return valid;
}
##################################################################################
#### Creates the vector objects to store the resultant points and outcrop trace lines
proc createDestVectors( )
{
local string flags$ = "Polygonal,3DVector";
GetOutputVector(StrikeDipVector, flags$, "", Group.Extents);
createVectorGeoreference();
}
##################################################################################
#### Creates the vector georeference from the raster if necessary
func createVectorGeoreference( )
{
# get the last used georeference object (returns 0 if none)
SDgeoref = GetLastUsedGeorefObject(StrikeDipVector);
if (!SDgeoref)
{
CreateImpliedGeoref(StrikeDipVector, rastCRS);
SDgeoref = GetLastUsedGeorefObject(StrikeDipVector);
}
}
##################################################################################
#### This function is used to check if the vector is already in a layer in the View
func vectorLayerExists( string name ) {
local class VECTOR V;
# Set the active layer to the top layer in the first group
firstGroup.SetActiveLayer(firstGroup.LastLayer);
# Cycle through all the layers in the group
while (firstGroup.ActiveLayer != 0)
{
if (firstGroup.ActiveLayer.TypeID == "Vector")
{
DispGetVectorFromLayer(V, firstGroup.ActiveLayer);
# If the vector layer has the same name, return true
if (V.$Info.Name == name)
{
CloseVector(V);
return true;
}
CloseVector(V);
}
# If there are no more layers to check, return false
if (firstGroup.ActiveLayer.PrevLayer == 0) then
return false;
# Set the active layer to the next one down
firstGroup.SetActiveLayer(firstGroup.ActiveLayer.PrevLayer);
}
return false;
}
##################################################################################
#### Add the vector to the display group if it is not already there
proc addVectorsToDisplay( ) {
# Check if the StrikeDipVector layer does not already exist
if(!vectorLayerExists(StrikeDipVector.$Info.Name))
{
# Add the vector to the View
SDvectorLayer = GroupQuickAddVectorVar(firstGroup, StrikeDipVector);
SDvectorLayer.IgnoreExtents = 1;
}
else
{
SDvectorLayer = firstGroup.ActiveLayer;
CloseVector(StrikeDipVector);
DispGetVectorFromLayer(StrikeDipVector, SDvectorLayer);
SDvectorLayer.IgnoreExtents = 1;
}
# Set up how the layers display points, lines and polygons
SDpoints = SDvectorLayer.Point;
# Use the modified bedding.qry CartoScript developed by MicroImages to
# be used by this ToolScript if it exists in the same directory
SDpoints.Select.Mode = "All";
SDvectorLayer.Point.StyleMode = "ByScript";
SDvectorLayer.Point.Script = reconSDqry$;
SDvectorLayer.SaveDispParmSubObject();
}
###########################################################
#### Convert line tool vertices from screen to map coordinates
func class POINT3D setPtMap(class POINT3D pt3d)
{
local class POINT2D tmp;
tmp.x = pt3d.x;
tmp.y = pt3d.y;
# convert from screen to view coords
tmp = TransPoint2D(tmp, ViewGetTransViewToScreen(View, 1));
# convert from view to map coords
tmp = TransPoint2D(tmp, ViewGetTransMapToView(View, rasterLayer.MapRegion.CoordRefSys, 1));
# return a 3D point with map coordinates
local class POINT3D retPnt;
retPnt.x = tmp.x;
retPnt.y = tmp.y;
return retPnt;
}
##################################################################################
#### Compute the center point of the line tool
func class POINT3D computeCenterPoint(class POINT3D pt1, class POINT3D pt2)
{
local class POINT3D ctr;
ctr.x = (pt1.x + pt2.x) / 2;
ctr.y = (pt1.y + pt2.y) / 2;
return ctr;
}
##################################################################################
#### Convert geographic coordinates to planar coordinates in the designated UTM CRS
func class POINT2D convertGeogToUTM(class POINT2D geogPt)
{
local class POINT2D mapCoords; # 2D map coordinates
local class POINT2D utmPt; # 2D point to return
mapCoords.x = geogPt.x; # read geographic coordinates from 3D point to 2D point
mapCoords.y = geogPt.y;
mapCoords = TransPoint2D(mapCoords, transGeogUTM); # convert 2D point to UTM
utmPt.x = mapCoords.x; # assign coordinate values to 3D point to return
utmPt.y = mapCoords.y;
return utmPt;
}
##################################################################################
#### Convert planar coordinates in the designated UTM CRS back to geographic
func class POINT3D convertUTMtoGeog(class POINT3D utmPt) {
local class POINT2D mapCoords; # 2D map coordinates
local class POINT3D geogPt; # 3D point to return
mapCoords.x = utmPt.x;
mapCoords.y = utmPt.y;
mapCoords = TransPoint2D(mapCoords, transGeogUTM, 1); # inverse transformation
geogPt.x = mapCoords.x;
geogPt.y = mapCoords.y;
return geogPt;
}
##################################################################################
#### Find angle between grid north and true north for station location (center point)
func findAngleToNorth (class POINT3D ctr)
{
local class POINT2D mapCoords;
local class SR_COORDREFSYS ptCRS;
if (transGeogCoords == 1) {
ctr = convertGeogToUTM(ctrPt);
ptCRS = utmCRS;
}
else {
ptCRS = rastCRS;
}
return ptCRS.ComputeAngleToNorth(ctr);
}
##################################################################################
#### Add the point to the StrikeDipVector and return its element number
func addPointToVector(class POINT3D pt)
{
local numeric x = pt.x;
local numeric y = pt.y;
VectorAddPoint(StrikeDipVector, x, y);
VectorValidate(StrikeDipVector);
return FindClosestPoint(StrikeDipVector, x, y, SDgeoref);
}
##################################################################################
#### Add a record to the StrikeDipVector point database with appropriate values
proc addRecordToDatabase( numeric pointElemNumAdded )
{
local class POINT3D lStart, lEnd;
# Get the current end points of the line tool to save in the record
lStart = setPtMap(tool.start);
lEnd = setPtMap(tool.end);
# If editing, use the same station number
if (Current_Mode == "EDIT")
{
station = deletedStation;
}
# If adding a new one, set as the highest station incremented by 1
else
{
station = 0;
local numeric tempVal;
local numeric numRecords = NumRecords(SDtable);
local numeric i;
for i = 1 to numRecords
{
tempVal = TableReadFieldNum(SDtable, "Station", i);
if (tempVal > station)
{
station = tempVal;
}
}
station = station + 1;
}
# Write the record for the Strike Dip point and attach it
records[1] = TableWriteRecord(SDtable, 0, station, strikeAng, dipCategory$, dipDir,
overturned, lStart.x, lStart.y, lEnd.x, lEnd.y);
TableWriteAttachment(SDtable, pointElemNumAdded, records, 1, "point");
# close the database and remove the strike/dip vector
CloseDatabase(SDdb);
GroupRemoveLayer(firstGroup, SDvectorLayer);
addVectorsToDisplay();
initializeBeddingDatabaseTable();
}
##################################################################################
#### This function deletes the point and database record that
#### are related to the station that is being deleted.
proc deleteStation( )
{
local numeric numToDelete = 0;
local numeric i;
local array numeric tempRecords[10];
local numeric tempStation;
local numeric numRecords;
# Turn off the highlighted point
SDpoints.HighlightSingle(selectedElementNum, "Toggle");
# Get the station number from the selected point
deletedStation = StrikeDipVector.point[selectedElementNum].Bedding.Station;
# Scan through and delete the Strike and Dip station
numPoints = NumVectorPoints(StrikeDipVector);
local array numeric pointsToDelete[numPoints];
local numeric pointToDelete;
for i = 1 to numPoints
{
tempStation = StrikeDipVector.point[i].Bedding.Station;
if (tempStation == deletedStation)
{
# Unnattach the records if the point is being marked to delete
numRecords = TableReadAttachment(SDtable, i, tempRecords, "point");
TableRemoveAttachment(SDtable, i, tempRecords, numRecords, "point");
# Save point number to delete
numToDelete = numToDelete + 1;
pointsToDelete[numToDelete] = i;
}
}
# Delete all the marked points
if (numToDelete > 0)
{
VectorDeletePoints(StrikeDipVector, pointsToDelete, numToDelete);
}
# Remove all the records that are no longer attached
TableRemoveUnattachedRecords(SDtable);
VectorValidate(StrikeDipVector);
}
##################################################################################
#### Create the vector point database tables for the StrikeDipVector
proc initializeBeddingDatabaseTable( )
{
local string name$ = "Bedding";
local string desc$ = "Strike and dip bedding";
SDdb = OpenVectorPointDatabase(StrikeDipVector);
# If the table doesn't exist it needs to be created
if( !TableExists(SDdb, name$) )
{
SDtable = TableCreate(SDdb, name$, desc$);
SDtable.OneRecordPerElement = 1;
# Create the fields
TableAddFieldInteger(SDtable, "Station", 8);
TableAddFieldInteger(SDtable, "StrikeAngle", 11);
TableAddFieldString(SDtable, "DipCategory", 11);
TableAddFieldInteger(SDtable, "DipDirection", 12);
TableAddFieldInteger(SDtable, "Overturned", 10);
TableAddFieldFloat(SDtable, "ToolPos1_x", 12, 4);
TableAddFieldFloat(SDtable, "ToolPos1_y", 12, 4);
TableAddFieldFloat(SDtable, "ToolPos2_x", 12, 4);
TableAddFieldFloat(SDtable, "ToolPos2_y", 12, 4);
}
# Else the table does exist, get the info for it
else
{
SDtable = DatabaseGetTableInfo(SDdb, name$);
}
SDstationfield = FieldGetInfoByName(SDtable, "Station");
}
#################################################################################
#### Callback for when line tool position is set
proc OnLineSet()
{
promptString.SetLabel("Right-click to set line position.");
}
##################################################################################
#### Callback for right click with LINETOOL.
proc cbToolApply()
{
local class POINT3D lStart, lEnd;
local numeric distance, azimuth, elevation;
local numeric northAng;
promptString.SetLabel("Computing Data...");
lStart = setPtMap(tool.start);
lEnd = setPtMap(tool.end);
# check if tool start and end points are the same for non-horizontal dip
if ( (lStart.x == lEnd.x && lStart.y == lEnd.y) && !togHORIZONTAL.GetValue() )
promptString.SetLabel("Start/end points coincide. Draw line.");
else
{
ctrPt = computeCenterPoint(lStart, lEnd);
if (togHORIZONTAL.GetValue() ) # dip category set to HORIZONTAL
{
strikeAng = -1; # strike and dip direction are undefined, so set to -1
dipDir = -1;
strikeFld.SetValueNum(-1);
dipDirFld.SetValueNum(-1);
}
if (!togHORIZONTAL.GetValue() ) # dip category set to GENTLE, MODERATE, STEEP, or VERTICAL
{
# find azimuth of line
Displacement3Dd(lStart.x, lStart.y, lStart.z, lEnd.x, lEnd.y, lEnd.z, distance, azimuth, elevation);
northAng = findAngleToNorth(ctrPt);
strikeAng = round(azimuth + northAng);
dipDir = strikeAng + 90;
if (dipDir > 360) then
dipDir = dipDir - 360;
if (Current_Mode == "ADD" or Current_Mode == "EDIT")
togOVERTURNED.SetValue(0, 0); # set toggle to OFF without calling the on change callback
strikeFld.SetValueNum(strikeAng);
dipDirFld.SetValueNum(round(dipDir));
}
togOVERTURNED.SetEnabled(1);
# Manage the controls in the display
idMODE.SetEnabled(0);
btnCLOSE.SetEnabled(0);
btnACCEPT.SetEnabled(1);
btnCANCEL.SetEnabled(1);
btnREVERSE.SetEnabled(1);
if (Current_Mode == "ADD")
{
promptString.SetLabel("Accept this New point?");
}
else if (Current_Mode == "EDIT")
{
promptString.SetLabel("Accept this Edited point?");
}
}
} # end cbToolApply
##################################################################################
#### Manages the control dialog when the active mode has been changed
proc OnModeChange( ) {
# Get the current Mode
Current_Mode = idMODE.GetValueStr();
# Set controls to default values
strikeFld.SetValueNum(0);
dipDirFld.SetValueNum(0);
togOVERTURNED.SetEnabled(1);
togOVERTURNED.SetValue(0,0);
togOVERTURNED.SetEnabled(0);
btnACCEPT.SetEnabled(0);
btnCANCEL.SetEnabled(0);
btnDELETE.SetEnabled(0);
# Based on Mode, set the controls and tool to appropriate settings
if ( Current_Mode == "VIEW") {
promptString.SetLabel("Select Point to Toggle ON");
tool.managed = 0;
ScriptGadget.Managed = 1;
} else if ( Current_Mode == "ADD" ) {
promptString.SetLabel("Draw Line in Strike Direction");
tool.managed = 1;
} else if ( Current_Mode == "EDIT" ) {
promptString.SetLabel("Select Point to Edit");
tool.managed = 0;
ScriptGadget.Managed = 1;
} else if ( Current_Mode == "DELETE" ) {
promptString.SetLabel("Select Point to Delete");
tool.managed = 0;
ScriptGadget.Managed = 1;
}
}
#################################################################################
#### Called when the Gentle dip category toggle button is pressed
proc OnGentlePressed()
{
if ( togGENTLE.GetValue() )
{
dipCategory$ = "GENTLE";
togMODERATE.SetValue(0, 0);
togSTEEP.SetValue(0, 0);
togHORIZONTAL.SetValue(0, 0);
togVERTICAL.SetValue(0, 0);
}
}
#################################################################################
#### Called when the Moderate dip category toggle button is pressed
proc OnModeratePressed()
{
if( togMODERATE.GetValue() )
{
dipCategory$ = "MODERATE";
togGENTLE.SetValue(0, 0);
togSTEEP.SetValue(0, 0);
togHORIZONTAL.SetValue(0, 0);
togVERTICAL.SetValue(0, 0);
}
}
#################################################################################
#### Called when the Steep dip category toggle button is pressed
proc OnSteepPressed()
{
if ( togSTEEP.GetValue() )
{
dipCategory$ = "STEEP";
togGENTLE.SetValue(0, 0);
togMODERATE.SetValue(0, 0);
togHORIZONTAL.SetValue(0, 0);
togVERTICAL.SetValue(0, 0);
}
}
#################################################################################
#### Called when the Horizontal dip category toggle button is pressed
proc OnHorizontalPressed()
{
if ( togHORIZONTAL.GetValue() )
{
dipCategory$ = "HORIZONTAL";
togGENTLE.SetValue(0, 0);
togMODERATE.SetValue(0, 0);
togSTEEP.SetValue(0, 0);
togVERTICAL.SetValue(0, 0);
}
}
#################################################################################
#### Called when the Vertical dip category toggle button is pressed
proc OnVerticalPressed()
{
if ( togVERTICAL.GetValue() )
{
dipCategory$ = "VERTICAL";
togGENTLE.SetValue(0, 0);
togMODERATE.SetValue(0, 0);
togSTEEP.SetValue(0, 0);
togHORIZONTAL.SetValue(0, 0);
}
}
#################################################################################
#### callback for Reverse Strike Line button on dialog
proc OnReverseStrikeLine(class LINETOOL tool)
{
local class POINT3D origStart, origEnd;
origStart = tool.start;
origEnd = tool.end;
tool.start = origEnd;
tool.end = origStart;
cbToolApply();
}
##################################################################################
#### Called when the user clicks on the "Set as Overturned" togglebutton. It
#### adjusts the value of the Strike angle by 180 degrees if it is set as overturned
proc OnOverturnedChanged( )
{
# If the Strike Angle is not 0
if (strikeFld.GetValueNum() != 0)
{
# If the angle is less then 180 degrees
if (strikeAng < 180) then
strikeAng = strikeAng + 180;
# If the angle is greater than 180 degrees
else if (strikeAng > 180) then
strikeAng = strikeAng - 180;
strikeFld.SetValueNum(strikeAng);
}
}
##################################################################################
#### Called when the user clicks on the Accept button in the dialog. Actions are
#### based on the current Mode of the ToolScript
proc OnAccept( )
{
# If in ADD Mode, add the computed Strike and Dip data to the Destination Vectors
if (Current_Mode == "ADD")
{
promptString.SetLabel("Saving Data...");
overturned = togOVERTURNED.GetValue();
if (overturned) then togOVERTURNED.SetValue(0, 0);
togOVERTURNED.SetEnabled(0);
btnREVERSE.SetEnabled(0);
btnACCEPT.SetEnabled(0);
btnCANCEL.SetEnabled(0);
addRecordToDatabase( addPointToVector(ctrPt) );
waitingForAddConfirmation = 0;
# Reset the line tool
tool.HasPosition = 0;
# Update the display
ViewRedrawLayer(View, SDvectorLayer);
selectedElementNum = 0;
idMODE.SetEnabled(1);
btnCLOSE.SetEnabled(1);
strikeFld.SetValueNum(0);
dipDirFld.SetValueNum(0);
promptString.SetLabel("Draw Line in Strike Direction");
}
# If in EDIT Mode, reload the data or save the new edited data
else if (Current_Mode == "EDIT")
{
# Check if the point has already been selected and in modifying mode
if ( currentlyEditing )
{
promptString.SetLabel("Editing Data...");
overturned = togOVERTURNED.GetValue();
if (overturned) then togOVERTURNED.SetValue(0, 0);
togOVERTURNED.SetEnabled(0);
btnREVERSE.SetEnabled(0);
btnACCEPT.SetEnabled(0);
btnCANCEL.SetEnabled(0);
# Delete the old station information and add the new station information
deleteStation();
addRecordToDatabase( addPointToVector(ctrPt) );
waitingForAddConfirmation = 0;
# Update the display
ViewRedrawLayer(View, SDvectorLayer);
# Switch to the default tool for left-click
tool.Managed = 0;
ScriptGadget.Managed = 1;
currentlyEditing = 0;
selectedElementNum = 0;
# clear the strike and dip direction fields
strikeFld.SetValueNum(0);
dipDirFld.SetValueNum(0);
togOVERTURNED.SetValue(0, 0);
idMODE.SetEnabled(1);
btnCLOSE.SetEnabled(1);
promptString.SetLabel("Select point to Edit");
}
# Else the point needs to be loaded and allowed to be modified
else
{
promptString.SetLabel("Loading Data...");
btnACCEPT.SetEnabled(0);
btnCANCEL.SetEnabled(0);
togOVERTURNED.SetEnabled(1);
btnREVERSE.SetEnabled(1);
local class POINT2D p1, p2, p3;
p1.x = StrikeDipVector.point[selectedElementNum].Bedding.ToolPos1_x;
p1.y = StrikeDipVector.point[selectedElementNum].Bedding.ToolPos1_y;
p2.x = StrikeDipVector.point[selectedElementNum].Bedding.ToolPos2_x;
p2.y = StrikeDipVector.point[selectedElementNum].Bedding.ToolPos2_y;
# Map them to the screen coordinates
local class TRANS2D_MAPGEN trans; # transform from map to view
trans = View.GetTransMapToView(rasterLayer.MapRegion.CoordRefSys, 0);
p1 = trans.ConvertPoint2DFwd(p1);
p2 = trans.ConvertPoint2DFwd(p2);
trans = View.GetTransViewToScreen(0);
p1 = trans.ConvertPoint2DFwd(p1);
p2 = trans.ConvertPoint2DFwd(p2);
# Reset the line tool with the 2 points
tool.start = p1;
tool.end = p2;
# Set the line tool for editing
currentlyEditing = 1;
tool.Managed = 1;
promptString.SetLabel("Modify the line");
}
}
} # end of OnAccept();
##################################################################################
#### Called when the user clicks on the Cancel button in the dialog. Actions are
#### based on the current Mode of the ToolScript
proc OnCancel( )
{
strikeFld.SetValueNum(0);
dipDirFld.SetValueNum(0);
togOVERTURNED.SetValue(0, 0);
# If in VIEW mode, unselect the point and reset the control dialog
if (Current_Mode == "VIEW")
{
btnACCEPT.SetEnabled(0);
btnCANCEL.SetEnabled(0);
SDpoints.HighlightSingle(selectedElementNum, "Toggle");
idMODE.SetEnabled(1);
btnCLOSE.SetEnabled(1);
promptString.SetLabel("Select point to Toggle ON");
}
# If in ADD mode, reset the dialog
else if (Current_Mode == "ADD")
{
togOVERTURNED.SetEnabled(0);
btnREVERSE.SetEnabled(0);
btnACCEPT.SetEnabled(0);
btnCANCEL.SetEnabled(0);
promptString.SetLabel("Clearing Data");
# If canceling a computed point, refresh the display
if (waitingForAddConfirmation) {
waitingForAddConfirmation = 0;
ViewRedrawLayer(View, SDvectorLayer);
}
idMODE.SetEnabled(1);
btnCLOSE.SetEnabled(1);
promptString.SetLabel("Draw Line in Strike Direction");
}
# If in EDIT mode, cancel out of selecting a point, or remove the temporary data
else if (Current_Mode == "EDIT")
{
if (togOVERTURNED.GetValue() ) then togOVERTURNED.SetValueNum(0);
btnREVERSE.SetEnabled(0);
btnACCEPT.SetEnabled(0);
btnCANCEL.SetEnabled(0);
SDpoints.HighlightSingle(selectedElementNum, "Toggle");
tool.Managed = 0;
currentlyEditing = 0;
waitingForAddConfirmation = 0;
idMODE.SetEnabled(1);
btnCLOSE.SetEnabled(1);
promptString.SetLabel("Select point to Edit");
}
# If in DELETE mode, deselect the point
else if (Current_Mode == "DELETE")
{
if (togOVERTURNED.GetValue() ) then togOVERTURNED.SetValueNum(0);
btnDELETE.SetEnabled(0);
btnCANCEL.SetEnabled(0);
SDpoints.HighlightSingle(selectedElementNum, "Toggle");
idMODE.SetEnabled(1);
btnCLOSE.SetEnabled(1);
promptString.SetLabel("Select point to Delete");
}
# Reset the selected element to nothing
selectedElementNum = 0;
} # end OnCancel
##################################################################################
#### Called when the user clicks on the Cancel button in the dialog. Deletes the
#### selected point and all the records attached to that station.
proc OnDelete( )
{
promptString.SetLabel("Deleting Data...");
idMODE.SetEnabled(0);
btnCLOSE.SetEnabled(0);
btnCANCEL.SetEnabled(0);
btnDELETE.SetEnabled(0);
# Delete the station and attached records and update the display
deleteStation();
ViewRedrawLayer(View, SDvectorLayer);
strikeFld.SetValueNum(0);
dipDirFld.SetValueNum(0);
togOVERTURNED.SetValue(0, 0);
idMODE.SetEnabled(1);
btnCLOSE.SetEnabled(1);
promptString.SetLabel("Select point to Delete");
selectedElementNum = 0;
}
##################################################################################
#### Called when the user clicks on the Close button to close the dialog
proc OnClose( )
{
tool.Managed = 0;
setDefaultWhenClose = true;
View.SetDefaultTool();
}
###################################################################################
# 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.
###########################################################
#### Called the first time the tool is activated.
#### If the tool implements a dialog it should be created (but not displayed) here.
proc OnInitialize ()
{
local class XMLDOC dlgdoc; # class instance for XML document containing the dialog specification
local class XMLNODE node; # node in the XML document corresponding to the dialog
# Is this a layout? Set callbacks in case things change
if (Layout)
{
WidgetAddCallback(Layout.GroupSelectedCallback, cbGroup);
firstGroup = Layout.FirstGroup;
}
else
{
firstGroup = Group;
}
WidgetAddCallback(firstGroup.LayerSelectedCallback, cbLayer);
# Is the bottom layer a valid DEM raster?
if ( checkLayer() )
{
# Initialize tool
tool = ViewCreateLineGadget(View);
ToolAddCallback(tool.ActivateCallback, cbToolApply);
ToolAddCallback(tool.PositionClearedCallback, OnCancel);
ToolAddCallback(tool.PositionSetCallback, OnLineSet);
checkGeoref();
# Create the destination vectors and their tables
createDestVectors();
addVectorsToDisplay();
initializeBeddingDatabaseTable();
View.Redraw();
}
else
{
string message$ = "Active Layer: "+activeLayer.Name+" is not a valid DEM raster.";
PopupMessage(message$);
}
# XML script that specifies the context of the dialog
local class STRING xml$='<?xml version="1.0"?>
<root>
<dialog id="id_StrikeDipDialog" Title="Recon StrikeDip Control Panel" buttons="">
<groupbox Name=" Current Mode: " ExtraBorder="5">
<radiogroup id="id_MODE" orientation="Horizontal" Default="ADD" OnSelection="OnModeChange();">
<item Value="VIEW" Name="View"/>
<item Value="ADD" Name="Add"/>
<item Value="EDIT" Name="Edit"/>
<item Value="DELETE" Name="Delete"/>
</radiogroup>
</groupbox>
<pane Orientation="Horizontal" HorizResize="Fixed">
<label WidthGroup="1">Strike Azimuth </label>
<editnumber Width="6" id="id_STRIKEANGLE" Precision="0" ReadOnly="true" HorizResize="Fixed"/>
</pane>
<pane Orientation="Horizontal" HorizResize="Fixed">
<label WidthGroup="1">Dip Azimuth </label>
<editnumber Width="6" id="id_DIPDIRECTION" Precision="0" ReadOnly="true" HorizResize="Fixed"/>
</pane>
<groupbox Name=" Dip Category " ExtraBorder="3">
<pane Orientation="Horizontal">
<togglebutton id="id_GENTLE" name="Gentle" OnChanged="OnGentlePressed();"/>
<togglebutton id="id_MODERATE" name="Moderate" OnChanged="OnModeratePressed();"/>
<togglebutton id="id_STEEP" name="Steep" OnChanged="OnSteepPressed();"/>
</pane>
<pane Orientation="Horizontal">
<togglebutton id="id_HORIZONTAL" name="Horizontal" OnChanged="OnHorizontalPressed();"/>
<togglebutton id="id_VERTICAL" name="Vertical" OnChanged="OnVerticalPressed();"/>
</pane>
</groupbox>
<togglebutton id="id_OVERTURNED" name="Set as Overturned" OnChanged="OnOverturnedChanged();" Selected="false" Enabled="false"/>
<pushbutton id = "id_REVERSE" name="Reverse Strike Line" Enabled="false" OnPressed="OnReverseStrikeLine(tool);"/>
<groupbox Name=" Apply Action: " Orientation="Horizontal" ExtraBorder="5">
<pushbutton id="id_ACCEPT" Name="Accept" OnPressed="OnAccept();"/>
<pushbutton id="id_CANCEL" Name="Cancel" OnPressed="OnCancel();"/>
<pushbutton id="id_DELETE" Name="Delete" OnPressed="OnDelete();"/>
<pushbutton id="id_CLOSE" Name="Close" OnPressed="OnClose();"/>
</groupbox>
<label id="id_PROMPT">Select Prompt</label>
</dialog>
</root>';
# Parse the document to make sure it is valid
local numeric err = dlgdoc.Parse(xml$);
if ( err < 0 )
{
PopupError( err ); # Popup an error dialog. "Details" button shows syntax errors.
Exit();
}
# Find the document
node = dlgdoc.GetElementByID("id_StrikeDipDialog");
if ( node == 0 )
{
PopupMessage("Could not find dialog node in XML document");
Exit();
}
# Set the XML Node
err = dlg.SetXMLNode(node);
if ( err < 0 )
{
PopupMessage("Could not set the XML Node");
Exit();
}
# Create a modeless dialog and assign some commonly changed elements to controls
dlg.CreateModeless();
idMODE = dlg.GetCtrlByID("id_MODE");
strikeFld = dlg.GetCtrlByID("id_STRIKEANGLE");
dipDirFld = dlg.GetCtrlByID("id_DIPDIRECTION");
togGENTLE = dlg.GetCtrlByID("id_GENTLE");
togMODERATE = dlg.GetCtrlByID("id_MODERATE");
togSTEEP = dlg.GetCtrlByID("id_STEEP");
togHORIZONTAL = dlg.GetCtrlByID("id_HORIZONTAL");
togVERTICAL = dlg.GetCtrlByID("id_VERTICAL");
togOVERTURNED = dlg.GetCtrlByID("id_OVERTURNED");
btnREVERSE = dlg.GetCtrlByID("id_REVERSE");
btnACCEPT = dlg.GetCtrlByID("id_ACCEPT");
btnCANCEL = dlg.GetCtrlByID("id_CANCEL");
btnDELETE = dlg.GetCtrlByID("id_DELETE");
btnCLOSE = dlg.GetCtrlByID("id_CLOSE");
promptString = dlg.GetCtrlByID("id_PROMPT");
togGENTLE.SetValue(1, 0);
dipCategory$ = "GENTLE";
OnModeChange();
} # 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;
CloseDatabase(SDdb);
CloseVector(StrikeDipVector);
} # end of OnDestroy
#########################################################################
#### Called when tool is activated.
#### If the tool implements a dialog it should be "managed" (displayed) here.
proc OnActivate () {
dlg.Open();
OnModeChange();
setDefaultWhenClose = true;
} # 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 ()
{
dlg.Close(0);
setDefaultWhenClose = false;
} # end of OnDeactivate
##################################################################################
#### Called when the Left Button is pressed. This selects the closest point in the
#### StrikeDipVector and displays the information related to that point. Certain
#### modes use this selected point for their operations
proc OnLeftButtonPress ()
{
# Make sure the linetool is not currently active or this will conflict with it
if (!tool.Managed)
{
# Get the point on the screen that was clicked
local class POINT2D screenPoint, layerPoint;
screenPoint.x = PointerX;
screenPoint.y = PointerY;
# Get the layer coordinates from the screen point and find the closest point
local class TRANS2D_MAPGEN transparm = View.GetTransLayerToScreen(SDvectorLayer, 1);
layerPoint = transparm.ConvertPoint2DFwd(screenPoint);
selectedElementNum = FindClosestPoint(StrikeDipVector, layerPoint.x, layerPoint.y, SDgeoref, 300);
# If greater then 0, it has found the closest point
if (selectedElementNum > 0)
{
SDpoints.HighlightSingle(selectedElementNum, "Replace");
# Load the values for that point in the dialog
strikeFld.SetValueNum(StrikeDipVector.point[selectedElementNum].Bedding.StrikeAngle);
dipDirFld.SetValueNum(StrikeDipVector.point[selectedElementNum].Bedding.DipDirection);
dipCategory$ = StrikeDipVector.point[selectedElementNum].Bedding.DipCategory$
if (dipCategory$ == "HORIZONTAL") then
togHORIZONTAL.SetValue(1, 1);
else if (dipCategory$ == "GENTLE") then
togGENTLE.SetValue(1, 1);
else if (dipCategory$ == "MODERATE") then
togMODERATE.SetValue(1, 1);
else if (dipCategory$ == "STEEP") then
togSTEEP.SetValue(1, 1);
else if (dipCategory$ == "VERTICAL") then
togVERTICAL.SetValue(1, 1);
togOVERTURNED.SetEnabled(1);
togOVERTURNED.SetValue(StrikeDipVector.point[selectedElementNum].Bedding.Overturned, 0);
togOVERTURNED.SetEnabled(0);
# Update the control dialog settings based on the current mode
idMODE.SetEnabled(0);
btnCANCEL.SetEnabled(1);
btnCLOSE.SetEnabled(0);
if (Current_Mode == "EDIT")
{
promptString.SetLabel("CONFIRM: Edit this point?");
btnACCEPT.SetEnabled(1);
}
else if (Current_Mode == "DELETE")
{
promptString.SetLabel("CONFIRM: Delete this point?");
btnDELETE.SetEnabled(1);
}
}
}
} # end of OnLeftButtonPress
##################################################################################
#### Called when the Right Button is pressed. This is an alternative method of
#### clicking "Accept" in certain situations
proc OnRightButtonPress( )
{
if (!tool.Managed)
{
if (selectedElementNum > 0)
{
if (Current_Mode == "VIEW") then
OnAccept();
else if (Current_Mode == "DELETE") then
OnDelete();
}
}
} # end of OnRightButtonPress()