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

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

minor fixes to sync with trunk

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