source: branches/1.4/gui/scripts/flowvisviewer.tcl @ 5278

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

merge r5276 from trunk

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