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

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

Merge some changes from trunk (mostly still unused)

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