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

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

add KP_Enter to Return bindings. Implement OK handler in visviewer base class. Fix setting # of isolines while running a sequence of heightmaps/contours

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