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

Last change on this file since 3899 was 3899, checked in by ldelgass, 8 years ago

Add cutplane visibility button to nanovis viewers.

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