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

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

Remove camera reset on resize from streamlines,vtk mesh/polydata viewers

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