source: branches/blt4/gui/scripts/vtkviewer.tcl @ 2742

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

sync with trunk

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