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

Last change on this file since 4046 was 4046, checked in by ldelgass, 11 years ago

Fix errors in vtkvolume viewer

File size: 97.3 KB
RevLine 
[3330]1# -*- mode: tcl; indent-tabs-mode: nil -*-
[2718]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
[3177]10#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
[2718]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}
[3967]64    public method updateTransferFunctions {}
[2718]65
[3986]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 }
[3967]71    private method HideAllMarkers {}
72    private method InitComponentSettings { cname }
73    private method ParseLevelsOption { cname levels }
74    private method ParseMarkersOption { cname markers }
[3986]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 }
[3975]80
[3967]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
[2718]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.
[3967]109
[2718]110    private method BuildAxisTab {}
111    private method BuildCameraTab {}
112    private method BuildCutplaneTab {}
113    private method BuildDownloadPopup { widget command }
114    private method BuildVolumeTab {}
[3441]115    private method DrawLegend {}
[3967]116    private method DrawLegendOld {}
[2718]117    private method Combo { option }
118    private method EnterLegend { x y }
119    private method EventuallyResize { w h }
[3967]120    private method EventuallyRequestLegend {}
[2718]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 ""
[2744]135    private variable _dlist ""     ;    # list of data objects
[2718]136    private variable _obj2datasets
[2744]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.
[2718]142    private variable _dataset2style    ;# maps dataobj-component to transfunc
143
[2744]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
[2718]147    private variable _settings
[2744]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.
[2718]152
[2744]153    private variable _first ""     ;    # This is the topmost dataset.
[2718]154    private variable _start 0
155    private variable _title ""
156    private variable _seeds
157
[2744]158    common _downloadPopup;              # download options from popup
[2718]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
[3441]167    private variable _curFldName ""
168    private variable _curFldLabel ""
[3963]169    private variable _colorMode "scalar";#  Mode of colormap (vmag or scalar)
[2718]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} {
[2792]181    package require vtk
[2718]182    set _serverType "vtkvis"
183
[3967]184    EnableWaitDialog 900
185
[2718]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 \
[3984]205        "[itcl::code $this AdjustSetting cutplanePositionX]; list"
[2718]206
207    # Y-Cutplane event
208    $_dispatcher register !ycutplane
209    $_dispatcher dispatch $this !ycutplane \
[3984]210        "[itcl::code $this AdjustSetting cutplanePositionY]; list"
[2718]211
212    # Z-Cutplane event
213    $_dispatcher register !zcutplane
214    $_dispatcher dispatch $this !zcutplane \
[3984]215        "[itcl::code $this AdjustSetting cutplanePositionZ]; list"
[2718]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 {
[3123]226        qw              0.853553
227        qx              -0.353553
228        qy              0.353553
229        qz              0.146447
[2744]230        zoom            1.0
231        xpan            0
232        ypan            0
233        ortho           0
[2718]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
[3441]239    array set _settings {
240        axesVisible             1
[3984]241        axisGridX               0
242        axisGridY               0
243        axisGridZ               0
[3441]244        axisLabels              1
245        cutplaneEdges           0
[3984]246        cutplaneLighting        1
247        cutplaneOpacity         100
[3986]248        cutplanePositionX       50
249        cutplanePositionY       50
250        cutplanePositionZ       50
[3896]251        cutplaneVisible         0
[3984]252        cutplaneVisibleX        1
253        cutplaneVisibleY        1
254        cutplaneVisibleZ        1
[3441]255        cutplaneWireframe       0
[3984]256        legendVisible           1
257        volumeAmbient           40
258        volumeBlendMode         composite
259        volumeDiffuse           60
[3441]260        volumeLighting          1
[3984]261        volumeOpacity           50
262        volumeQuality           50
263        volumeSpecularExponent  90
264        volumeSpecularLevel     30
265        volumeThickness         350
[3441]266        volumeVisible           1
267    }
[2718]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 \
[2744]279            -tearoff no
[2718]280    } {
[2744]281        usual
282        ignore -background -foreground -relief -tearoff
[2718]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"
[3330]293    bind $c <Control-F1> [itcl::code $this ToggleConsole]
[2718]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] \
[3441]345            -variable [itcl::scope _settings(volumeVisible)] \
346            -command [itcl::code $this AdjustSetting volumeVisible]
[2718]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] \
[3441]357            -variable [itcl::scope _settings(cutplaneVisible)] \
358            -command [itcl::code $this AdjustSetting cutplaneVisible]
[2718]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 {
[2744]366        BuildVolumeTab
367        BuildCutplaneTab
368        BuildAxisTab
369        BuildCameraTab
[2718]370    } errs] != 0 } {
[2744]371        puts stderr errs=$errs
[2718]372    }
373    # Legend
374
375    set _image(legend) [image create photo]
376    itk_component add legend {
[3967]377        canvas $itk_component(plotarea).legend -height 50 -highlightthickness 0
[2718]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) \
[3967]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
[2718]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
[3443]416    #bind $itk_component(view) <ButtonRelease-3> \
417    #    [itcl::code $this Pick %x %y]
[2718]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 } {
[2744]469        set _width 500
[2718]470    }
471    if { $_height < 2 } {
[2744]472        set _height 500
[2718]473    }
474    set _start [clock clicks -milliseconds]
475    SendCmd "screen size $_width $_height"
[3438]476
[3967]477    EventuallyRequestLegend
[2718]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
[3967]497itcl::body Rappture::VtkVolumeViewer::EventuallyRequestLegend {} {
498    if { !$_legendPending } {
499        set _legendPending 1
500        $_dispatcher event -after 600 !legend
[2718]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
[2744]510        global rotate_delay
[2718]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 ""}} {
[3974]530    if { ![IsValidObject $dataobj] } {
531        return;                         # Ignore invalid objects.
532    }
[2718]533    array set params {
534        -color auto
535        -width 1
536        -linestyle solid
537        -brightness 0
538        -raise 0
539        -description ""
540        -param ""
[2744]541        -type ""
[2718]542    }
543    array set params $settings
544    set params(-description) ""
545    set params(-param) ""
[3799]546    array set params $settings
547
[2718]548    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
549        # can't handle -autocolors yet
550        set params(-color) black
551    }
[3813]552    set pos [lsearch -exact $_dlist $dataobj]
[2718]553    if {$pos < 0} {
[2744]554        lappend _dlist $dataobj
[2718]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]
[2744]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
[2718]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 {
[2744]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        }
[2718]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} {
[3967]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
[3974]683
[2718]684    foreach dataobj $args {
[3967]685        if { ![$dataobj isvalid] } {
686            continue;                     # Object doesn't contain valid data.
687        }
[3974]688        # Determine limits for each axis.
[3967]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        }
[3974]706        # Determine limits for each field.
[3441]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]
[2744]721        }
[3974]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)] } {
[4046]732                set _limits($cname) [list $min $max]
[3974]733            } else {
[4046]734                foreach {vmin vmax} $_limits($cname) break
735                if { $min < $vmin } {
[3974]736                    set vmin $min
737                }
[4046]738                if { $max > $vmax } {
[3974]739                    set vmax $max
740                }
[4046]741                set _limits($cname) [list $vmin $vmax]
[3974]742            }
743        }
[2718]744    }
[3974]745    BuildVolumeComponents
746    updateTransferFunctions
[2718]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:"
[2744]781            update idletasks            ;# Fix initial sizes
[2718]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 } {
[3592]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
[2718]840        set w [winfo width $itk_component(view)]
841        set h [winfo height $itk_component(view)]
842        EventuallyResize $w $h
843    }
[3984]844    $_dispatcher event -idle !rebuild
[2718]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
[3984]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
[2718]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" } {
[2744]917        if 0 {
918            set f [open "last.ppm" "w"]
919            puts $f $bytes
920            close $f
921        }
[2718]922        $_image(plot) configure -data $bytes
[2744]923        set time [clock seconds]
924        set date [clock format $time]
[2718]925        #puts stderr "$date: received image [image width $_image(plot)]x[image height $_image(plot)] image>"       
[2744]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        }
[2718]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 {
[2744]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" {
[2718]969            foreach { name } [lindex $args 1] {
970                #puts stderr "Dataset: $name"
971            }
[2744]972        }
973        default {
974            error "unknown dataset option \"$option\" from server"
975        }
[2718]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 } {
[2744]991        $_dispatcher event -idle !rebuild
992        return
[2718]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).   
[3421]998    StartBufferingCommands
999
[3392]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
[3984]1018        InitSettings axisGridX axisGridY axisGridZ axisFlyMode \
[3441]1019            axesVisible axisLabels
[3392]1020        PanCamera
[2718]1021    }
1022    set _first ""
1023
1024    SendCmd "imgflush"
1025    set _first ""
[2727]1026
[3814]1027    SendCmd "dataset visible 0"
[2718]1028    foreach dataobj [get -objects] {
[2744]1029        if { [info exists _obj2ovride($dataobj-raise)] &&  $_first == "" } {
1030            set _first $dataobj
1031        }
1032        set _obj2datasets($dataobj) ""
[2718]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]
[3421]1038                if { $_reportClientInfo }  {
[3392]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
[3394]1046                    lappend info "dataset_tag"   $tag
[3392]1047                    SendCmd [list "clientinfo" $info]
1048                }
[2718]1049                append _outbuf "dataset add $tag data follows $length\n"
1050                append _outbuf $bytes
1051                set _datasets($tag) 1
[2744]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
[2718]1059        }
1060    }
1061    if {"" != $_first} {
1062        set location [$_first hints camera]
1063        if { $location != "" } {
1064            array set view $location
1065        }
1066
[2744]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        }
[3441]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
[3896]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                    }
[3441]1103                }
1104            }
[2744]1105        }
[3441]1106        $itk_component(field) value $_curFldLabel
[2718]1107    }
1108
[3967]1109    InitSettings volumeColormap \
[3984]1110        volumeAmbient volumeDiffuse volumeSpecularLevel volumeSpecularExponent \
1111        volumeOpacity volumeQuality volumeVisible \
[3441]1112        cutplaneVisible \
[3984]1113        cutplanePositionX cutplanePositionY cutplanePositionZ \
1114        cutplaneVisibleX cutplaneVisibleY cutplaneVisibleZ
[2718]1115
1116    if { $_reset } {
[3441]1117        InitSettings volumeLighting
[3984]1118        SendCmd "camera reset"
1119        SendCmd "camera zoom $_view(zoom)"
[2744]1120        set _reset 0
[2718]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)
[3421]1125    StopBufferingCommands
[2718]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 {
[2744]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        }
[2718]1161    }
1162    set rlist ""
1163    foreach dataobj $dlist {
[2744]1164        foreach comp [$dataobj components] {
1165            set tag $dataobj-$comp
1166            if { [info exists _datasets($tag)] && $_datasets($tag) } {
1167                lappend rlist $tag
1168            }
1169        }
[2718]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}]
[2744]1186            SendCmd "camera zoom $_view(zoom)"
[2718]1187        }
1188        "out" {
1189            set _view(zoom) [expr {$_view(zoom)*0.8}]
[2744]1190            SendCmd "camera zoom $_view(zoom)"
[2718]1191        }
1192        "reset" {
1193            array set _view {
[3123]1194                qw      0.853553
1195                qx      -0.353553
1196                qy      0.353553
1197                qz      0.146447
[2718]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            }
[2744]1208            set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1209            $_arcball quaternion $q
1210            DoRotate
[3551]1211            SendCmd "camera reset"
[2718]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                }
[2744]1255                if { $dx == 0 && $dy == 0 } {
1256                    return
1257                }
1258                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1259                EventuallyRotate $q
[2718]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 {
[2744]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        }
[2718]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 {
[2744]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
[2718]1347    }
1348}
1349
1350#
1351# AdjustSetting --
1352#
[2744]1353#       Changes/updates a specific setting in the widget.  There are
1354#       usually user-setable option.  Commands are sent to the render
1355#       server.
[2718]1356#
1357itcl::body Rappture::VtkVolumeViewer::AdjustSetting {what {value ""}} {
1358    if { ![isconnected] } {
[3984]1359        if { $_reset } {
1360            # Just reconnect if we've been reset.
1361            Connect
1362        }
[2744]1363        return
[2718]1364    }
1365    switch -- $what {
[3441]1366        "volumeVisible" {
1367            set bool $_settings(volumeVisible)
[4046]1368            set _settings($_current-volumeVisible) $bool
[3986]1369            foreach tag [GetDatasetsWithComponent $_current] {
1370                SendCmd "volume visible $bool $tag"
[2718]1371            }
[2744]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            }
[2718]1379        }
[3984]1380        "volumeBlendMode" {
[3963]1381            set val [$itk_component(blendmode) value]
1382            set mode [$itk_component(blendmode) translate $val]
[3984]1383            set _settings(volumeBlendMode) $mode
[3988]1384            set _settings($_current-volumeBlendMode) $mode
[3986]1385            foreach tag [GetDatasetsWithComponent $_current] {
1386                SendCmd "volume blendmode $mode $tag"
[3963]1387            }
1388        }
[3967]1389        "volumeAmbient" {
1390            set val $_settings(volumeAmbient)
[3990]1391            set _settings($_current-volumeAmbient) $val
[3963]1392            set ambient [expr {0.01*$val}]
[3986]1393            foreach tag [GetDatasetsWithComponent $_current] {
1394                SendCmd "volume shading ambient $ambient $tag"
[3963]1395            }
1396        }
[3967]1397        "volumeDiffuse" {
1398            set val $_settings(volumeDiffuse)
[3988]1399            set _settings($_current-volumeDiffuse) $val
[2758]1400            set diffuse [expr {0.01*$val}]
[3986]1401            foreach tag [GetDatasetsWithComponent $_current] {
1402                SendCmd "volume shading diffuse $diffuse $tag"
[2758]1403            }
1404        }
[3984]1405        "volumeSpecularLevel" - "volumeSpecularExponent" {
1406            set val $_settings(volumeSpecularLevel)
[3990]1407            set _settings($_current-volumeSpecularLevel) $val
[3986]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"
[3963]1412            }
1413        }
[3441]1414        "volumeLighting" {
1415            set bool $_settings(volumeLighting)
[3988]1416            set _settings($_current-volumeLighting) $bool
[3986]1417            foreach tag [GetDatasetsWithComponent $_current] {
1418                SendCmd "volume lighting $bool $tag"
[2718]1419            }
1420        }
[3984]1421        "volumeOpacity" {
1422            set val $_settings(volumeOpacity)
[3988]1423            set _settings($_current-volumeOpacity) $val
[3963]1424            set val [expr {0.01*$val}]
[3986]1425            foreach tag [GetDatasetsWithComponent $_current] {
1426                SendCmd "volume opacity $val $tag"
[3963]1427            }
1428        }
[3984]1429        "volumeQuality" {
1430            set val $_settings(volumeQuality)
[3988]1431            set _settings($_current-volumeQuality) $val
[2758]1432            set val [expr {0.01*$val}]
[3986]1433            foreach tag [GetDatasetsWithComponent $_current] {
1434                SendCmd "volume quality $val $tag"
[2758]1435            }
1436        }
[3441]1437        "axesVisible" {
1438            set bool $_settings(axesVisible)
[2744]1439            SendCmd "axis visible all $bool"
[2718]1440        }
[3441]1441        "axisLabels" {
1442            set bool $_settings(axisLabels)
[2744]1443            SendCmd "axis labels all $bool"
[2718]1444        }
[3984]1445        "axisGridX" - "axisGridY" - "axisGridZ" {
1446            set axis [string tolower [string range $what end end]]
[2744]1447            set bool $_settings($what)
1448            SendCmd "axis grid $axis $bool"
[2718]1449        }
[3441]1450        "axisFlyMode" {
[2744]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"
[2718]1455        }
[3441]1456        "cutplaneEdges" {
[2744]1457            set bool $_settings($what)
1458            foreach dataset [CurrentDatasets -visible] {
1459                SendCmd "cutplane edges $bool $dataset"
[2718]1460            }
1461        }
[3441]1462        "cutplaneVisible" {
[2744]1463            set bool $_settings($what)
1464            foreach dataset [CurrentDatasets -visible] {
1465                SendCmd "cutplane visible $bool $dataset"
[2718]1466            }
1467        }
[3441]1468        "cutplaneWireframe" {
[2744]1469            set bool $_settings($what)
1470            foreach dataset [CurrentDatasets -visible] {
1471                SendCmd "cutplane wireframe $bool $dataset"
[2718]1472            }
1473        }
[3441]1474        "cutplaneLighting" {
[2744]1475            set bool $_settings($what)
1476            foreach dataset [CurrentDatasets -visible] {
1477                SendCmd "cutplane lighting $bool $dataset"
[2718]1478            }
1479        }
[3984]1480        "cutplaneOpacity" {
[2744]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            }
[2718]1486        }
[3984]1487        "cutplaneVisibleX" - "cutplaneVisibleY" - "cutplaneVisibleZ" {
1488            set axis [string tolower [string range $what end end]]
[2744]1489            set bool $_settings($what)
[2718]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            }
[2755]1497            foreach dataset [CurrentDatasets -visible] {
1498                SendCmd "cutplane axis $axis $bool $dataset"
1499            }
[2744]1500        }
[3984]1501        "cutplanePositionX" - "cutplanePositionY" - "cutplanePositionZ" {
1502            set axis [string tolower [string range $what end end]]
[2744]1503            set pos [expr $_settings($what) * 0.01]
[2755]1504            foreach dataset [CurrentDatasets -visible] {
1505                SendCmd "cutplane slice ${axis} ${pos} $dataset"
1506            }
[2744]1507            set _cutplanePending 0
1508        }
[3967]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
[2744]1519            set _legendPending 1
[2718]1520        }
[3441]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 } {
[3896]1528                    puts stderr "Can't use a vector field in a volume"
1529                    return
[3441]1530                } else {
1531                    set _colorMode scalar
1532                }
1533                set _curFldName $fname
1534                set _curFldLabel $label
[2744]1535            } else {
[3441]1536                puts stderr "unknown field \"$fname\""
[2744]1537                return
[2718]1538            }
[3896]1539            foreach dataset [CurrentDatasets -visible $_first] {
1540                #SendCmd "volume colormode $_colorMode ${fname} $dataset"
1541                SendCmd "cutplane colormode $_colorMode ${fname} $dataset"
1542            }
[3441]1543            SendCmd "camera reset"
1544            DrawLegend
[2718]1545        }
1546        default {
1547            error "don't know how to fix $what"
1548        }
1549    }
1550}
1551
1552#
1553# RequestLegend --
1554#
[2744]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.
[2718]1558#
1559itcl::body Rappture::VtkVolumeViewer::RequestLegend {} {
1560    set font "Arial 8"
[3967]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}]
[3969]1566    set w [expr {$w-20}]
[2718]1567    # Set the legend on the first volume dataset.
1568    foreach dataset [CurrentDatasets -visible $_first] {
[2744]1569        foreach {dataobj comp} [split $dataset -] break
1570        if { [info exists _dataset2style($dataset)] } {
[2718]1571            SendCmdNoWait \
[3441]1572                "legend $_dataset2style($dataset) $_colorMode $_curFldName {} $w $h 0"
[2744]1573            break;
[2718]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 {} {
[3963]1600    set font [option get $itk_component(hull) font Font]
1601    #set bfont [option get $itk_component(hull) boldFont Font]
[2718]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
[3967]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
[3963]1616    checkbutton $inner.visibility \
1617        -text "Visible" \
1618        -font $font \
[3441]1619        -variable [itcl::scope _settings(volumeVisible)] \
[3963]1620        -command [itcl::code $this AdjustSetting volumeVisible]
[2718]1621
[3963]1622    label $inner.lighting_l \
1623        -text "Lighting / Material Properties" \
1624        -font "Arial 9 bold"
1625
[2718]1626    checkbutton $inner.lighting \
1627        -text "Enable Lighting" \
[3963]1628        -font $font \
[3441]1629        -variable [itcl::scope _settings(volumeLighting)] \
[3963]1630        -command [itcl::code $this AdjustSetting volumeLighting]
[2718]1631
[3963]1632    label $inner.ambient_l \
1633        -text "Ambient" \
1634        -font $font
1635    ::scale $inner.ambient -from 0 -to 100 -orient horizontal \
[3967]1636        -variable [itcl::scope _settings(volumeAmbient)] \
1637        -showvalue off -command [itcl::code $this AdjustSetting volumeAmbient] \
[3963]1638        -troughcolor grey92
[2758]1639
[3963]1640    label $inner.diffuse_l -text "Diffuse" -font $font
1641    ::scale $inner.diffuse -from 0 -to 100 -orient horizontal \
[3967]1642        -variable [itcl::scope _settings(volumeDiffuse)] \
1643        -showvalue off -command [itcl::code $this AdjustSetting volumeDiffuse] \
[3963]1644        -troughcolor grey92
1645
1646    label $inner.specularLevel_l -text "Specular" -font $font
1647    ::scale $inner.specularLevel -from 0 -to 100 -orient horizontal \
[3984]1648        -variable [itcl::scope _settings(volumeSpecularLevel)] \
1649        -showvalue off -command [itcl::code $this AdjustSetting volumeSpecularLevel] \
[3963]1650        -troughcolor grey92
1651
1652    label $inner.specularExponent_l -text "Shininess" -font $font
1653    ::scale $inner.specularExponent -from 10 -to 128 -orient horizontal \
[3984]1654        -variable [itcl::scope _settings(volumeSpecularExponent)] \
1655        -showvalue off -command [itcl::code $this AdjustSetting volumeSpecularExponent] \
[3963]1656        -troughcolor grey92
1657
1658    label $inner.opacity_l -text "Opacity" -font $font
[2718]1659    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
[3984]1660        -variable [itcl::scope _settings(volumeOpacity)] \
1661        -showvalue off -command [itcl::code $this AdjustSetting volumeOpacity] \
[3963]1662        -troughcolor grey92
[2718]1663
[3963]1664    label $inner.quality_l -text "Quality" -font $font
[2758]1665    ::scale $inner.quality -from 0 -to 100 -orient horizontal \
[3984]1666        -variable [itcl::scope _settings(volumeQuality)] \
1667        -showvalue off -command [itcl::code $this AdjustSetting volumeQuality] \
[3963]1668        -troughcolor grey92
[2758]1669
[3963]1670    label $inner.field_l -text "Field" -font $font
[2718]1671    itk_component add field {
[3963]1672        Rappture::Combobox $inner.field -editable no
[2718]1673    }
1674    bind $inner.field <<Value>> \
[3441]1675        [itcl::code $this AdjustSetting field]
[2718]1676
[3963]1677    label $inner.transferfunction_l \
1678        -text "Transfer Function" -font "Arial 9 bold"
1679
[3967]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
[2718]1692    }
[3967]1693    $inner.colormap choices insert end \
[2744]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"   
[2718]1710
[3967]1711    $itk_component(colormap) value "BCGYR"
1712    bind $inner.colormap <<Value>> \
1713        [itcl::code $this AdjustSetting volumeColormap]
[2718]1714
[3969]1715    label $inner.blendmode_l -text "Blend Mode" -font $font
[3963]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>> \
[3984]1726        [itcl::code $this AdjustSetting volumeBlendMode]
[3963]1727
[2718]1728    blt::table $inner \
[3967]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 \
[3969]1733        2,0 $inner.lighting_l -anchor w -cspan 4 \
[3967]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 \
[3969]1746        10,0 $inner.transferfunction_l -anchor w              -cspan 4 \
[3967]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 
[2718]1756
1757    blt::table configure $inner r* c* -resize none
[3963]1758    blt::table configure $inner r* -pady { 2 0 }
[3967]1759    blt::table configure $inner c2 c3 r15 -resize expand
[3963]1760    blt::table configure $inner c0 -width .1i
[2718]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" \
[3441]1775        -variable [itcl::scope _settings(axesVisible)] \
1776        -command [itcl::code $this AdjustSetting axesVisible] \
[2718]1777        -font "Arial 9"
1778
1779    checkbutton $inner.labels \
1780        -text "Show Axis Labels" \
[3441]1781        -variable [itcl::scope _settings(axisLabels)] \
1782        -command [itcl::code $this AdjustSetting axisLabels] \
[2718]1783        -font "Arial 9"
1784
1785    checkbutton $inner.gridx \
1786        -text "Show X Grid" \
[3984]1787        -variable [itcl::scope _settings(axisGridX)] \
1788        -command [itcl::code $this AdjustSetting axisGridX] \
[2718]1789        -font "Arial 9"
1790    checkbutton $inner.gridy \
1791        -text "Show Y Grid" \
[3984]1792        -variable [itcl::scope _settings(axisGridY)] \
1793        -command [itcl::code $this AdjustSetting axisGridY] \
[2718]1794        -font "Arial 9"
1795    checkbutton $inner.gridz \
1796        -text "Show Z Grid" \
[3984]1797        -variable [itcl::scope _settings(axisGridZ)] \
1798        -command [itcl::code $this AdjustSetting axisGridZ] \
[2718]1799        -font "Arial 9"
1800
1801    label $inner.mode_l -text "Mode" -font "Arial 9"
1802
1803    itk_component add axismode {
[2744]1804        Rappture::Combobox $inner.mode -width 10 -editable no
[2718]1805    }
1806    $inner.mode choices insert end \
1807        "static_triad"    "static" \
1808        "closest_triad"   "closest" \
[3923]1809        "furthest_triad"  "farthest" \
[2718]1810        "outer_edges"     "outer"         
1811    $itk_component(axismode) value "static"
[3441]1812    bind $inner.mode <<Value>> [itcl::code $this AdjustSetting axisFlyMode]
[2718]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
[3969]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
[2718]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 \
[3441]1867            $row,0 $inner.ortho -cspan 2 -anchor w -pady 2
[2718]1868    blt::table configure $inner r$row -resize none
1869    incr row
1870
[3969]1871    blt::table configure $inner r* c0 c1 -resize none
[2718]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" \
[2744]1882        -icon [Rappture::icon cutbutton]]
[2718]1883
1884    $inner configure -borderwidth 4
1885
1886    checkbutton $inner.visible \
1887        -text "Show Cutplanes" \
[3441]1888        -variable [itcl::scope _settings(cutplaneVisible)] \
1889        -command [itcl::code $this AdjustSetting cutplaneVisible] \
[2718]1890        -font "Arial 9"
1891
1892    checkbutton $inner.wireframe \
1893        -text "Show Wireframe" \
[3441]1894        -variable [itcl::scope _settings(cutplaneWireframe)] \
1895        -command [itcl::code $this AdjustSetting cutplaneWireframe] \
[2718]1896        -font "Arial 9"
1897
1898    checkbutton $inner.lighting \
1899        -text "Enable Lighting" \
[3441]1900        -variable [itcl::scope _settings(cutplaneLighting)] \
1901        -command [itcl::code $this AdjustSetting cutplaneLighting] \
[2718]1902        -font "Arial 9"
1903
1904    checkbutton $inner.edges \
1905        -text "Show Edges" \
[3441]1906        -variable [itcl::scope _settings(cutplaneEdges)] \
1907        -command [itcl::code $this AdjustSetting cutplaneEdges] \
[2718]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 \
[3984]1912        -variable [itcl::scope _settings(cutplaneOpacity)] \
[2718]1913        -width 10 \
1914        -showvalue off \
[3984]1915        -command [itcl::code $this AdjustSetting cutplaneOpacity]
1916    $inner.opacity set $_settings(cutplaneOpacity)
[2718]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] \
[3984]1923            -command [itcl::code $this AdjustSetting cutplaneVisibleX] \
1924            -variable [itcl::scope _settings(cutplaneVisibleX)]
[2718]1925    }
1926    Rappture::Tooltip::for $itk_component(xCutButton) \
1927        "Toggle the X-axis cutplane on/off"
[3896]1928    $itk_component(xCutButton) select
[2718]1929
1930    itk_component add xCutScale {
[3330]1931        ::scale $inner.xval -from 100 -to 0 \
[2718]1932            -width 10 -orient vertical -showvalue yes \
1933            -borderwidth 1 -highlightthickness 0 \
1934            -command [itcl::code $this EventuallySetCutplane x] \
[3984]1935            -variable [itcl::scope _settings(cutplanePositionX)]
[2718]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] \
[3984]1951            -command [itcl::code $this AdjustSetting cutplaneVisibleY] \
1952            -variable [itcl::scope _settings(cutplaneVisibleY)]
[2718]1953    }
1954    Rappture::Tooltip::for $itk_component(yCutButton) \
1955        "Toggle the Y-axis cutplane on/off"
[3896]1956    $itk_component(yCutButton) select
[2718]1957
1958    itk_component add yCutScale {
[3330]1959        ::scale $inner.yval -from 100 -to 0 \
[2718]1960            -width 10 -orient vertical -showvalue yes \
1961            -borderwidth 1 -highlightthickness 0 \
1962            -command [itcl::code $this EventuallySetCutplane y] \
[3984]1963            -variable [itcl::scope _settings(cutplanePositionY)]
[2718]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] \
[3984]1979            -command [itcl::code $this AdjustSetting cutplaneVisibleZ] \
1980            -variable [itcl::scope _settings(cutplaneVisibleZ)]
[2718]1981    }
1982    Rappture::Tooltip::for $itk_component(zCutButton) \
1983        "Toggle the Z-axis cutplane on/off"
[3896]1984    $itk_component(zCutButton) select
[2718]1985
1986    itk_component add zCutScale {
[3330]1987        ::scale $inner.zval -from 100 -to 0 \
[2718]1988            -width 10 -orient vertical -showvalue yes \
1989            -borderwidth 1 -highlightthickness 0 \
1990            -command [itcl::code $this EventuallySetCutplane z] \
[3984]1991            -variable [itcl::scope _settings(cutplanePositionZ)]
[2718]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 \
[2744]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 \
[2718]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)]
[2744]2047                    $_arcball quaternion $q
2048                    EventuallyRotate $q
[2718]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
[3738]2063            set contents [$dataobj vtkdata $comp]
2064            append bytes "$contents\n"
[2718]2065        }
2066    }
2067    return [list .vtk $bytes]
2068}
2069
2070itcl::body Rappture::VtkVolumeViewer::GetImage { args } {
2071    if { [image width $_image(download)] > 0 &&
[2744]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]
[2718]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" \
[2744]2097        -highlightthickness 0 -pady 2 -padx 3 \
[2718]2098        -command $command \
[2744]2099        -compound left \
2100        -image [Rappture::icon download]
[2718]2101
2102    button $inner.cancel -text "Cancel" \
[2744]2103        -highlightthickness 0 -pady 2 -padx 3 \
2104        -command [list $popup deactivate] \
2105        -compound left \
2106        -image [Rappture::icon cancel]
[2718]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
[3967]2121itcl::body Rappture::VtkVolumeViewer::SetObjectStyle { dataobj cname } {
[2718]2122    # Parse style string.
[3967]2123    set tag $dataobj-$cname
2124    set style [$dataobj style $cname]
[2718]2125    array set settings {
[2744]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
[2718]2136    }
2137    if { $dataobj != $_first } {
[2744]2138        set settings(-opacity) 1
[2718]2139    }
2140    array set settings $style
2141    SendCmd "volume add $tag"
2142    SendCmd "cutplane add $tag"
[3896]2143    SendCmd "cutplane visible 0 $tag"
[2722]2144    SendCmd "volume lighting $settings(-lighting) $tag"
[3441]2145    set _settings(volumeLighting) $settings(-lighting)
[3967]2146    SetInitialTransferFunction $dataobj $cname
2147    SendCmd "volume colormap $cname $tag"
[2718]2148}
2149
2150itcl::body Rappture::VtkVolumeViewer::IsValidObject { dataobj } {
2151    if {[catch {$dataobj isa Rappture::Field} valid] != 0 || !$valid} {
[2744]2152        return 0
[2718]2153    }
2154    return 1
2155}
2156
2157# ----------------------------------------------------------------------
2158# USAGE: ReceiveLegend <colormap> <title> <vmin> <vmax> <size>
2159#
2160# Invoked automatically whenever the "legend" command comes in from
2161# the rendering server.  Indicates that binary image data with the
2162# specified <size> will follow.
2163# ----------------------------------------------------------------------
2164itcl::body Rappture::VtkVolumeViewer::ReceiveLegend { colormap title vmin vmax size } {
2165    set _legendPending 0
[3984]2166    if { [isconnected] } {
[2718]2167        set bytes [ReceiveBytes $size]
2168        if { ![info exists _image(legend)] } {
2169            set _image(legend) [image create photo]
2170        }
2171        $_image(legend) configure -data $bytes
[3969]2172        #puts stderr "read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
[3441]2173        if { [catch {DrawLegend} errs] != 0 } {
[2744]2174            puts stderr errs=$errs
2175        }
[2718]2176    }
2177}
2178
2179#
2180# DrawLegend --
2181#
[3967]2182itcl::body Rappture::VtkVolumeViewer::DrawLegend {} {
2183    if { $_current == "" } {
2184        set _current "component"
2185    }
2186    set cname $_current
2187    set c $itk_component(legend)
2188    set w [winfo width $c]
2189    set h [winfo height $c]
2190    set lx 10
2191    set ly [expr {$h - 1}]
2192    if {"" == [$c find withtag transfunc]} {
2193        $c create image 10 10 -anchor nw \
2194            -image $_image(legend) -tags transfunc
2195        $c create text $lx $ly -anchor sw \
2196            -fill $itk_option(-plotforeground) -tags "limits text vmin"
2197        $c create text [expr {$w-$lx}] $ly -anchor se \
2198            -fill $itk_option(-plotforeground) -tags "limits text vmax"
2199        $c create text [expr {$w/2}] $ly -anchor s \
2200            -fill $itk_option(-plotforeground) -tags "limits text title"
2201        $c lower transfunc
2202    }
2203
2204    # Display the markers used by the current transfer function.
2205    HideAllMarkers
2206    if { [info exists _transferFunctionEditors($cname)] } {
2207        $_transferFunctionEditors($cname) showMarkers $_limits($cname)
2208    }
2209
2210    foreach {min max} $_limits($cname) break
2211    $c itemconfigure vmin -text [format %.2g $min]
2212    $c coords vmin $lx $ly
2213
2214    $c itemconfigure vmax -text [format %.2g $max]
2215    $c coords vmax [expr {$w-$lx}] $ly
2216
2217    set title ""
2218    if { $_first != "" } {
2219        set title [$_first hints label]
2220        set units [$_first hints units]
2221        if { $units != "" } {
2222            set title "$title ($units)"
2223        }
2224    }
2225    $c itemconfigure title -text $title
2226    $c coords title [expr {$w/2}] $ly
2227}
2228
2229#
2230# DrawLegendOld --
2231#
[2744]2232#       Draws the legend in it's own canvas which resides to the right
2233#       of the contour plot area.
[2718]2234#
[3967]2235itcl::body Rappture::VtkVolumeViewer::DrawLegendOld { } {
[3441]2236    set fname $_curFldName
[2718]2237    set c $itk_component(view)
2238    set w [winfo width $c]
2239    set h [winfo height $c]
2240    set font "Arial 8"
2241    set lineht [font metrics $font -linespace]
2242   
[3441]2243    if { [info exists _fields($fname)] } {
2244        foreach { title units } $_fields($fname) break
[2744]2245        if { $units != "" } {
2246            set title [format "%s (%s)" $title $units]
2247        }
[2718]2248    } else {
[3441]2249        set title $fname
[2718]2250    }
[3441]2251    if { $_settings(legendVisible) } {
[2744]2252        set x [expr $w - 2]
2253        if { [$c find withtag "legend"] == "" } {
2254            set y 2
2255            $c create text $x $y \
2256                -anchor ne \
2257                -fill $itk_option(-plotforeground) -tags "title legend" \
2258                -font $font
2259            incr y $lineht
2260            $c create text $x $y \
2261                -anchor ne \
2262                -fill $itk_option(-plotforeground) -tags "vmax legend" \
2263                -font $font
2264            incr y $lineht
2265            $c create image $x $y \
2266                -anchor ne \
2267                -image $_image(legend) -tags "colormap legend"
2268            $c create text $x [expr {$h-2}] \
2269                -anchor se \
2270                -fill $itk_option(-plotforeground) -tags "vmin legend" \
2271                -font $font
2272            #$c bind colormap <Enter> [itcl::code $this EnterLegend %x %y]
2273            $c bind colormap <Leave> [itcl::code $this LeaveLegend]
2274            $c bind colormap <Motion> [itcl::code $this MotionLegend %x %y]
2275        }
2276        $c bind title <ButtonPress> [itcl::code $this Combo post]
2277        $c bind title <Enter> [itcl::code $this Combo activate]
2278        $c bind title <Leave> [itcl::code $this Combo deactivate]
2279        # Reset the item coordinates according the current size of the plot.
2280        $c itemconfigure title -text $title
[3441]2281        if { [info exists _limits($_curFldName)] } {
2282            foreach { vmin vmax } $_limits($_curFldName) break
2283            $c itemconfigure vmin -text [format %g $vmin]
2284            $c itemconfigure vmax -text [format %g $vmax]
[2744]2285        }
2286        set y 2
2287        $c coords title $x $y
2288        incr y $lineht
2289        $c coords vmax $x $y
2290        incr y $lineht
2291        $c coords colormap $x $y
2292        $c coords vmin $x [expr {$h - 2}]
[2718]2293    }
2294}
2295
2296#
2297# EnterLegend --
2298#
2299itcl::body Rappture::VtkVolumeViewer::EnterLegend { x y } {
2300    SetLegendTip $x $y
2301}
2302
2303#
2304# MotionLegend --
2305#
2306itcl::body Rappture::VtkVolumeViewer::MotionLegend { x y } {
2307    Rappture::Tooltip::tooltip cancel
2308    set c $itk_component(view)
2309    SetLegendTip $x $y
2310}
2311
2312#
2313# LeaveLegend --
2314#
2315itcl::body Rappture::VtkVolumeViewer::LeaveLegend { } {
2316    Rappture::Tooltip::tooltip cancel
2317    .rappturetooltip configure -icon ""
2318}
2319
2320#
2321# SetLegendTip --
2322#
2323itcl::body Rappture::VtkVolumeViewer::SetLegendTip { x y } {
2324    set c $itk_component(view)
2325    set w [winfo width $c]
2326    set h [winfo height $c]
2327    set font "Arial 8"
2328    set lineht [font metrics $font -linespace]
2329   
2330    set imgHeight [image height $_image(legend)]
2331    set coords [$c coords colormap]
2332    set imgX [expr $w - [image width $_image(legend)] - 2]
2333    set imgY [expr $y - 2 * ($lineht + 2)]
2334
2335    if { [info exists _fields($_title)] } {
[2744]2336        foreach { title units } $_fields($_title) break
2337        if { $units != "" } {
2338            set title [format "%s (%s)" $title $units]
2339        }
[2718]2340    } else {
[2744]2341        set title $_title
[2718]2342    }
2343    # Make a swatch of the selected color
2344    if { [catch { $_image(legend) get 10 $imgY } pixel] != 0 } {
[2744]2345        #puts stderr "out of range: $imgY"
2346        return
[2718]2347    }
2348    if { ![info exists _image(swatch)] } {
[2744]2349        set _image(swatch) [image create photo -width 24 -height 24]
[2718]2350    }
2351    set color [eval format "\#%02x%02x%02x" $pixel]
2352    $_image(swatch) put black  -to 0 0 23 23
2353    $_image(swatch) put $color -to 1 1 22 22
2354    .rappturetooltip configure -icon $_image(swatch)
2355
2356    # Compute the value of the point
[3441]2357    if { [info exists _limits($_curFldName)] } {
2358        foreach { vmin vmax } $_limits($_curFldName) break
[2744]2359        set t [expr 1.0 - (double($imgY) / double($imgHeight-1))]
[3441]2360        set value [expr $t * ($vmax - $vmin) + $vmin]
[2718]2361    } else {
[2744]2362        set value 0.0
[2718]2363    }
2364    set tipx [expr $x + 15]
2365    set tipy [expr $y - 5]
2366    Rappture::Tooltip::text $c "$title $value"
2367    Rappture::Tooltip::tooltip show $c +$tipx,+$tipy   
2368}
2369
2370
2371# ----------------------------------------------------------------------
2372# USAGE: Slice move x|y|z <newval>
2373#
2374# Called automatically when the user drags the slider to move the
2375# cut plane that slices 3D data.  Gets the current value from the
2376# slider and moves the cut plane to the appropriate point in the
2377# data set.
2378# ----------------------------------------------------------------------
2379itcl::body Rappture::VtkVolumeViewer::Slice {option args} {
2380    switch -- $option {
2381        "move" {
2382            set axis [lindex $args 0]
2383            set newval [lindex $args 1]
2384            if {[llength $args] != 2} {
2385                error "wrong # args: should be \"Slice move x|y|z newval\""
2386            }
2387            set newpos [expr {0.01*$newval}]
2388            SendCmd "cutplane slice $axis $newpos"
2389        }
[2744]2390        "tooltip" {
2391            set axis [lindex $args 0]
2392            set val [$itk_component(${axis}CutScale) get]
2393            return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
2394        }
[2718]2395        default {
2396            error "bad option \"$option\": should be axis, move, or tooltip"
2397        }
2398    }
2399}
2400
2401
2402# ----------------------------------------------------------------------
2403# USAGE: _dropdown post
2404# USAGE: _dropdown unpost
2405# USAGE: _dropdown select
2406#
2407# Used internally to handle the dropdown list for this combobox.  The
2408# post/unpost options are invoked when the list is posted or unposted
2409# to manage the relief of the controlling button.  The select option
2410# is invoked whenever there is a selection from the list, to assign
2411# the value back to the gauge.
2412# ----------------------------------------------------------------------
2413itcl::body Rappture::VtkVolumeViewer::Combo {option} {
2414    set c $itk_component(view)
2415    switch -- $option {
2416        post {
[2744]2417            foreach { x1 y1 x2 y2 } [$c bbox title] break
2418            set x1 [expr [winfo width $itk_component(view)] - [winfo reqwidth $itk_component(fieldmenu)]]
2419            set x [expr $x1 + [winfo rootx $itk_component(view)]]
2420            set y [expr $y2 + [winfo rooty $itk_component(view)]]
2421            tk_popup $itk_component(fieldmenu) $x $y
[2718]2422        }
2423        activate {
[2744]2424            $c itemconfigure title -fill red
[2718]2425        }
2426        deactivate {
[2744]2427            $c itemconfigure title -fill white
[2718]2428        }
[2744]2429        invoke {
[3441]2430            $itk_component(field) value _curFldLabel
2431            AdjustSetting field
[2744]2432        }
[2718]2433        default {
2434            error "bad option \"$option\": should be post, unpost, select"
2435        }
2436    }
2437}
[2728]2438
[3967]2439#
2440# The -levels option takes a single value that represents the number
2441# of evenly distributed markers based on the current data range. Each
2442# marker is a relative value from 0.0 to 1.0.
2443#
2444itcl::body Rappture::VtkVolumeViewer::ParseLevelsOption { cname levels } {
2445    set c $itk_component(legend)
2446    set list {}
2447    regsub -all "," $levels " " levels
2448    if {[string is int $levels]} {
2449        for {set i 1} { $i <= $levels } {incr i} {
2450            lappend list [expr {double($i)/($levels+1)}]
2451        }
2452    } else {
2453        foreach x $levels {
2454            lappend list $x
2455        }
2456    }
2457    set _parsedFunction($cname) 1
2458    $_transferFunctionEditors($cname) addMarkers $list
2459}
2460
2461#
2462# The -markers option takes a list of zero or more values (the values
2463# may be separated either by spaces or commas) that have the following
2464# format:
2465#
2466#   N%  Percent of current total data range.  Converted to
2467#       to a relative value between 0.0 and 1.0.
2468#   N   Absolute value of marker.  If the marker is outside of
2469#       the current range, it will be displayed on the outer
2470#       edge of the legends, but it range it represents will
2471#       not be seen.
2472#
2473itcl::body Rappture::VtkVolumeViewer::ParseMarkersOption { cname markers } {
2474    set c $itk_component(legend)
2475    set list {}
2476    foreach { min max } $_limits($cname) break
2477    regsub -all "," $markers " " markers
2478    foreach marker $markers {
2479        set n [scan $marker "%g%s" value suffix]
2480        if { $n == 2 && $suffix == "%" } {
2481            # $n% : Set relative value (0..1).
2482            lappend list [expr {$value * 0.01}]
2483        } else {
2484            # $n : absolute value, compute relative
2485            lappend list  [expr {(double($value)-$min)/($max-$min)]}
2486        }
2487    }
2488    set _parsedFunction($cname) 1
2489    $_transferFunctionEditors($cname) addMarkers $list
2490}
2491
2492#
2493# SetInitialTransferFunction --
2494#
2495#       Creates a transfer function name based on the <style> settings in the
2496#       library run.xml file. This placeholder will be used later to create
2497#       and send the actual transfer function once the data info has been sent
2498#       to us by the render server. [We won't know the volume limits until the
2499#       server parses the 3D data and sends back the limits via ReceiveData.]
2500#
2501itcl::body Rappture::VtkVolumeViewer::SetInitialTransferFunction { dataobj cname } {
2502    set tag $dataobj-$cname
2503    if { ![info exists _cname2transferFunction($cname)] } {
2504        ComputeTransferFunction $cname
2505    }
2506    set _dataset2style($tag) $cname
2507    lappend _style2datasets($cname) $tag
2508
2509    return $cname
2510}
2511
2512#
2513# ComputeTransferFunction --
2514#
2515#       Computes and sends the transfer function to the render server.  It's
2516#       assumed that the volume data limits are known and that the global
2517#       transfer-functions slider values have been set up.  Both parts are
2518#       needed to compute the relative value (location) of the marker, and
2519#       the alpha map of the transfer function.
2520#
2521itcl::body Rappture::VtkVolumeViewer::ComputeTransferFunction { cname } {
2522
2523    if { ![info exists _transferFunctionEditors($cname)] } {
2524        set _transferFunctionEditors($cname) \
2525            [Rappture::TransferFunctionEditor ::\#auto $itk_component(legend) \
2526                 $cname \
2527                 -command [itcl::code $this updateTransferFunctions]]
2528    }
2529
2530    # We have to parse the style attributes for a volume using this
2531    # transfer-function *once*.  This sets up the initial isomarkers for the
2532    # transfer function.  The user may add/delete markers, so we have to
2533    # maintain a list of markers for each transfer-function.  We use the one
2534    # of the volumes (the first in the list) using the transfer-function as a
2535    # reference.
2536
2537    if { ![info exists _parsedFunction($cname)] || ![info exists _cname2transferFunction($cname)] } {
2538        array set style {
2539            -color BCGYR
2540            -levels 6
2541            -opacity 1.0
2542            -markers ""
2543        }
2544
2545        # Accumulate the style from all the datasets using it.
2546        foreach tag [GetDatasetsWithComponent $cname] {
2547            foreach {dataobj cname} [split [lindex $tag 0] -] break
2548            array set style [lindex [$dataobj components -style $cname] 0]
2549        }
2550        set cmap [ColorsToColormap $style(-color)]
2551        set _cname2defaultcolormap($cname) $cmap
2552        set _settings($cname-colormap) $style(-color)
2553        if { [info exists _transferFunctionEditors($cname)] } {
2554            eval $_transferFunctionEditors($cname) limits $_limits($cname)
2555        }
2556        if { [info exists style(-markers)] &&
2557             [llength $style(-markers)] > 0 } {
2558            ParseMarkersOption $cname $style(-markers)
2559        } else {
2560            ParseLevelsOption $cname $style(-levels)
2561        }
2562    } else {
2563        foreach {cmap wmap} $_cname2transferFunction($cname) break
2564    }
2565
2566    set wmap [ComputeAlphamap $cname]
2567    set _cname2transferFunction($cname) [list $cmap $wmap]
2568    SendCmd [list colormap add $cname $cmap $wmap]
2569}
2570
2571#
2572# ResetColormap --
2573#
2574#       Changes only the colormap portion of the transfer function.
2575#
2576itcl::body Rappture::VtkVolumeViewer::ResetColormap { cname color } {
2577    # Get the current transfer function
2578    if { ![info exists _cname2transferFunction($cname)] } {
2579        return
2580    }
2581    foreach { cmap wmap } $_cname2transferFunction($cname) break
2582    set cmap [GetColormap $cname $color]
2583    set _cname2transferFunction($cname) [list $cmap $wmap]
2584    SendCmd [list colormap add $cname $cmap $wmap]
[4045]2585    SendCmd [list cutplane colormap $cname]
[3969]2586    EventuallyRequestLegend
[3967]2587}
2588
2589# ----------------------------------------------------------------------
2590# USAGE: updateTransferFunctions
2591#
2592#       This is called by the transfer function editor whenever the
2593#       transfer function definition changes.
2594#
2595# ----------------------------------------------------------------------
2596itcl::body Rappture::VtkVolumeViewer::updateTransferFunctions {} {
2597    foreach cname [array names _volcomponents] {
2598        ComputeTransferFunction $cname
2599    }
[3969]2600    EventuallyRequestLegend
[3967]2601}
2602
[3969]2603itcl::body Rappture::VtkVolumeViewer::SetOrientation { side } {
2604    array set positions {
2605        front "1 0 0 0"
2606        back  "0 0 1 0"
2607        left  "0.707107 0 -0.707107 0"
2608        right "0.707107 0 0.707107 0"
2609        top   "0.707107 -0.707107 0 0"
2610        bottom "0.707107 0.707107 0 0"
2611    }
2612    foreach name { qw qx qy qz } value $positions($side) {
2613        set _view($name) $value
2614    }
2615    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
2616    $_arcball quaternion $q
2617    SendCmd "camera orient $q"
2618    SendCmd "camera reset"
2619    set _view(xpan) 0
2620    set _view(ypan) 0
2621    set _view(zoom) 1.0
2622    set _settings($this-xpan) $_view(xpan)
2623    set _settings($this-ypan) $_view(ypan)
2624    set _settings($this-zoom) $_view(zoom)
2625}
2626
[3967]2627#
2628# InitComponentSettings --
2629#
2630#       Initializes the volume settings for a specific component. This
2631#       should match what's used as global settings above. This
2632#       is called the first time we try to switch to a given component
2633#       in SwitchComponent below.
2634#
2635itcl::body Rappture::VtkVolumeViewer::InitComponentSettings { cname } {
2636    array set _settings [subst {
2637        $cname-ambient           60
2638        $cname-colormap          default
2639        $cname-diffuse           40
2640        $cname-light2side        1
2641        $cname-opacity           100
2642        $cname-outline           0
2643        $cname-specularExponent  90
2644        $cname-specularLevel     30
2645        $cname-thickness         350
2646        $cname-transp            50
2647        $cname-volumeVisible     1
2648    }]
2649}
2650
2651#
2652# SwitchComponent --
2653#
2654#       This is called when the current component is changed by the
2655#       dropdown menu in the volume tab.  It synchronizes the global
2656#       volume settings with the settings of the new current component.
2657#
2658itcl::body Rappture::VtkVolumeViewer::SwitchComponent { cname } {
2659    if { ![info exists _settings($cname-ambient)] } {
2660        InitComponentSettings $cname
2661    }
2662    # _settings variables change widgets, except for colormap
2663    set _settings($this-ambient)          $_settings($cname-ambient)
2664    set _settings($this-colormap)         $_settings($cname-colormap)
2665    set _settings($this-diffuse)          $_settings($cname-diffuse)
2666    set _settings($this-light2side)       $_settings($cname-light2side)
2667    set _settings($this-opacity)          $_settings($cname-opacity)
2668    set _settings($this-outline)          $_settings($cname-outline)
2669    set _settings($this-specularExponent) $_settings($cname-specularExponent)
2670    set _settings($this-specularLevel)    $_settings($cname-specularLevel)
2671    set _settings($this-thickness)        $_settings($cname-thickness)
2672    set _settings($this-transp)           $_settings($cname-transp)
2673    set _settings($this-volumeVisible)    $_settings($cname-volumeVisible)
2674    $itk_component(colormap) value        $_settings($cname-colormap)
2675    set _current $cname;                # Reset the current component
2676}
2677
2678itcl::body Rappture::VtkVolumeViewer::ComputeAlphamap { cname } {
2679    if { ![info exists _transferFunctionEditors($cname)] } {
2680        return [list 0.0 0.0 1.0 1.0]
2681    }
2682    if { ![info exists _settings($cname-ambient)] } {
2683        InitComponentSettings $cname
2684    }
2685    set max 1.0 ;                       #$_settings($tag-opacity)
2686
2687    set isovalues [$_transferFunctionEditors($cname) values]
2688
2689    # Ensure that the global opacity and thickness settings (in the slider
2690    # settings widgets) are used for the active transfer-function.  Update
2691    # the values in the _settings varible.
2692    set opacity [expr { double($_settings($cname-opacity)) * 0.01 }]
2693
2694    # Scale values between 0.00001 and 0.01000
2695    set delta [expr {double($_settings($cname-thickness)) * 0.0001}]
2696   
2697    set first [lindex $isovalues 0]
2698    set last [lindex $isovalues end]
2699    set wmap ""
2700    if { $first == "" || $first != 0.0 } {
2701        lappend wmap 0.0 0.0
2702    }
2703    foreach x $isovalues {
2704        set x1 [expr {$x-$delta-0.00001}]
2705        set x2 [expr {$x-$delta}]
2706        set x3 [expr {$x+$delta}]
2707        set x4 [expr {$x+$delta+0.00001}]
2708        if { $x1 < 0.0 } {
2709            set x1 0.0
2710        } elseif { $x1 > 1.0 } {
2711            set x1 1.0
2712        }
2713        if { $x2 < 0.0 } {
2714            set x2 0.0
2715        } elseif { $x2 > 1.0 } {
2716            set x2 1.0
2717        }
2718        if { $x3 < 0.0 } {
2719            set x3 0.0
2720        } elseif { $x3 > 1.0 } {
2721            set x3 1.0
2722        }
2723        if { $x4 < 0.0 } {
2724            set x4 0.0
2725        } elseif { $x4 > 1.0 } {
2726            set x4 1.0
2727        }
2728        # add spikes in the middle
2729        lappend wmap $x1 0.0
2730        lappend wmap $x2 $max
2731        lappend wmap $x3 $max
2732        lappend wmap $x4 0.0
2733    }
2734    if { $last == "" || $last != 1.0 } {
2735        lappend wmap 1.0 0.0
2736    }
2737    return $wmap
2738}
2739
2740#
2741# HideAllMarkers --
2742#
2743#       Hide all the markers in all the transfer functions.  Can't simply
2744#       delete and recreate markers from the <style> since the user may
2745#       have create, deleted, or moved markers.
2746#
2747itcl::body Rappture::VtkVolumeViewer::HideAllMarkers {} {
2748    foreach cname [array names _transferFunctionEditors] {
2749        $_transferFunctionEditors($cname) hideMarkers
2750    }
2751}
2752
2753
2754#
2755# GetDatasetsWithComponents --
2756#
2757#       Returns a list of all the datasets (known by the combination of
2758#       their data object and component name) that match the given
2759#       component name.  For example, this is used where we want to change
2760#       the settings of volumes that have the current component.
2761#
2762itcl::body Rappture::VtkVolumeViewer::GetDatasetsWithComponent { cname } {
2763    if { ![info exists _volcomponents($cname)] } {
2764        return ""
2765    }
[3975]2766    return $_volcomponents($cname)
[3967]2767}
2768
2769#
2770# BuildVolumeComponents --
2771#
2772#       This is called from the "scale" method which is called when a
2773#       new dataset is added or deleted.  It repopulates the dropdown
2774#       menu of volume component names.  It sets the current component
2775#       to the first component in the list (of components found).
2776#       Finally, if there is only one component, don't display the
2777#       label or the combobox in the volume settings tab.
2778#
2779itcl::body Rappture::VtkVolumeViewer::BuildVolumeComponents {} {
2780    $itk_component(volcomponents) choices delete 0 end
2781    foreach name $_componentsList {
2782        $itk_component(volcomponents) choices insert end $name $name
2783    }
2784    set _current [lindex $_componentsList 0]
2785    $itk_component(volcomponents) value $_current
2786    set parent [winfo parent $itk_component(volcomponents)]
2787    if { [llength $_componentsList] <= 1 } {
2788        # Unpack the components label and dropdown if there's only one
2789        # component.
2790        blt::table forget $parent.volcomponents_l $parent.volcomponents
2791    } else {
2792        # Pack the components label and dropdown into the table there's
2793        # more than one component to select.
2794        blt::table $parent \
2795            0,0 $parent.volcomponents_l -anchor e -cspan 2 \
2796            0,2 $parent.volcomponents -cspan 3 -fill x
2797    }
2798}
2799
2800itcl::body Rappture::VtkVolumeViewer::GetColormap { cname color } {
2801    if { $color == "default" } {
2802        return $_cname2defaultcolormap($cname)
2803    }
2804    return [ColorsToColormap $color]
2805}
Note: See TracBrowser for help on using the repository browser.