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