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

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

merge r5068:r5069 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}
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        $_dispatcher event -idle !rebuild
920        return
921    }
922
923    # Turn on buffering of commands to the server.  We don't want to
924    # be preempted by a server disconnect/reconnect (which automatically
925    # generates a new call to Rebuild).   
926    StartBufferingCommands
927
928    set _legendPending 1
929
930    if { $_reset } {
931        set _width $w
932        set _height $h
933        $_arcball resize $w $h
934        DoResize
935        #
936        # Reset the camera and other view parameters
937        #
938        set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
939        $_arcball quaternion $q
940        if {$_view(ortho)} {
941            SendCmd "camera mode ortho"
942        } else {
943            SendCmd "camera mode persp"
944        }
945        DoRotate
946        InitSettings axis-xgrid axis-ygrid axis-zgrid axisFlyMode \
947            axesVisible axisLabels
948        PanCamera
949    }
950    set _first ""
951
952    SendCmd "imgflush"
953    set _first ""
954
955    SendCmd "dataset visible 0"
956    foreach dataobj [get -objects] {
957        if { [info exists _obj2ovride($dataobj-raise)] &&  $_first == "" } {
958            set _first $dataobj
959        }
960        set _obj2datasets($dataobj) ""
961        foreach comp [$dataobj components] {
962            set tag $dataobj-$comp
963            if { ![info exists _datasets($tag)] } {
964                set bytes [$dataobj vtkdata $comp]
965                set length [string length $bytes]
966                if { $_reportClientInfo }  {
967                    set info {}
968                    lappend info "tool_id"       [$dataobj hints toolid]
969                    lappend info "tool_name"     [$dataobj hints toolname]
970                    lappend info "tool_title"    [$dataobj hints tooltitle]
971                    lappend info "tool_command"  [$dataobj hints toolcommand]
972                    lappend info "tool_revision" [$dataobj hints toolrevision]
973                    lappend info "dataset_label" [$dataobj hints label]
974                    lappend info "dataset_size"  $length
975                    lappend info "dataset_tag"   $tag
976                    SendCmd [list "clientinfo" $info]
977                }
978                append _outbuf "dataset add $tag data follows $length\n"
979                append _outbuf $bytes
980                set _datasets($tag) 1
981                SetObjectStyle $dataobj $comp
982            }
983            lappend _obj2datasets($dataobj) $tag
984            if { [info exists _obj2ovride($dataobj-raise)] } {
985                SendCmd "dataset visible 1 $tag"
986            }
987            break
988        }
989    }
990    if {"" != $_first} {
991        set location [$_first hints camera]
992        if { $location != "" } {
993            array set view $location
994        }
995
996        foreach axis { x y z } {
997            set label [$_first hints ${axis}label]
998            if { $label != "" } {
999                SendCmd "axis name $axis $label"
1000            }
1001            set units [$_first hints ${axis}units]
1002            if { $units != "" } {
1003                SendCmd "axis units $axis $units"
1004            }
1005        }
1006        $itk_component(field) choices delete 0 end
1007        $itk_component(fieldmenu) delete 0 end
1008        array unset _fields
1009        set _curFldName ""
1010        foreach cname [$_first components] {
1011            foreach fname [$_first fieldnames $cname] {
1012                if { [info exists _fields($fname)] } {
1013                    continue
1014                }
1015                foreach { label units components } \
1016                    [$_first fieldinfo $fname] break
1017                # Only scalar fields are valid
1018                if {$components == 1} {
1019                    $itk_component(field) choices insert end "$fname" "$label"
1020                    $itk_component(fieldmenu) add radiobutton -label "$label" \
1021                        -value $label -variable [itcl::scope _curFldLabel] \
1022                        -selectcolor red \
1023                        -activebackground $itk_option(-plotbackground) \
1024                        -activeforeground $itk_option(-plotforeground) \
1025                        -font "Arial 8" \
1026                        -command [itcl::code $this Combo invoke]
1027                    set _fields($fname) [list $label $units $components]
1028                    if { $_curFldName == "" } {
1029                        set _curFldName $fname
1030                        set _curFldLabel $label
1031                    }
1032                }
1033            }
1034        }
1035        $itk_component(field) value $_curFldLabel
1036    }
1037
1038    InitSettings volume-palette volume-material volume-quality volumeVisible \
1039        cutplaneVisible \
1040        cutplane-xposition cutplane-yposition cutplane-zposition \
1041        cutplane-xvisible cutplane-yvisible cutplane-zvisible
1042
1043    if { $_reset } {
1044        InitSettings volumeLighting
1045        Zoom reset
1046        set _reset 0
1047    }
1048    # Actually write the commands to the server socket.  If it fails, we don't
1049    # care.  We're finished here.
1050    blt::busy hold $itk_component(hull)
1051    StopBufferingCommands
1052    blt::busy release $itk_component(hull)
1053}
1054
1055# ----------------------------------------------------------------------
1056# USAGE: CurrentDatasets ?-all -visible? ?dataobjs?
1057#
1058# Returns a list of server IDs for the current datasets being displayed.  This
1059# is normally a single ID, but it might be a list of IDs if the current data
1060# object has multiple components.
1061# ----------------------------------------------------------------------
1062itcl::body Rappture::VtkVolumeViewer::CurrentDatasets {args} {
1063    set flag [lindex $args 0]
1064    switch -- $flag {
1065        "-all" {
1066            if { [llength $args] > 1 } {
1067                error "CurrentDatasets: can't specify dataobj after \"-all\""
1068            }
1069            set dlist [get -objects]
1070        }
1071        "-visible" {
1072            if { [llength $args] > 1 } {
1073                set dlist {}
1074                set args [lrange $args 1 end]
1075                foreach dataobj $args {
1076                    if { [info exists _obj2ovride($dataobj-raise)] } {
1077                        lappend dlist $dataobj
1078                    }
1079                }
1080            } else {
1081                set dlist [get -visible]
1082            }
1083        }           
1084        default {
1085            set dlist $args
1086        }
1087    }
1088    set rlist ""
1089    foreach dataobj $dlist {
1090        foreach comp [$dataobj components] {
1091            set tag $dataobj-$comp
1092            if { [info exists _datasets($tag)] && $_datasets($tag) } {
1093                lappend rlist $tag
1094            }
1095        }
1096    }
1097    return $rlist
1098}
1099
1100# ----------------------------------------------------------------------
1101# USAGE: Zoom in
1102# USAGE: Zoom out
1103# USAGE: Zoom reset
1104#
1105# Called automatically when the user clicks on one of the zoom
1106# controls for this widget.  Changes the zoom for the current view.
1107# ----------------------------------------------------------------------
1108itcl::body Rappture::VtkVolumeViewer::Zoom {option} {
1109    switch -- $option {
1110        "in" {
1111            set _view(zoom) [expr {$_view(zoom)*1.25}]
1112            SendCmd "camera zoom $_view(zoom)"
1113        }
1114        "out" {
1115            set _view(zoom) [expr {$_view(zoom)*0.8}]
1116            SendCmd "camera zoom $_view(zoom)"
1117        }
1118        "reset" {
1119            array set _view {
1120                qw      0.853553
1121                qx      -0.353553
1122                qy      0.353553
1123                qz      0.146447
1124                zoom    1.0
1125                xpan   0
1126                ypan   0
1127            }
1128            if { $_first != "" } {
1129                set location [$_first hints camera]
1130                if { $location != "" } {
1131                    array set _view $location
1132                }
1133            }
1134            set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1135            $_arcball quaternion $q
1136            DoRotate
1137            SendCmd "camera reset"
1138        }
1139    }
1140}
1141
1142itcl::body Rappture::VtkVolumeViewer::PanCamera {} {
1143    set x $_view(xpan)
1144    set y $_view(ypan)
1145    SendCmd "camera pan $x $y"
1146}
1147
1148
1149# ----------------------------------------------------------------------
1150# USAGE: Rotate click <x> <y>
1151# USAGE: Rotate drag <x> <y>
1152# USAGE: Rotate release <x> <y>
1153#
1154# Called automatically when the user clicks/drags/releases in the
1155# plot area.  Moves the plot according to the user's actions.
1156# ----------------------------------------------------------------------
1157itcl::body Rappture::VtkVolumeViewer::Rotate {option x y} {
1158    switch -- $option {
1159        "click" {
1160            $itk_component(view) configure -cursor fleur
1161            set _click(x) $x
1162            set _click(y) $y
1163        }
1164        "drag" {
1165            if {[array size _click] == 0} {
1166                Rotate click $x $y
1167            } else {
1168                set w [winfo width $itk_component(view)]
1169                set h [winfo height $itk_component(view)]
1170                if {$w <= 0 || $h <= 0} {
1171                    return
1172                }
1173
1174                if {[catch {
1175                    # this fails sometimes for no apparent reason
1176                    set dx [expr {double($x-$_click(x))/$w}]
1177                    set dy [expr {double($y-$_click(y))/$h}]
1178                }]} {
1179                    return
1180                }
1181                if { $dx == 0 && $dy == 0 } {
1182                    return
1183                }
1184                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1185                EventuallyRotate $q
1186                set _click(x) $x
1187                set _click(y) $y
1188            }
1189        }
1190        "release" {
1191            Rotate drag $x $y
1192            $itk_component(view) configure -cursor ""
1193            catch {unset _click}
1194        }
1195        default {
1196            error "bad option \"$option\": should be click, drag, release"
1197        }
1198    }
1199}
1200
1201itcl::body Rappture::VtkVolumeViewer::Pick {x y} {
1202    foreach tag [CurrentDatasets -visible] {
1203        SendCmd "dataset getscalar pixel $x $y $tag"
1204    }
1205}
1206
1207# ----------------------------------------------------------------------
1208# USAGE: $this Pan click x y
1209#        $this Pan drag x y
1210#        $this Pan release x y
1211#
1212# Called automatically when the user clicks on one of the zoom
1213# controls for this widget.  Changes the zoom for the current view.
1214# ----------------------------------------------------------------------
1215itcl::body Rappture::VtkVolumeViewer::Pan {option x y} {
1216    switch -- $option {
1217        "set" {
1218            set w [winfo width $itk_component(view)]
1219            set h [winfo height $itk_component(view)]
1220            set x [expr $x / double($w)]
1221            set y [expr $y / double($h)]
1222            set _view(xpan) [expr $_view(xpan) + $x]
1223            set _view(ypan) [expr $_view(ypan) + $y]
1224            PanCamera
1225            return
1226        }
1227        "click" {
1228            set _click(x) $x
1229            set _click(y) $y
1230            $itk_component(view) configure -cursor hand1
1231        }
1232        "drag" {
1233            if { ![info exists _click(x)] } {
1234                set _click(x) $x
1235            }
1236            if { ![info exists _click(y)] } {
1237                set _click(y) $y
1238            }
1239            set w [winfo width $itk_component(view)]
1240            set h [winfo height $itk_component(view)]
1241            set dx [expr ($_click(x) - $x)/double($w)]
1242            set dy [expr ($_click(y) - $y)/double($h)]
1243            set _click(x) $x
1244            set _click(y) $y
1245            set _view(xpan) [expr $_view(xpan) - $dx]
1246            set _view(ypan) [expr $_view(ypan) - $dy]
1247            PanCamera
1248        }
1249        "release" {
1250            Pan drag $x $y
1251            $itk_component(view) configure -cursor ""
1252        }
1253        default {
1254            error "unknown option \"$option\": should set, click, drag, or release"
1255        }
1256    }
1257}
1258
1259# ----------------------------------------------------------------------
1260# USAGE: InitSettings <what> ?<value>?
1261#
1262# Used internally to update rendering settings whenever parameters
1263# change in the popup settings panel.  Sends the new settings off
1264# to the back end.
1265# ----------------------------------------------------------------------
1266itcl::body Rappture::VtkVolumeViewer::InitSettings { args } {
1267    foreach spec $args {
1268        if { [info exists _settings($_first-$spec)] } {
1269            # Reset global setting with dataobj specific setting
1270            set _settings($spec) $_settings($_first-$spec)
1271        }
1272        AdjustSetting $spec
1273    }
1274}
1275
1276#
1277# AdjustSetting --
1278#
1279#       Changes/updates a specific setting in the widget.  There are
1280#       usually user-setable option.  Commands are sent to the render
1281#       server.
1282#
1283itcl::body Rappture::VtkVolumeViewer::AdjustSetting {what {value ""}} {
1284    if { ![isconnected] } {
1285        return
1286    }
1287    switch -- $what {
1288        "volumeVisible" {
1289            set bool $_settings(volumeVisible)
1290            foreach dataset [CurrentDatasets -visible] {
1291                SendCmd "volume visible $bool $dataset"
1292            }
1293            if { $bool } {
1294                Rappture::Tooltip::for $itk_component(volume) \
1295                    "Hide the volume"
1296            } else {
1297                Rappture::Tooltip::for $itk_component(volume) \
1298                    "Show the volume"
1299            }
1300        }
1301        "volume-material" {
1302            set val $_settings(volume-material)
1303            set diffuse [expr {0.01*$val}]
1304            set specular [expr {0.01*$val}]
1305            #set power [expr {sqrt(160*$val+1.0)}]
1306            set power [expr {$val+1.0}]
1307            foreach dataset [CurrentDatasets -visible] {
1308                SendCmd "volume shading diffuse $diffuse $dataset"
1309                SendCmd "volume shading specular $specular $power $dataset"
1310            }
1311        }
1312        "volumeLighting" {
1313            set bool $_settings(volumeLighting)
1314            foreach dataset [CurrentDatasets -visible] {
1315                SendCmd "volume lighting $bool $dataset"
1316            }
1317        }
1318        "volume-quality" {
1319            set val $_settings(volume-quality)
1320            set val [expr {0.01*$val}]
1321            foreach dataset [CurrentDatasets -visible] {
1322                SendCmd "volume quality $val $dataset"
1323            }
1324        }
1325        "axesVisible" {
1326            set bool $_settings(axesVisible)
1327            SendCmd "axis visible all $bool"
1328        }
1329        "axisLabels" {
1330            set bool $_settings(axisLabels)
1331            SendCmd "axis labels all $bool"
1332        }
1333        "axis-xgrid" - "axis-ygrid" - "axis-zgrid" {
1334            set axis [string range $what 5 5]
1335            set bool $_settings($what)
1336            SendCmd "axis grid $axis $bool"
1337        }
1338        "axisFlyMode" {
1339            set mode [$itk_component(axismode) value]
1340            set mode [$itk_component(axismode) translate $mode]
1341            set _settings($what) $mode
1342            SendCmd "axis flymode $mode"
1343        }
1344        "cutplaneEdges" {
1345            set bool $_settings($what)
1346            foreach dataset [CurrentDatasets -visible] {
1347                SendCmd "cutplane edges $bool $dataset"
1348            }
1349        }
1350        "cutplaneVisible" {
1351            set bool $_settings($what)
1352            foreach dataset [CurrentDatasets -visible] {
1353                SendCmd "cutplane visible $bool $dataset"
1354            }
1355        }
1356        "cutplaneWireframe" {
1357            set bool $_settings($what)
1358            foreach dataset [CurrentDatasets -visible] {
1359                SendCmd "cutplane wireframe $bool $dataset"
1360            }
1361        }
1362        "cutplaneLighting" {
1363            set bool $_settings($what)
1364            foreach dataset [CurrentDatasets -visible] {
1365                SendCmd "cutplane lighting $bool $dataset"
1366            }
1367        }
1368        "cutplane-opacity" {
1369            set val $_settings($what)
1370            set sval [expr { 0.01 * double($val) }]
1371            foreach dataset [CurrentDatasets -visible] {
1372                SendCmd "cutplane opacity $sval $dataset"
1373            }
1374        }
1375        "cutplane-xvisible" - "cutplane-yvisible" - "cutplane-zvisible" {
1376            set axis [string range $what 9 9]
1377            set bool $_settings($what)
1378            if { $bool } {
1379                $itk_component(${axis}CutScale) configure -state normal \
1380                    -troughcolor white
1381            } else {
1382                $itk_component(${axis}CutScale) configure -state disabled \
1383                    -troughcolor grey82
1384            }
1385            foreach dataset [CurrentDatasets -visible] {
1386                SendCmd "cutplane axis $axis $bool $dataset"
1387            }
1388        }
1389        "cutplane-xposition" - "cutplane-yposition" - "cutplane-zposition" {
1390            set axis [string range $what 9 9]
1391            set pos [expr $_settings($what) * 0.01]
1392            foreach dataset [CurrentDatasets -visible] {
1393                SendCmd "cutplane slice ${axis} ${pos} $dataset"
1394            }
1395            set _cutplanePending 0
1396        }
1397        "volume-palette" {
1398            set palette [$itk_component(palette) value]
1399            set _settings(volume-palette) $palette
1400            foreach dataset [CurrentDatasets -visible $_first] {
1401                foreach {dataobj comp} [split $dataset -] break
1402                ChangeColormap $dataobj $comp $palette
1403            }
1404            set _legendPending 1
1405        }
1406        "volume-palette" {
1407            set palette [$itk_component(palette) value]
1408            set _settings(volume-palette) $palette
1409            foreach dataset [CurrentDatasets -visible $_first] {
1410                foreach {dataobj comp} [split $dataset -] break
1411                ChangeColormap $dataobj $comp $palette
1412            }
1413            set _legendPending 1
1414        }
1415        "field" {
1416            set label [$itk_component(field) value]
1417            set fname [$itk_component(field) translate $label]
1418            set _settings(field) $fname
1419            if { [info exists _fields($fname)] } {
1420                foreach { label units components } $_fields($fname) break
1421                if { $components > 1 } {
1422                    puts stderr "Can't use a vector field in a volume"
1423                    return
1424                } else {
1425                    set _colorMode scalar
1426                }
1427                set _curFldName $fname
1428                set _curFldLabel $label
1429            } else {
1430                puts stderr "unknown field \"$fname\""
1431                return
1432            }
1433            foreach dataset [CurrentDatasets -visible $_first] {
1434                #SendCmd "volume colormode $_colorMode ${fname} $dataset"
1435                SendCmd "cutplane colormode $_colorMode ${fname} $dataset"
1436            }
1437            SendCmd "camera reset"
1438            DrawLegend
1439        }
1440        default {
1441            error "don't know how to fix $what"
1442        }
1443    }
1444}
1445
1446#
1447# RequestLegend --
1448#
1449#       Request a new legend from the server.  The size of the legend
1450#       is determined from the height of the canvas.  It will be rotated
1451#       to be vertical when drawn.
1452#
1453itcl::body Rappture::VtkVolumeViewer::RequestLegend {} {
1454    set font "Arial 8"
1455    set lineht [font metrics $font -linespace]
1456    set c $itk_component(legend)
1457    set w 12
1458    set h [expr {$_height - 3 * ($lineht + 2)}]
1459    if { $h < 1} {
1460        return
1461    }
1462    # Set the legend on the first volume dataset.
1463    foreach dataset [CurrentDatasets -visible $_first] {
1464        foreach {dataobj comp} [split $dataset -] break
1465        if { [info exists _dataset2style($dataset)] } {
1466            SendCmd \
1467                "legend $_dataset2style($dataset) $_colorMode $_curFldName {} $w $h 0"
1468            break;
1469        }
1470    }
1471}
1472
1473#
1474# ChangeColormap --
1475#
1476itcl::body Rappture::VtkVolumeViewer::ChangeColormap {dataobj comp color} {
1477    set tag $dataobj-$comp
1478    if { ![info exist _style($tag)] } {
1479        error "no initial colormap"
1480    }
1481    array set style $_style($tag)
1482    set style(-color) $color
1483    set _style($tag) [array get style]
1484    SetColormap $dataobj $comp
1485}
1486
1487#
1488# SetColormap --
1489#
1490itcl::body Rappture::VtkVolumeViewer::SetColormap { dataobj comp } {
1491    array set style {
1492        -color BCGYR
1493        -levels 6
1494        -opacity 1.0
1495    }
1496    set tag $dataobj-$comp
1497    if { ![info exists _initialStyle($tag)] } {
1498        # Save the initial component style.
1499        set _initialStyle($tag) [$dataobj style $comp]
1500    }
1501
1502    # Override defaults with initial style defined in xml.
1503    array set style $_initialStyle($tag)
1504
1505    if { ![info exists _style($tag)] } {
1506        set _style($tag) [array get style]
1507    }
1508    # Override initial style with current style.
1509    array set style $_style($tag)
1510
1511    set name "$style(-color):$style(-levels):$style(-opacity)"
1512    if { ![info exists _colormaps($name)] } {
1513        BuildColormap $name [array get style]
1514        set _colormaps($name) 1
1515    }
1516    if { ![info exists _dataset2style($tag)] ||
1517         $_dataset2style($tag) != $name } {
1518        SendCmd "volume colormap $name $tag"
1519        SendCmd "cutplane colormap $name-opaque $tag"
1520        set _dataset2style($tag) $name
1521    }
1522}
1523
1524#
1525# BuildColormap --
1526#
1527itcl::body Rappture::VtkVolumeViewer::BuildColormap { name styles } {
1528    array set style $styles
1529    set cmap [ColorsToColormap $style(-color)]
1530    if { [llength $cmap] == 0 } {
1531        set cmap "0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0"
1532    }
1533    if { ![info exists _settings(volume-opacity)] } {
1534        set _settings(volume-opacity) $style(-opacity)
1535    }
1536    set max $_settings(volume-opacity)
1537
1538    set opaqueWmap "0.0 1.0 1.0 1.0"
1539    #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"
1540    # Approximate cubic opacity curve
1541    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"
1542    SendCmd "colormap add $name { $cmap } { $wmap }"
1543    SendCmd "colormap add $name-opaque { $cmap } { $opaqueWmap }"
1544}
1545
1546# ----------------------------------------------------------------------
1547# CONFIGURATION OPTION: -plotbackground
1548# ----------------------------------------------------------------------
1549itcl::configbody Rappture::VtkVolumeViewer::plotbackground {
1550    if { [isconnected] } {
1551        foreach {r g b} [Color2RGB $itk_option(-plotbackground)] break
1552        SendCmd "screen bgcolor $r $g $b"
1553    }
1554}
1555
1556# ----------------------------------------------------------------------
1557# CONFIGURATION OPTION: -plotforeground
1558# ----------------------------------------------------------------------
1559itcl::configbody Rappture::VtkVolumeViewer::plotforeground {
1560    if { [isconnected] } {
1561        foreach {r g b} [Color2RGB $itk_option(-plotforeground)] break
1562        #fix this!
1563        #SendCmd "color background $r $g $b"
1564    }
1565}
1566
1567itcl::body Rappture::VtkVolumeViewer::BuildVolumeTab {} {
1568
1569    set fg [option get $itk_component(hull) font Font]
1570    #set bfg [option get $itk_component(hull) boldFont Font]
1571
1572    set inner [$itk_component(main) insert end \
1573        -title "Volume Settings" \
1574        -icon [Rappture::icon volume-on]]
1575    $inner configure -borderwidth 4
1576
1577    checkbutton $inner.volume \
1578        -text "Show Volume" \
1579        -variable [itcl::scope _settings(volumeVisible)] \
1580        -command [itcl::code $this AdjustSetting volumeVisible] \
1581        -font "Arial 9"
1582
1583    checkbutton $inner.lighting \
1584        -text "Enable Lighting" \
1585        -variable [itcl::scope _settings(volumeLighting)] \
1586        -command [itcl::code $this AdjustSetting volumeLighting] \
1587        -font "Arial 9"
1588
1589    label $inner.dim_l -text "Dim" -font "Arial 9"
1590    ::scale $inner.material -from 0 -to 100 -orient horizontal \
1591        -variable [itcl::scope _settings(volume-material)] \
1592        -width 10 \
1593        -showvalue off -command [itcl::code $this AdjustSetting volume-material]
1594    label $inner.bright_l -text "Bright" -font "Arial 9"
1595
1596    label $inner.opacity_l -text "Opacity" -font "Arial 9"
1597    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1598        -variable [itcl::scope _settings(volume-opacity)] \
1599        -width 10 \
1600        -showvalue off \
1601        -command [itcl::code $this AdjustSetting volume-opacity]
1602
1603    label $inner.quality_l -text "Quality" -font "Arial 9"
1604    ::scale $inner.quality -from 0 -to 100 -orient horizontal \
1605        -variable [itcl::scope _settings(volume-quality)] \
1606        -width 10 \
1607        -showvalue off -command [itcl::code $this AdjustSetting volume-quality]
1608
1609    itk_component add field_l {
1610        label $inner.field_l -text "Field" -font "Arial 9"
1611    } {
1612        ignore -font
1613    }
1614    itk_component add field {
1615        Rappture::Combobox $inner.field -width 10 -editable no
1616    }
1617    bind $inner.field <<Value>> \
1618        [itcl::code $this AdjustSetting field]
1619
1620    label $inner.palette_l -text "Palette" -font "Arial 9"
1621    itk_component add palette {
1622        Rappture::Combobox $inner.palette -width 10 -editable no
1623    }
1624    $inner.palette choices insert end \
1625        "BCGYR"              "BCGYR"            \
1626        "BGYOR"              "BGYOR"            \
1627        "blue"               "blue"             \
1628        "blue-to-brown"      "blue-to-brown"    \
1629        "blue-to-orange"     "blue-to-orange"   \
1630        "blue-to-grey"       "blue-to-grey"     \
1631        "green-to-magenta"   "green-to-magenta" \
1632        "greyscale"          "greyscale"        \
1633        "nanohub"            "nanohub"          \
1634        "rainbow"            "rainbow"          \
1635        "spectral"           "spectral"         \
1636        "ROYGB"              "ROYGB"            \
1637        "RYGCB"              "RYGCB"            \
1638        "brown-to-blue"      "brown-to-blue"    \
1639        "grey-to-blue"       "grey-to-blue"     \
1640        "orange-to-blue"     "orange-to-blue"   
1641
1642    $itk_component(palette) value "BCGYR"
1643    bind $inner.palette <<Value>> \
1644        [itcl::code $this AdjustSetting volume-palette]
1645
1646    blt::table $inner \
1647        0,0 $inner.field_l   -anchor w -pady 2  \
1648        0,1 $inner.field     -anchor w -pady 2 -cspan 2 \
1649        1,0 $inner.volume    -anchor w -pady 2 -cspan 4 \
1650        2,0 $inner.lighting  -anchor w -pady 2 -cspan 4 \
1651        3,0 $inner.dim_l     -anchor e -pady 2 \
1652        3,1 $inner.material  -fill x   -pady 2 \
1653        3,2 $inner.bright_l  -anchor w -pady 2 \
1654        4,0 $inner.quality_l -anchor w -pady 2 -cspan 2 \
1655        5,0 $inner.quality   -fill x   -pady 2 -cspan 2 \
1656        7,0 $inner.palette_l -anchor w -pady 2  \
1657        7,1 $inner.palette   -anchor w -pady 2 -cspan 2 \
1658
1659    blt::table configure $inner r* c* -resize none
1660    blt::table configure $inner r8 -resize expand
1661}
1662
1663itcl::body Rappture::VtkVolumeViewer::BuildAxisTab {} {
1664
1665    set fg [option get $itk_component(hull) font Font]
1666    #set bfg [option get $itk_component(hull) boldFont Font]
1667
1668    set inner [$itk_component(main) insert end \
1669        -title "Axis Settings" \
1670        -icon [Rappture::icon axis1]]
1671    $inner configure -borderwidth 4
1672
1673    checkbutton $inner.visible \
1674        -text "Show Axes" \
1675        -variable [itcl::scope _settings(axesVisible)] \
1676        -command [itcl::code $this AdjustSetting axesVisible] \
1677        -font "Arial 9"
1678
1679    checkbutton $inner.labels \
1680        -text "Show Axis Labels" \
1681        -variable [itcl::scope _settings(axisLabels)] \
1682        -command [itcl::code $this AdjustSetting axisLabels] \
1683        -font "Arial 9"
1684
1685    checkbutton $inner.gridx \
1686        -text "Show X Grid" \
1687        -variable [itcl::scope _settings(axis-xgrid)] \
1688        -command [itcl::code $this AdjustSetting axis-xgrid] \
1689        -font "Arial 9"
1690    checkbutton $inner.gridy \
1691        -text "Show Y Grid" \
1692        -variable [itcl::scope _settings(axis-ygrid)] \
1693        -command [itcl::code $this AdjustSetting axis-ygrid] \
1694        -font "Arial 9"
1695    checkbutton $inner.gridz \
1696        -text "Show Z Grid" \
1697        -variable [itcl::scope _settings(axis-zgrid)] \
1698        -command [itcl::code $this AdjustSetting axis-zgrid] \
1699        -font "Arial 9"
1700
1701    label $inner.mode_l -text "Mode" -font "Arial 9"
1702
1703    itk_component add axismode {
1704        Rappture::Combobox $inner.mode -width 10 -editable no
1705    }
1706    $inner.mode choices insert end \
1707        "static_triad"    "static" \
1708        "closest_triad"   "closest" \
1709        "furthest_triad"  "furthest" \
1710        "outer_edges"     "outer"         
1711    $itk_component(axismode) value "static"
1712    bind $inner.mode <<Value>> [itcl::code $this AdjustSetting axisFlyMode]
1713
1714    blt::table $inner \
1715        0,0 $inner.visible -anchor w -cspan 2 \
1716        1,0 $inner.labels  -anchor w -cspan 2 \
1717        2,0 $inner.gridx   -anchor w -cspan 2 \
1718        3,0 $inner.gridy   -anchor w -cspan 2 \
1719        4,0 $inner.gridz   -anchor w -cspan 2 \
1720        5,0 $inner.mode_l  -anchor w -cspan 2 -padx { 2 0 } \
1721        6,0 $inner.mode    -fill x   -cspan 2
1722
1723    blt::table configure $inner r* c* -resize none
1724    blt::table configure $inner r7 c1 -resize expand
1725}
1726
1727
1728itcl::body Rappture::VtkVolumeViewer::BuildCameraTab {} {
1729    set inner [$itk_component(main) insert end \
1730        -title "Camera Settings" \
1731        -icon [Rappture::icon camera]]
1732    $inner configure -borderwidth 4
1733
1734    set labels { qx qy qz qw xpan ypan zoom }
1735    set row 0
1736    foreach tag $labels {
1737        label $inner.${tag}label -text $tag -font "Arial 9"
1738        entry $inner.${tag} -font "Arial 9"  -bg white \
1739            -textvariable [itcl::scope _view($tag)]
1740        bind $inner.${tag} <KeyPress-Return> \
1741            [itcl::code $this camera set ${tag}]
1742        blt::table $inner \
1743            $row,0 $inner.${tag}label -anchor e -pady 2 \
1744            $row,1 $inner.${tag} -anchor w -pady 2
1745        blt::table configure $inner r$row -resize none
1746        incr row
1747    }
1748    checkbutton $inner.ortho \
1749        -text "Orthographic Projection" \
1750        -variable [itcl::scope _view(ortho)] \
1751        -command [itcl::code $this camera set ortho] \
1752        -font "Arial 9"
1753    blt::table $inner \
1754            $row,0 $inner.ortho -cspan 2 -anchor w -pady 2
1755    blt::table configure $inner r$row -resize none
1756    incr row
1757
1758    blt::table configure $inner c0 c1 -resize none
1759    blt::table configure $inner c2 -resize expand
1760    blt::table configure $inner r$row -resize expand
1761}
1762
1763itcl::body Rappture::VtkVolumeViewer::BuildCutplaneTab {} {
1764
1765    set fg [option get $itk_component(hull) font Font]
1766   
1767    set inner [$itk_component(main) insert end \
1768        -title "Cutplane Settings" \
1769        -icon [Rappture::icon cutbutton]]
1770
1771    $inner configure -borderwidth 4
1772
1773    checkbutton $inner.visible \
1774        -text "Show Cutplanes" \
1775        -variable [itcl::scope _settings(cutplaneVisible)] \
1776        -command [itcl::code $this AdjustSetting cutplaneVisible] \
1777        -font "Arial 9"
1778
1779    checkbutton $inner.wireframe \
1780        -text "Show Wireframe" \
1781        -variable [itcl::scope _settings(cutplaneWireframe)] \
1782        -command [itcl::code $this AdjustSetting cutplaneWireframe] \
1783        -font "Arial 9"
1784
1785    checkbutton $inner.lighting \
1786        -text "Enable Lighting" \
1787        -variable [itcl::scope _settings(cutplaneLighting)] \
1788        -command [itcl::code $this AdjustSetting cutplaneLighting] \
1789        -font "Arial 9"
1790
1791    checkbutton $inner.edges \
1792        -text "Show Edges" \
1793        -variable [itcl::scope _settings(cutplaneEdges)] \
1794        -command [itcl::code $this AdjustSetting cutplaneEdges] \
1795        -font "Arial 9"
1796
1797    label $inner.opacity_l -text "Opacity" -font "Arial 9"
1798    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1799        -variable [itcl::scope _settings(cutplane-opacity)] \
1800        -width 10 \
1801        -showvalue off \
1802        -command [itcl::code $this AdjustSetting cutplane-opacity]
1803    $inner.opacity set $_settings(cutplane-opacity)
1804
1805    # X-value slicer...
1806    itk_component add xCutButton {
1807        Rappture::PushButton $inner.xbutton \
1808            -onimage [Rappture::icon x-cutplane] \
1809            -offimage [Rappture::icon x-cutplane] \
1810            -command [itcl::code $this AdjustSetting cutplane-xvisible] \
1811            -variable [itcl::scope _settings(cutplane-xvisible)]
1812    }
1813    Rappture::Tooltip::for $itk_component(xCutButton) \
1814        "Toggle the X-axis cutplane on/off"
1815    $itk_component(xCutButton) select
1816
1817    itk_component add xCutScale {
1818        ::scale $inner.xval -from 100 -to 0 \
1819            -width 10 -orient vertical -showvalue yes \
1820            -borderwidth 1 -highlightthickness 0 \
1821            -command [itcl::code $this EventuallySetCutplane x] \
1822            -variable [itcl::scope _settings(cutplane-xposition)]
1823    } {
1824        usual
1825        ignore -borderwidth -highlightthickness
1826    }
1827    # Set the default cutplane value before disabling the scale.
1828    $itk_component(xCutScale) set 50
1829    $itk_component(xCutScale) configure -state disabled
1830    Rappture::Tooltip::for $itk_component(xCutScale) \
1831        "@[itcl::code $this Slice tooltip x]"
1832
1833    # Y-value slicer...
1834    itk_component add yCutButton {
1835        Rappture::PushButton $inner.ybutton \
1836            -onimage [Rappture::icon y-cutplane] \
1837            -offimage [Rappture::icon y-cutplane] \
1838            -command [itcl::code $this AdjustSetting cutplane-yvisible] \
1839            -variable [itcl::scope _settings(cutplane-yvisible)]
1840    }
1841    Rappture::Tooltip::for $itk_component(yCutButton) \
1842        "Toggle the Y-axis cutplane on/off"
1843    $itk_component(yCutButton) select
1844
1845    itk_component add yCutScale {
1846        ::scale $inner.yval -from 100 -to 0 \
1847            -width 10 -orient vertical -showvalue yes \
1848            -borderwidth 1 -highlightthickness 0 \
1849            -command [itcl::code $this EventuallySetCutplane y] \
1850            -variable [itcl::scope _settings(cutplane-yposition)]
1851    } {
1852        usual
1853        ignore -borderwidth -highlightthickness
1854    }
1855    Rappture::Tooltip::for $itk_component(yCutScale) \
1856        "@[itcl::code $this Slice tooltip y]"
1857    # Set the default cutplane value before disabling the scale.
1858    $itk_component(yCutScale) set 50
1859    $itk_component(yCutScale) configure -state disabled
1860
1861    # Z-value slicer...
1862    itk_component add zCutButton {
1863        Rappture::PushButton $inner.zbutton \
1864            -onimage [Rappture::icon z-cutplane] \
1865            -offimage [Rappture::icon z-cutplane] \
1866            -command [itcl::code $this AdjustSetting cutplane-zvisible] \
1867            -variable [itcl::scope _settings(cutplane-zvisible)]
1868    }
1869    Rappture::Tooltip::for $itk_component(zCutButton) \
1870        "Toggle the Z-axis cutplane on/off"
1871    $itk_component(zCutButton) select
1872
1873    itk_component add zCutScale {
1874        ::scale $inner.zval -from 100 -to 0 \
1875            -width 10 -orient vertical -showvalue yes \
1876            -borderwidth 1 -highlightthickness 0 \
1877            -command [itcl::code $this EventuallySetCutplane z] \
1878            -variable [itcl::scope _settings(cutplane-zposition)]
1879    } {
1880        usual
1881        ignore -borderwidth -highlightthickness
1882    }
1883    $itk_component(zCutScale) set 50
1884    $itk_component(zCutScale) configure -state disabled
1885    Rappture::Tooltip::for $itk_component(zCutScale) \
1886        "@[itcl::code $this Slice tooltip z]"
1887
1888    blt::table $inner \
1889        0,0 $inner.visible              -anchor w -pady 2 -cspan 4 \
1890        1,0 $inner.lighting             -anchor w -pady 2 -cspan 4 \
1891        2,0 $inner.wireframe            -anchor w -pady 2 -cspan 4 \
1892        3,0 $inner.edges                -anchor w -pady 2 -cspan 4 \
1893        4,0 $inner.opacity_l            -anchor w -pady 2 -cspan 3 \
1894        5,0 $inner.opacity              -fill x   -pady 2 -cspan 3 \
1895        6,0 $itk_component(xCutButton)  -anchor e -padx 2 -pady 2 \
1896        7,0 $itk_component(xCutScale)   -fill y \
1897        6,1 $itk_component(yCutButton)  -anchor e -padx 2 -pady 2 \
1898        7,1 $itk_component(yCutScale)   -fill y \
1899        6,2 $itk_component(zCutButton)  -anchor e -padx 2 -pady 2 \
1900        7,2 $itk_component(zCutScale)   -fill y \
1901
1902    blt::table configure $inner r* c* -resize none
1903    blt::table configure $inner r7 c3 -resize expand
1904}
1905
1906#
1907#  camera --
1908#
1909itcl::body Rappture::VtkVolumeViewer::camera {option args} {
1910    switch -- $option {
1911        "show" {
1912            puts [array get _view]
1913        }
1914        "set" {
1915            set who [lindex $args 0]
1916            set x $_view($who)
1917            set code [catch { string is double $x } result]
1918            if { $code != 0 || !$result } {
1919                return
1920            }
1921            switch -- $who {
1922                "ortho" {
1923                    if {$_view(ortho)} {
1924                        SendCmd "camera mode ortho"
1925                    } else {
1926                        SendCmd "camera mode persp"
1927                    }
1928                }
1929                "xpan" - "ypan" {
1930                    PanCamera
1931                }
1932                "qx" - "qy" - "qz" - "qw" {
1933                    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1934                    $_arcball quaternion $q
1935                    EventuallyRotate $q
1936                }
1937                "zoom" {
1938                    SendCmd "camera zoom $_view(zoom)"
1939                }
1940            }
1941        }
1942    }
1943}
1944
1945itcl::body Rappture::VtkVolumeViewer::GetVtkData { args } {
1946    set bytes ""
1947    foreach dataobj [get] {
1948        foreach comp [$dataobj components] {
1949            set tag $dataobj-$comp
1950            set contents [$dataobj vtkdata $comp]
1951            append bytes "$contents\n"
1952        }
1953    }
1954    return [list .vtk $bytes]
1955}
1956
1957itcl::body Rappture::VtkVolumeViewer::GetImage { args } {
1958    if { [image width $_image(download)] > 0 &&
1959         [image height $_image(download)] > 0 } {
1960        set bytes [$_image(download) data -format "jpeg -quality 100"]
1961        set bytes [Rappture::encoding::decode -as b64 $bytes]
1962        return [list .jpg $bytes]
1963    }
1964    return ""
1965}
1966
1967itcl::body Rappture::VtkVolumeViewer::BuildDownloadPopup { popup command } {
1968    Rappture::Balloon $popup \
1969        -title "[Rappture::filexfer::label downloadWord] as..."
1970    set inner [$popup component inner]
1971    label $inner.summary -text "" -anchor w
1972    radiobutton $inner.vtk_button -text "VTK data file" \
1973        -variable [itcl::scope _downloadPopup(format)] \
1974        -font "Helvetica 9 " \
1975        -value vtk 
1976    Rappture::Tooltip::for $inner.vtk_button "Save as VTK data file."
1977    radiobutton $inner.image_button -text "Image File" \
1978        -variable [itcl::scope _downloadPopup(format)] \
1979        -value image
1980    Rappture::Tooltip::for $inner.image_button \
1981        "Save as digital image."
1982
1983    button $inner.ok -text "Save" \
1984        -highlightthickness 0 -pady 2 -padx 3 \
1985        -command $command \
1986        -compound left \
1987        -image [Rappture::icon download]
1988
1989    button $inner.cancel -text "Cancel" \
1990        -highlightthickness 0 -pady 2 -padx 3 \
1991        -command [list $popup deactivate] \
1992        -compound left \
1993        -image [Rappture::icon cancel]
1994
1995    blt::table $inner \
1996        0,0 $inner.summary -cspan 2  \
1997        1,0 $inner.vtk_button -anchor w -cspan 2 -padx { 4 0 } \
1998        2,0 $inner.image_button -anchor w -cspan 2 -padx { 4 0 } \
1999        4,1 $inner.cancel -width .9i -fill y \
2000        4,0 $inner.ok -padx 2 -width .9i -fill y
2001    blt::table configure $inner r3 -height 4
2002    blt::table configure $inner r4 -pady 4
2003    raise $inner.image_button
2004    $inner.vtk_button invoke
2005    return $inner
2006}
2007
2008itcl::body Rappture::VtkVolumeViewer::SetObjectStyle { dataobj comp } {
2009    # Parse style string.
2010    set tag $dataobj-$comp
2011    set style [$dataobj style $comp]
2012    array set settings {
2013        -color \#808080
2014        -edges 0
2015        -edgecolor black
2016        -linewidth 1.0
2017        -opacity 0.4
2018        -wireframe 0
2019        -lighting 1
2020        -seeds 1
2021        -seedcolor white
2022        -visible 1
2023    }
2024    if { $dataobj != $_first } {
2025        set settings(-opacity) 1
2026    }
2027    array set settings $style
2028    SendCmd "volume add $tag"
2029    SendCmd "cutplane add $tag"
2030    SendCmd "cutplane visible 0 $tag"
2031
2032    SendCmd "volume lighting $settings(-lighting) $tag"
2033    set _settings(volumeLighting) $settings(-lighting)
2034    SetColormap $dataobj $comp
2035}
2036
2037itcl::body Rappture::VtkVolumeViewer::IsValidObject { dataobj } {
2038    if {[catch {$dataobj isa Rappture::Field} valid] != 0 || !$valid} {
2039        return 0
2040    }
2041    return 1
2042}
2043
2044# ----------------------------------------------------------------------
2045# USAGE: ReceiveLegend <colormap> <title> <vmin> <vmax> <size>
2046#
2047# Invoked automatically whenever the "legend" command comes in from
2048# the rendering server.  Indicates that binary image data with the
2049# specified <size> will follow.
2050# ----------------------------------------------------------------------
2051itcl::body Rappture::VtkVolumeViewer::ReceiveLegend { colormap title vmin vmax size } {
2052    set _legendPending 0
2053    #puts stderr "ReceiveLegend colormap=$colormap title=$title range=$vmin,$vmax size=$size"
2054    if { [IsConnected] } {
2055        set bytes [ReceiveBytes $size]
2056        if { ![info exists _image(legend)] } {
2057            set _image(legend) [image create photo]
2058        }
2059        $_image(legend) configure -data $bytes
2060        #puts stderr "read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
2061        if { [catch {DrawLegend} errs] != 0 } {
2062            puts stderr errs=$errs
2063        }
2064    }
2065}
2066
2067#
2068# DrawLegend --
2069#
2070#       Draws the legend in it's own canvas which resides to the right
2071#       of the contour plot area.
2072#
2073itcl::body Rappture::VtkVolumeViewer::DrawLegend { } {
2074    set fname $_curFldName
2075    set c $itk_component(view)
2076    set w [winfo width $c]
2077    set h [winfo height $c]
2078    set font "Arial 8"
2079    set lineht [font metrics $font -linespace]
2080   
2081    if { [info exists _fields($fname)] } {
2082        foreach { title units } $_fields($fname) break
2083        if { $units != "" } {
2084            set title [format "%s (%s)" $title $units]
2085        }
2086    } else {
2087        set title $fname
2088    }
2089    if { $_settings(legendVisible) } {
2090        set x [expr $w - 2]
2091        if { [$c find withtag "legend"] == "" } {
2092            set y 2
2093            $c create text $x $y \
2094                -anchor ne \
2095                -fill $itk_option(-plotforeground) -tags "title legend" \
2096                -font $font
2097            incr y $lineht
2098            $c create text $x $y \
2099                -anchor ne \
2100                -fill $itk_option(-plotforeground) -tags "vmax legend" \
2101                -font $font
2102            incr y $lineht
2103            $c create image $x $y \
2104                -anchor ne \
2105                -image $_image(legend) -tags "colormap legend"
2106            $c create text $x [expr {$h-2}] \
2107                -anchor se \
2108                -fill $itk_option(-plotforeground) -tags "vmin legend" \
2109                -font $font
2110            #$c bind colormap <Enter> [itcl::code $this EnterLegend %x %y]
2111            $c bind colormap <Leave> [itcl::code $this LeaveLegend]
2112            $c bind colormap <Motion> [itcl::code $this MotionLegend %x %y]
2113        }
2114        $c bind title <ButtonPress> [itcl::code $this Combo post]
2115        $c bind title <Enter> [itcl::code $this Combo activate]
2116        $c bind title <Leave> [itcl::code $this Combo deactivate]
2117        # Reset the item coordinates according the current size of the plot.
2118        $c itemconfigure title -text $title
2119        if { [info exists _limits($_curFldName)] } {
2120            foreach { vmin vmax } $_limits($_curFldName) break
2121            $c itemconfigure vmin -text [format %g $vmin]
2122            $c itemconfigure vmax -text [format %g $vmax]
2123        }
2124        set y 2
2125        $c coords title $x $y
2126        incr y $lineht
2127        $c coords vmax $x $y
2128        incr y $lineht
2129        $c coords colormap $x $y
2130        $c coords vmin $x [expr {$h - 2}]
2131    }
2132}
2133
2134#
2135# EnterLegend --
2136#
2137itcl::body Rappture::VtkVolumeViewer::EnterLegend { x y } {
2138    SetLegendTip $x $y
2139}
2140
2141#
2142# MotionLegend --
2143#
2144itcl::body Rappture::VtkVolumeViewer::MotionLegend { x y } {
2145    Rappture::Tooltip::tooltip cancel
2146    set c $itk_component(view)
2147    SetLegendTip $x $y
2148}
2149
2150#
2151# LeaveLegend --
2152#
2153itcl::body Rappture::VtkVolumeViewer::LeaveLegend { } {
2154    Rappture::Tooltip::tooltip cancel
2155    .rappturetooltip configure -icon ""
2156}
2157
2158#
2159# SetLegendTip --
2160#
2161itcl::body Rappture::VtkVolumeViewer::SetLegendTip { x y } {
2162    set c $itk_component(view)
2163    set w [winfo width $c]
2164    set h [winfo height $c]
2165    set font "Arial 8"
2166    set lineht [font metrics $font -linespace]
2167   
2168    set imgHeight [image height $_image(legend)]
2169    set coords [$c coords colormap]
2170    set imgX [expr $w - [image width $_image(legend)] - 2]
2171    set imgY [expr $y - 2 * ($lineht + 2)]
2172
2173    if { [info exists _fields($_title)] } {
2174        foreach { title units } $_fields($_title) break
2175        if { $units != "" } {
2176            set title [format "%s (%s)" $title $units]
2177        }
2178    } else {
2179        set title $_title
2180    }
2181    # Make a swatch of the selected color
2182    if { [catch { $_image(legend) get 10 $imgY } pixel] != 0 } {
2183        #puts stderr "out of range: $imgY"
2184        return
2185    }
2186    if { ![info exists _image(swatch)] } {
2187        set _image(swatch) [image create photo -width 24 -height 24]
2188    }
2189    set color [eval format "\#%02x%02x%02x" $pixel]
2190    $_image(swatch) put black  -to 0 0 23 23
2191    $_image(swatch) put $color -to 1 1 22 22
2192    .rappturetooltip configure -icon $_image(swatch)
2193
2194    # Compute the value of the point
2195    if { [info exists _limits($_curFldName)] } {
2196        foreach { vmin vmax } $_limits($_curFldName) break
2197        set t [expr 1.0 - (double($imgY) / double($imgHeight-1))]
2198        set value [expr $t * ($vmax - $vmin) + $vmin]
2199    } else {
2200        set value 0.0
2201    }
2202    set tipx [expr $x + 15]
2203    set tipy [expr $y - 5]
2204    Rappture::Tooltip::text $c "$title $value"
2205    Rappture::Tooltip::tooltip show $c +$tipx,+$tipy   
2206}
2207
2208
2209# ----------------------------------------------------------------------
2210# USAGE: Slice move x|y|z <newval>
2211#
2212# Called automatically when the user drags the slider to move the
2213# cut plane that slices 3D data.  Gets the current value from the
2214# slider and moves the cut plane to the appropriate point in the
2215# data set.
2216# ----------------------------------------------------------------------
2217itcl::body Rappture::VtkVolumeViewer::Slice {option args} {
2218    switch -- $option {
2219        "move" {
2220            set axis [lindex $args 0]
2221            set newval [lindex $args 1]
2222            if {[llength $args] != 2} {
2223                error "wrong # args: should be \"Slice move x|y|z newval\""
2224            }
2225            set newpos [expr {0.01*$newval}]
2226            SendCmd "cutplane slice $axis $newpos"
2227        }
2228        "tooltip" {
2229            set axis [lindex $args 0]
2230            set val [$itk_component(${axis}CutScale) get]
2231            return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
2232        }
2233        default {
2234            error "bad option \"$option\": should be axis, move, or tooltip"
2235        }
2236    }
2237}
2238
2239
2240# ----------------------------------------------------------------------
2241# USAGE: _dropdown post
2242# USAGE: _dropdown unpost
2243# USAGE: _dropdown select
2244#
2245# Used internally to handle the dropdown list for this combobox.  The
2246# post/unpost options are invoked when the list is posted or unposted
2247# to manage the relief of the controlling button.  The select option
2248# is invoked whenever there is a selection from the list, to assign
2249# the value back to the gauge.
2250# ----------------------------------------------------------------------
2251itcl::body Rappture::VtkVolumeViewer::Combo {option} {
2252    set c $itk_component(view)
2253    switch -- $option {
2254        post {
2255            foreach { x1 y1 x2 y2 } [$c bbox title] break
2256            set x1 [expr [winfo width $itk_component(view)] - [winfo reqwidth $itk_component(fieldmenu)]]
2257            set x [expr $x1 + [winfo rootx $itk_component(view)]]
2258            set y [expr $y2 + [winfo rooty $itk_component(view)]]
2259            tk_popup $itk_component(fieldmenu) $x $y
2260        }
2261        activate {
2262            $c itemconfigure title -fill red
2263        }
2264        deactivate {
2265            $c itemconfigure title -fill white
2266        }
2267        invoke {
2268            $itk_component(field) value _curFldLabel
2269            AdjustSetting field
2270        }
2271        default {
2272            error "bad option \"$option\": should be post, unpost, select"
2273        }
2274    }
2275}
2276
Note: See TracBrowser for help on using the repository browser.