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

Last change on this file since 3765 was 3765, checked in by gah, 11 years ago

fix drawing default coordinates, rewrite of xyresult scaling, sync with trunk

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