source: tags/1.3.5/gui/scripts/vtkvolumeviewer.tcl @ 4753

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

merge r4749 from trunk

File size: 77.4 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_title"    [$dataobj hints tooltitle]
969                    lappend info "tool_command"  [$dataobj hints toolcommand]
970                    lappend info "tool_revision" [$dataobj hints toolrevision]
971                    lappend info "dataset_label" [$dataobj hints label]
972                    lappend info "dataset_size"  $length
973                    lappend info "dataset_tag"   $tag
974                    SendCmd [list "clientinfo" $info]
975                }
976                append _outbuf "dataset add $tag data follows $length\n"
977                append _outbuf $bytes
978                set _datasets($tag) 1
979                SetObjectStyle $dataobj $comp
980            }
981            lappend _obj2datasets($dataobj) $tag
982            if { [info exists _obj2ovride($dataobj-raise)] } {
983                SendCmd "dataset visible 1 $tag"
984            }
985            break
986        }
987    }
988    if {"" != $_first} {
989        set location [$_first hints camera]
990        if { $location != "" } {
991            array set view $location
992        }
993
994        foreach axis { x y z } {
995            set label [$_first hints ${axis}label]
996            if { $label != "" } {
997                SendCmd "axis name $axis $label"
998            }
999            set units [$_first hints ${axis}units]
1000            if { $units != "" } {
1001                SendCmd "axis units $axis $units"
1002            }
1003        }
1004        $itk_component(field) choices delete 0 end
1005        $itk_component(fieldmenu) delete 0 end
1006        array unset _fields
1007        set _curFldName ""
1008        foreach cname [$_first components] {
1009            foreach fname [$_first fieldnames $cname] {
1010                if { [info exists _fields($fname)] } {
1011                    continue
1012                }
1013                foreach { label units components } \
1014                    [$_first fieldinfo $fname] break
1015                # Only scalar fields are valid
1016                if {$components == 1} {
1017                    $itk_component(field) choices insert end "$fname" "$label"
1018                    $itk_component(fieldmenu) add radiobutton -label "$label" \
1019                        -value $label -variable [itcl::scope _curFldLabel] \
1020                        -selectcolor red \
1021                        -activebackground $itk_option(-plotbackground) \
1022                        -activeforeground $itk_option(-plotforeground) \
1023                        -font "Arial 8" \
1024                        -command [itcl::code $this Combo invoke]
1025                    set _fields($fname) [list $label $units $components]
1026                    if { $_curFldName == "" } {
1027                        set _curFldName $fname
1028                        set _curFldLabel $label
1029                    }
1030                }
1031            }
1032        }
1033        $itk_component(field) value $_curFldLabel
1034    }
1035
1036    InitSettings volume-palette volume-material volume-quality volumeVisible \
1037        cutplaneVisible \
1038        cutplane-xposition cutplane-yposition cutplane-zposition \
1039        cutplane-xvisible cutplane-yvisible cutplane-zvisible
1040
1041    if { $_reset } {
1042        InitSettings volumeLighting
1043        Zoom reset
1044        set _reset 0
1045    }
1046    # Actually write the commands to the server socket.  If it fails, we don't
1047    # care.  We're finished here.
1048    blt::busy hold $itk_component(hull)
1049    StopBufferingCommands
1050    blt::busy release $itk_component(hull)
1051}
1052
1053# ----------------------------------------------------------------------
1054# USAGE: CurrentDatasets ?-all -visible? ?dataobjs?
1055#
1056# Returns a list of server IDs for the current datasets being displayed.  This
1057# is normally a single ID, but it might be a list of IDs if the current data
1058# object has multiple components.
1059# ----------------------------------------------------------------------
1060itcl::body Rappture::VtkVolumeViewer::CurrentDatasets {args} {
1061    set flag [lindex $args 0]
1062    switch -- $flag {
1063        "-all" {
1064            if { [llength $args] > 1 } {
1065                error "CurrentDatasets: can't specify dataobj after \"-all\""
1066            }
1067            set dlist [get -objects]
1068        }
1069        "-visible" {
1070            if { [llength $args] > 1 } {
1071                set dlist {}
1072                set args [lrange $args 1 end]
1073                foreach dataobj $args {
1074                    if { [info exists _obj2ovride($dataobj-raise)] } {
1075                        lappend dlist $dataobj
1076                    }
1077                }
1078            } else {
1079                set dlist [get -visible]
1080            }
1081        }           
1082        default {
1083            set dlist $args
1084        }
1085    }
1086    set rlist ""
1087    foreach dataobj $dlist {
1088        foreach comp [$dataobj components] {
1089            set tag $dataobj-$comp
1090            if { [info exists _datasets($tag)] && $_datasets($tag) } {
1091                lappend rlist $tag
1092            }
1093        }
1094    }
1095    return $rlist
1096}
1097
1098# ----------------------------------------------------------------------
1099# USAGE: Zoom in
1100# USAGE: Zoom out
1101# USAGE: Zoom reset
1102#
1103# Called automatically when the user clicks on one of the zoom
1104# controls for this widget.  Changes the zoom for the current view.
1105# ----------------------------------------------------------------------
1106itcl::body Rappture::VtkVolumeViewer::Zoom {option} {
1107    switch -- $option {
1108        "in" {
1109            set _view(zoom) [expr {$_view(zoom)*1.25}]
1110            SendCmd "camera zoom $_view(zoom)"
1111        }
1112        "out" {
1113            set _view(zoom) [expr {$_view(zoom)*0.8}]
1114            SendCmd "camera zoom $_view(zoom)"
1115        }
1116        "reset" {
1117            array set _view {
1118                qw      0.853553
1119                qx      -0.353553
1120                qy      0.353553
1121                qz      0.146447
1122                zoom    1.0
1123                xpan   0
1124                ypan   0
1125            }
1126            if { $_first != "" } {
1127                set location [$_first hints camera]
1128                if { $location != "" } {
1129                    array set _view $location
1130                }
1131            }
1132            set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1133            $_arcball quaternion $q
1134            DoRotate
1135            SendCmd "camera reset"
1136        }
1137    }
1138}
1139
1140itcl::body Rappture::VtkVolumeViewer::PanCamera {} {
1141    set x $_view(xpan)
1142    set y $_view(ypan)
1143    SendCmd "camera pan $x $y"
1144}
1145
1146
1147# ----------------------------------------------------------------------
1148# USAGE: Rotate click <x> <y>
1149# USAGE: Rotate drag <x> <y>
1150# USAGE: Rotate release <x> <y>
1151#
1152# Called automatically when the user clicks/drags/releases in the
1153# plot area.  Moves the plot according to the user's actions.
1154# ----------------------------------------------------------------------
1155itcl::body Rappture::VtkVolumeViewer::Rotate {option x y} {
1156    switch -- $option {
1157        "click" {
1158            $itk_component(view) configure -cursor fleur
1159            set _click(x) $x
1160            set _click(y) $y
1161        }
1162        "drag" {
1163            if {[array size _click] == 0} {
1164                Rotate click $x $y
1165            } else {
1166                set w [winfo width $itk_component(view)]
1167                set h [winfo height $itk_component(view)]
1168                if {$w <= 0 || $h <= 0} {
1169                    return
1170                }
1171
1172                if {[catch {
1173                    # this fails sometimes for no apparent reason
1174                    set dx [expr {double($x-$_click(x))/$w}]
1175                    set dy [expr {double($y-$_click(y))/$h}]
1176                }]} {
1177                    return
1178                }
1179                if { $dx == 0 && $dy == 0 } {
1180                    return
1181                }
1182                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1183                EventuallyRotate $q
1184                set _click(x) $x
1185                set _click(y) $y
1186            }
1187        }
1188        "release" {
1189            Rotate drag $x $y
1190            $itk_component(view) configure -cursor ""
1191            catch {unset _click}
1192        }
1193        default {
1194            error "bad option \"$option\": should be click, drag, release"
1195        }
1196    }
1197}
1198
1199itcl::body Rappture::VtkVolumeViewer::Pick {x y} {
1200    foreach tag [CurrentDatasets -visible] {
1201        SendCmd "dataset getscalar pixel $x $y $tag"
1202    }
1203}
1204
1205# ----------------------------------------------------------------------
1206# USAGE: $this Pan click x y
1207#        $this Pan drag x y
1208#        $this Pan release x y
1209#
1210# Called automatically when the user clicks on one of the zoom
1211# controls for this widget.  Changes the zoom for the current view.
1212# ----------------------------------------------------------------------
1213itcl::body Rappture::VtkVolumeViewer::Pan {option x y} {
1214    switch -- $option {
1215        "set" {
1216            set w [winfo width $itk_component(view)]
1217            set h [winfo height $itk_component(view)]
1218            set x [expr $x / double($w)]
1219            set y [expr $y / double($h)]
1220            set _view(xpan) [expr $_view(xpan) + $x]
1221            set _view(ypan) [expr $_view(ypan) + $y]
1222            PanCamera
1223            return
1224        }
1225        "click" {
1226            set _click(x) $x
1227            set _click(y) $y
1228            $itk_component(view) configure -cursor hand1
1229        }
1230        "drag" {
1231            if { ![info exists _click(x)] } {
1232                set _click(x) $x
1233            }
1234            if { ![info exists _click(y)] } {
1235                set _click(y) $y
1236            }
1237            set w [winfo width $itk_component(view)]
1238            set h [winfo height $itk_component(view)]
1239            set dx [expr ($_click(x) - $x)/double($w)]
1240            set dy [expr ($_click(y) - $y)/double($h)]
1241            set _click(x) $x
1242            set _click(y) $y
1243            set _view(xpan) [expr $_view(xpan) - $dx]
1244            set _view(ypan) [expr $_view(ypan) - $dy]
1245            PanCamera
1246        }
1247        "release" {
1248            Pan drag $x $y
1249            $itk_component(view) configure -cursor ""
1250        }
1251        default {
1252            error "unknown option \"$option\": should set, click, drag, or release"
1253        }
1254    }
1255}
1256
1257# ----------------------------------------------------------------------
1258# USAGE: InitSettings <what> ?<value>?
1259#
1260# Used internally to update rendering settings whenever parameters
1261# change in the popup settings panel.  Sends the new settings off
1262# to the back end.
1263# ----------------------------------------------------------------------
1264itcl::body Rappture::VtkVolumeViewer::InitSettings { args } {
1265    foreach spec $args {
1266        if { [info exists _settings($_first-$spec)] } {
1267            # Reset global setting with dataobj specific setting
1268            set _settings($spec) $_settings($_first-$spec)
1269        }
1270        AdjustSetting $spec
1271    }
1272}
1273
1274#
1275# AdjustSetting --
1276#
1277#       Changes/updates a specific setting in the widget.  There are
1278#       usually user-setable option.  Commands are sent to the render
1279#       server.
1280#
1281itcl::body Rappture::VtkVolumeViewer::AdjustSetting {what {value ""}} {
1282    if { ![isconnected] } {
1283        return
1284    }
1285    switch -- $what {
1286        "volumeVisible" {
1287            set bool $_settings(volumeVisible)
1288            foreach dataset [CurrentDatasets -visible] {
1289                SendCmd "volume visible $bool $dataset"
1290            }
1291            if { $bool } {
1292                Rappture::Tooltip::for $itk_component(volume) \
1293                    "Hide the volume"
1294            } else {
1295                Rappture::Tooltip::for $itk_component(volume) \
1296                    "Show the volume"
1297            }
1298        }
1299        "volume-material" {
1300            set val $_settings(volume-material)
1301            set diffuse [expr {0.01*$val}]
1302            set specular [expr {0.01*$val}]
1303            #set power [expr {sqrt(160*$val+1.0)}]
1304            set power [expr {$val+1.0}]
1305            foreach dataset [CurrentDatasets -visible] {
1306                SendCmd "volume shading diffuse $diffuse $dataset"
1307                SendCmd "volume shading specular $specular $power $dataset"
1308            }
1309        }
1310        "volumeLighting" {
1311            set bool $_settings(volumeLighting)
1312            foreach dataset [CurrentDatasets -visible] {
1313                SendCmd "volume lighting $bool $dataset"
1314            }
1315        }
1316        "volume-quality" {
1317            set val $_settings(volume-quality)
1318            set val [expr {0.01*$val}]
1319            foreach dataset [CurrentDatasets -visible] {
1320                SendCmd "volume quality $val $dataset"
1321            }
1322        }
1323        "axesVisible" {
1324            set bool $_settings(axesVisible)
1325            SendCmd "axis visible all $bool"
1326        }
1327        "axisLabels" {
1328            set bool $_settings(axisLabels)
1329            SendCmd "axis labels all $bool"
1330        }
1331        "axis-xgrid" - "axis-ygrid" - "axis-zgrid" {
1332            set axis [string range $what 5 5]
1333            set bool $_settings($what)
1334            SendCmd "axis grid $axis $bool"
1335        }
1336        "axisFlyMode" {
1337            set mode [$itk_component(axismode) value]
1338            set mode [$itk_component(axismode) translate $mode]
1339            set _settings($what) $mode
1340            SendCmd "axis flymode $mode"
1341        }
1342        "cutplaneEdges" {
1343            set bool $_settings($what)
1344            foreach dataset [CurrentDatasets -visible] {
1345                SendCmd "cutplane edges $bool $dataset"
1346            }
1347        }
1348        "cutplaneVisible" {
1349            set bool $_settings($what)
1350            foreach dataset [CurrentDatasets -visible] {
1351                SendCmd "cutplane visible $bool $dataset"
1352            }
1353        }
1354        "cutplaneWireframe" {
1355            set bool $_settings($what)
1356            foreach dataset [CurrentDatasets -visible] {
1357                SendCmd "cutplane wireframe $bool $dataset"
1358            }
1359        }
1360        "cutplaneLighting" {
1361            set bool $_settings($what)
1362            foreach dataset [CurrentDatasets -visible] {
1363                SendCmd "cutplane lighting $bool $dataset"
1364            }
1365        }
1366        "cutplane-opacity" {
1367            set val $_settings($what)
1368            set sval [expr { 0.01 * double($val) }]
1369            foreach dataset [CurrentDatasets -visible] {
1370                SendCmd "cutplane opacity $sval $dataset"
1371            }
1372        }
1373        "cutplane-xvisible" - "cutplane-yvisible" - "cutplane-zvisible" {
1374            set axis [string range $what 9 9]
1375            set bool $_settings($what)
1376            if { $bool } {
1377                $itk_component(${axis}CutScale) configure -state normal \
1378                    -troughcolor white
1379            } else {
1380                $itk_component(${axis}CutScale) configure -state disabled \
1381                    -troughcolor grey82
1382            }
1383            foreach dataset [CurrentDatasets -visible] {
1384                SendCmd "cutplane axis $axis $bool $dataset"
1385            }
1386        }
1387        "cutplane-xposition" - "cutplane-yposition" - "cutplane-zposition" {
1388            set axis [string range $what 9 9]
1389            set pos [expr $_settings($what) * 0.01]
1390            foreach dataset [CurrentDatasets -visible] {
1391                SendCmd "cutplane slice ${axis} ${pos} $dataset"
1392            }
1393            set _cutplanePending 0
1394        }
1395        "volume-palette" {
1396            set palette [$itk_component(palette) value]
1397            set _settings(volume-palette) $palette
1398            foreach dataset [CurrentDatasets -visible $_first] {
1399                foreach {dataobj comp} [split $dataset -] break
1400                ChangeColormap $dataobj $comp $palette
1401            }
1402            set _legendPending 1
1403        }
1404        "volume-palette" {
1405            set palette [$itk_component(palette) value]
1406            set _settings(volume-palette) $palette
1407            foreach dataset [CurrentDatasets -visible $_first] {
1408                foreach {dataobj comp} [split $dataset -] break
1409                ChangeColormap $dataobj $comp $palette
1410            }
1411            set _legendPending 1
1412        }
1413        "field" {
1414            set label [$itk_component(field) value]
1415            set fname [$itk_component(field) translate $label]
1416            set _settings(field) $fname
1417            if { [info exists _fields($fname)] } {
1418                foreach { label units components } $_fields($fname) break
1419                if { $components > 1 } {
1420                    puts stderr "Can't use a vector field in a volume"
1421                    return
1422                } else {
1423                    set _colorMode scalar
1424                }
1425                set _curFldName $fname
1426                set _curFldLabel $label
1427            } else {
1428                puts stderr "unknown field \"$fname\""
1429                return
1430            }
1431            foreach dataset [CurrentDatasets -visible $_first] {
1432                #SendCmd "volume colormode $_colorMode ${fname} $dataset"
1433                SendCmd "cutplane colormode $_colorMode ${fname} $dataset"
1434            }
1435            SendCmd "camera reset"
1436            DrawLegend
1437        }
1438        default {
1439            error "don't know how to fix $what"
1440        }
1441    }
1442}
1443
1444#
1445# RequestLegend --
1446#
1447#       Request a new legend from the server.  The size of the legend
1448#       is determined from the height of the canvas.  It will be rotated
1449#       to be vertical when drawn.
1450#
1451itcl::body Rappture::VtkVolumeViewer::RequestLegend {} {
1452    set font "Arial 8"
1453    set lineht [font metrics $font -linespace]
1454    set c $itk_component(legend)
1455    set w 12
1456    set h [expr {$_height - 3 * ($lineht + 2)}]
1457    if { $h < 1} {
1458        return
1459    }
1460    # Set the legend on the first volume dataset.
1461    foreach dataset [CurrentDatasets -visible $_first] {
1462        foreach {dataobj comp} [split $dataset -] break
1463        if { [info exists _dataset2style($dataset)] } {
1464            SendCmdNoWait \
1465                "legend $_dataset2style($dataset) $_colorMode $_curFldName {} $w $h 0"
1466            break;
1467        }
1468    }
1469}
1470
1471#
1472# ChangeColormap --
1473#
1474itcl::body Rappture::VtkVolumeViewer::ChangeColormap {dataobj comp color} {
1475    set tag $dataobj-$comp
1476    if { ![info exist _style($tag)] } {
1477        error "no initial colormap"
1478    }
1479    array set style $_style($tag)
1480    set style(-color) $color
1481    set _style($tag) [array get style]
1482    SetColormap $dataobj $comp
1483}
1484
1485#
1486# SetColormap --
1487#
1488itcl::body Rappture::VtkVolumeViewer::SetColormap { dataobj comp } {
1489    array set style {
1490        -color BCGYR
1491        -levels 6
1492        -opacity 1.0
1493    }
1494    set tag $dataobj-$comp
1495    if { ![info exists _initialStyle($tag)] } {
1496        # Save the initial component style.
1497        set _initialStyle($tag) [$dataobj style $comp]
1498    }
1499
1500    # Override defaults with initial style defined in xml.
1501    array set style $_initialStyle($tag)
1502
1503    if { ![info exists _style($tag)] } {
1504        set _style($tag) [array get style]
1505    }
1506    # Override initial style with current style.
1507    array set style $_style($tag)
1508
1509    set name "$style(-color):$style(-levels):$style(-opacity)"
1510    if { ![info exists _colormaps($name)] } {
1511        BuildColormap $name [array get style]
1512        set _colormaps($name) 1
1513    }
1514    if { ![info exists _dataset2style($tag)] ||
1515         $_dataset2style($tag) != $name } {
1516        SendCmd "volume colormap $name $tag"
1517        SendCmd "cutplane colormap $name-opaque $tag"
1518        set _dataset2style($tag) $name
1519    }
1520}
1521
1522#
1523# BuildColormap --
1524#
1525itcl::body Rappture::VtkVolumeViewer::BuildColormap { name styles } {
1526    array set style $styles
1527    set cmap [ColorsToColormap $style(-color)]
1528    if { [llength $cmap] == 0 } {
1529        set cmap "0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0"
1530    }
1531    if { ![info exists _settings(volume-opacity)] } {
1532        set _settings(volume-opacity) $style(-opacity)
1533    }
1534    set max $_settings(volume-opacity)
1535
1536    set opaqueWmap "0.0 1.0 1.0 1.0"
1537    #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"
1538    # Approximate cubic opacity curve
1539    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"
1540    SendCmd "colormap add $name { $cmap } { $wmap }"
1541    SendCmd "colormap add $name-opaque { $cmap } { $opaqueWmap }"
1542}
1543
1544# ----------------------------------------------------------------------
1545# CONFIGURATION OPTION: -plotbackground
1546# ----------------------------------------------------------------------
1547itcl::configbody Rappture::VtkVolumeViewer::plotbackground {
1548    if { [isconnected] } {
1549        foreach {r g b} [Color2RGB $itk_option(-plotbackground)] break
1550        SendCmd "screen bgcolor $r $g $b"
1551    }
1552}
1553
1554# ----------------------------------------------------------------------
1555# CONFIGURATION OPTION: -plotforeground
1556# ----------------------------------------------------------------------
1557itcl::configbody Rappture::VtkVolumeViewer::plotforeground {
1558    if { [isconnected] } {
1559        foreach {r g b} [Color2RGB $itk_option(-plotforeground)] break
1560        #fix this!
1561        #SendCmd "color background $r $g $b"
1562    }
1563}
1564
1565itcl::body Rappture::VtkVolumeViewer::BuildVolumeTab {} {
1566
1567    set fg [option get $itk_component(hull) font Font]
1568    #set bfg [option get $itk_component(hull) boldFont Font]
1569
1570    set inner [$itk_component(main) insert end \
1571        -title "Volume Settings" \
1572        -icon [Rappture::icon volume-on]]
1573    $inner configure -borderwidth 4
1574
1575    checkbutton $inner.volume \
1576        -text "Show Volume" \
1577        -variable [itcl::scope _settings(volumeVisible)] \
1578        -command [itcl::code $this AdjustSetting volumeVisible] \
1579        -font "Arial 9"
1580
1581    checkbutton $inner.lighting \
1582        -text "Enable Lighting" \
1583        -variable [itcl::scope _settings(volumeLighting)] \
1584        -command [itcl::code $this AdjustSetting volumeLighting] \
1585        -font "Arial 9"
1586
1587    label $inner.dim_l -text "Dim" -font "Arial 9"
1588    ::scale $inner.material -from 0 -to 100 -orient horizontal \
1589        -variable [itcl::scope _settings(volume-material)] \
1590        -width 10 \
1591        -showvalue off -command [itcl::code $this AdjustSetting volume-material]
1592    label $inner.bright_l -text "Bright" -font "Arial 9"
1593
1594    label $inner.opacity_l -text "Opacity" -font "Arial 9"
1595    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1596        -variable [itcl::scope _settings(volume-opacity)] \
1597        -width 10 \
1598        -showvalue off \
1599        -command [itcl::code $this AdjustSetting volume-opacity]
1600
1601    label $inner.quality_l -text "Quality" -font "Arial 9"
1602    ::scale $inner.quality -from 0 -to 100 -orient horizontal \
1603        -variable [itcl::scope _settings(volume-quality)] \
1604        -width 10 \
1605        -showvalue off -command [itcl::code $this AdjustSetting volume-quality]
1606
1607    itk_component add field_l {
1608        label $inner.field_l -text "Field" -font "Arial 9"
1609    } {
1610        ignore -font
1611    }
1612    itk_component add field {
1613        Rappture::Combobox $inner.field -width 10 -editable no
1614    }
1615    bind $inner.field <<Value>> \
1616        [itcl::code $this AdjustSetting field]
1617
1618    label $inner.palette_l -text "Palette" -font "Arial 9"
1619    itk_component add palette {
1620        Rappture::Combobox $inner.palette -width 10 -editable no
1621    }
1622    $inner.palette choices insert end \
1623        "BCGYR"              "BCGYR"            \
1624        "BGYOR"              "BGYOR"            \
1625        "blue"               "blue"             \
1626        "blue-to-brown"      "blue-to-brown"    \
1627        "blue-to-orange"     "blue-to-orange"   \
1628        "blue-to-grey"       "blue-to-grey"     \
1629        "green-to-magenta"   "green-to-magenta" \
1630        "greyscale"          "greyscale"        \
1631        "nanohub"            "nanohub"          \
1632        "rainbow"            "rainbow"          \
1633        "spectral"           "spectral"         \
1634        "ROYGB"              "ROYGB"            \
1635        "RYGCB"              "RYGCB"            \
1636        "brown-to-blue"      "brown-to-blue"    \
1637        "grey-to-blue"       "grey-to-blue"     \
1638        "orange-to-blue"     "orange-to-blue"   
1639
1640    $itk_component(palette) value "BCGYR"
1641    bind $inner.palette <<Value>> \
1642        [itcl::code $this AdjustSetting volume-palette]
1643
1644    blt::table $inner \
1645        0,0 $inner.field_l   -anchor w -pady 2  \
1646        0,1 $inner.field     -anchor w -pady 2 -cspan 2 \
1647        1,0 $inner.volume    -anchor w -pady 2 -cspan 4 \
1648        2,0 $inner.lighting  -anchor w -pady 2 -cspan 4 \
1649        3,0 $inner.dim_l     -anchor e -pady 2 \
1650        3,1 $inner.material  -fill x   -pady 2 \
1651        3,2 $inner.bright_l  -anchor w -pady 2 \
1652        4,0 $inner.quality_l -anchor w -pady 2 -cspan 2 \
1653        5,0 $inner.quality   -fill x   -pady 2 -cspan 2 \
1654        7,0 $inner.palette_l -anchor w -pady 2  \
1655        7,1 $inner.palette   -anchor w -pady 2 -cspan 2 \
1656
1657    blt::table configure $inner r* c* -resize none
1658    blt::table configure $inner r8 -resize expand
1659}
1660
1661itcl::body Rappture::VtkVolumeViewer::BuildAxisTab {} {
1662
1663    set fg [option get $itk_component(hull) font Font]
1664    #set bfg [option get $itk_component(hull) boldFont Font]
1665
1666    set inner [$itk_component(main) insert end \
1667        -title "Axis Settings" \
1668        -icon [Rappture::icon axis1]]
1669    $inner configure -borderwidth 4
1670
1671    checkbutton $inner.visible \
1672        -text "Show Axes" \
1673        -variable [itcl::scope _settings(axesVisible)] \
1674        -command [itcl::code $this AdjustSetting axesVisible] \
1675        -font "Arial 9"
1676
1677    checkbutton $inner.labels \
1678        -text "Show Axis Labels" \
1679        -variable [itcl::scope _settings(axisLabels)] \
1680        -command [itcl::code $this AdjustSetting axisLabels] \
1681        -font "Arial 9"
1682
1683    checkbutton $inner.gridx \
1684        -text "Show X Grid" \
1685        -variable [itcl::scope _settings(axis-xgrid)] \
1686        -command [itcl::code $this AdjustSetting axis-xgrid] \
1687        -font "Arial 9"
1688    checkbutton $inner.gridy \
1689        -text "Show Y Grid" \
1690        -variable [itcl::scope _settings(axis-ygrid)] \
1691        -command [itcl::code $this AdjustSetting axis-ygrid] \
1692        -font "Arial 9"
1693    checkbutton $inner.gridz \
1694        -text "Show Z Grid" \
1695        -variable [itcl::scope _settings(axis-zgrid)] \
1696        -command [itcl::code $this AdjustSetting axis-zgrid] \
1697        -font "Arial 9"
1698
1699    label $inner.mode_l -text "Mode" -font "Arial 9"
1700
1701    itk_component add axismode {
1702        Rappture::Combobox $inner.mode -width 10 -editable no
1703    }
1704    $inner.mode choices insert end \
1705        "static_triad"    "static" \
1706        "closest_triad"   "closest" \
1707        "furthest_triad"  "furthest" \
1708        "outer_edges"     "outer"         
1709    $itk_component(axismode) value "static"
1710    bind $inner.mode <<Value>> [itcl::code $this AdjustSetting axisFlyMode]
1711
1712    blt::table $inner \
1713        0,0 $inner.visible -anchor w -cspan 2 \
1714        1,0 $inner.labels  -anchor w -cspan 2 \
1715        2,0 $inner.gridx   -anchor w -cspan 2 \
1716        3,0 $inner.gridy   -anchor w -cspan 2 \
1717        4,0 $inner.gridz   -anchor w -cspan 2 \
1718        5,0 $inner.mode_l  -anchor w -cspan 2 -padx { 2 0 } \
1719        6,0 $inner.mode    -fill x   -cspan 2
1720
1721    blt::table configure $inner r* c* -resize none
1722    blt::table configure $inner r7 c1 -resize expand
1723}
1724
1725
1726itcl::body Rappture::VtkVolumeViewer::BuildCameraTab {} {
1727    set inner [$itk_component(main) insert end \
1728        -title "Camera Settings" \
1729        -icon [Rappture::icon camera]]
1730    $inner configure -borderwidth 4
1731
1732    set labels { qx qy qz qw xpan ypan zoom }
1733    set row 0
1734    foreach tag $labels {
1735        label $inner.${tag}label -text $tag -font "Arial 9"
1736        entry $inner.${tag} -font "Arial 9"  -bg white \
1737            -textvariable [itcl::scope _view($tag)]
1738        bind $inner.${tag} <KeyPress-Return> \
1739            [itcl::code $this camera set ${tag}]
1740        blt::table $inner \
1741            $row,0 $inner.${tag}label -anchor e -pady 2 \
1742            $row,1 $inner.${tag} -anchor w -pady 2
1743        blt::table configure $inner r$row -resize none
1744        incr row
1745    }
1746    checkbutton $inner.ortho \
1747        -text "Orthographic Projection" \
1748        -variable [itcl::scope _view(ortho)] \
1749        -command [itcl::code $this camera set ortho] \
1750        -font "Arial 9"
1751    blt::table $inner \
1752            $row,0 $inner.ortho -cspan 2 -anchor w -pady 2
1753    blt::table configure $inner r$row -resize none
1754    incr row
1755
1756    blt::table configure $inner c0 c1 -resize none
1757    blt::table configure $inner c2 -resize expand
1758    blt::table configure $inner r$row -resize expand
1759}
1760
1761itcl::body Rappture::VtkVolumeViewer::BuildCutplaneTab {} {
1762
1763    set fg [option get $itk_component(hull) font Font]
1764   
1765    set inner [$itk_component(main) insert end \
1766        -title "Cutplane Settings" \
1767        -icon [Rappture::icon cutbutton]]
1768
1769    $inner configure -borderwidth 4
1770
1771    checkbutton $inner.visible \
1772        -text "Show Cutplanes" \
1773        -variable [itcl::scope _settings(cutplaneVisible)] \
1774        -command [itcl::code $this AdjustSetting cutplaneVisible] \
1775        -font "Arial 9"
1776
1777    checkbutton $inner.wireframe \
1778        -text "Show Wireframe" \
1779        -variable [itcl::scope _settings(cutplaneWireframe)] \
1780        -command [itcl::code $this AdjustSetting cutplaneWireframe] \
1781        -font "Arial 9"
1782
1783    checkbutton $inner.lighting \
1784        -text "Enable Lighting" \
1785        -variable [itcl::scope _settings(cutplaneLighting)] \
1786        -command [itcl::code $this AdjustSetting cutplaneLighting] \
1787        -font "Arial 9"
1788
1789    checkbutton $inner.edges \
1790        -text "Show Edges" \
1791        -variable [itcl::scope _settings(cutplaneEdges)] \
1792        -command [itcl::code $this AdjustSetting cutplaneEdges] \
1793        -font "Arial 9"
1794
1795    label $inner.opacity_l -text "Opacity" -font "Arial 9"
1796    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1797        -variable [itcl::scope _settings(cutplane-opacity)] \
1798        -width 10 \
1799        -showvalue off \
1800        -command [itcl::code $this AdjustSetting cutplane-opacity]
1801    $inner.opacity set $_settings(cutplane-opacity)
1802
1803    # X-value slicer...
1804    itk_component add xCutButton {
1805        Rappture::PushButton $inner.xbutton \
1806            -onimage [Rappture::icon x-cutplane] \
1807            -offimage [Rappture::icon x-cutplane] \
1808            -command [itcl::code $this AdjustSetting cutplane-xvisible] \
1809            -variable [itcl::scope _settings(cutplane-xvisible)]
1810    }
1811    Rappture::Tooltip::for $itk_component(xCutButton) \
1812        "Toggle the X-axis cutplane on/off"
1813    $itk_component(xCutButton) select
1814
1815    itk_component add xCutScale {
1816        ::scale $inner.xval -from 100 -to 0 \
1817            -width 10 -orient vertical -showvalue yes \
1818            -borderwidth 1 -highlightthickness 0 \
1819            -command [itcl::code $this EventuallySetCutplane x] \
1820            -variable [itcl::scope _settings(cutplane-xposition)]
1821    } {
1822        usual
1823        ignore -borderwidth -highlightthickness
1824    }
1825    # Set the default cutplane value before disabling the scale.
1826    $itk_component(xCutScale) set 50
1827    $itk_component(xCutScale) configure -state disabled
1828    Rappture::Tooltip::for $itk_component(xCutScale) \
1829        "@[itcl::code $this Slice tooltip x]"
1830
1831    # Y-value slicer...
1832    itk_component add yCutButton {
1833        Rappture::PushButton $inner.ybutton \
1834            -onimage [Rappture::icon y-cutplane] \
1835            -offimage [Rappture::icon y-cutplane] \
1836            -command [itcl::code $this AdjustSetting cutplane-yvisible] \
1837            -variable [itcl::scope _settings(cutplane-yvisible)]
1838    }
1839    Rappture::Tooltip::for $itk_component(yCutButton) \
1840        "Toggle the Y-axis cutplane on/off"
1841    $itk_component(yCutButton) select
1842
1843    itk_component add yCutScale {
1844        ::scale $inner.yval -from 100 -to 0 \
1845            -width 10 -orient vertical -showvalue yes \
1846            -borderwidth 1 -highlightthickness 0 \
1847            -command [itcl::code $this EventuallySetCutplane y] \
1848            -variable [itcl::scope _settings(cutplane-yposition)]
1849    } {
1850        usual
1851        ignore -borderwidth -highlightthickness
1852    }
1853    Rappture::Tooltip::for $itk_component(yCutScale) \
1854        "@[itcl::code $this Slice tooltip y]"
1855    # Set the default cutplane value before disabling the scale.
1856    $itk_component(yCutScale) set 50
1857    $itk_component(yCutScale) configure -state disabled
1858
1859    # Z-value slicer...
1860    itk_component add zCutButton {
1861        Rappture::PushButton $inner.zbutton \
1862            -onimage [Rappture::icon z-cutplane] \
1863            -offimage [Rappture::icon z-cutplane] \
1864            -command [itcl::code $this AdjustSetting cutplane-zvisible] \
1865            -variable [itcl::scope _settings(cutplane-zvisible)]
1866    }
1867    Rappture::Tooltip::for $itk_component(zCutButton) \
1868        "Toggle the Z-axis cutplane on/off"
1869    $itk_component(zCutButton) select
1870
1871    itk_component add zCutScale {
1872        ::scale $inner.zval -from 100 -to 0 \
1873            -width 10 -orient vertical -showvalue yes \
1874            -borderwidth 1 -highlightthickness 0 \
1875            -command [itcl::code $this EventuallySetCutplane z] \
1876            -variable [itcl::scope _settings(cutplane-zposition)]
1877    } {
1878        usual
1879        ignore -borderwidth -highlightthickness
1880    }
1881    $itk_component(zCutScale) set 50
1882    $itk_component(zCutScale) configure -state disabled
1883    Rappture::Tooltip::for $itk_component(zCutScale) \
1884        "@[itcl::code $this Slice tooltip z]"
1885
1886    blt::table $inner \
1887        0,0 $inner.visible              -anchor w -pady 2 -cspan 4 \
1888        1,0 $inner.lighting             -anchor w -pady 2 -cspan 4 \
1889        2,0 $inner.wireframe            -anchor w -pady 2 -cspan 4 \
1890        3,0 $inner.edges                -anchor w -pady 2 -cspan 4 \
1891        4,0 $inner.opacity_l            -anchor w -pady 2 -cspan 3 \
1892        5,0 $inner.opacity              -fill x   -pady 2 -cspan 3 \
1893        6,0 $itk_component(xCutButton)  -anchor e -padx 2 -pady 2 \
1894        7,0 $itk_component(xCutScale)   -fill y \
1895        6,1 $itk_component(yCutButton)  -anchor e -padx 2 -pady 2 \
1896        7,1 $itk_component(yCutScale)   -fill y \
1897        6,2 $itk_component(zCutButton)  -anchor e -padx 2 -pady 2 \
1898        7,2 $itk_component(zCutScale)   -fill y \
1899
1900    blt::table configure $inner r* c* -resize none
1901    blt::table configure $inner r7 c3 -resize expand
1902}
1903
1904#
1905#  camera --
1906#
1907itcl::body Rappture::VtkVolumeViewer::camera {option args} {
1908    switch -- $option {
1909        "show" {
1910            puts [array get _view]
1911        }
1912        "set" {
1913            set who [lindex $args 0]
1914            set x $_view($who)
1915            set code [catch { string is double $x } result]
1916            if { $code != 0 || !$result } {
1917                return
1918            }
1919            switch -- $who {
1920                "ortho" {
1921                    if {$_view(ortho)} {
1922                        SendCmd "camera mode ortho"
1923                    } else {
1924                        SendCmd "camera mode persp"
1925                    }
1926                }
1927                "xpan" - "ypan" {
1928                    PanCamera
1929                }
1930                "qx" - "qy" - "qz" - "qw" {
1931                    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1932                    $_arcball quaternion $q
1933                    EventuallyRotate $q
1934                }
1935                "zoom" {
1936                    SendCmd "camera zoom $_view(zoom)"
1937                }
1938            }
1939        }
1940    }
1941}
1942
1943itcl::body Rappture::VtkVolumeViewer::GetVtkData { args } {
1944    set bytes ""
1945    foreach dataobj [get] {
1946        foreach comp [$dataobj components] {
1947            set tag $dataobj-$comp
1948            set contents [$dataobj vtkdata $comp]
1949            append bytes "$contents\n"
1950        }
1951    }
1952    return [list .vtk $bytes]
1953}
1954
1955itcl::body Rappture::VtkVolumeViewer::GetImage { args } {
1956    if { [image width $_image(download)] > 0 &&
1957         [image height $_image(download)] > 0 } {
1958        set bytes [$_image(download) data -format "jpeg -quality 100"]
1959        set bytes [Rappture::encoding::decode -as b64 $bytes]
1960        return [list .jpg $bytes]
1961    }
1962    return ""
1963}
1964
1965itcl::body Rappture::VtkVolumeViewer::BuildDownloadPopup { popup command } {
1966    Rappture::Balloon $popup \
1967        -title "[Rappture::filexfer::label downloadWord] as..."
1968    set inner [$popup component inner]
1969    label $inner.summary -text "" -anchor w
1970    radiobutton $inner.vtk_button -text "VTK data file" \
1971        -variable [itcl::scope _downloadPopup(format)] \
1972        -font "Helvetica 9 " \
1973        -value vtk 
1974    Rappture::Tooltip::for $inner.vtk_button "Save as VTK data file."
1975    radiobutton $inner.image_button -text "Image File" \
1976        -variable [itcl::scope _downloadPopup(format)] \
1977        -value image
1978    Rappture::Tooltip::for $inner.image_button \
1979        "Save as digital image."
1980
1981    button $inner.ok -text "Save" \
1982        -highlightthickness 0 -pady 2 -padx 3 \
1983        -command $command \
1984        -compound left \
1985        -image [Rappture::icon download]
1986
1987    button $inner.cancel -text "Cancel" \
1988        -highlightthickness 0 -pady 2 -padx 3 \
1989        -command [list $popup deactivate] \
1990        -compound left \
1991        -image [Rappture::icon cancel]
1992
1993    blt::table $inner \
1994        0,0 $inner.summary -cspan 2  \
1995        1,0 $inner.vtk_button -anchor w -cspan 2 -padx { 4 0 } \
1996        2,0 $inner.image_button -anchor w -cspan 2 -padx { 4 0 } \
1997        4,1 $inner.cancel -width .9i -fill y \
1998        4,0 $inner.ok -padx 2 -width .9i -fill y
1999    blt::table configure $inner r3 -height 4
2000    blt::table configure $inner r4 -pady 4
2001    raise $inner.image_button
2002    $inner.vtk_button invoke
2003    return $inner
2004}
2005
2006itcl::body Rappture::VtkVolumeViewer::SetObjectStyle { dataobj comp } {
2007    # Parse style string.
2008    set tag $dataobj-$comp
2009    set style [$dataobj style $comp]
2010    array set settings {
2011        -color \#808080
2012        -edges 0
2013        -edgecolor black
2014        -linewidth 1.0
2015        -opacity 0.4
2016        -wireframe 0
2017        -lighting 1
2018        -seeds 1
2019        -seedcolor white
2020        -visible 1
2021    }
2022    if { $dataobj != $_first } {
2023        set settings(-opacity) 1
2024    }
2025    array set settings $style
2026    SendCmd "volume add $tag"
2027    SendCmd "cutplane add $tag"
2028    SendCmd "cutplane visible 0 $tag"
2029
2030    SendCmd "volume lighting $settings(-lighting) $tag"
2031    set _settings(volumeLighting) $settings(-lighting)
2032    SetColormap $dataobj $comp
2033}
2034
2035itcl::body Rappture::VtkVolumeViewer::IsValidObject { dataobj } {
2036    if {[catch {$dataobj isa Rappture::Field} valid] != 0 || !$valid} {
2037        return 0
2038    }
2039    return 1
2040}
2041
2042# ----------------------------------------------------------------------
2043# USAGE: ReceiveLegend <colormap> <title> <vmin> <vmax> <size>
2044#
2045# Invoked automatically whenever the "legend" command comes in from
2046# the rendering server.  Indicates that binary image data with the
2047# specified <size> will follow.
2048# ----------------------------------------------------------------------
2049itcl::body Rappture::VtkVolumeViewer::ReceiveLegend { colormap title vmin vmax size } {
2050    set _legendPending 0
2051    #puts stderr "ReceiveLegend colormap=$colormap title=$title range=$vmin,$vmax size=$size"
2052    if { [IsConnected] } {
2053        set bytes [ReceiveBytes $size]
2054        if { ![info exists _image(legend)] } {
2055            set _image(legend) [image create photo]
2056        }
2057        $_image(legend) configure -data $bytes
2058        #puts stderr "read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
2059        if { [catch {DrawLegend} errs] != 0 } {
2060            puts stderr errs=$errs
2061        }
2062    }
2063}
2064
2065#
2066# DrawLegend --
2067#
2068#       Draws the legend in it's own canvas which resides to the right
2069#       of the contour plot area.
2070#
2071itcl::body Rappture::VtkVolumeViewer::DrawLegend { } {
2072    set fname $_curFldName
2073    set c $itk_component(view)
2074    set w [winfo width $c]
2075    set h [winfo height $c]
2076    set font "Arial 8"
2077    set lineht [font metrics $font -linespace]
2078   
2079    if { [info exists _fields($fname)] } {
2080        foreach { title units } $_fields($fname) break
2081        if { $units != "" } {
2082            set title [format "%s (%s)" $title $units]
2083        }
2084    } else {
2085        set title $fname
2086    }
2087    if { $_settings(legendVisible) } {
2088        set x [expr $w - 2]
2089        if { [$c find withtag "legend"] == "" } {
2090            set y 2
2091            $c create text $x $y \
2092                -anchor ne \
2093                -fill $itk_option(-plotforeground) -tags "title legend" \
2094                -font $font
2095            incr y $lineht
2096            $c create text $x $y \
2097                -anchor ne \
2098                -fill $itk_option(-plotforeground) -tags "vmax legend" \
2099                -font $font
2100            incr y $lineht
2101            $c create image $x $y \
2102                -anchor ne \
2103                -image $_image(legend) -tags "colormap legend"
2104            $c create text $x [expr {$h-2}] \
2105                -anchor se \
2106                -fill $itk_option(-plotforeground) -tags "vmin legend" \
2107                -font $font
2108            #$c bind colormap <Enter> [itcl::code $this EnterLegend %x %y]
2109            $c bind colormap <Leave> [itcl::code $this LeaveLegend]
2110            $c bind colormap <Motion> [itcl::code $this MotionLegend %x %y]
2111        }
2112        $c bind title <ButtonPress> [itcl::code $this Combo post]
2113        $c bind title <Enter> [itcl::code $this Combo activate]
2114        $c bind title <Leave> [itcl::code $this Combo deactivate]
2115        # Reset the item coordinates according the current size of the plot.
2116        $c itemconfigure title -text $title
2117        if { [info exists _limits($_curFldName)] } {
2118            foreach { vmin vmax } $_limits($_curFldName) break
2119            $c itemconfigure vmin -text [format %g $vmin]
2120            $c itemconfigure vmax -text [format %g $vmax]
2121        }
2122        set y 2
2123        $c coords title $x $y
2124        incr y $lineht
2125        $c coords vmax $x $y
2126        incr y $lineht
2127        $c coords colormap $x $y
2128        $c coords vmin $x [expr {$h - 2}]
2129    }
2130}
2131
2132#
2133# EnterLegend --
2134#
2135itcl::body Rappture::VtkVolumeViewer::EnterLegend { x y } {
2136    SetLegendTip $x $y
2137}
2138
2139#
2140# MotionLegend --
2141#
2142itcl::body Rappture::VtkVolumeViewer::MotionLegend { x y } {
2143    Rappture::Tooltip::tooltip cancel
2144    set c $itk_component(view)
2145    SetLegendTip $x $y
2146}
2147
2148#
2149# LeaveLegend --
2150#
2151itcl::body Rappture::VtkVolumeViewer::LeaveLegend { } {
2152    Rappture::Tooltip::tooltip cancel
2153    .rappturetooltip configure -icon ""
2154}
2155
2156#
2157# SetLegendTip --
2158#
2159itcl::body Rappture::VtkVolumeViewer::SetLegendTip { x y } {
2160    set c $itk_component(view)
2161    set w [winfo width $c]
2162    set h [winfo height $c]
2163    set font "Arial 8"
2164    set lineht [font metrics $font -linespace]
2165   
2166    set imgHeight [image height $_image(legend)]
2167    set coords [$c coords colormap]
2168    set imgX [expr $w - [image width $_image(legend)] - 2]
2169    set imgY [expr $y - 2 * ($lineht + 2)]
2170
2171    if { [info exists _fields($_title)] } {
2172        foreach { title units } $_fields($_title) break
2173        if { $units != "" } {
2174            set title [format "%s (%s)" $title $units]
2175        }
2176    } else {
2177        set title $_title
2178    }
2179    # Make a swatch of the selected color
2180    if { [catch { $_image(legend) get 10 $imgY } pixel] != 0 } {
2181        #puts stderr "out of range: $imgY"
2182        return
2183    }
2184    if { ![info exists _image(swatch)] } {
2185        set _image(swatch) [image create photo -width 24 -height 24]
2186    }
2187    set color [eval format "\#%02x%02x%02x" $pixel]
2188    $_image(swatch) put black  -to 0 0 23 23
2189    $_image(swatch) put $color -to 1 1 22 22
2190    .rappturetooltip configure -icon $_image(swatch)
2191
2192    # Compute the value of the point
2193    if { [info exists _limits($_curFldName)] } {
2194        foreach { vmin vmax } $_limits($_curFldName) break
2195        set t [expr 1.0 - (double($imgY) / double($imgHeight-1))]
2196        set value [expr $t * ($vmax - $vmin) + $vmin]
2197    } else {
2198        set value 0.0
2199    }
2200    set tipx [expr $x + 15]
2201    set tipy [expr $y - 5]
2202    Rappture::Tooltip::text $c "$title $value"
2203    Rappture::Tooltip::tooltip show $c +$tipx,+$tipy   
2204}
2205
2206
2207# ----------------------------------------------------------------------
2208# USAGE: Slice move x|y|z <newval>
2209#
2210# Called automatically when the user drags the slider to move the
2211# cut plane that slices 3D data.  Gets the current value from the
2212# slider and moves the cut plane to the appropriate point in the
2213# data set.
2214# ----------------------------------------------------------------------
2215itcl::body Rappture::VtkVolumeViewer::Slice {option args} {
2216    switch -- $option {
2217        "move" {
2218            set axis [lindex $args 0]
2219            set newval [lindex $args 1]
2220            if {[llength $args] != 2} {
2221                error "wrong # args: should be \"Slice move x|y|z newval\""
2222            }
2223            set newpos [expr {0.01*$newval}]
2224            SendCmd "cutplane slice $axis $newpos"
2225        }
2226        "tooltip" {
2227            set axis [lindex $args 0]
2228            set val [$itk_component(${axis}CutScale) get]
2229            return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
2230        }
2231        default {
2232            error "bad option \"$option\": should be axis, move, or tooltip"
2233        }
2234    }
2235}
2236
2237
2238# ----------------------------------------------------------------------
2239# USAGE: _dropdown post
2240# USAGE: _dropdown unpost
2241# USAGE: _dropdown select
2242#
2243# Used internally to handle the dropdown list for this combobox.  The
2244# post/unpost options are invoked when the list is posted or unposted
2245# to manage the relief of the controlling button.  The select option
2246# is invoked whenever there is a selection from the list, to assign
2247# the value back to the gauge.
2248# ----------------------------------------------------------------------
2249itcl::body Rappture::VtkVolumeViewer::Combo {option} {
2250    set c $itk_component(view)
2251    switch -- $option {
2252        post {
2253            foreach { x1 y1 x2 y2 } [$c bbox title] break
2254            set x1 [expr [winfo width $itk_component(view)] - [winfo reqwidth $itk_component(fieldmenu)]]
2255            set x [expr $x1 + [winfo rootx $itk_component(view)]]
2256            set y [expr $y2 + [winfo rooty $itk_component(view)]]
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.