source: branches/1.4/gui/scripts/vtkvolumeviewer.tcl @ 5183

Last change on this file since 5183 was 5183, checked in by ldelgass, 9 years ago

s/wmap/amap/

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