VPTOOL.SML

  Download

More scripts: Display Toolbar

Syntax Highlighing:

comments, key words, predefined symbols, class members & methods, functions & classes
            
# VPTOOL.sml
# View ToolScript "View Marks"
# Provides a dialog that allows recording of view positions (center of current
# View) in WGS84/Geographic coordinates along with current view scale.  When
# adding a View Mark, user is prompted to name it; default name includes the
# scale and lat/lon position.  The name of the View Mark is shown in a Listbox
# in the control dialog and can be selected there.
# Actions controlled by icon buttons in dialog:
	# New: clear all view marks from the list
	# Open: open saved view mark text file
	# Save: save current view mark list to a text file with .pos extension 
	# Add: add a view mark to the list
	# Remove: remove the selected view mark from the list
	# Zoom: pan/zoom the view to the selected view mark
	# Close: close the dialog and switch to default tool
### Revision 24 June 2008.
### Requires version 2007:73 or later of the TNT products
	#
	# 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
	#
### GLOBAL VARIABLES
class SR_COORDREFSYS crsLatLon;		# Latitude/longitude CRS for defining View Mark positions
class TRANS2D_MAPGEN transLatLonView;	# coordinate transformation between View coordinates and latitude/longitude
class FILE posfile;					# handle for text file containing position list
numeric ischanged;
numeric setDefaultWhenClose;
numeric numpos;					# number of positions in list
array numeric posX[1];			# arrays for x and y positions of view marks in list
array numeric posY[1];
array numeric posScale[1];		# array for current view scale value for each view mark
class STRINGLIST nameList;		# stringlist to hold View Mark names
# variables for dialog and its controls
class GUI_DLG dlgwin;
class GUI_CTRL_LISTBOX vpList;
###################################################################################
##############   USER-DEFINED FUNCTIONS AND PROCEDURES   ##########################
###################################################################################
# Save the list to a file.
func DoSave ()
	{
	if (numpos == 0) return false;
	local class STRING posfilename$ = GetOutputFileName("", "Select position file to save as:", "pos");
	posfile = fopen(posfilename$,"w", "UTF8");
	if (posfile == 0) return (false);
	# loop through stringlist and arrays to write View Mark list to text file
	local numeric i;
	for i = 1 to numpos {
		fprintf(posfile, "%s,%f,%f,%f\n", nameList[i - 1], posX[i], posY[i], posScale[i]);
		}
	fclose(posfile);
	ischanged = false;
	return (true);
	}
func AskSave ()
	{
	if (!ischanged || numpos == 0) return (true);
	local numeric answer;
	answer = PopupYesNoCancel("Save current point list?", 1);
	if (answer < 0) return (false);
	if (answer == 0) return (true);
	return ( DoSave() );
	}
# Zoom to selected position
proc DoZoom ()
	{
	local numeric selpos;
	if (numpos == 0) return;
	if (vpList.GetSelectedItemCount() > 0)
		{
		selpos = vpList.GetSelectedItemIndex();
		# Listbox indexing begins with 0, whereas array indexing begins with 1.
		# Increment recorded index of selected item to align it with the arrays
		++selpos;
		# get coordinate transformation from Latitude/Longitude to View coordinates
		transLatLonView = View.GetTransMapToView(crsLatLon)
		if (transLatLonView == 0)
			{
			PopupMessage("Cannot obtain map/view transformation.");
			return;
			}
		local class POINT2D zpoint;	# point to hold position coordinates
		# read lat/lon coordinates for the selected position from the arrays
		zpoint.x = posX[selpos];
		zpoint.y = posY[selpos];
		# convert point to curent View coordinates
		zpoint = transLatLonView.ConvertPoint2dFwd(zpoint);	# forward transformation, from Lat/Lon to View
		# check if point is within the extents of the data currently in the View
		if ( !View.Extents.ContainsPoint(zpoint) )
			{
			PopupMessage("Point is outside extents of objects being viewed.");
			return;
			}
		View.DisableRedraw = true;
		View.CurrentMapScale = posScale[selpos];
		View.Center = zpoint;
		View.DisableRedraw = false;
		View.Redraw();
		}
	}
