1*ebaecc14Sdanielk1977# 2008 Feb 19 2*ebaecc14Sdanielk1977# 3*ebaecc14Sdanielk1977# The author disclaims copyright to this source code. In place of 4*ebaecc14Sdanielk1977# a legal notice, here is a blessing: 5*ebaecc14Sdanielk1977# 6*ebaecc14Sdanielk1977# May you do good and not evil. 7*ebaecc14Sdanielk1977# May you find forgiveness for yourself and forgive others. 8*ebaecc14Sdanielk1977# May you share freely, never taking more than you give. 9*ebaecc14Sdanielk1977# 10*ebaecc14Sdanielk1977#*********************************************************************** 11*ebaecc14Sdanielk1977# 12*ebaecc14Sdanielk1977# This file contains Tcl code that may be useful for testing or 13*ebaecc14Sdanielk1977# analyzing r-tree structures created with this module. It is 14*ebaecc14Sdanielk1977# used by both test procedures and the r-tree viewer application. 15*ebaecc14Sdanielk1977# 16*ebaecc14Sdanielk1977# $Id: rtree_util.tcl,v 1.1 2008/05/26 18:41:54 danielk1977 Exp $ 17*ebaecc14Sdanielk1977# 18*ebaecc14Sdanielk1977 19*ebaecc14Sdanielk1977 20*ebaecc14Sdanielk1977#-------------------------------------------------------------------------- 21*ebaecc14Sdanielk1977# PUBLIC API: 22*ebaecc14Sdanielk1977# 23*ebaecc14Sdanielk1977# rtree_depth 24*ebaecc14Sdanielk1977# rtree_ndim 25*ebaecc14Sdanielk1977# rtree_node 26*ebaecc14Sdanielk1977# rtree_mincells 27*ebaecc14Sdanielk1977# rtree_check 28*ebaecc14Sdanielk1977# rtree_dump 29*ebaecc14Sdanielk1977# rtree_treedump 30*ebaecc14Sdanielk1977# 31*ebaecc14Sdanielk1977 32*ebaecc14Sdanielk1977proc rtree_depth {db zTab} { 33*ebaecc14Sdanielk1977 $db one "SELECT rtreedepth(data) FROM ${zTab}_node WHERE nodeno=1" 34*ebaecc14Sdanielk1977} 35*ebaecc14Sdanielk1977 36*ebaecc14Sdanielk1977proc rtree_nodedepth {db zTab iNode} { 37*ebaecc14Sdanielk1977 set iDepth [rtree_depth $db $zTab] 38*ebaecc14Sdanielk1977 39*ebaecc14Sdanielk1977 set ii $iNode 40*ebaecc14Sdanielk1977 while {$ii != 1} { 41*ebaecc14Sdanielk1977 set sql "SELECT parentnode FROM ${zTab}_parent WHERE nodeno = $ii" 42*ebaecc14Sdanielk1977 set ii [db one $sql] 43*ebaecc14Sdanielk1977 incr iDepth -1 44*ebaecc14Sdanielk1977 } 45*ebaecc14Sdanielk1977 46*ebaecc14Sdanielk1977 return $iDepth 47*ebaecc14Sdanielk1977} 48*ebaecc14Sdanielk1977 49*ebaecc14Sdanielk1977# Return the number of dimensions of the rtree. 50*ebaecc14Sdanielk1977# 51*ebaecc14Sdanielk1977proc rtree_ndim {db zTab} { 52*ebaecc14Sdanielk1977 set nDim [expr {(([llength [$db eval "pragma table_info($zTab)"]]/6)-1)/2}] 53*ebaecc14Sdanielk1977} 54*ebaecc14Sdanielk1977 55*ebaecc14Sdanielk1977# Return the contents of rtree node $iNode. 56*ebaecc14Sdanielk1977# 57*ebaecc14Sdanielk1977proc rtree_node {db zTab iNode {iPrec 6}} { 58*ebaecc14Sdanielk1977 set nDim [rtree_ndim $db $zTab] 59*ebaecc14Sdanielk1977 set sql " 60*ebaecc14Sdanielk1977 SELECT rtreenode($nDim, data) FROM ${zTab}_node WHERE nodeno = $iNode 61*ebaecc14Sdanielk1977 " 62*ebaecc14Sdanielk1977 set node [db one $sql] 63*ebaecc14Sdanielk1977 64*ebaecc14Sdanielk1977 set nCell [llength $node] 65*ebaecc14Sdanielk1977 set nCoord [expr $nDim*2] 66*ebaecc14Sdanielk1977 for {set ii 0} {$ii < $nCell} {incr ii} { 67*ebaecc14Sdanielk1977 for {set jj 1} {$jj <= $nCoord} {incr jj} { 68*ebaecc14Sdanielk1977 set newval [format "%.${iPrec}f" [lindex $node $ii $jj]] 69*ebaecc14Sdanielk1977 lset node $ii $jj $newval 70*ebaecc14Sdanielk1977 } 71*ebaecc14Sdanielk1977 } 72*ebaecc14Sdanielk1977 set node 73*ebaecc14Sdanielk1977} 74*ebaecc14Sdanielk1977 75*ebaecc14Sdanielk1977proc rtree_mincells {db zTab} { 76*ebaecc14Sdanielk1977 set n [$db one "select length(data) FROM ${zTab}_node LIMIT 1"] 77*ebaecc14Sdanielk1977 set nMax [expr {int(($n-4)/(8+[rtree_ndim $db $zTab]*2*4))}] 78*ebaecc14Sdanielk1977 return [expr {int($nMax/3)}] 79*ebaecc14Sdanielk1977} 80*ebaecc14Sdanielk1977 81*ebaecc14Sdanielk1977# An integrity check for the rtree $zTab accessible via database 82*ebaecc14Sdanielk1977# connection $db. 83*ebaecc14Sdanielk1977# 84*ebaecc14Sdanielk1977proc rtree_check {db zTab} { 85*ebaecc14Sdanielk1977 array unset ::checked 86*ebaecc14Sdanielk1977 87*ebaecc14Sdanielk1977 # Check each r-tree node. 88*ebaecc14Sdanielk1977 set rc [catch { 89*ebaecc14Sdanielk1977 rtree_node_check $db $zTab 1 [rtree_depth $db $zTab] 90*ebaecc14Sdanielk1977 } msg] 91*ebaecc14Sdanielk1977 if {$rc && $msg ne ""} { error $msg } 92*ebaecc14Sdanielk1977 93*ebaecc14Sdanielk1977 # Check that the _rowid and _parent tables have the right 94*ebaecc14Sdanielk1977 # number of entries. 95*ebaecc14Sdanielk1977 set nNode [$db one "SELECT count(*) FROM ${zTab}_node"] 96*ebaecc14Sdanielk1977 set nRow [$db one "SELECT count(*) FROM ${zTab}"] 97*ebaecc14Sdanielk1977 set nRowid [$db one "SELECT count(*) FROM ${zTab}_rowid"] 98*ebaecc14Sdanielk1977 set nParent [$db one "SELECT count(*) FROM ${zTab}_parent"] 99*ebaecc14Sdanielk1977 100*ebaecc14Sdanielk1977 if {$nNode != ($nParent+1)} { 101*ebaecc14Sdanielk1977 error "Wrong number of entries in ${zTab}_parent" 102*ebaecc14Sdanielk1977 } 103*ebaecc14Sdanielk1977 if {$nRow != $nRowid} { 104*ebaecc14Sdanielk1977 error "Wrong number of entries in ${zTab}_rowid" 105*ebaecc14Sdanielk1977 } 106*ebaecc14Sdanielk1977 107*ebaecc14Sdanielk1977 return $rc 108*ebaecc14Sdanielk1977} 109*ebaecc14Sdanielk1977 110*ebaecc14Sdanielk1977proc rtree_node_check {db zTab iNode iDepth} { 111*ebaecc14Sdanielk1977 if {[info exists ::checked($iNode)]} { error "Second ref to $iNode" } 112*ebaecc14Sdanielk1977 set ::checked($iNode) 1 113*ebaecc14Sdanielk1977 114*ebaecc14Sdanielk1977 set node [rtree_node $db $zTab $iNode] 115*ebaecc14Sdanielk1977 if {$iNode!=1 && [llength $node]==0} { error "No such node: $iNode" } 116*ebaecc14Sdanielk1977 117*ebaecc14Sdanielk1977 if {$iNode != 1 && [llength $node]<[rtree_mincells $db $zTab]} { 118*ebaecc14Sdanielk1977 puts "Node $iNode: Has only [llength $node] cells" 119*ebaecc14Sdanielk1977 error "" 120*ebaecc14Sdanielk1977 } 121*ebaecc14Sdanielk1977 if {$iNode == 1 && [llength $node]==1 && [rtree_depth $db $zTab]>0} { 122*ebaecc14Sdanielk1977 set depth [rtree_depth $db $zTab] 123*ebaecc14Sdanielk1977 puts "Node $iNode: Has only 1 child (tree depth is $depth)" 124*ebaecc14Sdanielk1977 error "" 125*ebaecc14Sdanielk1977 } 126*ebaecc14Sdanielk1977 127*ebaecc14Sdanielk1977 set nDim [expr {([llength [lindex $node 0]]-1)/2}] 128*ebaecc14Sdanielk1977 129*ebaecc14Sdanielk1977 if {$iDepth > 0} { 130*ebaecc14Sdanielk1977 set d [expr $iDepth-1] 131*ebaecc14Sdanielk1977 foreach cell $node { 132*ebaecc14Sdanielk1977 set shouldbe [rtree_node_check $db $zTab [lindex $cell 0] $d] 133*ebaecc14Sdanielk1977 if {$cell ne $shouldbe} { 134*ebaecc14Sdanielk1977 puts "Node $iNode: Cell is: {$cell}, should be {$shouldbe}" 135*ebaecc14Sdanielk1977 error "" 136*ebaecc14Sdanielk1977 } 137*ebaecc14Sdanielk1977 } 138*ebaecc14Sdanielk1977 } 139*ebaecc14Sdanielk1977 140*ebaecc14Sdanielk1977 set mapping_table "${zTab}_parent" 141*ebaecc14Sdanielk1977 set mapping_sql "SELECT parentnode FROM $mapping_table WHERE rowid = \$rowid" 142*ebaecc14Sdanielk1977 if {$iDepth==0} { 143*ebaecc14Sdanielk1977 set mapping_table "${zTab}_rowid" 144*ebaecc14Sdanielk1977 set mapping_sql "SELECT nodeno FROM $mapping_table WHERE rowid = \$rowid" 145*ebaecc14Sdanielk1977 } 146*ebaecc14Sdanielk1977 foreach cell $node { 147*ebaecc14Sdanielk1977 set rowid [lindex $cell 0] 148*ebaecc14Sdanielk1977 set mapping [db one $mapping_sql] 149*ebaecc14Sdanielk1977 if {$mapping != $iNode} { 150*ebaecc14Sdanielk1977 puts "Node $iNode: $mapping_table entry for cell $rowid is $mapping" 151*ebaecc14Sdanielk1977 error "" 152*ebaecc14Sdanielk1977 } 153*ebaecc14Sdanielk1977 } 154*ebaecc14Sdanielk1977 155*ebaecc14Sdanielk1977 set ret [list $iNode] 156*ebaecc14Sdanielk1977 for {set ii 1} {$ii <= $nDim*2} {incr ii} { 157*ebaecc14Sdanielk1977 set f [lindex $node 0 $ii] 158*ebaecc14Sdanielk1977 foreach cell $node { 159*ebaecc14Sdanielk1977 set f2 [lindex $cell $ii] 160*ebaecc14Sdanielk1977 if {($ii%2)==1 && $f2<$f} {set f $f2} 161*ebaecc14Sdanielk1977 if {($ii%2)==0 && $f2>$f} {set f $f2} 162*ebaecc14Sdanielk1977 } 163*ebaecc14Sdanielk1977 lappend ret $f 164*ebaecc14Sdanielk1977 } 165*ebaecc14Sdanielk1977 return $ret 166*ebaecc14Sdanielk1977} 167*ebaecc14Sdanielk1977 168*ebaecc14Sdanielk1977proc rtree_dump {db zTab} { 169*ebaecc14Sdanielk1977 set zRet "" 170*ebaecc14Sdanielk1977 set nDim [expr {(([llength [$db eval "pragma table_info($zTab)"]]/6)-1)/2}] 171*ebaecc14Sdanielk1977 set sql "SELECT nodeno, rtreenode($nDim, data) AS node FROM ${zTab}_node" 172*ebaecc14Sdanielk1977 $db eval $sql { 173*ebaecc14Sdanielk1977 append zRet [format "% -10s %s\n" $nodeno $node] 174*ebaecc14Sdanielk1977 } 175*ebaecc14Sdanielk1977 set zRet 176*ebaecc14Sdanielk1977} 177*ebaecc14Sdanielk1977 178*ebaecc14Sdanielk1977proc rtree_nodetreedump {db zTab zIndent iDepth iNode} { 179*ebaecc14Sdanielk1977 set ret "" 180*ebaecc14Sdanielk1977 set node [rtree_node $db $zTab $iNode 1] 181*ebaecc14Sdanielk1977 append ret [format "%-3d %s%s\n" $iNode $zIndent $node] 182*ebaecc14Sdanielk1977 if {$iDepth>0} { 183*ebaecc14Sdanielk1977 foreach cell $node { 184*ebaecc14Sdanielk1977 set i [lindex $cell 0] 185*ebaecc14Sdanielk1977 append ret [rtree_nodetreedump $db $zTab "$zIndent " [expr $iDepth-1] $i] 186*ebaecc14Sdanielk1977 } 187*ebaecc14Sdanielk1977 } 188*ebaecc14Sdanielk1977 set ret 189*ebaecc14Sdanielk1977} 190*ebaecc14Sdanielk1977 191*ebaecc14Sdanielk1977proc rtree_treedump {db zTab} { 192*ebaecc14Sdanielk1977 set d [rtree_depth $db $zTab] 193*ebaecc14Sdanielk1977 rtree_nodetreedump $db $zTab "" $d 1 194*ebaecc14Sdanielk1977} 195*ebaecc14Sdanielk1977 196