#
# 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();
}