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

Last change on this file since 3395 was 3395, checked in by ldelgass, 11 years ago

standardize default colormap

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