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

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

Fixes for dataobj delete in VTK viewers:

  • Don't hide datasets from delete method since it isn't buffered and causes

flashes

  • Don't keep deleted dataobjs in _dlist: the commands are no longer valid even

though server objects remain. FIXME: should delete server objects or reuse
dataobj names for results, as we leak server datasets when user clears
datasets. However, we don't want to delete hidden sequence elts.

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