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

Last change on this file since 2754 was 2754, checked in by ldelgass, 13 years ago

Use opaque colormap for cutplanes

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