viewrtree.tcl 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. load ./libsqlite3.dylib
  2. #package require sqlite3
  3. source [file join [file dirname $argv0] rtree_util.tcl]
  4. wm title . "SQLite r-tree viewer"
  5. if {[llength $argv]!=1} {
  6. puts stderr "Usage: $argv0 <database-file>"
  7. puts stderr ""
  8. exit
  9. }
  10. sqlite3 db [lindex $argv 0]
  11. canvas .c -background white -width 400 -height 300 -highlightthickness 0
  12. button .b -text "Parent Node" -command {
  13. set sql "SELECT parentnode FROM $::O(zTab)_parent WHERE nodeno = $::O(iNode)"
  14. set ::O(iNode) [db one $sql]
  15. if {$::O(iNode) eq ""} {set ::O(iNode) 1}
  16. view_node
  17. }
  18. set O(iNode) 1
  19. set O(zTab) ""
  20. set O(listbox_captions) [list]
  21. set O(listbox_itemmap) [list]
  22. set O(listbox_highlight) -1
  23. listbox .l -listvariable ::O(listbox_captions) -yscrollcommand {.ls set}
  24. scrollbar .ls -command {.l yview}
  25. label .status -font courier -anchor w
  26. label .title -anchor w -text "Node 1:" -background white -borderwidth 0
  27. set rtree_tables [list]
  28. db eval {
  29. SELECT name
  30. FROM sqlite_master
  31. WHERE type='table' AND sql LIKE '%virtual%table%using%rtree%'
  32. } {
  33. set nCol [expr [llength [db eval "pragma table_info($name)"]]/6]
  34. if {$nCol != 5} {
  35. puts stderr "Not viewing $name - is not 2-dimensional"
  36. } else {
  37. lappend rtree_tables [list Table $name]
  38. }
  39. }
  40. if {$rtree_tables eq ""} {
  41. puts stderr "Cannot find an r-tree table in database [lindex $argv 0]"
  42. puts stderr ""
  43. exit
  44. }
  45. eval tk_optionMenu .select option_var $rtree_tables
  46. trace add variable option_var write set_option_var
  47. proc set_option_var {args} {
  48. set ::O(zTab) [lindex $::option_var 1]
  49. set ::O(iNode) 1
  50. view_node
  51. }
  52. set ::O(zTab) [lindex $::rtree_tables 0 1]
  53. bind .l <1> {listbox_click [.l nearest %y]}
  54. bind .l <Motion> {listbox_mouseover [.l nearest %y]}
  55. bind .l <Leave> {listbox_mouseover -1}
  56. proc listbox_click {sel} {
  57. if {$sel ne ""} {
  58. set ::O(iNode) [lindex $::O(listbox_captions) $sel 1]
  59. view_node
  60. }
  61. }
  62. proc listbox_mouseover {i} {
  63. set oldid [lindex $::O(listbox_itemmap) $::O(listbox_highlight)]
  64. .c itemconfigure $oldid -fill ""
  65. .l selection clear 0 end
  66. .status configure -text ""
  67. if {$i>=0} {
  68. set id [lindex $::O(listbox_itemmap) $i]
  69. .c itemconfigure $id -fill grey
  70. .c lower $id
  71. set ::O(listbox_highlight) $i
  72. .l selection set $i
  73. .status configure -text [cell_report db $::O(zTab) $::O(iNode) $i]
  74. }
  75. }
  76. grid configure .select -row 0 -column 0 -columnspan 2 -sticky nsew
  77. grid configure .b -row 1 -column 0 -columnspan 2 -sticky nsew
  78. grid configure .l -row 2 -column 0 -sticky nsew
  79. grid configure .status -row 3 -column 0 -columnspan 3 -sticky nsew
  80. grid configure .title -row 0 -column 2 -sticky nsew
  81. grid configure .c -row 1 -column 2 -rowspan 2 -sticky nsew
  82. grid configure .ls -row 2 -column 1 -sticky nsew
  83. grid columnconfigure . 2 -weight 1
  84. grid rowconfigure . 2 -weight 1
  85. proc node_bbox {data} {
  86. set xmin 0
  87. set xmax 0
  88. set ymin 0
  89. set ymax 0
  90. foreach {rowid xmin xmax ymin ymax} [lindex $data 0] break
  91. foreach cell [lrange $data 1 end] {
  92. foreach {rowid x1 x2 y1 y2} $cell break
  93. if {$x1 < $xmin} {set xmin $x1}
  94. if {$x2 > $xmax} {set xmax $x2}
  95. if {$y1 < $ymin} {set ymin $y1}
  96. if {$y2 > $ymax} {set ymax $y2}
  97. }
  98. list $xmin $xmax $ymin $ymax
  99. }
  100. proc view_node {} {
  101. set iNode $::O(iNode)
  102. set zTab $::O(zTab)
  103. set data [rtree_node db $zTab $iNode 12]
  104. set depth [rtree_nodedepth db $zTab $iNode]
  105. .c delete all
  106. set ::O(listbox_captions) [list]
  107. set ::O(listbox_itemmap) [list]
  108. set $::O(listbox_highlight) -1
  109. .b configure -state normal
  110. if {$iNode == 1} {.b configure -state disabled}
  111. .title configure -text "Node $iNode: [cell_report db $zTab $iNode -1]"
  112. foreach {xmin xmax ymin ymax} [node_bbox $data] break
  113. set total_area 0.0
  114. set xscale [expr {double([winfo width .c]-20)/($xmax-$xmin)}]
  115. set yscale [expr {double([winfo height .c]-20)/($ymax-$ymin)}]
  116. set xoff [expr {10.0 - $xmin*$xscale}]
  117. set yoff [expr {10.0 - $ymin*$yscale}]
  118. foreach cell $data {
  119. foreach {rowid x1 x2 y1 y2} $cell break
  120. set total_area [expr {$total_area + ($x2-$x1)*($y2-$y1)}]
  121. set x1 [expr {$x1*$xscale + $xoff}]
  122. set x2 [expr {$x2*$xscale + $xoff}]
  123. set y1 [expr {$y1*$yscale + $yoff}]
  124. set y2 [expr {$y2*$yscale + $yoff}]
  125. set id [.c create rectangle $x1 $y1 $x2 $y2]
  126. if {$depth>0} {
  127. lappend ::O(listbox_captions) "Node $rowid"
  128. lappend ::O(listbox_itemmap) $id
  129. }
  130. }
  131. }
  132. proc cell_report {db zTab iParent iCell} {
  133. set data [rtree_node db $zTab $iParent 12]
  134. set cell [lindex $data $iCell]
  135. foreach {xmin xmax ymin ymax} [node_bbox $data] break
  136. set total_area [expr ($xmax-$xmin)*($ymax-$ymin)]
  137. if {$cell eq ""} {
  138. set cell_area 0.0
  139. foreach cell $data {
  140. foreach {rowid x1 x2 y1 y2} $cell break
  141. set cell_area [expr $cell_area+($x2-$x1)*($y2-$y1)]
  142. }
  143. set cell_area [expr $cell_area/[llength $data]]
  144. set zReport [format "Size = %.1f x %.1f Average child area = %.1f%%" \
  145. [expr $xmax-$xmin] [expr $ymax-$ymin] [expr 100.0*$cell_area/$total_area]\
  146. ]
  147. append zReport " Sub-tree height: [rtree_nodedepth db $zTab $iParent]"
  148. } else {
  149. foreach {rowid x1 x2 y1 y2} $cell break
  150. set cell_area [expr ($x2-$x1)*($y2-$y1)]
  151. set zReport [format "Size = %.1f x %.1f Area = %.1f%%" \
  152. [expr $x2-$x1] [expr $y2-$y1] [expr 100.0*$cell_area/$total_area]
  153. ]
  154. }
  155. return $zReport
  156. }
  157. view_node
  158. bind .c <Configure> view_node