source: trunk/gui/scripts/vtkstreamlinesviewer.tcl @ 2504

Last change on this file since 2504 was 2504, checked in by gah, 13 years ago

create vtkstreamlinesviewer client

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