source: tags/1.3.5/gui/scripts/vtkvolumeviewer.tcl @ 4754

Last change on this file since 4754 was 4754, checked in by ldelgass, 7 years ago

merge r4668:4669 from trunk

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