d.rast.edit.tcl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. if {[array get env GISBASE] == ""} {
  2. puts stderr "You must be in GRASS GIS to run this program."
  3. exit 1
  4. }
  5. if {$tcl_platform(platform) == "windows"} {
  6. set stderr NUL:
  7. } else {
  8. set stderr @stderr
  9. }
  10. set outmap $env(GIS_OPT_OUTPUT)
  11. set inmap $env(GIS_OPT_INPUT)
  12. set aspect $env(GIS_OPT_ASPECT)
  13. set width $env(GIS_OPT_WIDTH)
  14. set height $env(GIS_OPT_HEIGHT)
  15. set size $env(GIS_OPT_SIZE)
  16. set rows $env(GIS_OPT_ROWS)
  17. set cols $env(GIS_OPT_COLS)
  18. set status(row) ""
  19. set status(col) ""
  20. set status(x) ""
  21. set status(y) ""
  22. set status(value) ""
  23. set status(aspect) ""
  24. set brush "*"
  25. set origin(x) 0
  26. set origin(y) 0
  27. set finalized false
  28. proc initialize {} {
  29. global tempbase tempfile tempreg tempmap env stderr
  30. global inmap outmap
  31. set tempbase [exec g.tempfile pid=[pid]]
  32. file delete $tempbase
  33. set tempfile $tempbase.ppm
  34. set tempreg tmp.d.rast.edit
  35. set tempmap tmp.d.rast.edit
  36. exec g.region --q --o save=$tempreg 2>$stderr
  37. set env(WIND_OVERRIDE) $tempreg
  38. exec g.copy --q --o rast=$inmap,$outmap 2>$stderr
  39. exec r.colors --q map=$outmap rast=$inmap 2>$stderr
  40. }
  41. proc finalize {} {
  42. global tempfile tempreg tempmap stderr finalized
  43. if {$finalized} return
  44. save_map
  45. file delete $tempfile
  46. exec g.remove --q rast=$tempmap region=$tempreg 2>$stderr
  47. set finalized true
  48. exit 0
  49. }
  50. proc force_window {} {
  51. global origin rows cols total
  52. if {$origin(x) < 0} {set origin(x) 0}
  53. if {$origin(x) > $total(cols) - $cols} {set origin(x) [expr $total(cols) - $cols]}
  54. if {$origin(y) < 0} {set origin(y) 0}
  55. if {$origin(y) > $total(rows) - $rows} {set origin(y) [expr $total(rows) - $rows]}
  56. }
  57. proc set_window {x y} {
  58. global origin rows cols
  59. set origin(x) [expr [.overview.canvas canvasx $x] - $cols / 2]
  60. set origin(y) [expr [.overview.canvas canvasy $y] - $rows / 2]
  61. force_window
  62. set x0 $origin(x)
  63. set y0 $origin(y)
  64. set x1 [expr $x0 + $cols]
  65. set y1 [expr $y0 + $rows]
  66. .overview.canvas delete window
  67. .overview.canvas create rectangle $x0 $y0 $x1 $y1 -dash {4 4} -tags window
  68. }
  69. proc update_window {} {
  70. global wind total origin rows cols
  71. set x0 $origin(x)
  72. set y0 $origin(y)
  73. set x1 [expr $x0 + $cols]
  74. set y1 [expr $y0 + $rows]
  75. set wind(n) [expr $total(n) - $y0 * $total(nsres)]
  76. set wind(s) [expr $total(n) - $y1 * $total(nsres)]
  77. set wind(w) [expr $total(w) + $x0 * $total(ewres)]
  78. set wind(e) [expr $total(w) + $x1 * $total(ewres)]
  79. set wind(rows) $rows
  80. set wind(cols) $cols
  81. }
  82. proc change_window {} {
  83. save_map
  84. update_window
  85. load_map
  86. load_aspect
  87. refresh_canvas
  88. }
  89. proc create_overview {} {
  90. global inmap outmap stderr env total rows cols tempfile
  91. exec g.region --q rast=$inmap 2>$stderr
  92. exec r.out.ppm --q $inmap out=$tempfile 2>$stderr
  93. set reg [exec g.region --q -g 2>$stderr]
  94. set reg [regsub -all {[\r\n]+} $reg { }]
  95. set reg [regsub -all {=} $reg { }]
  96. array set total $reg
  97. image create photo overview -file $tempfile
  98. file delete $tempfile
  99. toplevel .overview
  100. wm title .overview "d.rast.edit overview ($inmap)"
  101. set w $total(cols)
  102. set h $total(rows)
  103. canvas .overview.canvas -width $w -height $h -scrollregion [list 0 0 $w $h] \
  104. -xscrollcommand {.overview.xscroll set} -yscrollcommand {.overview.yscroll set}
  105. scrollbar .overview.xscroll -orient horizontal -command {.overview.canvas xview}
  106. scrollbar .overview.yscroll -orient vertical -command {.overview.canvas yview}
  107. if {$cols > $total(cols)} {set cols $total(cols)}
  108. if {$rows > $total(rows)} {set rows $total(rows)}
  109. force_window
  110. .overview.canvas create image 0 0 -anchor nw -image overview -tags image
  111. .overview.canvas create rectangle 0 0 $cols $rows -dash {4 4} -tags window
  112. grid .overview.canvas .overview.yscroll -sticky nsew
  113. grid .overview.xscroll -sticky nsew
  114. grid rowconfigure .overview 0 -weight 1
  115. grid columnconfigure .overview 0 -weight 1
  116. bind .overview.canvas <ButtonPress-1> { set_window %x %y }
  117. bind .overview.canvas <B1-Motion> { set_window %x %y }
  118. bind .overview.canvas <ButtonRelease-1> { set_window %x %y ; change_window }
  119. bind .overview <Destroy> { finalize }
  120. }
  121. proc read_header {infile window} {
  122. upvar \#0 $window wind
  123. regexp {^north: *([0-9]+)$} [gets $infile] dummy wind(n)
  124. regexp {^south: *([0-9]+)$} [gets $infile] dummy wind(s)
  125. regexp {^east: *([0-9]+)$} [gets $infile] dummy wind(e)
  126. regexp {^west: *([0-9]+)$} [gets $infile] dummy wind(w)
  127. regexp {^rows: *([0-9]+)$} [gets $infile] dummy wind(rows)
  128. regexp {^cols: *([0-9]+)$} [gets $infile] dummy wind(cols)
  129. }
  130. proc read_data {infile array} {
  131. global wind
  132. upvar \#0 $array values
  133. for {set row 0} {$row < $wind(rows)} {incr row} {
  134. gets $infile line
  135. set col 0
  136. foreach elem $line {
  137. set values($row,$col) $elem
  138. incr col
  139. }
  140. }
  141. }
  142. proc clear_changes {} {
  143. global wind changed
  144. for {set row 0} {$row < $wind(rows)} {incr row} {
  145. for {set col 0} {$col < $wind(cols)} {incr col} {
  146. set changed($row,$col) 0
  147. }
  148. }
  149. }
  150. proc load_map {} {
  151. global tempfile wind values changed colors inmap stderr
  152. exec g.region --q n=$wind(n) s=$wind(s) e=$wind(e) w=$wind(w) \
  153. rows=$wind(rows) cols=$wind(cols) 2>$stderr
  154. set infile [open "|r.out.ascii --q input=$inmap 2>$stderr" r]
  155. read_header $infile wind
  156. read_data $infile values
  157. close $infile
  158. clear_changes
  159. exec r.out.ppm --q input=$inmap output=$tempfile 2>$stderr
  160. image create photo colorimg -file $tempfile
  161. file delete $tempfile
  162. for {set row 0} {$row < $wind(rows)} {incr row} {
  163. for {set col 0} {$col < $wind(cols)} {incr col} {
  164. set val $values($row,$col)
  165. if {[array get colors $val] != ""} continue
  166. set pix [colorimg get $col $row]
  167. set r [lindex $pix 0]
  168. set g [lindex $pix 1]
  169. set b [lindex $pix 2]
  170. set color [format "#%02x%02x%02x" $r $g $b]
  171. set colors($val) $color
  172. }
  173. }
  174. image delete colorimg
  175. }
  176. proc load_aspect {} {
  177. global wind angles aspect stderr
  178. if {$aspect == ""} return
  179. set infile [open "|r.out.ascii --q input=$aspect 2>$stderr" r]
  180. read_header $infile dummy
  181. read_data $infile angles
  182. close $infile
  183. }
  184. proc save_map {} {
  185. global inmap outmap tempmap stderr
  186. global wind values changed
  187. set outfile [open "|r.in.ascii --q --o input=- output=$tempmap 2>$stderr" w]
  188. puts $outfile "north: $wind(n)"
  189. puts $outfile "south: $wind(s)"
  190. puts $outfile "east: $wind(e)"
  191. puts $outfile "west: $wind(w)"
  192. puts $outfile "rows: $wind(rows)"
  193. puts $outfile "cols: $wind(cols)"
  194. for {set row 0} {$row < $wind(rows)} {incr row} {
  195. for {set col 0} {$col < $wind(cols)} {incr col} {
  196. if {$col > 0} {
  197. puts -nonewline $outfile " "
  198. }
  199. if {$changed($row,$col)} {
  200. puts -nonewline $outfile "$values($row,$col)"
  201. } else {
  202. puts -nonewline $outfile "*"
  203. }
  204. }
  205. puts $outfile ""
  206. }
  207. close $outfile
  208. exec g.region --q rast=$inmap 2>$stderr
  209. exec r.patch --q --o input=$tempmap,$outmap output=$outmap 2>$stderr
  210. exec r.colors --q map=$outmap rast=$inmap 2>$stderr
  211. exec g.remove --q rast=$tempmap 2>$stderr
  212. }
  213. proc force_color {val} {
  214. global tempfile tempreg tempmap colors inmap stderr env
  215. exec g.region --q rows=1 cols=1 2>$stderr
  216. exec r.mapcalc "$tempmap = $val" 2>$stderr
  217. exec r.colors --q map=$tempmap rast=$inmap 2>$stderr
  218. exec r.out.ppm --q $tempmap out=$tempfile 2>$stderr
  219. exec g.remove --q rast=$tempmap 2>$stderr
  220. image create photo tempimg -file $tempfile
  221. file delete $tempfile
  222. set pix [tempimg get 0 0]
  223. set r [lindex $pix 0]
  224. set g [lindex $pix 1]
  225. set b [lindex $pix 2]
  226. set color [format "#%02x%02x%02x" $r $g $b]
  227. set colors($val) $color
  228. image delete tempimg
  229. }
  230. proc get_color {val} {
  231. global colors
  232. if {[array get colors $val] == ""} {
  233. if {[catch {force_color $val}]} {
  234. set colors($val) "#ffffff"
  235. }
  236. }
  237. return $colors($val)
  238. }
  239. proc brush_update {} {
  240. global brush colors
  241. if {$brush == "*"} {
  242. .tools.color configure -bitmap gray12 -foreground black
  243. } else {
  244. .tools.color configure -bitmap gray75 -foreground [get_color $brush]
  245. }
  246. }
  247. proc current_cell {} {
  248. global canvas
  249. set row ""
  250. set col ""
  251. set tags [.canvas itemcget current -tags]
  252. foreach tag $tags {
  253. if {[regexp {row-([0-9]+)} $tag dummy r]} {set row $r}
  254. if {[regexp {col-([0-9]+)} $tag dummy c]} {set col $c}
  255. }
  256. return [list $row $col]
  257. }
  258. proc cell_enter {} {
  259. global status
  260. global wind values angles
  261. set pos [current_cell]
  262. set row [lindex $pos 0]
  263. set col [lindex $pos 1]
  264. if {$row == "" || $col == ""} return
  265. set status(row) $row
  266. set status(col) $col
  267. set status(x) [expr {$wind(e) + ($col + 0.5) * ($wind(e) - $wind(w)) / $wind(cols)}]
  268. set status(y) [expr {$wind(n) - ($row + 0.5) * ($wind(n) - $wind(s)) / $wind(rows)}]
  269. set status(value) $values($row,$col)
  270. if {[array exists angles]} {
  271. set status(aspect) $angles($row,$col)
  272. }
  273. }
  274. proc cell_leave {} {
  275. global status
  276. set status(row) ""
  277. set status(col) ""
  278. set status(x) ""
  279. set status(y) ""
  280. set status(value) ""
  281. set status(aspect) ""
  282. }
  283. proc cell_get {} {
  284. global brush values colors
  285. set pos [current_cell]
  286. set row [lindex $pos 0]
  287. set col [lindex $pos 1]
  288. set brush $values($row,$col)
  289. brush_update
  290. }
  291. proc cell_set {} {
  292. global canvas brush values changed colors
  293. set pos [current_cell]
  294. set row [lindex $pos 0]
  295. set col [lindex $pos 1]
  296. set val $brush
  297. set values($row,$col) $val
  298. set changed($row,$col) 1
  299. set cell [.canvas find withtag "(cell&&row-$row&&col-$col)"]
  300. if {$val == "*"} {
  301. set fill black
  302. set stipple gray12
  303. } else {
  304. set fill [get_color $val]
  305. set stipple ""
  306. }
  307. .canvas itemconfigure $cell -outline white -fill $fill -stipple $stipple
  308. }
  309. proc refresh_canvas {} {
  310. global wind size values colors angles
  311. .canvas delete all
  312. set aspect [array exists angles]
  313. set pi [expr 2 * acos(0)]
  314. for {set row 0} {$row < $wind(rows)} {incr row} {
  315. for {set col 0} {$col < $wind(cols)} {incr col} {
  316. set x0 [expr $col * $size + 1]
  317. set x1 [expr $x0 + $size - 1]
  318. set y0 [expr $row * $size + 1]
  319. set y1 [expr $y0 + $size - 1]
  320. if {$values($row,$col) == "*"} {
  321. set color black
  322. set stipple gray12
  323. } else {
  324. set color $colors($values($row,$col))
  325. set stipple ""
  326. }
  327. .canvas create polygon $x0 $y0 $x1 $y0 $x1 $y1 $x0 $y1 \
  328. -fill $color -stipple $stipple \
  329. -outline black -activeoutline red \
  330. -tags [list cell row-$row col-$col]
  331. if {! $aspect} continue
  332. if {$angles($row,$col) == "*"} continue
  333. set cx [expr ($x0 + $x1) / 2]
  334. set cy [expr ($y0 + $y1) / 2]
  335. set a [expr $angles($row,$col) * $pi / 180]
  336. set dx [expr cos($a) * $size / 2]
  337. set dy [expr - sin($a) * $size / 2]
  338. set x0 [expr $cx - $dx]
  339. set y0 [expr $cy - $dy]
  340. set x1 [expr $cx + $dx]
  341. set y1 [expr $cy + $dy]
  342. .canvas create line $x0 $y0 $x1 $y1 \
  343. -arrow last \
  344. -disabledfill white -state disabled \
  345. -tags [list arrow row-$row col-$col]
  346. }
  347. }
  348. }
  349. proc make_canvas {} {
  350. global canvas values colors angles rows cols
  351. global size width height
  352. set cx [expr $width / $cols]
  353. set cy [expr $height / $rows]
  354. set sz [expr ($cx > $cy) ? $cx : $cy]
  355. if {$size < $sz} {set size $sz}
  356. set w [expr $cols * $size]
  357. set h [expr $rows * $size]
  358. canvas .canvas -width $width -height $height -scrollregion [list 0 0 $w $h] \
  359. -xscrollcommand {.xscroll set} -yscrollcommand {.yscroll set}
  360. scrollbar .xscroll -orient horizontal -command {.canvas xview}
  361. scrollbar .yscroll -orient vertical -command {.canvas yview}
  362. .canvas bind cell <Any-Enter> { cell_enter }
  363. .canvas bind cell <Any-Leave> { cell_leave }
  364. .canvas bind cell <Button-1> { cell_set }
  365. .canvas bind cell <Button-3> { cell_get }
  366. bind .canvas <Any-Leave> { cell_leave }
  367. }
  368. proc make_ui {} {
  369. global canvas inmap
  370. wm title . "d.rast.edit ($inmap)"
  371. bind . <Destroy> { finalize }
  372. menu .menu -tearoff 0
  373. menu .menu.file -tearoff 0
  374. .menu add cascade -label "File" -menu .menu.file -underline 0
  375. .menu.file add command -label "Save" -underline 0 -command {save_map}
  376. .menu.file add command -label "Exit" -underline 1 -command {destroy .}
  377. . configure -menu .menu
  378. frame .status
  379. label .status.row_l -text "Row:"
  380. entry .status.row -textvariable status(row) -width 6
  381. label .status.col_l -text "Col:"
  382. entry .status.col -textvariable status(col) -width 6
  383. label .status.x_l -text "X:"
  384. entry .status.x -textvariable status(x) -width 10
  385. label .status.y_l -text "Y:"
  386. entry .status.y -textvariable status(y) -width 10
  387. label .status.value_l -text "Value:"
  388. entry .status.value -textvariable status(value) -width 10
  389. label .status.aspect_l -text "Aspect:"
  390. entry .status.aspect -textvariable status(aspect) -width 10
  391. pack \
  392. .status.row_l .status.row \
  393. .status.col_l .status.col \
  394. .status.x_l .status.x \
  395. .status.y_l .status.y \
  396. .status.value_l .status.value \
  397. .status.aspect_l .status.aspect \
  398. -side left
  399. frame .tools
  400. label .tools.value_l -text "New value:"
  401. entry .tools.value -textvariable brush
  402. label .tools.color_l -text "Color:"
  403. label .tools.color -bitmap gray12 -foreground black
  404. pack \
  405. .tools.value_l .tools.value \
  406. .tools.color_l .tools.color \
  407. -side left
  408. bind .tools.value <KeyPress-Return> brush_update
  409. grid .canvas .yscroll -sticky nsew
  410. grid .xscroll -sticky nsew
  411. grid .status -sticky nsew
  412. grid .tools -sticky nsew
  413. grid rowconfigure . 0 -weight 1
  414. grid columnconfigure . 0 -weight 1
  415. }
  416. initialize
  417. create_overview
  418. make_canvas
  419. make_ui
  420. update_window
  421. load_map
  422. load_aspect
  423. refresh_canvas