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