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

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

More colormap fixes for cutplanes

File size: 97.5 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 _limits($cname) [list $min $max]
733            } else {
734                foreach {vmin vmax} $_limits($cname) break
735                if { $min < $vmin } {
736                    set vmin $min
737                }
738                if { $max > $vmax } {
739                    set vmax $max
740                }
741                set _limits($cname) [list $vmin $vmax]
742            }
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) $bool
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    SendCmd "cutplane colormap $cname-opaque $tag"
2149}
2150
2151itcl::body Rappture::VtkVolumeViewer::IsValidObject { dataobj } {
2152    if {[catch {$dataobj isa Rappture::Field} valid] != 0 || !$valid} {
2153        return 0
2154    }
2155    return 1
2156}
2157
2158# ----------------------------------------------------------------------
2159# USAGE: ReceiveLegend <colormap> <title> <vmin> <vmax> <size>
2160#
2161# Invoked automatically whenever the "legend" command comes in from
2162# the rendering server.  Indicates that binary image data with the
2163# specified <size> will follow.
2164# ----------------------------------------------------------------------
2165itcl::body Rappture::VtkVolumeViewer::ReceiveLegend { colormap title vmin vmax size } {
2166    set _legendPending 0
2167    if { [isconnected] } {
2168        set bytes [ReceiveBytes $size]
2169        if { ![info exists _image(legend)] } {
2170            set _image(legend) [image create photo]
2171        }
2172        $_image(legend) configure -data $bytes
2173        #puts stderr "read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
2174        if { [catch {DrawLegend} errs] != 0 } {
2175            puts stderr errs=$errs
2176        }
2177    }
2178}
2179
2180#
2181# DrawLegend --
2182#
2183itcl::body Rappture::VtkVolumeViewer::DrawLegend {} {
2184    if { $_current == "" } {
2185        set _current "component"
2186    }
2187    set cname $_current
2188    set c $itk_component(legend)
2189    set w [winfo width $c]
2190    set h [winfo height $c]
2191    set lx 10
2192    set ly [expr {$h - 1}]
2193    if {"" == [$c find withtag transfunc]} {
2194        $c create image 10 10 -anchor nw \
2195            -image $_image(legend) -tags transfunc
2196        $c create text $lx $ly -anchor sw \
2197            -fill $itk_option(-plotforeground) -tags "limits text vmin"
2198        $c create text [expr {$w-$lx}] $ly -anchor se \
2199            -fill $itk_option(-plotforeground) -tags "limits text vmax"
2200        $c create text [expr {$w/2}] $ly -anchor s \
2201            -fill $itk_option(-plotforeground) -tags "limits text title"
2202        $c lower transfunc
2203    }
2204
2205    # Display the markers used by the current transfer function.
2206    HideAllMarkers
2207    if { [info exists _transferFunctionEditors($cname)] } {
2208        $_transferFunctionEditors($cname) showMarkers $_limits($cname)
2209    }
2210
2211    foreach {min max} $_limits($cname) break
2212    $c itemconfigure vmin -text [format %.2g $min]
2213    $c coords vmin $lx $ly
2214
2215    $c itemconfigure vmax -text [format %.2g $max]
2216    $c coords vmax [expr {$w-$lx}] $ly
2217
2218    set title ""
2219    if { $_first != "" } {
2220        set title [$_first hints label]
2221        set units [$_first hints units]
2222        if { $units != "" } {
2223            set title "$title ($units)"
2224        }
2225    }
2226    $c itemconfigure title -text $title
2227    $c coords title [expr {$w/2}] $ly
2228}
2229
2230#
2231# DrawLegendOld --
2232#
2233#       Draws the legend in it's own canvas which resides to the right
2234#       of the contour plot area.
2235#
2236itcl::body Rappture::VtkVolumeViewer::DrawLegendOld { } {
2237    set fname $_curFldName
2238    set c $itk_component(view)
2239    set w [winfo width $c]
2240    set h [winfo height $c]
2241    set font "Arial 8"
2242    set lineht [font metrics $font -linespace]
2243   
2244    if { [info exists _fields($fname)] } {
2245        foreach { title units } $_fields($fname) break
2246        if { $units != "" } {
2247            set title [format "%s (%s)" $title $units]
2248        }
2249    } else {
2250        set title $fname
2251    }
2252    if { $_settings(legendVisible) } {
2253        set x [expr $w - 2]
2254        if { [$c find withtag "legend"] == "" } {
2255            set y 2
2256            $c create text $x $y \
2257                -anchor ne \
2258                -fill $itk_option(-plotforeground) -tags "title legend" \
2259                -font $font
2260            incr y $lineht
2261            $c create text $x $y \
2262                -anchor ne \
2263                -fill $itk_option(-plotforeground) -tags "vmax legend" \
2264                -font $font
2265            incr y $lineht
2266            $c create image $x $y \
2267                -anchor ne \
2268                -image $_image(legend) -tags "colormap legend"
2269            $c create text $x [expr {$h-2}] \
2270                -anchor se \
2271                -fill $itk_option(-plotforeground) -tags "vmin legend" \
2272                -font $font
2273            #$c bind colormap <Enter> [itcl::code $this EnterLegend %x %y]
2274            $c bind colormap <Leave> [itcl::code $this LeaveLegend]
2275            $c bind colormap <Motion> [itcl::code $this MotionLegend %x %y]
2276        }
2277        $c bind title <ButtonPress> [itcl::code $this Combo post]
2278        $c bind title <Enter> [itcl::code $this Combo activate]
2279        $c bind title <Leave> [itcl::code $this Combo deactivate]
2280        # Reset the item coordinates according the current size of the plot.
2281        $c itemconfigure title -text $title
2282        if { [info exists _limits($_curFldName)] } {
2283            foreach { vmin vmax } $_limits($_curFldName) break
2284            $c itemconfigure vmin -text [format %g $vmin]
2285            $c itemconfigure vmax -text [format %g $vmax]
2286        }
2287        set y 2
2288        $c coords title $x $y
2289        incr y $lineht
2290        $c coords vmax $x $y
2291        incr y $lineht
2292        $c coords colormap $x $y
2293        $c coords vmin $x [expr {$h - 2}]
2294    }
2295}
2296
2297#
2298# EnterLegend --
2299#
2300itcl::body Rappture::VtkVolumeViewer::EnterLegend { x y } {
2301    SetLegendTip $x $y
2302}
2303
2304#
2305# MotionLegend --
2306#
2307itcl::body Rappture::VtkVolumeViewer::MotionLegend { x y } {
2308    Rappture::Tooltip::tooltip cancel
2309    set c $itk_component(view)
2310    SetLegendTip $x $y
2311}
2312
2313#
2314# LeaveLegend --
2315#
2316itcl::body Rappture::VtkVolumeViewer::LeaveLegend { } {
2317    Rappture::Tooltip::tooltip cancel
2318    .rappturetooltip configure -icon ""
2319}
2320
2321#
2322# SetLegendTip --
2323#
2324itcl::body Rappture::VtkVolumeViewer::SetLegendTip { x y } {
2325    set c $itk_component(view)
2326    set w [winfo width $c]
2327    set h [winfo height $c]
2328    set font "Arial 8"
2329    set lineht [font metrics $font -linespace]
2330   
2331    set imgHeight [image height $_image(legend)]
2332    set coords [$c coords colormap]
2333    set imgX [expr $w - [image width $_image(legend)] - 2]
2334    set imgY [expr $y - 2 * ($lineht + 2)]
2335
2336    if { [info exists _fields($_title)] } {
2337        foreach { title units } $_fields($_title) break
2338        if { $units != "" } {
2339            set title [format "%s (%s)" $title $units]
2340        }
2341    } else {
2342        set title $_title
2343    }
2344    # Make a swatch of the selected color
2345    if { [catch { $_image(legend) get 10 $imgY } pixel] != 0 } {
2346        #puts stderr "out of range: $imgY"
2347        return
2348    }
2349    if { ![info exists _image(swatch)] } {
2350        set _image(swatch) [image create photo -width 24 -height 24]
2351    }
2352    set color [eval format "\#%02x%02x%02x" $pixel]
2353    $_image(swatch) put black  -to 0 0 23 23
2354    $_image(swatch) put $color -to 1 1 22 22
2355    .rappturetooltip configure -icon $_image(swatch)
2356
2357    # Compute the value of the point
2358    if { [info exists _limits($_curFldName)] } {
2359        foreach { vmin vmax } $_limits($_curFldName) break
2360        set t [expr 1.0 - (double($imgY) / double($imgHeight-1))]
2361        set value [expr $t * ($vmax - $vmin) + $vmin]
2362    } else {
2363        set value 0.0
2364    }
2365    set tipx [expr $x + 15]
2366    set tipy [expr $y - 5]
2367    Rappture::Tooltip::text $c "$title $value"
2368    Rappture::Tooltip::tooltip show $c +$tipx,+$tipy   
2369}
2370
2371
2372# ----------------------------------------------------------------------
2373# USAGE: Slice move x|y|z <newval>
2374#
2375# Called automatically when the user drags the slider to move the
2376# cut plane that slices 3D data.  Gets the current value from the
2377# slider and moves the cut plane to the appropriate point in the
2378# data set.
2379# ----------------------------------------------------------------------
2380itcl::body Rappture::VtkVolumeViewer::Slice {option args} {
2381    switch -- $option {
2382        "move" {
2383            set axis [lindex $args 0]
2384            set newval [lindex $args 1]
2385            if {[llength $args] != 2} {
2386                error "wrong # args: should be \"Slice move x|y|z newval\""
2387            }
2388            set newpos [expr {0.01*$newval}]
2389            SendCmd "cutplane slice $axis $newpos"
2390        }
2391        "tooltip" {
2392            set axis [lindex $args 0]
2393            set val [$itk_component(${axis}CutScale) get]
2394            return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
2395        }
2396        default {
2397            error "bad option \"$option\": should be axis, move, or tooltip"
2398        }
2399    }
2400}
2401
2402
2403# ----------------------------------------------------------------------
2404# USAGE: _dropdown post
2405# USAGE: _dropdown unpost
2406# USAGE: _dropdown select
2407#
2408# Used internally to handle the dropdown list for this combobox.  The
2409# post/unpost options are invoked when the list is posted or unposted
2410# to manage the relief of the controlling button.  The select option
2411# is invoked whenever there is a selection from the list, to assign
2412# the value back to the gauge.
2413# ----------------------------------------------------------------------
2414itcl::body Rappture::VtkVolumeViewer::Combo {option} {
2415    set c $itk_component(view)
2416    switch -- $option {
2417        post {
2418            foreach { x1 y1 x2 y2 } [$c bbox title] break
2419            set x1 [expr [winfo width $itk_component(view)] - [winfo reqwidth $itk_component(fieldmenu)]]
2420            set x [expr $x1 + [winfo rootx $itk_component(view)]]
2421            set y [expr $y2 + [winfo rooty $itk_component(view)]]
2422            tk_popup $itk_component(fieldmenu) $x $y
2423        }
2424        activate {
2425            $c itemconfigure title -fill red
2426        }
2427        deactivate {
2428            $c itemconfigure title -fill white
2429        }
2430        invoke {
2431            $itk_component(field) value _curFldLabel
2432            AdjustSetting field
2433        }
2434        default {
2435            error "bad option \"$option\": should be post, unpost, select"
2436        }
2437    }
2438}
2439
2440#
2441# The -levels option takes a single value that represents the number
2442# of evenly distributed markers based on the current data range. Each
2443# marker is a relative value from 0.0 to 1.0.
2444#
2445itcl::body Rappture::VtkVolumeViewer::ParseLevelsOption { cname levels } {
2446    set c $itk_component(legend)
2447    set list {}
2448    regsub -all "," $levels " " levels
2449    if {[string is int $levels]} {
2450        for {set i 1} { $i <= $levels } {incr i} {
2451            lappend list [expr {double($i)/($levels+1)}]
2452        }
2453    } else {
2454        foreach x $levels {
2455            lappend list $x
2456        }
2457    }
2458    set _parsedFunction($cname) 1
2459    $_transferFunctionEditors($cname) addMarkers $list
2460}
2461
2462#
2463# The -markers option takes a list of zero or more values (the values
2464# may be separated either by spaces or commas) that have the following
2465# format:
2466#
2467#   N%  Percent of current total data range.  Converted to
2468#       to a relative value between 0.0 and 1.0.
2469#   N   Absolute value of marker.  If the marker is outside of
2470#       the current range, it will be displayed on the outer
2471#       edge of the legends, but it range it represents will
2472#       not be seen.
2473#
2474itcl::body Rappture::VtkVolumeViewer::ParseMarkersOption { cname markers } {
2475    set c $itk_component(legend)
2476    set list {}
2477    foreach { min max } $_limits($cname) break
2478    regsub -all "," $markers " " markers
2479    foreach marker $markers {
2480        set n [scan $marker "%g%s" value suffix]
2481        if { $n == 2 && $suffix == "%" } {
2482            # $n% : Set relative value (0..1).
2483            lappend list [expr {$value * 0.01}]
2484        } else {
2485            # $n : absolute value, compute relative
2486            lappend list  [expr {(double($value)-$min)/($max-$min)]}
2487        }
2488    }
2489    set _parsedFunction($cname) 1
2490    $_transferFunctionEditors($cname) addMarkers $list
2491}
2492
2493#
2494# SetInitialTransferFunction --
2495#
2496#       Creates a transfer function name based on the <style> settings in the
2497#       library run.xml file. This placeholder will be used later to create
2498#       and send the actual transfer function once the data info has been sent
2499#       to us by the render server. [We won't know the volume limits until the
2500#       server parses the 3D data and sends back the limits via ReceiveData.]
2501#
2502itcl::body Rappture::VtkVolumeViewer::SetInitialTransferFunction { dataobj cname } {
2503    set tag $dataobj-$cname
2504    if { ![info exists _cname2transferFunction($cname)] } {
2505        ComputeTransferFunction $cname
2506    }
2507    set _dataset2style($tag) $cname
2508    lappend _style2datasets($cname) $tag
2509
2510    return $cname
2511}
2512
2513#
2514# ComputeTransferFunction --
2515#
2516#       Computes and sends the transfer function to the render server.  It's
2517#       assumed that the volume data limits are known and that the global
2518#       transfer-functions slider values have been set up.  Both parts are
2519#       needed to compute the relative value (location) of the marker, and
2520#       the alpha map of the transfer function.
2521#
2522itcl::body Rappture::VtkVolumeViewer::ComputeTransferFunction { cname } {
2523
2524    if { ![info exists _transferFunctionEditors($cname)] } {
2525        set _transferFunctionEditors($cname) \
2526            [Rappture::TransferFunctionEditor ::\#auto $itk_component(legend) \
2527                 $cname \
2528                 -command [itcl::code $this updateTransferFunctions]]
2529    }
2530
2531    # We have to parse the style attributes for a volume using this
2532    # transfer-function *once*.  This sets up the initial isomarkers for the
2533    # transfer function.  The user may add/delete markers, so we have to
2534    # maintain a list of markers for each transfer-function.  We use the one
2535    # of the volumes (the first in the list) using the transfer-function as a
2536    # reference.
2537
2538    if { ![info exists _parsedFunction($cname)] || ![info exists _cname2transferFunction($cname)] } {
2539        array set style {
2540            -color BCGYR
2541            -levels 6
2542            -opacity 1.0
2543            -markers ""
2544        }
2545
2546        # Accumulate the style from all the datasets using it.
2547        foreach tag [GetDatasetsWithComponent $cname] {
2548            foreach {dataobj cname} [split [lindex $tag 0] -] break
2549            array set style [lindex [$dataobj components -style $cname] 0]
2550        }
2551        set cmap [ColorsToColormap $style(-color)]
2552        set _cname2defaultcolormap($cname) $cmap
2553        set _settings($cname-colormap) $style(-color)
2554        if { [info exists _transferFunctionEditors($cname)] } {
2555            eval $_transferFunctionEditors($cname) limits $_limits($cname)
2556        }
2557        if { [info exists style(-markers)] &&
2558             [llength $style(-markers)] > 0 } {
2559            ParseMarkersOption $cname $style(-markers)
2560        } else {
2561            ParseLevelsOption $cname $style(-levels)
2562        }
2563    } else {
2564        foreach {cmap amap} $_cname2transferFunction($cname) break
2565    }
2566
2567    set amap [ComputeAlphamap $cname]
2568    set opaqueAmap "0.0 1.0 1.0 1.0"
2569    set _cname2transferFunction($cname) [list $cmap $amap]
2570    SendCmd [list colormap add $cname $cmap $amap]
2571    SendCmd [list colormap add $cname-opaque $cmap $opaqueAmap]
2572}
2573
2574#
2575# ResetColormap --
2576#
2577#       Changes only the colormap portion of the transfer function.
2578#
2579itcl::body Rappture::VtkVolumeViewer::ResetColormap { cname color } {
2580    # Get the current transfer function
2581    if { ![info exists _cname2transferFunction($cname)] } {
2582        return
2583    }
2584    foreach { cmap amap } $_cname2transferFunction($cname) break
2585    set cmap [GetColormap $cname $color]
2586    set _cname2transferFunction($cname) [list $cmap $amap]
2587    set opaqueAmap "0.0 1.0 1.0 1.0"
2588    SendCmd [list colormap add $cname $cmap $amap]
2589    SendCmd [list colormap add $cname-opaque $cmap $opaqueAmap]
2590    EventuallyRequestLegend
2591}
2592
2593# ----------------------------------------------------------------------
2594# USAGE: updateTransferFunctions
2595#
2596#       This is called by the transfer function editor whenever the
2597#       transfer function definition changes.
2598#
2599# ----------------------------------------------------------------------
2600itcl::body Rappture::VtkVolumeViewer::updateTransferFunctions {} {
2601    foreach cname [array names _volcomponents] {
2602        ComputeTransferFunction $cname
2603    }
2604    EventuallyRequestLegend
2605}
2606
2607itcl::body Rappture::VtkVolumeViewer::SetOrientation { side } {
2608    array set positions {
2609        front "1 0 0 0"
2610        back  "0 0 1 0"
2611        left  "0.707107 0 -0.707107 0"
2612        right "0.707107 0 0.707107 0"
2613        top   "0.707107 -0.707107 0 0"
2614        bottom "0.707107 0.707107 0 0"
2615    }
2616    foreach name { qw qx qy qz } value $positions($side) {
2617        set _view($name) $value
2618    }
2619    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
2620    $_arcball quaternion $q
2621    SendCmd "camera orient $q"
2622    SendCmd "camera reset"
2623    set _view(xpan) 0
2624    set _view(ypan) 0
2625    set _view(zoom) 1.0
2626    set _settings($this-xpan) $_view(xpan)
2627    set _settings($this-ypan) $_view(ypan)
2628    set _settings($this-zoom) $_view(zoom)
2629}
2630
2631#
2632# InitComponentSettings --
2633#
2634#       Initializes the volume settings for a specific component. This
2635#       should match what's used as global settings above. This
2636#       is called the first time we try to switch to a given component
2637#       in SwitchComponent below.
2638#
2639itcl::body Rappture::VtkVolumeViewer::InitComponentSettings { cname } {
2640    array set _settings [subst {
2641        $cname-ambient           60
2642        $cname-colormap          default
2643        $cname-diffuse           40
2644        $cname-light2side        1
2645        $cname-opacity           100
2646        $cname-outline           0
2647        $cname-specularExponent  90
2648        $cname-specularLevel     30
2649        $cname-thickness         350
2650        $cname-transp            50
2651        $cname-volumeVisible     1
2652    }]
2653}
2654
2655#
2656# SwitchComponent --
2657#
2658#       This is called when the current component is changed by the
2659#       dropdown menu in the volume tab.  It synchronizes the global
2660#       volume settings with the settings of the new current component.
2661#
2662itcl::body Rappture::VtkVolumeViewer::SwitchComponent { cname } {
2663    if { ![info exists _settings($cname-ambient)] } {
2664        InitComponentSettings $cname
2665    }
2666    # _settings variables change widgets, except for colormap
2667    set _settings($this-ambient)          $_settings($cname-ambient)
2668    set _settings($this-colormap)         $_settings($cname-colormap)
2669    set _settings($this-diffuse)          $_settings($cname-diffuse)
2670    set _settings($this-light2side)       $_settings($cname-light2side)
2671    set _settings($this-opacity)          $_settings($cname-opacity)
2672    set _settings($this-outline)          $_settings($cname-outline)
2673    set _settings($this-specularExponent) $_settings($cname-specularExponent)
2674    set _settings($this-specularLevel)    $_settings($cname-specularLevel)
2675    set _settings($this-thickness)        $_settings($cname-thickness)
2676    set _settings($this-transp)           $_settings($cname-transp)
2677    set _settings($this-volumeVisible)    $_settings($cname-volumeVisible)
2678    $itk_component(colormap) value        $_settings($cname-colormap)
2679    set _current $cname;                # Reset the current component
2680}
2681
2682itcl::body Rappture::VtkVolumeViewer::ComputeAlphamap { cname } {
2683    if { ![info exists _transferFunctionEditors($cname)] } {
2684        return [list 0.0 0.0 1.0 1.0]
2685    }
2686    if { ![info exists _settings($cname-ambient)] } {
2687        InitComponentSettings $cname
2688    }
2689    set max 1.0 ;                       #$_settings($tag-opacity)
2690
2691    set isovalues [$_transferFunctionEditors($cname) values]
2692
2693    # Ensure that the global opacity and thickness settings (in the slider
2694    # settings widgets) are used for the active transfer-function.  Update
2695    # the values in the _settings varible.
2696    set opacity [expr { double($_settings($cname-opacity)) * 0.01 }]
2697
2698    # Scale values between 0.00001 and 0.01000
2699    set delta [expr {double($_settings($cname-thickness)) * 0.0001}]
2700   
2701    set first [lindex $isovalues 0]
2702    set last [lindex $isovalues end]
2703    set amap ""
2704    if { $first == "" || $first != 0.0 } {
2705        lappend amap 0.0 0.0
2706    }
2707    foreach x $isovalues {
2708        set x1 [expr {$x-$delta-0.00001}]
2709        set x2 [expr {$x-$delta}]
2710        set x3 [expr {$x+$delta}]
2711        set x4 [expr {$x+$delta+0.00001}]
2712        if { $x1 < 0.0 } {
2713            set x1 0.0
2714        } elseif { $x1 > 1.0 } {
2715            set x1 1.0
2716        }
2717        if { $x2 < 0.0 } {
2718            set x2 0.0
2719        } elseif { $x2 > 1.0 } {
2720            set x2 1.0
2721        }
2722        if { $x3 < 0.0 } {
2723            set x3 0.0
2724        } elseif { $x3 > 1.0 } {
2725            set x3 1.0
2726        }
2727        if { $x4 < 0.0 } {
2728            set x4 0.0
2729        } elseif { $x4 > 1.0 } {
2730            set x4 1.0
2731        }
2732        # add spikes in the middle
2733        lappend amap $x1 0.0
2734        lappend amap $x2 $max
2735        lappend amap $x3 $max
2736        lappend amap $x4 0.0
2737    }
2738    if { $last == "" || $last != 1.0 } {
2739        lappend amap 1.0 0.0
2740    }
2741    return $amap
2742}
2743
2744#
2745# HideAllMarkers --
2746#
2747#       Hide all the markers in all the transfer functions.  Can't simply
2748#       delete and recreate markers from the <style> since the user may
2749#       have create, deleted, or moved markers.
2750#
2751itcl::body Rappture::VtkVolumeViewer::HideAllMarkers {} {
2752    foreach cname [array names _transferFunctionEditors] {
2753        $_transferFunctionEditors($cname) hideMarkers
2754    }
2755}
2756
2757
2758#
2759# GetDatasetsWithComponents --
2760#
2761#       Returns a list of all the datasets (known by the combination of
2762#       their data object and component name) that match the given
2763#       component name.  For example, this is used where we want to change
2764#       the settings of volumes that have the current component.
2765#
2766itcl::body Rappture::VtkVolumeViewer::GetDatasetsWithComponent { cname } {
2767    if { ![info exists _volcomponents($cname)] } {
2768        return ""
2769    }
2770    return $_volcomponents($cname)
2771}
2772
2773#
2774# BuildVolumeComponents --
2775#
2776#       This is called from the "scale" method which is called when a
2777#       new dataset is added or deleted.  It repopulates the dropdown
2778#       menu of volume component names.  It sets the current component
2779#       to the first component in the list (of components found).
2780#       Finally, if there is only one component, don't display the
2781#       label or the combobox in the volume settings tab.
2782#
2783itcl::body Rappture::VtkVolumeViewer::BuildVolumeComponents {} {
2784    $itk_component(volcomponents) choices delete 0 end
2785    foreach name $_componentsList {
2786        $itk_component(volcomponents) choices insert end $name $name
2787    }
2788    set _current [lindex $_componentsList 0]
2789    $itk_component(volcomponents) value $_current
2790    set parent [winfo parent $itk_component(volcomponents)]
2791    if { [llength $_componentsList] <= 1 } {
2792        # Unpack the components label and dropdown if there's only one
2793        # component.
2794        blt::table forget $parent.volcomponents_l $parent.volcomponents
2795    } else {
2796        # Pack the components label and dropdown into the table there's
2797        # more than one component to select.
2798        blt::table $parent \
2799            0,0 $parent.volcomponents_l -anchor e -cspan 2 \
2800            0,2 $parent.volcomponents -cspan 3 -fill x
2801    }
2802}
2803
2804itcl::body Rappture::VtkVolumeViewer::GetColormap { cname color } {
2805    if { $color == "default" } {
2806        return $_cname2defaultcolormap($cname)
2807    }
2808    return [ColorsToColormap $color]
2809}
Note: See TracBrowser for help on using the repository browser.