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

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

Backport some changes to vtk volume viewer from trunk

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