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

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

misc cleanup vtkvolumeviewer

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