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

Last change on this file since 5469 was 5469, checked in by ldelgass, 9 years ago

fix legend toggle in vtkvolume

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