source: trunk/gui/scripts/flowvisviewer.tcl @ 5642

Last change on this file since 5642 was 5642, checked in by ldelgass, 9 years ago

Don't need to rely on nanovis to return limits any more, so cleanup some old
code. Also sync up nanovis and flowvis viewers.

File size: 101.0 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: flowvisviewer - 3D flow rendering
4#
5#  This widget performs volume and flow rendering on 3D scalar/vector datasets.
6#  It connects to the Nanovis 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
17package require Img
18
19option add *FlowvisViewer.width 5i widgetDefault
20option add *FlowvisViewer*cursor crosshair widgetDefault
21option add *FlowvisViewer.height 4i widgetDefault
22option add *FlowvisViewer.foreground black widgetDefault
23option add *FlowvisViewer.controlBackground gray widgetDefault
24option add *FlowvisViewer.controlDarkBackground #999999 widgetDefault
25option add *FlowvisViewer.plotBackground black widgetDefault
26option add *FlowvisViewer.plotForeground white widgetDefault
27option add *FlowvisViewer.plotOutline gray widgetDefault
28option add *FlowvisViewer.font \
29    -*-helvetica-medium-r-normal-*-12-* widgetDefault
30
31# must use this name -- plugs into Rappture::resources::load
32proc FlowvisViewer_init_resources {} {
33    Rappture::resources::register \
34        nanovis_server Rappture::FlowvisViewer::SetServerList
35}
36
37itcl::class Rappture::FlowvisViewer {
38    inherit Rappture::VisViewer
39
40    itk_option define -plotforeground plotForeground Foreground ""
41    itk_option define -plotbackground plotBackground Background ""
42    itk_option define -plotoutline plotOutline PlotOutline ""
43
44    constructor { hostlist args } {
45        Rappture::VisViewer::constructor $hostlist
46    } {
47        # defined below
48    }
49    destructor {
50        # defined below
51    }
52    public proc SetServerList { namelist } {
53        Rappture::VisViewer::SetServerList "nanovis" $namelist
54    }
55    public method add {dataobj {settings ""}}
56    public method camera {option args}
57    public method delete {args}
58    public method disconnect {}
59    public method download {option args}
60    public method flow {option}
61    public method get {args}
62    public method isconnected {}
63    public method limits { cname }
64    public method overMarker { m x }
65    public method parameters {title args} {
66        # do nothing
67    }
68    public method removeDuplicateMarker { m x }
69    public method scale {args}
70    public method updateTransferFunctions {}
71
72    # The following methods are only used by this class.
73    private method AddIsoMarker { x y }
74    private method AdjustSetting {what {value ""}}
75    private method BuildCameraTab {}
76    private method BuildCutplanesTab {}
77    private method BuildDownloadPopup { widget command }
78    private method BuildViewTab {}
79    private method BuildVolumeComponents {}
80    private method BuildVolumeTab {}
81    private method ComputeTransferFunction { tf }
82    private method Connect {}
83    private method CurrentDatasets {{what -all}}
84    private method Disconnect {}
85    private method DoResize {}
86    private method DrawLegend { tf }
87    private method EventuallyGoto { nSteps }
88    private method EventuallyRedrawLegend { }
89    private method EventuallyResize { w h }
90    private method FixLegend {}
91    private method GetDatasetsWithComponent { cname }
92    private method GetFlowInfo { widget }
93    private method GetImage { args }
94    private method GetMovie { widget width height }
95    private method GetPngImage { widget width height }
96    private method GetVtkData { args }
97    private method InitSettings { args }
98    private method NameTransferFunction { dataobj comp }
99    private method Pan {option x y}
100    private method PanCamera {}
101    private method ParseLevelsOption { tf levels }
102    private method ParseMarkersOption { tf markers }
103    private method QuaternionToView { q } {
104        foreach { _view(-qw) _view(-qx) _view(-qy) _view(-qz) } $q break
105    }
106    private method Rebuild {}
107    private method ReceiveData { args }
108    private method ReceiveImage { args }
109    private method ReceiveLegend { tf vmin vmax size }
110    private method Rotate {option x y}
111    private method SendFlowCmd { dataobj comp nbytes numComponents }
112    private method SendTransferFunctions {}
113    private method SetOrientation { side }
114    private method Slice {option args}
115    private method SlicerTip {axis}
116    private method ViewToQuaternion {} {
117        return [list $_view(-qw) $_view(-qx) $_view(-qy) $_view(-qz)]
118    }
119    private method WaitIcon { option widget }
120    private method Zoom {option}
121    private method arrows { tag name }
122    private method box { tag name }
123    private method millisecs2str { value }
124    private method particles { tag name }
125    private method str2millisecs { value }
126    private method streams { tag name }
127
128    private variable _arcball ""
129    private variable _dlist ""         ;# list of data objects
130    private variable _obj2ovride       ;# maps dataobj => style override
131    private variable _datasets         ;# contains all the dataobj-component
132                                       ;# to volumes in the server
133    private variable _dataset2style    ;# maps dataobj-component to transfunc
134    private variable _style2datasets   ;# maps tf back to list of
135                                       ;# dataobj-components using the tf.
136    private variable _dataset2flow     ;# Maps dataobj-component to a flow.
137
138    private variable _reset 1          ;# Connection to server has been reset.
139    private variable _click            ;# Info used for rotate operations.
140    private variable _limits           ;# Autoscale min/max for all axes
141    private variable _view             ;# View params for 3D view
142    private variable _isomarkers       ;# array of isosurface level values 0..1
143    private variable _settings
144    private variable _activeTf ""      ;# Currently active transfer function
145    private variable _first ""         ;# This is the topmost volume.
146    private variable _volcomponents    ;# Maps component name to list of
147                                       ;# dataobj-component tags
148    private variable _componentsList   ;# List of components found
149    private variable _nextToken 0
150    private variable _icon 0
151    private variable _flow
152    private variable _width 0
153    private variable _height 0
154    private variable _resizePending 0
155    private variable _resizeLegendPending 0
156    private variable _gotoPending 0
157
158    private common _downloadPopup      ;# download options from popup
159    private common _hardcopy
160}
161
162itk::usual FlowvisViewer {
163    keep -background -foreground -cursor -font
164    keep -plotbackground -plotforeground
165}
166
167# ----------------------------------------------------------------------
168# CONSTRUCTOR
169# ----------------------------------------------------------------------
170itcl::body Rappture::FlowvisViewer::constructor {hostlist args} {
171    set _serverType "nanovis"
172
173    # Draw legend event
174    $_dispatcher register !legend
175    $_dispatcher dispatch $this !legend "[itcl::code $this FixLegend]; list"
176
177    # Send transfer functions event
178    $_dispatcher register !send_transfunc
179    $_dispatcher dispatch $this !send_transfunc \
180        "[itcl::code $this SendTransferFunctions]; list"
181
182    # Rebuild event
183    $_dispatcher register !rebuild
184    $_dispatcher dispatch $this !rebuild "[itcl::code $this Rebuild]; list"
185
186    # Resize event
187    $_dispatcher register !resize
188    $_dispatcher dispatch $this !resize "[itcl::code $this DoResize]; list"
189
190    $_dispatcher register !play
191    $_dispatcher dispatch $this !play "[itcl::code $this flow next]; list"
192
193    $_dispatcher register !goto
194    $_dispatcher dispatch $this !goto "[itcl::code $this flow goto2]; list"
195
196    $_dispatcher register !movietimeout
197    $_dispatcher register !waiticon
198
199    set _flow(state) 0
200
201    array set _downloadPopup {
202        format vtk
203    }
204    #
205    # Populate parser with commands handle incoming requests
206    #
207    $_parser alias image [itcl::code $this ReceiveImage]
208    $_parser alias legend [itcl::code $this ReceiveLegend]
209    $_parser alias data [itcl::code $this ReceiveData]
210
211    # Initialize the view to some default parameters.
212    array set _view {
213        -qw      0.853553
214        -qx      -0.353553
215        -qy      0.353553
216        -qz      0.146447
217        -xpan    0
218        -ypan    0
219        -zoom    1.0
220    }
221    set _arcball [blt::arcball create 100 100]
222    $_arcball quaternion [ViewToQuaternion]
223
224    set _reset 1
225
226    array set _settings [subst {
227        -ambient                60
228        -arrows                 0
229        -axesvisible            0
230        -background             black
231        -colormap               BCGYR
232        -currenttime            0
233        -cutplanesvisible       0
234        -diffuse                40
235        -duration               1:00
236        -gridvisible            0
237        -isosurfaceshading      0
238        -legendvisible          1
239        -lic                    1
240        -light2side             1
241        -loop                   0
242        -opacity                50
243        -outlinevisible         1
244        -particles              1
245        -play                   0
246        -qw                     $_view(-qw)
247        -qx                     $_view(-qx)
248        -qy                     $_view(-qy)
249        -qz                     $_view(-qz)
250        -specularexponent       90
251        -specularlevel          30
252        -speed                  500
253        -step                   0
254        -streams                0
255        -thickness              350
256        -volume                 1
257        -xcutplaneposition      50
258        -xcutplanevisible       1
259        -xpan                   $_view(-xpan)
260        -ycutplaneposition      50
261        -ycutplanevisible       1
262        -ypan                   $_view(-ypan)
263        -zcutplaneposition      50
264        -zcutplanevisible       1
265        -zoom                   $_view(-zoom)
266    }]
267
268    itk_component add 3dview {
269        label $itk_component(plotarea).view -image $_image(plot) \
270            -highlightthickness 0 -borderwidth 0
271    } {
272        usual
273        ignore -highlightthickness -borderwidth  -background
274    }
275    bind $itk_component(3dview) <Control-F1> [itcl::code $this ToggleConsole]
276
277    set f [$itk_component(main) component controls]
278    itk_component add reset {
279        button $f.reset -borderwidth 1 -padx 1 -pady 1 \
280            -highlightthickness 0 \
281            -image [Rappture::icon reset-view] \
282            -command [itcl::code $this Zoom reset]
283    } {
284        usual
285        ignore -highlightthickness
286    }
287    pack $itk_component(reset) -side top -padx 2 -pady 2
288    Rappture::Tooltip::for $itk_component(reset) \
289        "Reset the view to the default zoom level"
290
291    itk_component add zoomin {
292        button $f.zin -borderwidth 1 -padx 1 -pady 1 \
293            -highlightthickness 0 \
294            -image [Rappture::icon zoom-in] \
295            -command [itcl::code $this Zoom in]
296    } {
297        usual
298        ignore -highlightthickness
299    }
300    pack $itk_component(zoomin) -side top -padx 2 -pady 2
301    Rappture::Tooltip::for $itk_component(zoomin) "Zoom in"
302
303    itk_component add zoomout {
304        button $f.zout -borderwidth 1 -padx 1 -pady 1 \
305            -highlightthickness 0 \
306            -image [Rappture::icon zoom-out] \
307            -command [itcl::code $this Zoom out]
308    } {
309        usual
310        ignore -highlightthickness
311    }
312    pack $itk_component(zoomout) -side top -padx 2 -pady 2
313    Rappture::Tooltip::for $itk_component(zoomout) "Zoom out"
314
315    itk_component add volume {
316        Rappture::PushButton $f.volume \
317            -onimage [Rappture::icon volume-on] \
318            -offimage [Rappture::icon volume-off] \
319            -command [itcl::code $this AdjustSetting -volume] \
320            -variable [itcl::scope _settings(-volume)]
321    }
322    $itk_component(volume) select
323    Rappture::Tooltip::for $itk_component(volume) \
324        "Toggle the volume cloud on/off"
325    pack $itk_component(volume) -padx 2 -pady 2
326
327    itk_component add cutplane {
328        Rappture::PushButton $f.cutplane \
329            -onimage [Rappture::icon cutbutton] \
330            -offimage [Rappture::icon cutbutton] \
331            -variable [itcl::scope _settings(-cutplanesvisible)] \
332            -command [itcl::code $this AdjustSetting -cutplanesvisible]
333    }
334    Rappture::Tooltip::for $itk_component(cutplane) \
335        "Show/Hide cutplanes"
336    pack $itk_component(cutplane) -padx 2 -pady 2
337
338    if { [catch {
339        BuildViewTab
340        BuildVolumeTab
341        BuildCutplanesTab
342        BuildCameraTab
343    } errs] != 0 } {
344        global errorInfo
345        puts stderr "errs=$errs errorInfo=$errorInfo"
346    }
347
348    # Legend
349    set _image(legend) [image create photo]
350    itk_component add legend {
351        canvas $itk_component(plotarea).legend -height 50 -highlightthickness 0
352    } {
353        usual
354        ignore -highlightthickness
355        rename -background -plotbackground plotBackground Background
356    }
357    bind $itk_component(legend) <Configure> \
358        [itcl::code $this EventuallyRedrawLegend]
359
360    # Hack around the Tk panewindow.  The problem is that the requested
361    # size of the 3d view isn't set until an image is retrieved from
362    # the server.  So the panewindow uses the tiny size.
363    set w 10000
364    pack forget $itk_component(3dview)
365    blt::table $itk_component(plotarea) \
366        0,0 $itk_component(3dview) -fill both -reqwidth $w \
367        1,0 $itk_component(legend) -fill x
368    blt::table configure $itk_component(plotarea) r1 -resize none
369
370    # Create flow controls...
371    itk_component add flowcontrols {
372        frame $itk_interior.flowcontrols
373    } {
374        usual
375        rename -background -controlbackground controlBackground Background
376    }
377    pack forget $itk_component(main)
378    blt::table $itk_interior \
379        0,0 $itk_component(main) -fill both  \
380        1,0 $itk_component(flowcontrols) -fill x
381    blt::table configure $itk_interior r1 -resize none
382
383    # Rewind
384    itk_component add rewind {
385        button $itk_component(flowcontrols).reset \
386            -borderwidth 1 -padx 1 -pady 1 \
387            -image [Rappture::icon flow-rewind] \
388            -command [itcl::code $this flow reset]
389    } {
390        usual
391        ignore -borderwidth
392        rename -highlightbackground -controlbackground controlBackground \
393            Background
394    }
395    Rappture::Tooltip::for $itk_component(rewind) \
396        "Rewind flow"
397
398    # Stop
399    itk_component add stop {
400        button $itk_component(flowcontrols).stop \
401            -borderwidth 1 -padx 1 -pady 1 \
402            -image [Rappture::icon flow-stop] \
403            -command [itcl::code $this flow stop]
404    } {
405        usual
406        ignore -borderwidth
407        rename -highlightbackground -controlbackground controlBackground \
408            Background
409    }
410    Rappture::Tooltip::for $itk_component(stop) \
411        "Stop flow"
412
413    # Play
414    itk_component add play {
415        Rappture::PushButton $itk_component(flowcontrols).play \
416            -onimage [Rappture::icon flow-pause] \
417            -offimage [Rappture::icon flow-play] \
418            -variable [itcl::scope _settings(-play)] \
419            -command [itcl::code $this flow toggle]
420    }
421    set fg [option get $itk_component(hull) font Font]
422    Rappture::Tooltip::for $itk_component(play) \
423        "Play/Pause flow"
424
425    # Loop
426    itk_component add loop {
427        Rappture::PushButton $itk_component(flowcontrols).loop \
428            -onimage [Rappture::icon flow-loop] \
429            -offimage [Rappture::icon flow-loop] \
430            -variable [itcl::scope _settings(-loop)]
431    }
432    Rappture::Tooltip::for $itk_component(loop) \
433        "Play continuously"
434
435    itk_component add dial {
436        Rappture::Flowdial $itk_component(flowcontrols).dial \
437            -length 10 -valuewidth 0 -valuepadding 0 -padding 6 \
438            -linecolor "" -activelinecolor "" \
439            -min 0.0 -max 1.0 \
440            -variable [itcl::scope _settings(-currenttime)] \
441            -knobimage [Rappture::icon knob2] -knobposition center@middle
442    } {
443        usual
444        ignore -dialprogresscolor
445        rename -background -controlbackground controlBackground Background
446    }
447    $itk_component(dial) current 0.0
448    bind $itk_component(dial) <<Value>> [itcl::code $this flow goto]
449    # Duration
450    itk_component add duration {
451        entry $itk_component(flowcontrols).duration \
452            -textvariable [itcl::scope _settings(-duration)] \
453            -bg white -width 6 -font "arial 9"
454    } {
455        usual
456        ignore -highlightthickness -background
457    }
458    bind $itk_component(duration) <Return> [itcl::code $this flow duration]
459    bind $itk_component(duration) <KP_Enter> [itcl::code $this flow duration]
460    bind $itk_component(duration) <Tab> [itcl::code $this flow duration]
461    Rappture::Tooltip::for $itk_component(duration) \
462        "Set duration of flow (format is min:sec)"
463
464    itk_component add durationlabel {
465        label $itk_component(flowcontrols).durationl \
466            -text "Duration:" -font $fg \
467            -highlightthickness 0
468    } {
469        usual
470        ignore -highlightthickness
471        rename -background -controlbackground controlBackground Background
472    }
473
474    itk_component add speedlabel {
475        label $itk_component(flowcontrols).speedl -text "Speed:" -font $fg \
476            -highlightthickness 0
477    } {
478        usual
479        ignore -highlightthickness
480        rename -background -controlbackground controlBackground Background
481    }
482
483    # Speed
484    itk_component add speed {
485        Rappture::Flowspeed $itk_component(flowcontrols).speed \
486            -min 1 -max 10 -width 3 -font "arial 9"
487    } {
488        usual
489        ignore -highlightthickness
490        rename -background -controlbackground controlBackground Background
491    }
492    Rappture::Tooltip::for $itk_component(speed) \
493        "Change speed of flow"
494
495    $itk_component(speed) value 1
496    bind $itk_component(speed) <<Value>> [itcl::code $this flow speed]
497
498
499    blt::table $itk_component(flowcontrols) \
500        0,0 $itk_component(rewind) -padx {3 0} \
501        0,1 $itk_component(stop) -padx {2 0} \
502        0,2 $itk_component(play) -padx {2 0} \
503        0,3 $itk_component(loop) -padx {2 0} \
504        0,4 $itk_component(dial) -fill x -padx {2 0 } \
505        0,5 $itk_component(duration) -padx { 0 0} \
506        0,7 $itk_component(speed) -padx {2 3}
507
508#        0,6 $itk_component(speedlabel) -padx {2 0}
509    blt::table configure $itk_component(flowcontrols) c* -resize none
510    blt::table configure $itk_component(flowcontrols) c4 -resize both
511    blt::table configure $itk_component(flowcontrols) r0 -pady 1
512    # Bindings for rotation via mouse
513    bind $itk_component(3dview) <ButtonPress-1> \
514        [itcl::code $this Rotate click %x %y]
515    bind $itk_component(3dview) <B1-Motion> \
516        [itcl::code $this Rotate drag %x %y]
517    bind $itk_component(3dview) <ButtonRelease-1> \
518        [itcl::code $this Rotate release %x %y]
519
520    bind $itk_component(3dview) <Configure> \
521        [itcl::code $this EventuallyResize %w %h]
522
523    # Bindings for panning via mouse
524    bind $itk_component(3dview) <ButtonPress-2> \
525        [itcl::code $this Pan click %x %y]
526    bind $itk_component(3dview) <B2-Motion> \
527        [itcl::code $this Pan drag %x %y]
528    bind $itk_component(3dview) <ButtonRelease-2> \
529        [itcl::code $this Pan release %x %y]
530
531    # Bindings for panning via keyboard
532    bind $itk_component(3dview) <KeyPress-Left> \
533        [itcl::code $this Pan set -10 0]
534    bind $itk_component(3dview) <KeyPress-Right> \
535        [itcl::code $this Pan set 10 0]
536    bind $itk_component(3dview) <KeyPress-Up> \
537        [itcl::code $this Pan set 0 -10]
538    bind $itk_component(3dview) <KeyPress-Down> \
539        [itcl::code $this Pan set 0 10]
540    bind $itk_component(3dview) <Shift-KeyPress-Left> \
541        [itcl::code $this Pan set -2 0]
542    bind $itk_component(3dview) <Shift-KeyPress-Right> \
543        [itcl::code $this Pan set 2 0]
544    bind $itk_component(3dview) <Shift-KeyPress-Up> \
545        [itcl::code $this Pan set 0 -2]
546    bind $itk_component(3dview) <Shift-KeyPress-Down> \
547        [itcl::code $this Pan set 0 2]
548
549    # Bindings for zoom via keyboard
550    bind $itk_component(3dview) <KeyPress-Prior> \
551        [itcl::code $this Zoom out]
552    bind $itk_component(3dview) <KeyPress-Next> \
553        [itcl::code $this Zoom in]
554
555    bind $itk_component(3dview) <Enter> "focus $itk_component(3dview)"
556
557    if {[string equal "x11" [tk windowingsystem]]} {
558        # Bindings for zoom via mouse
559        bind $itk_component(3dview) <4> [itcl::code $this Zoom out]
560        bind $itk_component(3dview) <5> [itcl::code $this Zoom in]
561    }
562
563    set _image(download) [image create photo]
564
565    eval itk_initialize $args
566
567    EnableWaitDialog 900
568    Connect
569}
570
571# ----------------------------------------------------------------------
572# DESTRUCTOR
573# ----------------------------------------------------------------------
574itcl::body Rappture::FlowvisViewer::destructor {} {
575    $_dispatcher cancel !rebuild
576    $_dispatcher cancel !send_transfunc
577    $_dispatcher cancel !resize
578    image delete $_image(plot)
579    image delete $_image(legend)
580    image delete $_image(download)
581    catch { blt::arcball destroy $_arcball }
582    array unset _settings
583}
584
585# ----------------------------------------------------------------------
586# USAGE: add <dataobj> ?<settings>?
587#
588# Clients use this to add a data object to the plot.  The optional
589# <settings> are used to configure the plot.  Allowed settings are
590# -color, -brightness, -width, -linestyle, and -raise.
591# ----------------------------------------------------------------------
592itcl::body Rappture::FlowvisViewer::add {dataobj {settings ""}} {
593    if { ![$dataobj isvalid] } {
594        return;                         # Object doesn't contain valid data.
595    }
596    array set params {
597        -color auto
598        -width 1
599        -linestyle solid
600        -brightness 0
601        -raise 0
602        -description ""
603        -param ""
604    }
605    array set params $settings
606
607    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
608        # can't handle -autocolors yet
609        set params(-color) black
610    }
611    foreach cname [$dataobj components] {
612        set flowobj [$dataobj flowhints $cname]
613        if { $flowobj == "" } {
614            puts stderr "no flowhints $dataobj-$cname"
615            continue
616        }
617        set _dataset2flow($dataobj-$cname) $flowobj
618    }
619    set pos [lsearch -exact $_dlist $dataobj]
620    if {$pos < 0} {
621        lappend _dlist $dataobj
622        set _obj2ovride($dataobj-color) $params(-color)
623        set _obj2ovride($dataobj-width) $params(-width)
624        set _obj2ovride($dataobj-raise) $params(-raise)
625        $_dispatcher event -idle !rebuild
626    }
627}
628
629# ----------------------------------------------------------------------
630# USAGE: get ?-objects?
631# USAGE: get ?-image 3dview|legend?
632#
633# Clients use this to query the list of objects being plotted, in
634# order from bottom to top of this result.  The optional "-image"
635# flag can also request the internal images being shown.
636# ----------------------------------------------------------------------
637itcl::body Rappture::FlowvisViewer::get {args} {
638    if {[llength $args] == 0} {
639        set args "-objects"
640    }
641
642    set op [lindex $args 0]
643    switch -- $op {
644        -objects {
645            # put the dataobj list in order according to -raise options
646            set dlist $_dlist
647            foreach dataobj $dlist {
648                if {[info exists _obj2ovride($dataobj-raise)] &&
649                    $_obj2ovride($dataobj-raise)} {
650                    set i [lsearch -exact $dlist $dataobj]
651                    if {$i >= 0} {
652                        set dlist [lreplace $dlist $i $i]
653                        lappend dlist $dataobj
654                    }
655                }
656            }
657            return $dlist
658        }
659        -image {
660            if {[llength $args] != 2} {
661                error "wrong # args: should be \"get -image 3dview|legend\""
662            }
663            switch -- [lindex $args end] {
664                3dview {
665                    return $_image(plot)
666                }
667                legend {
668                    return $_image(legend)
669                }
670                default {
671                    error "bad image name \"[lindex $args end]\": should be 3dview or legend"
672                }
673            }
674        }
675        default {
676            error "bad option \"$op\": should be -objects or -image"
677        }
678    }
679}
680
681# ----------------------------------------------------------------------
682# USAGE: delete ?<dataobj1> <dataobj2> ...?
683#
684#       Clients use this to delete a dataobj from the plot.  If no dataobjs
685#       are specified, then all dataobjs are deleted.  No data objects are
686#       deleted.  They are only removed from the display list.
687#
688# ----------------------------------------------------------------------
689itcl::body Rappture::FlowvisViewer::delete {args} {
690    flow stop
691    if {[llength $args] == 0} {
692        set args $_dlist
693    }
694
695    # Delete all specified dataobjs
696    set changed 0
697    foreach dataobj $args {
698        set pos [lsearch -exact $_dlist $dataobj]
699        if { $pos >= 0 } {
700            set _dlist [lreplace $_dlist $pos $pos]
701            array unset _obj2ovride $dataobj-*
702            set changed 1
703        }
704    }
705    # If anything changed, then rebuild the plot
706    if {$changed} {
707        $_dispatcher event -idle !rebuild
708    }
709}
710
711# ----------------------------------------------------------------------
712# USAGE: scale ?<data1> <data2> ...?
713#
714# Sets the default limits for the overall plot according to the
715# limits of the data for all of the given <data> objects.  This
716# accounts for all objects--even those not showing on the screen.
717# Because of this, the limits are appropriate for all objects as
718# the user scans through data in the ResultSet viewer.
719# ----------------------------------------------------------------------
720itcl::body Rappture::FlowvisViewer::scale {args} {
721    array set style {
722        -color    BCGYR
723        -levels   6
724        -markers  ""
725    }
726    array unset _limits
727    array unset _volcomponents
728    foreach dataobj $args {
729        if { ![$dataobj isvalid] } {
730            continue;                     # Object doesn't contain valid data.
731        }
732        foreach cname [$dataobj components] {
733            if { ![info exists _volcomponents($cname)] } {
734                lappend _componentsList $cname
735                array set style [lindex [$dataobj components -style $cname] 0]
736                set cmap [ColorsToColormap $style(-color)]
737                set _settings($cname-colormap) $style(-color)
738            }
739            lappend _volcomponents($cname) $dataobj-$cname
740            array unset limits
741            array set limits [$dataobj valueLimits $cname]
742            set _limits($cname) $limits(v)
743        }
744        foreach axis {x y z} {
745            foreach { min max } [$dataobj limits $axis] break
746            if {"" != $min && "" != $max} {
747                if { ![info exists _limits($axis)] } {
748                    set _limits($axis) [list $min $max]
749                    continue
750                }
751                foreach {amin amax} $_limits($axis) break
752                if {$min < $amin} {
753                    set amin $min
754                }
755                if {$max > $amax} {
756                    set amax $max
757                }
758                set _limits($axis) [list $amin $amax]
759            }
760        }
761    }
762    #BuildVolumeComponents
763}
764
765# ----------------------------------------------------------------------
766# USAGE: download coming
767# USAGE: download controls <downloadCommand>
768# USAGE: download now
769#
770# Clients use this method to create a downloadable representation
771# of the plot.  Returns a list of the form {ext string}, where
772# "ext" is the file extension (indicating the type of data) and
773# "string" is the data itself.
774# ----------------------------------------------------------------------
775itcl::body Rappture::FlowvisViewer::download {option args} {
776    switch $option {
777        coming {
778            if {[catch {
779                blt::winop snap $itk_component(plotarea) $_image(download)
780            }]} {
781                $_image(download) configure -width 1 -height 1
782                $_image(download) put #000000
783            }
784        }
785        controls {
786            set popup .flowvisviewerdownload
787            if { ![winfo exists $popup] } {
788                set inner [BuildDownloadPopup $popup [lindex $args 0]]
789            } else {
790                set inner [$popup component inner]
791            }
792            # FIXME: we only support download of current active component
793            #set num [llength [get]]
794            #set num [expr {($num == 1) ? "1 result" : "$num results"}]
795            set num "current flow"
796            set word [Rappture::filexfer::label downloadWord]
797            $inner.summary configure -text "$word $num in the following format:"
798            update idletasks            ;# Fix initial sizes
799            return $popup
800        }
801        now {
802            set popup .flowvisviewerdownload
803            if { [winfo exists $popup] } {
804                $popup deactivate
805            }
806            switch -- $_downloadPopup(format) {
807                "640x480" {
808                    return [$this GetMovie [lindex $args 0] 640 480]
809                }
810                "1024x768" {
811                    return [$this GetMovie [lindex $args 0] 1024 768]
812                }
813                "image" {
814                    return [$this GetImage [lindex $args 0]]
815                }
816                "vtk" {
817                    return [$this GetVtkData [lindex $args 0]]
818                }
819                default {
820                    error "bad download format \"$_downloadPopup(format)\""
821                }
822            }
823        }
824        default {
825            error "bad option \"$option\": should be coming, controls, now"
826        }
827    }
828}
829
830# ----------------------------------------------------------------------
831# USAGE: Connect ?<host:port>,<host:port>...?
832#
833# Clients use this method to establish a connection to a new
834# server, or to reestablish a connection to the previous server.
835# Any existing connection is automatically closed.
836# ----------------------------------------------------------------------
837itcl::body Rappture::FlowvisViewer::Connect {} {
838    set _hosts [GetServerList "nanovis"]
839    if { "" == $_hosts } {
840        return 0
841    }
842    set _reset 1
843    set result [VisViewer::Connect $_hosts]
844    if { $result } {
845        if { $_reportClientInfo }  {
846            # Tell the server the viewer, hub, user and session.
847            # Do this immediately on connect before buffering any commands
848            global env
849
850            set info {}
851            set user "???"
852            if { [info exists env(USER)] } {
853                set user $env(USER)
854            }
855            set session "???"
856            if { [info exists env(SESSION)] } {
857                set session $env(SESSION)
858            }
859            lappend info "version" "$Rappture::version"
860            lappend info "build" "$Rappture::build"
861            lappend info "svnurl" "$Rappture::svnurl"
862            lappend info "installdir" "$Rappture::installdir"
863            lappend info "hub" [exec hostname]
864            lappend info "client" "flowvisviewer"
865            lappend info "user" $user
866            lappend info "session" $session
867            SendCmd "clientinfo [list $info]"
868        }
869
870        set w [winfo width $itk_component(3dview)]
871        set h [winfo height $itk_component(3dview)]
872        EventuallyResize $w $h
873    }
874    return $result
875}
876
877#
878# isconnected --
879#
880#       Indicates if we are currently connected to the visualization server.
881#
882itcl::body Rappture::FlowvisViewer::isconnected {} {
883    return [VisViewer::IsConnected]
884}
885
886#
887# disconnect --
888#
889itcl::body Rappture::FlowvisViewer::disconnect {} {
890    Disconnect
891}
892
893#
894# Disconnect --
895#
896#       Clients use this method to disconnect from the current rendering
897#       server.
898#
899itcl::body Rappture::FlowvisViewer::Disconnect {} {
900    VisViewer::Disconnect
901
902    # disconnected -- no more data sitting on server
903    array unset _datasets
904}
905
906# ----------------------------------------------------------------------
907# USAGE: SendTransferFunctions
908# ----------------------------------------------------------------------
909itcl::body Rappture::FlowvisViewer::SendTransferFunctions {} {
910    if { $_activeTf == "" } {
911        puts stderr "no active tf"
912        return
913    }
914    set tf $_activeTf
915    if { $_first == "" } {
916        puts stderr "first not set"
917        return
918    }
919
920    # Ensure that the global thickness setting (in the slider
921    # settings widget) is used for the active transfer-function.  Update
922    # the value in the _settings variable.
923
924    # Scale values between 0.00001 and 0.01000
925    set thickness [expr {double($_settings(-thickness)) * 0.0001}]
926    set _settings($tf-thickness) $thickness
927
928    foreach tag [array names _dataset2style $_first-*] {
929        if { [info exists _dataset2style($tag)] } {
930            foreach tf $_dataset2style($tag) {
931                ComputeTransferFunction $tf
932            }
933        }
934    }
935    EventuallyRedrawLegend
936}
937
938# ----------------------------------------------------------------------
939# USAGE: ReceiveImage -bytes <size> -type <type> -token <token>
940#
941# Invoked automatically whenever the "image" command comes in from
942# the rendering server.  Indicates that binary image data with the
943# specified <size> will follow.
944# ----------------------------------------------------------------------
945itcl::body Rappture::FlowvisViewer::ReceiveImage { args } {
946    array set info {
947        -token "???"
948        -bytes 0
949        -type image
950    }
951    array set info $args
952    set bytes [ReceiveBytes $info(-bytes)]
953    switch -- $info(-type) {
954        "image" {
955            #puts stderr "received image [image width $_image(plot)]x[image height $_image(plot)]"
956            $_image(plot) configure -data $bytes
957        }
958        "print" {
959            set tag $this-$info(-token)
960            set _hardcopy($tag) $bytes
961        }
962        "movie" {
963            set tag $this-$info(-token)
964            set _hardcopy($tag) $bytes
965        }
966        default {
967            puts stderr "unknown image type $info(-type)"
968        }
969    }
970}
971
972#
973# DrawLegend --
974#
975itcl::body Rappture::FlowvisViewer::DrawLegend { tag } {
976    set c $itk_component(legend)
977    set w [winfo width $c]
978    set h [winfo height $c]
979    set lx 10
980    set ly [expr {$h - 1}]
981    if {"" == [$c find withtag colorbar]} {
982        $c create image 10 10 -anchor nw \
983            -image $_image(legend) -tags colorbar
984        $c create text $lx $ly -anchor sw \
985            -fill $itk_option(-plotforeground) -tags "limits text vmin"
986        $c create text [expr {$w-$lx}] $ly -anchor se \
987            -fill $itk_option(-plotforeground) -tags "limits text vmax"
988        $c create text [expr {$w/2}] $ly -anchor s \
989            -fill $itk_option(-plotforeground) -tags "title text"
990        $c lower colorbar
991        $c bind colorbar <ButtonRelease-1> [itcl::code $this AddIsoMarker %x %y]
992    }
993
994    # Display the markers used by the current transfer function.
995    set tf $_dataset2style($tag)
996    foreach {min max} [limits $tf] break
997    $c itemconfigure vmin -text [format %g $min]
998    $c coords vmin $lx $ly
999
1000    $c itemconfigure vmax -text [format %g $max]
1001    $c coords vmax [expr {$w-$lx}] $ly
1002
1003    set title [$_first hints label]
1004    set units [$_first hints units]
1005    if { $units != "" } {
1006        set title "$title ($units)"
1007    }
1008    $c itemconfigure title -text $title
1009    $c coords title [expr {$w/2}] $ly
1010
1011    if { [info exists _isomarkers($tf)] } {
1012        foreach m $_isomarkers($tf) {
1013            $m visible yes
1014        }
1015    }
1016}
1017
1018#
1019# ReceiveLegend --
1020#
1021#       The procedure is the response from the render server to each "legend"
1022#       command.  The server sends back a "legend" command invoked our
1023#       the slave interpreter.  The purpose is to collect data of the image
1024#       representing the legend in the canvas.  In addition, the
1025#       active transfer function is displayed.
1026#
1027itcl::body Rappture::FlowvisViewer::ReceiveLegend { tag vmin vmax size } {
1028    if { ![isconnected] } {
1029        return
1030    }
1031    set bytes [ReceiveBytes $size]
1032    $_image(legend) configure -data $bytes
1033    ReceiveEcho <<line "<read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
1034
1035    DrawLegend $tag
1036}
1037
1038#
1039# ReceiveData --
1040#
1041#       The procedure is the response from the render server to each "data
1042#       follows" command.  The server sends back a "data" command invoked our
1043#       the slave interpreter.  The purpose was to collect the min/max of the
1044#       volume sent to the render server.  This is no longer needed since we
1045#       already know the limits.
1046#
1047itcl::body Rappture::FlowvisViewer::ReceiveData { args } {
1048    if { ![isconnected] } {
1049        return
1050    }
1051
1052    # Arguments from server are name value pairs. Stuff them in an array.
1053    array set info $args
1054
1055    set tag $info(tag)
1056    set _limits($tag) [list $info(min) $info(max)]
1057}
1058
1059# ----------------------------------------------------------------------
1060# USAGE: Rebuild
1061#
1062# Called automatically whenever something changes that affects the
1063# data in the widget.  Clears any existing data and rebuilds the
1064# widget to display new data.
1065# ----------------------------------------------------------------------
1066itcl::body Rappture::FlowvisViewer::Rebuild {} {
1067    set w [winfo width $itk_component(3dview)]
1068    set h [winfo height $itk_component(3dview)]
1069    if { $w < 2 || $h < 2 } {
1070        update
1071        $_dispatcher event -idle !rebuild
1072        return
1073    }
1074
1075    # Turn on buffering of commands to the server.  We don't want to
1076    # be preempted by a server disconnect/reconnect (which automatically
1077    # generates a new call to Rebuild).
1078    StartBufferingCommands
1079
1080    # Hide all the isomarkers. Can't remove them. Have to remember the
1081    # settings since the user may have created/deleted/moved markers.
1082
1083    foreach tf [array names _isomarkers] {
1084        foreach m $_isomarkers($tf) {
1085            $m visible no
1086        }
1087    }
1088
1089    if { $_width != $w || $_height != $h || $_reset } {
1090        set _width $w
1091        set _height $h
1092        $_arcball resize $w $h
1093        DoResize
1094    }
1095
1096    set _first ""
1097    foreach dataobj [get -objects] {
1098        if { [info exists _obj2ovride($dataobj-raise)] &&  $_first == "" } {
1099            set _first $dataobj
1100        }
1101        foreach cname [$dataobj components] {
1102            set tag $dataobj-$cname
1103            if { ![info exists _datasets($tag)] } {
1104                if { [$dataobj type] == "dx" } {
1105                    set data [$dataobj blob $cname]
1106                } else {
1107                    set data [$dataobj vtkdata $cname]
1108                }
1109                set nbytes [string length $data]
1110                if { $_reportClientInfo }  {
1111                    set info {}
1112                    lappend info "tool_id"       [$dataobj hints toolid]
1113                    lappend info "tool_name"     [$dataobj hints toolname]
1114                    lappend info "tool_title"    [$dataobj hints tooltitle]
1115                    lappend info "tool_command"  [$dataobj hints toolcommand]
1116                    lappend info "tool_revision" [$dataobj hints toolrevision]
1117                    lappend info "dataset_label" [$dataobj hints label]
1118                    lappend info "dataset_size"  $nbytes
1119                    lappend info "dataset_tag"   $tag
1120                    SendCmd "clientinfo [list $info]"
1121                }
1122                set numComponents [$dataobj numComponents $cname]
1123                # I have a field. Is a vector field or a volume field?
1124                if { $numComponents == 1 } {
1125                    SendCmd "volume data follows $nbytes $tag"
1126                } else {
1127                    if {[SendFlowCmd $dataobj $cname $nbytes $numComponents] < 0} {
1128                        continue
1129                    }
1130                }
1131                SendData $data
1132                set _datasets($tag) 1
1133                NameTransferFunction $dataobj $cname
1134            }
1135        }
1136    }
1137
1138    # Turn off cutplanes for all volumes
1139    foreach axis {x y z} {
1140        SendCmd "cutplane state 0 $axis"
1141    }
1142
1143    InitSettings -volume -outlinevisible -cutplanesvisible \
1144        -xcutplanevisible -ycutplanevisible -zcutplanevisible \
1145        -xcutplaneposition -ycutplaneposition -zcutplaneposition
1146
1147    if { $_reset } {
1148        InitSettings -axesvisible -gridvisible \
1149            -opacity -light2side -isosurfaceshading \
1150            -ambient -diffuse -specularlevel -specularexponent
1151
1152        #
1153        # Reset the camera and other view parameters
1154        #
1155        if {"" != $_first} {
1156            set axis [$_first hints updir]
1157            if { "" != $axis } {
1158                SendCmd "up $axis"
1159            }
1160            set location [$_first hints camera]
1161            if { $location != "" } {
1162                array set _view $location
1163            }
1164        }
1165        set _settings(-qw)    $_view(-qw)
1166        set _settings(-qx)    $_view(-qx)
1167        set _settings(-qy)    $_view(-qy)
1168        set _settings(-qz)    $_view(-qz)
1169        set _settings(-xpan)  $_view(-xpan)
1170        set _settings(-ypan)  $_view(-ypan)
1171        set _settings(-zoom)  $_view(-zoom)
1172
1173        set q [ViewToQuaternion]
1174        $_arcball quaternion $q
1175        SendCmd "camera orient $q"
1176        SendCmd "camera reset"
1177        PanCamera
1178        SendCmd "camera zoom $_view(-zoom)"
1179    }
1180
1181    if {"" != $_first} {
1182        set cname [lindex [$_first components] 0]
1183        set _activeTf [lindex $_dataset2style($_first-$cname) 0]
1184        # Make sure we display the proper transfer function in the legend.
1185        updateTransferFunctions
1186    }
1187
1188    # Actually write the commands to the server socket.  If it fails, we don't
1189    # care.  We're finished here.
1190    blt::busy hold $itk_component(hull)
1191    StopBufferingCommands
1192    blt::busy release $itk_component(hull)
1193    set _reset 0
1194}
1195
1196# ----------------------------------------------------------------------
1197# USAGE: CurrentDatasets ?-cutplanes?
1198#
1199# Returns a list of volume server IDs for the current volume being
1200# displayed.  This is normally a single ID, but it might be a list
1201# of IDs if the current data object has multiple components.
1202# ----------------------------------------------------------------------
1203itcl::body Rappture::FlowvisViewer::CurrentDatasets {{what -all}} {
1204    set rlist ""
1205    if { $_first == "" } {
1206        return
1207    }
1208    foreach cname [$_first components] {
1209        set tag $_first-$cname
1210        if { [info exists _datasets($tag)] && $_datasets($tag) } {
1211            array set style {
1212                -cutplanes 1
1213            }
1214            array set style [lindex [$_first components -style $cname] 0]
1215            if { $what != "-cutplanes" || $style(-cutplanes) } {
1216                lappend rlist $tag
1217            }
1218        }
1219    }
1220    return $rlist
1221}
1222
1223# ----------------------------------------------------------------------
1224# USAGE: Zoom in
1225# USAGE: Zoom out
1226# USAGE: Zoom reset
1227#
1228# Called automatically when the user clicks on one of the zoom
1229# controls for this widget.  Changes the zoom for the current view.
1230# ----------------------------------------------------------------------
1231itcl::body Rappture::FlowvisViewer::Zoom {option} {
1232    switch -- $option {
1233        "in" {
1234            set _view(-zoom) [expr {$_view(-zoom)*1.25}]
1235            set _settings(-zoom) $_view(-zoom)
1236            SendCmd "camera zoom $_view(-zoom)"
1237        }
1238        "out" {
1239            set _view(-zoom) [expr {$_view(-zoom)*0.8}]
1240            set _settings(-zoom) $_view(-zoom)
1241            SendCmd "camera zoom $_view(-zoom)"
1242        }
1243        "reset" {
1244            array set _view {
1245                -qw      0.853553
1246                -qx      -0.353553
1247                -qy      0.353553
1248                -qz      0.146447
1249                -xpan    0
1250                -ypan    0
1251                -zoom    1.0
1252            }
1253            if { $_first != "" } {
1254                set location [$_first hints camera]
1255                if { $location != "" } {
1256                    array set _view $location
1257                }
1258            }
1259            set q [ViewToQuaternion]
1260            $_arcball quaternion $q
1261            SendCmd "camera orient $q"
1262            SendCmd "camera reset"
1263            set _settings(-qw)    $_view(-qw)
1264            set _settings(-qx)    $_view(-qx)
1265            set _settings(-qy)    $_view(-qy)
1266            set _settings(-qz)    $_view(-qz)
1267            set _settings(-xpan)  $_view(-xpan)
1268            set _settings(-ypan)  $_view(-ypan)
1269            set _settings(-zoom)  $_view(-zoom)
1270        }
1271    }
1272}
1273
1274itcl::body Rappture::FlowvisViewer::PanCamera {} {
1275    set x $_view(-xpan)
1276    set y $_view(-ypan)
1277    SendCmd "camera pan $x $y"
1278}
1279
1280# ----------------------------------------------------------------------
1281# USAGE: Rotate click <x> <y>
1282# USAGE: Rotate drag <x> <y>
1283# USAGE: Rotate release <x> <y>
1284#
1285# Called automatically when the user clicks/drags/releases in the
1286# plot area.  Moves the plot according to the user's actions.
1287# ----------------------------------------------------------------------
1288itcl::body Rappture::FlowvisViewer::Rotate {option x y} {
1289    switch -- $option {
1290        click {
1291            $itk_component(3dview) configure -cursor fleur
1292            set _click(x) $x
1293            set _click(y) $y
1294        }
1295        drag {
1296            if {[array size _click] == 0} {
1297                Rotate click $x $y
1298            } else {
1299                set w [winfo width $itk_component(3dview)]
1300                set h [winfo height $itk_component(3dview)]
1301                if {$w <= 0 || $h <= 0} {
1302                    return
1303                }
1304
1305                if {[catch {
1306                    # this fails sometimes for no apparent reason
1307                    set dx [expr {double($x-$_click(x))/$w}]
1308                    set dy [expr {double($y-$_click(y))/$h}]
1309                }]} {
1310                    return
1311                }
1312
1313                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1314                QuaternionToView $q
1315                set _settings(-qw) $_view(-qw)
1316                set _settings(-qx) $_view(-qx)
1317                set _settings(-qy) $_view(-qy)
1318                set _settings(-qz) $_view(-qz)
1319                SendCmd "camera orient $q"
1320
1321                set _click(x) $x
1322                set _click(y) $y
1323            }
1324        }
1325        release {
1326            Rotate drag $x $y
1327            $itk_component(3dview) configure -cursor ""
1328            catch {unset _click}
1329        }
1330        default {
1331            error "bad option \"$option\": should be click, drag, release"
1332        }
1333    }
1334}
1335
1336# ----------------------------------------------------------------------
1337# USAGE: $this Pan click x y
1338#        $this Pan drag x y
1339#        $this Pan release x y
1340#
1341# Called automatically when the user clicks on one of the zoom
1342# controls for this widget.  Changes the zoom for the current view.
1343# ----------------------------------------------------------------------
1344itcl::body Rappture::FlowvisViewer::Pan {option x y} {
1345    # Experimental stuff
1346    set w [winfo width $itk_component(3dview)]
1347    set h [winfo height $itk_component(3dview)]
1348    if { $option == "set" } {
1349        set x [expr $x / double($w)]
1350        set y [expr $y / double($h)]
1351        set _view(-xpan) [expr $_view(-xpan) + $x]
1352        set _view(-ypan) [expr $_view(-ypan) + $y]
1353        PanCamera
1354        set _settings(-xpan) $_view(-xpan)
1355        set _settings(-ypan) $_view(-ypan)
1356        return
1357    }
1358    if { $option == "click" } {
1359        set _click(x) $x
1360        set _click(y) $y
1361        $itk_component(3dview) configure -cursor hand1
1362    }
1363    if { $option == "drag" || $option == "release" } {
1364        set dx [expr ($_click(x) - $x)/double($w)]
1365        set dy [expr ($_click(y) - $y)/double($h)]
1366        set _click(x) $x
1367        set _click(y) $y
1368        set _view(-xpan) [expr $_view(-xpan) - $dx]
1369        set _view(-ypan) [expr $_view(-ypan) - $dy]
1370        PanCamera
1371        set _settings(-xpan) $_view(-xpan)
1372        set _settings(-ypan) $_view(-ypan)
1373    }
1374    if { $option == "release" } {
1375        $itk_component(3dview) configure -cursor ""
1376    }
1377}
1378
1379# ----------------------------------------------------------------------
1380# USAGE: InitSettings <what> ?<value>?
1381#
1382# Used internally to update rendering settings whenever parameters
1383# change in the popup settings panel.  Sends the new settings off
1384# to the back end.
1385# ----------------------------------------------------------------------
1386itcl::body Rappture::FlowvisViewer::InitSettings { args } {
1387    foreach arg $args {
1388        AdjustSetting $arg
1389    }
1390}
1391
1392# ----------------------------------------------------------------------
1393# USAGE: AdjustSetting <what> ?<value>?
1394#
1395# Used internally to update rendering settings whenever parameters
1396# change in the popup settings panel.  Sends the new settings off
1397# to the back end.
1398# ----------------------------------------------------------------------
1399itcl::body Rappture::FlowvisViewer::AdjustSetting {what {value ""}} {
1400    if {![isconnected]} {
1401        return
1402    }
1403    switch -- $what {
1404        "-ambient" {
1405            if { $_first != "" } {
1406                set comp [lindex [$_first components] 0]
1407                set tag $_first-$comp
1408                set val $_settings($what)
1409                set val [expr {0.01*$val}]
1410                SendCmd "$tag configure -ambient $val"
1411            }
1412        }
1413        "-axesvisible" {
1414            SendCmd "axis visible $_settings($what)"
1415        }
1416        "-background" {
1417            set bgcolor [$itk_component(background) value]
1418            array set fgcolors {
1419                "black" "white"
1420                "white" "black"
1421                "grey"  "black"
1422            }
1423            configure -plotbackground $bgcolor \
1424                -plotforeground $fgcolors($bgcolor)
1425            if { $_first != "" } {
1426                set comp [lindex [$_first components] 0]
1427                set tag $_first-$comp
1428                DrawLegend $tag
1429            }
1430        }
1431        "-colormap" {
1432            set color [$itk_component(colormap) value]
1433            set _settings($what) $color
1434            #ResetColormap $color
1435        }
1436        "-cutplanesvisible" {
1437            set bool $_settings($what)
1438            set datasets [CurrentDatasets -cutplanes]
1439            set tag [lindex $datasets 0]
1440            SendCmd "cutplane visible $bool $tag"
1441        }
1442        "-diffuse" {
1443            if { $_first != "" } {
1444                set comp [lindex [$_first components] 0]
1445                set tag $_first-$comp
1446                set val $_settings($what)
1447                set val [expr {0.01*$val}]
1448                SendCmd "$tag configure -diffuse $val"
1449            }
1450        }
1451        "-gridvisible" {
1452            SendCmd "grid visible $_settings($what)"
1453        }
1454        "-isosurfaceshading" {
1455            if { $_first != "" } {
1456                set comp [lindex [$_first components] 0]
1457                set tag $_first-$comp
1458                set val $_settings($what)
1459                # This flag isn't implemented in the server
1460                #SendCmd "$tag configure -isosurface $val"
1461            }
1462        }
1463        "-legendvisible" {
1464            if { $_settings($what) } {
1465                blt::table $itk_component(plotarea) \
1466                    0,0 $itk_component(3dview) -fill both \
1467                    1,0 $itk_component(legend) -fill x
1468                blt::table configure $itk_component(plotarea) r1 -resize none
1469            } else {
1470                blt::table forget $itk_component(legend)
1471            }
1472        }
1473        "-light2side" {
1474            if { $_first != "" } {
1475                set comp [lindex [$_first components] 0]
1476                set tag $_first-$comp
1477                set val $_settings($what)
1478                SendCmd "$tag configure -light2side $val"
1479            }
1480        }
1481        "-opacity" {
1482            if { $_first != "" } {
1483                set comp [lindex [$_first components] 0]
1484                set tag $_first-$comp
1485                set opacity [expr { 0.01 * double($_settings($what)) }]
1486                SendCmd "$tag configure -opacity $opacity"
1487            }
1488        }
1489        "-outlinevisible" {
1490            if { $_first != "" } {
1491                set comp [lindex [$_first components] 0]
1492                set tag $_first-$comp
1493                SendCmd "$tag configure -outline $_settings($what)"
1494            }
1495        }
1496        "-specularlevel" {
1497            if { $_first != "" } {
1498                set comp [lindex [$_first components] 0]
1499                set tag $_first-$comp
1500                set val $_settings($what)
1501                set val [expr {0.01*$val}]
1502                SendCmd "$tag configure -specularLevel $val"
1503            }
1504        }
1505        "-specularexponent" {
1506            if { $_first != "" } {
1507                set comp [lindex [$_first components] 0]
1508                set tag $_first-$comp
1509                set val $_settings($what)
1510                SendCmd "$tag configure -specularExp $val"
1511            }
1512        }
1513        "-thickness" {
1514            if { $_first != "" && $_activeTf != "" } {
1515                set val $_settings($what)
1516                # Scale values between 0.00001 and 0.01000
1517                set sval [expr {0.0001*double($val)}]
1518                set tf $_activeTf
1519                set _settings($tf${what}) $sval
1520                updateTransferFunctions
1521            }
1522        }
1523        "-volume" {
1524            if { $_first != "" } {
1525                set comp [lindex [$_first components] 0]
1526                set tag $_first-$comp
1527                SendCmd "$tag configure -volume $_settings($what)"
1528            }
1529        }
1530        "-xcutplaneposition" - "-ycutplaneposition" - "-zcutplaneposition" {
1531            set axis [string range $what 1 1]
1532            set pos [expr $_settings($what) * 0.01]
1533            # We only set cutplanes on the first dataset.
1534            set datasets [CurrentDatasets -cutplanes]
1535            set tag [lindex $datasets 0]
1536            SendCmd "cutplane position $pos $axis $tag"
1537        }
1538        "-xcutplanevisible" - "-ycutplanevisible" - "-zcutplanevisible" {
1539            set axis [string range $what 1 1]
1540            set bool $_settings($what)
1541            # We only set cutplanes on the first dataset.
1542            set datasets [CurrentDatasets -cutplanes]
1543            set tag [lindex $datasets 0]
1544            SendCmd "cutplane state $bool $axis $tag"
1545            if { $bool } {
1546                $itk_component(${axis}CutScale) configure -state normal \
1547                    -troughcolor white
1548            } else {
1549                $itk_component(${axis}CutScale) configure -state disabled \
1550                    -troughcolor grey82
1551            }
1552        }
1553        default {
1554            error "don't know how to fix $what"
1555        }
1556    }
1557}
1558
1559# ----------------------------------------------------------------------
1560# USAGE: FixLegend
1561#
1562# Used internally to update the legend area whenever it changes size
1563# or when the field changes.  Asks the server to send a new legend
1564# for the current field.
1565# ----------------------------------------------------------------------
1566itcl::body Rappture::FlowvisViewer::FixLegend {} {
1567    set _resizeLegendPending 0
1568    set lineht [font metrics $itk_option(-font) -linespace]
1569    set w [expr {$_width-20}]
1570    set h [expr {[winfo height $itk_component(legend)]-20-$lineht}]
1571
1572    if { $_first == "" } {
1573        return
1574    }
1575    set comp [lindex [$_first components] 0]
1576    set tag $_first-$comp
1577    #set _activeTf [lindex $_dataset2style($tag) 0]
1578    if {$w > 0 && $h > 0 && "" != $_activeTf} {
1579        #SendCmd "legend $_activeTf $w $h"
1580        SendCmd "$tag legend $w $h"
1581    }
1582}
1583
1584#
1585# NameTransferFunction --
1586#
1587#       Creates a transfer function name based on the <style> settings in the
1588#       library run.xml file. This placeholder will be used later to create
1589#       and send the actual transfer function once the data info has been sent
1590#       to us by the render server. [We won't know the volume limits until the
1591#       server parses the 3D data and sends back the limits via ReceiveData.]
1592#
1593itcl::body Rappture::FlowvisViewer::NameTransferFunction { dataobj cname } {
1594    array set style {
1595        -color BCGYR
1596        -levels 6
1597        -opacity 0.5
1598    }
1599    array set style [lindex [$dataobj components -style $cname] 0]
1600    # Some tools erroneously set -opacity to 1 in style, so
1601    # override the requested opacity for now
1602    set style(-opacity) 0.5
1603    set _settings(-opacity) [expr $style(-opacity) * 100]
1604    set _dataset2style($dataobj-$cname) $cname
1605    lappend _style2datasets($cname) $dataobj $cname
1606    return $cname
1607}
1608
1609#
1610# ComputeTransferFunction --
1611#
1612#       Computes and sends the transfer function to the render server.  It's
1613#       assumed that the volume data limits are known and that the global
1614#       transfer-functions slider values have been set up.  Both parts are
1615#       needed to compute the relative value (location) of the marker, and
1616#       the alpha map of the transfer function.
1617#
1618itcl::body Rappture::FlowvisViewer::ComputeTransferFunction { tf } {
1619    array set style {
1620        -color BCGYR
1621        -levels 6
1622        -opacity 0.5
1623    }
1624    set dataobj ""; set cname ""
1625    foreach {dataobj cname} $_style2datasets($tf) break
1626    if { $dataobj == "" } {
1627        return 0
1628    }
1629    array set style [lindex [$dataobj components -style $cname] 0]
1630    # Some tools erroneously set -opacity to 1 in style, so
1631    # override the requested opacity for now
1632    set style(-opacity) 0.5
1633
1634    # We have to parse the style attributes for a volume using this
1635    # transfer-function *once*.  This sets up the initial isomarkers for the
1636    # transfer function.  The user may add/delete markers, so we have to
1637    # maintain a list of markers for each transfer-function.  We use the one
1638    # of the volumes (the first in the list) using the transfer-function as a
1639    # reference.
1640
1641    if { ![info exists _isomarkers($tf)] } {
1642        # Have to defer creation of isomarkers until we have data limits
1643        if { [info exists style(-markers)] &&
1644             [llength $style(-markers)] > 0  } {
1645            ParseMarkersOption $tf $style(-markers)
1646        } else {
1647            ParseLevelsOption $tf $style(-levels)
1648        }
1649    }
1650    if { [info exists style(-nonuniformcolors)] } {
1651        foreach { value color } $style(-nonuniformcolors) {
1652            append cmap "$value [Color2RGB $color] "
1653        }
1654    } else {
1655        set cmap [ColorsToColormap $style(-color)]
1656    }
1657
1658    if { ![info exists _settings(-opacity)] } {
1659        set _settings(-opacity) [expr $style(-opacity) * 100]
1660    }
1661
1662    # Transfer function should be normalized with [0,1] range
1663    # The volume shading opacity setting is used to scale opacity
1664    # in the volume shader.
1665    set max 1.0
1666
1667    set isovalues {}
1668    foreach m $_isomarkers($tf) {
1669        lappend isovalues [$m relval]
1670    }
1671    # Sort the isovalues
1672    set isovalues [lsort -real $isovalues]
1673
1674    set tag $tf
1675    if { ![info exists _settings($tag-thickness)]} {
1676        set _settings($tag-thickness) 0.005
1677    }
1678    set delta $_settings($tag-thickness)
1679
1680    set first [lindex $isovalues 0]
1681    set last [lindex $isovalues end]
1682    set amap ""
1683    if { $first == "" || $first != 0.0 } {
1684        lappend amap 0.0 0.0
1685    }
1686    foreach x $isovalues {
1687        set x1 [expr {$x-$delta-0.00001}]
1688        set x2 [expr {$x-$delta}]
1689        set x3 [expr {$x+$delta}]
1690        set x4 [expr {$x+$delta+0.00001}]
1691        if { $x1 < 0.0 } {
1692            set x1 0.0
1693        } elseif { $x1 > 1.0 } {
1694            set x1 1.0
1695        }
1696        if { $x2 < 0.0 } {
1697            set x2 0.0
1698        } elseif { $x2 > 1.0 } {
1699            set x2 1.0
1700        }
1701        if { $x3 < 0.0 } {
1702            set x3 0.0
1703        } elseif { $x3 > 1.0 } {
1704            set x3 1.0
1705        }
1706        if { $x4 < 0.0 } {
1707            set x4 0.0
1708        } elseif { $x4 > 1.0 } {
1709            set x4 1.0
1710        }
1711        # add spikes in the middle
1712        lappend amap $x1 0.0
1713        lappend amap $x2 $max
1714        lappend amap $x3 $max
1715        lappend amap $x4 0.0
1716    }
1717    if { $last == "" || $last != 1.0 } {
1718        lappend amap 1.0 0.0
1719    }
1720    SendCmd "transfunc define $tf { $cmap } { $amap }"
1721    return [SendCmd "$dataobj-$cname configure -transferfunction $tf"]
1722}
1723
1724# ----------------------------------------------------------------------
1725# CONFIGURATION OPTION: -plotbackground
1726# ----------------------------------------------------------------------
1727itcl::configbody Rappture::FlowvisViewer::plotbackground {
1728    if { [isconnected] } {
1729        set color $itk_option(-plotbackground)
1730        set rgb [Color2RGB $color]
1731        SendCmd "screen bgcolor $rgb"
1732        $itk_component(legend) configure -background $color
1733    }
1734}
1735
1736# ----------------------------------------------------------------------
1737# CONFIGURATION OPTION: -plotforeground
1738# ----------------------------------------------------------------------
1739itcl::configbody Rappture::FlowvisViewer::plotforeground {
1740    if { [isconnected] } {
1741        set color $itk_option(-plotforeground)
1742        set rgb [Color2RGB $color]
1743        SendCmd "volume outline color $rgb"
1744        SendCmd "grid axiscolor $rgb"
1745        SendCmd "grid linecolor $rgb"
1746        $itk_component(legend) itemconfigure text -fill $color
1747    }
1748}
1749
1750# ----------------------------------------------------------------------
1751# CONFIGURATION OPTION: -plotoutline
1752# ----------------------------------------------------------------------
1753itcl::configbody Rappture::FlowvisViewer::plotoutline {
1754    # Must check if we are connected because this routine is called from the
1755    # class body when the -plotoutline itk_option is defined.  At that point
1756    # the FlowvisViewer class constructor hasn't been called, so we can't
1757    # start sending commands to visualization server.
1758    if { [isconnected] } {
1759        if {"" == $itk_option(-plotoutline)} {
1760            SendCmd "volume outline state off"
1761        } else {
1762            SendCmd "volume outline state on"
1763            SendCmd "volume outline color [Color2RGB $itk_option(-plotoutline)]"
1764        }
1765    }
1766}
1767
1768#
1769# The -levels option takes a single value that represents the number
1770# of evenly distributed markers based on the current data range. Each
1771# marker is a relative value from 0.0 to 1.0.
1772#
1773itcl::body Rappture::FlowvisViewer::ParseLevelsOption { tf levels } {
1774    set c $itk_component(legend)
1775    regsub -all "," $levels " " levels
1776    if {[string is int $levels]} {
1777        for {set i 1} { $i <= $levels } {incr i} {
1778            set x [expr {double($i)/($levels+1)}]
1779            set m [Rappture::IsoMarker \#auto $c $this $tf]
1780            $itk_component(legend) itemconfigure labels -fill $itk_option(-plotforeground)
1781            $m relval $x
1782            lappend _isomarkers($tf) $m
1783        }
1784    } else {
1785        foreach x $levels {
1786            set m [Rappture::IsoMarker \#auto $c $this $tf]
1787            $itk_component(legend) itemconfigure labels -fill $itk_option(-plotforeground)
1788            $m relval $x
1789            lappend _isomarkers($tf) $m
1790        }
1791    }
1792}
1793
1794#
1795# The -markers option takes a list of zero or more values (the values
1796# may be separated either by spaces or commas) that have the following
1797# format:
1798#
1799#   N%  Percent of current total data range.  Converted to
1800#       to a relative value between 0.0 and 1.0.
1801#   N   Absolute value of marker.  If the marker is outside of
1802#       the current range, it will be displayed on the outer
1803#       edge of the legends, but it range it represents will
1804#       not be seen.
1805#
1806itcl::body Rappture::FlowvisViewer::ParseMarkersOption { tf markers } {
1807    set c $itk_component(legend)
1808    regsub -all "," $markers " " markers
1809    foreach marker $markers {
1810        set n [scan $marker "%g%s" value suffix]
1811        if { $n == 2 && $suffix == "%" } {
1812            # ${n}% : Set relative value.
1813            set value [expr {$value * 0.01}]
1814            set m [Rappture::IsoMarker \#auto $c $this $tf]
1815            $itk_component(legend) itemconfigure labels -fill $itk_option(-plotforeground)
1816            $m relval $value
1817            lappend _isomarkers($tf) $m
1818        } else {
1819            # ${n} : Set absolute value.
1820            set m [Rappture::IsoMarker \#auto $c $this $tf]
1821            $itk_component(legend) itemconfigure labels -fill $itk_option(-plotforeground)
1822            $m absval $value
1823            lappend _isomarkers($tf) $m
1824        }
1825    }
1826}
1827
1828itcl::body Rappture::FlowvisViewer::updateTransferFunctions {} {
1829    $_dispatcher event -after 100 !send_transfunc
1830}
1831
1832itcl::body Rappture::FlowvisViewer::AddIsoMarker { x y } {
1833    if { $_activeTf == "" } {
1834        error "active transfer function isn't set"
1835    }
1836    set tf $_activeTf
1837    set c $itk_component(legend)
1838    set m [Rappture::IsoMarker \#auto $c $this $tf]
1839    $itk_component(legend) itemconfigure labels -fill $itk_option(-plotforeground)
1840    set w [winfo width $c]
1841    $m relval [expr {double($x-10)/($w-20)}]
1842    lappend _isomarkers($tf) $m
1843    updateTransferFunctions
1844    return 1
1845}
1846
1847itcl::body Rappture::FlowvisViewer::removeDuplicateMarker { marker x } {
1848    set tf [$marker transferfunc]
1849    set bool 0
1850    if { [info exists _isomarkers($tf)] } {
1851        set list {}
1852        set marker [namespace tail $marker]
1853        foreach m $_isomarkers($tf) {
1854            set sx [$m screenpos]
1855            if { $m != $marker } {
1856                if { $x >= ($sx-3) && $x <= ($sx+3) } {
1857                    $marker relval [$m relval]
1858                    itcl::delete object $m
1859                    bell
1860                    set bool 1
1861                    continue
1862                }
1863            }
1864            lappend list $m
1865        }
1866        set _isomarkers($tf) $list
1867        updateTransferFunctions
1868    }
1869    return $bool
1870}
1871
1872itcl::body Rappture::FlowvisViewer::overMarker { marker x } {
1873    set tf [$marker transferfunc]
1874    if { [info exists _isomarkers($tf)] } {
1875        set marker [namespace tail $marker]
1876        foreach m $_isomarkers($tf) {
1877            set sx [$m screenpos]
1878            if { $m != $marker } {
1879                set bool [expr { $x >= ($sx-3) && $x <= ($sx+3) }]
1880                $m activate $bool
1881            }
1882        }
1883    }
1884    return ""
1885}
1886
1887itcl::body Rappture::FlowvisViewer::limits { cname } {
1888    if { ![info exists _limits($cname)] } {
1889        puts stderr "no limits for cname=($cname)"
1890        return [list 0.0 1.0]
1891    }
1892    return $_limits($cname)
1893}
1894
1895itcl::body Rappture::FlowvisViewer::BuildViewTab {} {
1896    set fg [option get $itk_component(hull) font Font]
1897    #set bfg [option get $itk_component(hull) boldFont Font]
1898
1899    set inner [$itk_component(main) insert end \
1900        -title "View Settings" \
1901        -icon [Rappture::icon wrench]]
1902    $inner configure -borderwidth 4
1903
1904    # General options
1905    checkbutton $inner.axes \
1906        -text "Axes" \
1907        -variable [itcl::scope _settings(-axesvisible)] \
1908        -command [itcl::code $this AdjustSetting -axesvisible] \
1909        -font "Arial 9"
1910
1911    checkbutton $inner.grid \
1912        -text "Grid" \
1913        -variable [itcl::scope _settings(-gridvisible)] \
1914        -command [itcl::code $this AdjustSetting -gridvisible] \
1915        -font "Arial 9"
1916
1917    checkbutton $inner.legend \
1918        -text "Legend" \
1919        -variable [itcl::scope _settings(-legendvisible)] \
1920        -command [itcl::code $this AdjustSetting -legendvisible] \
1921        -font "Arial 9"
1922
1923    label $inner.background_l -text "Background" -font "Arial 9"
1924    itk_component add background {
1925        Rappture::Combobox $inner.background -width 10 -editable no
1926    }
1927    $inner.background choices insert end \
1928        "black" "black" \
1929        "white" "white" \
1930        "grey"  "grey"
1931
1932    $itk_component(background) value $_settings(-background)
1933    bind $inner.background <<Value>> \
1934        [itcl::code $this AdjustSetting -background]
1935
1936    # Dataset options
1937    label $inner.flow_l -text "Flow" -font "Arial 9 bold"
1938
1939    checkbutton $inner.outline \
1940        -text "Outline" \
1941        -variable [itcl::scope _settings(-outlinevisible)] \
1942        -command [itcl::code $this AdjustSetting -outlinevisible] \
1943        -font "Arial 9"
1944
1945    checkbutton $inner.volume \
1946        -text "Volume" \
1947        -variable [itcl::scope _settings(-volume)] \
1948        -command [itcl::code $this AdjustSetting -volume] \
1949        -font "Arial 9"
1950
1951    frame $inner.frame
1952
1953    blt::table $inner \
1954        0,0 $inner.axes -cspan 2 -anchor w \
1955        1,0 $inner.grid -cspan 2 -anchor w \
1956        2,0 $inner.legend -cspan 2 -anchor w \
1957        3,0 $inner.background_l -anchor e -pady 2 \
1958        3,1 $inner.background -fill x \
1959        4,0 $inner.flow_l -anchor w \
1960        5,0 $inner.outline -cspan 2 -anchor w \
1961        6,0 $inner.volume -cspan 2 -anchor w \
1962
1963    bind $inner <Map> [itcl::code $this GetFlowInfo $inner]
1964
1965    blt::table configure $inner c* r* -resize none
1966    blt::table configure $inner c2 r7 -resize expand
1967}
1968
1969itcl::body Rappture::FlowvisViewer::BuildVolumeTab {} {
1970    set inner [$itk_component(main) insert end \
1971        -title "Volume Settings" \
1972        -icon [Rappture::icon volume-on]]
1973    $inner configure -borderwidth 4
1974
1975    set fg [option get $itk_component(hull) font Font]
1976    #set bfg [option get $itk_component(hull) boldFont Font]
1977
1978    checkbutton $inner.vol -text "Show volume" -font $fg \
1979        -text "Volume" \
1980        -variable [itcl::scope _settings(-volume)] \
1981        -command [itcl::code $this AdjustSetting -volume] \
1982        -font "Arial 9"
1983
1984    label $inner.lighting_l \
1985        -text "Lighting / Material Properties" \
1986        -font "Arial 9 bold"
1987
1988    checkbutton $inner.isosurface -text "Isosurface shading" -font $fg \
1989        -variable [itcl::scope _settings(-isosurfaceshading)] \
1990        -command [itcl::code $this AdjustSetting -isosurfaceshading]
1991
1992    checkbutton $inner.light2side -text "Two-sided lighting" -font $fg \
1993        -variable [itcl::scope _settings(-light2side)] \
1994        -command [itcl::code $this AdjustSetting -light2side]
1995
1996    label $inner.ambient_l -text "Ambient" -font $fg
1997    ::scale $inner.ambient -from 0 -to 100 -orient horizontal \
1998        -variable [itcl::scope _settings(-ambient)] \
1999        -width 10 \
2000        -showvalue off -command [itcl::code $this AdjustSetting -ambient]
2001
2002    label $inner.diffuse_l -text "Diffuse" -font $fg
2003    ::scale $inner.diffuse -from 0 -to 100 -orient horizontal \
2004        -variable [itcl::scope _settings(-diffuse)] \
2005        -width 10 \
2006        -showvalue off -command [itcl::code $this AdjustSetting -diffuse]
2007
2008    label $inner.specularLevel_l -text "Specular" -font $fg
2009    ::scale $inner.specularLevel -from 0 -to 100 -orient horizontal \
2010        -variable [itcl::scope _settings(-specularlevel)] \
2011        -width 10 \
2012        -showvalue off -command [itcl::code $this AdjustSetting -specularlevel]
2013
2014    label $inner.specularExponent_l -text "Shininess" -font $fg
2015    ::scale $inner.specularExponent -from 10 -to 128 -orient horizontal \
2016        -variable [itcl::scope _settings(-specularexponent)] \
2017        -width 10 \
2018        -showvalue off -command [itcl::code $this AdjustSetting -specularexponent]
2019
2020    # Opacity
2021    label $inner.opacity_l -text "Opacity" -font $fg
2022    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
2023        -variable [itcl::scope _settings(-opacity)] \
2024        -width 10 \
2025        -showvalue off -command [itcl::code $this AdjustSetting -opacity]
2026
2027    label $inner.transferfunction_l \
2028        -text "Transfer Function" -font "Arial 9 bold"
2029
2030    # Tooth thickness
2031    label $inner.thin -text "Thin" -font $fg
2032    ::scale $inner.thickness -from 0 -to 1000 -orient horizontal \
2033        -variable [itcl::scope _settings(-thickness)] \
2034        -width 10 \
2035        -showvalue off -command [itcl::code $this AdjustSetting -thickness]
2036    label $inner.thick -text "Thick" -font $fg
2037
2038    # Colormap
2039    label $inner.colormap_l -text "Colormap" -font $fg
2040    itk_component add colormap {
2041        Rappture::Combobox $inner.colormap -width 10 -editable no
2042    }
2043    $inner.colormap choices insert end [GetColormapList -includeNone]
2044    bind $inner.colormap <<Value>> \
2045        [itcl::code $this AdjustSetting -colormap]
2046    $itk_component(colormap) value "BCGYR"
2047    set _settings(-colormap) "BCGYR"
2048
2049    blt::table $inner \
2050        0,0 $inner.vol -cspan 4 -anchor w -pady 2 \
2051        1,0 $inner.lighting_l -cspan 4 -anchor w -pady {10 2} \
2052        2,0 $inner.light2side -cspan 4 -anchor w -pady 2 \
2053        3,0 $inner.ambient_l -anchor e -pady 2 \
2054        3,1 $inner.ambient -cspan 3 -pady 2 -fill x \
2055        4,0 $inner.diffuse_l -anchor e -pady 2 \
2056        4,1 $inner.diffuse -cspan 3 -pady 2 -fill x \
2057        5,0 $inner.specularLevel_l -anchor e -pady 2 \
2058        5,1 $inner.specularLevel -cspan 3 -pady 2 -fill x \
2059        6,0 $inner.specularExponent_l -anchor e -pady 2 \
2060        6,1 $inner.specularExponent -cspan 3 -pady 2 -fill x \
2061        7,0 $inner.opacity_l -anchor e -pady 2 \
2062        7,1 $inner.opacity -cspan 3 -pady 2 -fill x \
2063        8,0 $inner.thin -anchor e -pady 2 \
2064        8,1 $inner.thickness -cspan 2 -pady 2 -fill x \
2065        8,3 $inner.thick -anchor w -pady 2
2066
2067    blt::table configure $inner c0 c1 c3 r* -resize none
2068    blt::table configure $inner r9 -resize expand
2069}
2070
2071itcl::body Rappture::FlowvisViewer::BuildCutplanesTab {} {
2072    set inner [$itk_component(main) insert end \
2073        -title "Cutplane Settings" \
2074        -icon [Rappture::icon cutbutton]]
2075    $inner configure -borderwidth 4
2076
2077    checkbutton $inner.visible \
2078        -text "Show Cutplanes" \
2079        -variable [itcl::scope _settings(-cutplanesvisible)] \
2080        -command [itcl::code $this AdjustSetting -cutplanesvisible] \
2081        -font "Arial 9"
2082
2083    # X-value slicer...
2084    itk_component add xCutButton {
2085        Rappture::PushButton $inner.xbutton \
2086            -onimage [Rappture::icon x-cutplane] \
2087            -offimage [Rappture::icon x-cutplane] \
2088            -command [itcl::code $this AdjustSetting -xcutplanevisible] \
2089            -variable [itcl::scope _settings(-xcutplanevisible)]
2090    }
2091    Rappture::Tooltip::for $itk_component(xCutButton) \
2092        "Toggle the X cut plane on/off"
2093    $itk_component(xCutButton) select
2094
2095    itk_component add xCutScale {
2096        ::scale $inner.xval -from 100 -to 0 \
2097            -width 10 -orient vertical -showvalue off \
2098            -borderwidth 1 -highlightthickness 0 \
2099            -command [itcl::code $this Slice move x] \
2100            -variable [itcl::scope _settings(-xcutplaneposition)]
2101    } {
2102        usual
2103        ignore -borderwidth -highlightthickness
2104    }
2105    # Set the default cutplane value before disabling the scale.
2106    $itk_component(xCutScale) set 50
2107    $itk_component(xCutScale) configure -state disabled
2108    Rappture::Tooltip::for $itk_component(xCutScale) \
2109        "@[itcl::code $this SlicerTip x]"
2110
2111    # Y-value slicer...
2112    itk_component add yCutButton {
2113        Rappture::PushButton $inner.ybutton \
2114            -onimage [Rappture::icon y-cutplane] \
2115            -offimage [Rappture::icon y-cutplane] \
2116            -command [itcl::code $this AdjustSetting -ycutplanevisible] \
2117            -variable [itcl::scope _settings(-ycutplanevisible)]
2118    }
2119    Rappture::Tooltip::for $itk_component(yCutButton) \
2120        "Toggle the Y cut plane on/off"
2121    $itk_component(yCutButton) select
2122
2123    itk_component add yCutScale {
2124        ::scale $inner.yval -from 100 -to 0 \
2125            -width 10 -orient vertical -showvalue off \
2126            -borderwidth 1 -highlightthickness 0 \
2127            -command [itcl::code $this Slice move y] \
2128            -variable [itcl::scope _settings(-ycutplaneposition)]
2129    } {
2130        usual
2131        ignore -borderwidth -highlightthickness
2132    }
2133    Rappture::Tooltip::for $itk_component(yCutScale) \
2134        "@[itcl::code $this SlicerTip y]"
2135    # Set the default cutplane value before disabling the scale.
2136    $itk_component(yCutScale) set 50
2137    $itk_component(yCutScale) configure -state disabled
2138
2139    # Z-value slicer...
2140    itk_component add zCutButton {
2141        Rappture::PushButton $inner.zbutton \
2142            -onimage [Rappture::icon z-cutplane] \
2143            -offimage [Rappture::icon z-cutplane] \
2144            -command [itcl::code $this AdjustSetting -zcutplanevisible] \
2145            -variable [itcl::scope _settings(-zcutplanevisible)]
2146    }
2147    Rappture::Tooltip::for $itk_component(zCutButton) \
2148        "Toggle the Z cut plane on/off"
2149    $itk_component(zCutButton) select
2150
2151    itk_component add zCutScale {
2152        ::scale $inner.zval -from 100 -to 0 \
2153            -width 10 -orient vertical -showvalue off \
2154            -borderwidth 1 -highlightthickness 0 \
2155            -command [itcl::code $this Slice move z] \
2156            -variable [itcl::scope _settings(-zcutplaneposition)]
2157    } {
2158        usual
2159        ignore -borderwidth -highlightthickness
2160    }
2161    $itk_component(zCutScale) set 50
2162    $itk_component(zCutScale) configure -state disabled
2163    Rappture::Tooltip::for $itk_component(zCutScale) \
2164        "@[itcl::code $this SlicerTip z]"
2165
2166    blt::table $inner \
2167        0,1 $inner.visible -anchor w -pady 2 -cspan 4 \
2168        1,1 $itk_component(xCutScale) \
2169        1,2 $itk_component(yCutScale) \
2170        1,3 $itk_component(zCutScale) \
2171        2,1 $itk_component(xCutButton) \
2172        2,2 $itk_component(yCutButton) \
2173        2,3 $itk_component(zCutButton)
2174
2175    blt::table configure $inner r0 r1 r2 c* -resize none
2176    blt::table configure $inner r3 c4 -resize expand
2177    blt::table configure $inner c0 -width 2
2178    blt::table configure $inner c1 c2 c3 -padx 2
2179}
2180
2181itcl::body Rappture::FlowvisViewer::BuildCameraTab {} {
2182    set inner [$itk_component(main) insert end \
2183        -title "Camera Settings" \
2184        -icon [Rappture::icon camera]]
2185    $inner configure -borderwidth 4
2186
2187    label $inner.view_l -text "view" -font "Arial 9"
2188    set f [frame $inner.view]
2189    foreach side { front back left right top bottom } {
2190        button $f.$side  -image [Rappture::icon view$side] \
2191            -command [itcl::code $this SetOrientation $side]
2192        Rappture::Tooltip::for $f.$side "Change the view to $side"
2193        pack $f.$side -side left
2194    }
2195
2196    blt::table $inner \
2197        0,0 $inner.view_l -anchor e -pady 2 \
2198        0,1 $inner.view -anchor w -pady 2
2199    blt::table configure $inner r0 -resize none
2200
2201    set row 1
2202    set labels { qw qx qy qz xpan ypan zoom }
2203    foreach tag $labels {
2204        label $inner.${tag}label -text $tag -font "Arial 9"
2205        entry $inner.${tag} -font "Arial 9"  -bg white \
2206            -textvariable [itcl::scope _settings(-$tag)]
2207        bind $inner.${tag} <Return> \
2208            [itcl::code $this camera set -${tag}]
2209        bind $inner.${tag} <KP_Enter> \
2210            [itcl::code $this camera set -${tag}]
2211        blt::table $inner \
2212            $row,0 $inner.${tag}label -anchor e -pady 2 \
2213            $row,1 $inner.${tag} -anchor w -pady 2
2214        blt::table configure $inner r$row -resize none
2215        incr row
2216    }
2217
2218    blt::table configure $inner c* -resize none
2219    blt::table configure $inner c2 -resize expand
2220    blt::table configure $inner r$row -resize expand
2221}
2222
2223itcl::body Rappture::FlowvisViewer::GetFlowInfo { w } {
2224    set flowobj ""
2225    foreach key [array names _dataset2flow] {
2226        set flowobj $_dataset2flow($key)
2227        break
2228    }
2229    if { $flowobj == "" } {
2230        return
2231    }
2232    if { [winfo exists $w.frame] } {
2233        destroy $w.frame
2234    }
2235    set inner [frame $w.frame]
2236    blt::table $w \
2237        7,0 $inner -fill both -cspan 2 -anchor nw
2238    array set hints [$flowobj hints]
2239    checkbutton $inner.showstreams -text "Streams Plane" \
2240        -variable [itcl::scope _settings(-streams)] \
2241        -command  [itcl::code $this streams $key $hints(name)]  \
2242        -font "Arial 9"
2243    Rappture::Tooltip::for $inner.showstreams $hints(description)
2244
2245    checkbutton $inner.showarrows -text "Arrows" \
2246        -variable [itcl::scope _settings(-arrows)] \
2247        -command  [itcl::code $this arrows $key $hints(name)]  \
2248        -font "Arial 9"
2249
2250    label $inner.particles -text "Particles" -font "Arial 9 bold"
2251    label $inner.boxes -text "Boxes" -font "Arial 9 bold"
2252
2253    blt::table $inner \
2254        1,0 $inner.showstreams  -anchor w \
2255        2,0 $inner.showarrows  -anchor w
2256    blt::table configure $inner c0 c1 -resize none
2257    blt::table configure $inner c2 -resize expand
2258
2259    set row 3
2260    set particles [$flowobj particles]
2261    if { [llength $particles] > 0 } {
2262        blt::table $inner $row,0 $inner.particles  -anchor w
2263        incr row
2264    }
2265    foreach part $particles {
2266        array unset info
2267        array set info $part
2268        set name $info(name)
2269        if { ![info exists _settings(-particles-$name)] } {
2270            set _settings(-particles-$name) $info(hide)
2271        }
2272        checkbutton $inner.part$row -text $info(label) \
2273            -variable [itcl::scope _settings(-particles-$name)] \
2274            -onvalue 0 -offvalue 1 \
2275            -command [itcl::code $this particles $key $name] \
2276            -font "Arial 9"
2277        Rappture::Tooltip::for $inner.part$row $info(description)
2278        blt::table $inner $row,0 $inner.part$row -anchor w
2279        if { !$_settings(-particles-$name) } {
2280            $inner.part$row select
2281        }
2282        incr row
2283    }
2284    set boxes [$flowobj boxes]
2285    if { [llength $boxes] > 0 } {
2286        blt::table $inner $row,0 $inner.boxes  -anchor w
2287        incr row
2288    }
2289    foreach box $boxes {
2290        array unset info
2291        array set info $box
2292        set name $info(name)
2293        if { ![info exists _settings(-box-$name)] } {
2294            set _settings(-box-$name) $info(hide)
2295        }
2296        checkbutton $inner.box$row -text $info(label) \
2297            -variable [itcl::scope _settings(-box-$name)] \
2298            -onvalue 0 -offvalue 1 \
2299            -command [itcl::code $this box $key $name] \
2300            -font "Arial 9"
2301        Rappture::Tooltip::for $inner.box$row $info(description)
2302        blt::table $inner $row,0 $inner.box$row -anchor w
2303        if { !$_settings(-box-$name) } {
2304            $inner.box$row select
2305        }
2306        incr row
2307    }
2308    blt::table configure $inner r* -resize none
2309    blt::table configure $inner r$row -resize expand
2310    blt::table configure $inner c3 -resize expand
2311    event generate [winfo parent [winfo parent $w]] <Configure>
2312}
2313
2314itcl::body Rappture::FlowvisViewer::particles { tag name } {
2315    set bool $_settings(-particles-$name)
2316    SendCmd "$tag particles configure {$name} -hide $bool"
2317}
2318
2319itcl::body Rappture::FlowvisViewer::box { tag name } {
2320    set bool $_settings(-box-$name)
2321    SendCmd "$tag box configure {$name} -hide $bool"
2322}
2323
2324itcl::body Rappture::FlowvisViewer::streams { tag name } {
2325    set bool $_settings(-streams)
2326    SendCmd "$tag configure -slice $bool"
2327}
2328
2329itcl::body Rappture::FlowvisViewer::arrows { tag name } {
2330    set bool $_settings(-arrows)
2331    SendCmd "$tag configure -arrows $bool"
2332}
2333
2334# ----------------------------------------------------------------------
2335# USAGE: Slice move x|y|z <newval>
2336#
2337# Called automatically when the user drags the slider to move the
2338# cut plane that slices 3D data.  Gets the current value from the
2339# slider and moves the cut plane to the appropriate point in the
2340# data set.
2341# ----------------------------------------------------------------------
2342itcl::body Rappture::FlowvisViewer::Slice {option args} {
2343    switch -- $option {
2344        move {
2345            if {[llength $args] != 2} {
2346                error "wrong # args: should be \"Slice move x|y|z newval\""
2347            }
2348            set axis [lindex $args 0]
2349            set newval [lindex $args 1]
2350
2351            set newpos [expr {0.01*$newval}]
2352            set datasets [CurrentDatasets -cutplanes]
2353            set tag [lindex $datasets 0]
2354            SendCmd "cutplane position $newpos $axis $tag"
2355        }
2356        default {
2357            error "bad option \"$option\": should be axis, move, or volume"
2358        }
2359    }
2360}
2361
2362# ----------------------------------------------------------------------
2363# USAGE: SlicerTip <axis>
2364#
2365# Used internally to generate a tooltip for the x/y/z slicer controls.
2366# Returns a message that includes the current slicer value.
2367# ----------------------------------------------------------------------
2368itcl::body Rappture::FlowvisViewer::SlicerTip {axis} {
2369    set val [$itk_component(${axis}CutScale) get]
2370    return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
2371}
2372
2373itcl::body Rappture::FlowvisViewer::DoResize {} {
2374    $_arcball resize $_width $_height
2375    SendCmd "screen size $_width $_height"
2376    set _resizePending 0
2377}
2378
2379itcl::body Rappture::FlowvisViewer::EventuallyResize { w h } {
2380    set _width $w
2381    set _height $h
2382    $_arcball resize $w $h
2383    if { !$_resizePending } {
2384        $_dispatcher event -after 200 !resize
2385        set _resizePending 1
2386    }
2387}
2388
2389itcl::body Rappture::FlowvisViewer::EventuallyRedrawLegend {} {
2390    if { !$_resizeLegendPending } {
2391        $_dispatcher event -after 100 !legend
2392        set _resizeLegendPending 1
2393    }
2394}
2395
2396itcl::body Rappture::FlowvisViewer::EventuallyGoto { nSteps } {
2397    set _flow(goto) $nSteps
2398    if { !$_gotoPending } {
2399        $_dispatcher event -after 1000 !goto
2400        set _gotoPending 1
2401    }
2402}
2403
2404#  camera --
2405#
2406itcl::body Rappture::FlowvisViewer::camera {option args} {
2407    switch -- $option {
2408        "show" {
2409            puts [array get _view]
2410        }
2411        "set" {
2412            set what [lindex $args 0]
2413            set x $_settings($what)
2414            set code [catch { string is double $x } result]
2415            if { $code != 0 || !$result } {
2416                set _settings($what) $_view($what)
2417                return
2418            }
2419            switch -- $what {
2420                "-xpan" - "-ypan" {
2421                    set _view($what) $_settings($what)
2422                    PanCamera
2423                }
2424                "-qx" - "-qy" - "-qz" - "-qw" {
2425                    set _view($what) $_settings($what)
2426                    set q [ViewToQuaternion]
2427                    $_arcball quaternion $q
2428                    SendCmd "camera orient $q"
2429                }
2430                "-zoom" {
2431                    set _view($what) $_settings($what)
2432                    SendCmd "camera zoom $_view($what)"
2433                }
2434            }
2435        }
2436    }
2437}
2438
2439itcl::body Rappture::FlowvisViewer::SendFlowCmd { dataobj comp nbytes numComponents } {
2440    set tag "$dataobj-$comp"
2441    if { ![info exists _dataset2flow($tag)] } {
2442        SendCmd "flow add $tag"
2443        SendCmd "$tag data follows $nbytes $numComponents"
2444        return 0
2445    }
2446    set flowobj $_dataset2flow($tag)
2447    if { $flowobj == "" } {
2448        puts stderr "no flowobj"
2449        return -1
2450    }
2451    SendCmd "if {\[flow exists $tag\]} {flow delete $tag}"
2452    array set info [$flowobj hints]
2453    set _settings(-volume) $info(volume)
2454    set _settings(-outlinevisible) $info(outline)
2455    set _settings(-arrows) $info(arrows)
2456    set _settings(-duration) $info(duration)
2457    $itk_component(speed) value $info(speed)
2458    set cmd {}
2459    append cmd "flow add $tag"
2460    append cmd " -position $info(position)"
2461    append cmd " -axis $info(axis)"
2462    append cmd " -volume $info(volume)"
2463    append cmd " -outline $info(outline)"
2464    append cmd " -slice $info(streams)"
2465    append cmd " -arrows $info(arrows)"
2466    SendCmd $cmd
2467    foreach part [$flowobj particles] {
2468        set cmd {}
2469        array unset info
2470        array set info $part
2471        set color [Color2RGB $info(color)]
2472        append cmd "$tag particles add $info(name)"
2473        append cmd " -position $info(position)"
2474        append cmd " -hide $info(hide)"
2475        append cmd " -axis $info(axis)"
2476        append cmd " -color {$color}"
2477        append cmd " -size $info(size)"
2478        SendCmd $cmd
2479    }
2480    foreach box [$flowobj boxes] {
2481        set cmd {}
2482        array unset info
2483        set info(corner1) ""
2484        set info(corner2) ""
2485        array set info $box
2486        if { $info(corner1) == "" || $info(corner2) == "" } {
2487            continue
2488        }
2489        set color [Color2RGB $info(color)]
2490        append cmd "$tag box add $info(name)"
2491        append cmd " -color {$color}"
2492        append cmd " -hide $info(hide)"
2493        append cmd " -linewidth $info(linewidth) "
2494        append cmd " -corner1 {$info(corner1)} "
2495        append cmd " -corner2 {$info(corner2)}"
2496        SendCmd $cmd
2497    }
2498    SendCmd "$tag data follows $nbytes $numComponents"
2499    return 0
2500}
2501
2502#
2503# flow --
2504#
2505# Called when the user clicks on the stop or play buttons
2506# for flow visualization.
2507#
2508#        $this flow play
2509#        $this flow stop
2510#        $this flow toggle
2511#        $this flow reset
2512#        $this flow pause
2513#        $this flow next
2514#
2515itcl::body Rappture::FlowvisViewer::flow { args } {
2516    set option [lindex $args 0]
2517    switch -- $option {
2518        "goto2" {
2519            puts stderr "actually sending \"flow goto $_flow(goto)\""
2520            SendCmd "flow goto $_flow(goto)"
2521            set _gotoPending 0
2522        }
2523        "goto" {
2524            puts stderr "flow goto to $_settings(-currenttime)"
2525            # Figure out how many steps to the current time based upon
2526            # the speed and duration.
2527            set current $_settings(-currenttime)
2528            set speed [$itk_component(speed) value]
2529            set time [str2millisecs $_settings(-duration)]
2530            $itk_component(dial) configure -max $time
2531            set delay [expr int(round(500.0/$speed))]
2532            set timePerStep [expr {double($time) / $delay}]
2533            set nSteps [expr {int(ceil($current/$timePerStep))}]
2534            EventuallyGoto $nSteps
2535        }
2536        "speed" {
2537            set speed [$itk_component(speed) value]
2538            set _flow(delay) [expr int(round(500.0/$speed))]
2539        }
2540        "duration" {
2541            set max [str2millisecs $_settings(-duration)]
2542            if { $max < 0 } {
2543                bell
2544                return
2545            }
2546            set _flow(duration) $max
2547            set _settings(-duration) [millisecs2str $max]
2548            $itk_component(dial) configure -max $max
2549        }
2550        "off" {
2551            set _flow(state) 0
2552            $_dispatcher cancel !play
2553            $itk_component(play) deselect
2554        }
2555        "on" {
2556            flow speed
2557            flow duration
2558            set _flow(state) 1
2559            set _settings(-currenttime) 0
2560            $itk_component(play) select
2561        }
2562        "stop" {
2563            if { $_flow(state) } {
2564                flow off
2565                flow reset
2566            }
2567        }
2568        "pause" {
2569            if { $_flow(state) } {
2570                flow off
2571            }
2572        }
2573        "play" {
2574            # If the flow is currently off, then restart it.
2575            if { !$_flow(state) } {
2576                flow on
2577                # If we're at the end of the flow, reset the flow.
2578                set _settings(-currenttime) \
2579                    [expr {$_settings(-currenttime) + $_flow(delay)}]
2580                if { $_settings(-currenttime) >= $_flow(duration) } {
2581                    set _settings(-step) 1
2582                    SendCmd "flow reset"
2583                }
2584                flow next
2585            }
2586        }
2587        "toggle" {
2588            if { $_settings(-play) } {
2589                flow play
2590            } else {
2591                flow pause
2592            }
2593        }
2594        "reset" {
2595            set _settings(-currenttime) 0
2596            SendCmd "flow reset"
2597        }
2598        "next" {
2599            if { ![winfo viewable $itk_component(3dview)] } {
2600                flow stop
2601                return
2602            }
2603            set _settings(-currenttime) \
2604                [expr {$_settings(-currenttime) + $_flow(delay)}]
2605            if { $_settings(-currenttime) >= $_flow(duration) } {
2606                if { !$_settings(-loop) } {
2607                    flow off
2608                    return
2609                }
2610                flow reset
2611            } else {
2612                SendCmd "flow next"
2613            }
2614            $_dispatcher event -after $_flow(delay) !play
2615        }
2616        default {
2617            error "bad option \"$option\": should be play, stop, toggle, or reset."
2618        }
2619    }
2620}
2621
2622itcl::body Rappture::FlowvisViewer::WaitIcon { option widget } {
2623    switch -- $option {
2624        "start" {
2625            $_dispatcher dispatch $this !waiticon \
2626                "[itcl::code $this WaitIcon "next" $widget] ; list"
2627            set _icon 0
2628            $widget configure -image [Rappture::icon bigroller${_icon}]
2629            $_dispatcher event -after 100 !waiticon
2630        }
2631        "next" {
2632            incr _icon
2633            if { $_icon >= 8 } {
2634                set _icon 0
2635            }
2636            $widget configure -image [Rappture::icon bigroller${_icon}]
2637            $_dispatcher event -after 100 !waiticon
2638        }
2639        "stop" {
2640            $_dispatcher cancel !waiticon
2641        }
2642    }
2643}
2644
2645itcl::body Rappture::FlowvisViewer::GetVtkData { args } {
2646    # FIXME: We can only put one component of one dataset in a single
2647    # VTK file.  To download all components/results, we would need
2648    # to put them in an archive (e.g. zip or tar file)
2649    if { $_first != "" } {
2650        set cname [lindex [$_first components] 0]
2651        set bytes [$_first vtkdata $cname]
2652        return [list .vtk $bytes]
2653    }
2654    puts stderr "Failed to get vtkdata"
2655    return ""
2656}
2657
2658itcl::body Rappture::FlowvisViewer::GetImage { args } {
2659    if { [image width $_image(download)] > 0 &&
2660         [image height $_image(download)] > 0 } {
2661        set bytes [$_image(download) data -format "jpeg -quality 100"]
2662        set bytes [Rappture::encoding::decode -as b64 $bytes]
2663        return [list .jpg $bytes]
2664    }
2665    return ""
2666}
2667
2668itcl::body Rappture::FlowvisViewer::GetPngImage { widget width height } {
2669    set token "print[incr _nextToken]"
2670    set var ::Rappture::FlowvisViewer::_hardcopy($this-$token)
2671    set $var ""
2672
2673    # Setup an automatic timeout procedure.
2674    $_dispatcher dispatch $this !pngtimeout "set $var {} ; list"
2675
2676    set popup .flowvisviewerprint
2677    if {![winfo exists $popup]} {
2678        Rappture::Balloon $popup -title "Generating file..."
2679        set inner [$popup component inner]
2680        label $inner.title -text "Generating hardcopy." -font "Arial 10 bold"
2681        label $inner.please -text "This may take a minute." -font "Arial 10"
2682        label $inner.icon -image [Rappture::icon bigroller0]
2683        button $inner.cancel -text "Cancel" -font "Arial 10 bold" \
2684            -command [list set $var ""]
2685        blt::table $inner \
2686            0,0 $inner.title -cspan 2 \
2687            1,0 $inner.please -anchor w \
2688            1,1 $inner.icon -anchor e  \
2689            2,0 $inner.cancel -cspan 2
2690        blt::table configure $inner r0 -pady 4
2691        blt::table configure $inner r2 -pady 4
2692        bind $inner.cancel <KeyPress-Return> [list $inner.cancel invoke]
2693    } else {
2694        set inner [$popup component inner]
2695    }
2696
2697    $_dispatcher event -after 60000 !pngtimeout
2698    WaitIcon start $inner.icon
2699    grab set $inner
2700    focus $inner.cancel
2701
2702    SendCmd "print $token $width $height"
2703
2704    $popup activate $widget below
2705    update idletasks
2706    update
2707    # We wait here for either
2708    #  1) the png to be delivered or
2709    #  2) timeout or
2710    #  3) user cancels the operation.
2711    tkwait variable $var
2712
2713    # Clean up.
2714    $_dispatcher cancel !pngtimeout
2715    WaitIcon stop $inner.icon
2716    grab release $inner
2717    $popup deactivate
2718    update
2719
2720    if { $_hardcopy($this-$token) != "" } {
2721        return [list .png $_hardcopy($this-$token)]
2722    }
2723    return ""
2724}
2725
2726itcl::body Rappture::FlowvisViewer::GetMovie { widget w h } {
2727    set token "movie[incr _nextToken]"
2728    set var ::Rappture::FlowvisViewer::_hardcopy($this-$token)
2729    set $var ""
2730
2731    # Setup an automatic timeout procedure.
2732    $_dispatcher dispatch $this !movietimeout "set $var {} ; list"
2733    set popup .flowvisviewermovie
2734    if {![winfo exists $popup]} {
2735        Rappture::Balloon $popup -title "Generating movie..."
2736        set inner [$popup component inner]
2737        label $inner.title -text "Generating movie for download" \
2738                -font "Arial 10 bold"
2739        label $inner.please -text "This may take a few minutes." \
2740                -font "Arial 10"
2741        label $inner.icon -image [Rappture::icon bigroller0]
2742        button $inner.cancel -text "Cancel" -font "Arial 10 bold" \
2743            -command [list set $var ""]
2744        blt::table $inner \
2745            0,0 $inner.title -cspan 2 \
2746            1,0 $inner.please -anchor w \
2747            1,1 $inner.icon -anchor e  \
2748            2,0 $inner.cancel -cspan 2
2749        blt::table configure $inner r0 -pady 4
2750        blt::table configure $inner r2 -pady 4
2751        bind $inner.cancel <KeyPress-Return> [list $inner.cancel invoke]
2752    } else {
2753        set inner [$popup component inner]
2754    }
2755    update
2756    # Timeout is set to 10 minutes.
2757    $_dispatcher event -after 600000 !movietimeout
2758    WaitIcon start $inner.icon
2759    grab set $inner
2760    focus $inner.cancel
2761
2762    flow duration
2763    flow speed
2764    set nframes [expr round($_flow(duration) / $_flow(delay))]
2765    set framerate [expr 1000.0 / $_flow(delay)]
2766
2767    # These are specific to MPEG1 video generation
2768    set framerate 25.0
2769    set bitrate 6.0e+6
2770
2771    set start [clock seconds]
2772    SendCmd "flow video $token -width $w -height $h -numframes $nframes "
2773
2774    $popup activate $widget below
2775    update idletasks
2776    update
2777    # We wait here until
2778    #  1. the movie is delivered or
2779    #  2. we've timed out or
2780    #  3. the user has canceled the operation.b
2781    tkwait variable $var
2782
2783    puts stderr "Video generated in [expr [clock seconds] - $start] seconds."
2784
2785    # Clean up.
2786    $_dispatcher cancel !movietimeout
2787    WaitIcon stop $inner.icon
2788    grab release $inner
2789    $popup deactivate
2790    destroy $popup
2791    update
2792
2793    # This will both cancel the movie generation (if it hasn't already
2794    # completed) and reset the flow.
2795    SendCmd "flow reset"
2796    if { $_hardcopy($this-$token) != "" } {
2797        return [list .mpg $_hardcopy($this-$token)]
2798    }
2799    return ""
2800}
2801
2802itcl::body Rappture::FlowvisViewer::BuildDownloadPopup { popup command } {
2803    Rappture::Balloon $popup \
2804        -title "[Rappture::filexfer::label downloadWord] as..."
2805    set inner [$popup component inner]
2806    label $inner.summary -text "" -anchor w
2807    radiobutton $inner.vtk_button -text "VTK data file" \
2808        -variable [itcl::scope _downloadPopup(format)] \
2809        -font "Arial 9" \
2810        -value vtk
2811    Rappture::Tooltip::for $inner.vtk_button "Save as VTK data file."
2812
2813    radiobutton $inner.image_button -text "Image File" \
2814        -variable [itcl::scope _downloadPopup(format)] \
2815        -font "Arial 9 " \
2816        -value image
2817    Rappture::Tooltip::for $inner.image_button \
2818        "Save as digital image."
2819
2820    set res "640x480"
2821    radiobutton $inner.movie_std -text "Movie (standard $res)" \
2822        -variable [itcl::scope _downloadPopup(format)] \
2823        -value $res
2824    Rappture::Tooltip::for $inner.movie_std \
2825        "Save as movie file."
2826
2827    set res "1024x768"
2828    radiobutton $inner.movie_high -text "Movie (high quality $res)" \
2829        -variable [itcl::scope _downloadPopup(format)] \
2830        -value $res
2831    Rappture::Tooltip::for $inner.movie_high \
2832        "Save as movie file."
2833
2834    button $inner.ok -text "Save" \
2835        -highlightthickness 0 -pady 2 -padx 3 \
2836        -command $command \
2837        -compound left \
2838        -image [Rappture::icon download]
2839
2840    button $inner.cancel -text "Cancel" \
2841        -highlightthickness 0 -pady 2 -padx 3 \
2842        -command [list $popup deactivate] \
2843        -compound left \
2844        -image [Rappture::icon cancel]
2845
2846    blt::table $inner \
2847        0,0 $inner.summary -cspan 2  \
2848        1,0 $inner.vtk_button -anchor w -cspan 2 -padx { 4 0 } \
2849        2,0 $inner.image_button -anchor w -cspan 2 -padx { 4 0 } \
2850        3,0 $inner.movie_std -anchor w -cspan 2 -padx { 4 0 } \
2851        4,0 $inner.movie_high -anchor w -cspan 2 -padx { 4 0 } \
2852        6,1 $inner.cancel -width .9i -fill y \
2853        6,0 $inner.ok -padx 2 -width .9i -fill y
2854    blt::table configure $inner r5 -height 4
2855    blt::table configure $inner r6 -pady 4
2856    raise $inner.image_button
2857    $inner.vtk_button invoke
2858    return $inner
2859}
2860
2861itcl::body Rappture::FlowvisViewer::str2millisecs { value } {
2862    set parts [split $value :]
2863    set secs 0
2864    set mins 0
2865    if { [llength $parts] == 1 } {
2866        scan [lindex $parts 0] "%d" secs
2867    } else {
2868        scan [lindex $parts 1] "%d" secs
2869        scan [lindex $parts 0] "%d" mins
2870    }
2871    set ms [expr {(($mins * 60) + $secs) * 1000.0}]
2872    if { $ms > 600000.0 } {
2873        set ms 600000.0
2874    }
2875    if { $ms == 0.0 } {
2876        set ms 60000.0
2877    }
2878    return $ms
2879}
2880
2881itcl::body Rappture::FlowvisViewer::millisecs2str { value } {
2882    set min [expr floor($value / 60000.0)]
2883    set sec [expr ($value - ($min*60000.0)) / 1000.0]
2884    return [format %02d:%02d [expr round($min)] [expr round($sec)]]
2885}
2886
2887itcl::body Rappture::FlowvisViewer::SetOrientation { side } {
2888    array set positions {
2889        front "1 0 0 0"
2890        back  "0 0 1 0"
2891        left  "0.707107 0 -0.707107 0"
2892        right "0.707107 0 0.707107 0"
2893        top   "0.707107 -0.707107 0 0"
2894        bottom "0.707107 0.707107 0 0"
2895    }
2896    foreach name { -qw -qx -qy -qz } value $positions($side) {
2897        set _view($name) $value
2898    }
2899    set q [ViewToQuaternion]
2900    $_arcball quaternion $q
2901    SendCmd "camera orient $q"
2902    SendCmd "camera reset"
2903    set _view(-xpan) 0
2904    set _view(-ypan) 0
2905    set _view(-zoom) 1.0
2906    set _settings(-xpan) $_view(-xpan)
2907    set _settings(-ypan) $_view(-ypan)
2908    set _settings(-zoom) $_view(-zoom)
2909}
2910
2911#
2912# BuildVolumeComponents --
2913#
2914#    This is called from the "scale" method which is called when a new
2915#    dataset is added or deleted.  It repopulates the dropdown menu of
2916#    volume component names.  It sets the current component to the first
2917#    component in the list (of components found).  Finally, if there is
2918#    only one component, don't display the label or the combobox in the
2919#    volume settings tab.
2920#
2921itcl::body Rappture::FlowvisViewer::BuildVolumeComponents {} {
2922    $itk_component(volcomponents) choices delete 0 end
2923    foreach name $_componentsList {
2924        $itk_component(volcomponents) choices insert end $name $name
2925    }
2926    set _current [lindex $_componentsList 0]
2927    $itk_component(volcomponents) value $_current
2928}
2929
2930#
2931# GetDatasetsWithComponents --
2932#
2933#    Returns a list of all the datasets (known by the combination of their
2934#    data object and component name) that match the given component name.
2935#    For example, this is used where we want to change the settings of
2936#    volumes that have the current component.
2937#
2938itcl::body Rappture::FlowvisViewer::GetDatasetsWithComponent { cname } {
2939    if { ![info exists _volcomponents($cname)] } {
2940        return ""
2941    }
2942    set list ""
2943    foreach tag $_volcomponents($cname) {
2944        if { ![info exists _datasets($tag)] } {
2945            continue
2946        }
2947        lappend list $tag
2948    }
2949    return $list
2950}
Note: See TracBrowser for help on using the repository browser.