# Add current viewpoint to list
proc DoAdd ()
	{
	# get coordinate transformation from Latitude/Longitude to View coordinates
	transLatLonView = View.GetTransMapToView(crsLatLon);
	if (transLatLonView == 0)
		{
		PopupMessage("Cannot obtain map/view transformation.");
		return;
		}
	local class POINT2D cpoint;	# point to record View center coordinates
	cpoint = transLatLonView.ConvertPoint2DInv(View.Center);	# inverse transformation, from View to Lat/Lon
	++numpos;			# increment list counter
	# resize arrays and add coordinates and scale for current View Mark
	ResizeArrayPreserve(posX, numpos);
	ResizeArrayPreserve(posY, numpos);
	ResizeArrayPreserve(posScale, numpos);
	posX[numpos] = cpoint.x;
	posY[numpos] = cpoint.y;
	posScale[numpos] = View.CurrentMapScale;
	local string namestr$ = sprintf("%d: %.0f %f %f", numpos, posScale[numpos], posX[numpos], posY[numpos]);
	namestr$ = PopupString("Enter view position name:",namestr$);
	local numeric i;
	local numeric foundDup = 1;
	local numeric dup;
	while (foundDup == 1)
		{
		dup = 0;
		for i = 0 to nameList.GetNumItems() - 1
			{
			if (nameList[i] == namestr$) then ++dup;
			}
		if (dup == 0) then foundDup = 0;
		else
			namestr$ = PopupString("Name already used.\nEnter view position name:", namestr$);
		}
	nameList.AddToEnd(namestr$);			# add name of View Mark to stringlist
	vpList.AddItem(namestr$, namestr$);	# add name to Listbox control in dialog
	ischanged = true;
	}
# Remove selected item from list
proc DoRemove ()
	{
	local numeric selpos, i;
	if (numpos == 0) return;
	if (vpList.GetSelectedItemCount() > 0)
		{
		selpos = vpList.GetSelectedItemIndex();
		vpList.DeleteItemIndex(selpos);	# delete entry from listbox
		nameList.Remove(selpos);			# delete View Mark name from stringlist
		# Listbox & stringlist indexing begin with 0, whereas array indexing begins with 1.
		# Increment recorded index of removed item to align it with the arrays
		++selpos;
		# Copy next highest value in each array to current index, beginning with
		# index corresponding to the deleted item.
		for i = selpos to numpos - 1
			{
			posX[i] = posX[i + 1];
			posY[i] = posY[i + 1];
	 		posScale[i] = posScale[i + 1];
			}
		--numpos;		# decrement position counter
		ischanged = true;
		}
	}
# Clear the list
proc DoNew ()
	{
	if ( !AskSave() ) return;
	numpos = 0;
	vpList.DeleteAllItems();
	ischanged = false;
	}
# Open file containing list.
proc DoOpen ()
	{
	if ( !AskSave() ) return;
	posfile = GetInputTextFile("","Select positions file to open:","pos", "UTF8");
	if (posfile == 0) return;
	numpos = 0;
	vpList.DeleteAllItems();	# clear the current list in View Mark listbox
	nameList.Clear();				# clear the View Mark name stringlist
	ischanged = false;
	# read the values from the text file
	local class STRING filestr$, name$;
	while (!feof(posfile)) {		# while not at end of text file
		filestr$ = fgetline$(posfile);		# get next line of text
		if (NumberTokens(filestr$,",") < 4) continue;		# jump to next iteration if less than 4 tokens in text line
		++numpos;
		ResizeArrayPreserve(posX, numpos);		# resize the coordinate and scale arrays
		ResizeArrayPreserve(posY, numpos);
		ResizeArrayPreserve(posScale, numpos);
		name$ = GetToken(filestr$,",",1);
		nameList.AddToEnd(name$);		# add View Mark name to stringlist
		vpList.AddItem(name$);			# add View Mark name to listbox control
		posX[numpos] = StrToNum(GetToken(filestr$,",",2));		# add values to numeric arrays
		posY[numpos] = StrToNum(GetToken(filestr$,",",3));
		posScale[numpos] = StrToNum(GetToken(filestr$,",",4));
		}
	fclose(posfile);
	}
