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

Last change on this file since 4045 was 4045, checked in by ldelgass, 10 years ago

Revert colormap change from r4042. Cutplane colormap should default to the
same as volume colormap. Also, grayscale is already pre-defined by server,
it is called "grayDefault". If we need grayscale for medical data, a grayscale
colormap should be chosen by a tool or custom viewer. Default volume rendering
should use the colormap similar to nanovis.

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