home products news downloads documentation support gallery online maps resellers search
TNTmips Downloads Menu

HOME

CONTACT US

CURRENT RELEASE
  TNT 2013

DEVELOPMENT VERSION
  TNT 2014

TNTmips Pro
PRIOR RELEASES
  TNT 2012

FREE SOFTWARE
  TNTmips Free
  TNTatlas
  TNTsdk

MORE DOWNLOADS
  HASP Key Driver
  Screen Recorder
  TNT Language Kits
  Sample Geodata
  TNT Scripts

DOCUMENTATION
  TNTmips Tutorials
  Tutorial Datasets
  Technical Guides
  Scripts
  Quick Guides

MORE INFO
  Download FAQs
  FTP
  Download Managers
  Find Reseller

SITE MAP


LineProfile.sml

See other examples of Tool and Macro scripts  ...


#
# This script is meant to be run as a Toolscript
#
# Current Assumptions:
# In the group there are two layers:
# Layer 1: DEM - not needed
# Layer 2: Overlaying vector lines (must be last layer)
#
# Purpose:
# The script creates a window displaying a plotted profile of the
# selected lines nearest line, using the vector DB values for elevation.
#
# Usage:
# Left click: toggle select/deselect line
# Right click: Accept current line and draw
#

# GUI global definitions
class GUI_DLG dlgwin;
class GUI_CANVAS canvas;
class GC gc;
class GUI_CTRL_TOGGLEBUTTON gridToggle;
class GUI_CTRL_EDIT_NUMBER gridIntervalX;
class GUI_CTRL_EDIT_NUMBER gridIntervalY;
class GUI_CTRL_TOGGLEBUTTON demToggle;
class GUI_CTRL_EDIT_NUMBER graphMinSetting;
class GUI_CTRL_EDIT_NUMBER graphMaxSetting;
class GUI_CTRL_TOGGLEBUTTON fillToggle;
#class GUI_CTRL_EDIT_NUMBER elemDisplay;
#class GUI_CTRL_EDIT_NUMBER lineDisplay;
#class GUI_CTRL_EDIT_NUMBER vertexDisplay;
class GUI_CTRL_EDIT_NUMBER mouseXDisplay;
class GUI_CTRL_EDIT_NUMBER mouseYDisplay;
class GUI_CTRL_EDIT_NUMBER slopeDisplay;
class GUI_CTRL_EDIT_NUMBER diameterDisplay;
class GUI_CTRL_EDIT_STRING materialDisplay;

# Group/layer/object global definitions
class GRE_GROUP activegroup;
class TRANSPARM mapTrans;
class GRE_LAYER_VECTOR vectorLayer;
class GRE_LAYER_RASTER rasterLayer;
class VECTOR lineVector;
class GEOREF vecGeoref;
class RASTER dem;
string vectorName$;
class DBTABLEINFO nodeTable;
class DBTABLEINFO lineTable;
numeric dbIsInit=0;

# Graphical display global definitions
class POLYLINE pipeBottomSave, pipeTopSave, pipeFaceSave; # used for highlighting
class STRINGLIST colors;
numeric drawable=0, demSet=0;
numeric graphMinZ, graphMaxZ, dataMinZ, dataMaxZ;
numeric setDefaultWhenClose = false;
numeric leftGraphOffset, bottomGraphOffset=20, rightGraphOffset=15, topGraphOffset=50; #5,15
numeric currentlyActive = -1;
numeric needsRedraw = 0;

# Utility global definitions
class POLYLINE demLine;
class STRINGLIST elemList;
class STRINGLIST orderedElemList;
class STRINGLIST reversedList;
array numeric endNodes[2];
numeric MAX_NUMBER = 9999999;

