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

Last change on this file since 3799 was 3799, checked in by gah, 11 years ago

add -simulation to plotadd calls

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