source: trunk/gui/scripts/vtkvolumeviewer.tcl @ 3974

Last change on this file since 3974 was 3974, checked in by gah, 11 years ago

fix in scale method to component overall limits for each component.

File size: 99.3 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2
3# ----------------------------------------------------------------------
4#  COMPONENT: VtkVolumeViewer - Vtk volume viewer
5#
6#  It connects to the Vtk server running on a rendering farm,
7#  transmits data, and displays the results.
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
11#
12#  See the file "license.terms" for information on usage and
13#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14# ======================================================================
15package require Itk
16package require BLT
17#package require Img
18
19option add *VtkVolumeViewer.width 4i widgetDefault
20option add *VtkVolumeViewer*cursor crosshair widgetDefault
21option add *VtkVolumeViewer.height 4i widgetDefault
22option add *VtkVolumeViewer.foreground black widgetDefault
23option add *VtkVolumeViewer.controlBackground gray widgetDefault
24option add *VtkVolumeViewer.controlDarkBackground #999999 widgetDefault
25option add *VtkVolumeViewer.plotBackground black widgetDefault
26option add *VtkVolumeViewer.plotForeground white widgetDefault
27option add *VtkVolumeViewer.font \
28    -*-helvetica-medium-r-normal-*-12-* widgetDefault
29
30# must use this name -- plugs into Rappture::resources::load
31proc VtkVolumeViewer_init_resources {} {
32    Rappture::resources::register \
33        vtkvis_server Rappture::VtkVolumeViewer::SetServerList
34}
35
36itcl::class Rappture::VtkVolumeViewer {
37    inherit Rappture::VisViewer
38
39    itk_option define -plotforeground plotForeground Foreground ""
40    itk_option define -plotbackground plotBackground Background ""
41
42    constructor { hostlist args } {
43        Rappture::VisViewer::constructor $hostlist
44    } {
45        # defined below
46    }
47    destructor {
48        # defined below
49    }
50    public proc SetServerList { namelist } {
51        Rappture::VisViewer::SetServerList "vtkvis" $namelist
52    }
53    public method add {dataobj {settings ""}}
54    public method camera {option args}
55    public method delete {args}
56    public method disconnect {}
57    public method download {option args}
58    public method get {args}
59    public method isconnected {}
60    public method parameters {title args} {
61        # do nothing
62    }
63    public method scale {args}
64    public method updateTransferFunctions {}
65
66    private method SetOrientation { side }
67    private method HideAllMarkers {}
68    private method GetColormap { cname color }
69    private method ResetColormap { cname color }
70    private method InitComponentSettings { cname }
71    private method SwitchComponent { cname }
72    private method GetDatasetsWithComponent { cname }
73    private method ComputeAlphamap { cname }
74    private method ComputeTransferFunction { cname }
75    private method SetInitialTransferFunction { dataobj cname }
76    private method SendTransferFunctions {}
77    private method ParseLevelsOption { cname levels }
78    private method ParseMarkersOption { cname markers }
79    private method BuildVolumeComponents {}
80    private variable _serverDatasets   ;# contains all the dataobj-component
81                                   ;# to volumes in the server
82    private variable _current "";       # Currently selected component
83    private variable _volcomponents   ; # Array of components found
84    private variable _componentsList   ; # Array of components found
85    private variable _cname2style
86    private variable _cname2transferFunction
87    private variable _cname2defaultcolormap
88    private variable _cname2defaultalphamap
89
90    private variable _parsedFunction
91    private variable _transferFunctionEditors
92
93    protected method Connect {}
94    protected method CurrentDatasets {args}
95    protected method Disconnect {}
96    protected method DoResize {}
97    protected method DoReseed {}
98    protected method DoRotate {}
99    protected method AdjustSetting {what {value ""}}
100    protected method InitSettings { args  }
101    protected method Pan {option x y}
102    protected method Pick {x y}
103    protected method Rebuild {}
104    protected method ReceiveDataset { args }
105    protected method ReceiveImage { args }
106    protected method ReceiveLegend { colormap title vmin vmax size }
107    protected method Rotate {option x y}
108    protected method Zoom {option}
109
110    # The following methods are only used by this class.
111
112    private method BuildAxisTab {}
113    private method BuildCameraTab {}
114    private method BuildColormap { name colors }
115    private method BuildCutplaneTab {}
116    private method BuildDownloadPopup { widget command }
117    private method BuildVolumeTab {}
118    private method DrawLegend {}
119    private method DrawLegendOld {}
120    private method Combo { option }
121    private method EnterLegend { x y }
122    private method EventuallyResize { w h }
123    private method EventuallyRequestLegend {}
124    private method EventuallyRotate { q }
125    private method EventuallySetCutplane { axis args }
126    private method GetImage { args }
127    private method GetVtkData { args }
128    private method IsValidObject { dataobj }
129    private method LeaveLegend {}
130    private method MotionLegend { x y }
131    private method PanCamera {}
132    private method RequestLegend {}
133    private method SetColormap { dataobj comp }
134    private method ChangeColormap { dataobj comp color }
135    private method SetLegendTip { x y }
136    private method SetObjectStyle { dataobj comp }
137    private method Slice {option args}
138
139    private variable _arcball ""
140    private variable _dlist ""     ;    # list of data objects
141    private variable _obj2datasets
142    private variable _obj2ovride   ;    # maps dataobj => style override
143    private variable _datasets     ;    # contains all the dataobj-component
144                                   ;    # datasets in the server
145    private variable _colormaps    ;    # contains all the colormaps
146                                   ;    # in the server.
147    private variable _dataset2style    ;# maps dataobj-component to transfunc
148
149    private variable _click        ;    # info used for rotate operations
150    private variable _limits       ;    # autoscale min/max for all axes
151    private variable _view         ;    # view params for 3D view
152    private variable _settings
153    private variable _style;            # Array of current component styles.
154    private variable _initialStyle;     # Array of initial component styles.
155    private variable _reset 1;          # indicates if camera needs to be reset
156                                        # to starting position.
157
158    private variable _first ""     ;    # This is the topmost dataset.
159    private variable _start 0
160    private variable _title ""
161    private variable _seeds
162
163    common _downloadPopup;              # download options from popup
164    private common _hardcopy
165    private variable _width 0
166    private variable _height 0
167    private variable _resizePending 0
168    private variable _reseedPending 0
169    private variable _rotatePending 0
170    private variable _cutplanePending 0
171    private variable _legendPending 0
172    private variable _fields
173    private variable _curFldName ""
174    private variable _curFldLabel ""
175    private variable _colorMode "scalar";#  Mode of colormap (vmag or scalar)
176}
177
178itk::usual VtkVolumeViewer {
179    keep -background -foreground -cursor -font
180    keep -plotbackground -plotforeground
181}
182
183# ----------------------------------------------------------------------
184# CONSTRUCTOR
185# ----------------------------------------------------------------------
186itcl::body Rappture::VtkVolumeViewer::constructor {hostlist args} {
187    package require vtk
188    set _serverType "vtkvis"
189
190    EnableWaitDialog 900
191
192    # Rebuild event
193    $_dispatcher register !rebuild
194    $_dispatcher dispatch $this !rebuild "[itcl::code $this Rebuild]; list"
195
196    # Resize event
197    $_dispatcher register !resize
198    $_dispatcher dispatch $this !resize "[itcl::code $this DoResize]; list"
199
200    # Reseed event
201    $_dispatcher register !reseed
202    $_dispatcher dispatch $this !reseed "[itcl::code $this DoReseed]; list"
203
204    # Rotate event
205    $_dispatcher register !rotate
206    $_dispatcher dispatch $this !rotate "[itcl::code $this DoRotate]; list"
207
208    # Legend event
209    $_dispatcher register !legend
210    $_dispatcher dispatch $this !legend "[itcl::code $this RequestLegend]; list"
211
212    # X-Cutplane event
213    $_dispatcher register !xcutplane
214    $_dispatcher dispatch $this !xcutplane \
215        "[itcl::code $this AdjustSetting cutplane-xposition]; list"
216
217    # Y-Cutplane event
218    $_dispatcher register !ycutplane
219    $_dispatcher dispatch $this !ycutplane \
220        "[itcl::code $this AdjustSetting cutplane-yposition]; list"
221
222    # Z-Cutplane event
223    $_dispatcher register !zcutplane
224    $_dispatcher dispatch $this !zcutplane \
225        "[itcl::code $this AdjustSetting cutplane-zposition]; list"
226
227    #
228    # Populate parser with commands handle incoming requests
229    #
230    $_parser alias image [itcl::code $this ReceiveImage]
231    $_parser alias dataset [itcl::code $this ReceiveDataset]
232    $_parser alias legend [itcl::code $this ReceiveLegend]
233
234    # Initialize the view to some default parameters.
235    array set _view {
236        qw              0.853553
237        qx              -0.353553
238        qy              0.353553
239        qz              0.146447
240        zoom            1.0
241        xpan            0
242        ypan            0
243        ortho           0
244    }
245    set _arcball [blt::arcball create 100 100]
246    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
247    $_arcball quaternion $q
248
249    array set _settings {
250        axis-xgrid              0
251        axis-ygrid              0
252        axis-zgrid              0
253        axesVisible             1
254        axisLabels              1
255        cutplaneEdges           0
256        cutplane-xvisible       1
257        cutplane-yvisible       1
258        cutplane-zvisible       1
259        cutplane-xposition      50
260        cutplane-yposition      50
261        cutplane-zposition      50
262        cutplaneVisible         0
263        cutplaneLighting        1
264        cutplaneWireframe       0
265        cutplane-opacity        100
266        volume-blendmode        composite
267        volumeLighting          1
268        volumeAmbient          40
269        volumeDiffuse          60
270        volumeThickness        350
271        volume-specularLevel    30
272        volume-specularExponent 90
273        volume-opacity          50
274        volume-quality          50
275        volumeVisible           1
276        legendVisible           1
277    }
278
279    itk_component add view {
280        canvas $itk_component(plotarea).view \
281            -highlightthickness 0 -borderwidth 0
282    } {
283        usual
284        ignore -highlightthickness -borderwidth  -background
285    }
286
287    itk_component add fieldmenu {
288        menu $itk_component(plotarea).menu -bg black -fg white -relief flat \
289            -tearoff no
290    } {
291        usual
292        ignore -background -foreground -relief -tearoff
293    }
294    set c $itk_component(view)
295    bind $c <Configure> [itcl::code $this EventuallyResize %w %h]
296    bind $c <4> [itcl::code $this Zoom in 0.25]
297    bind $c <5> [itcl::code $this Zoom out 0.25]
298    bind $c <KeyPress-Left>  [list %W xview scroll 10 units]
299    bind $c <KeyPress-Right> [list %W xview scroll -10 units]
300    bind $c <KeyPress-Up>    [list %W yview scroll 10 units]
301    bind $c <KeyPress-Down>  [list %W yview scroll -10 units]
302    bind $c <Enter> "focus %W"
303    bind $c <Control-F1> [itcl::code $this ToggleConsole]
304
305    # Fixes the scrollregion in case we go off screen
306    $c configure -scrollregion [$c bbox all]
307
308    set _map(id) [$c create image 0 0 -anchor nw -image $_image(plot)]
309    set _map(cwidth) -1
310    set _map(cheight) -1
311    set _map(zoom) 1.0
312    set _map(original) ""
313
314    set f [$itk_component(main) component controls]
315    itk_component add reset {
316        button $f.reset -borderwidth 1 -padx 1 -pady 1 \
317            -highlightthickness 0 \
318            -image [Rappture::icon reset-view] \
319            -command [itcl::code $this Zoom reset]
320    } {
321        usual
322        ignore -highlightthickness
323    }
324    pack $itk_component(reset) -side top -padx 2 -pady 2
325    Rappture::Tooltip::for $itk_component(reset) "Reset the view to the default zoom level"
326
327    itk_component add zoomin {
328        button $f.zin -borderwidth 1 -padx 1 -pady 1 \
329            -highlightthickness 0 \
330            -image [Rappture::icon zoom-in] \
331            -command [itcl::code $this Zoom in]
332    } {
333        usual
334        ignore -highlightthickness
335    }
336    pack $itk_component(zoomin) -side top -padx 2 -pady 2
337    Rappture::Tooltip::for $itk_component(zoomin) "Zoom in"
338
339    itk_component add zoomout {
340        button $f.zout -borderwidth 1 -padx 1 -pady 1 \
341            -highlightthickness 0 \
342            -image [Rappture::icon zoom-out] \
343            -command [itcl::code $this Zoom out]
344    } {
345        usual
346        ignore -highlightthickness
347    }
348    pack $itk_component(zoomout) -side top -padx 2 -pady 2
349    Rappture::Tooltip::for $itk_component(zoomout) "Zoom out"
350
351    itk_component add volume {
352        Rappture::PushButton $f.volume \
353            -onimage [Rappture::icon volume-on] \
354            -offimage [Rappture::icon volume-off] \
355            -variable [itcl::scope _settings(volumeVisible)] \
356            -command [itcl::code $this AdjustSetting volumeVisible]
357    }
358    $itk_component(volume) select
359    Rappture::Tooltip::for $itk_component(volume) \
360        "Don't display the volume"
361    pack $itk_component(volume) -padx 2 -pady 2
362
363    itk_component add cutplane {
364        Rappture::PushButton $f.cutplane \
365            -onimage [Rappture::icon cutbutton] \
366            -offimage [Rappture::icon cutbutton] \
367            -variable [itcl::scope _settings(cutplaneVisible)] \
368            -command [itcl::code $this AdjustSetting cutplaneVisible]
369    }
370    Rappture::Tooltip::for $itk_component(cutplane) \
371        "Show/Hide cutplanes"
372    pack $itk_component(cutplane) -padx 2 -pady 2
373
374
375    if { [catch {
376        BuildVolumeTab
377        BuildCutplaneTab
378        BuildAxisTab
379        BuildCameraTab
380    } errs] != 0 } {
381        puts stderr errs=$errs
382    }
383    # Legend
384
385    set _image(legend) [image create photo]
386    itk_component add legend {
387        canvas $itk_component(plotarea).legend -height 50 -highlightthickness 0
388    } {
389        usual
390        ignore -highlightthickness
391        rename -background -plotbackground plotBackground Background
392    }
393
394    # Hack around the Tk panewindow.  The problem is that the requested
395    # size of the 3d view isn't set until an image is retrieved from
396    # the server.  So the panewindow uses the tiny size.
397    set w 10000
398    pack forget $itk_component(view)
399    blt::table $itk_component(plotarea) \
400        0,0 $itk_component(view) -fill both -reqwidth $w  \
401        1,0 $itk_component(legend) -fill x
402    blt::table configure $itk_component(plotarea) r1 -resize none
403
404    # Bindings for rotation via mouse
405    bind $itk_component(view) <ButtonPress-1> \
406        [itcl::code $this Rotate click %x %y]
407    bind $itk_component(view) <B1-Motion> \
408        [itcl::code $this Rotate drag %x %y]
409    bind $itk_component(view) <ButtonRelease-1> \
410        [itcl::code $this Rotate release %x %y]
411    bind $itk_component(view) <Configure> \
412        [itcl::code $this EventuallyResize %w %h]
413
414    if 0 {
415    bind $itk_component(view) <Configure> \
416        [itcl::code $this EventuallyResize %w %h]
417    }
418    # Bindings for panning via mouse
419    bind $itk_component(view) <ButtonPress-2> \
420        [itcl::code $this Pan click %x %y]
421    bind $itk_component(view) <B2-Motion> \
422        [itcl::code $this Pan drag %x %y]
423    bind $itk_component(view) <ButtonRelease-2> \
424        [itcl::code $this Pan release %x %y]
425
426    #bind $itk_component(view) <ButtonRelease-3> \
427    #    [itcl::code $this Pick %x %y]
428
429    # Bindings for panning via keyboard
430    bind $itk_component(view) <KeyPress-Left> \
431        [itcl::code $this Pan set -10 0]
432    bind $itk_component(view) <KeyPress-Right> \
433        [itcl::code $this Pan set 10 0]
434    bind $itk_component(view) <KeyPress-Up> \
435        [itcl::code $this Pan set 0 -10]
436    bind $itk_component(view) <KeyPress-Down> \
437        [itcl::code $this Pan set 0 10]
438    bind $itk_component(view) <Shift-KeyPress-Left> \
439        [itcl::code $this Pan set -2 0]
440    bind $itk_component(view) <Shift-KeyPress-Right> \
441        [itcl::code $this Pan set 2 0]
442    bind $itk_component(view) <Shift-KeyPress-Up> \
443        [itcl::code $this Pan set 0 -2]
444    bind $itk_component(view) <Shift-KeyPress-Down> \
445        [itcl::code $this Pan set 0 2]
446
447    # Bindings for zoom via keyboard
448    bind $itk_component(view) <KeyPress-Prior> \
449        [itcl::code $this Zoom out]
450    bind $itk_component(view) <KeyPress-Next> \
451        [itcl::code $this Zoom in]
452
453    bind $itk_component(view) <Enter> "focus $itk_component(view)"
454
455    if {[string equal "x11" [tk windowingsystem]]} {
456        # Bindings for zoom via mouse
457        bind $itk_component(view) <4> [itcl::code $this Zoom out]
458        bind $itk_component(view) <5> [itcl::code $this Zoom in]
459    }
460
461    set _image(download) [image create photo]
462
463    eval itk_initialize $args
464    Connect
465    update
466}
467
468# ----------------------------------------------------------------------
469# DESTRUCTOR
470# ----------------------------------------------------------------------
471itcl::body Rappture::VtkVolumeViewer::destructor {} {
472    Disconnect
473    image delete $_image(plot)
474    image delete $_image(download)
475    catch { blt::arcball destroy $_arcball }
476}
477
478itcl::body Rappture::VtkVolumeViewer::DoResize {} {
479    if { $_width < 2 } {
480        set _width 500
481    }
482    if { $_height < 2 } {
483        set _height 500
484    }
485    set _start [clock clicks -milliseconds]
486    SendCmd "screen size $_width $_height"
487
488    EventuallyRequestLegend
489    set _resizePending 0
490}
491
492itcl::body Rappture::VtkVolumeViewer::DoRotate {} {
493    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
494    SendCmd "camera orient $q"
495    set _rotatePending 0
496}
497
498itcl::body Rappture::VtkVolumeViewer::EventuallyResize { w h } {
499    set _width $w
500    set _height $h
501    $_arcball resize $w $h
502    if { !$_resizePending } {
503        set _resizePending 1
504        $_dispatcher event -after 400 !resize
505    }
506}
507
508itcl::body Rappture::VtkVolumeViewer::EventuallyRequestLegend {} {
509    if { !$_legendPending } {
510        set _legendPending 1
511        $_dispatcher event -after 600 !legend
512    }
513}
514
515set rotate_delay 100
516
517itcl::body Rappture::VtkVolumeViewer::EventuallyRotate { q } {
518    foreach { _view(qw) _view(qx) _view(qy) _view(qz) } $q break
519    if { !$_rotatePending } {
520        set _rotatePending 1
521        global rotate_delay
522        $_dispatcher event -after $rotate_delay !rotate
523    }
524}
525
526itcl::body Rappture::VtkVolumeViewer::EventuallySetCutplane { axis args } {
527    if { !$_cutplanePending } {
528        set _cutplanePending 1
529        $_dispatcher event -after 100 !${axis}cutplane
530    }
531}
532
533# ----------------------------------------------------------------------
534# USAGE: add <dataobj> ?<settings>?
535#
536# Clients use this to add a data object to the plot.  The optional
537# <settings> are used to configure the plot.  Allowed settings are
538# -color, -brightness, -width, -linestyle, and -raise.
539# ----------------------------------------------------------------------
540itcl::body Rappture::VtkVolumeViewer::add {dataobj {settings ""}} {
541    if { ![IsValidObject $dataobj] } {
542        return;                         # Ignore invalid objects.
543    }
544    array set params {
545        -color auto
546        -width 1
547        -linestyle solid
548        -brightness 0
549        -raise 0
550        -description ""
551        -param ""
552        -type ""
553    }
554    array set params $settings
555    set params(-description) ""
556    set params(-param) ""
557    array set params $settings
558
559    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
560        # can't handle -autocolors yet
561        set params(-color) black
562    }
563    set pos [lsearch -exact $_dlist $dataobj]
564    if {$pos < 0} {
565        lappend _dlist $dataobj
566    }
567    set _obj2ovride($dataobj-color) $params(-color)
568    set _obj2ovride($dataobj-width) $params(-width)
569    set _obj2ovride($dataobj-raise) $params(-raise)
570    $_dispatcher event -idle !rebuild
571}
572
573
574# ----------------------------------------------------------------------
575# USAGE: delete ?<dataobj1> <dataobj2> ...?
576#
577#       Clients use this to delete a dataobj from the plot.  If no dataobjs
578#       are specified, then all dataobjs are deleted.  No data objects are
579#       deleted.  They are only removed from the display list.
580#
581# ----------------------------------------------------------------------
582itcl::body Rappture::VtkVolumeViewer::delete {args} {
583    if { [llength $args] == 0} {
584        set args $_dlist
585    }
586    # Delete all specified dataobjs
587    set changed 0
588    foreach dataobj $args {
589        set pos [lsearch -exact $_dlist $dataobj]
590        if { $pos < 0 } {
591            continue;                   # Don't know anything about it.
592        }
593        # Remove it from the dataobj list.
594        set _dlist [lreplace $_dlist $pos $pos]
595        array unset _obj2ovride $dataobj-*
596        array unset _settings $dataobj-*
597        set changed 1
598    }
599    # If anything changed, then rebuild the plot
600    if { $changed } {
601        $_dispatcher event -idle !rebuild
602    }
603}
604
605# ----------------------------------------------------------------------
606# USAGE: get ?-objects?
607# USAGE: get ?-visible?
608# USAGE: get ?-image view?
609#
610# Clients use this to query the list of objects being plotted, in
611# order from bottom to top of this result.  The optional "-image"
612# flag can also request the internal images being shown.
613# ----------------------------------------------------------------------
614itcl::body Rappture::VtkVolumeViewer::get {args} {
615    if {[llength $args] == 0} {
616        set args "-objects"
617    }
618
619    set op [lindex $args 0]
620    switch -- $op {
621        "-objects" {
622            # put the dataobj list in order according to -raise options
623            set dlist {}
624            foreach dataobj $_dlist {
625                if { ![IsValidObject $dataobj] } {
626                    continue
627                }
628                if {[info exists _obj2ovride($dataobj-raise)] &&
629                    $_obj2ovride($dataobj-raise)} {
630                    set dlist [linsert $dlist 0 $dataobj]
631                } else {
632                    lappend dlist $dataobj
633                }
634            }
635            return $dlist
636        }
637        "-visible" {
638            set dlist {}
639            foreach dataobj $_dlist {
640                if { ![IsValidObject $dataobj] } {
641                    continue
642                }
643                if { ![info exists _obj2ovride($dataobj-raise)] } {
644                    # No setting indicates that the object isn't visible.
645                    continue
646                }
647                # Otherwise use the -raise parameter to put the object to
648                # the front of the list.
649                if { $_obj2ovride($dataobj-raise) } {
650                    set dlist [linsert $dlist 0 $dataobj]
651                } else {
652                    lappend dlist $dataobj
653                }
654            }
655            return $dlist
656        }           
657        -image {
658            if {[llength $args] != 2} {
659                error "wrong # args: should be \"get -image view\""
660            }
661            switch -- [lindex $args end] {
662                view {
663                    return $_image(plot)
664                }
665                default {
666                    error "bad image name \"[lindex $args end]\": should be view"
667                }
668            }
669        }
670        default {
671            error "bad option \"$op\": should be -objects or -image"
672        }
673    }
674}
675
676# ----------------------------------------------------------------------
677# USAGE: scale ?<data1> <data2> ...?
678#
679# Sets the default limits for the overall plot according to the
680# limits of the data for all of the given <data> objects.  This
681# accounts for all objects--even those not showing on the screen.
682# Because of this, the limits are appropriate for all objects as
683# the user scans through data in the ResultSet viewer.
684# ----------------------------------------------------------------------
685itcl::body Rappture::VtkVolumeViewer::scale {args} {
686    array set style {
687        -color BCGYR
688        -levels 6
689        -opacity 1.0
690        -markers ""
691    }
692    array unset _limits
693    array unset _volcomponents
694
695    foreach dataobj $args {
696        if { ![$dataobj isvalid] } {
697            continue;                     # Object doesn't contain valid data.
698        }
699        # Determine limits for each axis.
700        foreach axis {x y z v} {
701            foreach { min max } [$dataobj limits $axis] break
702            if {"" != $min && "" != $max} {
703                if { ![info exists _limits($axis)] } {
704                    set _limits($axis) [list $min $max]
705                } else {
706                    foreach {amin amax} $_limits($axis) break
707                    if {$min < $amin} {
708                        set amin $min
709                    }
710                    if {$max > $amax} {
711                        set amax $max
712                    }
713                    set _limits($axis) [list $amin $amax]
714                }
715            }
716        }
717        # Determine limits for each field.
718        foreach { fname lim } [$dataobj fieldlimits] {
719            if { ![info exists _limits($fname)] } {
720                set _limits($fname) $lim
721                continue
722            }
723            foreach {min max} $lim break
724            foreach {fmin fmax} $_limits($fname) break
725            if { $fmin > $min } {
726                set fmin $min
727            }
728            if { $fmax < $max } {
729                set fmax $max
730            }
731            set _limits($fname) [list $fmin $fmax]
732        }
733        # Get limits for each component.
734        foreach cname [$dataobj components] {
735            if { ![info exists _volcomponents($cname)] } {
736                lappend _componentsList $cname
737            }
738            lappend _volcomponents($cname) $dataobj-$cname
739            array unset limits
740            array set limits [$dataobj valueLimits $cname]
741            foreach {min max} $limits(v) break
742            if { ![info exists _limits($cname)] } {
743                set vmin $min
744                set vmax $max
745            } else {
746                if { $vmin > $min } {
747                    set vmin $min
748                }
749                if { $vmax < $max } {
750                    set vmax $max
751                }
752            }
753            set _limits($cname) [list $vmin $vmax]
754        }
755    }
756    BuildVolumeComponents
757    updateTransferFunctions
758}
759
760# ----------------------------------------------------------------------
761# USAGE: download coming
762# USAGE: download controls <downloadCommand>
763# USAGE: download now
764#
765# Clients use this method to create a downloadable representation
766# of the plot.  Returns a list of the form {ext string}, where
767# "ext" is the file extension (indicating the type of data) and
768# "string" is the data itself.
769# ----------------------------------------------------------------------
770itcl::body Rappture::VtkVolumeViewer::download {option args} {
771    switch $option {
772        coming {
773            if {[catch {
774                blt::winop snap $itk_component(plotarea) $_image(download)
775            }]} {
776                $_image(download) configure -width 1 -height 1
777                $_image(download) put #000000
778            }
779        }
780        controls {
781            set popup .vtkviewerdownload
782            if { ![winfo exists .vtkviewerdownload] } {
783                set inner [BuildDownloadPopup $popup [lindex $args 0]]
784            } else {
785                set inner [$popup component inner]
786            }
787            set _downloadPopup(image_controls) $inner.image_frame
788            set num [llength [get]]
789            set num [expr {($num == 1) ? "1 result" : "$num results"}]
790            set word [Rappture::filexfer::label downloadWord]
791            $inner.summary configure -text "$word $num in the following format:"
792            update idletasks            ;# Fix initial sizes
793            return $popup
794        }
795        now {
796            set popup .vtkviewerdownload
797            if {[winfo exists .vtkviewerdownload]} {
798                $popup deactivate
799            }
800            switch -- $_downloadPopup(format) {
801                "image" {
802                    return [$this GetImage [lindex $args 0]]
803                }
804                "vtk" {
805                    return [$this GetVtkData [lindex $args 0]]
806                }
807            }
808            return ""
809        }
810        default {
811            error "bad option \"$option\": should be coming, controls, now"
812        }
813    }
814}
815
816# ----------------------------------------------------------------------
817# USAGE: Connect ?<host:port>,<host:port>...?
818#
819# Clients use this method to establish a connection to a new
820# server, or to reestablish a connection to the previous server.
821# Any existing connection is automatically closed.
822# ----------------------------------------------------------------------
823itcl::body Rappture::VtkVolumeViewer::Connect {} {
824    set _hosts [GetServerList "vtkvis"]
825    if { "" == $_hosts } {
826        return 0
827    }
828    set result [VisViewer::Connect $_hosts]
829    if { $result } {
830        if { $_reportClientInfo }  {
831            # Tell the server the viewer, hub, user and session.
832            # Do this immediately on connect before buffing any commands
833            global env
834
835            set info {}
836            set user "???"
837            if { [info exists env(USER)] } {
838                set user $env(USER)
839            }
840            set session "???"
841            if { [info exists env(SESSION)] } {
842                set session $env(SESSION)
843            }
844            lappend info "hub" [exec hostname]
845            lappend info "client" "vtkvolumeviewer"
846            lappend info "user" $user
847            lappend info "session" $session
848            SendCmd "clientinfo [list $info]"
849        }
850
851        set w [winfo width $itk_component(view)]
852        set h [winfo height $itk_component(view)]
853        EventuallyResize $w $h
854    }
855    return $result
856}
857
858#
859# isconnected --
860#
861#       Indicates if we are currently connected to the visualization server.
862#
863itcl::body Rappture::VtkVolumeViewer::isconnected {} {
864    return [VisViewer::IsConnected]
865}
866
867#
868# disconnect --
869#
870itcl::body Rappture::VtkVolumeViewer::disconnect {} {
871    Disconnect
872    set _reset 1
873}
874
875#
876# Disconnect --
877#
878#       Clients use this method to disconnect from the current rendering
879#       server.
880#
881itcl::body Rappture::VtkVolumeViewer::Disconnect {} {
882    VisViewer::Disconnect
883
884    $_dispatcher cancel !rebuild
885    $_dispatcher cancel !resize
886    $_dispatcher cancel !reseed
887    $_dispatcher cancel !rotate
888    $_dispatcher cancel !xcutplane
889    $_dispatcher cancel !ycutplane
890    $_dispatcher cancel !zcutplane
891    $_dispatcher cancel !legend
892    # disconnected -- no more data sitting on server
893    set _outbuf ""
894    array unset _datasets
895    array unset _data
896    array unset _colormaps
897    array unset _seeds
898    array unset _dataset2style
899    array unset _obj2datasets
900}
901
902# ----------------------------------------------------------------------
903# USAGE: ReceiveImage -bytes <size> -type <type> -token <token>
904#
905# Invoked automatically whenever the "image" command comes in from
906# the rendering server.  Indicates that binary image data with the
907# specified <size> will follow.
908# ----------------------------------------------------------------------
909itcl::body Rappture::VtkVolumeViewer::ReceiveImage { args } {
910    array set info {
911        -token "???"
912        -bytes 0
913        -type image
914    }
915    array set info $args
916    set bytes [ReceiveBytes $info(-bytes)]
917    StopWaiting
918    if { $info(-type) == "image" } {
919        if 0 {
920            set f [open "last.ppm" "w"]
921            puts $f $bytes
922            close $f
923        }
924        $_image(plot) configure -data $bytes
925        set time [clock seconds]
926        set date [clock format $time]
927        #puts stderr "$date: received image [image width $_image(plot)]x[image height $_image(plot)] image>"       
928        if { $_start > 0 } {
929            set finish [clock clicks -milliseconds]
930            #puts stderr "round trip time [expr $finish -$_start] milliseconds"
931            set _start 0
932        }
933    } elseif { $info(type) == "print" } {
934        set tag $this-print-$info(-token)
935        set _hardcopy($tag) $bytes
936    }
937    if { $_legendPending } {
938        RequestLegend
939    }
940}
941
942#
943# ReceiveDataset --
944#
945itcl::body Rappture::VtkVolumeViewer::ReceiveDataset { args } {
946    if { ![isconnected] } {
947        return
948    }
949    set option [lindex $args 0]
950    switch -- $option {
951        "scalar" {
952            set option [lindex $args 1]
953            switch -- $option {
954                "world" {
955                    foreach { x y z value tag } [lrange $args 2 end] break
956                }
957                "pixel" {
958                    foreach { x y value tag } [lrange $args 2 end] break
959                }
960            }
961        }
962        "vector" {
963            set option [lindex $args 1]
964            switch -- $option {
965                "world" {
966                    foreach { x y z vx vy vz tag } [lrange $args 2 end] break
967                }
968                "pixel" {
969                    foreach { x y vx vy vz tag } [lrange $args 2 end] break
970                }
971            }
972        }
973        "names" {
974            foreach { name } [lindex $args 1] {
975                #puts stderr "Dataset: $name"
976            }
977        }
978        default {
979            error "unknown dataset option \"$option\" from server"
980        }
981    }
982}
983
984# ----------------------------------------------------------------------
985# USAGE: Rebuild
986#
987# Called automatically whenever something changes that affects the
988# data in the widget.  Clears any existing data and rebuilds the
989# widget to display new data.
990# ----------------------------------------------------------------------
991itcl::body Rappture::VtkVolumeViewer::Rebuild {} {
992    update
993    set w [winfo width $itk_component(view)]
994    set h [winfo height $itk_component(view)]
995    if { $w < 2 || $h < 2 } {
996        $_dispatcher event -idle !rebuild
997        return
998    }
999
1000    # Turn on buffering of commands to the server.  We don't want to
1001    # be preempted by a server disconnect/reconnect (which automatically
1002    # generates a new call to Rebuild).   
1003    StartBufferingCommands
1004
1005    set _legendPending 1
1006
1007    if { $_reset } {
1008        set _width $w
1009        set _height $h
1010        $_arcball resize $w $h
1011        DoResize
1012        #
1013        # Reset the camera and other view parameters
1014        #
1015        set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1016        $_arcball quaternion $q
1017        if {$_view(ortho)} {
1018            SendCmd "camera mode ortho"
1019        } else {
1020            SendCmd "camera mode persp"
1021        }
1022        DoRotate
1023        InitSettings axis-xgrid axis-ygrid axis-zgrid axisFlyMode \
1024            axesVisible axisLabels
1025        PanCamera
1026    }
1027    set _first ""
1028
1029    SendCmd "imgflush"
1030    set _first ""
1031
1032    SendCmd "dataset visible 0"
1033    foreach dataobj [get -objects] {
1034        if { [info exists _obj2ovride($dataobj-raise)] &&  $_first == "" } {
1035            set _first $dataobj
1036        }
1037        set _obj2datasets($dataobj) ""
1038        foreach comp [$dataobj components] {
1039            set tag $dataobj-$comp
1040            if { ![info exists _datasets($tag)] } {
1041                set bytes [$dataobj vtkdata $comp]
1042                set length [string length $bytes]
1043                if { $_reportClientInfo }  {
1044                    set info {}
1045                    lappend info "tool_id"       [$dataobj hints toolId]
1046                    lappend info "tool_name"     [$dataobj hints toolName]
1047                    lappend info "tool_version"  [$dataobj hints toolRevision]
1048                    lappend info "tool_title"    [$dataobj hints toolTitle]
1049                    lappend info "dataset_label" [$dataobj hints label]
1050                    lappend info "dataset_size"  $length
1051                    lappend info "dataset_tag"   $tag
1052                    SendCmd [list "clientinfo" $info]
1053                }
1054                append _outbuf "dataset add $tag data follows $length\n"
1055                append _outbuf $bytes
1056                set _datasets($tag) 1
1057                SetObjectStyle $dataobj $comp
1058            }
1059            lappend _obj2datasets($dataobj) $tag
1060            if { [info exists _obj2ovride($dataobj-raise)] } {
1061                SendCmd "dataset visible 1 $tag"
1062            }
1063            break
1064        }
1065    }
1066    if {"" != $_first} {
1067        set location [$_first hints camera]
1068        if { $location != "" } {
1069            array set view $location
1070        }
1071
1072        foreach axis { x y z } {
1073            set label [$_first hints ${axis}label]
1074            if { $label != "" } {
1075                SendCmd "axis name $axis $label"
1076            }
1077            set units [$_first hints ${axis}units]
1078            if { $units != "" } {
1079                SendCmd "axis units $axis $units"
1080            }
1081        }
1082        $itk_component(field) choices delete 0 end
1083        $itk_component(fieldmenu) delete 0 end
1084        array unset _fields
1085        set _curFldName ""
1086        foreach cname [$_first components] {
1087            foreach fname [$_first fieldnames $cname] {
1088                if { [info exists _fields($fname)] } {
1089                    continue
1090                }
1091                foreach { label units components } \
1092                    [$_first fieldinfo $fname] break
1093                # Only scalar fields are valid
1094                if {$components == 1} {
1095                    $itk_component(field) choices insert end "$fname" "$label"
1096                    $itk_component(fieldmenu) add radiobutton -label "$label" \
1097                        -value $label -variable [itcl::scope _curFldLabel] \
1098                        -selectcolor red \
1099                        -activebackground $itk_option(-plotbackground) \
1100                        -activeforeground $itk_option(-plotforeground) \
1101                        -font "Arial 8" \
1102                        -command [itcl::code $this Combo invoke]
1103                    set _fields($fname) [list $label $units $components]
1104                    if { $_curFldName == "" } {
1105                        set _curFldName $fname
1106                        set _curFldLabel $label
1107                    }
1108                }
1109            }
1110        }
1111        $itk_component(field) value $_curFldLabel
1112    }
1113
1114    InitSettings volumeColormap \
1115        volumeAmbient volumeDiffuse volume-specularLevel volume-specularExponent \
1116        volume-opacity volume-quality volumeVisible \
1117        cutplaneVisible \
1118        cutplane-xposition cutplane-yposition cutplane-zposition \
1119        cutplane-xvisible cutplane-yvisible cutplane-zvisible
1120
1121    if { $_reset } {
1122        InitSettings volumeLighting
1123        Zoom reset
1124        set _reset 0
1125    }
1126    # Actually write the commands to the server socket.  If it fails, we don't
1127    # care.  We're finished here.
1128    blt::busy hold $itk_component(hull)
1129    StopBufferingCommands
1130    blt::busy release $itk_component(hull)
1131}
1132
1133# ----------------------------------------------------------------------
1134# USAGE: CurrentDatasets ?-all -visible? ?dataobjs?
1135#
1136# Returns a list of server IDs for the current datasets being displayed.  This
1137# is normally a single ID, but it might be a list of IDs if the current data
1138# object has multiple components.
1139# ----------------------------------------------------------------------
1140itcl::body Rappture::VtkVolumeViewer::CurrentDatasets {args} {
1141    set flag [lindex $args 0]
1142    switch -- $flag {
1143        "-all" {
1144            if { [llength $args] > 1 } {
1145                error "CurrentDatasets: can't specify dataobj after \"-all\""
1146            }
1147            set dlist [get -objects]
1148        }
1149        "-visible" {
1150            if { [llength $args] > 1 } {
1151                set dlist {}
1152                set args [lrange $args 1 end]
1153                foreach dataobj $args {
1154                    if { [info exists _obj2ovride($dataobj-raise)] } {
1155                        lappend dlist $dataobj
1156                    }
1157                }
1158            } else {
1159                set dlist [get -visible]
1160            }
1161        }           
1162        default {
1163            set dlist $args
1164        }
1165    }
1166    set rlist ""
1167    foreach dataobj $dlist {
1168        foreach comp [$dataobj components] {
1169            set tag $dataobj-$comp
1170            if { [info exists _datasets($tag)] && $_datasets($tag) } {
1171                lappend rlist $tag
1172            }
1173        }
1174    }
1175    return $rlist
1176}
1177
1178# ----------------------------------------------------------------------
1179# USAGE: Zoom in
1180# USAGE: Zoom out
1181# USAGE: Zoom reset
1182#
1183# Called automatically when the user clicks on one of the zoom
1184# controls for this widget.  Changes the zoom for the current view.
1185# ----------------------------------------------------------------------
1186itcl::body Rappture::VtkVolumeViewer::Zoom {option} {
1187    switch -- $option {
1188        "in" {
1189            set _view(zoom) [expr {$_view(zoom)*1.25}]
1190            SendCmd "camera zoom $_view(zoom)"
1191        }
1192        "out" {
1193            set _view(zoom) [expr {$_view(zoom)*0.8}]
1194            SendCmd "camera zoom $_view(zoom)"
1195        }
1196        "reset" {
1197            array set _view {
1198                qw      0.853553
1199                qx      -0.353553
1200                qy      0.353553
1201                qz      0.146447
1202                zoom    1.0
1203                xpan   0
1204                ypan   0
1205            }
1206            if { $_first != "" } {
1207                set location [$_first hints camera]
1208                if { $location != "" } {
1209                    array set _view $location
1210                }
1211            }
1212            set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1213            $_arcball quaternion $q
1214            DoRotate
1215            SendCmd "camera reset"
1216        }
1217    }
1218}
1219
1220itcl::body Rappture::VtkVolumeViewer::PanCamera {} {
1221    set x $_view(xpan)
1222    set y $_view(ypan)
1223    SendCmd "camera pan $x $y"
1224}
1225
1226
1227# ----------------------------------------------------------------------
1228# USAGE: Rotate click <x> <y>
1229# USAGE: Rotate drag <x> <y>
1230# USAGE: Rotate release <x> <y>
1231#
1232# Called automatically when the user clicks/drags/releases in the
1233# plot area.  Moves the plot according to the user's actions.
1234# ----------------------------------------------------------------------
1235itcl::body Rappture::VtkVolumeViewer::Rotate {option x y} {
1236    switch -- $option {
1237        "click" {
1238            $itk_component(view) configure -cursor fleur
1239            set _click(x) $x
1240            set _click(y) $y
1241        }
1242        "drag" {
1243            if {[array size _click] == 0} {
1244                Rotate click $x $y
1245            } else {
1246                set w [winfo width $itk_component(view)]
1247                set h [winfo height $itk_component(view)]
1248                if {$w <= 0 || $h <= 0} {
1249                    return
1250                }
1251
1252                if {[catch {
1253                    # this fails sometimes for no apparent reason
1254                    set dx [expr {double($x-$_click(x))/$w}]
1255                    set dy [expr {double($y-$_click(y))/$h}]
1256                }]} {
1257                    return
1258                }
1259                if { $dx == 0 && $dy == 0 } {
1260                    return
1261                }
1262                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1263                EventuallyRotate $q
1264                set _click(x) $x
1265                set _click(y) $y
1266            }
1267        }
1268        "release" {
1269            Rotate drag $x $y
1270            $itk_component(view) configure -cursor ""
1271            catch {unset _click}
1272        }
1273        default {
1274            error "bad option \"$option\": should be click, drag, release"
1275        }
1276    }
1277}
1278
1279itcl::body Rappture::VtkVolumeViewer::Pick {x y} {
1280    foreach tag [CurrentDatasets -visible] {
1281        SendCmd "dataset getscalar pixel $x $y $tag"
1282    }
1283}
1284
1285# ----------------------------------------------------------------------
1286# USAGE: $this Pan click x y
1287#        $this Pan drag x y
1288#        $this Pan release x y
1289#
1290# Called automatically when the user clicks on one of the zoom
1291# controls for this widget.  Changes the zoom for the current view.
1292# ----------------------------------------------------------------------
1293itcl::body Rappture::VtkVolumeViewer::Pan {option x y} {
1294    switch -- $option {
1295        "set" {
1296            set w [winfo width $itk_component(view)]
1297            set h [winfo height $itk_component(view)]
1298            set x [expr $x / double($w)]
1299            set y [expr $y / double($h)]
1300            set _view(xpan) [expr $_view(xpan) + $x]
1301            set _view(ypan) [expr $_view(ypan) + $y]
1302            PanCamera
1303            return
1304        }
1305        "click" {
1306            set _click(x) $x
1307            set _click(y) $y
1308            $itk_component(view) configure -cursor hand1
1309        }
1310        "drag" {
1311            if { ![info exists _click(x)] } {
1312                set _click(x) $x
1313            }
1314            if { ![info exists _click(y)] } {
1315                set _click(y) $y
1316            }
1317            set w [winfo width $itk_component(view)]
1318            set h [winfo height $itk_component(view)]
1319            set dx [expr ($_click(x) - $x)/double($w)]
1320            set dy [expr ($_click(y) - $y)/double($h)]
1321            set _click(x) $x
1322            set _click(y) $y
1323            set _view(xpan) [expr $_view(xpan) - $dx]
1324            set _view(ypan) [expr $_view(ypan) - $dy]
1325            PanCamera
1326        }
1327        "release" {
1328            Pan drag $x $y
1329            $itk_component(view) configure -cursor ""
1330        }
1331        default {
1332            error "unknown option \"$option\": should set, click, drag, or release"
1333        }
1334    }
1335}
1336
1337# ----------------------------------------------------------------------
1338# USAGE: InitSettings <what> ?<value>?
1339#
1340# Used internally to update rendering settings whenever parameters
1341# change in the popup settings panel.  Sends the new settings off
1342# to the back end.
1343# ----------------------------------------------------------------------
1344itcl::body Rappture::VtkVolumeViewer::InitSettings { args } {
1345    foreach spec $args {
1346        if { [info exists _settings($_first-$spec)] } {
1347            # Reset global setting with dataobj specific setting
1348            set _settings($spec) $_settings($_first-$spec)
1349        }
1350        AdjustSetting $spec
1351    }
1352}
1353
1354#
1355# AdjustSetting --
1356#
1357#       Changes/updates a specific setting in the widget.  There are
1358#       usually user-setable option.  Commands are sent to the render
1359#       server.
1360#
1361itcl::body Rappture::VtkVolumeViewer::AdjustSetting {what {value ""}} {
1362    if { ![isconnected] } {
1363        return
1364    }
1365    switch -- $what {
1366        "volumeVisible" {
1367            set bool $_settings(volumeVisible)
1368            foreach dataset [CurrentDatasets -visible] {
1369                SendCmd "volume visible $bool $dataset"
1370            }
1371            if { $bool } {
1372                Rappture::Tooltip::for $itk_component(volume) \
1373                    "Hide the volume"
1374            } else {
1375                Rappture::Tooltip::for $itk_component(volume) \
1376                    "Show the volume"
1377            }
1378        }
1379        "volume-blendmode" {
1380            set val [$itk_component(blendmode) value]
1381            set mode [$itk_component(blendmode) translate $val]
1382            set _settings(volume-blendmode) $mode
1383            foreach dataset [CurrentDatasets -visible] {
1384                SendCmd "volume blendmode $mode $dataset"
1385            }
1386        }
1387        "volumeAmbient" {
1388            set val $_settings(volumeAmbient)
1389            set ambient [expr {0.01*$val}]
1390            foreach dataset [CurrentDatasets -visible] {
1391                SendCmd "volume shading ambient $ambient $dataset"
1392            }
1393        }
1394        "volumeDiffuse" {
1395            set val $_settings(volumeDiffuse)
1396            set diffuse [expr {0.01*$val}]
1397            foreach dataset [CurrentDatasets -visible] {
1398                SendCmd "volume shading diffuse $diffuse $dataset"
1399            }
1400        }
1401        "volume-specularLevel" - "volume-specularExponent" {
1402            set val $_settings(volume-specularLevel)
1403            set specularLevel [expr {0.01*$val}]
1404            set specularExponent $_settings(volume-specularExponent)
1405            foreach dataset [CurrentDatasets -visible] {
1406                SendCmd "volume shading specular $specularLevel $specularExponent $dataset"
1407            }
1408        }
1409        "volumeLighting" {
1410            set bool $_settings(volumeLighting)
1411            foreach dataset [CurrentDatasets -visible] {
1412                SendCmd "volume lighting $bool $dataset"
1413            }
1414        }
1415        "volume-opacity" {
1416            set val $_settings(volume-opacity)
1417            set val [expr {0.01*$val}]
1418            foreach dataset [CurrentDatasets -visible] {
1419                SendCmd "volume opacity $val $dataset"
1420            }
1421        }
1422        "volume-quality" {
1423            set val $_settings(volume-quality)
1424            set val [expr {0.01*$val}]
1425            foreach dataset [CurrentDatasets -visible] {
1426                SendCmd "volume quality $val $dataset"
1427            }
1428        }
1429        "axesVisible" {
1430            set bool $_settings(axesVisible)
1431            SendCmd "axis visible all $bool"
1432        }
1433        "axisLabels" {
1434            set bool $_settings(axisLabels)
1435            SendCmd "axis labels all $bool"
1436        }
1437        "axis-xgrid" - "axis-ygrid" - "axis-zgrid" {
1438            set axis [string range $what 5 5]
1439            set bool $_settings($what)
1440            SendCmd "axis grid $axis $bool"
1441        }
1442        "axisFlyMode" {
1443            set mode [$itk_component(axismode) value]
1444            set mode [$itk_component(axismode) translate $mode]
1445            set _settings($what) $mode
1446            SendCmd "axis flymode $mode"
1447        }
1448        "cutplaneEdges" {
1449            set bool $_settings($what)
1450            foreach dataset [CurrentDatasets -visible] {
1451                SendCmd "cutplane edges $bool $dataset"
1452            }
1453        }
1454        "cutplaneVisible" {
1455            set bool $_settings($what)
1456            foreach dataset [CurrentDatasets -visible] {
1457                SendCmd "cutplane visible $bool $dataset"
1458            }
1459        }
1460        "cutplaneWireframe" {
1461            set bool $_settings($what)
1462            foreach dataset [CurrentDatasets -visible] {
1463                SendCmd "cutplane wireframe $bool $dataset"
1464            }
1465        }
1466        "cutplaneLighting" {
1467            set bool $_settings($what)
1468            foreach dataset [CurrentDatasets -visible] {
1469                SendCmd "cutplane lighting $bool $dataset"
1470            }
1471        }
1472        "cutplane-opacity" {
1473            set val $_settings($what)
1474            set sval [expr { 0.01 * double($val) }]
1475            foreach dataset [CurrentDatasets -visible] {
1476                SendCmd "cutplane opacity $sval $dataset"
1477            }
1478        }
1479        "cutplane-xvisible" - "cutplane-yvisible" - "cutplane-zvisible" {
1480            set axis [string range $what 9 9]
1481            set bool $_settings($what)
1482            if { $bool } {
1483                $itk_component(${axis}CutScale) configure -state normal \
1484                    -troughcolor white
1485            } else {
1486                $itk_component(${axis}CutScale) configure -state disabled \
1487                    -troughcolor grey82
1488            }
1489            foreach dataset [CurrentDatasets -visible] {
1490                SendCmd "cutplane axis $axis $bool $dataset"
1491            }
1492        }
1493        "cutplane-xposition" - "cutplane-yposition" - "cutplane-zposition" {
1494            set axis [string range $what 9 9]
1495            set pos [expr $_settings($what) * 0.01]
1496            foreach dataset [CurrentDatasets -visible] {
1497                SendCmd "cutplane slice ${axis} ${pos} $dataset"
1498            }
1499            set _cutplanePending 0
1500        }
1501        "thickness" {
1502            set val $_settings($this-thickness)
1503            set _settings($_current-thickness) $val
1504            updateTransferFunctions
1505        }
1506        "volumeColormap" {
1507            set color [$itk_component(colormap) value]
1508            set _settings($this-colormap) $color
1509            set _settings($_current-colormap) $color
1510            ResetColormap $_current $color
1511            set _legendPending 1
1512        }
1513        "field" {
1514            set label [$itk_component(field) value]
1515            set fname [$itk_component(field) translate $label]
1516            set _settings(field) $fname
1517            if { [info exists _fields($fname)] } {
1518                foreach { label units components } $_fields($fname) break
1519                if { $components > 1 } {
1520                    puts stderr "Can't use a vector field in a volume"
1521                    return
1522                } else {
1523                    set _colorMode scalar
1524                }
1525                set _curFldName $fname
1526                set _curFldLabel $label
1527            } else {
1528                puts stderr "unknown field \"$fname\""
1529                return
1530            }
1531            foreach dataset [CurrentDatasets -visible $_first] {
1532                #SendCmd "volume colormode $_colorMode ${fname} $dataset"
1533                SendCmd "cutplane colormode $_colorMode ${fname} $dataset"
1534            }
1535            SendCmd "camera reset"
1536            DrawLegend
1537        }
1538        default {
1539            error "don't know how to fix $what"
1540        }
1541    }
1542}
1543
1544#
1545# RequestLegend --
1546#
1547#       Request a new legend from the server.  The size of the legend
1548#       is determined from the height of the canvas.  It will be rotated
1549#       to be vertical when drawn.
1550#
1551itcl::body Rappture::VtkVolumeViewer::RequestLegend {} {
1552    set font "Arial 8"
1553    set lineht [font metrics $itk_option(-font) -linespace]
1554    set c $itk_component(legend)
1555    set w [winfo width $c]
1556    set h [winfo height $c]
1557    set h [expr {$h-$lineht-20}]
1558    set w [expr {$w-20}]
1559    # Set the legend on the first volume dataset.
1560    foreach dataset [CurrentDatasets -visible $_first] {
1561        foreach {dataobj comp} [split $dataset -] break
1562        if { [info exists _dataset2style($dataset)] } {
1563            SendCmdNoWait \
1564                "legend $_dataset2style($dataset) $_colorMode $_curFldName {} $w $h 0"
1565            break;
1566        }
1567    }
1568}
1569
1570#
1571# ChangeColormap --
1572#
1573itcl::body Rappture::VtkVolumeViewer::ChangeColormap {dataobj comp color} {
1574    set tag $dataobj-$comp
1575    if { ![info exist _style($tag)] } {
1576        error "no initial colormap"
1577    }
1578    array set style $_style($tag)
1579    set style(-color) $color
1580    set _style($tag) [array get style]
1581    SetColormap $dataobj $comp
1582}
1583
1584#
1585# SetColormap --
1586#
1587itcl::body Rappture::VtkVolumeViewer::SetColormap { dataobj comp } {
1588    array set style {
1589        -color BCGYR
1590        -levels 6
1591        -opacity 1.0
1592    }
1593    set tag $dataobj-$comp
1594    if { ![info exists _initialStyle($tag)] } {
1595        # Save the initial component style.
1596        set _initialStyle($tag) [$dataobj style $comp]
1597    }
1598
1599    # Override defaults with initial style defined in xml.
1600    array set style $_initialStyle($tag)
1601
1602    if { ![info exists _style($tag)] } {
1603        set _style($tag) [array get style]
1604    }
1605    # Override initial style with current style.
1606    array set style $_style($tag)
1607
1608    set name "$style(-color):$style(-levels):$style(-opacity)"
1609    if { ![info exists _colormaps($name)] } {
1610        BuildColormap $name [array get style]
1611        set _colormaps($name) 1
1612    }
1613    if { ![info exists _dataset2style($tag)] ||
1614         $_dataset2style($tag) != $name } {
1615        SendCmd "volume colormap $name $tag"
1616        SendCmd "cutplane colormap $name-opaque $tag"
1617        set _dataset2style($tag) $name
1618    }
1619}
1620
1621#
1622# BuildColormap --
1623#
1624itcl::body Rappture::VtkVolumeViewer::BuildColormap { name styles } {
1625    array set style $styles
1626    set cmap [ColorsToColormap $style(-color)]
1627    if { [llength $cmap] == 0 } {
1628        set cmap "0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0"
1629    }
1630    if { ![info exists _settings(volume-opacity)] } {
1631        set _settings(volume-opacity) $style(-opacity)
1632    }
1633    set max $_settings(volume-opacity)
1634
1635    set opaqueWmap "0.0 1.0 1.0 1.0"
1636    #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"
1637    # Approximate cubic opacity curve
1638    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"
1639    SendCmd "colormap add $name { $cmap } { $wmap }"
1640    SendCmd "colormap add $name-opaque { $cmap } { $opaqueWmap }"
1641}
1642
1643# ----------------------------------------------------------------------
1644# CONFIGURATION OPTION: -plotbackground
1645# ----------------------------------------------------------------------
1646itcl::configbody Rappture::VtkVolumeViewer::plotbackground {
1647    if { [isconnected] } {
1648        foreach {r g b} [Color2RGB $itk_option(-plotbackground)] break
1649        SendCmd "screen bgcolor $r $g $b"
1650    }
1651}
1652
1653# ----------------------------------------------------------------------
1654# CONFIGURATION OPTION: -plotforeground
1655# ----------------------------------------------------------------------
1656itcl::configbody Rappture::VtkVolumeViewer::plotforeground {
1657    if { [isconnected] } {
1658        foreach {r g b} [Color2RGB $itk_option(-plotforeground)] break
1659        #fix this!
1660        #SendCmd "color background $r $g $b"
1661    }
1662}
1663
1664itcl::body Rappture::VtkVolumeViewer::BuildVolumeTab {} {
1665    set font [option get $itk_component(hull) font Font]
1666    #set bfont [option get $itk_component(hull) boldFont Font]
1667
1668    set inner [$itk_component(main) insert end \
1669        -title "Volume Settings" \
1670        -icon [Rappture::icon volume-on]]
1671    $inner configure -borderwidth 4
1672
1673    label $inner.volcomponents_l -text "Component" -font $font
1674    itk_component add volcomponents {
1675        Rappture::Combobox $inner.volcomponents -editable no
1676    }
1677    $itk_component(volcomponents) value "BCGYR"
1678    bind $inner.volcomponents <<Value>> \
1679        [itcl::code $this AdjustSetting current]
1680
1681    checkbutton $inner.visibility \
1682        -text "Visible" \
1683        -font $font \
1684        -variable [itcl::scope _settings(volumeVisible)] \
1685        -command [itcl::code $this AdjustSetting volumeVisible]
1686
1687    label $inner.lighting_l \
1688        -text "Lighting / Material Properties" \
1689        -font "Arial 9 bold"
1690
1691    checkbutton $inner.lighting \
1692        -text "Enable Lighting" \
1693        -font $font \
1694        -variable [itcl::scope _settings(volumeLighting)] \
1695        -command [itcl::code $this AdjustSetting volumeLighting]
1696
1697    label $inner.ambient_l \
1698        -text "Ambient" \
1699        -font $font
1700    ::scale $inner.ambient -from 0 -to 100 -orient horizontal \
1701        -variable [itcl::scope _settings(volumeAmbient)] \
1702        -showvalue off -command [itcl::code $this AdjustSetting volumeAmbient] \
1703        -troughcolor grey92
1704
1705    label $inner.diffuse_l -text "Diffuse" -font $font
1706    ::scale $inner.diffuse -from 0 -to 100 -orient horizontal \
1707        -variable [itcl::scope _settings(volumeDiffuse)] \
1708        -showvalue off -command [itcl::code $this AdjustSetting volumeDiffuse] \
1709        -troughcolor grey92
1710
1711    label $inner.specularLevel_l -text "Specular" -font $font
1712    ::scale $inner.specularLevel -from 0 -to 100 -orient horizontal \
1713        -variable [itcl::scope _settings(volume-specularLevel)] \
1714        -showvalue off -command [itcl::code $this AdjustSetting volume-specularLevel] \
1715        -troughcolor grey92
1716
1717    label $inner.specularExponent_l -text "Shininess" -font $font
1718    ::scale $inner.specularExponent -from 10 -to 128 -orient horizontal \
1719        -variable [itcl::scope _settings(volume-specularExponent)] \
1720        -showvalue off -command [itcl::code $this AdjustSetting volume-specularExponent] \
1721        -troughcolor grey92
1722
1723    label $inner.opacity_l -text "Opacity" -font $font
1724    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1725        -variable [itcl::scope _settings(volume-opacity)] \
1726        -showvalue off -command [itcl::code $this AdjustSetting volume-opacity] \
1727        -troughcolor grey92
1728
1729    label $inner.quality_l -text "Quality" -font $font
1730    ::scale $inner.quality -from 0 -to 100 -orient horizontal \
1731        -variable [itcl::scope _settings(volume-quality)] \
1732        -showvalue off -command [itcl::code $this AdjustSetting volume-quality] \
1733        -troughcolor grey92
1734
1735    label $inner.field_l -text "Field" -font $font
1736    itk_component add field {
1737        Rappture::Combobox $inner.field -editable no
1738    }
1739    bind $inner.field <<Value>> \
1740        [itcl::code $this AdjustSetting field]
1741
1742    label $inner.transferfunction_l \
1743        -text "Transfer Function" -font "Arial 9 bold"
1744
1745    label $inner.thin -text "Thin" -font $font
1746    ::scale $inner.thickness -from 0 -to 1000 -orient horizontal \
1747        -variable [itcl::scope _settings($this-thickness)] \
1748        -showvalue off -command [itcl::code $this AdjustSetting thickness] \
1749        -troughcolor grey92
1750
1751    label $inner.thick -text "Thick" -font $font
1752
1753
1754    label $inner.colormap_l -text "Colormap" -font $font
1755    itk_component add colormap {
1756        Rappture::Combobox $inner.colormap -width 10 -editable no
1757    }
1758    $inner.colormap choices insert end \
1759        "BCGYR"              "BCGYR"            \
1760        "BGYOR"              "BGYOR"            \
1761        "blue"               "blue"             \
1762        "blue-to-brown"      "blue-to-brown"    \
1763        "blue-to-orange"     "blue-to-orange"   \
1764        "blue-to-grey"       "blue-to-grey"     \
1765        "green-to-magenta"   "green-to-magenta" \
1766        "greyscale"          "greyscale"        \
1767        "nanohub"            "nanohub"          \
1768        "rainbow"            "rainbow"          \
1769        "spectral"           "spectral"         \
1770        "ROYGB"              "ROYGB"            \
1771        "RYGCB"              "RYGCB"            \
1772        "brown-to-blue"      "brown-to-blue"    \
1773        "grey-to-blue"       "grey-to-blue"     \
1774        "orange-to-blue"     "orange-to-blue"   
1775
1776    $itk_component(colormap) value "BCGYR"
1777    bind $inner.colormap <<Value>> \
1778        [itcl::code $this AdjustSetting volumeColormap]
1779
1780    label $inner.blendmode_l -text "Blend Mode" -font $font
1781    itk_component add blendmode {
1782        Rappture::Combobox $inner.blendmode -editable no
1783    }
1784    $inner.blendmode choices insert end \
1785        "composite"          "Composite"         \
1786        "max_intensity"      "Maximum Intensity" \
1787        "additive"           "Additive"
1788
1789    $itk_component(blendmode) value "composite"
1790    bind $inner.blendmode <<Value>> \
1791        [itcl::code $this AdjustSetting volume-blendmode]
1792
1793    blt::table $inner \
1794        0,0 $inner.volcomponents_l -anchor e -cspan 2 \
1795        0,2 $inner.volcomponents             -cspan 3 -fill x \
1796        1,0 $inner.field_l   -anchor e -cspan 2  \
1797        1,2 $inner.field               -cspan 3 -fill x \
1798        2,0 $inner.lighting_l -anchor w -cspan 4 \
1799        3,1 $inner.lighting   -anchor w -cspan 3 \
1800        4,1 $inner.ambient_l       -anchor e -pady 2 \
1801        4,2 $inner.ambient                   -cspan 3 -fill x \
1802        5,1 $inner.diffuse_l       -anchor e -pady 2 \
1803        5,2 $inner.diffuse                   -cspan 3 -fill x \
1804        6,1 $inner.specularLevel_l -anchor e -pady 2 \
1805        6,2 $inner.specularLevel             -cspan 3 -fill x \
1806        7,1 $inner.specularExponent_l -anchor e -pady 2 \
1807        7,2 $inner.specularExponent          -cspan 3 -fill x \
1808        8,1 $inner.visibility    -anchor w -cspan 3 \
1809        9,1 $inner.quality_l -anchor e -pady 2 \
1810        9,2 $inner.quality                     -cspan 3 -fill x \
1811        10,0 $inner.transferfunction_l -anchor w              -cspan 4 \
1812        11,1 $inner.opacity_l -anchor e -pady 2 \
1813        11,2 $inner.opacity                    -cspan 3 -fill x \
1814        12,1 $inner.colormap_l -anchor e  \
1815        12,2 $inner.colormap                 -padx 2 -cspan 3 -fill x \
1816        13,1 $inner.blendmode_l -anchor e  \
1817        13,2 $inner.blendmode               -padx 2 -cspan 3 -fill x \
1818        14,1 $inner.thin             -anchor e \
1819        14,2 $inner.thickness                 -cspan 2 -fill x \
1820        14,4 $inner.thick -anchor w 
1821
1822    blt::table configure $inner r* c* -resize none
1823    blt::table configure $inner r* -pady { 2 0 }
1824    blt::table configure $inner c2 c3 r15 -resize expand
1825    blt::table configure $inner c0 -width .1i
1826}
1827
1828itcl::body Rappture::VtkVolumeViewer::BuildAxisTab {} {
1829
1830    set fg [option get $itk_component(hull) font Font]
1831    #set bfg [option get $itk_component(hull) boldFont Font]
1832
1833    set inner [$itk_component(main) insert end \
1834        -title "Axis Settings" \
1835        -icon [Rappture::icon axis1]]
1836    $inner configure -borderwidth 4
1837
1838    checkbutton $inner.visible \
1839        -text "Show Axes" \
1840        -variable [itcl::scope _settings(axesVisible)] \
1841        -command [itcl::code $this AdjustSetting axesVisible] \
1842        -font "Arial 9"
1843
1844    checkbutton $inner.labels \
1845        -text "Show Axis Labels" \
1846        -variable [itcl::scope _settings(axisLabels)] \
1847        -command [itcl::code $this AdjustSetting axisLabels] \
1848        -font "Arial 9"
1849
1850    checkbutton $inner.gridx \
1851        -text "Show X Grid" \
1852        -variable [itcl::scope _settings(axis-xgrid)] \
1853        -command [itcl::code $this AdjustSetting axis-xgrid] \
1854        -font "Arial 9"
1855    checkbutton $inner.gridy \
1856        -text "Show Y Grid" \
1857        -variable [itcl::scope _settings(axis-ygrid)] \
1858        -command [itcl::code $this AdjustSetting axis-ygrid] \
1859        -font "Arial 9"
1860    checkbutton $inner.gridz \
1861        -text "Show Z Grid" \
1862        -variable [itcl::scope _settings(axis-zgrid)] \
1863        -command [itcl::code $this AdjustSetting axis-zgrid] \
1864        -font "Arial 9"
1865
1866    label $inner.mode_l -text "Mode" -font "Arial 9"
1867
1868    itk_component add axismode {
1869        Rappture::Combobox $inner.mode -width 10 -editable no
1870    }
1871    $inner.mode choices insert end \
1872        "static_triad"    "static" \
1873        "closest_triad"   "closest" \
1874        "furthest_triad"  "farthest" \
1875        "outer_edges"     "outer"         
1876    $itk_component(axismode) value "static"
1877    bind $inner.mode <<Value>> [itcl::code $this AdjustSetting axisFlyMode]
1878
1879    blt::table $inner \
1880        0,0 $inner.visible -anchor w -cspan 2 \
1881        1,0 $inner.labels  -anchor w -cspan 2 \
1882        2,0 $inner.gridx   -anchor w -cspan 2 \
1883        3,0 $inner.gridy   -anchor w -cspan 2 \
1884        4,0 $inner.gridz   -anchor w -cspan 2 \
1885        5,0 $inner.mode_l  -anchor w -cspan 2 -padx { 2 0 } \
1886        6,0 $inner.mode    -fill x   -cspan 2
1887
1888    blt::table configure $inner r* c* -resize none
1889    blt::table configure $inner r7 c1 -resize expand
1890}
1891
1892
1893itcl::body Rappture::VtkVolumeViewer::BuildCameraTab {} {
1894    set inner [$itk_component(main) insert end \
1895        -title "Camera Settings" \
1896        -icon [Rappture::icon camera]]
1897    $inner configure -borderwidth 4
1898
1899    label $inner.view_l -text "view" -font "Arial 9"
1900    set f [frame $inner.view]
1901    foreach side { front back left right top bottom } {
1902        button $f.$side  -image [Rappture::icon view$side] \
1903            -command [itcl::code $this SetOrientation $side]
1904        Rappture::Tooltip::for $f.$side "Change the view to $side"
1905        pack $f.$side -side left
1906    }
1907    blt::table $inner \
1908        0,0 $inner.view_l -anchor e -pady 2 \
1909        0,1 $inner.view -anchor w -pady 2
1910
1911    set row 1
1912
1913    set labels { qx qy qz qw xpan ypan zoom }
1914    foreach tag $labels {
1915        label $inner.${tag}label -text $tag -font "Arial 9"
1916        entry $inner.${tag} -font "Arial 9"  -bg white \
1917            -textvariable [itcl::scope _view($tag)]
1918        bind $inner.${tag} <KeyPress-Return> \
1919            [itcl::code $this camera set ${tag}]
1920        blt::table $inner \
1921            $row,0 $inner.${tag}label -anchor e -pady 2 \
1922            $row,1 $inner.${tag} -anchor w -pady 2
1923        blt::table configure $inner r$row -resize none
1924        incr row
1925    }
1926    checkbutton $inner.ortho \
1927        -text "Orthographic Projection" \
1928        -variable [itcl::scope _view(ortho)] \
1929        -command [itcl::code $this camera set ortho] \
1930        -font "Arial 9"
1931    blt::table $inner \
1932            $row,0 $inner.ortho -cspan 2 -anchor w -pady 2
1933    blt::table configure $inner r$row -resize none
1934    incr row
1935
1936    blt::table configure $inner r* c0 c1 -resize none
1937    blt::table configure $inner c2 -resize expand
1938    blt::table configure $inner r$row -resize expand
1939}
1940
1941itcl::body Rappture::VtkVolumeViewer::BuildCutplaneTab {} {
1942
1943    set fg [option get $itk_component(hull) font Font]
1944   
1945    set inner [$itk_component(main) insert end \
1946        -title "Cutplane Settings" \
1947        -icon [Rappture::icon cutbutton]]
1948
1949    $inner configure -borderwidth 4
1950
1951    checkbutton $inner.visible \
1952        -text "Show Cutplanes" \
1953        -variable [itcl::scope _settings(cutplaneVisible)] \
1954        -command [itcl::code $this AdjustSetting cutplaneVisible] \
1955        -font "Arial 9"
1956
1957    checkbutton $inner.wireframe \
1958        -text "Show Wireframe" \
1959        -variable [itcl::scope _settings(cutplaneWireframe)] \
1960        -command [itcl::code $this AdjustSetting cutplaneWireframe] \
1961        -font "Arial 9"
1962
1963    checkbutton $inner.lighting \
1964        -text "Enable Lighting" \
1965        -variable [itcl::scope _settings(cutplaneLighting)] \
1966        -command [itcl::code $this AdjustSetting cutplaneLighting] \
1967        -font "Arial 9"
1968
1969    checkbutton $inner.edges \
1970        -text "Show Edges" \
1971        -variable [itcl::scope _settings(cutplaneEdges)] \
1972        -command [itcl::code $this AdjustSetting cutplaneEdges] \
1973        -font "Arial 9"
1974
1975    label $inner.opacity_l -text "Opacity" -font "Arial 9"
1976    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1977        -variable [itcl::scope _settings(cutplane-opacity)] \
1978        -width 10 \
1979        -showvalue off \
1980        -command [itcl::code $this AdjustSetting cutplane-opacity]
1981    $inner.opacity set $_settings(cutplane-opacity)
1982
1983    # X-value slicer...
1984    itk_component add xCutButton {
1985        Rappture::PushButton $inner.xbutton \
1986            -onimage [Rappture::icon x-cutplane] \
1987            -offimage [Rappture::icon x-cutplane] \
1988            -command [itcl::code $this AdjustSetting cutplane-xvisible] \
1989            -variable [itcl::scope _settings(cutplane-xvisible)]
1990    }
1991    Rappture::Tooltip::for $itk_component(xCutButton) \
1992        "Toggle the X-axis cutplane on/off"
1993    $itk_component(xCutButton) select
1994
1995    itk_component add xCutScale {
1996        ::scale $inner.xval -from 100 -to 0 \
1997            -width 10 -orient vertical -showvalue yes \
1998            -borderwidth 1 -highlightthickness 0 \
1999            -command [itcl::code $this EventuallySetCutplane x] \
2000            -variable [itcl::scope _settings(cutplane-xposition)]
2001    } {
2002        usual
2003        ignore -borderwidth -highlightthickness
2004    }
2005    # Set the default cutplane value before disabling the scale.
2006    $itk_component(xCutScale) set 50
2007    $itk_component(xCutScale) configure -state disabled
2008    Rappture::Tooltip::for $itk_component(xCutScale) \
2009        "@[itcl::code $this Slice tooltip x]"
2010
2011    # Y-value slicer...
2012    itk_component add yCutButton {
2013        Rappture::PushButton $inner.ybutton \
2014            -onimage [Rappture::icon y-cutplane] \
2015            -offimage [Rappture::icon y-cutplane] \
2016            -command [itcl::code $this AdjustSetting cutplane-yvisible] \
2017            -variable [itcl::scope _settings(cutplane-yvisible)]
2018    }
2019    Rappture::Tooltip::for $itk_component(yCutButton) \
2020        "Toggle the Y-axis cutplane on/off"
2021    $itk_component(yCutButton) select
2022
2023    itk_component add yCutScale {
2024        ::scale $inner.yval -from 100 -to 0 \
2025            -width 10 -orient vertical -showvalue yes \
2026            -borderwidth 1 -highlightthickness 0 \
2027            -command [itcl::code $this EventuallySetCutplane y] \
2028            -variable [itcl::scope _settings(cutplane-yposition)]
2029    } {
2030        usual
2031        ignore -borderwidth -highlightthickness
2032    }
2033    Rappture::Tooltip::for $itk_component(yCutScale) \
2034        "@[itcl::code $this Slice tooltip y]"
2035    # Set the default cutplane value before disabling the scale.
2036    $itk_component(yCutScale) set 50
2037    $itk_component(yCutScale) configure -state disabled
2038
2039    # Z-value slicer...
2040    itk_component add zCutButton {
2041        Rappture::PushButton $inner.zbutton \
2042            -onimage [Rappture::icon z-cutplane] \
2043            -offimage [Rappture::icon z-cutplane] \
2044            -command [itcl::code $this AdjustSetting cutplane-zvisible] \
2045            -variable [itcl::scope _settings(cutplane-zvisible)]
2046    }
2047    Rappture::Tooltip::for $itk_component(zCutButton) \
2048        "Toggle the Z-axis cutplane on/off"
2049    $itk_component(zCutButton) select
2050
2051    itk_component add zCutScale {
2052        ::scale $inner.zval -from 100 -to 0 \
2053            -width 10 -orient vertical -showvalue yes \
2054            -borderwidth 1 -highlightthickness 0 \
2055            -command [itcl::code $this EventuallySetCutplane z] \
2056            -variable [itcl::scope _settings(cutplane-zposition)]
2057    } {
2058        usual
2059        ignore -borderwidth -highlightthickness
2060    }
2061    $itk_component(zCutScale) set 50
2062    $itk_component(zCutScale) configure -state disabled
2063    Rappture::Tooltip::for $itk_component(zCutScale) \
2064        "@[itcl::code $this Slice tooltip z]"
2065
2066    blt::table $inner \
2067        0,0 $inner.visible              -anchor w -pady 2 -cspan 4 \
2068        1,0 $inner.lighting             -anchor w -pady 2 -cspan 4 \
2069        2,0 $inner.wireframe            -anchor w -pady 2 -cspan 4 \
2070        3,0 $inner.edges                -anchor w -pady 2 -cspan 4 \
2071        4,0 $inner.opacity_l            -anchor w -pady 2 -cspan 3 \
2072        5,0 $inner.opacity              -fill x   -pady 2 -cspan 3 \
2073        6,0 $itk_component(xCutButton)  -anchor e -padx 2 -pady 2 \
2074        7,0 $itk_component(xCutScale)   -fill y \
2075        6,1 $itk_component(yCutButton)  -anchor e -padx 2 -pady 2 \
2076        7,1 $itk_component(yCutScale)   -fill y \
2077        6,2 $itk_component(zCutButton)  -anchor e -padx 2 -pady 2 \
2078        7,2 $itk_component(zCutScale)   -fill y \
2079
2080    blt::table configure $inner r* c* -resize none
2081    blt::table configure $inner r7 c3 -resize expand
2082}
2083
2084#
2085#  camera --
2086#
2087itcl::body Rappture::VtkVolumeViewer::camera {option args} {
2088    switch -- $option {
2089        "show" {
2090            puts [array get _view]
2091        }
2092        "set" {
2093            set who [lindex $args 0]
2094            set x $_view($who)
2095            set code [catch { string is double $x } result]
2096            if { $code != 0 || !$result } {
2097                return
2098            }
2099            switch -- $who {
2100                "ortho" {
2101                    if {$_view(ortho)} {
2102                        SendCmd "camera mode ortho"
2103                    } else {
2104                        SendCmd "camera mode persp"
2105                    }
2106                }
2107                "xpan" - "ypan" {
2108                    PanCamera
2109                }
2110                "qx" - "qy" - "qz" - "qw" {
2111                    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
2112                    $_arcball quaternion $q
2113                    EventuallyRotate $q
2114                }
2115                "zoom" {
2116                    SendCmd "camera zoom $_view(zoom)"
2117                }
2118            }
2119        }
2120    }
2121}
2122
2123itcl::body Rappture::VtkVolumeViewer::GetVtkData { args } {
2124    set bytes ""
2125    foreach dataobj [get] {
2126        foreach comp [$dataobj components] {
2127            set tag $dataobj-$comp
2128            set contents [$dataobj vtkdata $comp]
2129            append bytes "$contents\n"
2130        }
2131    }
2132    return [list .vtk $bytes]
2133}
2134
2135itcl::body Rappture::VtkVolumeViewer::GetImage { args } {
2136    if { [image width $_image(download)] > 0 &&
2137         [image height $_image(download)] > 0 } {
2138        set bytes [$_image(download) data -format "jpeg -quality 100"]
2139        set bytes [Rappture::encoding::decode -as b64 $bytes]
2140        return [list .jpg $bytes]
2141    }
2142    return ""
2143}
2144
2145itcl::body Rappture::VtkVolumeViewer::BuildDownloadPopup { popup command } {
2146    Rappture::Balloon $popup \
2147        -title "[Rappture::filexfer::label downloadWord] as..."
2148    set inner [$popup component inner]
2149    label $inner.summary -text "" -anchor w
2150    radiobutton $inner.vtk_button -text "VTK data file" \
2151        -variable [itcl::scope _downloadPopup(format)] \
2152        -font "Helvetica 9 " \
2153        -value vtk 
2154    Rappture::Tooltip::for $inner.vtk_button "Save as VTK data file."
2155    radiobutton $inner.image_button -text "Image File" \
2156        -variable [itcl::scope _downloadPopup(format)] \
2157        -value image
2158    Rappture::Tooltip::for $inner.image_button \
2159        "Save as digital image."
2160
2161    button $inner.ok -text "Save" \
2162        -highlightthickness 0 -pady 2 -padx 3 \
2163        -command $command \
2164        -compound left \
2165        -image [Rappture::icon download]
2166
2167    button $inner.cancel -text "Cancel" \
2168        -highlightthickness 0 -pady 2 -padx 3 \
2169        -command [list $popup deactivate] \
2170        -compound left \
2171        -image [Rappture::icon cancel]
2172
2173    blt::table $inner \
2174        0,0 $inner.summary -cspan 2  \
2175        1,0 $inner.vtk_button -anchor w -cspan 2 -padx { 4 0 } \
2176        2,0 $inner.image_button -anchor w -cspan 2 -padx { 4 0 } \
2177        4,1 $inner.cancel -width .9i -fill y \
2178        4,0 $inner.ok -padx 2 -width .9i -fill y
2179    blt::table configure $inner r3 -height 4
2180    blt::table configure $inner r4 -pady 4
2181    raise $inner.image_button
2182    $inner.vtk_button invoke
2183    return $inner
2184}
2185
2186itcl::body Rappture::VtkVolumeViewer::SetObjectStyle { dataobj cname } {
2187    # Parse style string.
2188    set tag $dataobj-$cname
2189    set style [$dataobj style $cname]
2190    array set settings {
2191        -color \#808080
2192        -edges 0
2193        -edgecolor black
2194        -linewidth 1.0
2195        -opacity 0.4
2196        -wireframe 0
2197        -lighting 1
2198        -seeds 1
2199        -seedcolor white
2200        -visible 1
2201    }
2202    if { $dataobj != $_first } {
2203        set settings(-opacity) 1
2204    }
2205    array set settings $style
2206    SendCmd "volume add $tag"
2207    SendCmd "cutplane add $tag"
2208    SendCmd "cutplane visible 0 $tag"
2209    SendCmd "volume lighting $settings(-lighting) $tag"
2210    set _settings(volumeLighting) $settings(-lighting)
2211    SetInitialTransferFunction $dataobj $cname
2212    SendCmd "volume colormap $cname $tag"
2213}
2214
2215itcl::body Rappture::VtkVolumeViewer::IsValidObject { dataobj } {
2216    if {[catch {$dataobj isa Rappture::Field} valid] != 0 || !$valid} {
2217        return 0
2218    }
2219    return 1
2220}
2221
2222# ----------------------------------------------------------------------
2223# USAGE: ReceiveLegend <colormap> <title> <vmin> <vmax> <size>
2224#
2225# Invoked automatically whenever the "legend" command comes in from
2226# the rendering server.  Indicates that binary image data with the
2227# specified <size> will follow.
2228# ----------------------------------------------------------------------
2229itcl::body Rappture::VtkVolumeViewer::ReceiveLegend { colormap title vmin vmax size } {
2230    set _legendPending 0
2231    if { [IsConnected] } {
2232        set bytes [ReceiveBytes $size]
2233        if { ![info exists _image(legend)] } {
2234            set _image(legend) [image create photo]
2235        }
2236        $_image(legend) configure -data $bytes
2237        #puts stderr "read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
2238        if { [catch {DrawLegend} errs] != 0 } {
2239            puts stderr errs=$errs
2240        }
2241    }
2242}
2243
2244#
2245# DrawLegend --
2246#
2247itcl::body Rappture::VtkVolumeViewer::DrawLegend {} {
2248    if { $_current == "" } {
2249        set _current "component"
2250    }
2251    set cname $_current
2252    set c $itk_component(legend)
2253    set w [winfo width $c]
2254    set h [winfo height $c]
2255    set lx 10
2256    set ly [expr {$h - 1}]
2257    if {"" == [$c find withtag transfunc]} {
2258        $c create image 10 10 -anchor nw \
2259            -image $_image(legend) -tags transfunc
2260        $c create text $lx $ly -anchor sw \
2261            -fill $itk_option(-plotforeground) -tags "limits text vmin"
2262        $c create text [expr {$w-$lx}] $ly -anchor se \
2263            -fill $itk_option(-plotforeground) -tags "limits text vmax"
2264        $c create text [expr {$w/2}] $ly -anchor s \
2265            -fill $itk_option(-plotforeground) -tags "limits text title"
2266        $c lower transfunc
2267    }
2268
2269    # Display the markers used by the current transfer function.
2270    HideAllMarkers
2271    if { [info exists _transferFunctionEditors($cname)] } {
2272        $_transferFunctionEditors($cname) showMarkers $_limits($cname)
2273    }
2274
2275    foreach {min max} $_limits($cname) break
2276    $c itemconfigure vmin -text [format %.2g $min]
2277    $c coords vmin $lx $ly
2278
2279    $c itemconfigure vmax -text [format %.2g $max]
2280    $c coords vmax [expr {$w-$lx}] $ly
2281
2282    set title ""
2283    if { $_first != "" } {
2284        set title [$_first hints label]
2285        set units [$_first hints units]
2286        if { $units != "" } {
2287            set title "$title ($units)"
2288        }
2289    }
2290    $c itemconfigure title -text $title
2291    $c coords title [expr {$w/2}] $ly
2292}
2293
2294#
2295# DrawLegendOld --
2296#
2297#       Draws the legend in it's own canvas which resides to the right
2298#       of the contour plot area.
2299#
2300itcl::body Rappture::VtkVolumeViewer::DrawLegendOld { } {
2301    set fname $_curFldName
2302    set c $itk_component(view)
2303    set w [winfo width $c]
2304    set h [winfo height $c]
2305    set font "Arial 8"
2306    set lineht [font metrics $font -linespace]
2307   
2308    if { [info exists _fields($fname)] } {
2309        foreach { title units } $_fields($fname) break
2310        if { $units != "" } {
2311            set title [format "%s (%s)" $title $units]
2312        }
2313    } else {
2314        set title $fname
2315    }
2316    if { $_settings(legendVisible) } {
2317        set x [expr $w - 2]
2318        if { [$c find withtag "legend"] == "" } {
2319            set y 2
2320            $c create text $x $y \
2321                -anchor ne \
2322                -fill $itk_option(-plotforeground) -tags "title legend" \
2323                -font $font
2324            incr y $lineht
2325            $c create text $x $y \
2326                -anchor ne \
2327                -fill $itk_option(-plotforeground) -tags "vmax legend" \
2328                -font $font
2329            incr y $lineht
2330            $c create image $x $y \
2331                -anchor ne \
2332                -image $_image(legend) -tags "colormap legend"
2333            $c create text $x [expr {$h-2}] \
2334                -anchor se \
2335                -fill $itk_option(-plotforeground) -tags "vmin legend" \
2336                -font $font
2337            #$c bind colormap <Enter> [itcl::code $this EnterLegend %x %y]
2338            $c bind colormap <Leave> [itcl::code $this LeaveLegend]
2339            $c bind colormap <Motion> [itcl::code $this MotionLegend %x %y]
2340        }
2341        $c bind title <ButtonPress> [itcl::code $this Combo post]
2342        $c bind title <Enter> [itcl::code $this Combo activate]
2343        $c bind title <Leave> [itcl::code $this Combo deactivate]
2344        # Reset the item coordinates according the current size of the plot.
2345        $c itemconfigure title -text $title
2346        if { [info exists _limits($_curFldName)] } {
2347            foreach { vmin vmax } $_limits($_curFldName) break
2348            $c itemconfigure vmin -text [format %g $vmin]
2349            $c itemconfigure vmax -text [format %g $vmax]
2350        }
2351        set y 2
2352        $c coords title $x $y
2353        incr y $lineht
2354        $c coords vmax $x $y
2355        incr y $lineht
2356        $c coords colormap $x $y
2357        $c coords vmin $x [expr {$h - 2}]
2358    }
2359}
2360
2361#
2362# EnterLegend --
2363#
2364itcl::body Rappture::VtkVolumeViewer::EnterLegend { x y } {
2365    SetLegendTip $x $y
2366}
2367
2368#
2369# MotionLegend --
2370#
2371itcl::body Rappture::VtkVolumeViewer::MotionLegend { x y } {
2372    Rappture::Tooltip::tooltip cancel
2373    set c $itk_component(view)
2374    SetLegendTip $x $y
2375}
2376
2377#
2378# LeaveLegend --
2379#
2380itcl::body Rappture::VtkVolumeViewer::LeaveLegend { } {
2381    Rappture::Tooltip::tooltip cancel
2382    .rappturetooltip configure -icon ""
2383}
2384
2385#
2386# SetLegendTip --
2387#
2388itcl::body Rappture::VtkVolumeViewer::SetLegendTip { x y } {
2389    set c $itk_component(view)
2390    set w [winfo width $c]
2391    set h [winfo height $c]
2392    set font "Arial 8"
2393    set lineht [font metrics $font -linespace]
2394   
2395    set imgHeight [image height $_image(legend)]
2396    set coords [$c coords colormap]
2397    set imgX [expr $w - [image width $_image(legend)] - 2]
2398    set imgY [expr $y - 2 * ($lineht + 2)]
2399
2400    if { [info exists _fields($_title)] } {
2401        foreach { title units } $_fields($_title) break
2402        if { $units != "" } {
2403            set title [format "%s (%s)" $title $units]
2404        }
2405    } else {
2406        set title $_title
2407    }
2408    # Make a swatch of the selected color
2409    if { [catch { $_image(legend) get 10 $imgY } pixel] != 0 } {
2410        #puts stderr "out of range: $imgY"
2411        return
2412    }
2413    if { ![info exists _image(swatch)] } {
2414        set _image(swatch) [image create photo -width 24 -height 24]
2415    }
2416    set color [eval format "\#%02x%02x%02x" $pixel]
2417    $_image(swatch) put black  -to 0 0 23 23
2418    $_image(swatch) put $color -to 1 1 22 22
2419    .rappturetooltip configure -icon $_image(swatch)
2420
2421    # Compute the value of the point
2422    if { [info exists _limits($_curFldName)] } {
2423        foreach { vmin vmax } $_limits($_curFldName) break
2424        set t [expr 1.0 - (double($imgY) / double($imgHeight-1))]
2425        set value [expr $t * ($vmax - $vmin) + $vmin]
2426    } else {
2427        set value 0.0
2428    }
2429    set tipx [expr $x + 15]
2430    set tipy [expr $y - 5]
2431    Rappture::Tooltip::text $c "$title $value"
2432    Rappture::Tooltip::tooltip show $c +$tipx,+$tipy   
2433}
2434
2435
2436# ----------------------------------------------------------------------
2437# USAGE: Slice move x|y|z <newval>
2438#
2439# Called automatically when the user drags the slider to move the
2440# cut plane that slices 3D data.  Gets the current value from the
2441# slider and moves the cut plane to the appropriate point in the
2442# data set.
2443# ----------------------------------------------------------------------
2444itcl::body Rappture::VtkVolumeViewer::Slice {option args} {
2445    switch -- $option {
2446        "move" {
2447            set axis [lindex $args 0]
2448            set newval [lindex $args 1]
2449            if {[llength $args] != 2} {
2450                error "wrong # args: should be \"Slice move x|y|z newval\""
2451            }
2452            set newpos [expr {0.01*$newval}]
2453            SendCmd "cutplane slice $axis $newpos"
2454        }
2455        "tooltip" {
2456            set axis [lindex $args 0]
2457            set val [$itk_component(${axis}CutScale) get]
2458            return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
2459        }
2460        default {
2461            error "bad option \"$option\": should be axis, move, or tooltip"
2462        }
2463    }
2464}
2465
2466
2467# ----------------------------------------------------------------------
2468# USAGE: _dropdown post
2469# USAGE: _dropdown unpost
2470# USAGE: _dropdown select
2471#
2472# Used internally to handle the dropdown list for this combobox.  The
2473# post/unpost options are invoked when the list is posted or unposted
2474# to manage the relief of the controlling button.  The select option
2475# is invoked whenever there is a selection from the list, to assign
2476# the value back to the gauge.
2477# ----------------------------------------------------------------------
2478itcl::body Rappture::VtkVolumeViewer::Combo {option} {
2479    set c $itk_component(view)
2480    switch -- $option {
2481        post {
2482            foreach { x1 y1 x2 y2 } [$c bbox title] break
2483            set x1 [expr [winfo width $itk_component(view)] - [winfo reqwidth $itk_component(fieldmenu)]]
2484            set x [expr $x1 + [winfo rootx $itk_component(view)]]
2485            set y [expr $y2 + [winfo rooty $itk_component(view)]]
2486            tk_popup $itk_component(fieldmenu) $x $y
2487        }
2488        activate {
2489            $c itemconfigure title -fill red
2490        }
2491        deactivate {
2492            $c itemconfigure title -fill white
2493        }
2494        invoke {
2495            $itk_component(field) value _curFldLabel
2496            AdjustSetting field
2497        }
2498        default {
2499            error "bad option \"$option\": should be post, unpost, select"
2500        }
2501    }
2502}
2503
2504#
2505# The -levels option takes a single value that represents the number
2506# of evenly distributed markers based on the current data range. Each
2507# marker is a relative value from 0.0 to 1.0.
2508#
2509itcl::body Rappture::VtkVolumeViewer::ParseLevelsOption { cname levels } {
2510    set c $itk_component(legend)
2511    set list {}
2512    regsub -all "," $levels " " levels
2513    if {[string is int $levels]} {
2514        for {set i 1} { $i <= $levels } {incr i} {
2515            lappend list [expr {double($i)/($levels+1)}]
2516        }
2517    } else {
2518        foreach x $levels {
2519            lappend list $x
2520        }
2521    }
2522    set _parsedFunction($cname) 1
2523    $_transferFunctionEditors($cname) addMarkers $list
2524}
2525
2526#
2527# The -markers option takes a list of zero or more values (the values
2528# may be separated either by spaces or commas) that have the following
2529# format:
2530#
2531#   N%  Percent of current total data range.  Converted to
2532#       to a relative value between 0.0 and 1.0.
2533#   N   Absolute value of marker.  If the marker is outside of
2534#       the current range, it will be displayed on the outer
2535#       edge of the legends, but it range it represents will
2536#       not be seen.
2537#
2538itcl::body Rappture::VtkVolumeViewer::ParseMarkersOption { cname markers } {
2539    set c $itk_component(legend)
2540    set list {}
2541    foreach { min max } $_limits($cname) break
2542    regsub -all "," $markers " " markers
2543    foreach marker $markers {
2544        set n [scan $marker "%g%s" value suffix]
2545        if { $n == 2 && $suffix == "%" } {
2546            # $n% : Set relative value (0..1).
2547            lappend list [expr {$value * 0.01}]
2548        } else {
2549            # $n : absolute value, compute relative
2550            lappend list  [expr {(double($value)-$min)/($max-$min)]}
2551        }
2552    }
2553    set _parsedFunction($cname) 1
2554    $_transferFunctionEditors($cname) addMarkers $list
2555}
2556
2557#
2558# SetInitialTransferFunction --
2559#
2560#       Creates a transfer function name based on the <style> settings in the
2561#       library run.xml file. This placeholder will be used later to create
2562#       and send the actual transfer function once the data info has been sent
2563#       to us by the render server. [We won't know the volume limits until the
2564#       server parses the 3D data and sends back the limits via ReceiveData.]
2565#
2566itcl::body Rappture::VtkVolumeViewer::SetInitialTransferFunction { dataobj cname } {
2567    set tag $dataobj-$cname
2568    if { ![info exists _cname2transferFunction($cname)] } {
2569        ComputeTransferFunction $cname
2570    }
2571    set _dataset2style($tag) $cname
2572    lappend _style2datasets($cname) $tag
2573
2574    return $cname
2575}
2576
2577#
2578# ComputeTransferFunction --
2579#
2580#       Computes and sends the transfer function to the render server.  It's
2581#       assumed that the volume data limits are known and that the global
2582#       transfer-functions slider values have been set up.  Both parts are
2583#       needed to compute the relative value (location) of the marker, and
2584#       the alpha map of the transfer function.
2585#
2586itcl::body Rappture::VtkVolumeViewer::ComputeTransferFunction { cname } {
2587
2588    if { ![info exists _transferFunctionEditors($cname)] } {
2589        set _transferFunctionEditors($cname) \
2590            [Rappture::TransferFunctionEditor ::\#auto $itk_component(legend) \
2591                 $cname \
2592                 -command [itcl::code $this updateTransferFunctions]]
2593    }
2594
2595    # We have to parse the style attributes for a volume using this
2596    # transfer-function *once*.  This sets up the initial isomarkers for the
2597    # transfer function.  The user may add/delete markers, so we have to
2598    # maintain a list of markers for each transfer-function.  We use the one
2599    # of the volumes (the first in the list) using the transfer-function as a
2600    # reference.
2601
2602    if { ![info exists _parsedFunction($cname)] || ![info exists _cname2transferFunction($cname)] } {
2603        array set style {
2604            -color BCGYR
2605            -levels 6
2606            -opacity 1.0
2607            -markers ""
2608        }
2609
2610        # Accumulate the style from all the datasets using it.
2611        foreach tag [GetDatasetsWithComponent $cname] {
2612            foreach {dataobj cname} [split [lindex $tag 0] -] break
2613            array set style [lindex [$dataobj components -style $cname] 0]
2614        }
2615        set cmap [ColorsToColormap $style(-color)]
2616        set _cname2defaultcolormap($cname) $cmap
2617        set _settings($cname-colormap) $style(-color)
2618        if { [info exists _transferFunctionEditors($cname)] } {
2619            eval $_transferFunctionEditors($cname) limits $_limits($cname)
2620        }
2621        if { [info exists style(-markers)] &&
2622             [llength $style(-markers)] > 0 } {
2623            ParseMarkersOption $cname $style(-markers)
2624        } else {
2625            ParseLevelsOption $cname $style(-levels)
2626        }
2627    } else {
2628        foreach {cmap wmap} $_cname2transferFunction($cname) break
2629    }
2630
2631    set wmap [ComputeAlphamap $cname]
2632    set _cname2transferFunction($cname) [list $cmap $wmap]
2633    SendCmd [list colormap add $cname $cmap $wmap]
2634}
2635
2636#
2637# ResetColormap --
2638#
2639#       Changes only the colormap portion of the transfer function.
2640#
2641itcl::body Rappture::VtkVolumeViewer::ResetColormap { cname color } {
2642    # Get the current transfer function
2643    if { ![info exists _cname2transferFunction($cname)] } {
2644        return
2645    }
2646    foreach { cmap wmap } $_cname2transferFunction($cname) break
2647    set cmap [GetColormap $cname $color]
2648    set _cname2transferFunction($cname) [list $cmap $wmap]
2649    SendCmd [list colormap add $cname $cmap $wmap]
2650    EventuallyRequestLegend
2651}
2652
2653# ----------------------------------------------------------------------
2654# USAGE: updateTransferFunctions
2655#
2656#       This is called by the transfer function editor whenever the
2657#       transfer function definition changes.
2658#
2659# ----------------------------------------------------------------------
2660itcl::body Rappture::VtkVolumeViewer::updateTransferFunctions {} {
2661    foreach cname [array names _volcomponents] {
2662        ComputeTransferFunction $cname
2663    }
2664    EventuallyRequestLegend
2665}
2666
2667itcl::body Rappture::VtkVolumeViewer::SetOrientation { side } {
2668    array set positions {
2669        front "1 0 0 0"
2670        back  "0 0 1 0"
2671        left  "0.707107 0 -0.707107 0"
2672        right "0.707107 0 0.707107 0"
2673        top   "0.707107 -0.707107 0 0"
2674        bottom "0.707107 0.707107 0 0"
2675    }
2676    foreach name { qw qx qy qz } value $positions($side) {
2677        set _view($name) $value
2678    }
2679    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
2680    $_arcball quaternion $q
2681    SendCmd "camera orient $q"
2682    SendCmd "camera reset"
2683    set _view(xpan) 0
2684    set _view(ypan) 0
2685    set _view(zoom) 1.0
2686    set _settings($this-xpan) $_view(xpan)
2687    set _settings($this-ypan) $_view(ypan)
2688    set _settings($this-zoom) $_view(zoom)
2689}
2690
2691#
2692# InitComponentSettings --
2693#
2694#       Initializes the volume settings for a specific component. This
2695#       should match what's used as global settings above. This
2696#       is called the first time we try to switch to a given component
2697#       in SwitchComponent below.
2698#
2699itcl::body Rappture::VtkVolumeViewer::InitComponentSettings { cname } {
2700    array set _settings [subst {
2701        $cname-ambient           60
2702        $cname-colormap          default
2703        $cname-diffuse           40
2704        $cname-light2side        1
2705        $cname-opacity           100
2706        $cname-outline           0
2707        $cname-specularExponent  90
2708        $cname-specularLevel     30
2709        $cname-thickness         350
2710        $cname-transp            50
2711        $cname-volumeVisible     1
2712    }]
2713}
2714
2715#
2716# SwitchComponent --
2717#
2718#       This is called when the current component is changed by the
2719#       dropdown menu in the volume tab.  It synchronizes the global
2720#       volume settings with the settings of the new current component.
2721#
2722itcl::body Rappture::VtkVolumeViewer::SwitchComponent { cname } {
2723    if { ![info exists _settings($cname-ambient)] } {
2724        InitComponentSettings $cname
2725    }
2726    # _settings variables change widgets, except for colormap
2727    set _settings($this-ambient)          $_settings($cname-ambient)
2728    set _settings($this-colormap)         $_settings($cname-colormap)
2729    set _settings($this-diffuse)          $_settings($cname-diffuse)
2730    set _settings($this-light2side)       $_settings($cname-light2side)
2731    set _settings($this-opacity)          $_settings($cname-opacity)
2732    set _settings($this-outline)          $_settings($cname-outline)
2733    set _settings($this-specularExponent) $_settings($cname-specularExponent)
2734    set _settings($this-specularLevel)    $_settings($cname-specularLevel)
2735    set _settings($this-thickness)        $_settings($cname-thickness)
2736    set _settings($this-transp)           $_settings($cname-transp)
2737    set _settings($this-volumeVisible)    $_settings($cname-volumeVisible)
2738    $itk_component(colormap) value        $_settings($cname-colormap)
2739    set _current $cname;                # Reset the current component
2740}
2741
2742itcl::body Rappture::VtkVolumeViewer::ComputeAlphamap { cname } {
2743    if { ![info exists _transferFunctionEditors($cname)] } {
2744        return [list 0.0 0.0 1.0 1.0]
2745    }
2746    if { ![info exists _settings($cname-ambient)] } {
2747        InitComponentSettings $cname
2748    }
2749    set max 1.0 ;                       #$_settings($tag-opacity)
2750
2751    set isovalues [$_transferFunctionEditors($cname) values]
2752
2753    # Ensure that the global opacity and thickness settings (in the slider
2754    # settings widgets) are used for the active transfer-function.  Update
2755    # the values in the _settings varible.
2756    set opacity [expr { double($_settings($cname-opacity)) * 0.01 }]
2757
2758    # Scale values between 0.00001 and 0.01000
2759    set delta [expr {double($_settings($cname-thickness)) * 0.0001}]
2760   
2761    set first [lindex $isovalues 0]
2762    set last [lindex $isovalues end]
2763    set wmap ""
2764    if { $first == "" || $first != 0.0 } {
2765        lappend wmap 0.0 0.0
2766    }
2767    foreach x $isovalues {
2768        set x1 [expr {$x-$delta-0.00001}]
2769        set x2 [expr {$x-$delta}]
2770        set x3 [expr {$x+$delta}]
2771        set x4 [expr {$x+$delta+0.00001}]
2772        if { $x1 < 0.0 } {
2773            set x1 0.0
2774        } elseif { $x1 > 1.0 } {
2775            set x1 1.0
2776        }
2777        if { $x2 < 0.0 } {
2778            set x2 0.0
2779        } elseif { $x2 > 1.0 } {
2780            set x2 1.0
2781        }
2782        if { $x3 < 0.0 } {
2783            set x3 0.0
2784        } elseif { $x3 > 1.0 } {
2785            set x3 1.0
2786        }
2787        if { $x4 < 0.0 } {
2788            set x4 0.0
2789        } elseif { $x4 > 1.0 } {
2790            set x4 1.0
2791        }
2792        # add spikes in the middle
2793        lappend wmap $x1 0.0
2794        lappend wmap $x2 $max
2795        lappend wmap $x3 $max
2796        lappend wmap $x4 0.0
2797    }
2798    if { $last == "" || $last != 1.0 } {
2799        lappend wmap 1.0 0.0
2800    }
2801    return $wmap
2802}
2803
2804#
2805# HideAllMarkers --
2806#
2807#       Hide all the markers in all the transfer functions.  Can't simply
2808#       delete and recreate markers from the <style> since the user may
2809#       have create, deleted, or moved markers.
2810#
2811itcl::body Rappture::VtkVolumeViewer::HideAllMarkers {} {
2812    foreach cname [array names _transferFunctionEditors] {
2813        $_transferFunctionEditors($cname) hideMarkers
2814    }
2815}
2816
2817
2818#
2819# GetDatasetsWithComponents --
2820#
2821#       Returns a list of all the datasets (known by the combination of
2822#       their data object and component name) that match the given
2823#       component name.  For example, this is used where we want to change
2824#       the settings of volumes that have the current component.
2825#
2826itcl::body Rappture::VtkVolumeViewer::GetDatasetsWithComponent { cname } {
2827    if { ![info exists _volcomponents($cname)] } {
2828        return ""
2829    }
2830    set list ""
2831    foreach tag $_volcomponents($cname) {
2832        if { ![info exists _serverDatasets($tag)] } {
2833            continue
2834        }
2835        lappend list $tag
2836    }
2837    return $list
2838}
2839
2840#
2841# BuildVolumeComponents --
2842#
2843#       This is called from the "scale" method which is called when a
2844#       new dataset is added or deleted.  It repopulates the dropdown
2845#       menu of volume component names.  It sets the current component
2846#       to the first component in the list (of components found).
2847#       Finally, if there is only one component, don't display the
2848#       label or the combobox in the volume settings tab.
2849#
2850itcl::body Rappture::VtkVolumeViewer::BuildVolumeComponents {} {
2851    $itk_component(volcomponents) choices delete 0 end
2852    foreach name $_componentsList {
2853        $itk_component(volcomponents) choices insert end $name $name
2854    }
2855    set _current [lindex $_componentsList 0]
2856    $itk_component(volcomponents) value $_current
2857    set parent [winfo parent $itk_component(volcomponents)]
2858    if { [llength $_componentsList] <= 1 } {
2859        # Unpack the components label and dropdown if there's only one
2860        # component.
2861        blt::table forget $parent.volcomponents_l $parent.volcomponents
2862    } else {
2863        # Pack the components label and dropdown into the table there's
2864        # more than one component to select.
2865        blt::table $parent \
2866            0,0 $parent.volcomponents_l -anchor e -cspan 2 \
2867            0,2 $parent.volcomponents -cspan 3 -fill x
2868    }
2869}
2870
2871itcl::body Rappture::VtkVolumeViewer::GetColormap { cname color } {
2872    if { $color == "default" } {
2873        return $_cname2defaultcolormap($cname)
2874    }
2875    return [ColorsToColormap $color]
2876}
Note: See TracBrowser for help on using the repository browser.