edge
TCL/TK UseCase4
Abstract : Contains all procedure for creating and maintaining an edge object.
Comments : The procedures in this file for getting and setting can easily be
converted to call propagation patterns.
For Use Case 4 we have switch from having Tcl/Tk track objects
(which was done through label name) to have C++ track them
with a unique ID number passed to Tcl/Tk. This will allow for
better tracking and object manipulation. In files edge.tcl,
vertex.tcl, and bindings.tcl, most any referrence to the
varible "name" or "$name" is actually the ID number.
#
#edge.tcl
#
#Contains procedures for creating new edges and for retrieving and setting
#data related to edge objects
#####
###
# Bend node ovels...
###
###
#Calculates how to size the bendy node ovals
###
proc calcOval { x y } {
set width 6
set left [expr $x - ($width / 2)]
set top [expr $y - ($width / 2)]
set right [expr $left + $width]
set bottom [expr $top + $width]
return "$left $top $right $bottom"
}
###
#Determines which bendy node of an edge is selected
###
proc findListEntry { theList itemID } {
set index 0
foreach i $theList {
if {[lindex $i 0] == $itemID} {
return $index
}
incr index
}
return -1
}
###
# Set up an edge "data structure."
###
proc newEdge { name lbl type srcVert dstVert {lblOff {0 -20}} {nodes {}}} {
#Makes global vars accessible
global Edge iGraph inform changes
#Makes C++ calls for new edge. Only does this for user interaction.
#Also changes global flag "changes" to yes for a save changes check.
if {$inform == 1} {
# reformats some data that will be passed to C++
puts $nodes
if {$nodes != ""} {
set formatted "{$nodes}"
} else {
set formatted " "
}
set formatted2 "{$lblOff}"
if {$type == "Constr"} {
set changes yes
puts "Sending: $lbl $srcVert $dstVert $formatted2 $formatted"
set name [$iGraph cppCreCEdge: $lbl [fixID $srcVert]\
[fixID $dstVert] $formatted2\
$formatted]
} else {
set changes yes
puts "Sending: $srcVert $dstVert $formatted2 $formatted"
set name [$iGraph cppCreAEdge: [fixID $srcVert] [fixID $dstVert]\
$formatted]
} } else {
set srcVert ID$srcVert
set dstVert ID$dstVert
}
#puts "Getting: $name $lbl"
set name ID$name
#Initializes vars in Edge array
set Edge($name,Label) $lbl
set Edge($name,LabelOff) $lblOff
set Edge($name,srcVert) $srcVert
set Edge($name,dstVert) $dstVert
set Edge($name,nodeCoords) $nodes
set Edge($name,Type) $type
#Set pointers to procedures on how to creates the edge and edge label.
#There are different was for creating different edges.
set Edge($name,cmdCreate) createEdge_$type
set Edge($name,cmdCreateLbl) createEdgeLabel_$type
# initialize the item IDs (used for Tcl/Tk binding.)
set Edge($name,LabelID) -1
set Edge($name,LineIDs) {}
set Edge($name,OvalIDs) {}
#Adds new edge to the edge lists of its source and destination
appendVertexEdgeOut $srcVert $name
appendVertexEdgeIn $dstVert $name
createEdge $name
}
###
# The following functions are used to set and obtain data
# relating to edge objects. If the need be, these functions
# could be used to call propogation patterns that would
# set or return the item requested.
###
#
#Returns the type of a given edge.
proc getEdgeType { name } {
global Edge
return $Edge($name,Type)
}
#
#Sets the label of a given edge
proc setEdgeLabel { name lbl } {
global Edge
set Edge($name,Label) $lbl
}
#
#Returns the label of an edge
proc getEdgeLabel { name } {
global Edge
return $Edge($name,Label)
}
#
# Sends label update to C++
proc setEdgeLabelOff { name offset } {
global Edge iGraph changes
set changes yes
set Edge($name,LabelOff) $offset
set formatted "{$offset}"
# puts "Sending: $name $formatted"
$iGraph cppUpdELabel: [fixID $name] $formatted
# $iGraph cppUpdELabel: $name [getEdgeSrcVert $name] [getEdgeDstVert $name]\
# $formatted
}
#
#Returns the label offset for an edge
proc getEdgeLabelOff { name } {
global Edge
return $Edge($name,LabelOff)
}
#
#Returns the comand to create an edge.
proc getEdgeCreateCmd { name } {
global Edge
return $Edge($name,cmdCreate)
}
#
#Returns the command to create an edge label
proc getEdgeCreateLblCmd { name } {
global Edge
return $Edge($name,cmdCreateLbl)
}
#
#Sets the source vertex of an edge
proc setEdgeSrcVert { name vert } {
global Edge
set Edge($name,srcVert) $vert
}
#
#Returns the source vertex of an edge
proc getEdgeSrcVert { name } {
global Edge
return $Edge($name,srcVert)
}
#
#Sets the destination vertex of an edge
proc setEdgeDstVert { name vert } {
global Edge
set Edge($name,dstVert) $vert
}
#
#Returns the destination vertex of an edge
proc getEdgeDstVert { name } {
global Edge
return $Edge($name,dstVert)
}
#
# Informs C++ of start/end node for an edge.
proc setEdgeNodeCoords { name coords } {
global Edge iGraph changes
set changes yes
set Edge($name,nodeCoords) $coords
set formatted "{$coords}"
#puts "Sending: $name $formatted"
$iGraph cppUpdEdge: [fixID $name] $formatted
}
#
#Returns the node coordinates for a bendy node
proc getEdgeNodeCoords { name } {
global Edge
return $Edge($name,nodeCoords)
}
#
#Sets the label canvas id for an edge
proc setEdgeLabelID { name id } {
global Edge
set Edge($name,LabelID) $id
}
#
#Returns the label canvas id for an edge
proc getEdgeLabelID { name } {
global Edge
return $Edge($name,LabelID)
}
#
#Sets the line canvas id for an edge
proc setEdgeLineIDs { name ids } {
global Edge
set Edge($name,LineIDs) $ids
}
#
#Returns the line canvas id for an edge
proc getEdgeLineIDs { name } {
global Edge
return $Edge($name,LineIDs)
}
#
#Sets the oval id for an edge
proc setEdgeOvalIDs { name ids } {
global Edge
set Edge($name,OvalIDs) $ids
}
#
#Returns the oval id for an edge
proc getEdgeOvalIDs { name } {
global Edge
return $Edge($name,OvalIDs)
}
#
#Clears the edge ids for an edge that is being refreshed
proc clearEdgeIDs { name } {
global Edge
set Edge($name,LineIDs) {}
set Edge($name,OvalIDs) {}
}
###
#Deletes an edge associated with a node that has been moved (screen refresh)
###
proc deleteEdgeObjects { name } {
global Edge can
#Deletes lines
foreach i $Edge($name,LineIDs) {
for {set x 0} {$x < [llength $i]} {incr x 2} {
$can delete [lindex $i $x]
}
}
#Deletes bendy point ovals
foreach i $Edge($name,OvalIDs) { $can delete [lindex $i 0] }
#Deletes the label
$can delete [getEdgeLabelID $name]
clearEdgeIDs $name
setEdgeLabelID $name -1
}
###
#Creates a construction edge on the canvas
###
proc createEdge_Constr { name srcCoords dstCoords lst index {arrow 1} } {
global can
upvar $lst List
#Creates the line
set itemID [$can create line \
[lindex $srcCoords 0] [lindex $srcCoords 1] \
[lindex $dstCoords 0] [lindex $dstCoords 1] \
-tags "$name"]
#Creates the arrow
if {$arrow != 0} {
$can itemconfigure $itemID -arrow last
}
lappend List "$itemID $index"
$can raise $itemID
$can bind $itemID " onEdgeLineDbl $name %x %y "
return $itemID
}
###
# Calulate || lines for alternation edges.
###
proc calcAlterSlope { SourceX SourceY DestX DestY } {
set space 3
if {[expr ($DestX - $SourceX)] != 0} {
#Determines the slope of the edge
set slope [expr abs((($DestY - $SourceY) * 100) / ($DestX - $SourceX))]
#For more vertically inclined edges, offsets x coords
if {[expr $slope] >= 100} {
set xspace $space
set yspace 0
} else {
#For more horizontally inclined edges, offsets y coords
set xspace 0
set yspace $space
}
} else {
set yspace 0
set xspace $space
}
return "$xspace $yspace"
}
###
#Creates an alternation edge on the canvas.
###
proc createEdge_Alter { name srcCoords dstCoords lst index {arrow 1} } {
global can
upvar $lst List
#Determine slope and offsets for lines
set slope [calcAlterSlope [getXCoord $srcCoords] [getYCoord $srcCoords] \
[getXCoord $dstCoords] [getYCoord $dstCoords]]
set xspace [getXCoord $slope]
set yspace [getYCoord $slope]
#Create first line with arrow
set itemID [$can create line \
[expr [lindex $srcCoords 0] - $xspace ] \
[expr [lindex $srcCoords 1] - $yspace ] \
[expr [lindex $dstCoords 0] - $xspace ] \
[expr [lindex $dstCoords 1] - $yspace ] \
-tags "$name"]
if {$arrow != 0} {
$can itemconfigure $itemID -arrow last
}
#Create second line with arrow
set itemID2 [$can create line \
[expr [lindex $srcCoords 0] + $xspace ] \
[expr [lindex $srcCoords 1] + $yspace ] \
[expr [lindex $dstCoords 0] + $xspace ] \
[expr [lindex $dstCoords 1] + $yspace ] \
-tags "$name"]
if {$arrow != 0} {
$can itemconfigure $itemID2 -arrow last
}
lappend List "$itemID $index $itemID2 $index"
$can raise $itemID
$can raise $itemID2
#Create bindings for removing and adding bends
$can bind $itemID " onEdgeLineDbl $name %x %y "
$can bind $itemID2 " onEdgeLineDbl $name %x %y "
return "$itemID $itemID2"
}
###
# Find midpoint between 2 nodes.
###
proc edgeCalcMidpoint { name } {
#Initialize vars
set srcVertName [getEdgeSrcVert $name]
set dstVertName [getEdgeDstVert $name]
set srcCoords [getVertexCoords $srcVertName]
set dstCoords [getVertexCoords $dstVertName]
#Calculate midpoint
set srcCoords [getVertexCoords $srcVertName]
set dstCoords [getVertexCoords $dstVertName]
set midX [expr (([getXCoord $dstCoords] - [getXCoord $srcCoords]) / 2) + \
[getXCoord $srcCoords]]
set midY [expr (([getYCoord $dstCoords] - [getYCoord $srcCoords]) / 2) + \
[getYCoord $srcCoords]]
return "$midX $midY"
}
###
#Create the label for a construction edge.
###
proc createEdgeLabel_Constr { name } {
global can
#Initialize vars
set srcVertName [getEdgeSrcVert $name]
set dstVertName [getEdgeDstVert $name]
set srcCoords [getVertexCoords $srcVertName]
set dstCoords [getVertexCoords $dstVertName]
#Calculate midpoint
set srcCoords [getVertexCoords $srcVertName]
set dstCoords [getVertexCoords $dstVertName]
set midX [expr (([getXCoord $dstCoords] - [getXCoord $srcCoords]) / 2) + \
[getXCoord $srcCoords]]
set midY [expr (([getYCoord $dstCoords] - [getYCoord $srcCoords]) / 2) + \
[getYCoord $srcCoords]]
#Determine label coordinates based on midpoint of line
set labelX [expr $midX + [getXCoord [getEdgeLabelOff $name]]]
set labelY [expr $midY + [getYCoord [getEdgeLabelOff $name]]]
#Create the label object
set labelName [getEdgeLabel $name]
set label [$can create text $labelX $labelY \
-text $labelName -tags "_label_ $name"]
#Set bindings
$can bind $label " onEdgeLblMove $name %x %y "
setEdgeLabelID $name $label
}
#
#No such thing!
proc createEdgeLabel_Alter { name } {
}
###
#Creates an edge on the canvas
###
proc createEdge { name } {
global can
#Removes any existing edge
deleteEdgeObjects $name
#Initialize vars
set createEdgeCmd [getEdgeCreateCmd $name]
set srcVertName [getEdgeSrcVert $name]
set dstVertName [getEdgeDstVert $name]
set lnCoords [getEdgeNodeCoords $name]
set lnCoords [linsert $lnCoords 0 [getVertexCoords $srcVertName]]
lappend lnCoords [getVertexCoords $dstVertName]
set srcCoords [lindex $lnCoords 0]
set Lines {}
set Ovals {}
#Create bendy nodes
for {set index 1} { $index < [expr [llength $lnCoords] - 1]} {incr index} {
#Get destination of next line
set dstCoords [lindex $lnCoords $index]
set itemID [$createEdgeCmd $name $srcCoords $dstCoords Lines $index]
# lappend Lines "$itemID $index"
#Create oval node
set ovalCoords [calcOval [lindex $dstCoords 0] [lindex $dstCoords 1]]
set itemID [$can create oval \
[lindex $ovalCoords 0] [lindex $ovalCoords 1] \
[lindex $ovalCoords 2] [lindex $ovalCoords 3] \
-fill red]
lappend Ovals "$itemID $index"
$can raise $itemID
#Create bindings for bend points
# $can bind $itemID { onOvalDown %x %y }
$can bind $itemID " onOvalMove $name %x %y "
$can bind $itemID " onEdgeOvalUp $name %x %y "
$can bind $itemID " onEdgeOvalDbl $name %x %y "
set srcCoords $dstCoords
}
#Create edge
set dstCoords [lindex $lnCoords $index]
set itemID [$createEdgeCmd $name $srcCoords $dstCoords Lines $index 0]
# lappend Lines "$itemID $index"
#Add arrows to lines
if {$index == 1} {
foreach i $itemID {
$can itemconfigure $i -arrow last
}
}
#Set ids for lines and nodes
setEdgeLineIDs $name $Lines
setEdgeOvalIDs $name $Ovals
#Create edge label
set cmdCreateLabel [getEdgeCreateLblCmd $name]
$cmdCreateLabel $name
#Add bindings for edges
$can bind $name " onEdgeEnter $name %x %y "
$can bind $name " onEdgeLeave $name %x %y "
$can bind $name " onEdgeUp $name %x %y "
}
###
#Generic loop to search through a list of edge items
###
proc getEdgeItemIndex { theList itemID } {
set index 0
foreach i $theList {
for {set x 0} {$x < [llength $i]} {incr x 2} {
if {[lindex $i $x] == $itemID} {
return $index
}
incr index
}
}
return -1
}