source: branches/1.3/gui/scripts/vtkvolumeviewer.tcl @ 4335

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

Disable debug prints

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