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

Last change on this file since 5249 was 5249, checked in by ldelgass, 6 years ago

merge r5195 from trunk

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