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

Last change on this file since 2722 was 2722, checked in by gah, 13 years ago

vtkvolume additional viewer for dx files

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    foreach dataobj [get -objects] {
1006        if { [info exists _obj2ovride($dataobj-raise)] &&  $_first == "" } {
1007            set _first $dataobj
1008        }
1009        set _obj2datasets($dataobj) ""
1010        foreach comp [$dataobj components] {
1011            set tag $dataobj-$comp
1012            if { ![info exists _datasets($tag)] } {
1013                set bytes [$dataobj vtkdata $comp]
1014                set length [string length $bytes]
1015                append _outbuf "dataset add $tag data follows $length\n"
1016                append _outbuf $bytes
1017                set _datasets($tag) 1
1018                SetObjectStyle $dataobj $comp
1019            }
1020            lappend _obj2datasets($dataobj) $tag
1021            if { [info exists _obj2ovride($dataobj-raise)] } {
1022                SendCmd "dataset visible 1 $tag"
1023            } else {
1024                SendCmd "dataset visible 0 $tag"
1025            }
1026        }
1027    }
1028    if {"" != $_first} {
1029        set location [$_first hints camera]
1030        if { $location != "" } {
1031            array set view $location
1032        }
1033
1034        if 0 {
1035            # Tell the server the name of the tool, the version, and dataset
1036            # that we are rendering.  Have to do it here because we don't know
1037            # what data objects are using the renderer until be get here.
1038            set args ""
1039            lappend args tool [$_first hints toolId]
1040            lappend args version [$_first hints toolRevision]
1041            lappend args dataset [$_first hints label]
1042            SendCmd "clientinfo $args"
1043        }
1044
1045        foreach axis { x y z } {
1046            set label [$_first hints ${axis}label]
1047            if { $label != "" } {
1048                SendCmd "axis name $axis $label"
1049            }
1050            set units [$_first hints ${axis}units]
1051            if { $units != "" } {
1052                SendCmd "axis units $axis $units"
1053            }
1054        }
1055        array unset _scalarFields
1056        array unset _vectorFields
1057        set _currentField [$_first hints default]
1058        $itk_component(field) choices delete 0 end
1059        $itk_component(fieldmenu) delete 0 end
1060        array unset _fields
1061        foreach { name title units } [$_first hints vectors] {
1062            set _vectorFields($title) $name
1063            $itk_component(field) choices insert end "$name" "$title"
1064            $itk_component(fieldmenu) add radiobutton -label "$title" \
1065                -value $title -variable [itcl::scope _currentField] \
1066                -selectcolor red \
1067                -activebackground black \
1068                -activeforeground white \
1069                -font "Arial 8" \
1070                -command [itcl::code $this Combo invoke]
1071            set _fields($name) [list $title $units]
1072        }
1073        foreach { name title units } [$_first hints scalars] {
1074            set _scalarFields($title) $name
1075            $itk_component(field) choices insert end "$name" "$title"
1076            $itk_component(fieldmenu) add radiobutton -label "$title" \
1077                -value $title -variable [itcl::scope _currentField] \
1078                -selectcolor red \
1079                -activebackground black \
1080                -activeforeground white \
1081                -font "Arial 8" \
1082                -command [itcl::code $this Combo invoke]
1083            set _fields($name) [list $title $units]
1084        }
1085        $itk_component(field) value $_currentField
1086    }
1087
1088    InitSettings volume-palette volume-visible
1089
1090    if { $_reset } {
1091        InitSettings volume-lighting
1092        Zoom reset
1093        set _reset 0
1094    }
1095    set _buffering 0;                        # Turn off buffering.
1096
1097    # Actually write the commands to the server socket.  If it fails, we don't
1098    # care.  We're finished here.
1099    blt::busy hold $itk_component(hull)
1100    sendto $_outbuf;                       
1101    blt::busy release $itk_component(hull)
1102    set _outbuf "";                        # Clear the buffer.               
1103}
1104
1105# ----------------------------------------------------------------------
1106# USAGE: CurrentDatasets ?-all -visible? ?dataobjs?
1107#
1108# Returns a list of server IDs for the current datasets being displayed.  This
1109# is normally a single ID, but it might be a list of IDs if the current data
1110# object has multiple components.
1111# ----------------------------------------------------------------------
1112itcl::body Rappture::VtkVolumeViewer::CurrentDatasets {args} {
1113    set flag [lindex $args 0]
1114    switch -- $flag {
1115        "-all" {
1116            if { [llength $args] > 1 } {
1117                error "CurrentDatasets: can't specify dataobj after \"-all\""
1118            }
1119            set dlist [get -objects]
1120        }
1121        "-visible" {
1122            if { [llength $args] > 1 } {
1123                set dlist {}
1124                set args [lrange $args 1 end]
1125                foreach dataobj $args {
1126                    if { [info exists _obj2ovride($dataobj-raise)] } {
1127                        lappend dlist $dataobj
1128                    }
1129                }
1130            } else {
1131                set dlist [get -visible]
1132            }
1133        }           
1134        default {
1135            set dlist $args
1136        }
1137    }
1138    set rlist ""
1139    foreach dataobj $dlist {
1140        foreach comp [$dataobj components] {
1141            set tag $dataobj-$comp
1142            if { [info exists _datasets($tag)] && $_datasets($tag) } {
1143                lappend rlist $tag
1144            }
1145        }
1146    }
1147    return $rlist
1148}
1149
1150# ----------------------------------------------------------------------
1151# USAGE: Zoom in
1152# USAGE: Zoom out
1153# USAGE: Zoom reset
1154#
1155# Called automatically when the user clicks on one of the zoom
1156# controls for this widget.  Changes the zoom for the current view.
1157# ----------------------------------------------------------------------
1158itcl::body Rappture::VtkVolumeViewer::Zoom {option} {
1159    switch -- $option {
1160        "in" {
1161            set _view(zoom) [expr {$_view(zoom)*1.25}]
1162            SendCmd "camera zoom $_view(zoom)"
1163        }
1164        "out" {
1165            set _view(zoom) [expr {$_view(zoom)*0.8}]
1166            SendCmd "camera zoom $_view(zoom)"
1167        }
1168        "reset" {
1169            array set _view {
1170                qw      1
1171                qx      0
1172                qy      0
1173                qz      0
1174                zoom    1.0
1175                xpan   0
1176                ypan   0
1177            }
1178            SendCmd "camera reset all"
1179            if { $_first != "" } {
1180                set location [$_first hints camera]
1181                if { $location != "" } {
1182                    array set _view $location
1183                }
1184            }
1185            set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1186            $_arcball quaternion $q
1187            DoRotate
1188        }
1189    }
1190}
1191
1192itcl::body Rappture::VtkVolumeViewer::PanCamera {} {
1193    set x $_view(xpan)
1194    set y $_view(ypan)
1195    SendCmd "camera pan $x $y"
1196}
1197
1198
1199# ----------------------------------------------------------------------
1200# USAGE: Rotate click <x> <y>
1201# USAGE: Rotate drag <x> <y>
1202# USAGE: Rotate release <x> <y>
1203#
1204# Called automatically when the user clicks/drags/releases in the
1205# plot area.  Moves the plot according to the user's actions.
1206# ----------------------------------------------------------------------
1207itcl::body Rappture::VtkVolumeViewer::Rotate {option x y} {
1208    switch -- $option {
1209        "click" {
1210            $itk_component(view) configure -cursor fleur
1211            set _click(x) $x
1212            set _click(y) $y
1213        }
1214        "drag" {
1215            if {[array size _click] == 0} {
1216                Rotate click $x $y
1217            } else {
1218                set w [winfo width $itk_component(view)]
1219                set h [winfo height $itk_component(view)]
1220                if {$w <= 0 || $h <= 0} {
1221                    return
1222                }
1223
1224                if {[catch {
1225                    # this fails sometimes for no apparent reason
1226                    set dx [expr {double($x-$_click(x))/$w}]
1227                    set dy [expr {double($y-$_click(y))/$h}]
1228                }]} {
1229                    return
1230                }
1231                if { $dx == 0 && $dy == 0 } {
1232                    return
1233                }
1234                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1235                EventuallyRotate $q
1236                set _click(x) $x
1237                set _click(y) $y
1238            }
1239        }
1240        "release" {
1241            Rotate drag $x $y
1242            $itk_component(view) configure -cursor ""
1243            catch {unset _click}
1244        }
1245        default {
1246            error "bad option \"$option\": should be click, drag, release"
1247        }
1248    }
1249}
1250
1251itcl::body Rappture::VtkVolumeViewer::Pick {x y} {
1252    foreach tag [CurrentDatasets -visible] {
1253        SendCmd "dataset getscalar pixel $x $y $tag"
1254    }
1255}
1256
1257# ----------------------------------------------------------------------
1258# USAGE: $this Pan click x y
1259#        $this Pan drag x y
1260#        $this Pan release x y
1261#
1262# Called automatically when the user clicks on one of the zoom
1263# controls for this widget.  Changes the zoom for the current view.
1264# ----------------------------------------------------------------------
1265itcl::body Rappture::VtkVolumeViewer::Pan {option x y} {
1266    switch -- $option {
1267        "set" {
1268            set w [winfo width $itk_component(view)]
1269            set h [winfo height $itk_component(view)]
1270            set x [expr $x / double($w)]
1271            set y [expr $y / double($h)]
1272            set _view(xpan) [expr $_view(xpan) + $x]
1273            set _view(ypan) [expr $_view(ypan) + $y]
1274            PanCamera
1275            return
1276        }
1277        "click" {
1278            set _click(x) $x
1279            set _click(y) $y
1280            $itk_component(view) configure -cursor hand1
1281        }
1282        "drag" {
1283            if { ![info exists _click(x)] } {
1284                set _click(x) $x
1285            }
1286            if { ![info exists _click(y)] } {
1287                set _click(y) $y
1288            }
1289            set w [winfo width $itk_component(view)]
1290            set h [winfo height $itk_component(view)]
1291            set dx [expr ($_click(x) - $x)/double($w)]
1292            set dy [expr ($_click(y) - $y)/double($h)]
1293            set _click(x) $x
1294            set _click(y) $y
1295            set _view(xpan) [expr $_view(xpan) - $dx]
1296            set _view(ypan) [expr $_view(ypan) - $dy]
1297            PanCamera
1298        }
1299        "release" {
1300            Pan drag $x $y
1301            $itk_component(view) configure -cursor ""
1302        }
1303        default {
1304            error "unknown option \"$option\": should set, click, drag, or release"
1305        }
1306    }
1307}
1308
1309# ----------------------------------------------------------------------
1310# USAGE: InitSettings <what> ?<value>?
1311#
1312# Used internally to update rendering settings whenever parameters
1313# change in the popup settings panel.  Sends the new settings off
1314# to the back end.
1315# ----------------------------------------------------------------------
1316itcl::body Rappture::VtkVolumeViewer::InitSettings { args } {
1317    foreach spec $args {
1318        if { [info exists _settings($_first-$spec)] } {
1319            # Reset global setting with dataobj specific setting
1320            set _settings($spec) $_settings($_first-$spec)
1321        }
1322        AdjustSetting $spec
1323    }
1324}
1325
1326#
1327# AdjustSetting --
1328#
1329#       Changes/updates a specific setting in the widget.  There are
1330#       usually user-setable option.  Commands are sent to the render
1331#       server.
1332#
1333itcl::body Rappture::VtkVolumeViewer::AdjustSetting {what {value ""}} {
1334    if { ![isconnected] } {
1335        return
1336    }
1337    switch -- $what {
1338        "volume-visible" {
1339            set bool $_settings(volume-visible)
1340            foreach dataset [CurrentDatasets -visible] {
1341                SendCmd "volume visible $bool $dataset"
1342            }
1343            if { $bool } {
1344                Rappture::Tooltip::for $itk_component(volume) \
1345                    "Hide the volume"
1346            } else {
1347                Rappture::Tooltip::for $itk_component(volume) \
1348                    "Show the volume"
1349            }
1350        }
1351        "volume-lighting" {
1352            set bool $_settings(volume-lighting)
1353            foreach dataset [CurrentDatasets -visible] {
1354                SendCmd "volume lighting $bool $dataset"
1355            }
1356        }
1357        "axis-visible" {
1358            set bool $_settings(axis-visible)
1359            SendCmd "axis visible all $bool"
1360        }
1361        "axis-labels" {
1362            set bool $_settings(axis-labels)
1363            SendCmd "axis labels all $bool"
1364        }
1365        "axis-xgrid" - "axis-ygrid" - "axis-zgrid" {
1366            set axis [string range $what 5 5]
1367            set bool $_settings($what)
1368            SendCmd "axis grid $axis $bool"
1369        }
1370        "axis-mode" {
1371            set mode [$itk_component(axismode) value]
1372            set mode [$itk_component(axismode) translate $mode]
1373            set _settings($what) $mode
1374            SendCmd "axis flymode $mode"
1375        }
1376        "cutplane-edges" {
1377            set bool $_settings($what)
1378            foreach dataset [CurrentDatasets -visible] {
1379                SendCmd "cutplane edges $bool $dataset"
1380            }
1381        }
1382        "cutplane-visible" {
1383            set bool $_settings($what)
1384            foreach dataset [CurrentDatasets -visible] {
1385                SendCmd "cutplane visible $bool $dataset"
1386            }
1387        }
1388        "cutplane-wireframe" {
1389            set bool $_settings($what)
1390            foreach dataset [CurrentDatasets -visible] {
1391                SendCmd "cutplane wireframe $bool $dataset"
1392            }
1393        }
1394        "cutplane-lighting" {
1395            set bool $_settings($what)
1396            foreach dataset [CurrentDatasets -visible] {
1397                SendCmd "cutplane lighting $bool $dataset"
1398            }
1399        }
1400        "cutplane-opacity" {
1401            set val $_settings($what)
1402            set sval [expr { 0.01 * double($val) }]
1403            foreach dataset [CurrentDatasets -visible] {
1404                SendCmd "cutplane opacity $sval $dataset"
1405            }
1406        }
1407        "cutplane-xvisible" - "cutplane-yvisible" - "cutplane-zvisible" {
1408            set axis [string range $what 9 9]
1409            set bool $_settings($what)
1410            if { $bool } {
1411                $itk_component(${axis}CutScale) configure -state normal \
1412                    -troughcolor white
1413            } else {
1414                $itk_component(${axis}CutScale) configure -state disabled \
1415                    -troughcolor grey82
1416            }
1417            SendCmd "cutplane axis $axis $bool"
1418        }
1419        "cutplane-xposition" - "cutplane-yposition" - "cutplane-zposition" {
1420            set axis [string range $what 9 9]
1421            set pos [expr $_settings($what) * 0.01]
1422            SendCmd "cutplane slice ${axis} ${pos}"
1423            set _cutplanePending 0
1424        }
1425        "volume-palette" {
1426            set palette [$itk_component(palette) value]
1427            set _settings(volume-palette) $palette
1428            foreach dataset [CurrentDatasets -visible $_first] {
1429                foreach {dataobj comp} [split $dataset -] break
1430                ChangeColormap $dataobj $comp $palette
1431            }
1432            set _legendPending 1
1433        }
1434        "volume-palette" {
1435            set palette [$itk_component(palette) value]
1436            set _settings(volume-palette) $palette
1437            foreach dataset [CurrentDatasets -visible $_first] {
1438                foreach {dataobj comp} [split $dataset -] break
1439                ChangeColormap $dataobj $comp $palette
1440            }
1441            set _legendPending 1
1442        }
1443        "volume-field" {
1444            set new [$itk_component(field) value]
1445            set value [$itk_component(field) translate $new]
1446            set _settings(volume-field) $value
1447            if { [info exists _scalarFields($new)] } {
1448                set name $_scalarFields($new)
1449                set _colorMode scalar
1450                set _currentField $new
1451            } elseif { [info exists _vectorFields($new)] } {
1452                set name $_vectorFields($new)
1453                set _colorMode vmag
1454                set _currentField $new
1455            } else {
1456                puts stderr "unknown field \"$new\""
1457                return
1458            }
1459            foreach dataset [CurrentDatasets -visible] {
1460                puts stderr "volume colormode $_colorMode ${name} $dataset"
1461                puts stderr "cutplane colormode $_colorMode ${name} $dataset"
1462                SendCmd "volume colormode $_colorMode ${name} $dataset"
1463                SendCmd "cutplane colormode $_colorMode ${name} $dataset"
1464            }
1465            set _legendPending 1
1466        }
1467        default {
1468            error "don't know how to fix $what"
1469        }
1470    }
1471}
1472
1473#
1474# RequestLegend --
1475#
1476#       Request a new legend from the server.  The size of the legend
1477#       is determined from the height of the canvas.  It will be rotated
1478#       to be vertical when drawn.
1479#
1480itcl::body Rappture::VtkVolumeViewer::RequestLegend {} {
1481    set font "Arial 8"
1482    set lineht [font metrics $font -linespace]
1483    set c $itk_component(legend)
1484    set w 12
1485    set h [expr {$_height - 3 * ($lineht + 2)}]
1486    if { $h < 1} {
1487        return
1488    }
1489    if { [info exists _scalarFields($_currentField)] } {
1490        set name $_scalarFields($_currentField)
1491    } elseif { [info exists _vectorFields($_currentField)] } {
1492        set name $_vectorFields($_currentField)
1493    } else {
1494        return
1495    }
1496    # Set the legend on the first volume dataset.
1497    foreach dataset [CurrentDatasets -visible $_first] {
1498        foreach {dataobj comp} [split $dataset -] break
1499        if { [info exists _dataset2style($dataset)] } {
1500            SendCmdNoWait \
1501                "legend $_dataset2style($dataset) $_colorMode $name {} $w $h 0"
1502            break;
1503        }
1504    }
1505}
1506
1507#
1508# ChangeColormap --
1509#
1510itcl::body Rappture::VtkVolumeViewer::ChangeColormap {dataobj comp color} {
1511    set tag $dataobj-$comp
1512    if { ![info exist _style($tag)] } {
1513        error "no initial colormap"
1514    }
1515    array set style $_style($tag)
1516    set style(-color) $color
1517    set _style($tag) [array get style]
1518    SetColormap $dataobj $comp
1519}
1520
1521#
1522# SetColormap --
1523#
1524itcl::body Rappture::VtkVolumeViewer::SetColormap { dataobj comp } {
1525    array set style {
1526        -color BGYOR
1527        -levels 6
1528        -opacity 1.0
1529    }
1530    set tag $dataobj-$comp
1531    if { ![info exists _initialStyle($tag)] } {
1532        # Save the initial component style.
1533        set _initialStyle($tag) [$dataobj style $comp]
1534    }
1535
1536    # Override defaults with initial style defined in xml.
1537    array set style $_initialStyle($tag)
1538
1539    if { ![info exists _style($tag)] } {
1540        set _style($tag) [array get style]
1541    }
1542    # Override initial style with current style.
1543    array set style $_style($tag)
1544
1545    set name "$style(-color):$style(-levels):$style(-opacity)"
1546    if { ![info exists _colormaps($name)] } {
1547        BuildColormap $name [array get style]
1548        set _colormaps($name) 1
1549    }
1550    if { ![info exists _dataset2style($tag)] ||
1551         $_dataset2style($tag) != $name } {
1552        SendCmd "volume colormap $name $tag"
1553        SendCmd "cutplane colormap $name $tag"
1554        set _dataset2style($tag) $name
1555    }
1556}
1557
1558itcl::body Rappture::VtkVolumeViewer::ColorsToColormap { colors } {
1559puts stderr colors=$colors
1560    switch -- $colors {
1561        "grey-to-blue" {
1562            return {
1563                0.0                      0.200 0.200 0.200
1564                0.14285714285714285      0.400 0.400 0.400
1565                0.2857142857142857       0.600 0.600 0.600
1566                0.42857142857142855      0.900 0.900 0.900
1567                0.5714285714285714       0.800 1.000 1.000
1568                0.7142857142857143       0.600 1.000 1.000
1569                0.8571428571428571       0.400 0.900 1.000
1570                1.0                      0.000 0.600 0.800
1571            }
1572        }
1573        "blue-to-grey" {
1574            return {
1575                0.0                     0.000 0.600 0.800
1576                0.14285714285714285     0.400 0.900 1.000
1577                0.2857142857142857      0.600 1.000 1.000
1578                0.42857142857142855     0.800 1.000 1.000
1579                0.5714285714285714      0.900 0.900 0.900
1580                0.7142857142857143      0.600 0.600 0.600
1581                0.8571428571428571      0.400 0.400 0.400
1582                1.0                     0.200 0.200 0.200
1583            }
1584        }
1585        "blue" {
1586            return {
1587                0.0                     0.900 1.000 1.000
1588                0.1111111111111111      0.800 0.983 1.000
1589                0.2222222222222222      0.700 0.950 1.000
1590                0.3333333333333333      0.600 0.900 1.000
1591                0.4444444444444444      0.500 0.833 1.000
1592                0.5555555555555556      0.400 0.750 1.000
1593                0.6666666666666666      0.300 0.650 1.000
1594                0.7777777777777778      0.200 0.533 1.000
1595                0.8888888888888888      0.100 0.400 1.000
1596                1.0                     0.000 0.250 1.000
1597            }
1598        }
1599        "brown-to-blue" {
1600            return {
1601                0.0                             0.200   0.100   0.000
1602                0.09090909090909091             0.400   0.187   0.000
1603                0.18181818181818182             0.600   0.379   0.210
1604                0.2727272727272727              0.800   0.608   0.480
1605                0.36363636363636365             0.850   0.688   0.595
1606                0.45454545454545453             0.950   0.855   0.808
1607                0.5454545454545454              0.800   0.993   1.000
1608                0.6363636363636364              0.600   0.973   1.000
1609                0.7272727272727273              0.400   0.940   1.000
1610                0.8181818181818182              0.200   0.893   1.000
1611                0.9090909090909091              0.000   0.667   0.800
1612                1.0                             0.000   0.480   0.600
1613            }
1614        }
1615        "blue-to-brown" {
1616            return {
1617                0.0                             0.000   0.480   0.600
1618                0.09090909090909091             0.000   0.667   0.800
1619                0.18181818181818182             0.200   0.893   1.000
1620                0.2727272727272727              0.400   0.940   1.000
1621                0.36363636363636365             0.600   0.973   1.000
1622                0.45454545454545453             0.800   0.993   1.000
1623                0.5454545454545454              0.950   0.855   0.808
1624                0.6363636363636364              0.850   0.688   0.595
1625                0.7272727272727273              0.800   0.608   0.480
1626                0.8181818181818182              0.600   0.379   0.210
1627                0.9090909090909091              0.400   0.187   0.000
1628                1.0                             0.200   0.100   0.000
1629            }
1630        }
1631        "blue-to-orange" {
1632            return {
1633                0.0                             0.000   0.167   1.000
1634                0.09090909090909091             0.100   0.400   1.000
1635                0.18181818181818182             0.200   0.600   1.000
1636                0.2727272727272727              0.400   0.800   1.000
1637                0.36363636363636365             0.600   0.933   1.000
1638                0.45454545454545453             0.800   1.000   1.000
1639                0.5454545454545454              1.000   1.000   0.800
1640                0.6363636363636364              1.000   0.933   0.600
1641                0.7272727272727273              1.000   0.800   0.400
1642                0.8181818181818182              1.000   0.600   0.200
1643                0.9090909090909091              1.000   0.400   0.100
1644                1.0                             1.000   0.167   0.000
1645            }
1646        }
1647        "orange-to-blue" {
1648            return {
1649                0.0                             1.000   0.167   0.000
1650                0.09090909090909091             1.000   0.400   0.100
1651                0.18181818181818182             1.000   0.600   0.200
1652                0.2727272727272727              1.000   0.800   0.400
1653                0.36363636363636365             1.000   0.933   0.600
1654                0.45454545454545453             1.000   1.000   0.800
1655                0.5454545454545454              0.800   1.000   1.000
1656                0.6363636363636364              0.600   0.933   1.000
1657                0.7272727272727273              0.400   0.800   1.000
1658                0.8181818181818182              0.200   0.600   1.000
1659                0.9090909090909091              0.100   0.400   1.000
1660                1.0                             0.000   0.167   1.000
1661            }
1662        }
1663        "rainbow" {
1664            set clist {
1665                "#EE82EE"
1666                "#4B0082"
1667                "blue"
1668                "#008000"
1669                "yellow"
1670                "#FFA500"
1671                "red"
1672            }
1673        }
1674        "BGYOR" {
1675            set clist {
1676                "blue"
1677                "#008000"
1678                "yellow"
1679                "#FFA500"
1680                "red"
1681            }
1682        }
1683        "ROYGB" {
1684            set clist {
1685                "red"
1686                "#FFA500"
1687                "yellow"
1688                "#008000"
1689                "blue"
1690            }
1691        }
1692        "RYGCB" {
1693            set clist {
1694                "red"
1695                "yellow"
1696                "green"
1697                "cyan"
1698                "blue"
1699            }
1700        }
1701        "BCGYR" {
1702            set clist {
1703                "blue"
1704                "cyan"
1705                "green"
1706                "yellow"
1707                "red"
1708            }
1709        }
1710        "spectral" {
1711            return {
1712                0.0 0.150 0.300 1.000
1713                0.1 0.250 0.630 1.000
1714                0.2 0.450 0.850 1.000
1715                0.3 0.670 0.970 1.000
1716                0.4 0.880 1.000 1.000
1717                0.5 1.000 1.000 0.750
1718                0.6 1.000 0.880 0.600
1719                0.7 1.000 0.680 0.450
1720                0.8 0.970 0.430 0.370
1721                0.9 0.850 0.150 0.196
1722                1.0 0.650 0.000 0.130
1723            }
1724        }
1725        "green-to-magenta" {
1726            return {
1727                0.0 0.000 0.316 0.000
1728                0.06666666666666667 0.000 0.526 0.000
1729                0.13333333333333333 0.000 0.737 0.000
1730                0.2 0.000 0.947 0.000
1731                0.26666666666666666 0.316 1.000 0.316
1732                0.3333333333333333 0.526 1.000 0.526
1733                0.4 0.737 1.000 0.737
1734                0.4666666666666667 1.000 1.000 1.000
1735                0.5333333333333333 1.000 0.947 1.000
1736                0.6 1.000 0.737 1.000
1737                0.6666666666666666 1.000 0.526 1.000
1738                0.7333333333333333 1.000 0.316 1.000
1739                0.8 0.947 0.000 0.947
1740                0.8666666666666667 0.737 0.000 0.737
1741                0.9333333333333333 0.526 0.000 0.526
1742                1.0 0.316 0.000 0.316
1743            }
1744        }
1745        "greyscale" {
1746            return {
1747                0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0
1748            }
1749        }
1750        "nanohub" {
1751            set clist "white yellow green cyan blue magenta"
1752        }
1753        default {
1754            set clist $colors
1755        }
1756    }
1757    set cmap {}
1758    for {set i 0} {$i < [llength $clist]} {incr i} {
1759        set x [expr {double($i)/([llength $clist]-1)}]
1760        set color [lindex $clist $i]
1761        append cmap "$x [Color2RGB $color] "
1762    }
1763    return $cmap
1764}
1765
1766#
1767# BuildColormap --
1768#
1769itcl::body Rappture::VtkVolumeViewer::BuildColormap { name styles } {
1770    array set style $styles
1771    set cmap [ColorsToColormap $style(-color)]
1772    if { [llength $cmap] == 0 } {
1773        set cmap "0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0"
1774    }
1775    if { ![info exists _settings(volume-opacity)] } {
1776        set _settings(volume-opacity) $style(-opacity)
1777    }
1778    set max $_settings(volume-opacity)
1779
1780    set wmap "0.0 1.0 1.0 1.0"
1781    SendCmd "colormap add $name { $cmap } { $wmap }"
1782}
1783
1784# ----------------------------------------------------------------------
1785# CONFIGURATION OPTION: -plotbackground
1786# ----------------------------------------------------------------------
1787itcl::configbody Rappture::VtkVolumeViewer::plotbackground {
1788    if { [isconnected] } {
1789        foreach {r g b} [Color2RGB $itk_option(-plotbackground)] break
1790        SendCmd "screen bgcolor $r $g $b"
1791    }
1792}
1793
1794# ----------------------------------------------------------------------
1795# CONFIGURATION OPTION: -plotforeground
1796# ----------------------------------------------------------------------
1797itcl::configbody Rappture::VtkVolumeViewer::plotforeground {
1798    if { [isconnected] } {
1799        foreach {r g b} [Color2RGB $itk_option(-plotforeground)] break
1800        #fix this!
1801        #SendCmd "color background $r $g $b"
1802    }
1803}
1804
1805itcl::body Rappture::VtkVolumeViewer::limits { dataobj } {
1806    return
1807    array unset _limits $dataobj-*
1808    foreach comp [$dataobj components] {
1809        set tag $dataobj-$comp
1810        if { ![info exists _limits($tag)] } {
1811            set data [$dataobj blob $comp]
1812            set tmpfile file[pid].vtk
1813            set f [open "$tmpfile" "w"]
1814            fconfigure $f -translation binary -encoding binary
1815            puts $f $data
1816            close $f
1817            set reader [vtkDataSetReader $tag-xvtkDataSetReader]
1818            $reader SetFileName $tmpfile
1819            $reader ReadAllScalarsOn
1820            $reader ReadAllVectorsOn
1821            $reader ReadAllFieldsOn
1822            $reader Update
1823            set output [$reader GetOutput]
1824            set _limits($tag) [$output GetBounds]
1825            set pointData [$output GetPointData]
1826            puts stderr "\#scalars=[$reader GetNumberOfScalarsInFile]"
1827            puts stderr "\#fielddata=[$reader GetNumberOfFieldDataInFile]"
1828            puts stderr "fielddataname=[$reader GetFieldDataNameInFile 0]"
1829            set fieldData [$output GetFieldData]
1830            set pointData [$output GetPointData]
1831            puts stderr "field \#arrays=[$fieldData GetNumberOfArrays]"
1832            for { set i 0 } { $i < [$fieldData GetNumberOfArrays] } { incr i } {
1833                puts stderr [$fieldData GetArrayName $i]
1834            }
1835            puts stderr "point \#arrays=[$pointData GetNumberOfArrays]"
1836            for { set i 0 } { $i < [$pointData GetNumberOfArrays] } { incr i } {
1837                set name [$pointData GetArrayName $i]
1838                if { ![info exists _fields($name)] } {
1839                    $itk_component(field) choices insert end "$name" "$name"
1840                    set _fields($name) 1
1841                }
1842            }
1843            puts stderr "field \#components=[$fieldData GetNumberOfComponents]"
1844            puts stderr "point \#components=[$pointData GetNumberOfComponents]"
1845            puts stderr "field \#tuples=[$fieldData GetNumberOfTuples]"
1846            puts stderr "point \#tuples=[$pointData GetNumberOfTuples]"
1847            puts stderr "point \#scalars=[$pointData GetScalars]"
1848            puts stderr vectors=[$pointData GetVectors]
1849            rename $output ""
1850            rename $reader ""
1851            file delete $tmpfile
1852        }
1853        foreach { xMin xMax yMin yMax zMin zMax} $_limits($tag) break
1854        if {![info exists limits(xmin)] || $limits(xmin) > $xMin} {
1855            set limits(xmin) $xMin
1856        }
1857        if {![info exists limits(xmax)] || $limits(xmax) < $xMax} {
1858            set limits(xmax) $xMax
1859        }
1860        if {![info exists limits(ymin)] || $limits(ymin) > $yMin} {
1861            set limits(ymin) $xMin
1862        }
1863        if {![info exists limits(ymax)] || $limits(ymax) < $yMax} {
1864            set limits(ymax) $yMax
1865        }
1866        if {![info exists limits(zmin)] || $limits(zmin) > $zMin} {
1867            set limits(zmin) $zMin
1868        }
1869        if {![info exists limits(zmax)] || $limits(zmax) < $zMax} {
1870            set limits(zmax) $zMax
1871        }
1872    }
1873    return [array get limits]
1874}
1875
1876itcl::body Rappture::VtkVolumeViewer::BuildVolumeTab {} {
1877
1878    set fg [option get $itk_component(hull) font Font]
1879    #set bfg [option get $itk_component(hull) boldFont Font]
1880
1881    set inner [$itk_component(main) insert end \
1882        -title "Volume Settings" \
1883        -icon [Rappture::icon volume-on]]
1884    $inner configure -borderwidth 4
1885
1886    checkbutton $inner.volume \
1887        -text "Show Volume" \
1888        -variable [itcl::scope _settings(volume-visible)] \
1889        -command [itcl::code $this AdjustSetting volume-visible] \
1890        -font "Arial 9"
1891
1892    checkbutton $inner.lighting \
1893        -text "Enable Lighting" \
1894        -variable [itcl::scope _settings(volume-lighting)] \
1895        -command [itcl::code $this AdjustSetting volume-lighting] \
1896        -font "Arial 9"
1897
1898    label $inner.opacity_l -text "Opacity" -font "Arial 9"
1899    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1900        -variable [itcl::scope _settings(volume-opacity)] \
1901        -width 10 \
1902        -showvalue off \
1903        -command [itcl::code $this AdjustSetting volume-opacity]
1904
1905    label $inner.field_l -text "Field" -font "Arial 9"
1906    itk_component add field {
1907        Rappture::Combobox $inner.field -width 10 -editable no
1908    }
1909    bind $inner.field <<Value>> \
1910        [itcl::code $this AdjustSetting volume-field]
1911
1912    label $inner.palette_l -text "Palette" -font "Arial 9"
1913    itk_component add palette {
1914        Rappture::Combobox $inner.palette -width 10 -editable no
1915    }
1916    $inner.palette choices insert end \
1917        "BCGYR"              "BCGYR"            \
1918        "BGYOR"              "BGYOR"            \
1919        "blue"               "blue"             \
1920        "blue-to-brown"      "blue-to-brown"    \
1921        "blue-to-orange"     "blue-to-orange"   \
1922        "blue-to-grey"       "blue-to-grey"     \
1923        "green-to-magenta"   "green-to-magenta" \
1924        "greyscale"          "greyscale"        \
1925        "nanohub"            "nanohub"          \
1926        "rainbow"            "rainbow"          \
1927        "spectral"           "spectral"         \
1928        "ROYGB"              "ROYGB"            \
1929        "RYGCB"              "RYGCB"            \
1930        "brown-to-blue"      "brown-to-blue"    \
1931        "grey-to-blue"       "grey-to-blue"     \
1932        "orange-to-blue"     "orange-to-blue"   
1933
1934    $itk_component(palette) value "BCGYR"
1935    bind $inner.palette <<Value>> \
1936        [itcl::code $this AdjustSetting volume-palette]
1937
1938    blt::table $inner \
1939        0,0 $inner.volume    -anchor w -pady 2 \
1940        2,0 $inner.lighting  -anchor w -pady 2 \
1941        6,0 $inner.field_l     -anchor w -pady 2  \
1942        6,1 $inner.field       -anchor w -pady 2  \
1943        7,0 $inner.palette_l   -anchor w -pady 2  \
1944        7,1 $inner.palette     -anchor w -pady 2  \
1945
1946    blt::table configure $inner r* c* -resize none
1947    blt::table configure $inner r8 c1 -resize expand
1948}
1949
1950itcl::body Rappture::VtkVolumeViewer::BuildAxisTab {} {
1951
1952    set fg [option get $itk_component(hull) font Font]
1953    #set bfg [option get $itk_component(hull) boldFont Font]
1954
1955    set inner [$itk_component(main) insert end \
1956        -title "Axis Settings" \
1957        -icon [Rappture::icon axis1]]
1958    $inner configure -borderwidth 4
1959
1960    checkbutton $inner.visible \
1961        -text "Show Axes" \
1962        -variable [itcl::scope _settings(axis-visible)] \
1963        -command [itcl::code $this AdjustSetting axis-visible] \
1964        -font "Arial 9"
1965
1966    checkbutton $inner.labels \
1967        -text "Show Axis Labels" \
1968        -variable [itcl::scope _settings(axis-labels)] \
1969        -command [itcl::code $this AdjustSetting axis-labels] \
1970        -font "Arial 9"
1971
1972    checkbutton $inner.gridx \
1973        -text "Show X Grid" \
1974        -variable [itcl::scope _settings(axis-xgrid)] \
1975        -command [itcl::code $this AdjustSetting axis-xgrid] \
1976        -font "Arial 9"
1977    checkbutton $inner.gridy \
1978        -text "Show Y Grid" \
1979        -variable [itcl::scope _settings(axis-ygrid)] \
1980        -command [itcl::code $this AdjustSetting axis-ygrid] \
1981        -font "Arial 9"
1982    checkbutton $inner.gridz \
1983        -text "Show Z Grid" \
1984        -variable [itcl::scope _settings(axis-zgrid)] \
1985        -command [itcl::code $this AdjustSetting axis-zgrid] \
1986        -font "Arial 9"
1987
1988    label $inner.mode_l -text "Mode" -font "Arial 9"
1989
1990    itk_component add axismode {
1991        Rappture::Combobox $inner.mode -width 10 -editable no
1992    }
1993    $inner.mode choices insert end \
1994        "static_triad"    "static" \
1995        "closest_triad"   "closest" \
1996        "furthest_triad"  "furthest" \
1997        "outer_edges"     "outer"         
1998    $itk_component(axismode) value "static"
1999    bind $inner.mode <<Value>> [itcl::code $this AdjustSetting axis-mode]
2000
2001    blt::table $inner \
2002        0,0 $inner.visible -anchor w -cspan 2 \
2003        1,0 $inner.labels  -anchor w -cspan 2 \
2004        2,0 $inner.gridx   -anchor w -cspan 2 \
2005        3,0 $inner.gridy   -anchor w -cspan 2 \
2006        4,0 $inner.gridz   -anchor w -cspan 2 \
2007        5,0 $inner.mode_l  -anchor w -cspan 2 -padx { 2 0 } \
2008        6,0 $inner.mode    -fill x   -cspan 2
2009
2010    blt::table configure $inner r* c* -resize none
2011    blt::table configure $inner r7 c1 -resize expand
2012}
2013
2014
2015itcl::body Rappture::VtkVolumeViewer::BuildCameraTab {} {
2016    set inner [$itk_component(main) insert end \
2017        -title "Camera Settings" \
2018        -icon [Rappture::icon camera]]
2019    $inner configure -borderwidth 4
2020
2021    set labels { qx qy qz qw xpan ypan zoom }
2022    set row 0
2023    foreach tag $labels {
2024        label $inner.${tag}label -text $tag -font "Arial 9"
2025        entry $inner.${tag} -font "Arial 9"  -bg white \
2026            -textvariable [itcl::scope _view($tag)]
2027        bind $inner.${tag} <KeyPress-Return> \
2028            [itcl::code $this camera set ${tag}]
2029        blt::table $inner \
2030            $row,0 $inner.${tag}label -anchor e -pady 2 \
2031            $row,1 $inner.${tag} -anchor w -pady 2
2032        blt::table configure $inner r$row -resize none
2033        incr row
2034    }
2035    checkbutton $inner.ortho \
2036        -text "Orthographic Projection" \
2037        -variable [itcl::scope _view(ortho)] \
2038        -command [itcl::code $this camera set ortho] \
2039        -font "Arial 9"
2040    blt::table $inner \
2041            $row,0 $inner.ortho -columnspan 2 -anchor w -pady 2
2042    blt::table configure $inner r$row -resize none
2043    incr row
2044
2045    blt::table configure $inner c0 c1 -resize none
2046    blt::table configure $inner c2 -resize expand
2047    blt::table configure $inner r$row -resize expand
2048}
2049
2050itcl::body Rappture::VtkVolumeViewer::BuildCutplaneTab {} {
2051
2052    set fg [option get $itk_component(hull) font Font]
2053   
2054    set inner [$itk_component(main) insert end \
2055        -title "Cutplane Settings" \
2056        -icon [Rappture::icon cutbutton]]
2057
2058    $inner configure -borderwidth 4
2059
2060    checkbutton $inner.visible \
2061        -text "Show Cutplanes" \
2062        -variable [itcl::scope _settings(cutplane-visible)] \
2063        -command [itcl::code $this AdjustSetting cutplane-visible] \
2064        -font "Arial 9"
2065
2066    checkbutton $inner.wireframe \
2067        -text "Show Wireframe" \
2068        -variable [itcl::scope _settings(cutplane-wireframe)] \
2069        -command [itcl::code $this AdjustSetting cutplane-wireframe] \
2070        -font "Arial 9"
2071
2072    checkbutton $inner.lighting \
2073        -text "Enable Lighting" \
2074        -variable [itcl::scope _settings(cutplane-lighting)] \
2075        -command [itcl::code $this AdjustSetting cutplane-lighting] \
2076        -font "Arial 9"
2077
2078    checkbutton $inner.edges \
2079        -text "Show Edges" \
2080        -variable [itcl::scope _settings(cutplane-edges)] \
2081        -command [itcl::code $this AdjustSetting cutplane-edges] \
2082        -font "Arial 9"
2083
2084    label $inner.opacity_l -text "Opacity" -font "Arial 9"
2085    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
2086        -variable [itcl::scope _settings(cutplane-opacity)] \
2087        -width 10 \
2088        -showvalue off \
2089        -command [itcl::code $this AdjustSetting cutplane-opacity]
2090    $inner.opacity set $_settings(cutplane-opacity)
2091
2092    # X-value slicer...
2093    itk_component add xCutButton {
2094        Rappture::PushButton $inner.xbutton \
2095            -onimage [Rappture::icon x-cutplane] \
2096            -offimage [Rappture::icon x-cutplane] \
2097            -command [itcl::code $this AdjustSetting cutplane-xvisible] \
2098            -variable [itcl::scope _settings(cutplane-xvisible)]
2099    }
2100    Rappture::Tooltip::for $itk_component(xCutButton) \
2101        "Toggle the X-axis cutplane on/off"
2102
2103    itk_component add xCutScale {
2104        ::scale $inner.xval -from 100 -to 1 \
2105            -width 10 -orient vertical -showvalue yes \
2106            -borderwidth 1 -highlightthickness 0 \
2107            -command [itcl::code $this EventuallySetCutplane x] \
2108            -variable [itcl::scope _settings(cutplane-xposition)]
2109    } {
2110        usual
2111        ignore -borderwidth -highlightthickness
2112    }
2113    # Set the default cutplane value before disabling the scale.
2114    $itk_component(xCutScale) set 50
2115    $itk_component(xCutScale) configure -state disabled
2116    Rappture::Tooltip::for $itk_component(xCutScale) \
2117        "@[itcl::code $this Slice tooltip x]"
2118
2119    # Y-value slicer...
2120    itk_component add yCutButton {
2121        Rappture::PushButton $inner.ybutton \
2122            -onimage [Rappture::icon y-cutplane] \
2123            -offimage [Rappture::icon y-cutplane] \
2124            -command [itcl::code $this AdjustSetting cutplane-yvisible] \
2125            -variable [itcl::scope _settings(cutplane-yvisible)]
2126    }
2127    Rappture::Tooltip::for $itk_component(yCutButton) \
2128        "Toggle the Y-axis cutplane on/off"
2129
2130    itk_component add yCutScale {
2131        ::scale $inner.yval -from 100 -to 1 \
2132            -width 10 -orient vertical -showvalue yes \
2133            -borderwidth 1 -highlightthickness 0 \
2134            -command [itcl::code $this EventuallySetCutplane y] \
2135            -variable [itcl::scope _settings(cutplane-yposition)]
2136    } {
2137        usual
2138        ignore -borderwidth -highlightthickness
2139    }
2140    Rappture::Tooltip::for $itk_component(yCutScale) \
2141        "@[itcl::code $this Slice tooltip y]"
2142    # Set the default cutplane value before disabling the scale.
2143    $itk_component(yCutScale) set 50
2144    $itk_component(yCutScale) configure -state disabled
2145
2146    # Z-value slicer...
2147    itk_component add zCutButton {
2148        Rappture::PushButton $inner.zbutton \
2149            -onimage [Rappture::icon z-cutplane] \
2150            -offimage [Rappture::icon z-cutplane] \
2151            -command [itcl::code $this AdjustSetting cutplane-zvisible] \
2152            -variable [itcl::scope _settings(cutplane-zvisible)]
2153    }
2154    Rappture::Tooltip::for $itk_component(zCutButton) \
2155        "Toggle the Z-axis cutplane on/off"
2156
2157    itk_component add zCutScale {
2158        ::scale $inner.zval -from 100 -to 1 \
2159            -width 10 -orient vertical -showvalue yes \
2160            -borderwidth 1 -highlightthickness 0 \
2161            -command [itcl::code $this EventuallySetCutplane z] \
2162            -variable [itcl::scope _settings(cutplane-zposition)]
2163    } {
2164        usual
2165        ignore -borderwidth -highlightthickness
2166    }
2167    $itk_component(zCutScale) set 50
2168    $itk_component(zCutScale) configure -state disabled
2169    #$itk_component(zCutScale) configure -state disabled
2170    Rappture::Tooltip::for $itk_component(zCutScale) \
2171        "@[itcl::code $this Slice tooltip z]"
2172
2173    blt::table $inner \
2174        0,0 $inner.visible              -anchor w -pady 2 -cspan 4 \
2175        1,0 $inner.lighting             -anchor w -pady 2 -cspan 4 \
2176        2,0 $inner.wireframe            -anchor w -pady 2 -cspan 4 \
2177        3,0 $inner.edges                -anchor w -pady 2 -cspan 4 \
2178        4,0 $inner.opacity_l            -anchor w -pady 2 -cspan 3 \
2179        5,0 $inner.opacity              -fill x   -pady 2 -cspan 3 \
2180        6,0 $itk_component(xCutButton)  -anchor e -padx 2 -pady 2 \
2181        7,0 $itk_component(xCutScale)   -fill y \
2182        6,1 $itk_component(yCutButton)  -anchor e -padx 2 -pady 2 \
2183        7,1 $itk_component(yCutScale)   -fill y \
2184        6,2 $itk_component(zCutButton)  -anchor e -padx 2 -pady 2 \
2185        7,2 $itk_component(zCutScale)   -fill y \
2186
2187    blt::table configure $inner r* c* -resize none
2188    blt::table configure $inner r7 c3 -resize expand
2189}
2190
2191
2192
2193#
2194#  camera --
2195#
2196itcl::body Rappture::VtkVolumeViewer::camera {option args} {
2197    switch -- $option {
2198        "show" {
2199            puts [array get _view]
2200        }
2201        "set" {
2202            set who [lindex $args 0]
2203            set x $_view($who)
2204            set code [catch { string is double $x } result]
2205            if { $code != 0 || !$result } {
2206                return
2207            }
2208            switch -- $who {
2209                "ortho" {
2210                    if {$_view(ortho)} {
2211                        SendCmd "camera mode ortho"
2212                    } else {
2213                        SendCmd "camera mode persp"
2214                    }
2215                }
2216                "xpan" - "ypan" {
2217                    PanCamera
2218                }
2219                "qx" - "qy" - "qz" - "qw" {
2220                    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
2221                    $_arcball quaternion $q
2222                    EventuallyRotate $q
2223                }
2224                "zoom" {
2225                    SendCmd "camera zoom $_view(zoom)"
2226                }
2227            }
2228        }
2229    }
2230}
2231
2232itcl::body Rappture::VtkVolumeViewer::ConvertToVtkData { dataobj comp } {
2233    foreach { x1 x2 xN y1 y2 yN } [$dataobj mesh $comp] break
2234    set values [$dataobj values $comp]
2235    append out "# vtk DataFile Version 2.0 \n"
2236    append out "Test data \n"
2237    append out "ASCII \n"
2238    append out "DATASET STRUCTURED_POINTS \n"
2239    append out "DIMENSIONS $xN $yN 1 \n"
2240    append out "ORIGIN 0 0 0 \n"
2241    append out "SPACING 1 1 1 \n"
2242    append out "POINT_DATA [expr $xN * $yN] \n"
2243    append out "SCALARS field float 1 \n"
2244    append out "LOOKUP_TABLE default \n"
2245    append out [join $values "\n"]
2246    append out "\n"
2247    return $out
2248}
2249
2250
2251itcl::body Rappture::VtkVolumeViewer::GetVtkData { args } {
2252    set bytes ""
2253    foreach dataobj [get] {
2254        foreach comp [$dataobj components] {
2255            set tag $dataobj-$comp
2256            #set contents [ConvertToVtkData $dataobj $comp]
2257            set contents [$dataobj blob $comp]
2258            append bytes "$contents\n\n"
2259        }
2260    }
2261    return [list .vtk $bytes]
2262}
2263
2264itcl::body Rappture::VtkVolumeViewer::GetImage { args } {
2265    if { [image width $_image(download)] > 0 &&
2266         [image height $_image(download)] > 0 } {
2267        set bytes [$_image(download) data -format "jpeg -quality 100"]
2268        set bytes [Rappture::encoding::decode -as b64 $bytes]
2269        return [list .jpg $bytes]
2270    }
2271    return ""
2272}
2273
2274itcl::body Rappture::VtkVolumeViewer::BuildDownloadPopup { popup command } {
2275    Rappture::Balloon $popup \
2276        -title "[Rappture::filexfer::label downloadWord] as..."
2277    set inner [$popup component inner]
2278    label $inner.summary -text "" -anchor w
2279    radiobutton $inner.vtk_button -text "VTK data file" \
2280        -variable [itcl::scope _downloadPopup(format)] \
2281        -font "Helvetica 9 " \
2282        -value vtk 
2283    Rappture::Tooltip::for $inner.vtk_button "Save as VTK data file."
2284    radiobutton $inner.image_button -text "Image File" \
2285        -variable [itcl::scope _downloadPopup(format)] \
2286        -value image
2287    Rappture::Tooltip::for $inner.image_button \
2288        "Save as digital image."
2289
2290    button $inner.ok -text "Save" \
2291        -highlightthickness 0 -pady 2 -padx 3 \
2292        -command $command \
2293        -compound left \
2294        -image [Rappture::icon download]
2295
2296    button $inner.cancel -text "Cancel" \
2297        -highlightthickness 0 -pady 2 -padx 3 \
2298        -command [list $popup deactivate] \
2299        -compound left \
2300        -image [Rappture::icon cancel]
2301
2302    blt::table $inner \
2303        0,0 $inner.summary -cspan 2  \
2304        1,0 $inner.vtk_button -anchor w -cspan 2 -padx { 4 0 } \
2305        2,0 $inner.image_button -anchor w -cspan 2 -padx { 4 0 } \
2306        4,1 $inner.cancel -width .9i -fill y \
2307        4,0 $inner.ok -padx 2 -width .9i -fill y
2308    blt::table configure $inner r3 -height 4
2309    blt::table configure $inner r4 -pady 4
2310    raise $inner.image_button
2311    $inner.vtk_button invoke
2312    return $inner
2313}
2314
2315itcl::body Rappture::VtkVolumeViewer::SetObjectStyle { dataobj comp } {
2316    # Parse style string.
2317    set tag $dataobj-$comp
2318    set style [$dataobj style $comp]
2319    array set settings {
2320        -color \#808080
2321        -edges 0
2322        -edgecolor black
2323        -linewidth 1.0
2324        -opacity 0.4
2325        -wireframe 0
2326        -lighting 1
2327        -seeds 1
2328        -seedcolor white
2329        -visible 1
2330    }
2331    if { $dataobj != $_first } {
2332        set settings(-opacity) 1
2333    }
2334    array set settings $style
2335    SendCmd "volume add $tag"
2336    SendCmd "cutplane add $tag"
2337    SendCmd "cutplane edges 0 $tag"
2338    SendCmd "cutplane wireframe 0 $tag"
2339    SendCmd "cutplane lighting 1 $tag"
2340    SendCmd "cutplane linewidth 1 $tag"
2341    #SendCmd "cutplane linecolor 1 1 1 $tag"
2342    #SendCmd "cutplane visible $tag"
2343    foreach axis { x y z } {
2344        SendCmd "cutplane slice $axis 1.0 $tag"
2345        SendCmd "cutplane axis $axis 0 $tag"
2346    }
2347
2348    SendCmd "volume lighting $settings(-lighting) $tag"
2349    set _settings(volume-lighting) $settings(-lighting)
2350    SetColormap $dataobj $comp
2351}
2352
2353itcl::body Rappture::VtkVolumeViewer::IsValidObject { dataobj } {
2354    if {[catch {$dataobj isa Rappture::Field} valid] != 0 || !$valid} {
2355        return 0
2356    }
2357    return 1
2358}
2359
2360# ----------------------------------------------------------------------
2361# USAGE: ReceiveLegend <colormap> <title> <vmin> <vmax> <size>
2362#
2363# Invoked automatically whenever the "legend" command comes in from
2364# the rendering server.  Indicates that binary image data with the
2365# specified <size> will follow.
2366# ----------------------------------------------------------------------
2367itcl::body Rappture::VtkVolumeViewer::ReceiveLegend { colormap title vmin vmax size } {
2368    set _legendPending 0
2369    puts stderr "ReceiveLegend colormap=$colormap title=$title range=$vmin,$vmax size=$size"
2370    set _limits(vmin) $vmin
2371    set _limits(vmax) $vmax
2372    set _title $title
2373    regsub {\(mag\)} $title "" _title
2374    if { [IsConnected] } {
2375        set bytes [ReceiveBytes $size]
2376        if { ![info exists _image(legend)] } {
2377            set _image(legend) [image create photo]
2378        }
2379        $_image(legend) configure -data $bytes
2380        #puts stderr "read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
2381        if { [catch {DrawLegend $_title} errs] != 0 } {
2382            puts stderr errs=$errs
2383        }
2384    }
2385}
2386
2387#
2388# DrawLegend --
2389#
2390#       Draws the legend in it's own canvas which resides to the right
2391#       of the contour plot area.
2392#
2393itcl::body Rappture::VtkVolumeViewer::DrawLegend { name } {
2394    set c $itk_component(view)
2395    set w [winfo width $c]
2396    set h [winfo height $c]
2397    set font "Arial 8"
2398    set lineht [font metrics $font -linespace]
2399   
2400    if { [info exists _fields($name)] } {
2401        foreach { title units } $_fields($name) break
2402        if { $units != "" } {
2403            set title [format "%s (%s)" $title $units]
2404        }
2405    } else {
2406        set title $name
2407    }
2408    if { $_settings(legend-visible) } {
2409        set x [expr $w - 2]
2410        if { [$c find withtag "legend"] == "" } {
2411            set y 2
2412            $c create text $x $y \
2413                -anchor ne \
2414                -fill $itk_option(-plotforeground) -tags "title legend" \
2415                -font $font
2416            incr y $lineht
2417            $c create text $x $y \
2418                -anchor ne \
2419                -fill $itk_option(-plotforeground) -tags "vmax legend" \
2420                -font $font
2421            incr y $lineht
2422            $c create image $x $y \
2423                -anchor ne \
2424                -image $_image(legend) -tags "colormap legend"
2425            $c create text $x [expr {$h-2}] \
2426                -anchor se \
2427                -fill $itk_option(-plotforeground) -tags "vmin legend" \
2428                -font $font
2429            #$c bind colormap <Enter> [itcl::code $this EnterLegend %x %y]
2430            $c bind colormap <Leave> [itcl::code $this LeaveLegend]
2431            $c bind colormap <Motion> [itcl::code $this MotionLegend %x %y]
2432        }
2433        $c bind title <ButtonPress> [itcl::code $this Combo post]
2434        $c bind title <Enter> [itcl::code $this Combo activate]
2435        $c bind title <Leave> [itcl::code $this Combo deactivate]
2436        # Reset the item coordinates according the current size of the plot.
2437        $c itemconfigure title -text $title
2438        if { $_limits(vmin) != "" } {
2439            $c itemconfigure vmin -text [format %g $_limits(vmin)]
2440        }
2441        if { $_limits(vmax) != "" } {
2442            $c itemconfigure vmax -text [format %g $_limits(vmax)]
2443        }
2444        set y 2
2445        $c coords title $x $y
2446        incr y $lineht
2447        $c coords vmax $x $y
2448        incr y $lineht
2449        $c coords colormap $x $y
2450        $c coords vmin $x [expr {$h - 2}]
2451    }
2452}
2453
2454#
2455# EnterLegend --
2456#
2457itcl::body Rappture::VtkVolumeViewer::EnterLegend { x y } {
2458    SetLegendTip $x $y
2459}
2460
2461#
2462# MotionLegend --
2463#
2464itcl::body Rappture::VtkVolumeViewer::MotionLegend { x y } {
2465    Rappture::Tooltip::tooltip cancel
2466    set c $itk_component(view)
2467    SetLegendTip $x $y
2468}
2469
2470#
2471# LeaveLegend --
2472#
2473itcl::body Rappture::VtkVolumeViewer::LeaveLegend { } {
2474    Rappture::Tooltip::tooltip cancel
2475    .rappturetooltip configure -icon ""
2476}
2477
2478#
2479# SetLegendTip --
2480#
2481itcl::body Rappture::VtkVolumeViewer::SetLegendTip { x y } {
2482    set c $itk_component(view)
2483    set w [winfo width $c]
2484    set h [winfo height $c]
2485    set font "Arial 8"
2486    set lineht [font metrics $font -linespace]
2487   
2488    set imgHeight [image height $_image(legend)]
2489    set coords [$c coords colormap]
2490    set imgX [expr $w - [image width $_image(legend)] - 2]
2491    set imgY [expr $y - 2 * ($lineht + 2)]
2492
2493    if { [info exists _fields($_title)] } {
2494        foreach { title units } $_fields($_title) break
2495        if { $units != "" } {
2496            set title [format "%s (%s)" $title $units]
2497        }
2498    } else {
2499        set title $_title
2500    }
2501    # Make a swatch of the selected color
2502    if { [catch { $_image(legend) get 10 $imgY } pixel] != 0 } {
2503        #puts stderr "out of range: $imgY"
2504        return
2505    }
2506    if { ![info exists _image(swatch)] } {
2507        set _image(swatch) [image create photo -width 24 -height 24]
2508    }
2509    set color [eval format "\#%02x%02x%02x" $pixel]
2510    $_image(swatch) put black  -to 0 0 23 23
2511    $_image(swatch) put $color -to 1 1 22 22
2512    .rappturetooltip configure -icon $_image(swatch)
2513
2514    # Compute the value of the point
2515    if { [info exists _limits(vmax)] && [info exists _limits(vmin)] } {
2516        set t [expr 1.0 - (double($imgY) / double($imgHeight-1))]
2517        set value [expr $t * ($_limits(vmax) - $_limits(vmin)) + $_limits(vmin)]
2518    } else {
2519        set value 0.0
2520    }
2521    set tipx [expr $x + 15]
2522    set tipy [expr $y - 5]
2523    Rappture::Tooltip::text $c "$title $value"
2524    Rappture::Tooltip::tooltip show $c +$tipx,+$tipy   
2525}
2526
2527
2528# ----------------------------------------------------------------------
2529# USAGE: Slice move x|y|z <newval>
2530#
2531# Called automatically when the user drags the slider to move the
2532# cut plane that slices 3D data.  Gets the current value from the
2533# slider and moves the cut plane to the appropriate point in the
2534# data set.
2535# ----------------------------------------------------------------------
2536itcl::body Rappture::VtkVolumeViewer::Slice {option args} {
2537    switch -- $option {
2538        "move" {
2539            set axis [lindex $args 0]
2540            set oldval $_settings(axis-${axis}position)
2541            set newval [lindex $args 1]
2542            if {[llength $args] != 2} {
2543                error "wrong # args: should be \"Slice move x|y|z newval\""
2544            }
2545            set newpos [expr {0.01*$newval}]
2546            SendCmd "cutplane slice $axis $newpos"
2547        }
2548        "tooltip" {
2549            set axis [lindex $args 0]
2550            set val [$itk_component(${axis}CutScale) get]
2551            return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
2552        }
2553        default {
2554            error "bad option \"$option\": should be axis, move, or tooltip"
2555        }
2556    }
2557}
2558
2559
2560# ----------------------------------------------------------------------
2561# USAGE: _dropdown post
2562# USAGE: _dropdown unpost
2563# USAGE: _dropdown select
2564#
2565# Used internally to handle the dropdown list for this combobox.  The
2566# post/unpost options are invoked when the list is posted or unposted
2567# to manage the relief of the controlling button.  The select option
2568# is invoked whenever there is a selection from the list, to assign
2569# the value back to the gauge.
2570# ----------------------------------------------------------------------
2571itcl::body Rappture::VtkVolumeViewer::Combo {option} {
2572    set c $itk_component(view)
2573    switch -- $option {
2574        post {
2575            foreach { x1 y1 x2 y2 } [$c bbox title] break
2576            set x1 [expr [winfo width $itk_component(view)] - [winfo reqwidth $itk_component(fieldmenu)]]
2577            set x [expr $x1 + [winfo rootx $itk_component(view)]]
2578            set y [expr $y2 + [winfo rooty $itk_component(view)]]
2579            puts stderr "combo x=$x y=$y"
2580            tk_popup $itk_component(fieldmenu) $x $y
2581        }
2582        activate {
2583            $c itemconfigure title -fill red
2584        }
2585        deactivate {
2586            $c itemconfigure title -fill white
2587        }
2588        invoke {
2589            $itk_component(field) value $_currentField
2590            AdjustSetting volume-field
2591        }
2592        default {
2593            error "bad option \"$option\": should be post, unpost, select"
2594        }
2595    }
2596}
Note: See TracBrowser for help on using the repository browser.