source: branches/1.4/gui/scripts/vtkvolumeviewer.tcl @ 5226

Last change on this file since 5226 was 5226, checked in by ldelgass, 6 years ago

whitespace

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