source: branches/1.3/gui/scripts/vtkvolumeviewer.tcl @ 4531

Last change on this file since 4531 was 4474, checked in by ldelgass, 10 years ago

Merge mesh/field fixes from trunk, add mesh viewer

File size: 75.5 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: VtkVolumeViewer - Vtk volume viewer
4#
5#  It connects to the Vtk server running on a rendering farm,
6#  transmits data, and displays the results.
7# ======================================================================
8#  AUTHOR:  Michael McLennan, Purdue University
9#  Copyright (c) 2004-2014  HUBzero Foundation, LLC
10#
11#  See the file "license.terms" for information on usage and
12#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13# ======================================================================
14package require Itk
15package require BLT
16#package require Img
17
18option add *VtkVolumeViewer.width 4i widgetDefault
19option add *VtkVolumeViewer*cursor crosshair widgetDefault
20option add *VtkVolumeViewer.height 4i widgetDefault
21option add *VtkVolumeViewer.foreground black widgetDefault
22option add *VtkVolumeViewer.controlBackground gray widgetDefault
23option add *VtkVolumeViewer.controlDarkBackground #999999 widgetDefault
24option add *VtkVolumeViewer.plotBackground black widgetDefault
25option add *VtkVolumeViewer.plotForeground white widgetDefault
26option add *VtkVolumeViewer.font \
27    -*-helvetica-medium-r-normal-*-12-* widgetDefault
28
29# must use this name -- plugs into Rappture::resources::load
30proc VtkVolumeViewer_init_resources {} {
31    Rappture::resources::register \
32        vtkvis_server Rappture::VtkVolumeViewer::SetServerList
33}
34
35itcl::class Rappture::VtkVolumeViewer {
36    inherit Rappture::VisViewer
37
38    itk_option define -plotforeground plotForeground Foreground ""
39    itk_option define -plotbackground plotBackground Background ""
40
41    constructor { hostlist args } {
42        Rappture::VisViewer::constructor $hostlist
43    } {
44        # defined below
45    }
46    destructor {
47        # defined below
48    }
49    public proc SetServerList { namelist } {
50        Rappture::VisViewer::SetServerList "vtkvis" $namelist
51    }
52    public method add {dataobj {settings ""}}
53    public method camera {option args}
54    public method delete {args}
55    public method disconnect {}
56    public method download {option args}
57    public method get {args}
58    public method isconnected {}
59    public method parameters {title args} {
60        # do nothing
61    }
62    public method scale {args}
63
64    protected method Connect {}
65    protected method CurrentDatasets {args}
66    protected method Disconnect {}
67    protected method DoResize {}
68    protected method DoRotate {}
69    protected method AdjustSetting {what {value ""}}
70    protected method InitSettings { args  }
71    protected method Pan {option x y}
72    protected method Pick {x y}
73    protected method Rebuild {}
74    protected method ReceiveDataset { args }
75    protected method ReceiveImage { args }
76    protected method ReceiveLegend { colormap title vmin vmax size }
77    protected method Rotate {option x y}
78    protected method Zoom {option}
79
80    # The following methods are only used by this class.
81    private method BuildAxisTab {}
82    private method BuildCameraTab {}
83    private method BuildColormap { name colors }
84    private method BuildCutplaneTab {}
85    private method BuildDownloadPopup { widget command }
86    private method BuildVolumeTab {}
87    private method DrawLegend {}
88    private method Combo { option }
89    private method EnterLegend { x y }
90    private method EventuallyResize { w h }
91    private method EventuallyRotate { q }
92    private method EventuallySetCutplane { axis args }
93    private method GetImage { args }
94    private method GetVtkData { args }
95    private method IsValidObject { dataobj }
96    private method LeaveLegend {}
97    private method MotionLegend { x y }
98    private method PanCamera {}
99    private method RequestLegend {}
100    private method SetColormap { dataobj comp }
101    private method ChangeColormap { dataobj comp color }
102    private method SetLegendTip { x y }
103    private method SetObjectStyle { dataobj comp }
104    private method Slice {option args}
105
106    private variable _arcball ""
107    private variable _dlist ""     ;    # list of data objects
108    private variable _obj2datasets
109    private variable _obj2ovride   ;    # maps dataobj => style override
110    private variable _datasets     ;    # contains all the dataobj-component
111                                   ;    # datasets in the server
112    private variable _colormaps    ;    # contains all the colormaps
113                                   ;    # in the server.
114    private variable _dataset2style    ;# maps dataobj-component to transfunc
115
116    private variable _click        ;    # info used for rotate operations
117    private variable _limits       ;    # autoscale min/max for all axes
118    private variable _view         ;    # view params for 3D view
119    private variable _settings
120    private variable _style;            # Array of current component styles.
121    private variable _initialStyle;     # Array of initial component styles.
122    private variable _reset 1;          # indicates if camera needs to be reset
123                                        # to starting position.
124
125    private variable _first ""     ;    # This is the topmost dataset.
126    private variable _start 0
127    private variable _title ""
128
129    common _downloadPopup;              # download options from popup
130    private common _hardcopy
131    private variable _width 0
132    private variable _height 0
133    private variable _resizePending 0
134    private variable _rotatePending 0
135    private variable _cutplanePending 0
136    private variable _legendPending 0
137    private variable _fields
138    private variable _curFldName ""
139    private variable _curFldLabel ""
140    private variable _colorMode "vmag";#  Mode of colormap (vmag or scalar)
141}
142
143itk::usual VtkVolumeViewer {
144    keep -background -foreground -cursor -font
145    keep -plotbackground -plotforeground
146}
147
148# ----------------------------------------------------------------------
149# CONSTRUCTOR
150# ----------------------------------------------------------------------
151itcl::body Rappture::VtkVolumeViewer::constructor {hostlist args} {
152    package require vtk
153    set _serverType "vtkvis"
154
155    # Rebuild event
156    $_dispatcher register !rebuild
157    $_dispatcher dispatch $this !rebuild "[itcl::code $this Rebuild]; list"
158
159    # Resize event
160    $_dispatcher register !resize
161    $_dispatcher dispatch $this !resize "[itcl::code $this DoResize]; list"
162
163    # Rotate event
164    $_dispatcher register !rotate
165    $_dispatcher dispatch $this !rotate "[itcl::code $this DoRotate]; list"
166
167    # Legend event
168    $_dispatcher register !legend
169    $_dispatcher dispatch $this !legend "[itcl::code $this RequestLegend]; list"
170
171    # X-Cutplane event
172    $_dispatcher register !xcutplane
173    $_dispatcher dispatch $this !xcutplane \
174        "[itcl::code $this AdjustSetting cutplane-xposition]; list"
175
176    # Y-Cutplane event
177    $_dispatcher register !ycutplane
178    $_dispatcher dispatch $this !ycutplane \
179        "[itcl::code $this AdjustSetting cutplane-yposition]; list"
180
181    # Z-Cutplane event
182    $_dispatcher register !zcutplane
183    $_dispatcher dispatch $this !zcutplane \
184        "[itcl::code $this AdjustSetting cutplane-zposition]; list"
185
186    #
187    # Populate parser with commands handle incoming requests
188    #
189    $_parser alias image [itcl::code $this ReceiveImage]
190    $_parser alias dataset [itcl::code $this ReceiveDataset]
191    $_parser alias legend [itcl::code $this ReceiveLegend]
192
193    # Initialize the view to some default parameters.
194    array set _view {
195        qw              0.853553
196        qx              -0.353553
197        qy              0.353553
198        qz              0.146447
199        zoom            1.0
200        xpan            0
201        ypan            0
202        ortho           0
203    }
204    set _arcball [blt::arcball create 100 100]
205    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
206    $_arcball quaternion $q
207
208    array set _settings {
209        axis-xgrid              0
210        axis-ygrid              0
211        axis-zgrid              0
212        axesVisible             1
213        axisLabels              1
214        cutplaneEdges           0
215        cutplane-xvisible       1
216        cutplane-yvisible       1
217        cutplane-zvisible       1
218        cutplane-xposition      50
219        cutplane-yposition      50
220        cutplane-zposition      50
221        cutplaneVisible         0
222        cutplaneLighting        1
223        cutplaneWireframe       0
224        cutplane-opacity        100
225        volumeLighting          1
226        volume-material         80
227        volume-opacity          40
228        volume-quality          50
229        volumeVisible           1
230        legendVisible           1
231    }
232
233    itk_component add view {
234        canvas $itk_component(plotarea).view \
235            -highlightthickness 0 -borderwidth 0
236    } {
237        usual
238        ignore -highlightthickness -borderwidth  -background
239    }
240
241    itk_component add fieldmenu {
242        menu $itk_component(plotarea).menu -bg black -fg white -relief flat \
243            -tearoff no
244    } {
245        usual
246        ignore -background -foreground -relief -tearoff
247    }
248    set c $itk_component(view)
249    bind $c <Configure> [itcl::code $this EventuallyResize %w %h]
250    bind $c <4> [itcl::code $this Zoom in 0.25]
251    bind $c <5> [itcl::code $this Zoom out 0.25]
252    bind $c <KeyPress-Left>  [list %W xview scroll 10 units]
253    bind $c <KeyPress-Right> [list %W xview scroll -10 units]
254    bind $c <KeyPress-Up>    [list %W yview scroll 10 units]
255    bind $c <KeyPress-Down>  [list %W yview scroll -10 units]
256    bind $c <Enter> "focus %W"
257    bind $c <Control-F1> [itcl::code $this ToggleConsole]
258
259    # Fixes the scrollregion in case we go off screen
260    $c configure -scrollregion [$c bbox all]
261
262    set _map(id) [$c create image 0 0 -anchor nw -image $_image(plot)]
263    set _map(cwidth) -1
264    set _map(cheight) -1
265    set _map(zoom) 1.0
266    set _map(original) ""
267
268    set f [$itk_component(main) component controls]
269    itk_component add reset {
270        button $f.reset -borderwidth 1 -padx 1 -pady 1 \
271            -highlightthickness 0 \
272            -image [Rappture::icon reset-view] \
273            -command [itcl::code $this Zoom reset]
274    } {
275        usual
276        ignore -highlightthickness
277    }
278    pack $itk_component(reset) -side top -padx 2 -pady 2
279    Rappture::Tooltip::for $itk_component(reset) "Reset the view to the default zoom level"
280
281    itk_component add zoomin {
282        button $f.zin -borderwidth 1 -padx 1 -pady 1 \
283            -highlightthickness 0 \
284            -image [Rappture::icon zoom-in] \
285            -command [itcl::code $this Zoom in]
286    } {
287        usual
288        ignore -highlightthickness
289    }
290    pack $itk_component(zoomin) -side top -padx 2 -pady 2
291    Rappture::Tooltip::for $itk_component(zoomin) "Zoom in"
292
293    itk_component add zoomout {
294        button $f.zout -borderwidth 1 -padx 1 -pady 1 \
295            -highlightthickness 0 \
296            -image [Rappture::icon zoom-out] \
297            -command [itcl::code $this Zoom out]
298    } {
299        usual
300        ignore -highlightthickness
301    }
302    pack $itk_component(zoomout) -side top -padx 2 -pady 2
303    Rappture::Tooltip::for $itk_component(zoomout) "Zoom out"
304
305    itk_component add volume {
306        Rappture::PushButton $f.volume \
307            -onimage [Rappture::icon volume-on] \
308            -offimage [Rappture::icon volume-off] \
309            -variable [itcl::scope _settings(volumeVisible)] \
310            -command [itcl::code $this AdjustSetting volumeVisible]
311    }
312    $itk_component(volume) select
313    Rappture::Tooltip::for $itk_component(volume) \
314        "Don't display the volume"
315    pack $itk_component(volume) -padx 2 -pady 2
316
317    itk_component add cutplane {
318        Rappture::PushButton $f.cutplane \
319            -onimage [Rappture::icon cutbutton] \
320            -offimage [Rappture::icon cutbutton] \
321            -variable [itcl::scope _settings(cutplaneVisible)] \
322            -command [itcl::code $this AdjustSetting cutplaneVisible]
323    }
324    Rappture::Tooltip::for $itk_component(cutplane) \
325        "Show/Hide cutplanes"
326    pack $itk_component(cutplane) -padx 2 -pady 2
327
328
329    if { [catch {
330        BuildVolumeTab
331        BuildCutplaneTab
332        BuildAxisTab
333        BuildCameraTab
334    } errs] != 0 } {
335        puts stderr errs=$errs
336    }
337
338    # Legend
339    set _image(legend) [image create photo]
340    itk_component add legend {
341        canvas $itk_component(plotarea).legend -width 50 -highlightthickness 0
342    } {
343        usual
344        ignore -highlightthickness
345        rename -background -plotbackground plotBackground Background
346    }
347
348    # Hack around the Tk panewindow.  The problem is that the requested
349    # size of the 3d view isn't set until an image is retrieved from
350    # the server.  So the panewindow uses the tiny size.
351    set w 10000
352    pack forget $itk_component(view)
353    blt::table $itk_component(plotarea) \
354        0,0 $itk_component(view) -fill both -reqwidth $w
355    blt::table configure $itk_component(plotarea) c1 -resize none
356
357    # Bindings for rotation via mouse
358    bind $itk_component(view) <ButtonPress-1> \
359        [itcl::code $this Rotate click %x %y]
360    bind $itk_component(view) <B1-Motion> \
361        [itcl::code $this Rotate drag %x %y]
362    bind $itk_component(view) <ButtonRelease-1> \
363        [itcl::code $this Rotate release %x %y]
364    bind $itk_component(view) <Configure> \
365        [itcl::code $this EventuallyResize %w %h]
366
367    # Bindings for panning via mouse
368    bind $itk_component(view) <ButtonPress-2> \
369        [itcl::code $this Pan click %x %y]
370    bind $itk_component(view) <B2-Motion> \
371        [itcl::code $this Pan drag %x %y]
372    bind $itk_component(view) <ButtonRelease-2> \
373        [itcl::code $this Pan release %x %y]
374
375    #bind $itk_component(view) <ButtonRelease-3> \
376    #    [itcl::code $this Pick %x %y]
377
378    # Bindings for panning via keyboard
379    bind $itk_component(view) <KeyPress-Left> \
380        [itcl::code $this Pan set -10 0]
381    bind $itk_component(view) <KeyPress-Right> \
382        [itcl::code $this Pan set 10 0]
383    bind $itk_component(view) <KeyPress-Up> \
384        [itcl::code $this Pan set 0 -10]
385    bind $itk_component(view) <KeyPress-Down> \
386        [itcl::code $this Pan set 0 10]
387    bind $itk_component(view) <Shift-KeyPress-Left> \
388        [itcl::code $this Pan set -2 0]
389    bind $itk_component(view) <Shift-KeyPress-Right> \
390        [itcl::code $this Pan set 2 0]
391    bind $itk_component(view) <Shift-KeyPress-Up> \
392        [itcl::code $this Pan set 0 -2]
393    bind $itk_component(view) <Shift-KeyPress-Down> \
394        [itcl::code $this Pan set 0 2]
395
396    # Bindings for zoom via keyboard
397    bind $itk_component(view) <KeyPress-Prior> \
398        [itcl::code $this Zoom out]
399    bind $itk_component(view) <KeyPress-Next> \
400        [itcl::code $this Zoom in]
401
402    bind $itk_component(view) <Enter> "focus $itk_component(view)"
403
404    if {[string equal "x11" [tk windowingsystem]]} {
405        # Bindings for zoom via mouse
406        bind $itk_component(view) <4> [itcl::code $this Zoom out]
407        bind $itk_component(view) <5> [itcl::code $this Zoom in]
408    }
409
410    set _image(download) [image create photo]
411
412    eval itk_initialize $args
413    Connect
414}
415
416# ----------------------------------------------------------------------
417# DESTRUCTOR
418# ----------------------------------------------------------------------
419itcl::body Rappture::VtkVolumeViewer::destructor {} {
420    Disconnect
421    image delete $_image(plot)
422    image delete $_image(download)
423    catch { blt::arcball destroy $_arcball }
424}
425
426itcl::body Rappture::VtkVolumeViewer::DoResize {} {
427    if { $_width < 2 } {
428        set _width 500
429    }
430    if { $_height < 2 } {
431        set _height 500
432    }
433    set _start [clock clicks -milliseconds]
434    SendCmd "screen size $_width $_height"
435
436    set _legendPending 1
437    set _resizePending 0
438}
439
440itcl::body Rappture::VtkVolumeViewer::DoRotate {} {
441    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
442    SendCmd "camera orient $q"
443    set _rotatePending 0
444}
445
446itcl::body Rappture::VtkVolumeViewer::EventuallyResize { w h } {
447    set _width $w
448    set _height $h
449    $_arcball resize $w $h
450    if { !$_resizePending } {
451        set _resizePending 1
452        $_dispatcher event -after 400 !resize
453    }
454}
455
456set rotate_delay 100
457
458itcl::body Rappture::VtkVolumeViewer::EventuallyRotate { q } {
459    foreach { _view(qw) _view(qx) _view(qy) _view(qz) } $q break
460    if { !$_rotatePending } {
461        set _rotatePending 1
462        global rotate_delay
463        $_dispatcher event -after $rotate_delay !rotate
464    }
465}
466
467itcl::body Rappture::VtkVolumeViewer::EventuallySetCutplane { axis args } {
468    if { !$_cutplanePending } {
469        set _cutplanePending 1
470        $_dispatcher event -after 100 !${axis}cutplane
471    }
472}
473
474# ----------------------------------------------------------------------
475# USAGE: add <dataobj> ?<settings>?
476#
477# Clients use this to add a data object to the plot.  The optional
478# <settings> are used to configure the plot.  Allowed settings are
479# -color, -brightness, -width, -linestyle, and -raise.
480# ----------------------------------------------------------------------
481itcl::body Rappture::VtkVolumeViewer::add {dataobj {settings ""}} {
482    array set params {
483        -color auto
484        -width 1
485        -linestyle solid
486        -brightness 0
487        -raise 0
488        -description ""
489        -param ""
490        -type ""
491    }
492    array set params $settings
493    set params(-description) ""
494    set params(-param) ""
495    array set params $settings
496
497    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
498        # can't handle -autocolors yet
499        set params(-color) black
500    }
501    set pos [lsearch -exact $_dlist $dataobj]
502    if {$pos < 0} {
503        lappend _dlist $dataobj
504    }
505    set _obj2ovride($dataobj-color) $params(-color)
506    set _obj2ovride($dataobj-width) $params(-width)
507    set _obj2ovride($dataobj-raise) $params(-raise)
508    $_dispatcher event -idle !rebuild
509}
510
511
512# ----------------------------------------------------------------------
513# USAGE: delete ?<dataobj1> <dataobj2> ...?
514#
515#       Clients use this to delete a dataobj from the plot.  If no dataobjs
516#       are specified, then all dataobjs are deleted.  No data objects are
517#       deleted.  They are only removed from the display list.
518#
519# ----------------------------------------------------------------------
520itcl::body Rappture::VtkVolumeViewer::delete {args} {
521    if { [llength $args] == 0} {
522        set args $_dlist
523    }
524    # Delete all specified dataobjs
525    set changed 0
526    foreach dataobj $args {
527        set pos [lsearch -exact $_dlist $dataobj]
528        if { $pos < 0 } {
529            continue;                   # Don't know anything about it.
530        }
531        # Remove it from the dataobj list.
532        set _dlist [lreplace $_dlist $pos $pos]
533        array unset _obj2ovride $dataobj-*
534        array unset _settings $dataobj-*
535        set changed 1
536    }
537    # If anything changed, then rebuild the plot
538    if { $changed } {
539        $_dispatcher event -idle !rebuild
540    }
541}
542
543# ----------------------------------------------------------------------
544# USAGE: get ?-objects?
545# USAGE: get ?-visible?
546# USAGE: get ?-image view?
547#
548# Clients use this to query the list of objects being plotted, in
549# order from bottom to top of this result.  The optional "-image"
550# flag can also request the internal images being shown.
551# ----------------------------------------------------------------------
552itcl::body Rappture::VtkVolumeViewer::get {args} {
553    if {[llength $args] == 0} {
554        set args "-objects"
555    }
556
557    set op [lindex $args 0]
558    switch -- $op {
559        "-objects" {
560            # put the dataobj list in order according to -raise options
561            set dlist {}
562            foreach dataobj $_dlist {
563                if { ![IsValidObject $dataobj] } {
564                    continue
565                }
566                if {[info exists _obj2ovride($dataobj-raise)] &&
567                    $_obj2ovride($dataobj-raise)} {
568                    set dlist [linsert $dlist 0 $dataobj]
569                } else {
570                    lappend dlist $dataobj
571                }
572            }
573            return $dlist
574        }
575        "-visible" {
576            set dlist {}
577            foreach dataobj $_dlist {
578                if { ![IsValidObject $dataobj] } {
579                    continue
580                }
581                if { ![info exists _obj2ovride($dataobj-raise)] } {
582                    # No setting indicates that the object isn't visible.
583                    continue
584                }
585                # Otherwise use the -raise parameter to put the object to
586                # the front of the list.
587                if { $_obj2ovride($dataobj-raise) } {
588                    set dlist [linsert $dlist 0 $dataobj]
589                } else {
590                    lappend dlist $dataobj
591                }
592            }
593            return $dlist
594        }           
595        -image {
596            if {[llength $args] != 2} {
597                error "wrong # args: should be \"get -image view\""
598            }
599            switch -- [lindex $args end] {
600                view {
601                    return $_image(plot)
602                }
603                default {
604                    error "bad image name \"[lindex $args end]\": should be view"
605                }
606            }
607        }
608        default {
609            error "bad option \"$op\": should be -objects or -image"
610        }
611    }
612}
613
614# ----------------------------------------------------------------------
615# USAGE: scale ?<data1> <data2> ...?
616#
617# Sets the default limits for the overall plot according to the
618# limits of the data for all of the given <data> objects.  This
619# accounts for all objects--even those not showing on the screen.
620# Because of this, the limits are appropriate for all objects as
621# the user scans through data in the ResultSet viewer.
622# ----------------------------------------------------------------------
623itcl::body Rappture::VtkVolumeViewer::scale {args} {
624    foreach dataobj $args {
625        foreach axis { x y z } {
626            set lim [$dataobj limits $axis]
627            if { ![info exists _limits($axis)] } {
628                set _limits($axis) $lim
629                continue
630            }
631            foreach {min max} $lim break
632            foreach {amin amax} $_limits($axis) break
633            if { $amin > $min } {
634                set amin $min
635            }
636            if { $amax < $max } {
637                set amax $max
638            }
639            set _limits($axis) [list $amin $amax]
640        }
641        foreach { fname lim } [$dataobj fieldlimits] {
642            if { ![info exists _limits($fname)] } {
643                set _limits($fname) $lim
644                continue
645            }
646            foreach {min max} $lim break
647            foreach {fmin fmax} $_limits($fname) break
648            if { $fmin > $min } {
649                set fmin $min
650            }
651            if { $fmax < $max } {
652                set fmax $max
653            }
654            set _limits($fname) [list $fmin $fmax]
655        }
656    }
657}
658
659# ----------------------------------------------------------------------
660# USAGE: download coming
661# USAGE: download controls <downloadCommand>
662# USAGE: download now
663#
664# Clients use this method to create a downloadable representation
665# of the plot.  Returns a list of the form {ext string}, where
666# "ext" is the file extension (indicating the type of data) and
667# "string" is the data itself.
668# ----------------------------------------------------------------------
669itcl::body Rappture::VtkVolumeViewer::download {option args} {
670    switch $option {
671        coming {
672            if {[catch {
673                blt::winop snap $itk_component(plotarea) $_image(download)
674            }]} {
675                $_image(download) configure -width 1 -height 1
676                $_image(download) put #000000
677            }
678        }
679        controls {
680            set popup .vtkviewerdownload
681            if { ![winfo exists .vtkviewerdownload] } {
682                set inner [BuildDownloadPopup $popup [lindex $args 0]]
683            } else {
684                set inner [$popup component inner]
685            }
686            set _downloadPopup(image_controls) $inner.image_frame
687            set num [llength [get]]
688            set num [expr {($num == 1) ? "1 result" : "$num results"}]
689            set word [Rappture::filexfer::label downloadWord]
690            $inner.summary configure -text "$word $num in the following format:"
691            update idletasks            ;# Fix initial sizes
692            return $popup
693        }
694        now {
695            set popup .vtkviewerdownload
696            if {[winfo exists .vtkviewerdownload]} {
697                $popup deactivate
698            }
699            switch -- $_downloadPopup(format) {
700                "image" {
701                    return [$this GetImage [lindex $args 0]]
702                }
703                "vtk" {
704                    return [$this GetVtkData [lindex $args 0]]
705                }
706            }
707            return ""
708        }
709        default {
710            error "bad option \"$option\": should be coming, controls, now"
711        }
712    }
713}
714
715# ----------------------------------------------------------------------
716# USAGE: Connect ?<host:port>,<host:port>...?
717#
718# Clients use this method to establish a connection to a new
719# server, or to reestablish a connection to the previous server.
720# Any existing connection is automatically closed.
721# ----------------------------------------------------------------------
722itcl::body Rappture::VtkVolumeViewer::Connect {} {
723    set _hosts [GetServerList "vtkvis"]
724    if { "" == $_hosts } {
725        return 0
726    }
727    set result [VisViewer::Connect $_hosts]
728    if { $result } {
729        if { $_reportClientInfo }  {
730            # Tell the server the viewer, hub, user and session.
731            # Do this immediately on connect before buffering any commands
732            global env
733
734            set info {}
735            set user "???"
736            if { [info exists env(USER)] } {
737                set user $env(USER)
738            }
739            set session "???"
740            if { [info exists env(SESSION)] } {
741                set session $env(SESSION)
742            }
743            lappend info "hub" [exec hostname]
744            lappend info "client" "vtkvolumeviewer"
745            lappend info "user" $user
746            lappend info "session" $session
747            SendCmd "clientinfo [list $info]"
748        }
749
750        set w [winfo width $itk_component(view)]
751        set h [winfo height $itk_component(view)]
752        EventuallyResize $w $h
753    }
754    return $result
755}
756
757#
758# isconnected --
759#
760#       Indicates if we are currently connected to the visualization server.
761#
762itcl::body Rappture::VtkVolumeViewer::isconnected {} {
763    return [VisViewer::IsConnected]
764}
765
766#
767# disconnect --
768#
769itcl::body Rappture::VtkVolumeViewer::disconnect {} {
770    Disconnect
771    set _reset 1
772}
773
774#
775# Disconnect --
776#
777#       Clients use this method to disconnect from the current rendering
778#       server.
779#
780itcl::body Rappture::VtkVolumeViewer::Disconnect {} {
781    VisViewer::Disconnect
782
783    $_dispatcher cancel !rebuild
784    $_dispatcher cancel !resize
785    $_dispatcher cancel !rotate
786    $_dispatcher cancel !xcutplane
787    $_dispatcher cancel !ycutplane
788    $_dispatcher cancel !zcutplane
789    $_dispatcher cancel !legend
790    # disconnected -- no more data sitting on server
791    set _outbuf ""
792    array unset _datasets
793    array unset _data
794    array unset _colormaps
795    array unset _dataset2style
796    array unset _obj2datasets
797}
798
799# ----------------------------------------------------------------------
800# USAGE: ReceiveImage -bytes <size> -type <type> -token <token>
801#
802# Invoked automatically whenever the "image" command comes in from
803# the rendering server.  Indicates that binary image data with the
804# specified <size> will follow.
805# ----------------------------------------------------------------------
806itcl::body Rappture::VtkVolumeViewer::ReceiveImage { args } {
807    array set info {
808        -token "???"
809        -bytes 0
810        -type image
811    }
812    array set info $args
813    set bytes [ReceiveBytes $info(-bytes)]
814    StopWaiting
815    if { $info(-type) == "image" } {
816        if 0 {
817            set f [open "last.ppm" "w"]
818            puts $f $bytes
819            close $f
820        }
821        $_image(plot) configure -data $bytes
822        set time [clock seconds]
823        set date [clock format $time]
824        #puts stderr "$date: received image [image width $_image(plot)]x[image height $_image(plot)] image>"       
825        if { $_start > 0 } {
826            set finish [clock clicks -milliseconds]
827            #puts stderr "round trip time [expr $finish -$_start] milliseconds"
828            set _start 0
829        }
830    } elseif { $info(type) == "print" } {
831        set tag $this-print-$info(-token)
832        set _hardcopy($tag) $bytes
833    }
834    if { $_legendPending } {
835        RequestLegend
836    }
837}
838
839#
840# ReceiveDataset --
841#
842itcl::body Rappture::VtkVolumeViewer::ReceiveDataset { args } {
843    if { ![isconnected] } {
844        return
845    }
846    set option [lindex $args 0]
847    switch -- $option {
848        "scalar" {
849            set option [lindex $args 1]
850            switch -- $option {
851                "world" {
852                    foreach { x y z value tag } [lrange $args 2 end] break
853                }
854                "pixel" {
855                    foreach { x y value tag } [lrange $args 2 end] break
856                }
857            }
858        }
859        "vector" {
860            set option [lindex $args 1]
861            switch -- $option {
862                "world" {
863                    foreach { x y z vx vy vz tag } [lrange $args 2 end] break
864                }
865                "pixel" {
866                    foreach { x y vx vy vz tag } [lrange $args 2 end] break
867                }
868            }
869        }
870        "names" {
871            foreach { name } [lindex $args 1] {
872                #puts stderr "Dataset: $name"
873            }
874        }
875        default {
876            error "unknown dataset option \"$option\" from server"
877        }
878    }
879}
880
881# ----------------------------------------------------------------------
882# USAGE: Rebuild
883#
884# Called automatically whenever something changes that affects the
885# data in the widget.  Clears any existing data and rebuilds the
886# widget to display new data.
887# ----------------------------------------------------------------------
888itcl::body Rappture::VtkVolumeViewer::Rebuild {} {
889    update
890    set w [winfo width $itk_component(view)]
891    set h [winfo height $itk_component(view)]
892    if { $w < 2 || $h < 2 } {
893        $_dispatcher event -idle !rebuild
894        return
895    }
896
897    # Turn on buffering of commands to the server.  We don't want to
898    # be preempted by a server disconnect/reconnect (which automatically
899    # generates a new call to Rebuild).   
900    StartBufferingCommands
901
902    set _legendPending 1
903
904    if { $_reset } {
905        set _width $w
906        set _height $h
907        $_arcball resize $w $h
908        DoResize
909        #
910        # Reset the camera and other view parameters
911        #
912        set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
913        $_arcball quaternion $q
914        if {$_view(ortho)} {
915            SendCmd "camera mode ortho"
916        } else {
917            SendCmd "camera mode persp"
918        }
919        DoRotate
920        InitSettings axis-xgrid axis-ygrid axis-zgrid axisFlyMode \
921            axesVisible axisLabels
922        PanCamera
923    }
924    set _first ""
925
926    SendCmd "imgflush"
927    set _first ""
928
929    SendCmd "dataset visible 0"
930    foreach dataobj [get -objects] {
931        if { [info exists _obj2ovride($dataobj-raise)] &&  $_first == "" } {
932            set _first $dataobj
933        }
934        set _obj2datasets($dataobj) ""
935        foreach comp [$dataobj components] {
936            set tag $dataobj-$comp
937            if { ![info exists _datasets($tag)] } {
938                set bytes [$dataobj vtkdata $comp]
939                set length [string length $bytes]
940                if { $_reportClientInfo }  {
941                    set info {}
942                    lappend info "tool_id"       [$dataobj hints toolId]
943                    lappend info "tool_name"     [$dataobj hints toolName]
944                    lappend info "tool_version"  [$dataobj hints toolRevision]
945                    lappend info "tool_title"    [$dataobj hints toolTitle]
946                    lappend info "dataset_label" [$dataobj hints label]
947                    lappend info "dataset_size"  $length
948                    lappend info "dataset_tag"   $tag
949                    SendCmd [list "clientinfo" $info]
950                }
951                append _outbuf "dataset add $tag data follows $length\n"
952                append _outbuf $bytes
953                set _datasets($tag) 1
954                SetObjectStyle $dataobj $comp
955            }
956            lappend _obj2datasets($dataobj) $tag
957            if { [info exists _obj2ovride($dataobj-raise)] } {
958                SendCmd "dataset visible 1 $tag"
959            }
960            break
961        }
962    }
963    if {"" != $_first} {
964        set location [$_first hints camera]
965        if { $location != "" } {
966            array set view $location
967        }
968
969        foreach axis { x y z } {
970            set label [$_first hints ${axis}label]
971            if { $label != "" } {
972                SendCmd [list axis name $axis $label]
973            }
974            set units [$_first hints ${axis}units]
975            if { $units != "" } {
976                SendCmd [list axis units $axis $units]
977            }
978        }
979        $itk_component(field) choices delete 0 end
980        $itk_component(fieldmenu) delete 0 end
981        array unset _fields
982        set _curFldName ""
983        foreach cname [$_first components] {
984            foreach fname [$_first fieldnames $cname] {
985                if { [info exists _fields($fname)] } {
986                    continue
987                }
988                foreach { label units components } \
989                    [$_first fieldinfo $fname] break
990                # Only scalar fields are valid
991                if {$components == 1} {
992                    $itk_component(field) choices insert end "$fname" "$label"
993                    $itk_component(fieldmenu) add radiobutton -label "$label" \
994                        -value $label -variable [itcl::scope _curFldLabel] \
995                        -selectcolor red \
996                        -activebackground $itk_option(-plotbackground) \
997                        -activeforeground $itk_option(-plotforeground) \
998                        -font "Arial 8" \
999                        -command [itcl::code $this Combo invoke]
1000                    set _fields($fname) [list $label $units $components]
1001                    if { $_curFldName == "" } {
1002                        set _curFldName $fname
1003                        set _curFldLabel $label
1004                    }
1005                }
1006            }
1007        }
1008        $itk_component(field) value $_curFldLabel
1009    }
1010
1011    InitSettings volume-palette volume-material volume-quality volumeVisible \
1012        cutplaneVisible \
1013        cutplane-xposition cutplane-yposition cutplane-zposition \
1014        cutplane-xvisible cutplane-yvisible cutplane-zvisible
1015
1016    if { $_reset } {
1017        InitSettings volumeLighting
1018        Zoom reset
1019        set _reset 0
1020    }
1021    # Actually write the commands to the server socket.  If it fails, we don't
1022    # care.  We're finished here.
1023    blt::busy hold $itk_component(hull)
1024    StopBufferingCommands
1025    blt::busy release $itk_component(hull)
1026}
1027
1028# ----------------------------------------------------------------------
1029# USAGE: CurrentDatasets ?-all -visible? ?dataobjs?
1030#
1031# Returns a list of server IDs for the current datasets being displayed.  This
1032# is normally a single ID, but it might be a list of IDs if the current data
1033# object has multiple components.
1034# ----------------------------------------------------------------------
1035itcl::body Rappture::VtkVolumeViewer::CurrentDatasets {args} {
1036    set flag [lindex $args 0]
1037    switch -- $flag {
1038        "-all" {
1039            if { [llength $args] > 1 } {
1040                error "CurrentDatasets: can't specify dataobj after \"-all\""
1041            }
1042            set dlist [get -objects]
1043        }
1044        "-visible" {
1045            if { [llength $args] > 1 } {
1046                set dlist {}
1047                set args [lrange $args 1 end]
1048                foreach dataobj $args {
1049                    if { [info exists _obj2ovride($dataobj-raise)] } {
1050                        lappend dlist $dataobj
1051                    }
1052                }
1053            } else {
1054                set dlist [get -visible]
1055            }
1056        }           
1057        default {
1058            set dlist $args
1059        }
1060    }
1061    set rlist ""
1062    foreach dataobj $dlist {
1063        foreach comp [$dataobj components] {
1064            set tag $dataobj-$comp
1065            if { [info exists _datasets($tag)] && $_datasets($tag) } {
1066                lappend rlist $tag
1067            }
1068        }
1069    }
1070    return $rlist
1071}
1072
1073# ----------------------------------------------------------------------
1074# USAGE: Zoom in
1075# USAGE: Zoom out
1076# USAGE: Zoom reset
1077#
1078# Called automatically when the user clicks on one of the zoom
1079# controls for this widget.  Changes the zoom for the current view.
1080# ----------------------------------------------------------------------
1081itcl::body Rappture::VtkVolumeViewer::Zoom {option} {
1082    switch -- $option {
1083        "in" {
1084            set _view(zoom) [expr {$_view(zoom)*1.25}]
1085            SendCmd "camera zoom $_view(zoom)"
1086        }
1087        "out" {
1088            set _view(zoom) [expr {$_view(zoom)*0.8}]
1089            SendCmd "camera zoom $_view(zoom)"
1090        }
1091        "reset" {
1092            array set _view {
1093                qw      0.853553
1094                qx      -0.353553
1095                qy      0.353553
1096                qz      0.146447
1097                zoom    1.0
1098                xpan   0
1099                ypan   0
1100            }
1101            if { $_first != "" } {
1102                set location [$_first hints camera]
1103                if { $location != "" } {
1104                    array set _view $location
1105                }
1106            }
1107            set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1108            $_arcball quaternion $q
1109            DoRotate
1110            SendCmd "camera reset"
1111        }
1112    }
1113}
1114
1115itcl::body Rappture::VtkVolumeViewer::PanCamera {} {
1116    set x $_view(xpan)
1117    set y $_view(ypan)
1118    SendCmd "camera pan $x $y"
1119}
1120
1121
1122# ----------------------------------------------------------------------
1123# USAGE: Rotate click <x> <y>
1124# USAGE: Rotate drag <x> <y>
1125# USAGE: Rotate release <x> <y>
1126#
1127# Called automatically when the user clicks/drags/releases in the
1128# plot area.  Moves the plot according to the user's actions.
1129# ----------------------------------------------------------------------
1130itcl::body Rappture::VtkVolumeViewer::Rotate {option x y} {
1131    switch -- $option {
1132        "click" {
1133            $itk_component(view) configure -cursor fleur
1134            set _click(x) $x
1135            set _click(y) $y
1136        }
1137        "drag" {
1138            if {[array size _click] == 0} {
1139                Rotate click $x $y
1140            } else {
1141                set w [winfo width $itk_component(view)]
1142                set h [winfo height $itk_component(view)]
1143                if {$w <= 0 || $h <= 0} {
1144                    return
1145                }
1146
1147                if {[catch {
1148                    # this fails sometimes for no apparent reason
1149                    set dx [expr {double($x-$_click(x))/$w}]
1150                    set dy [expr {double($y-$_click(y))/$h}]
1151                }]} {
1152                    return
1153                }
1154                if { $dx == 0 && $dy == 0 } {
1155                    return
1156                }
1157                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1158                EventuallyRotate $q
1159                set _click(x) $x
1160                set _click(y) $y
1161            }
1162        }
1163        "release" {
1164            Rotate drag $x $y
1165            $itk_component(view) configure -cursor ""
1166            catch {unset _click}
1167        }
1168        default {
1169            error "bad option \"$option\": should be click, drag, release"
1170        }
1171    }
1172}
1173
1174itcl::body Rappture::VtkVolumeViewer::Pick {x y} {
1175    foreach tag [CurrentDatasets -visible] {
1176        SendCmd "dataset getscalar pixel $x $y $tag"
1177    }
1178}
1179
1180# ----------------------------------------------------------------------
1181# USAGE: $this Pan click x y
1182#        $this Pan drag x y
1183#        $this Pan release x y
1184#
1185# Called automatically when the user clicks on one of the zoom
1186# controls for this widget.  Changes the zoom for the current view.
1187# ----------------------------------------------------------------------
1188itcl::body Rappture::VtkVolumeViewer::Pan {option x y} {
1189    switch -- $option {
1190        "set" {
1191            set w [winfo width $itk_component(view)]
1192            set h [winfo height $itk_component(view)]
1193            set x [expr $x / double($w)]
1194            set y [expr $y / double($h)]
1195            set _view(xpan) [expr $_view(xpan) + $x]
1196            set _view(ypan) [expr $_view(ypan) + $y]
1197            PanCamera
1198            return
1199        }
1200        "click" {
1201            set _click(x) $x
1202            set _click(y) $y
1203            $itk_component(view) configure -cursor hand1
1204        }
1205        "drag" {
1206            if { ![info exists _click(x)] } {
1207                set _click(x) $x
1208            }
1209            if { ![info exists _click(y)] } {
1210                set _click(y) $y
1211            }
1212            set w [winfo width $itk_component(view)]
1213            set h [winfo height $itk_component(view)]
1214            set dx [expr ($_click(x) - $x)/double($w)]
1215            set dy [expr ($_click(y) - $y)/double($h)]
1216            set _click(x) $x
1217            set _click(y) $y
1218            set _view(xpan) [expr $_view(xpan) - $dx]
1219            set _view(ypan) [expr $_view(ypan) - $dy]
1220            PanCamera
1221        }
1222        "release" {
1223            Pan drag $x $y
1224            $itk_component(view) configure -cursor ""
1225        }
1226        default {
1227            error "unknown option \"$option\": should set, click, drag, or release"
1228        }
1229    }
1230}
1231
1232# ----------------------------------------------------------------------
1233# USAGE: InitSettings <what> ?<value>?
1234#
1235# Used internally to update rendering settings whenever parameters
1236# change in the popup settings panel.  Sends the new settings off
1237# to the back end.
1238# ----------------------------------------------------------------------
1239itcl::body Rappture::VtkVolumeViewer::InitSettings { args } {
1240    foreach spec $args {
1241        if { [info exists _settings($_first-$spec)] } {
1242            # Reset global setting with dataobj specific setting
1243            set _settings($spec) $_settings($_first-$spec)
1244        }
1245        AdjustSetting $spec
1246    }
1247}
1248
1249#
1250# AdjustSetting --
1251#
1252#       Changes/updates a specific setting in the widget.  There are
1253#       usually user-setable option.  Commands are sent to the render
1254#       server.
1255#
1256itcl::body Rappture::VtkVolumeViewer::AdjustSetting {what {value ""}} {
1257    if { ![isconnected] } {
1258        return
1259    }
1260    switch -- $what {
1261        "volumeVisible" {
1262            set bool $_settings($what)
1263            foreach dataset [CurrentDatasets -visible] {
1264                SendCmd "volume visible $bool $dataset"
1265            }
1266            if { $bool } {
1267                Rappture::Tooltip::for $itk_component(volume) \
1268                    "Hide the volume"
1269            } else {
1270                Rappture::Tooltip::for $itk_component(volume) \
1271                    "Show the volume"
1272            }
1273        }
1274        "volume-material" {
1275            set val $_settings($what)
1276            set diffuse [expr {0.01*$val}]
1277            set specular [expr {0.01*$val}]
1278            #set power [expr {sqrt(160*$val+1.0)}]
1279            set power [expr {$val+1.0}]
1280            foreach dataset [CurrentDatasets -visible] {
1281                SendCmd "volume shading diffuse $diffuse $dataset"
1282                SendCmd "volume shading specular $specular $power $dataset"
1283            }
1284        }
1285        "volumeLighting" {
1286            set bool $_settings($what)
1287            foreach dataset [CurrentDatasets -visible] {
1288                SendCmd "volume lighting $bool $dataset"
1289            }
1290        }
1291        "volume-quality" {
1292            set val $_settings($what)
1293            set val [expr {0.01*$val}]
1294            foreach dataset [CurrentDatasets -visible] {
1295                SendCmd "volume quality $val $dataset"
1296            }
1297        }
1298        "axesVisible" {
1299            set bool $_settings($what)
1300            SendCmd "axis visible all $bool"
1301        }
1302        "axisLabels" {
1303            set bool $_settings($what)
1304            SendCmd "axis labels all $bool"
1305        }
1306        "axis-xgrid" - "axis-ygrid" - "axis-zgrid" {
1307            set axis [string range $what 5 5]
1308            set bool $_settings($what)
1309            SendCmd "axis grid $axis $bool"
1310        }
1311        "axisFlyMode" {
1312            set mode [$itk_component(axismode) value]
1313            set mode [$itk_component(axismode) translate $mode]
1314            set _settings($what) $mode
1315            SendCmd "axis flymode $mode"
1316        }
1317        "cutplaneEdges" {
1318            set bool $_settings($what)
1319            foreach dataset [CurrentDatasets -visible] {
1320                SendCmd "cutplane edges $bool $dataset"
1321            }
1322        }
1323        "cutplaneVisible" {
1324            set bool $_settings($what)
1325            foreach dataset [CurrentDatasets -visible] {
1326                SendCmd "cutplane visible $bool $dataset"
1327            }
1328        }
1329        "cutplaneWireframe" {
1330            set bool $_settings($what)
1331            foreach dataset [CurrentDatasets -visible] {
1332                SendCmd "cutplane wireframe $bool $dataset"
1333            }
1334        }
1335        "cutplaneLighting" {
1336            set bool $_settings($what)
1337            foreach dataset [CurrentDatasets -visible] {
1338                SendCmd "cutplane lighting $bool $dataset"
1339            }
1340        }
1341        "cutplane-opacity" {
1342            set val $_settings($what)
1343            set sval [expr { 0.01 * double($val) }]
1344            foreach dataset [CurrentDatasets -visible] {
1345                SendCmd "cutplane opacity $sval $dataset"
1346            }
1347        }
1348        "cutplane-xvisible" - "cutplane-yvisible" - "cutplane-zvisible" {
1349            set axis [string range $what 9 9]
1350            set bool $_settings($what)
1351            if { $bool } {
1352                $itk_component(${axis}CutScale) configure -state normal \
1353                    -troughcolor white
1354            } else {
1355                $itk_component(${axis}CutScale) configure -state disabled \
1356                    -troughcolor grey82
1357            }
1358            foreach dataset [CurrentDatasets -visible] {
1359                SendCmd "cutplane axis $axis $bool $dataset"
1360            }
1361        }
1362        "cutplane-xposition" - "cutplane-yposition" - "cutplane-zposition" {
1363            set axis [string range $what 9 9]
1364            set pos [expr $_settings($what) * 0.01]
1365            foreach dataset [CurrentDatasets -visible] {
1366                SendCmd "cutplane slice ${axis} ${pos} $dataset"
1367            }
1368            set _cutplanePending 0
1369        }
1370        "volume-palette" {
1371            set palette [$itk_component(palette) value]
1372            set _settings($what) $palette
1373            foreach dataset [CurrentDatasets -visible $_first] {
1374                foreach {dataobj comp} [split $dataset -] break
1375                ChangeColormap $dataobj $comp $palette
1376            }
1377            set _legendPending 1
1378        }
1379        "field" {
1380            set label [$itk_component(field) value]
1381            set fname [$itk_component(field) translate $label]
1382            set _settings($what) $fname
1383            if { [info exists _fields($fname)] } {
1384                foreach { label units components } $_fields($fname) break
1385                if { $components > 1 } {
1386                    puts stderr "Can't use a vector field in a volume"
1387                    return
1388                } else {
1389                    set _colorMode scalar
1390                }
1391                set _curFldName $fname
1392                set _curFldLabel $label
1393            } else {
1394                puts stderr "unknown field \"$fname\""
1395                return
1396            }
1397            foreach dataset [CurrentDatasets -visible $_first] {
1398                #SendCmd "volume colormode $_colorMode ${fname} $dataset"
1399                SendCmd "cutplane colormode $_colorMode ${fname} $dataset"
1400            }
1401            SendCmd "camera reset"
1402            DrawLegend
1403        }
1404        default {
1405            error "don't know how to fix $what"
1406        }
1407    }
1408}
1409
1410#
1411# RequestLegend --
1412#
1413#       Request a new legend from the server.  The size of the legend
1414#       is determined from the height of the canvas.  It will be rotated
1415#       to be vertical when drawn.
1416#
1417itcl::body Rappture::VtkVolumeViewer::RequestLegend {} {
1418    set font "Arial 8"
1419    set lineht [font metrics $font -linespace]
1420    set c $itk_component(legend)
1421    set w 12
1422    set h [expr {$_height - 3 * ($lineht + 2)}]
1423    if { $h < 1} {
1424        return
1425    }
1426    # Set the legend on the first volume dataset.
1427    foreach dataset [CurrentDatasets -visible $_first] {
1428        foreach {dataobj comp} [split $dataset -] break
1429        if { [info exists _dataset2style($dataset)] } {
1430            SendCmdNoWait \
1431                "legend $_dataset2style($dataset) $_colorMode $_curFldName {} $w $h 0"
1432            break;
1433        }
1434    }
1435}
1436
1437#
1438# ChangeColormap --
1439#
1440itcl::body Rappture::VtkVolumeViewer::ChangeColormap {dataobj comp color} {
1441    set tag $dataobj-$comp
1442    if { ![info exist _style($tag)] } {
1443        error "no initial colormap"
1444    }
1445    array set style $_style($tag)
1446    set style(-color) $color
1447    set _style($tag) [array get style]
1448    SetColormap $dataobj $comp
1449}
1450
1451#
1452# SetColormap --
1453#
1454itcl::body Rappture::VtkVolumeViewer::SetColormap { dataobj comp } {
1455    array set style {
1456        -color BCGYR
1457        -levels 6
1458        -opacity 1.0
1459    }
1460    set tag $dataobj-$comp
1461    if { ![info exists _initialStyle($tag)] } {
1462        # Save the initial component style.
1463        set _initialStyle($tag) [$dataobj style $comp]
1464    }
1465
1466    # Override defaults with initial style defined in xml.
1467    array set style $_initialStyle($tag)
1468
1469    if { ![info exists _style($tag)] } {
1470        set _style($tag) [array get style]
1471    }
1472    # Override initial style with current style.
1473    array set style $_style($tag)
1474
1475    set name "$style(-color):$style(-levels):$style(-opacity)"
1476    if { ![info exists _colormaps($name)] } {
1477        BuildColormap $name [array get style]
1478        set _colormaps($name) 1
1479    }
1480    if { ![info exists _dataset2style($tag)] ||
1481         $_dataset2style($tag) != $name } {
1482        SendCmd "volume colormap $name $tag"
1483        SendCmd "cutplane colormap $name-opaque $tag"
1484        set _dataset2style($tag) $name
1485    }
1486}
1487
1488#
1489# BuildColormap --
1490#
1491itcl::body Rappture::VtkVolumeViewer::BuildColormap { name styles } {
1492    array set style $styles
1493    set cmap [ColorsToColormap $style(-color)]
1494    if { [llength $cmap] == 0 } {
1495        set cmap "0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0"
1496    }
1497    if { ![info exists _settings(volume-opacity)] } {
1498        set _settings(volume-opacity) $style(-opacity)
1499    }
1500    set max $_settings(volume-opacity)
1501
1502    set opaqueWmap "0.0 1.0 1.0 1.0"
1503    #set wmap "0.0 0.0 0.1 0.0 0.2 0.8 0.98 0.8 0.99 0.0 1.0 0.0"
1504    # Approximate cubic opacity curve
1505    set wmap "0.0 0.0 0.1 0.001 0.2 0.008 0.3 0.027 0.4 0.064 0.5 0.125 0.6 0.216 0.7 0.343 0.8 0.512 0.9 0.729 1.0 1.0"
1506    SendCmd "colormap add $name { $cmap } { $wmap }"
1507    SendCmd "colormap add $name-opaque { $cmap } { $opaqueWmap }"
1508}
1509
1510# ----------------------------------------------------------------------
1511# CONFIGURATION OPTION: -plotbackground
1512# ----------------------------------------------------------------------
1513itcl::configbody Rappture::VtkVolumeViewer::plotbackground {
1514    if { [isconnected] } {
1515        foreach {r g b} [Color2RGB $itk_option(-plotbackground)] break
1516        SendCmd "screen bgcolor $r $g $b"
1517    }
1518}
1519
1520# ----------------------------------------------------------------------
1521# CONFIGURATION OPTION: -plotforeground
1522# ----------------------------------------------------------------------
1523itcl::configbody Rappture::VtkVolumeViewer::plotforeground {
1524    if { [isconnected] } {
1525        foreach {r g b} [Color2RGB $itk_option(-plotforeground)] break
1526        #fix this!
1527        #SendCmd "color background $r $g $b"
1528    }
1529}
1530
1531itcl::body Rappture::VtkVolumeViewer::BuildVolumeTab {} {
1532
1533    set fg [option get $itk_component(hull) font Font]
1534    #set bfg [option get $itk_component(hull) boldFont Font]
1535
1536    set inner [$itk_component(main) insert end \
1537        -title "Volume Settings" \
1538        -icon [Rappture::icon volume-on]]
1539    $inner configure -borderwidth 4
1540
1541    checkbutton $inner.volume \
1542        -text "Show Volume" \
1543        -variable [itcl::scope _settings(volumeVisible)] \
1544        -command [itcl::code $this AdjustSetting volumeVisible] \
1545        -font "Arial 9"
1546
1547    checkbutton $inner.lighting \
1548        -text "Enable Lighting" \
1549        -variable [itcl::scope _settings(volumeLighting)] \
1550        -command [itcl::code $this AdjustSetting volumeLighting] \
1551        -font "Arial 9"
1552
1553    label $inner.dim_l -text "Dim" -font "Arial 9"
1554    ::scale $inner.material -from 0 -to 100 -orient horizontal \
1555        -variable [itcl::scope _settings(volume-material)] \
1556        -width 10 \
1557        -showvalue off -command [itcl::code $this AdjustSetting volume-material]
1558    label $inner.bright_l -text "Bright" -font "Arial 9"
1559
1560    label $inner.opacity_l -text "Opacity" -font "Arial 9"
1561    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1562        -variable [itcl::scope _settings(volume-opacity)] \
1563        -width 10 \
1564        -showvalue off \
1565        -command [itcl::code $this AdjustSetting volume-opacity]
1566
1567    label $inner.quality_l -text "Quality" -font "Arial 9"
1568    ::scale $inner.quality -from 0 -to 100 -orient horizontal \
1569        -variable [itcl::scope _settings(volume-quality)] \
1570        -width 10 \
1571        -showvalue off -command [itcl::code $this AdjustSetting volume-quality]
1572
1573    itk_component add field_l {
1574        label $inner.field_l -text "Field" -font "Arial 9"
1575    } {
1576        ignore -font
1577    }
1578    itk_component add field {
1579        Rappture::Combobox $inner.field -width 10 -editable no
1580    }
1581    bind $inner.field <<Value>> \
1582        [itcl::code $this AdjustSetting field]
1583
1584    label $inner.palette_l -text "Palette" -font "Arial 9"
1585    itk_component add palette {
1586        Rappture::Combobox $inner.palette -width 10 -editable no
1587    }
1588
1589    $inner.palette choices insert end [GetColormapList]
1590    $itk_component(palette) value "BCGYR"
1591    bind $inner.palette <<Value>> \
1592        [itcl::code $this AdjustSetting volume-palette]
1593
1594    blt::table $inner \
1595        0,0 $inner.field_l   -anchor w -pady 2  \
1596        0,1 $inner.field     -anchor w -pady 2 -cspan 2 \
1597        1,0 $inner.volume    -anchor w -pady 2 -cspan 4 \
1598        2,0 $inner.lighting  -anchor w -pady 2 -cspan 4 \
1599        3,0 $inner.dim_l     -anchor e -pady 2 \
1600        3,1 $inner.material  -fill x   -pady 2 \
1601        3,2 $inner.bright_l  -anchor w -pady 2 \
1602        4,0 $inner.quality_l -anchor w -pady 2 -cspan 2 \
1603        5,0 $inner.quality   -fill x   -pady 2 -cspan 2 \
1604        7,0 $inner.palette_l -anchor w -pady 2  \
1605        7,1 $inner.palette   -anchor w -pady 2 -cspan 2 \
1606
1607    blt::table configure $inner r* c* -resize none
1608    blt::table configure $inner r8 -resize expand
1609}
1610
1611itcl::body Rappture::VtkVolumeViewer::BuildAxisTab {} {
1612
1613    set fg [option get $itk_component(hull) font Font]
1614    #set bfg [option get $itk_component(hull) boldFont Font]
1615
1616    set inner [$itk_component(main) insert end \
1617        -title "Axis Settings" \
1618        -icon [Rappture::icon axis1]]
1619    $inner configure -borderwidth 4
1620
1621    checkbutton $inner.visible \
1622        -text "Show Axes" \
1623        -variable [itcl::scope _settings(axesVisible)] \
1624        -command [itcl::code $this AdjustSetting axesVisible] \
1625        -font "Arial 9"
1626
1627    checkbutton $inner.labels \
1628        -text "Show Axis Labels" \
1629        -variable [itcl::scope _settings(axisLabels)] \
1630        -command [itcl::code $this AdjustSetting axisLabels] \
1631        -font "Arial 9"
1632
1633    checkbutton $inner.gridx \
1634        -text "Show X Grid" \
1635        -variable [itcl::scope _settings(axis-xgrid)] \
1636        -command [itcl::code $this AdjustSetting axis-xgrid] \
1637        -font "Arial 9"
1638    checkbutton $inner.gridy \
1639        -text "Show Y Grid" \
1640        -variable [itcl::scope _settings(axis-ygrid)] \
1641        -command [itcl::code $this AdjustSetting axis-ygrid] \
1642        -font "Arial 9"
1643    checkbutton $inner.gridz \
1644        -text "Show Z Grid" \
1645        -variable [itcl::scope _settings(axis-zgrid)] \
1646        -command [itcl::code $this AdjustSetting axis-zgrid] \
1647        -font "Arial 9"
1648
1649    label $inner.mode_l -text "Mode" -font "Arial 9"
1650
1651    itk_component add axismode {
1652        Rappture::Combobox $inner.mode -width 10 -editable no
1653    }
1654    $inner.mode choices insert end \
1655        "static_triad"    "static" \
1656        "closest_triad"   "closest" \
1657        "furthest_triad"  "farthest" \
1658        "outer_edges"     "outer"         
1659    $itk_component(axismode) value "static"
1660    bind $inner.mode <<Value>> [itcl::code $this AdjustSetting axisFlyMode]
1661
1662    blt::table $inner \
1663        0,0 $inner.visible -anchor w -cspan 2 \
1664        1,0 $inner.labels  -anchor w -cspan 2 \
1665        2,0 $inner.gridx   -anchor w -cspan 2 \
1666        3,0 $inner.gridy   -anchor w -cspan 2 \
1667        4,0 $inner.gridz   -anchor w -cspan 2 \
1668        5,0 $inner.mode_l  -anchor w -cspan 2 -padx { 2 0 } \
1669        6,0 $inner.mode    -fill x   -cspan 2
1670
1671    blt::table configure $inner r* c* -resize none
1672    blt::table configure $inner r7 c1 -resize expand
1673}
1674
1675
1676itcl::body Rappture::VtkVolumeViewer::BuildCameraTab {} {
1677    set inner [$itk_component(main) insert end \
1678        -title "Camera Settings" \
1679        -icon [Rappture::icon camera]]
1680    $inner configure -borderwidth 4
1681
1682    set labels { qx qy qz qw xpan ypan zoom }
1683    set row 0
1684    foreach tag $labels {
1685        label $inner.${tag}label -text $tag -font "Arial 9"
1686        entry $inner.${tag} -font "Arial 9"  -bg white \
1687            -textvariable [itcl::scope _view($tag)]
1688        bind $inner.${tag} <KeyPress-Return> \
1689            [itcl::code $this camera set ${tag}]
1690        blt::table $inner \
1691            $row,0 $inner.${tag}label -anchor e -pady 2 \
1692            $row,1 $inner.${tag} -anchor w -pady 2
1693        blt::table configure $inner r$row -resize none
1694        incr row
1695    }
1696    checkbutton $inner.ortho \
1697        -text "Orthographic Projection" \
1698        -variable [itcl::scope _view(ortho)] \
1699        -command [itcl::code $this camera set ortho] \
1700        -font "Arial 9"
1701    blt::table $inner \
1702            $row,0 $inner.ortho -cspan 2 -anchor w -pady 2
1703    blt::table configure $inner r$row -resize none
1704    incr row
1705
1706    blt::table configure $inner c0 c1 -resize none
1707    blt::table configure $inner c2 -resize expand
1708    blt::table configure $inner r$row -resize expand
1709}
1710
1711itcl::body Rappture::VtkVolumeViewer::BuildCutplaneTab {} {
1712
1713    set fg [option get $itk_component(hull) font Font]
1714   
1715    set inner [$itk_component(main) insert end \
1716        -title "Cutplane Settings" \
1717        -icon [Rappture::icon cutbutton]]
1718
1719    $inner configure -borderwidth 4
1720
1721    checkbutton $inner.visible \
1722        -text "Show Cutplanes" \
1723        -variable [itcl::scope _settings(cutplaneVisible)] \
1724        -command [itcl::code $this AdjustSetting cutplaneVisible] \
1725        -font "Arial 9"
1726
1727    checkbutton $inner.wireframe \
1728        -text "Show Wireframe" \
1729        -variable [itcl::scope _settings(cutplaneWireframe)] \
1730        -command [itcl::code $this AdjustSetting cutplaneWireframe] \
1731        -font "Arial 9"
1732
1733    checkbutton $inner.lighting \
1734        -text "Enable Lighting" \
1735        -variable [itcl::scope _settings(cutplaneLighting)] \
1736        -command [itcl::code $this AdjustSetting cutplaneLighting] \
1737        -font "Arial 9"
1738
1739    checkbutton $inner.edges \
1740        -text "Show Edges" \
1741        -variable [itcl::scope _settings(cutplaneEdges)] \
1742        -command [itcl::code $this AdjustSetting cutplaneEdges] \
1743        -font "Arial 9"
1744
1745    label $inner.opacity_l -text "Opacity" -font "Arial 9"
1746    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1747        -variable [itcl::scope _settings(cutplane-opacity)] \
1748        -width 10 \
1749        -showvalue off \
1750        -command [itcl::code $this AdjustSetting cutplane-opacity]
1751    $inner.opacity set $_settings(cutplane-opacity)
1752
1753    # X-value slicer...
1754    itk_component add xCutButton {
1755        Rappture::PushButton $inner.xbutton \
1756            -onimage [Rappture::icon x-cutplane] \
1757            -offimage [Rappture::icon x-cutplane] \
1758            -command [itcl::code $this AdjustSetting cutplane-xvisible] \
1759            -variable [itcl::scope _settings(cutplane-xvisible)]
1760    }
1761    Rappture::Tooltip::for $itk_component(xCutButton) \
1762        "Toggle the X-axis cutplane on/off"
1763    $itk_component(xCutButton) select
1764
1765    itk_component add xCutScale {
1766        ::scale $inner.xval -from 100 -to 0 \
1767            -width 10 -orient vertical -showvalue yes \
1768            -borderwidth 1 -highlightthickness 0 \
1769            -command [itcl::code $this EventuallySetCutplane x] \
1770            -variable [itcl::scope _settings(cutplane-xposition)]
1771    } {
1772        usual
1773        ignore -borderwidth -highlightthickness
1774    }
1775    # Set the default cutplane value before disabling the scale.
1776    $itk_component(xCutScale) set 50
1777    $itk_component(xCutScale) configure -state disabled
1778    Rappture::Tooltip::for $itk_component(xCutScale) \
1779        "@[itcl::code $this Slice tooltip x]"
1780
1781    # Y-value slicer...
1782    itk_component add yCutButton {
1783        Rappture::PushButton $inner.ybutton \
1784            -onimage [Rappture::icon y-cutplane] \
1785            -offimage [Rappture::icon y-cutplane] \
1786            -command [itcl::code $this AdjustSetting cutplane-yvisible] \
1787            -variable [itcl::scope _settings(cutplane-yvisible)]
1788    }
1789    Rappture::Tooltip::for $itk_component(yCutButton) \
1790        "Toggle the Y-axis cutplane on/off"
1791    $itk_component(yCutButton) select
1792
1793    itk_component add yCutScale {
1794        ::scale $inner.yval -from 100 -to 0 \
1795            -width 10 -orient vertical -showvalue yes \
1796            -borderwidth 1 -highlightthickness 0 \
1797            -command [itcl::code $this EventuallySetCutplane y] \
1798            -variable [itcl::scope _settings(cutplane-yposition)]
1799    } {
1800        usual
1801        ignore -borderwidth -highlightthickness
1802    }
1803    Rappture::Tooltip::for $itk_component(yCutScale) \
1804        "@[itcl::code $this Slice tooltip y]"
1805    # Set the default cutplane value before disabling the scale.
1806    $itk_component(yCutScale) set 50
1807    $itk_component(yCutScale) configure -state disabled
1808
1809    # Z-value slicer...
1810    itk_component add zCutButton {
1811        Rappture::PushButton $inner.zbutton \
1812            -onimage [Rappture::icon z-cutplane] \
1813            -offimage [Rappture::icon z-cutplane] \
1814            -command [itcl::code $this AdjustSetting cutplane-zvisible] \
1815            -variable [itcl::scope _settings(cutplane-zvisible)]
1816    }
1817    Rappture::Tooltip::for $itk_component(zCutButton) \
1818        "Toggle the Z-axis cutplane on/off"
1819    $itk_component(zCutButton) select
1820
1821    itk_component add zCutScale {
1822        ::scale $inner.zval -from 100 -to 0 \
1823            -width 10 -orient vertical -showvalue yes \
1824            -borderwidth 1 -highlightthickness 0 \
1825            -command [itcl::code $this EventuallySetCutplane z] \
1826            -variable [itcl::scope _settings(cutplane-zposition)]
1827    } {
1828        usual
1829        ignore -borderwidth -highlightthickness
1830    }
1831    $itk_component(zCutScale) set 50
1832    $itk_component(zCutScale) configure -state disabled
1833    Rappture::Tooltip::for $itk_component(zCutScale) \
1834        "@[itcl::code $this Slice tooltip z]"
1835
1836    blt::table $inner \
1837        0,0 $inner.visible              -anchor w -pady 2 -cspan 4 \
1838        1,0 $inner.lighting             -anchor w -pady 2 -cspan 4 \
1839        2,0 $inner.wireframe            -anchor w -pady 2 -cspan 4 \
1840        3,0 $inner.edges                -anchor w -pady 2 -cspan 4 \
1841        4,0 $inner.opacity_l            -anchor w -pady 2 -cspan 3 \
1842        5,0 $inner.opacity              -fill x   -pady 2 -cspan 3 \
1843        6,0 $itk_component(xCutButton)  -anchor e -padx 2 -pady 2 \
1844        7,0 $itk_component(xCutScale)   -fill y \
1845        6,1 $itk_component(yCutButton)  -anchor e -padx 2 -pady 2 \
1846        7,1 $itk_component(yCutScale)   -fill y \
1847        6,2 $itk_component(zCutButton)  -anchor e -padx 2 -pady 2 \
1848        7,2 $itk_component(zCutScale)   -fill y \
1849
1850    blt::table configure $inner r* c* -resize none
1851    blt::table configure $inner r7 c3 -resize expand
1852}
1853
1854#
1855#  camera --
1856#
1857itcl::body Rappture::VtkVolumeViewer::camera {option args} {
1858    switch -- $option {
1859        "show" {
1860            puts [array get _view]
1861        }
1862        "set" {
1863            set who [lindex $args 0]
1864            set x $_view($who)
1865            set code [catch { string is double $x } result]
1866            if { $code != 0 || !$result } {
1867                return
1868            }
1869            switch -- $who {
1870                "ortho" {
1871                    if {$_view(ortho)} {
1872                        SendCmd "camera mode ortho"
1873                    } else {
1874                        SendCmd "camera mode persp"
1875                    }
1876                }
1877                "xpan" - "ypan" {
1878                    PanCamera
1879                }
1880                "qx" - "qy" - "qz" - "qw" {
1881                    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1882                    $_arcball quaternion $q
1883                    EventuallyRotate $q
1884                }
1885                "zoom" {
1886                    SendCmd "camera zoom $_view(zoom)"
1887                }
1888            }
1889        }
1890    }
1891}
1892
1893itcl::body Rappture::VtkVolumeViewer::GetVtkData { args } {
1894    set bytes ""
1895    foreach dataobj [get] {
1896        foreach comp [$dataobj components] {
1897            set tag $dataobj-$comp
1898            set contents [$dataobj vtkdata $comp]
1899            append bytes "$contents\n"
1900        }
1901    }
1902    return [list .vtk $bytes]
1903}
1904
1905itcl::body Rappture::VtkVolumeViewer::GetImage { args } {
1906    if { [image width $_image(download)] > 0 &&
1907         [image height $_image(download)] > 0 } {
1908        set bytes [$_image(download) data -format "jpeg -quality 100"]
1909        set bytes [Rappture::encoding::decode -as b64 $bytes]
1910        return [list .jpg $bytes]
1911    }
1912    return ""
1913}
1914
1915itcl::body Rappture::VtkVolumeViewer::BuildDownloadPopup { popup command } {
1916    Rappture::Balloon $popup \
1917        -title "[Rappture::filexfer::label downloadWord] as..."
1918    set inner [$popup component inner]
1919    label $inner.summary -text "" -anchor w
1920    radiobutton $inner.vtk_button -text "VTK data file" \
1921        -variable [itcl::scope _downloadPopup(format)] \
1922        -font "Helvetica 9 " \
1923        -value vtk 
1924    Rappture::Tooltip::for $inner.vtk_button "Save as VTK data file."
1925    radiobutton $inner.image_button -text "Image File" \
1926        -variable [itcl::scope _downloadPopup(format)] \
1927        -value image
1928    Rappture::Tooltip::for $inner.image_button \
1929        "Save as digital image."
1930
1931    button $inner.ok -text "Save" \
1932        -highlightthickness 0 -pady 2 -padx 3 \
1933        -command $command \
1934        -compound left \
1935        -image [Rappture::icon download]
1936
1937    button $inner.cancel -text "Cancel" \
1938        -highlightthickness 0 -pady 2 -padx 3 \
1939        -command [list $popup deactivate] \
1940        -compound left \
1941        -image [Rappture::icon cancel]
1942
1943    blt::table $inner \
1944        0,0 $inner.summary -cspan 2  \
1945        1,0 $inner.vtk_button -anchor w -cspan 2 -padx { 4 0 } \
1946        2,0 $inner.image_button -anchor w -cspan 2 -padx { 4 0 } \
1947        4,1 $inner.cancel -width .9i -fill y \
1948        4,0 $inner.ok -padx 2 -width .9i -fill y
1949    blt::table configure $inner r3 -height 4
1950    blt::table configure $inner r4 -pady 4
1951    raise $inner.image_button
1952    $inner.vtk_button invoke
1953    return $inner
1954}
1955
1956itcl::body Rappture::VtkVolumeViewer::SetObjectStyle { dataobj comp } {
1957    # Parse style string.
1958    set tag $dataobj-$comp
1959    set style [$dataobj style $comp]
1960    array set settings {
1961        -color \#808080
1962        -edges 0
1963        -edgecolor black
1964        -linewidth 1.0
1965        -opacity 0.4
1966        -wireframe 0
1967        -lighting 1
1968        -seeds 1
1969        -seedcolor white
1970        -visible 1
1971    }
1972    if { $dataobj != $_first } {
1973        set settings(-opacity) 1
1974    }
1975    array set settings $style
1976    SendCmd "volume add $tag"
1977    SendCmd "cutplane add $tag"
1978    SendCmd "cutplane visible 0 $tag"
1979
1980    SendCmd "volume lighting $settings(-lighting) $tag"
1981    set _settings(volumeLighting) $settings(-lighting)
1982    SetColormap $dataobj $comp
1983}
1984
1985itcl::body Rappture::VtkVolumeViewer::IsValidObject { dataobj } {
1986    if {[catch {$dataobj isa Rappture::Field} valid] != 0 || !$valid} {
1987        return 0
1988    }
1989    return 1
1990}
1991
1992# ----------------------------------------------------------------------
1993# USAGE: ReceiveLegend <colormap> <title> <vmin> <vmax> <size>
1994#
1995# Invoked automatically whenever the "legend" command comes in from
1996# the rendering server.  Indicates that binary image data with the
1997# specified <size> will follow.
1998# ----------------------------------------------------------------------
1999itcl::body Rappture::VtkVolumeViewer::ReceiveLegend { colormap title vmin vmax size } {
2000    set _legendPending 0
2001    #puts stderr "ReceiveLegend colormap=$colormap title=$title range=$vmin,$vmax size=$size"
2002    if { [IsConnected] } {
2003        set bytes [ReceiveBytes $size]
2004        if { ![info exists _image(legend)] } {
2005            set _image(legend) [image create photo]
2006        }
2007        $_image(legend) configure -data $bytes
2008        #puts stderr "read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
2009        if { [catch {DrawLegend} errs] != 0 } {
2010            puts stderr errs=$errs
2011        }
2012    }
2013}
2014
2015#
2016# DrawLegend --
2017#
2018#       Draws the legend in it's own canvas which resides to the right
2019#       of the contour plot area.
2020#
2021itcl::body Rappture::VtkVolumeViewer::DrawLegend { } {
2022    set fname $_curFldName
2023    set c $itk_component(view)
2024    set w [winfo width $c]
2025    set h [winfo height $c]
2026    set font "Arial 8"
2027    set lineht [font metrics $font -linespace]
2028   
2029    if { [info exists _fields($fname)] } {
2030        foreach { title units } $_fields($fname) break
2031        if { $units != "" } {
2032            set title [format "%s (%s)" $title $units]
2033        }
2034    } else {
2035        set title $fname
2036    }
2037    if { $_settings(legendVisible) } {
2038        set x [expr $w - 2]
2039        if { [$c find withtag "legend"] == "" } {
2040            set y 2
2041            $c create text $x $y \
2042                -anchor ne \
2043                -fill $itk_option(-plotforeground) -tags "title legend" \
2044                -font $font
2045            incr y $lineht
2046            $c create text $x $y \
2047                -anchor ne \
2048                -fill $itk_option(-plotforeground) -tags "vmax legend" \
2049                -font $font
2050            incr y $lineht
2051            $c create image $x $y \
2052                -anchor ne \
2053                -image $_image(legend) -tags "colormap legend"
2054            $c create text $x [expr {$h-2}] \
2055                -anchor se \
2056                -fill $itk_option(-plotforeground) -tags "vmin legend" \
2057                -font $font
2058            #$c bind colormap <Enter> [itcl::code $this EnterLegend %x %y]
2059            $c bind colormap <Leave> [itcl::code $this LeaveLegend]
2060            $c bind colormap <Motion> [itcl::code $this MotionLegend %x %y]
2061        }
2062        $c bind title <ButtonPress> [itcl::code $this Combo post]
2063        $c bind title <Enter> [itcl::code $this Combo activate]
2064        $c bind title <Leave> [itcl::code $this Combo deactivate]
2065        # Reset the item coordinates according the current size of the plot.
2066        $c itemconfigure title -text $title
2067        if { [info exists _limits($_curFldName)] } {
2068            foreach { vmin vmax } $_limits($_curFldName) break
2069            $c itemconfigure vmin -text [format %g $vmin]
2070            $c itemconfigure vmax -text [format %g $vmax]
2071        }
2072        set y 2
2073        $c coords title $x $y
2074        incr y $lineht
2075        $c coords vmax $x $y
2076        incr y $lineht
2077        $c coords colormap $x $y
2078        $c coords vmin $x [expr {$h - 2}]
2079    }
2080}
2081
2082#
2083# EnterLegend --
2084#
2085itcl::body Rappture::VtkVolumeViewer::EnterLegend { x y } {
2086    SetLegendTip $x $y
2087}
2088
2089#
2090# MotionLegend --
2091#
2092itcl::body Rappture::VtkVolumeViewer::MotionLegend { x y } {
2093    Rappture::Tooltip::tooltip cancel
2094    set c $itk_component(view)
2095    SetLegendTip $x $y
2096}
2097
2098#
2099# LeaveLegend --
2100#
2101itcl::body Rappture::VtkVolumeViewer::LeaveLegend { } {
2102    Rappture::Tooltip::tooltip cancel
2103    .rappturetooltip configure -icon ""
2104}
2105
2106#
2107# SetLegendTip --
2108#
2109itcl::body Rappture::VtkVolumeViewer::SetLegendTip { x y } {
2110    set c $itk_component(view)
2111    set w [winfo width $c]
2112    set h [winfo height $c]
2113    set font "Arial 8"
2114    set lineht [font metrics $font -linespace]
2115   
2116    set imgHeight [image height $_image(legend)]
2117    set coords [$c coords colormap]
2118    set imgX [expr $w - [image width $_image(legend)] - 2]
2119    set imgY [expr $y - 2 * ($lineht + 2)]
2120
2121    if { [info exists _fields($_title)] } {
2122        foreach { title units } $_fields($_title) break
2123        if { $units != "" } {
2124            set title [format "%s (%s)" $title $units]
2125        }
2126    } else {
2127        set title $_title
2128    }
2129    # Make a swatch of the selected color
2130    if { [catch { $_image(legend) get 10 $imgY } pixel] != 0 } {
2131        #puts stderr "out of range: $imgY"
2132        return
2133    }
2134    if { ![info exists _image(swatch)] } {
2135        set _image(swatch) [image create photo -width 24 -height 24]
2136    }
2137    set color [eval format "\#%02x%02x%02x" $pixel]
2138    $_image(swatch) put black  -to 0 0 23 23
2139    $_image(swatch) put $color -to 1 1 22 22
2140    .rappturetooltip configure -icon $_image(swatch)
2141
2142    # Compute the value of the point
2143    if { [info exists _limits($_curFldName)] } {
2144        foreach { vmin vmax } $_limits($_curFldName) break
2145        set t [expr 1.0 - (double($imgY) / double($imgHeight-1))]
2146        set value [expr $t * ($vmax - $vmin) + $vmin]
2147    } else {
2148        set value 0.0
2149    }
2150    set tipx [expr $x + 15]
2151    set tipy [expr $y - 5]
2152    Rappture::Tooltip::text $c "$title $value"
2153    Rappture::Tooltip::tooltip show $c +$tipx,+$tipy   
2154}
2155
2156
2157# ----------------------------------------------------------------------
2158# USAGE: Slice move x|y|z <newval>
2159#
2160# Called automatically when the user drags the slider to move the
2161# cut plane that slices 3D data.  Gets the current value from the
2162# slider and moves the cut plane to the appropriate point in the
2163# data set.
2164# ----------------------------------------------------------------------
2165itcl::body Rappture::VtkVolumeViewer::Slice {option args} {
2166    switch -- $option {
2167        "move" {
2168            set axis [lindex $args 0]
2169            set newval [lindex $args 1]
2170            if {[llength $args] != 2} {
2171                error "wrong # args: should be \"Slice move x|y|z newval\""
2172            }
2173            set newpos [expr {0.01*$newval}]
2174            SendCmd "cutplane slice $axis $newpos"
2175        }
2176        "tooltip" {
2177            set axis [lindex $args 0]
2178            set val [$itk_component(${axis}CutScale) get]
2179            return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
2180        }
2181        default {
2182            error "bad option \"$option\": should be axis, move, or tooltip"
2183        }
2184    }
2185}
2186
2187
2188# ----------------------------------------------------------------------
2189# USAGE: _dropdown post
2190# USAGE: _dropdown unpost
2191# USAGE: _dropdown select
2192#
2193# Used internally to handle the dropdown list for this combobox.  The
2194# post/unpost options are invoked when the list is posted or unposted
2195# to manage the relief of the controlling button.  The select option
2196# is invoked whenever there is a selection from the list, to assign
2197# the value back to the gauge.
2198# ----------------------------------------------------------------------
2199itcl::body Rappture::VtkVolumeViewer::Combo {option} {
2200    set c $itk_component(view)
2201    switch -- $option {
2202        post {
2203            foreach { x1 y1 x2 y2 } [$c bbox title] break
2204            set x1 [expr [winfo width $itk_component(view)] - [winfo reqwidth $itk_component(fieldmenu)]]
2205            set x [expr $x1 + [winfo rootx $itk_component(view)]]
2206            set y [expr $y2 + [winfo rooty $itk_component(view)]]
2207            tk_popup $itk_component(fieldmenu) $x $y
2208        }
2209        activate {
2210            $c itemconfigure title -fill red
2211        }
2212        deactivate {
2213            $c itemconfigure title -fill white
2214        }
2215        invoke {
2216            $itk_component(field) value _curFldLabel
2217            AdjustSetting field
2218        }
2219        default {
2220            error "bad option \"$option\": should be post, unpost, select"
2221        }
2222    }
2223}
2224
Note: See TracBrowser for help on using the repository browser.