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

Last change on this file since 5240 was 5240, checked in by ldelgass, 5 years ago

minor ticks setting for axis in vtkvolume

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