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

Last change on this file since 4007 was 3844, checked in by ldelgass, 11 years ago

Sync with trunk. Branch now differs only from trunk by r3722 (branch is version
1.3, trunk is version 1.4)

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