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

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

Disable right-click binding for "Picking." This was only there for testing.

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