pathplan.tcl 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. #!/bin/sh
  2. # next line is a comment in tcl \
  3. exec wish "$0" ${1+"$@"}
  4. package require Tkspline
  5. package require Tclpathplan
  6. ########################################################################
  7. # shape - a shape drawing tool for testing the spring layout engine
  8. #
  9. # John Ellson - [email protected] - September 12, 1996
  10. # requires dash patch
  11. # Radio buttons select the drawing mode.
  12. # "draw" - draw a closed and filled polygon
  13. # "stretch" - move a vertex of a polygon, also
  14. # insert additional vertices with subsequent button 1 clicks
  15. # "collapse" - delete a vertex of a polygon (except last 2)
  16. # "move" - move a complete polygon without altering
  17. # its shape, or move the whole canvas.
  18. # "rotate" - rotate a polygon about its center
  19. # "scale" - scale a polygon
  20. # "clone" - copy an existing shape
  21. # "delete" - remove an entire polygon object
  22. # "path" - draw a line between two polygons and the
  23. # system will respond with the shortest path
  24. # around all the other polygons.
  25. # "bezier path" - draw a line between two polygons and the
  26. # system will respond with the spline that follows
  27. # the shortest path around all the other polygons.
  28. # "id" - identify a polygon. mostly for debugging.
  29. # "draw," "stretch," "move," "path", "bezier path", and "clone" use
  30. # button 1 for first though penultimate points, then button 2 to
  31. # complete the operation.
  32. # "rotate" and "scale" use the button 1 to grab a polygon and
  33. # button 2 to complete the operation.
  34. # "collapse" and "delete" just use button 1
  35. # "stretch, " "move, " "collapse," and "delete" operations all act on
  36. # a highlighted object
  37. # "grid" constrains the locations of input points to lie on a grid of
  38. # the specified spacing (in pixels).
  39. # Future...
  40. #
  41. # some other possible operations:
  42. # regularize (arrange points on circle)
  43. # transformations: skew, distort, scale
  44. # label text (inside or relative)
  45. # fill & outline color
  46. # fill & outline stipple
  47. # fill tile image
  48. # outline dash (mark, space offset)
  49. # outline width
  50. # number of peripheries
  51. #
  52. # group/ungroup
  53. #
  54. # raise/lower (not required if no overlap)
  55. #
  56. # constraints: no overlap
  57. # no twist
  58. #
  59. # resources: shape library
  60. # stipple patterns
  61. # tile images
  62. #
  63. ########################################################################
  64. set splinecolor orange
  65. set showmouse off
  66. proc nextpoint {vc c wx wy} {
  67. global id mode oldx oldy gain0 angle0 index grid
  68. set x [$c canvasx $wx]
  69. set y [$c canvasy $wy]
  70. set gx [expr $grid * int(($x / $grid) + 0.5)]
  71. set gy [expr $grid * int(($y / $grid) + 0.5)]
  72. switch $mode {
  73. draw {
  74. if [info exists id] {
  75. $c insert $id 0 [list $gx $gy]
  76. } {
  77. set id [$c create polygon $gx $gy $gx $gy \
  78. -fill red -outline #ffc000]
  79. }
  80. }
  81. stretch {
  82. if [info exists id] {
  83. $c insert $id $index [list $gx $gy]
  84. } {
  85. set id [$c find withtag current]
  86. if {$id == {}} {
  87. unset id
  88. } {
  89. set index [$c index $id @$x,$y]
  90. $c dchars $id $index
  91. $c insert $id $index [list $gx $gy]
  92. }
  93. }
  94. }
  95. collapse {
  96. set id [$c find withtag current]
  97. if {$id != {}} {
  98. set index [$c index $id @$x,$y]
  99. if {[llength [$c coords $id]] > 4} {$c dchars $id $index}
  100. $vc coords [lindex [$c gettags $id] 0] [$c coords $id]
  101. }
  102. unset id
  103. }
  104. clone {
  105. if [info exists id] {
  106. set tag [$vc insert [$c coords $id]]
  107. $c addtag $tag withtag $id
  108. }
  109. set t [$c find withtag current]
  110. if {$t != {}} {
  111. set id [$c create [$c type $t] [$c coords $t]]
  112. foreach config [$c itemconfigure $t] {
  113. foreach {config . . . val} $config {break}
  114. if {$config != "-tags"} {
  115. $c itemconfigure $id $config $val
  116. }
  117. }
  118. set oldx $gx
  119. set oldy $gy
  120. }
  121. }
  122. move {
  123. set id [$c find withtag current]
  124. if {$id == {}} {
  125. $c scan mark $wx $wy
  126. } {
  127. set oldx $gx
  128. set oldy $gy
  129. }
  130. }
  131. scale {
  132. set id [$c find withtag current]
  133. if {$id == {}} {
  134. unset id
  135. } {
  136. foreach {oldx oldy} \
  137. [$vc center [lindex [$c gettags $id] 0]] {break}
  138. set dx [expr $oldx-$x]
  139. set dy [expr $oldy-$y]
  140. set gain0 [expr sqrt($dx*$dx+$dy*$dy)]
  141. }
  142. }
  143. rotate {
  144. set id [$c find withtag current]
  145. if {$id == {}} {
  146. unset id
  147. } {
  148. foreach {oldx oldy} [$vc center [lindex [$c gettags $id] 0]] {
  149. break
  150. }
  151. set angle0 [expr atan2($x-$oldx, $oldy-$y)]
  152. }
  153. }
  154. path {
  155. if [info exists id] {
  156. set path [$c coords $id]
  157. if [catch {$vc path $path} path] {
  158. puts $path
  159. } {
  160. $c coords $id $path
  161. $c itemconfigure $id -fill red
  162. set id [$c create line $x $y $x $y \
  163. -fill red -state disabled]
  164. }
  165. } {
  166. set id [$c create line $gx $gy $gx $gy \
  167. -fill red -state disabled]
  168. }
  169. }
  170. bpath {
  171. if [info exists id] {
  172. set path [$c coords $id]
  173. if [catch {$vc bpath $path} path] {
  174. puts $path
  175. } {
  176. $c coords $id $path
  177. $c itemconfigure $id -fill orange
  178. set id [$c create line $x $y $x $y \
  179. -smooth spline -fill orange -state disabled]
  180. }
  181. } {
  182. set id [$c create line $gx $gy $gx $gy \
  183. -smooth spline -fill orange -state disabled]
  184. }
  185. }
  186. delete {
  187. $vc remove [lindex [$c gettags current] 0]
  188. $c delete current
  189. }
  190. triangulate {
  191. global mode
  192. if {[$vc bind triangle] == {}} {
  193. $vc bind triangle {
  194. if {$mode == "triangulate"} {
  195. $c create polygon %t -tag triangles \
  196. -fill {} -outline white -width 2
  197. } {
  198. $c create polygon %t -tag triangles \
  199. -fill {} -outline white -width 2 -state hidden
  200. }
  201. }
  202. }
  203. if {$mode == "triangulate"} {
  204. $c itemconfigure triangles -state normal
  205. } {
  206. $c itemconfigure triangles -state hidden
  207. }
  208. set t [$vc find $x $y]
  209. if {$t != {}} {
  210. $vc triangulate $t
  211. }
  212. }
  213. id {
  214. set t [$vc find $x $y]
  215. if {$t == {}} {
  216. puts "at: $x $y ....nothing"
  217. } {
  218. puts "at: $x $y\nid: $t\ncoords: [$vc coords $t]"
  219. }
  220. }
  221. }
  222. }
  223. proc lastpoint {vc c args} {
  224. global id mode
  225. if [info exists id] {
  226. switch $mode {
  227. draw {
  228. $c itemconfigure $id -fill darkgreen \
  229. -outline yellow -activeoutline #ffc000
  230. set tag [$vc insert [$c coords $id]]
  231. $c addtag $tag withtag $id
  232. }
  233. clone {
  234. set tag [$vc insert [$c coords $id]]
  235. $c addtag $tag withtag $id
  236. }
  237. move - stretch - rotate - scale {
  238. set t [lindex [$c gettags $id] 0]
  239. if {$t != {} && $t != "current"} {
  240. $vc coords $t [$c coords $id]
  241. }
  242. }
  243. path {
  244. set path [$c coords $id]
  245. if [catch {$vc path $path} path] {
  246. puts $path
  247. $c delete $id
  248. } {
  249. $c coords $id $path
  250. $c itemconfigure $id -fill
  251. }
  252. }
  253. bpath {
  254. set path [$c coords $id]
  255. if [catch {$vc bpath $path} path] {
  256. puts $path
  257. $c delete $id
  258. } {
  259. $c coords $id $path
  260. $c itemconfigure $id -fill red
  261. }
  262. }
  263. }
  264. $c configure -scrollregion [$c bbox all]
  265. unset id
  266. }
  267. }
  268. proc motion {vc c wx wy} {
  269. global id mode oldx oldy gain0 angle0 index grid showmouse
  270. set x [$c canvasx $wx]
  271. set y [$c canvasy $wy]
  272. if {$showmouse == "on"} {
  273. puts -nonewline stderr "\r$x,$y [list [$vc find $x $y]] "
  274. }
  275. if [info exists id] {
  276. switch $mode {
  277. draw {
  278. set gx [expr $grid * int(($x / $grid) + 0.5)]
  279. set gy [expr $grid * int(($y / $grid) + 0.5)]
  280. $c dchars $id 0
  281. $c insert $id 0 [list $gx $gy]
  282. }
  283. path {
  284. $c dchars $id 0
  285. $c insert $id 0 [list $x $y]
  286. }
  287. bpath {
  288. $c dchars $id 0
  289. $c insert $id 0 [list $x $y]
  290. }
  291. move - clone {
  292. if {$id == {}} {
  293. $c scan dragto $wx $wy 1
  294. } {
  295. set gx [expr $grid * int(($x / $grid) + 0.5)]
  296. set gy [expr $grid * int(($y / $grid) + 0.5)]
  297. $c move $id [expr $gx - $oldx] [expr $gy - $oldy]
  298. set oldx $gx
  299. set oldy $gy
  300. }
  301. }
  302. stretch {
  303. set gx [expr $grid * int(($x / $grid) + 0.5)]
  304. set gy [expr $grid * int(($y / $grid) + 0.5)]
  305. $c dchars $id $index
  306. $c insert $id $index [list $gx $gy]
  307. }
  308. scale {
  309. set t [lindex [$c gettags $id] 0]
  310. set dx [expr $x-$oldx]
  311. set dy [expr $y-$oldy]
  312. set gain [expr sqrt($dx*$dx+$dy*$dy)/20]
  313. $c coords $id [$vc scale $t $gain]
  314. }
  315. rotate {
  316. set t [lindex [$c gettags $id] 0]
  317. set alpha [expr atan2($x-$oldx,$oldy-$y) - $angle0]
  318. $c coords $id [$vc rotate $t $alpha]
  319. }
  320. }
  321. }
  322. }
  323. proc clearpaths {vc c} {
  324. catch { $c delete triangles }
  325. foreach i [$c find all] {
  326. set t [$c type $i]
  327. if {$t == "line"} {$c delete $i}
  328. }
  329. }
  330. proc clearall {vc c} {
  331. catch { $c delete triangles }
  332. foreach i [$c find all] {
  333. if {[$c type $i] == "polygon"} {$vc remove [lindex [$c gettags $i] 0]}
  334. $c delete $i
  335. }
  336. }
  337. proc loadpaths {vc c file} {
  338. if [catch {open $file r} f] {
  339. error "unable to open file for read: $file"
  340. }
  341. clearpaths $vc $c
  342. while {![eof $f]} {
  343. set path [gets $f]
  344. if {$path == {}} {continue}
  345. if [catch {$vc bpath $path} path] {
  346. puts $path
  347. } {
  348. $c create line $path \
  349. -smooth spline -fill #ff00c0 -state disabled
  350. }
  351. }
  352. close $f
  353. $c configure -scrollregion [$c bbox all]
  354. }
  355. proc loadvconfig {vc c file} {
  356. if [catch {open $file r} f] {
  357. error "unable to open file for read: $file"
  358. }
  359. clearall $vc $c
  360. while {![eof $f]} {
  361. set coords [string trim [gets $f]]
  362. if {$coords == {}} {continue}
  363. set tag [$vc insert $coords]
  364. $c create polygon $coords \
  365. -tag $tag \
  366. -fill darkgreen \
  367. -outline yellow \
  368. -activeoutline #ffc000
  369. }
  370. close $f
  371. $c configure -scrollregion [$c bbox all]
  372. }
  373. proc savepaths {vc c file} {
  374. if [catch {open $file w} f] {
  375. error "unable to open file for write: $file"
  376. }
  377. foreach i [$c find all] {
  378. set t [$c type $i]
  379. if {$t == "line"} {
  380. set path [$c coords $i]
  381. set l [llength $path]
  382. set x1 [lindex $path 0]
  383. set y1 [lindex $path 1]
  384. set x2 [lindex $path [incr l -2]]
  385. set y2 [lindex $path [incr l]]
  386. puts $f "$x1 $y1 $x2 $y2"
  387. }
  388. }
  389. close $f
  390. }
  391. proc savevconfig {vc c file} {
  392. if [catch {open $file w} f] {
  393. error "unable to open file for write: $file"
  394. }
  395. foreach id [$vc list] {
  396. puts $f [$vc coords $id]
  397. }
  398. close $f
  399. }
  400. proc nextfile {} {
  401. global filename
  402. set filename [file join [file dirname $filename] [file tail $filename]]
  403. set files [glob [file join [file dirname $filename] *[file extension $filename]]]
  404. set filename [lindex $files [expr ([lsearch $files $filename] + 1) % [llength $files]]]
  405. }
  406. set vc [vgpane]
  407. set mode draw
  408. set filename "pathplan.tcl.data/unknown.dat"
  409. frame .fl
  410. set a [frame .fl.a]
  411. set b [frame .fl.b]
  412. set c [canvas $a.c \
  413. -relief sunken \
  414. -borderwidth 2 \
  415. -bg lightblue \
  416. -xscrollcommand "$b.h set" \
  417. -yscrollcommand "$a.v set"]
  418. scrollbar $b.h -command "$c xview" -orient horiz
  419. scrollbar $a.v -command "$c yview"
  420. frame $b.pad \
  421. -width [expr [$a.v cget -width] + \
  422. [$a.v cget -bd]*2 + [$a.v cget -highlightthickness]*2 ] \
  423. -height [expr [$b.h cget -width] + \
  424. [$b.h cget -bd]*2 + [.fl.b.h cget -highlightthickness]*2 ]
  425. frame .fr
  426. frame .fr.bpath
  427. pack [radiobutton .fr.bpath.bpath -text "bezier path" -value bpath \
  428. -highlightthickness 0 -anchor w -variable mode] \
  429. -side left -anchor w -fill x
  430. pack [scale .fr.grid -orient horizontal -label grid -variable grid \
  431. -highlightthickness 0 -from 1 -to 100] \
  432. [radiobutton .fr.draw -text draw -value draw \
  433. -highlightthickness 0 -anchor w -variable mode] \
  434. [radiobutton .fr.stretch -text stretch -value stretch \
  435. -highlightthickness 0 -anchor w -variable mode] \
  436. [radiobutton .fr.collapse -text collapse -value collapse \
  437. -highlightthickness 0 -anchor w -variable mode] \
  438. [radiobutton .fr.clone -text clone -value clone \
  439. -highlightthickness 0 -anchor w -variable mode] \
  440. [radiobutton .fr.move -text move -value move \
  441. -highlightthickness 0 -anchor w -variable mode] \
  442. [radiobutton .fr.rotate -text rotate -value rotate \
  443. -highlightthickness 0 -anchor w -variable mode] \
  444. [radiobutton .fr.scale -text scale -value scale \
  445. -highlightthickness 0 -anchor w -variable mode] \
  446. [radiobutton .fr.delete -text delete -value delete \
  447. -highlightthickness 0 -anchor w -variable mode] \
  448. [radiobutton .fr.path -text path -value path \
  449. -highlightthickness 0 -anchor w -variable mode] \
  450. .fr.bpath \
  451. [radiobutton .fr.id -text id -value id \
  452. -highlightthickness 0 -anchor w -variable mode] \
  453. [radiobutton .fr.triangulate -text triangulate -value triangulate \
  454. -highlightthickness 0 -anchor w -variable mode] \
  455. -anchor w -fill x
  456. frame .fr.load
  457. pack [button .fr.load.load -text load \
  458. -highlightthickness 0 -command "loadvconfig $vc $c \$filename"] \
  459. [button .fr.load.paths -text loadpaths \
  460. -highlightthickness 0 -command "loadpaths $vc $c \$filename"] \
  461. -side left -fill x -expand true
  462. frame .fr.save
  463. pack [button .fr.save.save -text save \
  464. -highlightthickness 0 -command "savevconfig $vc $c \$filename"] \
  465. [button .fr.save.paths -text savepaths \
  466. -highlightthickness 0 -command "savepaths $vc $c \$filename"] \
  467. -side left -fill x -expand true
  468. frame .fr.clear
  469. pack [button .fr.clear.all -text clear -command "clearall $vc $c" \
  470. -highlightthickness 0] \
  471. [button .fr.clear.paths -text clearpaths -command "clearpaths $vc $c" \
  472. -highlightthickness 0] \
  473. -side left -fill x -expand true
  474. frame .fr.file
  475. pack [entry .fr.file.name -textvar filename -highlightthickness 0] \
  476. -side left -fill x -expand true
  477. pack [button .fr.file.next -text next \
  478. -highlightthickness 0 -command "nextfile"] \
  479. -side left
  480. frame .fr.quitdebug
  481. pack [button .fr.quitdebug.debug -text debug \
  482. -highlightthickness 0 -command "$vc debug"] \
  483. [button .fr.quitdebug.quit -text quit \
  484. -highlightthickness 0 -command "exit"] \
  485. -side left -fill x -expand true
  486. pack .fr.quitdebug .fr.clear .fr.save .fr.load .fr.file \
  487. [label .fr.flabel -anchor w -text "file"] \
  488. [entry .fr.coordinates -textvar coordinates -highlightthickness 0] \
  489. [label .fr.clabel -anchor w -text "coordinates"] \
  490. -side bottom -fill x -expand true
  491. pack $a.v -side right -fill y
  492. pack $c -side left -fill both -expand true
  493. pack $b.h -side left -fill x -expand true
  494. pack $b.pad -side right
  495. pack $b -side bottom -fill x
  496. pack $a -side top -fill both -expand true
  497. pack .fl -side left -fill both -expand true
  498. pack .fr -side left -fill y
  499. bind $c <1> "nextpoint $vc $c %x %y"
  500. bind $c <2> "lastpoint $vc $c"
  501. bind $c <Motion> "motion $vc $c %x %y"
  502. trace variable mode w "lastpoint $vc $c"
  503. bind .fr.file.name <Return> {
  504. .fr.loadsave.load flash
  505. loadvconfig $vc $c $filename
  506. }
  507. bind .fr.coordinates <Return> {
  508. if {$coordinates == {}} {continue}
  509. set coords [split $coordinates]
  510. set coordinates {}
  511. switch $mode {
  512. draw {
  513. if [catch {$vc insert $coords} tag] {
  514. puts $tag
  515. } {
  516. $c create polygon $coords \
  517. -fill darkgreen \
  518. -outline yellow \
  519. -activeoutline #ffc000 \
  520. -tag $tag
  521. }
  522. }
  523. path {
  524. if [catch {$vc path $coords} coords] {
  525. puts $coords
  526. } {
  527. $c create line $coords -fill #ff00c0 -state disabled
  528. }
  529. }
  530. bpath {
  531. if [catch {$vc bpath $coords} coords] {
  532. puts $coords
  533. } {
  534. $c create line $coords \
  535. -smooth spline -fill orange -state disabled
  536. }
  537. }
  538. }
  539. }
  540. proc balloon_help {w msg} {
  541. bind $w <Enter> "after 1000 \"balloon_help_aux %W [list $msg]\""
  542. bind $w <Leave> "after cancel \"balloon_help_aux %W [list $msg]\"
  543. catch {destroy %W.balloon_help}"
  544. }
  545. proc balloon_help_aux {w msg} {
  546. set t $w.balloon_help
  547. catch {destroy $t}
  548. toplevel $t
  549. wm overrideredirect $t 1
  550. pack [label $t.l -text $msg -relief groove -bd 1 -bg yellow] -fill both
  551. wm geometry $t +[expr [winfo rootx $w]+([winfo width $w]/2)]+[expr \
  552. [winfo rooty $w]+([winfo height $w]/2)]
  553. }
  554. balloon_help .fr.grid "set grid size for draw operations"
  555. balloon_help .fr.draw "draw a region. B1 foreach vertex except B2 for last"
  556. balloon_help .fr.stretch "B1 to stretch a vertex, next B1 inserts new vertex. B2 to end"
  557. balloon_help .fr.collapse "B1 collapses a vertex"
  558. balloon_help .fr.clone "each B1 creates a new clone of a region, B2 to end"
  559. balloon_help .fr.move "B1 to move, B2 to end"
  560. balloon_help .fr.rotate "B1 to rotate, B2 to end"
  561. balloon_help .fr.scale "B1 to scale, B2 to end"
  562. balloon_help .fr.delete "B1 to delete a region"
  563. balloon_help .fr.path "B1 starts a euclidean shortest path, B2 to end"
  564. balloon_help .fr.bpath.bpath "B1 starts a bezier spline path, B2 to end"
  565. balloon_help .fr.triangulate "B1 to display triangulation of a polygon"
  566. balloon_help .fr.id "print the identifier of a region"
  567. balloon_help .fr.coordinates "text entry of coordinates, alternative to button operations"
  568. balloon_help .fr.file.name "current file name, or enter new name"
  569. balloon_help .fr.file.next "next file with same directory and extension"
  570. balloon_help .fr.save.paths "save paths to file"
  571. balloon_help .fr.load.paths "load paths from file"
  572. balloon_help .fr.save.save "save regions to file"
  573. balloon_help .fr.load.load "load regions from file"
  574. balloon_help .fr.clear.all "clear canvas of all regions and paths"
  575. balloon_help .fr.clear.paths "clear canvas of all paths"
  576. balloon_help .fr.quitdebug.quit "quit this application"
  577. balloon_help .fr.quitdebug.debug "dump the vconfig"