# 
func writePolyline(class FILE f, class POLYLINE polyline)
{
	local class POINT2D p2d;
	local numeric i;
	for (i=0; i

func assignColors()
{
	colors.AddToEnd("red");
	colors.AddToEnd("orange");
	colors.AddToEnd("yellow");
	colors.AddToEnd("green");
	colors.AddToEnd("blue");
	colors.AddToEnd("purple");
	colors.AddToEnd("violet");
}


func class COLOR getColor(numeric index)
{
	local class COLOR c;
	c.Name = colors.GetString(index%colors.GetNumItems()-1);
	return c;
}


# Determine if the dem will be used or not
func doUseDEM()
{
	return demToggle.GetValue();
}

# Get the line table by name - return 1 if successful, 0 if table is null
func initLineTable(string tablename)
{
	local class DATABASE lineDB = OpenVectorLineDatabase(lineVector);
	if (lineDB==0) return 0;
	lineTable = DatabaseGetTableInfo(lineDB, tablename);
	if (lineTable==0) return 0;
	return 1;
}

# Get the node table by name - return 1 if successful, 0 if table is null
func initNodeTable(string tablename)
{
	local class DATABASE nodeDB = OpenVectorNodeDatabase(lineVector);
	if (nodeDB==0) return 0;
	nodeTable = DatabaseGetTableInfo(nodeDB, tablename);
	if (nodeTable==0) return 0;
	return 1;
}

# Checks layer to see if it is valid.
func checkLayer()
{
	if (doUseDEM())
	{
		# Raster is assumed to be first layer
		rasterLayer = activegroup.FirstLayer;
		if (rasterLayer.Type!="Raster")
		{
			demSet = 0;
			PopupMessage("The first layer is not a raster, the DEM was not assigned properly and the script may not function properly.");
		}
		DispGetRasterFromLayer(dem, rasterLayer);
		demSet = 1;
	}

	# Vector is assumed to be last layer
	vectorLayer = activegroup.LastLayer;
	DispGetVectorFromLayer(lineVector, vectorLayer);
	vecGeoref = GetLastUsedGeorefObject(lineVector);

	mapTrans.InputProjection = vectorLayer.Projection;
	mapTrans.OutputProjection = rasterLayer.Projection;

	# initialize the database tables
	initLineTable("SEW_INFO");
	initNodeTable("MH_GIS");

	return 1;
}

# Callback for when the active layer changes.
proc cbLayer()
{
	checkLayer();
}

# Callback for when the active group changes.
proc cbGroup()
{
	activegroup = Layout.ActiveGroup;
	WidgetAddCallback(activegroup.LayerSelectedCallback, cbLayer);
	cbLayer();
}

# return the max of two numbers
func max(numeric n1, numeric n2)
{
	if (n1 > n2) return n1;
	return n2;
}

# Get the element from our list
func getElement(class STRINGLIST list, numeric index)
{
	return StrToNum(list.GetString(index));
}

# Get the index of the element in our list, return index if found, -1 otherwise
func indexOf(class STRINGLIST list, numeric value)
{
	local numeric i;
	for (i=0; i-1)
#	{
#		local class POINT2D point1 = line.GetVertex(vertexNum);
#		local class POINT2D point2 = line.GetVertex(vertexNum+1);
#
#		if (point1!=point2)
#		{
#			return 0;
#		}
#	}
#	return 1;
#}


# Compute the distance between two points
func computeDistance(class POINT2D p1, class POINT2D p2)
{
	return sqrt((p2.x-p1.x)^2 + (p2.y-p1.y)^2);
}

# Determine if the given lin, col is within the raster extents
func isPointInRaster(numeric lin, numeric col)
{
	if (lin<1 || col<1 || lin>NumLins(dem) || col>NumCols(dem)) return 0;
	return 1;
}

# Get the value of the first record attached to the node "nodeNum" as a string
func string readNodeTableRecordStr(numeric nodeNum, string field)
{
	local array numeric records[1];
	TableReadAttachment(nodeTable, nodeNum, records, "node");
	local string retVal = TableReadFieldStr(nodeTable, field, records[1]);
	return retVal;
}

# Get the value of the first record attached to the line "lineNum" as a string
func string readLineTableRecordStr(numeric lineNum, string field)
{
	local array numeric records[1];
	TableReadAttachment(lineTable, lineNum, records, "line");
	local string retVal = TableReadFieldStr(lineTable, field, records[1]);
	return retVal;
}

# Get the value of the first record attached to the line "lineNum"
func readLineTableRecord(numeric lineNum, string field)
{
	local array numeric records[1];
	TableReadAttachment(lineTable, lineNum, records, "line");
	local numeric retVal = TableReadFieldNum(lineTable, field, records[1]);
	if (IsNull(retVal)) return 0;
	return retVal;
}

# Get the value of the first record attached to the line "nodeNum"
func readNodeTableRecord(numeric nodeNum, string field)
{
	local array numeric records[1];
	TableReadAttachment(nodeTable, nodeNum, records, "node");
	local numeric retVal = TableReadFieldNum(nodeTable, field, records[1]);
	return retVal;
}

# Get the z value
func computeElevationFromDEM(class POINT2D p)
{
	p = mapTrans.ConvertPoint2DFwd(p);	# convert from vector map to raster map coords

	local class POINT2D obj = MapToObject(GetLastUsedGeorefObject(dem), p.x, p.y, dem);
	obj.x = obj.x + .5; # center of cell
	obj.y = obj.y + .5; # center of cell
	local numeric demValue;
	if(isPointInRaster(obj.y, obj.x)) demValue = dem[obj.y, obj.x];	# y for line, x for column
	else demValue = null;
	return demValue;
}

# Find the closest line element using the polyline and the two nodes (vertices)
func findClosestLineElement(class POLYLINE origLine, numeric vertex1, numeric vertex2)
{
	# get the line given the two end points - straight line assumed
	local class POINT2D point1 = origLine.GetVertex(vertex1);
	local class POINT2D point2 = origLine.GetVertex(vertex2);
	local class POINT2D midPt = point1;
	midPt = midPt + point2;
	midPt.x = midPt.x / 2;
	midPt.y = midPt.y / 2;
	local numeric elemNum = FindClosestLine(lineVector, midPt.x, midPt.y);
	return elemNum;
}

# Interpolate between two points adding extra vertices
func class POLYLINE constructSmoothSurface(class POLYLINE p, numeric linscale, numeric colscale, numeric samplingRate)
{
	local class POLYLINE tmpLine, retLine;
	local class POINT2D point1, point2, tmpPt;
	local numeric numIntervals = 3;

	local numeric i;
	for (i=1; i graphMaxZ);
#	return (value == NullValue(dem));
}

# Get the width from the appropriate drawing device
func getHeight()
{
	return canvas.GetHeight();
}

# Get the width from the appropriate drawing device
func getWidth()
{
	return canvas.GetWidth();
}

# Get the extents of the graph
# (x1, y1) == UL corner
# (x2, y2) == LR corner
func class RECT getGraphExtents()
{
	local class RECT rect;
	rect.x1 = leftGraphOffset;
	rect.x2 = getWidth() - rightGraphOffset;
	rect.y1 = topGraphOffset;
	rect.y2 = getHeight() - bottomGraphOffset;
	return rect;
}

# Set the affine transformation for distance/elevation -> Graph Coords
proc setTrans(class POLYLINE graphLine)
{
	# copy the point
#	local class POINT2D retpoint;
#	retpoint = point;
#
#	# get graph extents
#	local numeric minx, maxx, miny, maxy;
#	minx = leftGraphOffset;
#	miny = topGraphOffset;
#	maxx = getWidth() - rightGraphOffset;
#	maxy = getHeight() - bottomGraphOffset;
#
#	# Get the drawing scale
#	local numeric xscale = 0, yscale = 0;
#	xscale = (maxx - minx) / abs(graphLine.GetVertex(graphLine.GetNumPoints()-1).x - graphLine.GetVertex(0).x);
#	if (graphMaxZ != graphMinZ) yscale = (maxy - miny) / (graphMaxZ - graphMinZ);
#
#	# apply scales and offsets
#	retpoint.x = point.x * xscale + leftGraphOffset;
#	if (yscale!=0) retpoint.y = getHeight() - ((point.y-graphMinZ) * yscale + bottomGraphOffset);
#	else retpoint.y = getHeight() - bottomGraphOffset;

	# redefinition here clears the trans each time we draw (which is desirable)
	class TRANSAFFINE trans;
	trans.ApplyScale(1,1);
	trans.ApplyOffset(0,0);

	# get graph extents
	local numeric minx, maxx, miny, maxy;
	minx = leftGraphOffset;
	miny = topGraphOffset;
	maxx = getWidth() - rightGraphOffset;
	maxy = getHeight() - bottomGraphOffset;

	# Get the drawing scale
	local numeric xscale = 0, yscale = 0;
	xscale = (maxx - minx) / abs(graphLine.GetVertex(graphLine.GetNumPoints()-1).x - graphLine.GetVertex(0).x);
	if (graphMaxZ != graphMinZ) yscale = (maxy - miny) / (graphMaxZ - graphMinZ);

	# apply scales and offsets
	trans.ApplyScale(xscale, -yscale);
	trans.ApplyOffset(leftGraphOffset, getHeight() + graphMinZ*yscale - bottomGraphOffset);
}

# Create the GC here using the appropriate drawing device (gc is global)
proc createGC()
{
	gc = canvas.CreateGC();
}

# draw the graph background fill
proc drawBackground(class GC gc, class COLOR bgcolor)
{
	if (drawable)
	{
		# draw the background rectangle
		gc.SetColorRGB(bgcolor.red, bgcolor.green, bgcolor.blue, 100);
		gc.FillRect(0, 0, getWidth(), getHeight());
	}
}

# draw the axes for the graph - dataMinZ == MAX_NUMBER and dataMaxZ == -MAX_NUMBER are displayed as null
proc drawGraphAxes(class GC gc, numeric distance, string xAxisLabel, string yAxisLabel, numeric drawTwoPointLines, class COLOR axiscolor, numeric fontHeight, numeric axisLabelOffset)
{
	if (drawable)
	{
		# set the axis colors
		gc.SetColorRGB(axiscolor.red, axiscolor.green, axiscolor.blue, 100);

		# set the min and max display variables
		local string min$ = sprintf("%0.2f", graphMinZ);
		local string max$ = sprintf("%0.2f", graphMaxZ);
		if (graphMaxZ==-MAX_NUMBER) max$ = "null";
		if (graphMinZ==MAX_NUMBER) min$ = "null";

		# Draw text for coordinate and elevation axis labels
		gc.DrawTextSetFont("ARIAL");
		gc.DrawTextSetHeightPixels(fontHeight);

		# Draw graph axes
		if (graphMaxZ == graphMinZ) max$ = "";
		local array numeric graphx[3], graphy[3];
		graphx[1] = leftGraphOffset;
		graphy[1] = topGraphOffset;
		graphx[2] = leftGraphOffset;
		graphy[2] = getHeight() - bottomGraphOffset;
		graphx[3] = getWidth() - rightGraphOffset;
		graphy[3] = graphy[2];
		gc.DrawPolyLine(graphx, graphy, 3);

		# draw y axis labels
		gc.TextStyle.Smoothing = 1;
		gc.DrawTextSimple(max$, 0, graphy[1]+fontHeight/2);
		gc.DrawTextSimple(min$, 0, graphy[2]+fontHeight/2);
		gc.DrawTextSimple(yAxisLabel, graphx[1]-axisLabelOffset, (graphy[3]-graphy[1])/2+gc.TextGetWidth(yAxisLabel)*1.5, 90);

		# draw x axis labels
		gc.DrawTextSimple("0", graphx[1] - gc.TextGetWidth("0")/2, getHeight()-3);
		local string str$ = sprintf("%0.2f", distance);
		gc.DrawTextSimple(str$, getWidth() - gc.TextGetWidth(str$), getHeight()-3);
		gc.DrawTextSimple(xAxisLabel, (graphx[3]-graphx[1])/2-gc.TextGetWidth(xAxisLabel)/4, graphy[3]+fontHeight+axisLabelOffset);
	}
}

# Translate a point on the graphline to image device coordinates for drawing
func class POINT2D transPointToGraph(class POINT2D point, class POLYLINE graphLine)
{
	local class POINT2D retpoint;
	if (trans!=0) retpoint = trans.ConvertPoint2DFwd(point);

	# copy the point
#	local class POINT2D retpoint;
#	retpoint = point;
#
#	# get graph extents
#	local numeric minx, maxx, miny, maxy;
#	minx = leftGraphOffset;
#	miny = topGraphOffset;
#	maxx = getWidth() - rightGraphOffset;
#	maxy = getHeight() - bottomGraphOffset;
#
#	# Get the drawing scale
#	local numeric xscale = 0, yscale = 0;
#	xscale = (maxx - minx) / abs(graphLine.GetVertex(graphLine.GetNumPoints()-1).x - graphLine.GetVertex(0).x);
#	if (graphMaxZ != graphMinZ) yscale = (maxy - miny) / (graphMaxZ - graphMinZ);
#
#	# apply scales and offsets
#	retpoint.x = point.x * xscale + leftGraphOffset;
#	if (yscale!=0) retpoint.y = getHeight() - ((point.y-graphMinZ) * yscale + bottomGraphOffset);
#	else retpoint.y = getHeight() - bottomGraphOffset;

	return retpoint;
}

# Plot the vertex and any connecting lines in the graphLine
# (note: this method is a bit more clever as it doesn't translate a point more than once
# but is not being used currently - it does make drawPolyline a bit less clear however).
proc plotLine(class GC gc, class POLYLINE graphLine, numeric vertexNum)
{
	local class POINT2D linePoint, graphPoint;

	linePoint = graphLine.GetVertex(vertexNum);
	graphPoint = transPointToGraph(linePoint, graphLine);

	if (0)#!isConsecutive(graphLine, vertexNum))
	{
		# if not consecutive, finish drawing and move to next
		gc.DrawTo(graphPoint.x, graphPoint.y);
		linePoint = graphLine.GetVertex(vertexNum+1);
		graphPoint = transPointToGraph(linePoint, graphLine);
		gc.MoveTo(graphPoint.x, graphPoint.y);
	}
	else if (isNull(linePoint.y))
	{
		# if null skip point and move to next
		linePoint = graphLine.GetVertex(vertexNum+1);
		graphPoint = transPointToGraph(linePoint, graphLine);
		gc.MoveTo(graphPoint.x, graphPoint.y);
	}
	else
	{
		gc.DrawTo(graphPoint.x, graphPoint.y);
	}
}

# draw a two point line from the polyline p
proc drawLineSegment(class POLYLINE p, numeric vertex1, numeric vertex2, class COLOR color)
{
	local class POINT2D point1, point2;
	point1 = p.GetVertex(vertex1);
	point2 = p.GetVertex(vertex2);

	if (isNull(point1.y)||isNull(point2.y))
	{
		# if null skip point and move to next
		point2 = transPointToGraph(point2, p);
		gc.MoveTo(point2.x, point2.y);
	}
	else
	{
		point1 = transPointToGraph(point1, p);
		point2 = transPointToGraph(point2, p);
		gc.SetColorRGB(color.red, color.green, color.blue, 100);
		gc.MoveTo(point1.x, point1.y);
		gc.DrawTo(point2.x, point2.y);
	}
}


# Draw the graph with the given polyline (not used currently - use with plotLine)
proc drawPolyline2(class GC gc, class POLYLINE graphLine, class COLOR lineColor)
{
	if (drawable && graphLine.GetNumPoints()>0)
	{
		# Draw the profile
		gc.SetColorRGB(lineColor.red, lineColor.green, lineColor.blue, 100);
		local class POINT2D linePoint = graphLine.GetVertex(0);

		# Plot point zero
		local class POINT2D graphPoint = transPointToGraph(linePoint, graphLine);
		gc.DrawPoint(graphPoint.x, graphPoint.y);

		# Plot the rest of the points - connecting them as lines
		local numeric i;
		for (i=0; i0)
	{
		# Plot the polyline one segment at a time
		local numeric i;
		for (i=0; i=5)
	{
		local numeric i;
		for (i=0; i0)
	{
		gc.DrawTextSetFont(font);
		gc.DrawTextSetHeightPixels(pixelFontHeight);
		gc.DrawTextSetColors(textColor);

		# Draw all the manhole names at the manhole tops
		local numeric i;
		for (i=0; i0 && surface.GetNumPoints()>0)
	{
		# Draw the profile
		gc.SetColorRGB(lineColor.red, lineColor.green, lineColor.blue, 100);

		# Plot the rest of the points - connecting them as lines
		local numeric i;
		for (i=0; i1)
	{
		# set the grid color
		gc.SetColorRGB(color.red, color.green, color.blue, 100);

		local class POINT2D pt1, pt2;

		# draw vertical lines
		local numeric length = bottomLine.GetVertex(bottomLine.GetNumPoints()-1).x;
		local class POINT2D bottomPoint;
		local class POINT2D topPoint;
		bottomPoint.y = graphMinZ;
		topPoint.y = graphMaxZ;
		for (bottomPoint.x = topPoint.x = xspacing; bottomPoint.x<=length; topPoint.x = bottomPoint.x = bottomPoint.x + xspacing)
		{
			# get graph coordinates
			local class POINT2D graphBottomPoint = transPointToGraph(bottomPoint, bottomLine);
			local class POINT2D graphTopPoint = transPointToGraph(topPoint, bottomLine);

			# do the drawing
			gc.MoveTo(graphTopPoint.x, graphTopPoint.y);
			gc.DrawTo(graphBottomPoint.x, graphBottomPoint.y);
		}

		# draw horizontal lines
		bottomPoint.x = 0;
		topPoint.x = length;
		bottomPoint.y = topPoint.y = graphMinZ;
		for (bottomPoint.y = topPoint.y = ceil(graphMinZ); bottomPoint.y<=graphMaxZ; topPoint.y = bottomPoint.y = bottomPoint.y + yspacing)
		{
			# get graph coordinates
			local class POINT2D graphBottomPoint = transPointToGraph(bottomPoint, bottomLine);
			local class POINT2D graphTopPoint = transPointToGraph(topPoint, bottomLine);

			# do the drawing
			gc.MoveTo(graphTopPoint.x, graphTopPoint.y);
			gc.DrawTo(graphBottomPoint.x, graphBottomPoint.y);
		}
	}
}

# Convert the polyline from obj to map coordinates
func class POLYLINE convertObjectToMap(class POLYLINE line)
{
	local class POLYLINE ret;
	local class POINT2D obj, map;

	local numeric i;

	# loop through the lines and convert from object to map coords
	for (i=0; i2) polyline.Straighten();
	}
	# if this is the first line just append and return
	if (line.GetNumPoints()==0)
	{
		line.Append(polyline);
		if (orderElements) orderedElemList.AddToFront(NumToStr(newLine));
		return;
	}

	# Check to see if we need to reverse the polyline
	local numeric reverse = needToReverseLine(line, polyline, 0, line.GetNumPoints()-1);
	if (reverse==1)
	{
		polyline.Reverse();
		reversedList.SetString("1", indexOf(elemList ,newLine));
	}

	# now simply append the line
	if (doAppend(line, polyline)==1)
	{
		# append to end
		line.Append(polyline);
		if (orderElements) orderedElemList.AddToEnd(NumToStr(newLine));
	}
	else if (doAppend(line, polyline)==2)
	{
		# append to front
		polyline.Append(line);
		line.Clear();
		line.Append(polyline);
		if (orderElements) orderedElemList.AddToFront(NumToStr(newLine));
	}
	else 
	{
		# can occur if loop is made, should clear selection
		PopupMessage("Cannot append disjoint line");
	}
}

# set the global graph offsets
proc setGraphOffsets(numeric fontHeight, numeric axisLabelOffset)
{
	# set the min and max display variables
	local string min$ = sprintf("%0.2f", graphMinZ);
	local string max$ = sprintf("%0.2f", graphMaxZ);
	if (graphMaxZ==-MAX_NUMBER) max$ = "null";
	if (graphMinZ==MAX_NUMBER) min$ = "null";

	if (graphMaxZ == graphMinZ) max$ = "";
	local numeric size = max(gc.TextGetWidth(max$), gc.TextGetWidth(min$));

	size = max(size, fontHeight+axisLabelOffset);
	leftGraphOffset = size+2;
}

# Function used to draw the graph
proc drawGraph(class POLYLINE pipeBottom, class POLYLINE pipeTop, class POLYLINE pipeFace, class POLYLINE surface, class POLYLINE demSurface, class POLYLINE smoothedSurface, class POLYLINE manholeDepth, class STRINGLIST manholeNames)
{
	# save pipe top and bottom for highlighting
	pipeBottomSave = pipeBottom;
	pipeTopSave = pipeTop;
	pipeFaceSave = pipeFace;

	# Draw the graph
	createGC();
	local class COLOR color;

	# set up the affine transformation for the graph
	setTrans(pipeBottom);

	# set up graph axes
	local string xlabel = "Distance (m)";
	local string ylabel = "Elevation (m)";
	local numeric drawTwoPointLines = 0;
	local numeric drawStartEndPoints = 1;

	# set the graph offsets - (globals)
	local numeric fontHeight = 12, axisLabelOffset=3;
	setGraphOffsets(fontHeight, axisLabelOffset);

	# fill in the background
	local class COLOR bgcolor;
	bgcolor.red = 90; bgcolor.green = 90; bgcolor.blue = 100;
	drawBackground(gc, bgcolor);

	# draw the grid
	color.red = 80; color.green = 80; color.blue = 80;
	drawGrid(gc, getGridIntervalX(), getGridIntervalY(), pipeBottom, color);

	# Draw and label the axes
	color.red = 0; color.green = 0; color.blue = 0;
	drawGraphAxes(gc, pipeBottom.GetVertex(pipeBottom.GetNumPoints()-1).x, xlabel, ylabel, drawTwoPointLines, color, fontHeight, axisLabelOffset);

	# draw the pipe bottom
	color = vectorLayer.SelectedElemColor;
#	drawPolyline(gc, pipeBottom, color);

	# draw the pipe top
#	drawPolyline(gc, pipeTop, color);

	# draw the pipe face
	local class COLOR fill = vectorLayer.SelectedElemColor;
#	fill.red = 40; fill.green = 40; fill.blue = 80;
	drawRectangles(gc, pipeFace, color, fill, fillToggle.GetValue());

	# draw the surface line (as dem or from DB)
	class POLYLINE manholeSurfaceLine;
	if (doUseDEM())
	{
		# draw smoothed dem surface line
		gc.DrawSetLineStyle("");
		color.red = 0; color.green = 0; color.blue = 0;
		drawPolyline(gc, smoothedSurface, color);
		manholeSurfaceLine = demSurface;
	}
	else
	{
		# draw surface line
		color.red = 0; color.green = 0; color.blue = 0;
		drawPolyline(gc, surface, color);
		manholeSurfaceLine = surface;
	}


	# draw the manholes
	color.red = 20; color.green = 80; color.blue = 20;
	drawManholes(gc, manholeDepth, manholeSurfaceLine, color);

	# draw the manhole labels
	color.red = 0; color.green = 0; color.blue = 0;
	drawManholeNames(gc, manholeSurfaceLine, manholeNames, color, "ARIAL", 12);

	canvas.Refresh(1);
}

# Called when the min or max z value is changed
proc OnChangeGraphZ()
{
	graphMinZ = graphMinSetting.GetValue();
	graphMaxZ = graphMaxSetting.GetValue();
	needsRedraw = 1;
}

# Callback for a right mouse button press
proc OnRightButtonPress()
{
	# make sure z settings are current
	OnChangeGraphZ();

	# clear the line
	demLine.Clear();
	orderedElemList.Clear();

	# Get the first line as a polyline
	class POLYLINE finalLine;

	# Get all of the lines, appending appropriately
	local numeric i;
	for (i=0; i 0 if one of the two nodes matches an end node.
# case 1: node1==endNodes[1] return 1
# case 2: node1==endNodes[2] return 2
# case 3: node2==endNodes[1] return 3
# case 4: node2==endNodes[2] return 4
func matchesEndNodes(numeric node1, numeric node2)
{
	if (node1==endNodes[1])	# S1 == S2
	{
		endNodes[1] = node2;
		return 1;
	}
	if (node1==endNodes[2])	# E1 == S2
	{
		endNodes[2] = node2;
		return 2;
	}
	if (node2==endNodes[1])	# S1 == E2
	{
		endNodes[1] = node1;
		return 3;
	}
	if (node2==endNodes[2])	# E1 == E2
	{
		endNodes[2] = node1;
		return 4;
	}
	return 0;
}

# if list has 0 -> 1 else -> 0
proc reverseBits(class STRINGLIST s)
{
	local numeric i;
	for (i=0; i=0)
	{
		local numeric doRemove = 0;
		# check to see if the current line is removable
		if (matchNum>0) doRemove = 1;
		if (doRemove)
		{
			# remove the line
			vectorLayer.Line.HighlightSingle(elemNum, "Subtract");
			elemList.Remove(index);
			reversedList.Remove(index);
			if (reversedList.GetString(0)=="1") reverseBits(reversedList);

			if(vectorLayer.Line.GetSelectedElement()==0)
			{
				endNodes[1] = -1;
				endNodes[2] = -1;
			}
		}
	}
	else
	{
		# if no lines exist, then simply append
		if (endNodes[1]==-1 && endNodes[2]==-1)
		{
			endNodes[1] = node1;
			endNodes[2] = node2;
			vectorLayer.Line.HighlightSingle(elemNum, "Add");
			elemList.AddToEnd(NumToStr(elemNum));
			reversedList.AddToEnd("0");
		}
		else if (matchNum>0) # check to see if the current line is appendable
		{
			# add the line
			vectorLayer.Line.HighlightSingle(elemNum, "Add");
			elemList.AddToEnd(NumToStr(elemNum));
			reversedList.AddToEnd("0");
		}
	}
}


# Toggle the line element closest to the point 'position'
func toggleClosestLine(class POINT2D position)
{
	local numeric elemNum = FindClosestLine(lineVector, position.x, position.y);
	if (elemNum > 0 )
	{
		toggleClosestLineElement(elemNum);
	}
	return elemNum;
}

# Callback for a left mouse button press
proc OnLeftButtonPress()
{
	# Find cursor position in screen coordinates
	local class POINT2D point;
	point.x = PointerX;
	point.y = PointerY;
	point = TransPoint2D(point, ViewGetTransLayerToScreen(View, vectorLayer, 1));

	# toggle the element as selected (if valid) or deselected (if possible)
	toggleClosestLine(point);
}

# Called when the close button is pressed.  Closes the dialogs.
proc cbClose()
{
	dlgwin.Close(0);
	if (setDefaultWhenClose)
	{
		setDefaultWhenClose = false;
		View.SetDefaultTool();
	}
}

# Called when the canvas is resized - gc is recreated before drawing
proc OnCanvasResize(class GUI_CANVAS canvas, numeric width, numeric height)
{
	OnRightButtonPress();
}

# return the element number of the nearest line to the graph point
func getNearestLineElementFromGraph(class POINT2D graphPoint)
{
	# make sure z settings are current
#	graphMinZ = graphMinSetting.GetValue();
#	graphMaxZ = graphMaxSetting.GetValue();

	local class POLYLINE splits;
	local class POINT2D tmp;
	local numeric distance = 0;
	tmp.x = distance;
	tmp.y = 0;
	splits.AppendVertex(tmp);

	local numeric i=0;
	for (i=1; i tmp.x)
	{
		vertexNum++;
	}
	if (vertexNum >= splits.GetNumPoints() || (vertexNum==1 && graphPoint.x < leftGraphOffset))
	{
		return 0;
	}

	# get the line from the vertex
	local numeric lineNum = floor(vertexNum/2);
	local numeric elemNum = getElement(orderedElemList, lineNum);

#	vertexDisplay.SetValue(vertexNum, 0);
#	lineDisplay.SetValue(lineNum, 0);
#	elemDisplay.SetValue(elemNum, 0);
	return elemNum;
}

proc highlightGraphSegment(numeric lineNum, class COLOR color)
{
	local class POLYLINE myrect;
	pipeFaceSave.Extract(lineNum*5, 5, myrect);
	drawRectangles(gc, myrect, color, color, fillToggle.GetValue());

	# draw the manholes
	color.red = 20; color.green = 80; color.blue = 20;
	drawManholes(gc, pipeBottomSave, pipeTopSave, color);

	canvas.Refresh(1);
}

proc makeLineActive(numeric elemNum)
{
	vectorLayer.Line.SetActiveElement(elemNum);

	local numeric lineOrdering = indexOf(orderedElemList, elemNum);
	if (lineOrdering>-1 && currentlyActive != lineOrdering)
	{
		local class COLOR color = vectorLayer.SelectedElemColor;
		if(currentlyActive>-1) highlightGraphSegment(currentlyActive, color);
		currentlyActive = lineOrdering;
#color.red = 90; color.green = 90; color.blue = 100;
#highlightGraphSegment(currentlyActive, color);
		color = vectorLayer.ActiveElemColor;
		highlightGraphSegment(currentlyActive, color);

		materialDisplay.SetValue(readLineTableRecordStr(elemNum, "CAN_MAT"), 0);
		slopeDisplay.SetValue(readLineTableRecord(elemNum, "CAN_SLOPE"), 0);
		diameterDisplay.SetValue(readLineTableRecord(elemNum, "CAN_DIAM")/1000, 0);
	}
}


func getNearestLineElementFromGraph2(class POINT2D graphPoint)
{

	# make sure z settings are current
#	graphMinZ = graphMinSetting.GetValue();
#	graphMaxZ = graphMaxSetting.GetValue();

	local class POLYLINE splits = pipeBottomSave;
	local class POINT2D tmp;
#	local numeric distance = 0;
#	tmp.x = distance;
#	tmp.y = 0;
#	splits.AppendVertex(tmp);
#
#	local numeric i=0;
#	for (i=1; i tmp.x)
	{
		vertexNum++;
	}
	if (vertexNum >= splits.GetNumPoints() || (vertexNum==1 && graphPoint.x < leftGraphOffset))
	{
		return 0;
	}

	# get the line from the vertex
	local numeric lineNum = floor(vertexNum/2);
	local numeric elemNum = getElement(orderedElemList, lineNum);

#	vertexDisplay.SetValue(vertexNum, 0);
#	lineDisplay.SetValue(lineNum, 0);
#	elemDisplay.SetValue(elemNum, 0);
	return elemNum;
}

# Called when the mouse is moved over the canvas - highlights the nearest line in the 2d view
proc OnCanvasMouseMove(class GUI_CANVAS canvas, class POINT2D point, numeric shift, numeric ctrl)
{

#
local class POINT2D mapPoint = trans.ConvertPoint2DInv(point);
if (!IsNull(mapPoint.x) && !IsNull(mapPoint.y))
{
	mouseXDisplay.SetValue(mapPoint.x,0);
	mouseYDisplay.SetValue(mapPoint.y,0);
}
#


	if (needsRedraw)
	{
		OnRightButtonPress();
	}
	local numeric elemNum = getNearestLineElementFromGraph(point);
	if (elemNum > 0)
	{
		makeLineActive(elemNum);
	}
	needsRedraw = 0;
}


# Called when mouse is moved over the 2D view - highlights the nearest line in the 2d view
proc OnPointerMoveNoButton()
{
	if (needsRedraw)
	{
		OnRightButtonPress();
		needsRedraw = 0;
	}
	local class POINT2D pointer;
	pointer.x = PointerX;
	pointer.y = PointerY;

	# Get the cursor position in map coords
	local class TRANSPARM screenToView = ViewGetTransViewToScreen(View, 1);
	local class TRANSPARM viewToLayer = ViewGetTransLayerToView(View, vectorLayer, 1);
	pointer = TransPoint2D(pointer, screenToView);
	pointer = TransPoint2D(pointer, viewToLayer);

	local numeric elemNum = FindClosestLine(lineVector, pointer.x, pointer.y);
	if (elemNum > 0)
	{
		makeLineActive(elemNum);
	}
}

# Called when the button to clear the lines is pressed
proc OnClearLines()
{
	endNodes[1]=-1;
	endNodes[2]=-1;
	elemList.Clear();
	orderedElemList.Clear();
	reversedList.Clear();
	vectorLayer.UnhighlightAllElements(1);
	materialDisplay.SetValue("", 0);
	slopeDisplay.SetValue(0, 0);
	diameterDisplay.SetValue(0, 0);
	mouseXDisplay.SetValue(0, 0);
	mouseYDisplay.SetValue(0, 0);
	OnRightButtonPress();
}

# Called with the grid toggle button is pressed, does a full redraw
proc OnGridTogglePressed()
{
	OnRightButtonPress();
}

# Called with the fill toggle button is pressed, does a full redraw
proc OnFillTogglePressed()
{
	OnRightButtonPress();
}

# Called with the grid toggle button is pressed, checks that dem exists
proc OnDemTogglePressed()
{
	checkLayer();
}

# Called the first time the tool is activated.
# If the tool implements a dialog it should be created (but not displayed) here.
func OnInitialize()
{
	# initialize the end node values, used to validate line appends
	endNodes[1]=-1;
	endNodes[2]=-1;

	# handle as layout or as group
	if (Layout)
	{
		WidgetAddCallback(Layout.GroupSelectedCallback, cbGroup);
		activegroup = Layout.ActiveGroup;
	}
	else activegroup = Group;
	WidgetAddCallback(activegroup.LayerSelectedCallback, cbLayer);

	# define the dialog here with xml specification
	string xml$ = 
	'
	
	
		
			
				
					
					
						
						
					
					
						
						
					
				
			
			
				
					
					
						
						
					
					
						
						
					
				
			
			
				
			
			
				
					
						
						
					
					
						
						
						
					
					
						
						
					
				
			
			
				
					
						
							
							
						
						
							
							
						
					
				
				
					
						
					
				
			


			
				
			
		
	
	';

	# Parse the xml dialog specification
	local class XMLDOC dlgdoc;
	local numeric err = dlgdoc.Parse(xml$);
	if (err < 0) {
		PopupError(err);
		Exit();
		}

	local string dlgid$ = "guicanvas";
	local class XMLNODE dlgnode = dlgdoc.GetElementByID(dlgid$);
	if (dlgnode == 0) {
		PopupMessage("Could not find specified id: "+dlgid$);
		Exit();
		}
	dlgwin.SetXMLNode(dlgnode);

	# create the dialog as a modeless dialog
	err = dlgwin.CreateModeless();
	if (err < 0) {
		PopupError(err);
		Exit();
		}

	# get the control for the drawing canvas
	canvas = dlgwin.GetCtrlByID("canvas");
	canvas.SetOnSize(OnCanvasResize);
	canvas.SetOnRightDown(OnCanvasResize);
	canvas.SetOnMouseMove(OnCanvasMouseMove);

	# get the control for the grid toggle
	gridToggle = dlgwin.GetCtrlByID("gridtoggle");
	gridToggle.SetValue(1,0);
	gridToggle.SetOnPressed(OnGridTogglePressed);

	# get the control for the dem toggle
	demToggle = dlgwin.GetCtrlByID("demtoggle");
	demToggle.SetOnPressed(OnDemTogglePressed);

	# get the controls for the grid interval settings
	gridIntervalX = dlgwin.GetCtrlByID("xinterval");
	gridIntervalY = dlgwin.GetCtrlByID("yinterval");

	# get the controls for the min and max z setting
	graphMinSetting = dlgwin.GetCtrlByID("minz");
	graphMaxSetting = dlgwin.GetCtrlByID("maxz");
	OnChangeGraphZ();

	# get the control for the grid toggle
	fillToggle = dlgwin.GetCtrlByID("filltoggle");
	fillToggle.SetValue(1,0);
	fillToggle.SetOnPressed(OnFillTogglePressed);

	# get control for display of info
#	vertexDisplay = dlgwin.GetCtrlByID("vertex");
#	lineDisplay = dlgwin.GetCtrlByID("line");
#	elemDisplay = dlgwin.GetCtrlByID("elem");
	mouseXDisplay = dlgwin.GetCtrlByID("mousex");
	mouseYDisplay = dlgwin.GetCtrlByID("mousey");
	materialDisplay = dlgwin.GetCtrlByID("material");
	slopeDisplay = dlgwin.GetCtrlByID("slope");
	diameterDisplay = dlgwin.GetCtrlByID("diameter");

	drawable = 0;
}
 
# Called when tool is to be destroyed, will not be called if tool was never activated.
func OnDestroy()
{
	dlgwin.Close(0);
}

# Called when tool is activated.
func OnActivate()
{
	checkLayer();

	# open the graph dialog window
	dlgwin.Open();

	# draw the graph
	OnRightButtonPress();

	setDefaultWhenClose = true;
}
 
# Called when tool is deactivated (usually when switching to another tool).
func OnDeactivate()
{
	setDefaultWhenClose = false;
	cbClose();
}


Back Home ©MicroImages, Inc. 2013 Published in the United States of America
11th Floor - Sharp Tower, 206 South 13th Street, Lincoln NE 68508-2010   USA
Business & Sales: (402)477-9554  Support: (402)477-9562  Fax: (402)477-9559
Business info@microimages.com  Support support@microimages.com  Web webmaster@microimages.com

25 March 2009

page update: 26 May 11