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

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