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

Last change on this file since 1315 was 1315, checked in by gah, 15 years ago

Added new icons for nanovisviewer

File size: 55.8 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: flowvisviewer - 3D vector field rendering
3#
4#  This widget performs vector field rendering on 3D scalar/vector datasets.
5#  It connects to the Nanovis server running on a rendering farm,
6#  transmits data, and displays the results.
7# ======================================================================
8#  AUTHOR:  Derrick Kearney, Purdue University
9#  Copyright (c) 2005-2009  Purdue Research Foundation
10#
11#  See the file "license.terms" for information on usage and
12#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13# ======================================================================
14
15package require Itk
16package require BLT
17package require Img
18
19option add *FlowvisViewer.width 4i widgetDefault
20option add *FlowvisViewer.height 4i widgetDefault
21option add *FlowvisViewer.foreground black widgetDefault
22option add *FlowvisViewer.controlBackground gray widgetDefault
23option add *FlowvisViewer.controlDarkBackground #999999 widgetDefault
24option add *FlowvisViewer.plotBackground black widgetDefault
25option add *FlowvisViewer.plotForeground white widgetDefault
26option add *FlowvisViewer.plotOutline white widgetDefault
27option add *FlowvisViewer.font \
28    -*-helvetica-medium-r-normal-*-12-* widgetDefault
29option add *FlowvisViewer.boldFont \
30    -*-helvetica-bold-r-normal-*-12-* widgetDefault
31
32# must use this name -- plugs into Rappture::resources::load
33proc FlowvisViewer_init_resources {} {
34    Rappture::resources::register \
35        nanovis_server Rappture::FlowvisViewer::SetServerList
36}
37
38itcl::class Rappture::FlowvisViewer {
39    inherit Rappture::VisViewer
40
41    itk_option define -plotforeground plotForeground Foreground ""
42    itk_option define -plotbackground plotBackground Background ""
43    itk_option define -plotoutline plotOutline PlotOutline ""
44
45    constructor { hostlist args } {
46        Rappture::VisViewer::constructor $hostlist
47    } {
48        # defined below
49    }
50    destructor {
51        # defined below
52    }
53
54    public proc SetServerList { namelist } {
55        Rappture::VisViewer::SetServerList "nanovis" $namelist
56    }
57    public method add {dataobj {settings ""}}
58    public method get {args}
59    public method delete {args}
60    public method scale {args}
61    public method download {option args}
62    public method parameters {title args} {
63        # do nothing
64    }
65    public method isconnected {}
66
67    protected method Connect {}
68    protected method Disconnect {}
69
70    protected method _send {string}
71    protected method _send_dataobjs {}
72    protected method ReceiveImage {option size}
73    protected method ReceiveFile {option size}
74    private method ReceiveLegend {tf vmin vmax size}
75    protected method _receive_echo {channel {data ""}}
76
77    protected method _rebuild {}
78    protected method _currentVolumeIds {{what -all}}
79    protected method _zoom {option}
80    protected method _pan {option x y}
81    protected method _rotate {option x y}
82    protected method _slice {option args}
83    protected method _slicertip {axis}
84
85    protected method _flow {option args}
86    protected method _play {}
87    protected method _pause {}
88
89    protected method _state {comp}
90    protected method _fixSettings {what {value ""}}
91    protected method _getTransfuncData {dataobj comp}
92
93
94    private variable outbuf_       ;# buffer for outgoing commands
95
96    private variable dlist_ ""     ;# list of data objects
97    private variable obj2style_    ;# maps dataobj => style settings
98    private variable obj2ovride_   ;# maps dataobj => style override
99    private variable obj2id_       ;# maps dataobj => heightmap ID in server
100    private variable id2obj_       ;# maps heightmap ID => dataobj in server
101    private variable sendobjs_ ""  ;# list of data objs to send to server
102    private variable receiveIds_   ;# list of data responses from the server
103    private variable click_        ;# info used for _rotate operations
104    private variable limits_       ;# autoscale min/max for all axes
105    private variable view_         ;# view params for 3D view
106
107    private common settings_       ;# Array used for checkbuttons and radiobuttons
108    private variable activeTf_ ""  ;# The currently active transfer function.
109
110    common _downloadPopup          ;# download options from popup
111
112    private variable _afterId ""   ;# current "after" event for play op
113    private common _play           ;# options for "play" operation
114    set _play(speed) 10
115}
116
117itk::usual FlowvisViewer {
118    keep -background -foreground -cursor -font
119    keep -plotbackground -plotforeground
120}
121
122# ----------------------------------------------------------------------
123# CONSTRUCTOR
124# ----------------------------------------------------------------------
125itcl::body Rappture::FlowvisViewer::constructor {hostlist args} {
126    # Send dataobjs event
127    $_dispatcher register !send_dataobjs
128    $_dispatcher dispatch $this !send_dataobjs \
129        "[itcl::code $this _send_dataobjs]; list"
130    # Rebuild event
131    $_dispatcher register !rebuild
132    $_dispatcher dispatch $this !rebuild "[itcl::code $this _rebuild]; list"
133
134    array set _downloadPopup {
135        format jpg
136    }
137
138    set outbuf_ ""
139
140    #
141    # Populate parser with commands handle incoming requests
142    #
143    $_parser alias image [itcl::code $this ReceiveImage]
144    $_parser alias file [itcl::code $this ReceiveFile]
145
146    # Initialize the view to some default parameters.
147    array set view_ {
148        theta   45
149        phi     45
150        psi     0
151        zoom    1.0
152        dx      0
153        dy      0
154    }
155    set obj2id_(count) 0
156
157    itk_component add zoom {
158        frame $itk_component(controls).zoom
159    } {
160        usual
161        rename -background -controlbackground controlBackground Background
162    }
163    pack $itk_component(zoom) -side top
164
165    itk_component add reset {
166        button $itk_component(zoom).reset \
167            -borderwidth 1 -padx 1 -pady 1 \
168            -image [Rappture::icon reset-view] \
169            -command [itcl::code $this _zoom reset]
170    } {
171        usual
172        ignore -borderwidth
173        rename -highlightbackground -controlbackground controlBackground Background
174    }
175    pack $itk_component(reset) -side left -padx {4 1} -pady 4
176    Rappture::Tooltip::for $itk_component(reset) "Reset the view to the default zoom level"
177
178    itk_component add zoomin {
179        button $itk_component(zoom).zin \
180            -borderwidth 1 -padx 1 -pady 1 \
181            -image [Rappture::icon zoom-in] \
182            -command [itcl::code $this _zoom in]
183    } {
184        usual
185        ignore -borderwidth
186        rename -highlightbackground -controlbackground controlBackground Background
187    }
188    pack $itk_component(zoomin) -side left -padx 1 -pady 4
189    Rappture::Tooltip::for $itk_component(zoomin) "Zoom in"
190
191    itk_component add zoomout {
192        button $itk_component(zoom).zout \
193            -borderwidth 1 -padx 1 -pady 1 \
194            -image [Rappture::icon zoom-out] \
195            -command [itcl::code $this _zoom out]
196    } {
197        usual
198        ignore -borderwidth
199        rename -highlightbackground -controlbackground controlBackground Background
200    }
201    pack $itk_component(zoomout) -side left -padx {1 4} -pady 4
202    Rappture::Tooltip::for $itk_component(zoomout) "Zoom out"
203
204    #
205    # Create slicer controls...
206    #
207    itk_component add slicers {
208        frame $itk_component(controls).slicers
209    } {
210        usual
211        rename -background -controlbackground controlBackground Background
212    }
213    pack $itk_component(slicers) -side bottom -padx 4 -pady 4
214    grid rowconfigure $itk_component(slicers) 1 -weight 1
215    #
216    # X-value slicer...
217    #
218    itk_component add xslice {
219        label $itk_component(slicers).xslice \
220            -borderwidth 1 -relief raised -padx 1 -pady 1 \
221            -image [Rappture::icon x-cutplane]
222    } {
223        usual
224        ignore -borderwidth
225        rename -highlightbackground -controlbackground controlBackground Background
226    }
227    bind $itk_component(xslice) <ButtonPress> \
228        [itcl::code $this _slice axis x toggle]
229    Rappture::Tooltip::for $itk_component(xslice) \
230        "Toggle the X cut plane on/off"
231    grid $itk_component(xslice) -row 1 -column 0 -sticky ew -padx 1
232
233    itk_component add xslicer {
234        ::scale $itk_component(slicers).xval -from 100 -to 0 \
235            -width 10 -orient vertical -showvalue off \
236            -borderwidth 1 -highlightthickness 0 \
237            -command [itcl::code $this _slice move x]
238    } {
239        usual
240        ignore -borderwidth
241        ignore -highlightthickness
242        rename -highlightbackground -controlbackground controlBackground Background
243        rename -troughcolor -controldarkbackground controlDarkBackground Background
244    }
245    $itk_component(xslicer) set 50
246    $itk_component(xslicer) configure -state disabled
247    grid $itk_component(xslicer) -row 2 -column 0 -padx 1
248    Rappture::Tooltip::for $itk_component(xslicer) \
249        "@[itcl::code $this _slicertip x]"
250
251    #
252    # Y-value slicer...
253    #
254    itk_component add yslice {
255        label $itk_component(slicers).yslice \
256            -borderwidth 1 -relief raised -padx 1 -pady 1 \
257            -image [Rappture::icon y-cutplane]
258    } {
259        usual
260        ignore -borderwidth
261        rename -highlightbackground -controlbackground controlBackground Background
262    }
263    bind $itk_component(yslice) <ButtonPress> \
264        [itcl::code $this _slice axis y toggle]
265    Rappture::Tooltip::for $itk_component(yslice) \
266        "Toggle the Y cut plane on/off"
267    grid $itk_component(yslice) -row 1 -column 1 -sticky ew -padx 1
268
269    itk_component add yslicer {
270        ::scale $itk_component(slicers).yval -from 100 -to 0 \
271            -width 10 -orient vertical -showvalue off \
272            -borderwidth 1 -highlightthickness 0 \
273            -command [itcl::code $this _slice move y]
274    } {
275        usual
276        ignore -borderwidth
277        ignore -highlightthickness
278        rename -highlightbackground -controlbackground controlBackground Background
279        rename -troughcolor -controldarkbackground controlDarkBackground Background
280    }
281    $itk_component(yslicer) set 50
282    $itk_component(yslicer) configure -state disabled
283    grid $itk_component(yslicer) -row 2 -column 1 -padx 1
284    Rappture::Tooltip::for $itk_component(yslicer) \
285        "@[itcl::code $this _slicertip y]"
286
287    #
288    # Z-value slicer...
289    #
290    itk_component add zslice {
291        label $itk_component(slicers).zslice \
292            -borderwidth 1 -relief raised -padx 1 -pady 1 \
293            -image [Rappture::icon z-cutplane]
294    } {
295        usual
296        ignore -borderwidth
297        rename -highlightbackground -controlbackground controlBackground Background
298    }
299    grid $itk_component(zslice) -row 1 -column 2 -sticky ew -padx 1
300    bind $itk_component(zslice) <ButtonPress> \
301        [itcl::code $this _slice axis z toggle]
302    Rappture::Tooltip::for $itk_component(zslice) \
303        "Toggle the Z cut plane on/off"
304
305    itk_component add zslicer {
306        ::scale $itk_component(slicers).zval -from 100 -to 0 \
307            -width 10 -orient vertical -showvalue off \
308            -borderwidth 1 -highlightthickness 0 \
309            -command [itcl::code $this _slice move z]
310    } {
311        usual
312        ignore -borderwidth
313        ignore -highlightthickness
314        rename -highlightbackground -controlbackground controlBackground Background
315        rename -troughcolor -controldarkbackground controlDarkBackground Background
316    }
317    $itk_component(zslicer) set 50
318    $itk_component(zslicer) configure -state disabled
319    grid $itk_component(zslicer) -row 2 -column 2 -padx 1
320    Rappture::Tooltip::for $itk_component(zslicer) \
321        "@[itcl::code $this _slicertip z]"
322
323    #
324    # Volume toggle...
325    #
326    itk_component add volume {
327        label $itk_component(slicers).volume \
328            -borderwidth 1 -relief sunken -padx 1 -pady 1 \
329            -text "Volume"
330    } {
331        usual
332        ignore -borderwidth
333        rename -highlightbackground -controlbackground controlBackground Background
334    }
335    bind $itk_component(volume) <ButtonPress> \
336        [itcl::code $this _slice volume toggle]
337    Rappture::Tooltip::for $itk_component(volume) \
338        "Toggle the volume cloud on/off"
339    grid $itk_component(volume) -row 0 -column 0 -columnspan 3 \
340        -sticky ew -padx 1 -pady 3
341
342    #
343    # Settings panel...
344    #
345    itk_component add settings {
346        button $itk_component(controls).settings -text "Settings..." \
347            -borderwidth 1 -relief flat -overrelief raised \
348            -padx 2 -pady 1 \
349            -command [list $itk_component(controls).panel activate $itk_component(controls).settings left]
350    } {
351        usual
352        ignore -borderwidth
353        rename -background -controlbackground controlBackground Background
354        rename -highlightbackground -controlbackground controlBackground Background
355    }
356    pack $itk_component(settings) -side top -pady 2
357
358    Rappture::Balloon $itk_component(controls).panel -title "Settings"
359    set inner [$itk_component(controls).panel component inner]
360    frame $inner.scales
361    pack $inner.scales -side top -fill x
362    grid columnconfigure $inner.scales 1 -weight 1
363    set fg [option get $itk_component(hull) font Font]
364    set bfg [option get $itk_component(hull) boldFont Font]
365
366    label $inner.scales.diml -text "Dim" -font $fg
367    grid $inner.scales.diml -row 0 -column 0 -sticky e
368    ::scale $inner.scales.light -from 0 -to 100 -orient horizontal \
369        -showvalue off -command [itcl::code $this _fixSettings light]
370    grid $inner.scales.light -row 0 -column 1 -sticky ew
371    label $inner.scales.brightl -text "Bright" -font $fg
372    grid $inner.scales.brightl -row 0 -column 2 -sticky w
373    $inner.scales.light set 20
374
375    label $inner.scales.fogl -text "Fog" -font $fg
376    grid $inner.scales.fogl -row 1 -column 0 -sticky e
377    ::scale $inner.scales.transp -from 0 -to 100 -orient horizontal \
378        -showvalue off -command [itcl::code $this _fixSettings transp]
379    grid $inner.scales.transp -row 1 -column 1 -sticky ew
380    label $inner.scales.plasticl -text "Plastic" -font $fg
381    grid $inner.scales.plasticl -row 1 -column 2 -sticky w
382    $inner.scales.transp set 20
383
384    label $inner.scales.zerol -text "Clear" -font $fg
385    grid $inner.scales.zerol -row 2 -column 0 -sticky e
386    ::scale $inner.scales.opacity -from 0 -to 100 -orient horizontal \
387        -showvalue off -command [itcl::code $this _fixSettings opacity]
388    grid $inner.scales.opacity -row 2 -column 1 -sticky ew
389    label $inner.scales.onel -text "Opaque" -font $fg
390    grid $inner.scales.onel -row 2 -column 2 -sticky w
391    $inner.scales.opacity set 100
392
393    label $inner.scales.thinl -text "Thin" -font $fg
394    grid $inner.scales.thinl -row 3 -column 0 -sticky e
395    ::scale $inner.scales.thickness -from 0 -to 1000 -orient horizontal \
396        -showvalue off -command [itcl::code $this _fixSettings thickness]
397    grid $inner.scales.thickness -row 3 -column 1 -sticky ew
398    label $inner.scales.thickl -text "Thick" -font $fg
399    grid $inner.scales.thickl -row 3 -column 2 -sticky w
400    $inner.scales.thickness set 350
401
402    set ::Rappture::FlowvisViewer::settings_($this-isosurface) 0
403    ::checkbutton $inner.scales.isosurface \
404        -text "Isosurface shading" \
405        -variable ::Rappture::FlowvisViewer::settings_($this-isosurface) \
406        -command [itcl::code $this _fixSettings isosurface]
407    grid $inner.scales.isosurface -row 4 -column 0 -columnspan 2 -sticky w
408
409    set ::Rappture::FlowvisViewer::settings_($this-axes) 1
410    ::checkbutton $inner.scales.axes \
411        -text "Axes" \
412        -variable ::Rappture::FlowvisViewer::settings_($this-axes) \
413        -command [itcl::code $this _fixSettings axes]
414    grid $inner.scales.axes -row 5 -column 0 -columnspan 2 -sticky w
415
416    set ::Rappture::FlowvisViewer::settings_($this-grid) 0
417    ::checkbutton $inner.scales.grid \
418        -text "Grid" \
419        -variable ::Rappture::FlowvisViewer::settings_($this-grid) \
420        -command [itcl::code $this _fixSettings grid]
421    grid $inner.scales.grid -row 6 -column 0 -columnspan 2 -sticky w
422
423    set ::Rappture::FlowvisViewer::settings_($this-outline) 1
424    ::checkbutton $inner.scales.outline \
425        -text "Outline" \
426        -variable ::Rappture::FlowvisViewer::settings_($this-outline) \
427        -command [itcl::code $this _fixSettings outline]
428    grid $inner.scales.outline -row 7 -column 0 -columnspan 2 -sticky w
429
430    set ::Rappture::FlowvisViewer::settings_($this-particlevis) 1
431    ::checkbutton $inner.scales.particlevis \
432        -text "Particle Visible" \
433        -variable ::Rappture::FlowvisViewer::settings_($this-particlevis) \
434        -command [itcl::code $this _fixSettings particlevis]
435    grid $inner.scales.particlevis -row 8 -column 0 -columnspan 2 -sticky w
436
437    set ::Rappture::FlowvisViewer::settings_($this-lic) 1
438    ::checkbutton $inner.scales.lic \
439        -text "Lic" \
440        -variable ::Rappture::FlowvisViewer::settings_($this-lic) \
441        -command [itcl::code $this _fixSettings lic]
442    grid $inner.scales.lic -row 9 -column 0 -columnspan 2 -sticky w
443
444# how do we know when to make something an itk component?
445
446    label $inner.scales.framecntlabel -text "# Frames" -font $fg
447    grid $inner.scales.framecntlabel -row 10 -column 0 -sticky e
448    Rappture::Spinint $inner.scales.framecnt
449    $inner.scales.framecnt value 100
450    grid $inner.scales.framecnt -row 10 -column 1 -sticky w
451
452    label $inner.scales.speedl -text "Flow Speed:" -font $bfg
453    grid $inner.scales.speedl -row 11 -column 0 -sticky e
454    frame $inner.scales.speed
455    grid $inner.scales.speed -row 11 -column 1 -sticky ew
456    label $inner.scales.speed.slowl -text "Slower" -font $fg
457    pack $inner.scales.speed.slowl -side left
458    ::scale $inner.scales.speed.value -from 100 -to 1 \
459        -showvalue 0 -orient horizontal \
460        -variable ::Rappture::FlowvisViewer::_play(speed)
461    pack $inner.scales.speed.value -side left
462    label $inner.scales.speed.fastl -text "Faster" -font $fg
463    pack $inner.scales.speed.fastl -side left
464
465    #
466    # Create flow controls...
467    #
468    itk_component add flowctrl {
469        frame $itk_component(controls).flowctrl
470    } {
471        usual
472        rename -background -controlbackground controlBackground Background
473    }
474    pack $itk_component(flowctrl) -side top -padx 4 -pady 4
475    grid rowconfigure $itk_component(flowctrl) 1 -weight 1
476
477    #
478    # flow record button...
479    #
480    itk_component add record {
481        label $itk_component(flowctrl).record \
482            -borderwidth 1 -relief raised -padx 1 -pady 1 \
483            -image [Rappture::icon playback-record]
484    } {
485        usual
486        ignore -borderwidth
487        rename -highlightbackground -controlbackground controlBackground Background
488    }
489    bind $itk_component(record) <ButtonPress> \
490        [itcl::code $this _flow movie record toggle]
491    Rappture::Tooltip::for $itk_component(record) \
492        "Record flow visualization"
493    grid $itk_component(record) -row 1 -column 0 -sticky ew -padx 1
494
495    #
496    # flow stop button...
497    #
498    itk_component add stop {
499        label $itk_component(flowctrl).stop \
500            -borderwidth 1 -relief sunken -state disable -padx 1 -pady 1 \
501            -image [Rappture::icon playback-stop]
502    } {
503        usual
504        ignore -borderwidth
505        rename -highlightbackground -controlbackground controlBackground Background
506    }
507    bind $itk_component(stop) <ButtonPress> \
508        [itcl::code $this _flow movie stop toggle]
509    Rappture::Tooltip::for $itk_component(stop) \
510        "Stop flow visualization"
511    grid $itk_component(stop) -row 1 -column 1 -sticky ew -padx 1
512
513    #
514    # flow play/pause button...
515    #
516    itk_component add play {
517        label $itk_component(flowctrl).play \
518            -borderwidth 1 -relief raised -padx 1 -pady 1 \
519            -image [Rappture::icon playback-start]
520    } {
521        usual
522        ignore -borderwidth
523        rename -highlightbackground -controlbackground controlBackground Background
524    }
525    bind $itk_component(play) <ButtonPress> \
526        [itcl::code $this _flow movie play toggle]
527    Rappture::Tooltip::for $itk_component(play) \
528        "Play/Pause flow visualization"
529    grid $itk_component(play) -row 1 -column 2 -sticky ew -padx 1
530
531    # Bindings for rotation via mouse
532    bind $itk_component(3dview) <ButtonPress-1> \
533        [itcl::code $this _rotate click %x %y]
534    bind $itk_component(3dview) <B1-Motion> \
535        [itcl::code $this _rotate drag %x %y]
536    bind $itk_component(3dview) <ButtonRelease-1> \
537        [itcl::code $this _rotate release %x %y]
538    bind $itk_component(3dview) <Configure> \
539        [itcl::code $this _send "screen %w %h"]
540
541    # Bindings for panning via mouse
542    bind $itk_component(3dview) <ButtonPress-2> \
543        [itcl::code $this _pan click %x %y]
544    bind $itk_component(3dview) <B2-Motion> \
545        [itcl::code $this _pan drag %x %y]
546    bind $itk_component(3dview) <ButtonRelease-2> \
547        [itcl::code $this _pan release %x %y]
548
549    # Bindings for panning via keyboard
550    bind $itk_component(3dview) <KeyPress-Left> \
551        [itcl::code $this _pan set -10 0]
552    bind $itk_component(3dview) <KeyPress-Right> \
553        [itcl::code $this _pan set 10 0]
554    bind $itk_component(3dview) <KeyPress-Up> \
555        [itcl::code $this _pan set 0 -10]
556    bind $itk_component(3dview) <KeyPress-Down> \
557        [itcl::code $this _pan set 0 10]
558    bind $itk_component(3dview) <Shift-KeyPress-Left> \
559        [itcl::code $this _pan set -2 0]
560    bind $itk_component(3dview) <Shift-KeyPress-Right> \
561        [itcl::code $this _pan set 2 0]
562    bind $itk_component(3dview) <Shift-KeyPress-Up> \
563        [itcl::code $this _pan set 0 -2]
564    bind $itk_component(3dview) <Shift-KeyPress-Down> \
565        [itcl::code $this _pan set 0 2]
566
567    # Bindings for zoom via keyboard
568    bind $itk_component(3dview) <KeyPress-Prior> \
569        [itcl::code $this _zoom out]
570    bind $itk_component(3dview) <KeyPress-Next> \
571        [itcl::code $this _zoom in]
572
573    bind $itk_component(3dview) <Enter> "focus $itk_component(3dview)"
574
575    if {[string equal "x11" [tk windowingsystem]]} {
576        # Bindings for zoom via mouse
577        bind $itk_component(3dview) <4> [itcl::code $this _zoom out]
578        bind $itk_component(3dview) <5> [itcl::code $this _zoom in]
579    }
580
581    set _image(download) [image create photo]
582
583    eval itk_initialize $args
584
585    Connect
586}
587
588# ----------------------------------------------------------------------
589# DESTRUCTOR
590# ----------------------------------------------------------------------
591itcl::body Rappture::FlowvisViewer::destructor {} {
592    set sendobjs_ ""  ;# stop any send in progress
593    $_dispatcher cancel !rebuild
594    $_dispatcher cancel !send_dataobjs
595    image delete $_image(plot)
596    image delete $_image(download)
597}
598
599# ----------------------------------------------------------------------
600# USAGE: add <dataobj> ?<settings>?
601#
602# Clients use this to add a data object to the plot.  The optional
603# <settings> are used to configure the plot.  Allowed settings are
604# -color, -brightness, -width, -linestyle, and -raise.
605# ----------------------------------------------------------------------
606itcl::body Rappture::FlowvisViewer::add {dataobj {settings ""}} {
607    array set params {
608        -color auto
609        -width 1
610        -linestyle solid
611        -brightness 0
612        -raise 0
613        -description ""
614        -param ""
615    }
616    foreach {opt val} $settings {
617        if {![info exists params($opt)]} {
618            error "bad setting \"$opt\": should be [join [lsort [array names params]] {, }]"
619        }
620        set params($opt) $val
621    }
622    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
623        # can't handle -autocolors yet
624        set params(-color) black
625    }
626
627    set pos [lsearch -exact $dataobj $dlist_]
628    if {$pos < 0} {
629        lappend dlist_ $dataobj
630        set obj2ovride_($dataobj-color) $params(-color)
631        set obj2ovride_($dataobj-width) $params(-width)
632        set obj2ovride_($dataobj-raise) $params(-raise)
633        $_dispatcher event -idle !rebuild
634    }
635}
636
637# ----------------------------------------------------------------------
638# USAGE: get ?-objects?
639# USAGE: get ?-image 3dview|legend?
640#
641# Clients use this to query the list of objects being plotted, in
642# order from bottom to top of this result.  The optional "-image"
643# flag can also request the internal images being shown.
644# ----------------------------------------------------------------------
645itcl::body Rappture::FlowvisViewer::get {args} {
646    if {[llength $args] == 0} {
647        set args "-objects"
648    }
649
650    set op [lindex $args 0]
651    switch -- $op {
652      -objects {
653        # put the dataobj list in order according to -raise options
654        set dlist $dlist_
655        foreach obj $dlist {
656            if { [info exists obj2ovride_($obj-raise)] &&
657                 $obj2ovride_($obj-raise)} {
658                set i [lsearch -exact $dlist $obj]
659                if {$i >= 0} {
660                    set dlist [lreplace $dlist $i $i]
661                    lappend dlist $obj
662                }
663            }
664        }
665        return $dlist
666      }
667      -image {
668        if {[llength $args] != 2} {
669            error "wrong # args: should be \"get -image 3dview|legend\""
670        }
671        switch -- [lindex $args end] {
672            3dview {
673                return $_image(plot)
674            }
675            default {
676                error "bad image name \"[lindex $args end]\": should be 3dview or legend"
677            }
678        }
679      }
680      default {
681        error "bad option \"$op\": should be -objects or -image"
682      }
683    }
684}
685
686# ----------------------------------------------------------------------
687# USAGE: delete ?<dataobj1> <dataobj2> ...?
688#
689# Clients use this to delete a dataobj from the plot.  If no dataobjs
690# are specified, then all dataobjs are deleted.
691# ----------------------------------------------------------------------
692itcl::body Rappture::FlowvisViewer::delete {args} {
693    if {[llength $args] == 0} {
694        set args $dlist_
695    }
696
697    # delete all specified dataobjs
698    set changed 0
699    foreach dataobj $args {
700        set pos [lsearch -exact $dlist_ $dataobj]
701        if {$pos >= 0} {
702            set dlist_ [lreplace $dlist_ $pos $pos]
703            foreach key [array names obj2ovride_ $dataobj-*] {
704                unset obj2ovride_($key)
705            }
706            set changed 1
707        }
708    }
709
710    # if anything changed, then rebuild the plot
711    if {$changed} {
712        $_dispatcher event -idle !rebuild
713    }
714}
715
716# ----------------------------------------------------------------------
717# USAGE: scale ?<data1> <data2> ...?
718#
719# Sets the default limits for the overall plot according to the
720# limits of the data for all of the given <data> objects.  This
721# accounts for all objects--even those not showing on the screen.
722# Because of this, the limits are appropriate for all objects as
723# the user scans through data in the ResultSet viewer.
724# ----------------------------------------------------------------------
725itcl::body Rappture::FlowvisViewer::scale {args} {
726    foreach val {xmin xmax ymin ymax zmin zmax vmin vmax} {
727        set limits_($val) ""
728    }
729    foreach obj $args {
730        foreach axis {x y z v} {
731            foreach {min max} [$obj limits $axis] break
732            if {"" != $min && "" != $max} {
733                if {"" == $limits_(${axis}min)} {
734                    set limits_(${axis}min) $min
735                    set limits_(${axis}max) $max
736                } else {
737                    if {$min < $limits_(${axis}min)} {
738                        set limits_(${axis}min) $min
739                    }
740                    if {$max > $limits_(${axis}max)} {
741                        set limits_(${axis}max) $max
742                    }
743                }
744            }
745        }
746    }
747}
748
749# ----------------------------------------------------------------------
750# USAGE: download coming
751# USAGE: download controls <downloadCommand>
752# USAGE: download now
753#
754# Clients use this method to create a downloadable representation
755# of the plot.  Returns a list of the form {ext string}, where
756# "ext" is the file extension (indicating the type of data) and
757# "string" is the data itself.
758# ----------------------------------------------------------------------
759itcl::body Rappture::FlowvisViewer::download {option args} {
760    switch $option {
761        coming {
762            if {[catch {
763                blt::winop snap $itk_component(area) $_image(download)
764            }]} {
765                $_image(download) configure -width 1 -height 1
766                $_image(download) put #000000
767            }
768        }
769        controls {
770            # no controls for this download yet
771            return ""
772        }
773        now {
774            switch -- $_downloadPopup(format) {
775                jpg {
776                    #
777                    # Hack alert!  Need data in binary format,
778                    # so we'll save to a file and read it back.
779                    #
780                    set tmpfile /tmp/image[pid].jpg
781                    $_image(download) write $tmpfile -format jpeg
782                    set fid [open $tmpfile r]
783                    fconfigure $fid -encoding binary -translation binary
784                    set bytes [read $fid]
785                    close $fid
786                    file delete -force $tmpfile
787
788                    return [list .jpg $bytes]
789                }
790            }
791        }
792        default {
793            error "bad option \"$option\": should be coming, controls, now"
794        }
795    }
796}
797
798# ----------------------------------------------------------------------
799# USAGE: Connect ?<host:port>,<host:port>...?
800#
801# Clients use this method to establish a connection to a new
802# server, or to reestablish a connection to the previous server.
803# Any existing connection is automatically closed.
804# ----------------------------------------------------------------------
805itcl::body Rappture::FlowvisViewer::Connect {} {
806    Disconnect
807    set _hosts [GetServerList "nanovis"]
808    if { "" == $_hosts } {
809        return 0
810    }
811    set result [VisViewer::Connect $_hosts]
812    return $result
813}
814
815#
816# isconnected --
817#
818#       Indicates if we are currently connected to the visualization server.
819#
820itcl::body Rappture::FlowvisViewer::isconnected {} {
821    return [VisViewer::IsConnected]
822}
823
824# ----------------------------------------------------------------------
825# USAGE: Disconnect
826#
827# Clients use this method to disconnect from the current rendering
828# server.
829# ----------------------------------------------------------------------
830itcl::body Rappture::FlowvisViewer::Disconnect {} {
831    VisViewer::Disconnect
832
833    set outbuf_ ""
834    # disconnected -- no more data sitting on server
835    catch {unset obj2id_}
836    array unset id2obj_
837    set obj2id_(count) 0
838    set id2obj_(cound) 0
839    set sendobjs_ ""
840}
841
842#
843# _send
844#
845#       Send commands off to the rendering server.  If we're currently
846#       sending data objects to the server, buffer the commands to be
847#       sent later.
848#
849itcl::body Rappture::FlowvisViewer::_send {string} {
850    if {[llength $sendobjs_] > 0} {
851        append outbuf_ $string "\n"
852    } else {
853        if {[SendBytes $string]} {
854            foreach line [split $string \n] {
855                SendEcho >>line $line
856            }
857        }
858    }
859}
860
861# ----------------------------------------------------------------------
862# USAGE: _send_dataobjs
863#
864# Used internally to send a series of volume objects off to the
865# server.  Sends each object, a little at a time, with updates in
866# between so the interface doesn't lock up.
867# ----------------------------------------------------------------------
868itcl::body Rappture::FlowvisViewer::_send_dataobjs {} {
869    blt::busy hold $itk_component(hull); update idletasks
870
871    # Reset the overall limits
872    if { $sendobjs_ != "" } {
873        set limits_(vmin) ""
874        set limits_(vmax) ""
875    }
876    foreach dataobj $sendobjs_ {
877        foreach comp [$dataobj components] {
878            set data [$dataobj values $comp]
879
880            # tell the engine to expect some data
881            set nbytes [string length $data]
882            if { ![SendBytes "flow data follows $nbytes"] } {
883                return
884            }
885            if { ![SendBytes $data] } {
886                return
887            }
888            set id $obj2id_(count)
889            incr obj2id_(count)
890            set id2obj_($id) [list $dataobj $comp]
891            set obj2id_($dataobj-$comp) $id
892            set receiveIds_($id) 1
893        }
894    }
895    set sendobjs_ ""
896    blt::busy release $itk_component(hull)
897
898    # activate the proper volume
899    set first [lindex [get] 0]
900    if {"" != $first} {
901        set axis [$first hints updir]
902        if {"" != $axis} {
903            _send "up $axis"
904        }
905    }
906
907# FIXME: does vectorid command turn off other vectors?
908    foreach key [array names obj2id_ *-*] {
909        _send "flow vectorid $obj2id_($key)"
910    }
911
912    # sync the state of slicers
913    set vols [_currentVolumeIds -cutplanes]
914    foreach axis {x y z} {
915        _send "cutplane state [_state ${axis}slice] $axis $vols"
916        set pos [expr {0.01*[$itk_component(${axis}slicer) get]}]
917        _send "cutplane position $pos $axis $vols"
918    }
919
920    # if there are any commands in the buffer, send them now that we're done
921    SendBytes $outbuf_
922    set outbuf_ ""
923}
924
925# ----------------------------------------------------------------------
926# USAGE: ReceiveImage -bytes <size>
927#
928# Invoked automatically whenever the "image" command comes in from
929# the rendering server.  Indicates that binary image data with the
930# specified <size> will follow.
931# ----------------------------------------------------------------------
932itcl::body Rappture::FlowvisViewer::ReceiveImage {option size} {
933    if {[IsConnected]} {
934        set bytes [ReceiveBytes $size]
935        $_image(plot) configure -data $bytes
936        ReceiveEcho <<line "<read $size bytes for [image width $_image(plot)]x[image height $_image(plot)] image>"
937    }
938}
939
940# ----------------------------------------------------------------------
941# USAGE: ReceiveFile -bytes <size>
942#
943# Invoked automatically whenever the "file" command comes in from
944# the rendering server.  Indicates that binary file data with the
945# specified <size> will follow.
946# ----------------------------------------------------------------------
947itcl::body Rappture::FlowvisViewer::ReceiveFile {option size} {
948    if {[IsConnected]} {
949        set bytes [ReceiveBytes $size]
950        ReceiveEcho <<line "<read $size bytes for file>"
951
952        # raise the record button back up.
953        $itk_component(record) configure -relief raised -state normal
954
955        # FIXME: manually download file???
956        set mesg [Rappture::filexfer::download $bytes "flowmovie.mpeg"]
957    }
958}
959
960# ----------------------------------------------------------------------
961# USAGE: _rebuild
962#
963# Called automatically whenever something changes that affects the
964# data in the widget.  Clears any existing data and rebuilds the
965# widget to display new data.
966# ----------------------------------------------------------------------
967itcl::body Rappture::FlowvisViewer::_rebuild {} {
968    # in the midst of sending data? then bail out
969    if {[llength $sendobjs_] > 0} {
970        return
971    }
972    # Find any new data that needs to be sent to the server.  Queue this up on
973    # the sendobjs_ list, and send it out a little at a time.  Do this first,
974    # before we rebuild the rest.
975    foreach dataobj [get] {
976        set comp [lindex [$dataobj components] 0]
977        if {![info exists obj2id_($dataobj-$comp)]} {
978            set i [lsearch -exact $sendobjs_ $dataobj]
979            if {$i < 0} {
980                lappend sendobjs_ $dataobj
981            }
982        }
983    }
984    if {[llength $sendobjs_] > 0} {
985        # Send off new data objects
986        $_dispatcher event -idle !send_dataobjs
987    } else {
988        # Nothing to send -- activate the proper volume
989        set first [lindex [get] 0]
990        if {"" != $first} {
991            set axis [$first hints updir]
992            if {"" != $axis} {
993                _send "up $axis"
994            }
995        }
996        foreach key [array names obj2id_ *-*] {
997            set state [string match $first-* $key]
998            _send "flow vectorid $obj2id_($key)"
999        }
1000    }
1001
1002    # Reset the screen size.
1003    set w [winfo width $itk_component(3dview)]
1004    set h [winfo height $itk_component(3dview)]
1005    _send "screen $w $h"
1006
1007    # Reset the camera and other view parameters
1008    set xyz [Euler2XYZ $view_(theta) $view_(phi) $view_(psi)]
1009    _send "camera angle $xyz"
1010    _send "camera zoom $view_(zoom)"
1011
1012    # _fixSettings wireframe
1013    _fixSettings light
1014    _fixSettings transp
1015    _fixSettings isosurface
1016    _fixSettings grid
1017    _fixSettings axes
1018    _fixSettings outline
1019    # _fixSettings contourlines
1020}
1021
1022# ----------------------------------------------------------------------
1023# USAGE: _currentVolumeIds ?-cutplanes?
1024#
1025# Returns a list of volume server IDs for the current volume being
1026# displayed.  This is normally a single ID, but it might be a list
1027# of IDs if the current data object has multiple components.
1028# ----------------------------------------------------------------------
1029itcl::body Rappture::FlowvisViewer::_currentVolumeIds {{what -all}} {
1030    set rlist ""
1031
1032    set first [lindex [get] 0]
1033    foreach key [array names _obj2id *-*] {
1034        if {[string match $first-* $key]} {
1035            array set style {
1036                -cutplanes 1
1037            }
1038            foreach {dataobj comp} [split $key -] break
1039            array set style [lindex [$dataobj components -style $comp] 0]
1040
1041            if {$what != "-cutplanes" || $style(-cutplanes)} {
1042                lappend rlist $_obj2id($key)
1043            }
1044        }
1045    }
1046    return $rlist
1047}
1048
1049# ----------------------------------------------------------------------
1050# USAGE: _zoom in
1051# USAGE: _zoom out
1052# USAGE: _zoom reset
1053#
1054# Called automatically when the user clicks on one of the zoom
1055# controls for this widget.  Changes the zoom for the current view.
1056# ----------------------------------------------------------------------
1057itcl::body Rappture::FlowvisViewer::_zoom {option} {
1058    switch -- $option {
1059        "in" {
1060            set view_(zoom) [expr {$view_(zoom)*1.25}]
1061        }
1062        "out" {
1063            set view_(zoom) [expr {$view_(zoom)*0.8}]
1064        }
1065        "reset" {
1066            array set view_ {
1067                theta   45
1068                phi     45
1069                psi     0
1070                zoom    1.0
1071                dx      0
1072                dy      0
1073            }
1074            set xyz [Euler2XYZ $view_(theta) $view_(phi) $view_(psi)]
1075            _send "camera angle $xyz"
1076            _send "camera pan $view_(dx) $view_(dy)"
1077        }
1078    }
1079    _send "camera zoom $view_(zoom)"
1080}
1081
1082# ----------------------------------------------------------------------
1083# USAGE: $this _pan click x y
1084#        $this _pan drag x y
1085#        $this _pan release x y
1086#
1087# Called automatically when the user clicks on one of the zoom
1088# controls for this widget.  Changes the zoom for the current view.
1089# ----------------------------------------------------------------------
1090itcl::body Rappture::FlowvisViewer::_pan {option x y} {
1091    # Experimental stuff
1092    set w [winfo width $itk_component(3dview)]
1093    set h [winfo height $itk_component(3dview)]
1094    if { $option == "set" } {
1095        set x [expr $x / double($w)]
1096        set y [expr $y / double($h)]
1097        set view_(dx) [expr $view_(dx) + $x]
1098        set view_(dy) [expr $view_(dy) + $y]
1099        _send "camera pan $view_(dx) $view_(dy)"
1100        return
1101    }
1102    if { $option == "click" } {
1103        set click_(x) $x
1104        set click_(y) $y
1105        $itk_component(3dview) configure -cursor hand1
1106    }
1107    if { $option == "drag" || $option == "release" } {
1108        set dx [expr ($click_(x) - $x)/double($w)]
1109        set dy [expr ($click_(y) - $y)/double($h)]
1110        set click_(x) $x
1111        set click_(y) $y
1112        set view_(dx) [expr $view_(dx) - $dx]
1113        set view_(dy) [expr $view_(dy) - $dy]
1114        _send "camera pan $view_(dx) $view_(dy)"
1115    }
1116    if { $option == "release" } {
1117        $itk_component(3dview) configure -cursor ""
1118    }
1119}
1120
1121# ----------------------------------------------------------------------
1122# USAGE: _rotate click <x> <y>
1123# USAGE: _rotate drag <x> <y>
1124# USAGE: _rotate release <x> <y>
1125#
1126# Called automatically when the user clicks/drags/releases in the
1127# plot area.  Moves the plot according to the user's actions.
1128# ----------------------------------------------------------------------
1129itcl::body Rappture::FlowvisViewer::_rotate {option x y} {
1130    switch -- $option {
1131        click {
1132            $itk_component(3dview) configure -cursor fleur
1133            array set click_ [subst {
1134                x       $x
1135                y       $y
1136                theta   $view_(theta)
1137                phi     $view_(phi)
1138            }]
1139        }
1140        drag {
1141            if {[array size click_] == 0} {
1142                _rotate click $x $y
1143            } else {
1144                set w [winfo width $itk_component(3dview)]
1145                set h [winfo height $itk_component(3dview)]
1146                if {$w <= 0 || $h <= 0} {
1147                    return
1148                }
1149
1150                if {[catch {
1151                    # this fails sometimes for no apparent reason
1152                    set dx [expr {double($x-$click_(x))/$w}]
1153                    set dy [expr {double($y-$click_(y))/$h}]
1154                }] != 0 } {
1155                    return
1156                }
1157
1158                #
1159                # Rotate the camera in 3D
1160                #
1161                if {$view_(psi) > 90 || $view_(psi) < -90} {
1162                    # when psi is flipped around, theta moves backwards
1163                    set dy [expr {-$dy}]
1164                }
1165                set theta [expr {$view_(theta) - $dy*180}]
1166                while {$theta < 0} { set theta [expr {$theta+180}] }
1167                while {$theta > 180} { set theta [expr {$theta-180}] }
1168
1169                if {abs($theta) >= 30 && abs($theta) <= 160} {
1170                    set phi [expr {$view_(phi) - $dx*360}]
1171                    while {$phi < 0} { set phi [expr {$phi+360}] }
1172                    while {$phi > 360} { set phi [expr {$phi-360}] }
1173                    set psi $view_(psi)
1174                } else {
1175                    set phi $view_(phi)
1176                    set psi [expr {$view_(psi) - $dx*360}]
1177                    while {$psi < -180} { set psi [expr {$psi+360}] }
1178                    while {$psi > 180} { set psi [expr {$psi-360}] }
1179                }
1180
1181                set view_(theta)        $theta
1182                set view_(phi)          $phi
1183                set view_(psi)          $psi
1184                set xyz [Euler2XYZ $view_(theta) $view_(phi) $view_(psi)]
1185                _send "camera angle $xyz"
1186                set click_(x) $x
1187                set click_(y) $y
1188            }
1189        }
1190        release {
1191            _rotate drag $x $y
1192            $itk_component(3dview) configure -cursor ""
1193            catch {unset click_}
1194        }
1195        default {
1196            error "bad option \"$option\": should be click, drag, release"
1197        }
1198    }
1199}
1200
1201# ----------------------------------------------------------------------
1202# USAGE: _slice axis x|y|z ?on|off|toggle?
1203# USAGE: _slice move x|y|z <newval>
1204# USAGE: _slice volume ?on|off|toggle?
1205#
1206# Called automatically when the user drags the slider to move the
1207# cut plane that slices 3D data.  Gets the current value from the
1208# slider and moves the cut plane to the appropriate point in the
1209# data set.
1210# ----------------------------------------------------------------------
1211itcl::body Rappture::FlowvisViewer::_slice {option args} {
1212    switch -- $option {
1213        axis {
1214            if {[llength $args] < 1 || [llength $args] > 2} {
1215                error "wrong # args: should be \"_slice axis x|y|z ?on|off|toggle?\""
1216            }
1217            set axis [lindex $args 0]
1218            set op [lindex $args 1]
1219            if {$op == ""} { set op "on" }
1220
1221            set current [_state ${axis}slice]
1222            if {$op == "toggle"} {
1223                if {$current == "on"} { set op "off" } else { set op "on" }
1224            }
1225            if {$op} {
1226                $itk_component(${axis}slicer) configure -state normal
1227                _send "cutplane state 1 $axis [_currentVolumeIds -cutplanes]"
1228                $itk_component(${axis}slice) configure -relief sunken
1229            } else {
1230                $itk_component(${axis}slicer) configure -state disabled
1231                _send "cutplane state 0 $axis [_currentVolumeIds -cutplanes]"
1232                $itk_component(${axis}slice) configure -relief raised
1233            }
1234        }
1235        move {
1236            if {[llength $args] != 2} {
1237                error "wrong # args: should be \"_slice move x|y|z newval\""
1238            }
1239            set axis [lindex $args 0]
1240            set newval [lindex $args 1]
1241
1242            set newpos [expr {0.01*$newval}]
1243#            set newval [expr {0.01*($newval-50)
1244#                *($limits_(${axis}max)-$limits_(${axis}min))
1245#                  + 0.5*($limits_(${axis}max)+$limits_(${axis}min))}]
1246
1247            # show the current value in the readout
1248            #puts "readout: $axis = $newval"
1249
1250            set ids [_currentVolumeIds -cutplanes]
1251            _send "cutplane position $newpos $axis $ids"
1252        }
1253        volume {
1254            if {[llength $args] > 1} {
1255                error "wrong # args: should be \"_slice volume ?on|off|toggle?\""
1256            }
1257            set op [lindex $args 0]
1258            if {$op == ""} { set op "on" }
1259
1260            set current [_state volume]
1261            if {$op == "toggle"} {
1262                if {$current == "on"} { set op "off" } else { set op "on" }
1263            }
1264
1265            if {$op} {
1266                _send "volume data state on [_currentVolumeIds]"
1267                $itk_component(volume) configure -relief sunken
1268            } else {
1269                _send "volume data state off [_currentVolumeIds]"
1270                $itk_component(volume) configure -relief raised
1271            }
1272        }
1273        default {
1274            error "bad option \"$option\": should be axis, move, or volume"
1275        }
1276    }
1277}
1278
1279# ----------------------------------------------------------------------
1280# USAGE: _slicertip <axis>
1281#
1282# Used internally to generate a tooltip for the x/y/z slicer controls.
1283# Returns a message that includes the current slicer value.
1284# ----------------------------------------------------------------------
1285itcl::body Rappture::FlowvisViewer::_slicertip {axis} {
1286    set val [$itk_component(${axis}slicer) get]
1287#    set val [expr {0.01*($val-50)
1288#        *($limits_(${axis}max)-$limits_(${axis}min))
1289#          + 0.5*($limits_(${axis}max)+$limits_(${axis}min))}]
1290    return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
1291}
1292
1293# ----------------------------------------------------------------------
1294# USAGE: _flow movie record|stop|play ?on|off|toggle?
1295#
1296# Called when the user clicks on the record, stop or play buttons
1297# for flow visualization.
1298# ----------------------------------------------------------------------
1299itcl::body Rappture::FlowvisViewer::_flow {option args} {
1300    switch -- $option {
1301        movie {
1302            if {[llength $args] < 1 || [llength $args] > 2} {
1303                error "wrong # args: should be \"_flow movie record|stop|play ?on|off|toggle?\""
1304            }
1305            set action [lindex $args 0]
1306            set op [lindex $args 1]
1307            if {$op == ""} { set op "on" }
1308
1309            set current [_state $action]
1310            if {$op == "toggle"} {
1311                if {$current == "on"} {
1312                    set op "off"
1313                } else {
1314                    set op "on"
1315                }
1316            }
1317            set cmds ""
1318            switch -- $action {
1319                record {
1320                    $itk_component(record) configure -relief sunken -state disable
1321                    $itk_component(stop) configure -relief raised -state normal
1322                    $itk_component(play) configure -relief raised -state normal
1323                    set inner [$itk_component(controls).panel component inner]
1324                    set frames [$inner.scales.framecnt value]
1325                    set cmds "flow capture $frames"
1326                    _send $cmds
1327                }
1328                stop {
1329                    $itk_component(record) configure -relief raised -state normal
1330                    $itk_component(stop) configure -relief sunken -state disable
1331                    $itk_component(play) configure -relief raised -state normal
1332                    _pause
1333                    set cmds "flow reset"
1334                    _send $cmds
1335
1336                }
1337                play {
1338                    $itk_component(record) configure -relief raised -state normal
1339                    $itk_component(stop) configure -relief raised -state normal
1340                    $itk_component(play) configure \
1341                        -image [Rappture::icon playback-pause] \
1342                        -relief sunken -state normal
1343                    bind $itk_component(play) <ButtonPress> \
1344                        [itcl::code $this _pause]
1345                    _play
1346                }
1347                default {
1348                    error "bad option \"$option\": should be one of record|stop|play"
1349                }
1350
1351            }
1352        }
1353        default {
1354            error "bad option \"$option\": should be movie"
1355        }
1356    }
1357}
1358
1359# ----------------------------------------------------------------------
1360# USAGE: _play
1361#
1362# ----------------------------------------------------------------------
1363itcl::body Rappture::FlowvisViewer::_play {} {
1364    set cmds {flow play}
1365    _send $cmds
1366    set delay [expr {int(ceil(pow($_play(speed)/10.0+2,2.0)*15))}]
1367    set _afterId [after $delay [itcl::code $this _play]]
1368}
1369
1370# ----------------------------------------------------------------------
1371# USAGE: _pause
1372#
1373# Invoked when the user hits the "pause" button to stop playing the
1374# current sequence of frames as a movie.
1375# ----------------------------------------------------------------------
1376itcl::body Rappture::FlowvisViewer::_pause {} {
1377    if {"" != $_afterId} {
1378        catch {after cancel $_afterId}
1379        set _afterId ""
1380    }
1381
1382    # toggle the button to "play" mode
1383    $itk_component(play) configure \
1384        -image [Rappture::icon playback-start] \
1385        -relief raised -state normal
1386    bind $itk_component(play) <ButtonPress> \
1387        [itcl::code $this _flow movie play toggle]
1388
1389}
1390
1391# ----------------------------------------------------------------------
1392# USAGE: _state <component>
1393#
1394# Used internally to determine the state of a toggle button.
1395# The <component> is the itk component name of the button.
1396# Returns on/off for the state of the button.
1397# ----------------------------------------------------------------------
1398itcl::body Rappture::FlowvisViewer::_state {comp} {
1399    if {[$itk_component($comp) cget -relief] == "sunken"} {
1400        return "on"
1401    }
1402    return "off"
1403}
1404
1405# ----------------------------------------------------------------------
1406# USAGE: _fixSettings <what> ?<value>?
1407#
1408# Used internally to update rendering settings whenever parameters
1409# change in the popup settings panel.  Sends the new settings off
1410# to the back end.
1411# ----------------------------------------------------------------------
1412itcl::body Rappture::FlowvisViewer::_fixSettings { what {value ""} } {
1413    set inner [$itk_component(controls).panel component inner]
1414    switch -- $what {
1415        light {
1416            if {[isconnected]} {
1417                set val [$inner.scales.light get]
1418                set sval [expr {0.1*$val}]
1419                _send "volume shading diffuse $sval"
1420
1421                set sval [expr {sqrt($val+1.0)}]
1422                _send "volume shading specular $sval"
1423            }
1424        }
1425        transp {
1426            if {[isconnected]} {
1427                set val [$inner.scales.transp get]
1428                set sval [expr {0.2*$val+1}]
1429                _send "volume shading opacity $sval"
1430            }
1431        }
1432        opacity {
1433            if {[isconnected] && $activeTf_ != "" } {
1434                set val [$inner.scales.opacity get]
1435                set sval [expr { 0.01 * double($val) }]
1436                set tf $activeTf_
1437                set settings_($this-$tf-opacity) $sval
1438                UpdateTransferFunctions
1439            }
1440        }
1441
1442        thickness {
1443            if {[isconnected] && $activeTf_ != "" } {
1444                set val [$inner.scales.thickness get]
1445                # Scale values between 0.00001 and 0.01000
1446                set sval [expr {0.0001*double($val)}]
1447                set tf $activeTf_
1448                set settings_($this-$tf-thickness) $sval
1449                UpdateTransferFunctions
1450            }
1451        }
1452        "outline" {
1453            if {[isconnected]} {
1454                _send "volume outline state $settings_($this-outline)"
1455            }
1456        }
1457        "isosurface" {
1458            if {[isconnected]} {
1459                _send "volume shading isosurface $settings_($this-isosurface)"
1460            }
1461        }
1462        "grid" {
1463            if { [IsConnected] } {
1464                _send "grid visible $settings_($this-grid)"
1465            }
1466        }
1467        "particlevis" {
1468            if { [IsConnected] } {
1469                _send "flow particle visible $settings_($this-particlevis)"
1470            }
1471        }
1472        "lic" {
1473            if { [IsConnected] } {
1474                _send "flow lic $settings_($this-lic)"
1475            }
1476        }
1477        "axes" {
1478            if { [IsConnected] } {
1479                _send "axis visible $settings_($this-axes)"
1480            }
1481        }
1482        default {
1483            error "don't know how to fix $what: should be grid, axes, contourlines, or legend"
1484        }
1485    }
1486}
1487
1488# ----------------------------------------------------------------------
1489# USAGE: _getTransfuncData <dataobj> <comp>
1490#
1491# Used internally to compute the colormap and alpha map used to define
1492# a transfer function for the specified component in a data object.
1493# Returns: name {v r g b ...} {v w ...}
1494# ----------------------------------------------------------------------
1495itcl::body Rappture::FlowvisViewer::_getTransfuncData {dataobj comp} {
1496    array set style {
1497        -color rainbow
1498        -levels 6
1499        -opacity 0.5
1500    }
1501    array set style [lindex [$dataobj components -style $comp] 0]
1502    set sname "$style(-color):$style(-levels):$style(-opacity)"
1503
1504    if {$style(-color) == "rainbow"} {
1505        set style(-color) "white:yellow:green:cyan:blue:magenta"
1506    }
1507    set clist [split $style(-color) :]
1508    set color white
1509    set cmap "0.0 [Color2RGB $color] "
1510    set range [expr $limits_(vmax) - $limits_(vmin)]
1511    for {set i 0} {$i < [llength $clist]} {incr i} {
1512        set xval [expr {double($i+1)/([llength $clist]+1)}]
1513        set color [lindex $clist $i]
1514        append cmap "$xval [Color2RGB $color] "
1515    }
1516    append cmap "1.0 [Color2RGB $color] "
1517
1518    set opacity $style(-opacity)
1519    set levels $style(-levels)
1520    set wmap {}
1521    if {[string is int $levels]} {
1522        lappend wmap 0.0 0.0
1523        set delta [expr {0.125/($levels+1)}]
1524        for {set i 1} {$i <= $levels} {incr i} {
1525            # add spikes in the middle
1526            set xval [expr {double($i)/($levels+1)}]
1527            lappend wmap [expr {$xval-$delta-0.01}] 0.0
1528            lappend wmap [expr {$xval-$delta}] $opacity
1529            lappend wmap [expr {$xval+$delta}] $opacity
1530            lappend wmap [expr {$xval+$delta+0.01}] 0.0
1531        }
1532        lappend wmap 1.0 0.0
1533    } else {
1534        lappend wmap 0.0 0.0
1535        set delta 0.05
1536        foreach xval [split $levels ,] {
1537            lappend wmap [expr {$xval-$delta}] 0.0
1538            lappend $xval $opacity
1539            lappend [expr {$xval+$delta}] 0.0
1540        }
1541        lappend wmap 1.0 0.0
1542    }
1543    return [list $sname $cmap $wmap]
1544}
1545
1546# ----------------------------------------------------------------------
1547# CONFIGURATION OPTION: -plotbackground
1548# ----------------------------------------------------------------------
1549itcl::configbody Rappture::FlowvisViewer::plotbackground {
1550    foreach {r g b} [Color2RGB $itk_option(-plotbackground)] break
1551    #fix this!
1552    #_send "color background $r $g $b"
1553}
1554
1555# ----------------------------------------------------------------------
1556# CONFIGURATION OPTION: -plotforeground
1557# ----------------------------------------------------------------------
1558itcl::configbody Rappture::FlowvisViewer::plotforeground {
1559    foreach {r g b} [Color2RGB $itk_option(-plotforeground)] break
1560    #fix this!
1561    #_send "color background $r $g $b"
1562}
1563
1564# ----------------------------------------------------------------------
1565# CONFIGURATION OPTION: -plotoutline
1566# ----------------------------------------------------------------------
1567itcl::configbody Rappture::FlowvisViewer::plotoutline {
1568    if {[IsConnected]} {
1569        _send "grid linecolor [Color2RGB $itk_option(-plotoutline)]"
1570    }
1571}
Note: See TracBrowser for help on using the repository browser.