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

Last change on this file since 4750 was 4750, checked in by ldelgass, 9 years ago

merge r4749 from trunk

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