source: trunk/gui/scripts/vtksurfaceviewer.tcl @ 4682

Last change on this file since 4682 was 4682, checked in by ldelgass, 6 years ago

Axis fixes for vtksurface viewer

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