# Close the window, switching to default tool
proc DoClose ()
	{
	if (setDefaultWhenClose)
		{
		setDefaultWhenClose = false;
		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 string xml$;
	local numeric err;
	# set up geographic coordinate reference system for recording View Mark positions
	crsLatLon.Assign("Geographic2D_WGS84_Deg");
	# string with dialog specification
	xml$ = '<?xml version="1.0" encoding="UTF-8"?>
	<!DOCTYPE root SYSTEM "smlforms.dtd">
	<root>
		<dialog id="vptool" Title="Viewpoint List" Buttons="">
			<pane Orientation="vertical">
				<pane Orientation="horizontal" ChildSpacing="8" HorizontalResize="Expand">
					<pane Orientation="horizontal" ChildSpacing="2">
						<pushbutton id="newBtn" Icon="FILE_NEW" ToolTip="New" OnPressed="DoNew()"/>
						<pushbutton id="openBtn" Icon="FILE_OPEN" ToolTip="Open.." OnPressed="DoOpen()"/>
						<pushbutton id="saveBtn" Icon="FILE_SAVE" ToolTip="Save..." OnPressed="DoSave()"/>
					</pane>
					<pane Orientation="horizontal" ChildSpacing="2">
						<pushbutton id="addBtn" Icon="CONTROL_ADD_CYAN" ToolTip="Add" OnPressed="DoAdd()"/>
						<pushbutton id="subtractBtn" Icon="CONTROL_SUBTRACT_CYAN" ToolTip="Remove" OnPressed="DoRemove()"/>
					</pane>
					<pane Orientation="horizontal" ChildSpacing="2">
						<pushbutton id="zoomBtn" Icon="EDIT_APPLY_RED" ToolTip="Zoom" OnPressed="DoZoom()"/>
						<pushbutton id="closeBtn" Icon="EDIT_DELETE_RED" ToolTip="Close" OnPressed="DoClose()"/>
					</pane>
				</pane>
				<listbox id="vpList" Width="30" Height="5"/>
			</pane>
		</dialog>
	</root>';
	### parse XML string; returns an error code (number < 0 ) if there are syntax errors
	local class XMLDOC doc;
	err = doc.Parse(xml$);
	if (err < 0)
		{
		PopupError(err); # Popup an error dialog. "Details" button shows syntax errors.
		Exit();
		}
	### declare class instance for the dialog element in the XML structure
	### and get the dialog handle from the XML structure.
	### Pop up an error dialog and exit if the dialog ID can't be found in the XML.
	class XMLNODE dlgnode;
	dlgnode = doc.GetElementByID("vptool");
	if (dlgnode == 0)
		{
		PopupMessage("Could not find dialog node in XML document");
		Exit();
		}
	### set the XML structure in memory as the source for the dialog.
	dlgwin.SetXMLNode(dlgnode);
	err = dlgwin.CreateModeless();
	if (err < 0)
		{
		PopupError(err); # Popup an error dialog. "Details" button shows syntax errors.
		Exit();
		}
	# get handles for dialog controls
	vpList = dlgwin.GetCtrlByID("vpList");
	} # 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 () {
# } # end of OnDestroy
# Called when tool is activated.
# If the tool implements a dialog it should be "managed" (displayed) here.
proc OnActivate ()
	{
	dlgwin.Open();
	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 ()
	{
	dlgwin.Close(0);
	setDefaultWhenClose = false;
	}  # 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 'right' pointer/mouse button.
	# proc OnRightButtonPress () {
	# }  # end of OnRightButtonPress
	# 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