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

Last change on this file since 3421 was 3421, checked in by gah, 12 years ago

push SendCmd? into base class w/ buffering

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