source: branches/1.4/gui/scripts/vtkvolumeviewer.tcl @ 5349

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

merge r5347 from trunk

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