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

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

merging some fixes from the trunk

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