registration.tcl
上传用户:kellyonhid
上传日期:2013-10-12
资源大小:932k
文件大小:37k
源码类别:

3D图形编程

开发平台:

Visual C++

  1. ######################################################################
  2. #
  3. # Global registration UI
  4. #
  5. ######################################################################
  6. proc globalRegistrationDialog {} {
  7.     if {[window_Activate .globalReg]} { return }
  8.     plv_globalreg init_import
  9.     # create UI window
  10.     set gr [toplevel .globalReg]
  11.     wm title $gr "Global registration"
  12.     window_Register $gr
  13.     frame $gr.file -relief groove -border 2
  14.     label $gr.file.l -text "File options" -anchor w
  15.     frame $gr.file.b
  16.     button $gr.file.b.force_reload -text "Reload" 
  17. -command "plv_globalreg re_import"
  18.     button $gr.file.b.delete -text "Delete..." 
  19. -command globalRegDeleteDialog
  20.     packchildren $gr.file.b -side left -fill x -expand true
  21.     packchildren $gr.file -side top -fill x -expand true
  22.     frame $gr.opts -relief groove -border 2
  23.     label $gr.opts.l -text "Render options" -anchor w
  24.     frame $gr.opts.b
  25.     button $gr.opts.b.showpartners -text "Show only partners" 
  26. -command {hideRegistrationNonPartners $theMesh}
  27.     button $gr.opts.b.showgroup -text "Show only group" 
  28. -command {hideRegistrationNonPartners $theMesh transitive}
  29.     packchildren $gr.opts.b -side left -fill x -expand true
  30.     frame $gr.opts.c
  31.     label $gr.opts.c.colorL -text "Color:"
  32.     tk_optionMenu $gr.opts.c.color 
  33. theColorMode gray false registration
  34.     packchildren $gr.opts.c -side left
  35.     packchildren $gr.opts -side top -fill x -expand true
  36.     frame $gr.show -relief groove -border 2
  37.     label $gr.show.l -text "Dump registered pairs" -anchor w
  38.     frame $gr.show.pairwise
  39.     button $gr.show.pairwise.point_point 
  40. -text "Pairwise (point-point)" 
  41. -command { 
  42.     badAlignDialog [plv_globalreg dumpallpairs 0 [.globalReg.show.thresh.entry get]]
  43. }
  44.     button $gr.show.pairwise.point_plane 
  45. -text "Pairwise (point-plane)" 
  46. -command { 
  47.     badAlignDialog [plv_globalreg dumpallpairs 1 [.globalReg.show.thresh.entry get]]
  48. }
  49.     packchildren $gr.show.pairwise -side left -fill x -expand true
  50.     frame $gr.show.dump
  51.     button $gr.show.dump.globalreg -text "Globalreg Error" 
  52. -command { 
  53.     badAlignDialog [plv_globalreg dumpallpairs 2 [.globalReg.show.thresh.entry get]]
  54. }
  55.     button $gr.show.dump.partners -text "Partners" 
  56. -command {dumpRegistrationPartners $theMesh}
  57.     packchildren $gr.show.dump -side left -fill x -expand true
  58. #     frame $gr.show.select
  59. #     button $gr.show.select.gr -text "Worst global to ICP" 
  60. #  -command { puts "Howdy" }
  61. #     button $gr.show.select.pw -text "Worst pairwise to ICP" 
  62. #  -command { 
  63. #      puts "Doody"
  64. #      ICPdialog
  65. #  }
  66. #     packchildren $gr.show.select -side left -fill x -expand true
  67.     frame $gr.show.thresh
  68.     label $gr.show.thresh.l -text "Show offenders threshold (mm):"
  69.     entry  $gr.show.thresh.entry 
  70.   -relief sunken -width 6
  71.     $gr.show.thresh.entry insert end 5
  72.     packchildren $gr.show.thresh -side left
  73.     frame $gr.show.npairs
  74.     label $gr.show.npairs.l -text "Pointpair counts"
  75.     button $gr.show.npairs.curr -text "Current" 
  76. -command {plv_globalreg point_pair_count $theMesh *}
  77.     button $gr.show.npairs.icp  -text "ICP dlg" 
  78. -command {plv_globalreg point_pair_count 
  79.       [globalset regICPFrom] [globalset regICPTo]}
  80.     packchildren $gr.show.npairs -side left -fill x -expand true
  81.     set p [frame $gr.show.part]
  82.     button $p.list -text "List" -command "listFewPartners $p.val"
  83.     label $p.l1 -text "meshes with fewer than"
  84.     entry $p.val -width 3
  85.     $p.val insert end 3
  86.     label $p.l2 -text "partners"
  87.     packchildren $p -side left
  88.     button $gr.show.groups -text "List connected subgroups" 
  89. -command listGroups
  90.     packchildren $gr.show -side top -fill x -expand true
  91.     frame $gr.auto -relief groove -border 2
  92.     set p [frame $gr.auto.choices]
  93.     label $p.lf -text "Auto add pairs: from" -anchor w
  94.     tk_optionMenu $gr.auto.choices.from autoFrom visible current
  95.     label $p.lt -text "to" -anchor w
  96.     tk_optionMenu $p.to autoTo visible all
  97.     packchildren $p -side left -fill x -expand 1
  98.     set f [frame $gr.auto.errorThresh]
  99.     label $f.l -text "Error threshold (mm):"
  100.     entry  $f.entry -relief sunken -width 6
  101.     $f.entry insert end 5
  102.     packchildren $f -side left -pady 2
  103.     set f [frame $gr.auto.nPairs]
  104.     label $f.l -text "Target number of pairs to calculate:"
  105.     entry $f.entry -relief sunken -width 6
  106.     $f.entry insert end 2000
  107.     packchildren $f -side left
  108.     checkbutton $gr.auto.preserve 
  109. -text "Preserve existing mesh pairs (don't recalculate)" 
  110. -variable preserveExistingInAutoAlign -anchor w
  111.     frame $gr.auto.b
  112.     button $gr.auto.b.go 
  113. -text "Go" 
  114. -command {
  115.     scz_auto_register $autoFrom $autoTo $theMesh 
  116. [.globalReg.auto.errorThresh.entry get] 
  117. [.globalReg.auto.nPairs.entry get] 
  118. $preserveExistingInAutoAlign
  119. }
  120.     packchildren $gr.auto.b -side top -anchor c
  121.     packchildren $gr.auto -side top -anchor w -fill x
  122.     frame $gr.reg -relief groove -border 2
  123.     label $gr.reg.l -text "Register:" -anchor w
  124.     frame $gr.reg.b
  125.     button $gr.reg.b.register -text "All<->All" 
  126. -command {doGlobalRegister}
  127.     button $gr.reg.b.register1 -text "Selected->all" 
  128. -command {doGlobalRegister $theMesh}
  129.     button $gr.reg.b.register12 -text "ICP 1->2" 
  130. -command {if {[winfo exists .regICP]} {
  131.     if {[_reg_check2meshes $regICPFrom $regICPTo]} {
  132. doGlobalRegister $regICPFrom $regICPTo
  133.     }
  134. } else {
  135.     tk_messageBox -title "scanalyze" -icon error 
  136. -parent .globalReg 
  137. -message "ICP dialog must be visible."
  138. }}
  139.     packchildren $gr.reg.b -side left -fill x -expand 1
  140.     frame $gr.reg.convTol
  141.     label $gr.reg.convTol.l -text "Convergence Tolerance:"
  142.     entry  $gr.reg.convTol.entry -relief sunken -width 6
  143.     $gr.reg.convTol.entry insert end .01
  144.     packchildren $gr.reg.convTol -side left -pady 2
  145.     packchildren $gr.reg -side top -fill x
  146.     packchildren $gr -side top -fill x -expand true 
  147. -pady 3 -padx 3
  148. }
  149. proc doGlobalRegister {args} {
  150.     eval plv_globalreg register [.globalReg.reg.convTol.entry get] $args
  151.     redraw 1
  152.     update idletasks
  153. }
  154. proc hideRegistrationNonPartners {mesh {trans ""}} {
  155.     if {$trans == ""} {
  156. set vis [plv_globalreg listpairsfor $mesh]
  157.     } else {
  158. set vis [plv_globalreg listpairsfor $mesh transitive]
  159.     }
  160.     eval showOnlyMesh $vis $mesh
  161. }
  162. proc dumpRegistrationPartners {mesh} {
  163.     set partner [plv_globalreg listpairsfor $mesh]
  164.     set trans [plv_globalreg listpairsfor $mesh transitive]
  165.     puts "$mesh is registered to:"
  166.     puts "directly:     $partner"
  167.     puts "transitively: $trans"
  168. }
  169. proc listFewPartners {widget} {
  170.     set min [$widget get]
  171.     foreach mesh [lsort -dictionary [getVisibleMeshes]] {
  172. set part [plv_globalreg getpaircount $mesh]
  173. if {$part < $min} {
  174.     puts "$mesh: $part partners"
  175. }
  176.     }
  177. }
  178. proc listGroups {} {
  179.     plv_globalreg groupstatus
  180.     foreach mesh [lsort -dictionary [getVisibleMeshes]] {
  181. if {![plv_globalreg getpaircount $mesh]} {
  182.     lappend missing $mesh
  183. }
  184.     }
  185.     
  186.     if {[info exists missing]} {
  187. puts "nnot registered at all ([llength $missing]): $missing"
  188.     }
  189. }
  190. ######################################################################
  191. #
  192. # Drag registration UI
  193. #
  194. ######################################################################
  195. proc dragRegistrationDialog {} {
  196.     global dragMeshesLeft
  197.     set dragMeshesLeft [getVisibleMeshes]
  198.     if {[llength $dragMeshesLeft] < 2} {
  199. tk_dialog .err "scanalyze" 
  200.     "You must have at least two meshes visible
  201.              to perform drag registration." "" 0 Ok
  202. return
  203.     }
  204.     set dr [toplevel .dragreg]
  205.     wm title $dr "Drag registration"
  206.     window_Register $dr
  207.     global meshVisible
  208.     foreach mesh $dragMeshesLeft {
  209. changeVis $mesh 0
  210.     }
  211.     frame $dr.cur
  212.     label $dr.cur.curlab -text "Current mesh:"
  213.     label $dr.cur.current -textvariable theMesh
  214.     pack $dr.cur.curlab $dr.cur.current -side left
  215.     pack $dr.cur -side top
  216.     label $dr.instruct 
  217. -text "Drag mesh to correct position, then click Next."
  218.     pack $dr.instruct -side top
  219.     frame $dr.method
  220.     radiobutton $dr.method.ptPt    -text "Point-to-point"
  221. -variable dragRegMethod -value horn
  222.     radiobutton $dr.method.ptPlane -text "Point-to-plane"
  223. -variable dragRegMethod -value chen
  224.     pack $dr.method.ptPt $dr.method.ptPlane -side left
  225.     button $dr.next -text Next -command dragRegNext
  226.     pack $dr.method $dr.next -side top -fill x -expand true
  227.     frame $dr.left
  228.     label $dr.left.leftlab -text "Remaining meshes:"
  229.     label $dr.left.remain -textvariable dragMeshesLeft
  230.     pack $dr.left.leftlab $dr.left.remain -side left
  231.     pack $dr.left -side top
  232.     bind $dr <Destroy> "+destroyDragRegUI %W"
  233.     selectScan ""
  234.     globalset theMover mesh
  235.     dragRegNext
  236. }
  237. proc dragRegNext {} {
  238.     global theMesh
  239.     global dragMeshesLeft
  240.     global meshVisible
  241.     # read z-buffer to get correspondence points, invoke algorithm
  242.     if {0 != [string compare $theMesh ""]} {
  243. if {[llength [getVisibleMeshes]] > 1} {
  244.     DragRegister $theMesh [globalset dragRegMethod]
  245. }
  246.     }
  247.     # on to next mesh:
  248.     # move first element of dragMeshesLeft to theMesh
  249.     selectScan [lindex $dragMeshesLeft 0]
  250.     set dragMeshesLeft [lrange $dragMeshesLeft 1 end]
  251.     # and if there IS a next mesh, make it visible
  252.     if {0 == [string compare $theMesh ""]} {
  253. # done!
  254. destroy .dragreg
  255.     } else {
  256. # make next mesh visible
  257. changeVis $theMesh 1
  258.     }
  259. }
  260. proc destroyDragRegUI {window} {
  261.     if {0 != [string compare $window .dragreg]} {
  262. return
  263.     }
  264.     globalset theMover viewer
  265.     global dragMeshesLeft
  266.     unset dragMeshesLeft
  267. }
  268. ######################################################################
  269. #
  270. # Correspondence registration UI
  271. #
  272. ######################################################################
  273. proc renderParamsChanged {} {
  274.     global correspRegWindows
  275.     if {[array exists correspRegWindows]} {
  276. refreshCorrespRegWindows *
  277.     }
  278. }
  279. proc correspRegistrationDialog {} {
  280.     global meshVisible
  281.     global uniqueInt
  282.     global toglPane
  283.     
  284.     if {[array size meshVisible] < 2} {
  285. tk_dialog .err "scanalyze" 
  286.     "You must have at least two meshes loaded
  287.              to perform registration." "" 0 Ok
  288. return
  289.     }
  290.     toplevel .reg
  291.     set which [frame .reg.which]
  292.     set meshFrom [eval tk_optionMenu $which.mFrom regCorrespFrom bogus]
  293.     set meshTo [eval tk_optionMenu $which.mTo regCorrespTo bogus]
  294.     $which.mFrom config -pady 4
  295.     $which.mTo config -pady 4
  296.     set winid 1
  297.     foreach meshMenu "$meshFrom $meshTo" {
  298. listRegMeshes $meshMenu
  299. bindCorrespRegMeshSelector $meshMenu $uniqueInt
  300. set winId$winid $uniqueInt
  301. incr winid
  302. incr uniqueInt
  303. bind $meshMenu <Shift-ButtonRelease> {
  304.     set chosenMesh [eval %W entrycget active -value]
  305.     createAlignmentView $uniqueInt $chosenMesh ""
  306.     incr uniqueInt
  307.     tkMenuUnpost {}
  308.     break
  309. }
  310.     }
  311.     label $which.lFrom -text Align
  312.     button $which.swap -text "<->" -padx 3 
  313. -command "swap regCorrespFrom regCorrespTo"
  314.     button $which.sync -text "Sync" 
  315. -command {
  316.     refreshCorrespMeshList $meshFrom $winId1 $meshTo $winId2
  317.     syncRegMeshes $meshFrom $meshTo
  318. } -pady 1
  319.     checkbutton $which.vis -text "Only visible" 
  320. -variable correspRegHideInvisible 
  321. -command "refreshCorrespMeshList $meshFrom $winId1 $meshTo $winId2"
  322.     button $which.help -text "Help..." 
  323. -command correspRegHelp -pady 1
  324.     pack $which.lFrom $which.mFrom $which.swap $which.mTo -side left
  325.     pack $which.help $which.vis $which.sync -side right
  326.     
  327.     frame .reg.lines
  328.     listbox .reg.lines.list -height 6 -borderwidth 2
  329.               -yscrollcommand ".reg.lines.scroll set"
  330.     scrollbar .reg.lines.scroll -command ".reg.lines.list yview"
  331.     pack .reg.lines.list -side left -fill both -expand true
  332.     pack .reg.lines.scroll -side right -fill y
  333.     # I want to just add some script to the existing Listbox binding,
  334.     # but this doesn't seem to be possible given the Tcl difference
  335.     # between substitutions inside "" and {} -- bind needs "" to work
  336.     # with %W, but the rest of the script needs {} to work with the
  337.     # temporary variables.  ARGH.
  338.     bind .reg.lines.list <ButtonRelease-1> {
  339. set oldSel [extractMeshesInCorrespondence .reg.lines.list]
  340. # eval [bind Listbox <ButtonRelease-1>]
  341. tkCancelRepeat
  342. %W activate @%x,%y
  343. set newSel [extractMeshesInCorrespondence .reg.lines.list]
  344.         refreshMeshesInCorrespondences [concat $oldSel $newSel]
  345.     }
  346. #    set listboxScript [bind Listbox <ButtonRelease-1>]
  347. #    bind .reg.lines.list <ButtonRelease-1> "
  348. # set oldSel [extractMeshesInCorrespondence %W]
  349. #        $listboxScript
  350. #        set newSel [extractMeshesInCorrespondence %W]
  351. #        refreshMeshesInCorrespondences [concat $oldSel $newSel]
  352. #    "
  353.     frame .reg.do
  354.     button .reg.do.reg -text "Register meshes:" 
  355. -command {
  356.     plv_registerCorresp .regLayout.togl $correspRegMode 
  357. $regCorrespFrom $regCorrespTo
  358.     redraw 1
  359.     .regLayout.togl render
  360. } -pady 0
  361.     globalset correspRegMode from2to
  362.     radiobutton .reg.do.from2to -text "From to To" 
  363. -variable correspRegMode -value from2to
  364.     radiobutton .reg.do.from2all -text "From to All" 
  365. -variable correspRegMode -value from2all
  366.     radiobutton .reg.do.all2all -text "All to all" 
  367. -variable correspRegMode -value all2all
  368.     pack .reg.do.reg .reg.do.from2to .reg.do.from2all .reg.do.all2all 
  369. -side left -fill x
  370.     frame .reg.sel
  371.     button .reg.sel.delete -text "Delete selected" 
  372. -command {
  373.     if {[string compare [.reg.lines.list cursel] ""] != 0} {
  374. DeleteRegCorrespondence .regLayout.togl 
  375.     [.reg.lines.list get active]
  376. refreshMeshesInCorrespondence 
  377.     [extractMeshesInCorrespondence .reg.lines.list]
  378. .reg.lines.list delete active
  379.     }
  380. } -pady 0
  381.     button .reg.sel.deselect -text "Deselect" 
  382. -command { deselectSelectedCorrespondence } -pady 0
  383.     checkbutton .reg.sel.colorPts -text "Color points" 
  384. -variable correspRegColorPoints 
  385. -command { plv_correspRegParms .regLayout.togl 
  386.        colorpoints $correspRegColorPoints
  387.     refreshCorrespRegWindows * }
  388.     pack .reg.sel.delete .reg.sel.deselect .reg.sel.colorPts 
  389. -side left -anchor w -padx 4
  390.     text .reg.halfDone -wrap none -height 1 -exportselection false 
  391. -foreground ForestGreen
  392.     .reg.halfDone config -state disabled
  393.     pack .reg.which -side top -fill x
  394.     pack .reg.lines -side top -anchor w -fill both -expand true
  395.     pack .reg.sel -side top -anchor w -fill x
  396.     pack .reg.do -side top -anchor w -fill x
  397.     pack .reg.halfDone -side right -anchor e
  398.     wm title .reg "Interactive mesh registration -- correspondences"
  399.     wm geometry .reg 500x300+0+0
  400.     window_Register .reg
  401.     createAlignmentOverview 500x300+524+0
  402.     createAlignmentView $winId1 "" 500x450+0+372
  403.     createAlignmentView $winId2 "" 500x450+524+372
  404.     bind .reg <Unmap>    { showCorrespRegWindows 0 }
  405.     bind .reg <Map>      { showCorrespRegWindows 1 }
  406.     wm protocol .reg WM_DELETE_WINDOW destroyCorrespRegUI
  407.     syncRegMeshes $meshFrom $meshTo 0 0
  408. }
  409. proc refreshCorrespMeshList {meshFrom winId1 meshTo winId2} {
  410.     global correspRegHideInvisible
  411.     listRegMeshes [list $meshFrom $meshTo] $correspRegHideInvisible
  412.     bindCorrespRegMeshSelector $meshFrom $winId1
  413.     bindCorrespRegMeshSelector $meshTo   $winId2
  414. }
  415. proc bindCorrespRegMeshSelector {meshlist windowid} {
  416.     set len [$meshlist index end]
  417.     for {set i 3} {$i <= $len} {incr i} {
  418. set mesh [$meshlist entrycget $i -label]
  419. $meshlist entryconfigure $i 
  420.     -command "resetAlignmentView $windowid $mesh"
  421.     }
  422. }
  423. proc invokeActiveMesh {meshlist} {
  424.     menuInvokeByName $meshlist [globalset theMesh]
  425. }
  426. proc activateMeshFromVariable {var} {
  427.     globalset theMesh [globalset $var]
  428. }
  429. proc listRegMeshes {meshlistlist {onlyvis 0}} {
  430.     set names [getSortedMeshList $onlyvis]
  431.     foreach meshlist $meshlistlist {
  432. set var [lindex [$meshlist entryconfig 3 -variable] 4]
  433. $meshlist delete 0 end
  434. $meshlist add command -label "Select active mesh" 
  435.     -command "invokeActiveMesh $meshlist"
  436. $meshlist add command -label "Activate selected mesh" 
  437.     -command "activateMeshFromVariable $var"
  438. $meshlist add separator
  439. set count 3
  440. set max 35
  441. foreach name $names {
  442.     set color [GetMeshFalseColor $name]
  443.     if {[expr $count % $max] == 0} {
  444. set cb 1
  445.     } else {
  446. set cb 0
  447.     }
  448.     incr count
  449.     $meshlist add radiobutton -label $name 
  450. -variable $var -value $name 
  451. -foreground $color -activebackground $color 
  452. -columnbreak $cb
  453. }
  454. if {[llength $names] == 0} {
  455.     $meshlist add radiobutton -label "No eligible meshes!" 
  456. -variable $var -state disabled
  457. }
  458.     }
  459. }
  460. proc syncRegMeshes {meshFrom meshTo {relist 0} {warn 1}} {
  461.     if {$relist != 0} {
  462. # refresh mesh list
  463. listRegMeshes "$meshFrom $meshTo" [expr $relist - 1]
  464.     }
  465.     # now try to select the 2 visible meshes
  466.     set vis [getVisibleMeshes]
  467.     if {[llength $vis] != 2} {
  468. if {$warn} {
  469.     tk_messageBox -type ok -icon error 
  470. -message "Must have exactly 2 meshes visible to sync"
  471. -parent $meshFrom
  472. } else {
  473.     # instead of failing, we're supposed to silently do our best.
  474.     # so select theMesh as first mesh, and anything else as second
  475.     set ind [menuInvokeByName $meshFrom [globalset theMesh]]
  476.          
  477.     if {$ind == 3} {
  478. $meshTo invoke 4
  479.     } else {
  480. $meshTo invoke 3
  481.     }
  482. }
  483. return 0
  484.     }
  485.     # if either is the current mesh, make it the "from" mesh
  486.     if {[globalset theMesh] == [lindex $vis 1]} {
  487. set vis [list [lindex $vis 1] [lindex $vis 0]]
  488.     }
  489.     set loop {{meshFrom 0} {meshTo 1}}
  490.     foreach entry $loop {
  491. set meshMenu [set [lindex $entry 0]]
  492. set ind [lindex $entry 1]
  493. set name [lindex $vis $ind]
  494. menuInvokeByName $meshMenu $name
  495.     }
  496.     return 1
  497. }
  498. proc correspRegHelp {} {
  499.     toplevel .help
  500.     text .help.instruct -wrap word -exportselection false
  501.     .help.instruct insert end "Choose two meshes from the dropdown menus.
  502.                If you want more than two mesh views, hold shift as you
  503.                select a mesh name.nn
  504.                Left-click a point in each mesh view to begin a correspondence;
  505.                middle button completes the correspondence and right button
  506.                cancels it.nn
  507.                Selecting a correspondence from the listbox will highlight it;
  508.                you can now delete it, or modify or delete individual points
  509.                by clicking in individual mesh views.nn
  510.                To manipulate the meshes with a trackball, hold down the
  511.                Alt key."
  512.     .help.instruct config -state disabled
  513.     pack .help.instruct -fill both -expand true
  514. }
  515. proc extractMeshesInCorrespondence {widget {corresp ""}} {
  516.     # if we're passed a widget and no correspondence, extract correspondence
  517.     if {0 == [string compare $corresp ""]} {
  518. # if there is one
  519. if {0 == [string compare "" [$widget cursel]]} {
  520.     return ""
  521. }
  522. set corresp [$widget get active]
  523.     }
  524.     set meshes ""
  525.     for {set i 1} {$i < [llength $corresp]} {set i [expr $i + 2]} {
  526. set mesh [lindex $corresp $i]
  527. set mesh [string range $mesh 0 [expr [string first : $mesh] - 1]]
  528. set meshes [concat $meshes $mesh]
  529.     }
  530.     return $meshes
  531. }
  532. proc refreshMeshesInCorrespondences {meshes} {
  533.     foreach mesh $meshes {
  534. set meshNames($mesh) 1
  535.     }
  536.     # use names as keys in associative array, then extract names, to
  537.     # discard duplicates
  538.     foreach mesh [array names meshNames] {
  539. if {0 != [string compare $mesh ""]} {
  540.     refreshCorrespRegWindows $mesh
  541. }
  542.     }
  543. }
  544. proc deselectSelectedCorrespondence {} {
  545.     set meshes [getListboxSelection .reg.lines.list]
  546.     .reg.lines.list selection clear 0 end
  547.     if {$meshes != ""} {
  548. refreshMeshesInCorrespondences 
  549.     [extractMeshesInCorrespondence "" $meshes]
  550.     }
  551. }
  552. proc rebuildSelectedCorrespondenceString {} {
  553.     set index [.reg.lines.list cursel]
  554.     if {$index == ""} {
  555. return
  556.     }
  557.     set sel [.reg.lines.list get $index]
  558.     set id [getCorrespondenceIndex $sel]
  559.     set sel [GetCorrespondenceInfo .regLayout.togl $id]
  560.     .reg.lines.list insert $index $sel
  561.     .reg.lines.list delete [expr $index + 1]
  562.     .reg.lines.list selection clear 0 end
  563.     .reg.lines.list selection set $index
  564. }
  565. proc refreshCorrespRegWindows {mesh} {
  566.     global correspRegWindows
  567.     foreach window [array names correspRegWindows] {
  568. set thisMesh $correspRegWindows($window)
  569. if {$mesh == $thisMesh || $mesh == "*"} {
  570.     $window.togl render
  571. }
  572.     }
  573.     if {$mesh == "*"} {
  574. .regLayout.togl render
  575.     }
  576. }
  577. proc showCorrespRegWindows {bShow} {
  578.     global correspRegWindows
  579.     foreach window [concat .regLayout [array names correspRegWindows]] {
  580. if {[string compare $bShow 0] == 0} {
  581.     wm withdraw $window
  582. } else {
  583.     wm deiconify $window
  584. }
  585.     }
  586. }
  587. proc destroyCorrespRegUI {} {
  588.     # delete dependent windows
  589.     global correspRegWindows
  590.     foreach window [array names correspRegWindows] {
  591. destroy $window
  592.     }
  593.     unset correspRegWindows
  594.     # then delete master windows
  595.     wm protocol .reg WM_DELETE_WINDOW {}
  596.     wm protocol .regLayout WM_DELETE_WINDOW {}
  597.     destroy .reg
  598.     destroy .regLayout
  599.     # don't let user accidentally destroy alignment
  600.     globalset theMover viewer
  601. }
  602. proc createAlignmentOverview {geometry} {
  603.     toplevel .regLayout
  604.     togl .regLayout.togl 
  605.         -rgba true -double true -depth true -accum true -overlay false
  606. -ident .regLayout.togl
  607.     pack .regLayout.togl -fill both -expand 1
  608.     wm title .regLayout "Interactive mesh registration -- layout"
  609.     wm geometry .regLayout $geometry
  610.     window_Register .regLayout
  611.     bindToglToAlignmentOverview .regLayout.togl
  612.     wm protocol .regLayout WM_DELETE_WINDOW destroyCorrespRegUI
  613. }
  614. proc createAlignmentView {viewName meshName geometry} {
  615.     set view [toplevel .regMesh$viewName]
  616.     togl $view.togl 
  617.         -rgba true -double true -depth true -accum true 
  618. -ident $view.togl -time 30
  619.     resetAlignmentView $viewName $meshName
  620.     pack $view.togl -fill both -expand 1
  621.     if {$geometry != ""} {
  622. wm geometry $view $geometry
  623.     }
  624.     bind $view.togl <Alt-ButtonPress-1> 
  625. "RegUIMouse $view.togl 1 %x %y %t start"
  626.     bind $view.togl <Alt-B1-Motion> 
  627. "RegUIMouse $view.togl 0 %x %y %t"
  628.     bind $view.togl <Alt-ButtonRelease-1> 
  629. "RegUIMouse $view.togl 1 %x %y %t stop"
  630.     bind $view.togl <Alt-ButtonPress-2> 
  631. "RegUIMouse $view.togl 2 %x %y %t start"
  632.     bind $view.togl <Alt-B2-Motion> 
  633. "RegUIMouse $view.togl 0 %x %y %t"
  634.     bind $view.togl <Alt-ButtonRelease-2> 
  635. "RegUIMouse $view.togl 2 %x %y %t stop"
  636.     global cursor
  637.     $view config -cursor "diamond_cross$cursor(Fore)$cursor(Back)"
  638.     bind $view <KeyPress-Alt_L>    
  639. "%W.togl config -cursor "$cursor(CurvedHand)$cursor(Fore)""
  640.     bind $view <KeyRelease-Alt_L>  
  641. "%W.togl config -cursor "diamond_cross$cursor(Fore)$cursor(Back)""
  642.     # enter bindings, in case you cross window boundary with Alt down
  643.     bind $view <Enter> 
  644. "%W config -cursor "diamond_cross$cursor(Fore)$cursor(Back)""
  645.     bind $view <Alt-Enter> 
  646. "%W config -cursor "$cursor(CurvedHand)$cursor(Fore)""
  647.     bind $view.togl <ButtonPress-1> 
  648. "clickCorrespondence $view.togl .regLayout.togl %x %y"
  649.     bind $view.togl <ButtonPress-2> 
  650. "completeCorrespondence .regLayout.togl"
  651.     bind $view.togl <ButtonPress-3> 
  652. "completeCorrespondence .regLayout.togl delete"
  653.     bind $view <Destroy> {+alignmentViewWentAway %W}
  654. }
  655. proc alignmentViewWentAway {widget} {
  656.     # ignore duplicates -- only the toplevel counts
  657.     if {0 != [string last . $widget]} { return }
  658.     global correspRegWindows
  659.     unset correspRegWindows($widget)
  660. }
  661. proc resetAlignmentView {viewName meshName} {
  662.     global correspRegWindows
  663.     set view ".regMesh$viewName"
  664.     bindToglToAlignmentView $view.togl $meshName
  665.     set correspRegWindows($view) $meshName
  666.     wm title $view "$meshName -- registration (Alt to trackball)"
  667.     bind $view <KeyPress-period> "setMeshResolution $meshName higher"
  668.     bind $view <KeyPress-comma>  "setMeshResolution $meshName lower"
  669. }
  670. proc clickCorrespondence {togl toglOV x y} {
  671.     set mesh [AddPartialRegCorrespondence $togl $toglOV $x $y]
  672.     if {[string compare $mesh ""] == 0} {
  673. beep
  674. puts "clicked on nothing"
  675. return
  676.     }
  677.     .reg.halfDone config -state normal
  678.     set meshPos [.reg.halfDone search $mesh 1.0]
  679.     if {$meshPos == ""} {
  680. # otherwise, it's already in the list
  681. .reg.halfDone insert end "$mesh "
  682. .reg.halfDone xview moveto 1
  683.     } else {
  684. set total [.reg.halfDone index "1.0 lineend"]
  685. set total [string range $total 2 end]
  686. set meshPos [string range $meshPos 2 end]
  687. .reg.halfDone xview moveto [expr $meshPos.0 / $total]
  688.     }
  689.     .reg.halfDone config -state disabled
  690. }
  691. proc getCorrespondenceIndex {corresp} {
  692.     set index [lindex $corresp 0]
  693.     set index [string range $index 
  694.    [expr [string first [ $index] + 1] 
  695.    [expr [string last  ] $index] - 1]]
  696.     return $index
  697. }
  698. proc completeCorrespondence {toglOV {delete ""}} {
  699.     # deselect any selection
  700.     deselectSelectedCorrespondence
  701.     # update C++ data structures
  702.     set corresp [ConfirmRegCorrespondence $toglOV $delete]
  703.     set index [getCorrespondenceIndex $corresp]
  704.     # if it wasn't cancelled
  705.     if {$index != 0} {
  706. # and list it in listbox
  707.      .reg.lines.list insert end $corresp
  708.     }
  709.     # update the views that are affected
  710.     update
  711.     refreshMeshesInCorrespondences 
  712. [extractMeshesInCorrespondence "" $corresp]
  713.     .reg.halfDone config -state normal
  714.     .reg.halfDone delete 1.0 end
  715.     .reg.halfDone config -state disabled
  716. }
  717. ######################################################################
  718. #
  719. # ICP Degistration UI
  720. #
  721. ######################################################################
  722. proc _reg_check2meshes { mfrom mto } {
  723.     if {$mfrom == $mto} {
  724. tk_messageBox -type ok -icon error -parent .regICP
  725. -message "Please select two meshes"
  726. return 0
  727.     }
  728.     global meshVisible
  729.     if {[lsearch [array names meshVisible] $mfrom] < 0 || 
  730.             [lsearch [array names meshVisible] $mto] < 0 || 
  731.             !$meshVisible($mfrom) || !$meshVisible($mto)} {
  732.         set warn "Warning: attempting to register mesh that is not"
  733.         set warn "$warn visible; sync first?"
  734.         set res [tk_messageBox -message $warn -parent .regICP 
  735.                 -type yesnocancel -default yes -icon warning]
  736.         if {$res == "cancel"} {
  737.             return 0
  738.         } elseif {$res == "yes"} {
  739.             .regICP.which.sync invoke
  740.             if {[lsearch [array names meshVisible] $mfrom] < 0 || 
  741.                     [lsearch [array names meshVisible] $mto] < 0 || 
  742.                     !$meshVisible($mfrom) || !$meshVisible($mto)} {
  743.                 return 0
  744.             }
  745.         }
  746.     }
  747.     return 1
  748. }
  749. proc doICP { samp normsamp n culling_percentage no_bdry opt_method 
  750.  mfrom mto thr_kind thr_val save_global gr_max_pairs qual} {
  751.     if {![_reg_check2meshes $mfrom $mto]} {
  752. return
  753.     }
  754.     .regICP config -cursor watch
  755.     cursor watch
  756.     if {$thr_kind == "rel"} {
  757. set thr_val [expr $thr_val / 100.0]
  758.     }
  759.     set err [plv_icpregister $samp $normsamp $n $culling_percentage $no_bdry 
  760.  $opt_method $mfrom $mto $thr_kind $thr_val $save_global 
  761.  $gr_max_pairs $qual]
  762.     redraw 1
  763.     .regICP config -cursor ""
  764.     .regICP.do.lastErr config -text $err
  765.     .regICP.gr_frm.qual config -state active
  766.     cursor restore
  767. }
  768. proc updateFromAndToMeshNames {} {
  769.     if {![window_Activate .regICP]} { return }
  770.     # do nothing if the ICP window is closed
  771.     set names [getMeshList]
  772.     if {[llength $names] == 0} { return }
  773.     # i.e. do nothing if all the meshes have been deleted
  774.     syncRegMeshes .regICP.which.mFrom.menu .regICP.which.mTo.menu 1 0
  775.     # calls syncRegMeshes to refresh the menus so that the current 
  776.     # selections for the from and to mesh are valid choices
  777. }
  778. proc ICPdialog {} {
  779.     global regICPFrom regICPTo
  780.     set names [getMeshList]
  781.     if {[expr [llength $names] < 2]} {
  782. puts "You need at least two meshes to register"
  783. return
  784.     }
  785.     if {[window_Activate .regICP]} { return }
  786.     toplevel .regICP
  787.     # Instruction message
  788.     message .regICP.instruct -aspect 1000 
  789.     -text "Choose two meshes in the menus"
  790.     -justify left
  791.     pack .regICP.instruct -side top -anchor w
  792.     # option menu for mesh names
  793.     set which [frame .regICP.which]
  794.     set meshFrom [eval tk_optionMenu $which.mFrom regICPFrom  bogus]
  795.     set meshTo [eval tk_optionMenu $which.mTo regICPTo bogus]
  796.     syncRegMeshes $meshFrom $meshTo 1 0
  797.     $meshFrom config -postcommand "refreshICPRegMeshes $meshFrom"
  798.     $meshTo config -postcommand "refreshICPRegMeshes $meshTo"
  799.    
  800.     label $which.lFrom -text Align -padx 3
  801.     button $which.swap -text "<->" -padx 3 
  802. -command "swap regICPFrom regICPTo"
  803.     button $which.sync -text "Sync" 
  804. -command "refreshICPRegMeshes {$meshFrom $meshTo} sync"
  805.     checkbutton $which.vis -text "Only visible" 
  806. -variable icpRegListsVisOnly -onvalue 1 -offvalue 0
  807.     pack $which.lFrom $which.mFrom $which.swap $which.mTo -side left
  808.     pack $which.sync $which.vis -side right
  809.     pack $which -side top -anchor w
  810.     # scales
  811.     set scl_frm [frame .regICP.scl_frm 
  812.     -borderwidth 4 -relief ridge]
  813.     # scale for the sampling rate
  814.     set lbl_wdth 13
  815.     set samp [frame $scl_frm.samp]
  816.     label  $samp.scl_label -text "Sampling rate" 
  817.     -width $lbl_wdth -anchor w -padx 3
  818.     scale  $samp.scl 
  819.     -from .01 -to 1 -resolution .01 
  820.     -variable regSample 
  821.     -orient horizontal 
  822.     -length 150
  823.     $samp.scl set .10
  824.     pack $samp -side top -expand true -fill x
  825.     pack $samp.scl_label -side left -anchor sw
  826.     pack $samp.scl -side right -expand true -fill x
  827.     # scale for the number of iterations
  828.     set iter [frame $scl_frm.iter]
  829.     label  $iter.scl_label -text "Iterations" 
  830.     -width $lbl_wdth -anchor w -padx 3
  831.     scale  $iter.scl 
  832.     -from 0 -to 20 
  833.     -variable regIterations 
  834.     -orient horizontal 
  835.     $iter.scl set 3
  836.     pack $iter -side top -expand true -fill x
  837.     pack $iter.scl_label -side left -anchor sw
  838.     pack $iter.scl -side right -expand true -fill x
  839.     # scale for the max relative edge length
  840.     set culling [frame $scl_frm.culling]
  841.     label  $culling.scl_label -text "Cull Percentage" 
  842.     -width $lbl_wdth -anchor w -padx 3
  843.     scale  $culling.scl 
  844.     -from 0 -to 99 
  845.     -variable cullingPercentage 
  846.     -orient horizontal
  847.     $culling.scl set 3
  848.     pack $culling -side top -expand true -fill x
  849.     pack $culling.scl_label -side left -anchor sw
  850.     pack $culling.scl -side right -expand true -fill x
  851.     # make a frame for thresholds
  852.     set thr_frm [frame .regICP.scl_frm.thr_frm]
  853.     # radio buttons
  854.     label $thr_frm.l -text "Threshold:"
  855.     set thr_radiob [frame $thr_frm.thr_radiob]
  856.     radiobutton $thr_radiob.abs -variable thresh_kind 
  857.     -value "abs" 
  858.     -text "Absolute (mm)"
  859.     radiobutton $thr_radiob.rel -variable thresh_kind 
  860.     -value "rel" 
  861.     -text "Relative (% of bbox)"
  862.     $thr_radiob.abs select
  863.     packchildren $thr_radiob -side bottom -anchor w
  864.     # entry field
  865.     entry  $thr_frm.entry 
  866.     -textvariable dist_threshold_val 
  867.     -relief sunken -width 6
  868.     globalset dist_threshold_val 5.0
  869.     packchildren $thr_frm -side left -expand true -fill x
  870.     pack $thr_frm -side top -expand true -fill x
  871.     pack $scl_frm -side top -expand true -fill x
  872.     frame .regICP.opt
  873.     # checkbutton for allowing mesh boundary targets
  874.     checkbutton .regICP.opt.bdry -variable no_bndr_trgt 
  875.     -text "Avoid boundary"
  876.     checkbutton .regICP.opt.normspace -variable norm_space_samp 
  877.     -text "Normal-space sampling"
  878.     .regICP.opt.bdry select
  879.     checkbutton .regICP.opt.lines -text "Show lines"
  880. -variable regicpShowLines -command {showIcpLines $regicpShowLines}
  881.     #.regICP.opt.lines select
  882.     showIcpLines 0
  883.     packchildren .regICP.opt -side left
  884.     pack .regICP.opt -side top -anchor w
  885.     # radiobuttons for choosing optimization method
  886.     set rad_frm [frame .regICP.rad_frm 
  887.     -borderwidth 4 -relief ridge]
  888.     radiobutton $rad_frm.point -variable opt_method 
  889.     -value "point" 
  890.     -text "Move points to points"
  891.     radiobutton $rad_frm.plane -variable opt_method 
  892.     -value "plane" 
  893.     -text "Move points to planes"
  894.     $rad_frm.plane select
  895.     pack $rad_frm.point $rad_frm.plane -side top -anchor w
  896.     pack $rad_frm -side top -expand true -fill x
  897.     # global registration stuff
  898.     set gr_frm [frame .regICP.gr_frm 
  899.     -borderwidth 4 -relief ridge]
  900.     checkbutton $gr_frm.l1 
  901. -text "Save data for globalreg, but no more than " 
  902. -variable saveICPForGlobal
  903.     entry  $gr_frm.entry 
  904.     -textvariable gr_max_pairs 
  905.     -relief sunken -width 7
  906.     globalset gr_max_pairs 200
  907.     label  $gr_frm.l2 -text " pairs.   " 
  908.     -width 5 -anchor w -padx 3
  909.     
  910.     label $gr_frm.l3 -text "Quality:"
  911.     set qualMenu [tk_optionMenu $gr_frm.qual regIcpQuality 
  912.       "0 - Unspecified" "1 - Bad" "2 - Fair" "3 - Good"]
  913.     bindCommandToAllMenuItems $qualMenu {
  914. plv_icpreg_markquality $regICPFrom $regICPTo $regIcpQuality
  915.     }
  916.     globalset regIcpQuality 0
  917.     
  918.     packchildren $gr_frm -side left
  919.     pack $gr_frm -side top -expand true -fill x
  920.     # button for doing registration
  921.     frame .regICP.do
  922.     
  923.     button .regICP.do.doIt -text "Register meshes" 
  924. -command {
  925.     doICP $regSample $norm_space_samp $regIterations $cullingPercentage 
  926. $no_bndr_trgt $opt_method $regICPFrom $regICPTo 
  927. $thresh_kind $dist_threshold_val $saveICPForGlobal 
  928. $gr_max_pairs $regIcpQuality
  929. }
  930.     button .regICP.do.doIt100 -text "Register 1 round, 100%" 
  931. -command {
  932.     doICP 1 0 1 $cullingPercentage 
  933. $no_bndr_trgt $opt_method $regICPFrom $regICPTo 
  934. $thresh_kind $dist_threshold_val $saveICPForGlobal 
  935. $gr_max_pairs $regIcpQuality
  936. }
  937.     button .regICP.do.histogram -text "Show histogram" 
  938. -command {
  939.     plv_error_histogram 
  940. $regSample $regIterations $cullingPercentage 
  941. $no_bndr_trgt $opt_method $regICPFrom $regICPTo 
  942. $thresh_kind $dist_threshold_val
  943. }
  944.     
  945.     label .regICP.do.lastErrl -text "Last err:"
  946.     label .regICP.do.lastErr -text "(none)"
  947.     packchildren .regICP.do -side left
  948.     pack .regICP.do -side top -anchor w
  949.     wm title .regICP "ICP registration"
  950.     bind .regICP <Destroy> "+destroyICPDialog %W"
  951.     bind .regICP <KeyPress-space> {.regICP.do.doIt invoke}
  952.     window_Register .regICP
  953.     trace variable regICPFrom w regIcpChangeMesh
  954.     trace variable regICPTo   w regIcpChangeMesh
  955.     regIcpChangeMesh ignore this arg
  956. }
  957. proc regIcpChangeMesh {var1 var2 op} {
  958.     # NOTE: should we always set to 0(unknown) when they switch meshes, or 
  959.     # if those meshes are already aligned, should we set it to their old grade?
  960.     globalset regIcpQuality 0
  961.     .regICP.do.lastErr config -text "(none)"
  962.     set reg [plv_globalreg pairstatus [globalset regICPFrom] 
  963.  [globalset regICPTo]]
  964.     if {$reg} {
  965. .regICP.gr_frm.qual config -state active
  966.     } else {
  967. .regICP.gr_frm.qual config -state disabled
  968.     }
  969. }
  970. proc refreshICPRegMeshes {meshLists {sync 0}} {
  971.     set invis [globalset icpRegListsVisOnly]
  972.     if {$sync != "0"} {
  973. if {[llength $meshLists] != 2} {
  974.     tk_messageBox -message "internal error in arg count!"
  975.     return
  976. }
  977. eval syncRegMeshes $meshLists [expr 1 + $invis]
  978.     } else {
  979. listRegMeshes $meshLists $invis
  980.     }
  981. }
  982. proc destroyICPDialog {widget} {
  983.     if {$widget != ".regICP"} {
  984. return
  985.     }
  986.     global regICPFrom
  987.     global regICPTo
  988.     trace vdelete regICPFrom w regIcpChangeMesh
  989.     trace vdelete regICPTo   w regIcpChangeMesh
  990.     showIcpLines 0
  991. }
  992. proc showIcpLines {show} {
  993.     plv_showicplines $show
  994.     redraw 1
  995. }
  996. proc globalRegDeleteDialog {} {
  997.     set grd [toplevel .globalregdel]
  998.     wm resizable $grd 0 0
  999.     wm title $grd "Delete from globalreg"
  1000.     button $grd.all -text "Clear all registration pairs!" 
  1001. -command "plv_globalreg reset"
  1002.     button $grd.current -text "Clear all pairs involving current mesh" 
  1003. -command {plv_globalreg killpair [globalset theMesh] *}
  1004.     button $grd.these -text "Clear pair selected in ICP dialog" 
  1005. -command {plv_globalreg killpair 
  1006.     [globalset regICPFrom] [globalset regICPTo]}
  1007.     set f [frame $grd.f1]
  1008.     set fb [frame $f.fb]
  1009.     button $fb.b1 -text "Clear all" 
  1010. -command { plv_globalreg deleteautopairs $auto_del_thrsh }
  1011.     button $fb.b2 
  1012. -text "Clear current mesh's" 
  1013. -command { 
  1014.     plv_globalreg deleteautopairs $auto_del_thrsh $theMesh
  1015. }
  1016.     packchildren $fb -side top -fill x -expand 1
  1017.     label $f.gt -text "auto pairs greater than"
  1018.     entry  $f.entry 
  1019.     -textvariable auto_del_thrsh 
  1020.     -relief sunken -width 6
  1021.     globalset auto_del_thrsh 1.0
  1022.     packchildren $f -side left -fill x -expand 1
  1023.     button $grd.cancel -text "Close" -command "destroy $grd"
  1024.     packchildren $grd -side top -fill x -expand 1
  1025. }
  1026. proc chooseICP {a b} {
  1027.     global regICPTo regICPFrom
  1028.     set regICPFrom $a
  1029.     set regICPTo $b
  1030.     ICPdialog
  1031.     showAllMeshes 0
  1032.     showMesh $a
  1033.     showMesh $b
  1034. }
  1035. proc badAlignDialog {str} {
  1036.     if {[winfo exists .badalign]} {
  1037. destroy .badalign
  1038.     }
  1039.     set bad [toplevel .badalign]
  1040.     wm resizable $bad 0 0
  1041.     wm title $bad "Bad aligns"
  1042.     set l [split $str]
  1043.     for {set i 0} {$i < [llength $l]} {incr i 4} {
  1044. if {[expr $i + 3] < [llength $l]} {
  1045.     button $bad.$i 
  1046. -text [join [lrange $l $i [expr $i + 3]]]
  1047. -command "chooseICP [lindex $l [expr $i + 0]] [lindex $l [expr $i + 1]]"
  1048. }
  1049.     }
  1050.     packchildren $bad -side top -fill x -expand 1
  1051. }