source: trunk/gui/scripts/vtkviewer.tcl @ 2616

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