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

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

Fix for outline

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