source: branches/Rappture 1.2/gui/scripts/vtkheightmapviewer.tcl @ 3302

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

fixes for clientdata output, fix streamlines to use vtkdata

File size: 87.8 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: vtkheightmapviewer - Vtk heightmap viewer
3#
4#  It connects to the Vtk server running on a rendering farm,
5#  transmits data, and displays the results.
6# ======================================================================
7#  AUTHOR:  Michael McLennan, Purdue University
8#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
9#
10#  See the file "license.terms" for information on usage and
11#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12# ======================================================================
13package require Itk
14package require BLT
15#package require Img
16
17option add *VtkHeightmapViewer.width 4i widgetDefault
18option add *VtkHeightmapViewer*cursor crosshair widgetDefault
19option add *VtkHeightmapViewer.height 4i widgetDefault
20option add *VtkHeightmapViewer.foreground black widgetDefault
21option add *VtkHeightmapViewer.controlBackground gray widgetDefault
22option add *VtkHeightmapViewer.controlDarkBackground #999999 widgetDefault
23option add *VtkHeightmapViewer.plotBackground black widgetDefault
24option add *VtkHeightmapViewer.plotForeground white widgetDefault
25option add *VtkHeightmapViewer.font \
26    -*-helvetica-medium-r-normal-*-12-* widgetDefault
27
28# must use this name -- plugs into Rappture::resources::load
29proc VtkHeightmapViewer_init_resources {} {
30    Rappture::resources::register \
31        vtkvis_server Rappture::VtkHeightmapViewer::SetServerList
32}
33
34itcl::class Rappture::VtkHeightmapViewer {
35    inherit Rappture::VisViewer
36
37    itk_option define -plotforeground plotForeground Foreground ""
38    itk_option define -plotbackground plotBackground Background ""
39    itk_option define -mode mode Mode "contour"
40
41    constructor { hostlist args } {
42        Rappture::VisViewer::constructor $hostlist
43    } {
44        # defined below
45    }
46    destructor {
47        # defined below
48    }
49    public proc SetServerList { namelist } {
50        Rappture::VisViewer::SetServerList "vtkvis" $namelist
51    }
52    public method add {dataobj {settings ""}}
53    public method camera {option args}
54    public method delete {args}
55    public method disconnect {}
56    public method download {option args}
57    public method get {args}
58    public method isconnected {}
59    public method limits { colormap }
60    public method sendto { string }
61    public method parameters {title args} {
62        # do nothing
63    }
64    public method scale {args}
65
66    protected method Connect {}
67    protected method CurrentDatasets {args}
68    protected method Disconnect {}
69    protected method DoResize {}
70    protected method DoContour {}
71    protected method DoRotate {}
72    protected method AdjustSetting {what {value ""}}
73    protected method InitSettings { 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 min max size }
80    protected method Rotate {option x y}
81    protected method SendCmd {string}
82    protected method SendCmdNoWait {string}
83    protected method Zoom {option}
84
85    # The following methods are only used by this class.
86    private method BuildAxisTab {}
87    private method BuildCameraTab {}
88    private method BuildColormap { name colors }
89    private method ResetColormap { color }
90    private method BuildContourTab {}
91    private method BuildDownloadPopup { widget command }
92    private method ColorsToColormap { color }
93    private method Combo { option }
94    private method ConvertToVtkData { dataobj comp }
95    private method DrawLegend { title }
96    private method EnterLegend { x y }
97    private method EventuallyContour { numContours }
98    private method EventuallyRequestLegend {}
99    private method EventuallyResize { w h }
100    private method EventuallyRotate { q }
101    private method GetImage { args }
102    private method GetVtkData { args }
103    private method IsValidObject { dataobj }
104    private method LeaveLegend {}
105    private method MotionLegend { x y }
106    private method PanCamera {}
107    private method RequestLegend {}
108    private method SetCurrentColormap { stylelist }
109    private method SetLegendTip { x y }
110    private method SetObjectStyle { dataobj comp }
111    private method GetHeightmapScale {}
112    private method EnterIsoline { x y value }
113    private method LeaveIsoline {}
114    private method SetIsolineTip { x y value }
115    private method ResetAxes {}
116
117    private variable _arcball ""
118    private variable _outbuf       ;    # buffer for outgoing commands
119
120    private variable _dlist ""     ;    # list of data objects
121    private variable _obj2datasets
122    private variable _obj2ovride   ;    # maps dataobj => style override
123    private variable _comp2scale;       # maps dataset to the heightmap scale.
124    private variable _datasets     ;    # contains all the dataobj-component
125                                   ;    # datasets in the server
126    private variable _colormaps    ;    # contains all the colormaps
127                                   ;    # in the server.
128
129    # The name of the current colormap used.  The colormap is global to all
130    # heightmaps displayed.
131    private variable _currentColormap "" ;   
132
133    private variable _click        ;    # info used for rotate operations
134    private variable _limits       ;    # autoscale min/max for all axes
135    private variable _view         ;    # view params for 3D view
136    private variable _settings
137    private variable _initialStyle "";  # First found style in dataobjects.
138    private variable _reset 1;          # indicates if camera needs to be reset
139                                        # to starting position.
140
141    private variable _first ""     ;    # This is the topmost dataset.
142    private variable _start 0
143    private variable _buffering 0
144    private variable _title ""
145
146    common _downloadPopup;              # download options from popup
147    private common _hardcopy
148    private variable _width 0
149    private variable _height 0
150    private variable _resizePending 0
151    private variable _contourPending 0
152    private variable _rotatePending 0
153    private variable _legendPending 0
154    private variable _fieldNames {}
155    private variable _fields
156    private variable _currentFieldName "Default"
157    private variable _numContours 0
158    private variable _colorMode "vmag";#  Mode of colormap (vmag or scalar)
159}
160
161itk::usual VtkHeightmapViewer {
162    keep -background -foreground -cursor -font
163    keep -plotbackground -plotforeground -mode
164}
165
166# ----------------------------------------------------------------------
167# CONSTRUCTOR
168# ----------------------------------------------------------------------
169itcl::body Rappture::VtkHeightmapViewer::constructor {hostlist args} {
170    set _serverType "vtkvis"
171
172    # Rebuild event
173    $_dispatcher register !rebuild
174    $_dispatcher dispatch $this !rebuild "[itcl::code $this Rebuild]; list"
175
176    # Resize event
177    $_dispatcher register !resize
178    $_dispatcher dispatch $this !resize "[itcl::code $this DoResize]; list"
179
180    # Recontour event
181    $_dispatcher register !contour
182    $_dispatcher dispatch $this !contour "[itcl::code $this DoContour]; list"
183
184    # Rotate event
185    $_dispatcher register !rotate
186    $_dispatcher dispatch $this !rotate "[itcl::code $this DoRotate]; list"
187
188    # Legend event
189    $_dispatcher register !legend
190    $_dispatcher dispatch $this !legend "[itcl::code $this RequestLegend]; list"
191
192    #
193    # Populate parser with commands handle incoming requests
194    #
195    $_parser alias image [itcl::code $this ReceiveImage]
196    $_parser alias dataset [itcl::code $this ReceiveDataset]
197    $_parser alias legend [itcl::code $this ReceiveLegend]
198
199    # Initialize the view to some default parameters.
200    array set _view {
201        qw      0.36
202        qx      0.25
203        qy      0.50
204        qz      0.70
205        zoom    1.0
206        xpan    0
207        ypan    0
208        ortho   1
209    }
210    set _arcball [blt::arcball create 100 100]
211    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
212    $_arcball quaternion $q
213
214    array set _settings [subst {
215        axisLabels              1
216        axis-visible            1
217        axis-xgrid              0
218        axis-xposition          0
219        axis-ygrid              0
220        axis-yposition          0
221        axis-zgrid              0
222        axis-zposition          0
223        axis-minticks           1
224        axis-flymode            "static"
225        edges                   0
226        field                   "Default"
227        isolines                10
228        lighting                0
229        outline                 0
230        contour-opacity         100
231        colormap-visible         1
232        isolines-visible         1
233        wireframe               0
234        isHeightmap             0
235        heightmap-scale         50
236        legendVisible           1
237        stretchToFit            0
238        x-scale                 1.0
239        y-scale                 1.0
240        z-scale                 1.0
241    }]
242
243    itk_component add view {
244        canvas $itk_component(plotarea).view \
245            -highlightthickness 0 -borderwidth 0
246    } {
247        usual
248        ignore -highlightthickness -borderwidth -background
249    }
250
251    itk_component add fieldmenu {
252        menu $itk_component(plotarea).menu \
253            -relief flat \
254            -tearoff no
255    } {
256        usual
257        ignore -background -foreground -relief -tearoff
258    }
259    set c $itk_component(view)
260    bind $c <Configure> [itcl::code $this EventuallyResize %w %h]
261    bind $c <4> [itcl::code $this Zoom in 0.25]
262    bind $c <5> [itcl::code $this Zoom out 0.25]
263    bind $c <KeyPress-Left>  [list %W xview scroll 10 units]
264    bind $c <KeyPress-Right> [list %W xview scroll -10 units]
265    bind $c <KeyPress-Up>    [list %W yview scroll 10 units]
266    bind $c <KeyPress-Down>  [list %W yview scroll -10 units]
267    bind $c <Enter> "focus %W"
268    bind $c <Control-F1> [itcl::code $this ToggleConsole]
269
270    # Fix the scrollregion in case we go off screen
271    $c configure -scrollregion [$c bbox all]
272
273    set _map(id) [$c create image 0 0 -anchor nw -image $_image(plot)]
274    set _map(cwidth) -1
275    set _map(cheight) -1
276    set _map(zoom) 1.0
277    set _map(original) ""
278
279    set f [$itk_component(main) component controls]
280    itk_component add reset {
281        button $f.reset -borderwidth 1 -padx 1 -pady 1 \
282            -highlightthickness 0 \
283            -image [Rappture::icon reset-view] \
284            -command [itcl::code $this Zoom reset]
285    } {
286        usual
287        ignore -highlightthickness
288    }
289    pack $itk_component(reset) -side top -padx 2 -pady 2
290    Rappture::Tooltip::for $itk_component(reset) "Reset the view to the default zoom level"
291
292    itk_component add zoomin {
293        button $f.zin -borderwidth 1 -padx 1 -pady 1 \
294            -highlightthickness 0 \
295            -image [Rappture::icon zoom-in] \
296            -command [itcl::code $this Zoom in]
297    } {
298        usual
299        ignore -highlightthickness
300    }
301    pack $itk_component(zoomin) -side top -padx 2 -pady 2
302    Rappture::Tooltip::for $itk_component(zoomin) "Zoom in"
303
304    itk_component add zoomout {
305        button $f.zout -borderwidth 1 -padx 1 -pady 1 \
306            -highlightthickness 0 \
307            -image [Rappture::icon zoom-out] \
308            -command [itcl::code $this Zoom out]
309    } {
310        usual
311        ignore -highlightthickness
312    }
313    pack $itk_component(zoomout) -side top -padx 2 -pady 2
314    Rappture::Tooltip::for $itk_component(zoomout) "Zoom out"
315
316    itk_component add mode {
317        Rappture::PushButton $f.mode \
318            -onimage [Rappture::icon surface] \
319            -offimage [Rappture::icon surface] \
320            -variable [itcl::scope _settings(isHeightmap)] \
321            -command [itcl::code $this AdjustSetting isHeightmap] \
322    }
323    Rappture::Tooltip::for $itk_component(mode) \
324        "Toggle the surface/contour on/off"
325    pack $itk_component(mode) -padx 2 -pady 2
326
327    if { [catch {
328        BuildContourTab
329        BuildAxisTab
330        BuildCameraTab
331    } errs] != 0 } {
332        global errorInfo
333        puts stderr "errs=$errs errorInfo=$errorInfo"
334    }
335    set _image(legend) [image create photo]
336
337    # Hack around the Tk panewindow.  The problem is that the requested
338    # size of the 3d view isn't set until an image is retrieved from
339    # the server.  So the panewindow uses the tiny size.
340    set w 10000
341    pack forget $itk_component(view)
342    blt::table $itk_component(plotarea) \
343        0,0 $itk_component(view) -fill both -reqwidth $w
344    blt::table configure $itk_component(plotarea) c1 -resize none
345
346    # Bindings for panning via mouse
347    bind $itk_component(view) <ButtonPress-2> \
348        [itcl::code $this Pan click %x %y]
349    bind $itk_component(view) <B2-Motion> \
350        [itcl::code $this Pan drag %x %y]
351    bind $itk_component(view) <ButtonRelease-2> \
352        [itcl::code $this Pan release %x %y]
353
354    bind $itk_component(view) <ButtonRelease-3> \
355        [itcl::code $this Pick %x %y]
356
357    # Bindings for panning via keyboard
358    bind $itk_component(view) <KeyPress-Left> \
359        [itcl::code $this Pan set -10 0]
360    bind $itk_component(view) <KeyPress-Right> \
361        [itcl::code $this Pan set 10 0]
362    bind $itk_component(view) <KeyPress-Up> \
363        [itcl::code $this Pan set 0 -10]
364    bind $itk_component(view) <KeyPress-Down> \
365        [itcl::code $this Pan set 0 10]
366    bind $itk_component(view) <Shift-KeyPress-Left> \
367        [itcl::code $this Pan set -2 0]
368    bind $itk_component(view) <Shift-KeyPress-Right> \
369        [itcl::code $this Pan set 2 0]
370    bind $itk_component(view) <Shift-KeyPress-Up> \
371        [itcl::code $this Pan set 0 -2]
372    bind $itk_component(view) <Shift-KeyPress-Down> \
373        [itcl::code $this Pan set 0 2]
374
375    # Bindings for zoom via keyboard
376    bind $itk_component(view) <KeyPress-Prior> \
377        [itcl::code $this Zoom out]
378    bind $itk_component(view) <KeyPress-Next> \
379        [itcl::code $this Zoom in]
380
381    bind $itk_component(view) <Enter> "focus $itk_component(view)"
382
383    if {[string equal "x11" [tk windowingsystem]]} {
384        # Bindings for zoom via mouse
385        bind $itk_component(view) <4> [itcl::code $this Zoom out]
386        bind $itk_component(view) <5> [itcl::code $this Zoom in]
387    }
388
389    set _image(download) [image create photo]
390
391    eval itk_initialize $args
392    Connect
393}
394
395# ----------------------------------------------------------------------
396# DESTRUCTOR
397# ----------------------------------------------------------------------
398itcl::body Rappture::VtkHeightmapViewer::destructor {} {
399    Disconnect
400    image delete $_image(plot)
401    image delete $_image(download)
402    catch { blt::arcball destroy $_arcball }
403}
404
405itcl::body Rappture::VtkHeightmapViewer::DoResize {} {
406    if { $_width < 2 } {
407        set _width 500
408    }
409    if { $_height < 2 } {
410        set _height 500
411    }
412    set _start [clock clicks -milliseconds]
413    SendCmd "screen size [expr $_width - 20] $_height"
414    EventuallyRequestLegend
415    set _resizePending 0
416}
417
418itcl::body Rappture::VtkHeightmapViewer::DoRotate {} {
419    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
420    SendCmd "camera orient $q"
421    set _rotatePending 0
422}
423
424itcl::body Rappture::VtkHeightmapViewer::DoContour {} {
425    foreach dataset [CurrentDatasets -all] {
426        foreach {dataobj comp} [split $dataset -] break
427        #SendCmd "heightmap numcontours $_numContours $dataset"
428    }
429    set _contourPending 0
430}
431
432itcl::body Rappture::VtkHeightmapViewer::EventuallyRequestLegend {} {
433    if { !$_legendPending } {
434        set _legendPending 1
435        $_dispatcher event -idle !legend
436    }
437}
438
439itcl::body Rappture::VtkHeightmapViewer::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
449itcl::body Rappture::VtkHeightmapViewer::EventuallyContour { numContours } {
450    set _numContours $numContours
451    if { !$_contourPending } {
452        set _contourPending 1
453        $_dispatcher event -after 600 !contour
454    }
455}
456
457set rotate_delay 100
458
459itcl::body Rappture::VtkHeightmapViewer::EventuallyRotate { q } {
460    foreach { _view(qw) _view(qx) _view(qy) _view(qz) } $q break
461    if { !$_rotatePending } {
462        set _rotatePending 1
463        global rotate_delay
464        $_dispatcher event -after $rotate_delay !rotate
465    }
466}
467
468# ----------------------------------------------------------------------
469# USAGE: add <dataobj> ?<settings>?
470#
471# Clients use this to add a data object to the plot.  The optional
472# <settings> are used to configure the plot.  Allowed settings are
473# -color, -brightness, -width, -linestyle, and -raise.
474# ----------------------------------------------------------------------
475itcl::body Rappture::VtkHeightmapViewer::add {dataobj {settings ""}} {
476    array set params {
477        -color auto
478        -width 1
479        -linestyle solid
480        -brightness 0
481        -raise 0
482        -description ""
483        -param ""
484        -type ""
485    }
486    array set params $settings
487    set params(-description) ""
488    set params(-param) ""
489    foreach {opt val} $settings {
490        if {![info exists params($opt)]} {
491            error "bad setting \"$opt\": should be [join [lsort [array names params]] {, }]"
492        }
493        set params($opt) $val
494    }
495    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
496        # can't handle -autocolors yet
497        set params(-color) white
498    }
499    set pos [lsearch -exact $dataobj $_dlist]
500    if {$pos < 0} {
501        lappend _dlist $dataobj
502    }
503    set _obj2ovride($dataobj-color) $params(-color)
504    set _obj2ovride($dataobj-width) $params(-width)
505    set _obj2ovride($dataobj-raise) $params(-raise)
506    $_dispatcher event -idle !rebuild
507}
508
509
510# ----------------------------------------------------------------------
511# USAGE: delete ?<dataobj1> <dataobj2> ...?
512#
513#       Clients use this to delete a dataobj from the plot.  If no dataobjs
514#       are specified, then all dataobjs are deleted.  No data objects are
515#       deleted.  They are only removed from the display list.
516#
517# ----------------------------------------------------------------------
518itcl::body Rappture::VtkHeightmapViewer::delete {args} {
519    if { [llength $args] == 0} {
520        set args $_dlist
521    }
522    # Delete all specified dataobjs
523    set changed 0
524    foreach dataobj $args {
525        set pos [lsearch -exact $_dlist $dataobj]
526        if { $pos < 0 } {
527            continue;                   # Don't know anything about it.
528        }
529        # Remove it from the dataobj list.
530        set _dlist [lreplace $_dlist $pos $pos]
531        array unset _obj2ovride $dataobj-*
532        array unset _settings $dataobj-*
533        # Append to the end of the dataobj list.
534        #lappend _dlist $dataobj
535        set changed 1
536    }
537    # If anything changed, then rebuild the plot
538    if { $changed } {
539        $_dispatcher event -idle !rebuild
540    }
541}
542
543# ----------------------------------------------------------------------
544# USAGE: get ?-objects?
545# USAGE: get ?-visible?
546# USAGE: get ?-image view?
547#
548# Clients use this to query the list of objects being plotted, in
549# order from bottom to top of this result.  The optional "-image"
550# flag can also request the internal images being shown.
551# ----------------------------------------------------------------------
552itcl::body Rappture::VtkHeightmapViewer::get {args} {
553    if {[llength $args] == 0} {
554        set args "-objects"
555    }
556
557    set op [lindex $args 0]
558    switch -- $op {
559        "-objects" {
560            # put the dataobj list in order according to -raise options
561            set dlist {}
562            foreach dataobj $_dlist {
563                if { ![IsValidObject $dataobj] } {
564                    continue
565                }
566                if {[info exists _obj2ovride($dataobj-raise)] &&
567                    $_obj2ovride($dataobj-raise)} {
568                    set dlist [linsert $dlist 0 $dataobj]
569                } else {
570                    lappend dlist $dataobj
571                }
572            }
573            return $dlist
574        }
575        "-visible" {
576            set dlist {}
577            foreach dataobj $_dlist {
578                if { ![IsValidObject $dataobj] } {
579                    continue
580                }
581                if { ![info exists _obj2ovride($dataobj-raise)] } {
582                    # No setting indicates that the object isn't visible.
583                    continue
584                }
585                # Otherwise use the -raise parameter to put the object to
586                # the front of the list.
587                if { $_obj2ovride($dataobj-raise) } {
588                    set dlist [linsert $dlist 0 $dataobj]
589                } else {
590                    lappend dlist $dataobj
591                }
592            }
593            return $dlist
594        }           
595        -image {
596            if {[llength $args] != 2} {
597                error "wrong # args: should be \"get -image view\""
598            }
599            switch -- [lindex $args end] {
600                view {
601                    return $_image(plot)
602                }
603                default {
604                    error "bad image name \"[lindex $args end]\": should be view"
605                }
606            }
607        }
608        default {
609            error "bad option \"$op\": should be -objects or -image"
610        }
611    }
612}
613
614# ----------------------------------------------------------------------
615# USAGE: scale ?<data1> <data2> ...?
616#
617# Sets the default limits for the overall plot according to the
618# limits of the data for all of the given <data> objects.  This
619# accounts for all objects--even those not showing on the screen.
620# Because of this, the limits are appropriate for all objects as
621# the user scans through data in the ResultSet viewer.
622# ----------------------------------------------------------------------
623itcl::body Rappture::VtkHeightmapViewer::scale {args} {
624    foreach dataobj $args {
625        set string [limits $dataobj]
626        if { $string == "" } {
627            continue
628        }
629        array set bounds $string
630        if {![info exists _limits(xmin)] || $_limits(xmin) > $bounds(xmin)} {
631            set _limits(xmin) $bounds(xmin)
632        }
633        if {![info exists _limits(xmax)] || $_limits(xmax) < $bounds(xmax)} {
634            set _limits(xmax) $bounds(xmax)
635        }
636
637        if {![info exists _limits(ymin)] || $_limits(ymin) > $bounds(ymin)} {
638            set _limits(ymin) $bounds(ymin)
639        }
640        if {![info exists _limits(ymax)] || $_limits(ymax) < $bounds(ymax)} {
641            set _limits(ymax) $bounds(ymax)
642        }
643
644        if {![info exists _limits(zmin)] || $_limits(zmin) > $bounds(zmin)} {
645            set _limits(zmin) $bounds(zmin)
646        }
647        if {![info exists _limits(zmax)] || $_limits(zmax) < $bounds(zmax)} {
648            set _limits(zmax) $bounds(zmax)
649        }
650    }
651}
652
653# ----------------------------------------------------------------------
654# USAGE: download coming
655# USAGE: download controls <downloadCommand>
656# USAGE: download now
657#
658# Clients use this method to create a downloadable representation
659# of the plot.  Returns a list of the form {ext string}, where
660# "ext" is the file extension (indicating the type of data) and
661# "string" is the data itself.
662# ----------------------------------------------------------------------
663itcl::body Rappture::VtkHeightmapViewer::download {option args} {
664    switch $option {
665        coming {
666            if {[catch {
667                blt::winop snap $itk_component(plotarea) $_image(download)
668            }]} {
669                $_image(download) configure -width 1 -height 1
670                $_image(download) put #000000
671            }
672        }
673        controls {
674            set popup .vtkviewerdownload
675            if { ![winfo exists .vtkviewerdownload] } {
676                set inner [BuildDownloadPopup $popup [lindex $args 0]]
677            } else {
678                set inner [$popup component inner]
679            }
680            set _downloadPopup(image_controls) $inner.image_frame
681            set num [llength [get]]
682            set num [expr {($num == 1) ? "1 result" : "$num results"}]
683            set word [Rappture::filexfer::label downloadWord]
684            $inner.summary configure -text "$word $num in the following format:"
685            update idletasks            ;# Fix initial sizes
686            return $popup
687        }
688        now {
689            set popup .vtkviewerdownload
690            if {[winfo exists .vtkviewerdownload]} {
691                $popup deactivate
692            }
693            switch -- $_downloadPopup(format) {
694                "image" {
695                    return [$this GetImage [lindex $args 0]]
696                }
697                "vtk" {
698                    return [$this GetVtkData [lindex $args 0]]
699                }
700            }
701            return ""
702        }
703        default {
704            error "bad option \"$option\": should be coming, controls, now"
705        }
706    }
707}
708
709# ----------------------------------------------------------------------
710# USAGE: Connect ?<host:port>,<host:port>...?
711#
712# Clients use this method to establish a connection to a new
713# server, or to reestablish a connection to the previous server.
714# Any existing connection is automatically closed.
715# ----------------------------------------------------------------------
716itcl::body Rappture::VtkHeightmapViewer::Connect {} {
717    global readyForNextFrame
718    set readyForNextFrame 1
719    set _reset 1
720    set _hosts [GetServerList "vtkvis"]
721    if { "" == $_hosts } {
722        return 0
723    }
724    set result [VisViewer::Connect $_hosts]
725    if { $result } {
726        set w [winfo width $itk_component(view)]
727        set h [winfo height $itk_component(view)]
728        EventuallyResize $w $h
729    }
730    return $result
731}
732
733#
734# isconnected --
735#
736#       Indicates if we are currently connected to the visualization server.
737#
738itcl::body Rappture::VtkHeightmapViewer::isconnected {} {
739    return [VisViewer::IsConnected]
740}
741
742#
743# disconnect --
744#
745itcl::body Rappture::VtkHeightmapViewer::disconnect {} {
746    Disconnect
747    set _reset 1
748}
749
750#
751# Disconnect --
752#
753#       Clients use this method to disconnect from the current rendering
754#       server.
755#
756itcl::body Rappture::VtkHeightmapViewer::Disconnect {} {
757    VisViewer::Disconnect
758
759    $_dispatcher cancel !rebuild
760    $_dispatcher cancel !resize
761    $_dispatcher cancel !contour
762    $_dispatcher cancel !rotate
763    $_dispatcher cancel !legend
764    # disconnected -- no more data sitting on server
765    set _outbuf ""
766    array unset _datasets
767    array unset _data
768    array unset _colormaps
769    array unset _obj2datasets
770    global readyForNextFrame
771    set readyForNextFrame 1
772}
773
774#
775# sendto --
776#
777itcl::body Rappture::VtkHeightmapViewer::sendto { bytes } {
778    SendBytes "$bytes\n"
779}
780
781#
782# SendCmd
783#
784#       Send commands off to the rendering server.  If we're currently
785#       sending data objects to the server, buffer the commands to be
786#       sent later.
787#
788itcl::body Rappture::VtkHeightmapViewer::SendCmd {string} {
789    if { $_buffering } {
790        append _outbuf $string "\n"
791    } else {
792        SendBytes "$string\n"
793    }
794}
795
796#
797# SendCmdNoWait
798#
799#       Send commands off to the rendering server.  If we're currently
800#       sending data objects to the server, buffer the commands to be
801#       sent later.
802#
803itcl::body Rappture::VtkHeightmapViewer::SendCmdNoWait {string} {
804    if { $_buffering } {
805        append _outbuf $string "\n"
806    } else {
807        SendBytes "$string\n"
808    }
809}
810
811# ----------------------------------------------------------------------
812# USAGE: ReceiveImage -bytes <size> -type <type> -token <token>
813#
814# Invoked automatically whenever the "image" command comes in from
815# the rendering server.  Indicates that binary image data with the
816# specified <size> will follow.
817# ----------------------------------------------------------------------
818itcl::body Rappture::VtkHeightmapViewer::ReceiveImage { args } {
819    global readyForNextFrame
820    set readyForNextFrame 1
821    array set info {
822        -token "???"
823        -bytes 0
824        -type image
825    }
826    array set info $args
827    set bytes [ReceiveBytes $info(-bytes)]
828    if { $info(-type) == "image" } {
829        if 0 {
830            set f [open "last.ppm" "w"]
831            puts $f $bytes
832            close $f
833        }
834        $_image(plot) configure -data $bytes
835        set time [clock seconds]
836        set date [clock format $time]
837        #puts stderr "$date: received image [image width $_image(plot)]x[image height $_image(plot)] image>"       
838        if { $_start > 0 } {
839            set finish [clock clicks -milliseconds]
840            #puts stderr "round trip time [expr $finish -$_start] milliseconds"
841            set _start 0
842        }
843    } elseif { $info(type) == "print" } {
844        set tag $this-print-$info(-token)
845        set _hardcopy($tag) $bytes
846    }
847}
848
849#
850# ReceiveDataset --
851#
852itcl::body Rappture::VtkHeightmapViewer::ReceiveDataset { args } {
853    if { ![isconnected] } {
854        return
855    }
856    set option [lindex $args 0]
857    switch -- $option {
858        "scalar" {
859            set option [lindex $args 1]
860            switch -- $option {
861                "world" {
862                    foreach { x y z value tag } [lrange $args 2 end] break
863                }
864                "pixel" {
865                    foreach { x y value tag } [lrange $args 2 end] break
866                }
867            }
868        }
869        "vector" {
870            set option [lindex $args 1]
871            switch -- $option {
872                "world" {
873                    foreach { x y z vx vy vz tag } [lrange $args 2 end] break
874                }
875                "pixel" {
876                    foreach { x y vx vy vz tag } [lrange $args 2 end] break
877                }
878            }
879        }
880        "names" {
881            foreach { name } [lindex $args 1] {
882                #puts stderr "Dataset: $name"
883            }
884        }
885        default {
886            error "unknown dataset option \"$option\" from server"
887        }
888    }
889}
890
891# ----------------------------------------------------------------------
892# USAGE: Rebuild
893#
894# Called automatically whenever something changes that affects the
895# data in the widget.  Clears any existing data and rebuilds the
896# widget to display new data.
897# ----------------------------------------------------------------------
898itcl::body Rappture::VtkHeightmapViewer::Rebuild {} {
899    set w [winfo width $itk_component(view)]
900    set h [winfo height $itk_component(view)]
901    if { $w < 2 || $h < 2 } {
902        $_dispatcher event -idle !rebuild
903        return
904    }
905
906    set _buffering 1
907    # Turn on buffering of commands to the server.  We don't want to
908    # be preempted by a server disconnect/reconnect (which automatically
909    # generates a new call to Rebuild).   
910    if { $_width != $w || $_height != $h || $_reset } {
911        set _width $w
912        set _height $h
913        $_arcball resize $w $h
914        DoResize
915        if { $_settings(stretchToFit) } {
916            Adjustsetting stretchToFit
917        }
918    }
919    if { $_reset } {
920        InitSettings isHeightmap background
921        #
922        # Reset the camera and other view parameters
923        #
924        SendCmd "axis color all [Color2RGB $itk_option(-plotforeground)]"
925        SendCmd "axis lrot z 90"
926        set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
927        $_arcball quaternion $q
928        if {$_settings(isHeightmap) } {
929            SendCmd "camera reset"
930            if { $_view(ortho)} {
931                SendCmd "camera mode ortho"
932            } else {
933                SendCmd "camera mode persp"
934            }
935        }           
936        DoRotate
937        PanCamera
938    }
939    set _first ""
940
941    #SendCmd "imgflush"
942
943    set _first ""
944    # Start off with no datasets are visible.
945    SendCmd "dataset visible 0"
946    set scale [GetHeightmapScale]
947    foreach dataobj [get -objects] {
948        if { [info exists _obj2ovride($dataobj-raise)] &&  $_first == "" } {
949            set _first $dataobj
950        }
951        scale $dataobj
952        set _obj2datasets($dataobj) ""
953        foreach comp [$dataobj components] {
954            set tag $dataobj-$comp
955            if { ![info exists _datasets($tag)] } {
956                set bytes [$dataobj vtkdata $comp]
957                if 1 {
958                set f [open /tmp/vtkheightmap.vtk "w"]
959                puts $f $bytes
960                close $f
961                }
962                set length [string length $bytes]
963                append _outbuf "dataset add $tag data follows $length\n"
964                append _outbuf $bytes
965                set _datasets($tag) 1
966                SetObjectStyle $dataobj $comp
967            }
968            lappend _obj2datasets($dataobj) $tag
969            if { [info exists _obj2ovride($dataobj-raise)] } {
970                SendCmd "heightmap visible 1 $tag"
971            }
972            if { ![info exists _comp2scale($tag)] ||
973                 $_comp2scale($tag) != $scale } {
974                SendCmd "heightmap heightscale $scale $tag"
975                set _comp2scale($tag) $scale
976            }
977        }
978    }
979    if { $_first != "" && $_reset } {
980        if 1 {
981            # Tell the server the name of the tool, the version, and dataset
982            # that we are rendering.  Have to do it here because we don't know
983            # what data objects are using the renderer until be get here.
984            global env
985
986            lappend out "hub" [exec hostname]
987            lappend out "viewer" "vtkheightmapviewer"
988            if { [info exists env(USER)] } {
989                lappend out "user" $env(USER)
990            }
991            if { [info exists env(SESSION)] } {
992                lappend out "session" $env(SESSION)
993            }
994            lappend out "tool_id"      [$_first hints toolId]
995            lappend out "tool_name"    [$_first hints toolName]
996            lappend out "tool_version" [$_first hints toolRevision]
997            lappend out "tool_title"   [$_first hints toolTitle]
998            lappend out "tool_dataset" [$_first hints label]
999            SendCmd "clientinfo [list $out]"
1000        }
1001        set _fieldNames [$_first hints fieldnames]
1002        set _fieldUnits [$_first hints fieldunits]
1003        set _fieldLabels [$_first hints fieldlabels]
1004        $itk_component(field) choices delete 0 end
1005        $itk_component(fieldmenu) delete 0 end
1006        array unset _fields
1007        foreach name $_fieldNames title $_fieldLabels units $_fieldUnits {
1008            SendCmd "dataset maprange explicit $_limits(zmin) $_limits(zmax) $name"
1009            if { $title == "" } {
1010                set title $name
1011            }
1012            $itk_component(field) choices insert end "$name" "$title"
1013            $itk_component(fieldmenu) add radiobutton -label "$title" \
1014                -value $title -variable [itcl::scope _currentFieldName] \
1015                -selectcolor red \
1016                -activebackground $itk_option(-plotbackground) \
1017                -activeforeground $itk_option(-plotforeground) \
1018                -font "Arial 8" \
1019                -command [itcl::code $this Combo invoke]
1020            set _fields($name) [list $title $units]
1021            set _currentFieldName $name
1022        }
1023        if { [array size _fields] == 1 } {
1024            set _currentFieldName $_fieldLabels
1025            if { $_currentFieldName == "" } {
1026                puts stderr "no default name from field"
1027                set _currentFieldName "Default"
1028            }
1029        }
1030        $itk_component(field) value $_currentFieldName
1031    }
1032    InitSettings stretchToFit
1033
1034    if { $_reset } {
1035        SendCmd "axis tickpos outside"
1036        foreach axis { x y z } {
1037            SendCmd "axis lformat $axis %g"
1038        }
1039        foreach axis { x y z } {
1040            set label [$_first hints ${axis}label]
1041            if { $label == "" } {
1042                if {$axis == "z"} {
1043                    set label [lindex $_fields($_currentFieldName) 0]
1044                } else {
1045                    set label [string toupper $axis]
1046                }
1047            }
1048            # May be a space in the axis label.
1049            SendCmd [list axis name $axis $label]
1050
1051            if {$axis == "z" && [$_first hints ${axis}units] == ""} {
1052                set units [lindex $_fields($_currentFieldName) 1]
1053            } else {
1054                set units [$_first hints ${axis}units]
1055            }
1056            if { $units != "" } {
1057                # May be a space in the axis units.
1058                SendCmd [list axis units $axis $units]
1059            }
1060        }
1061        #
1062        # Reset the camera and other view parameters
1063        #
1064        SendCmd "axis color all [Color2RGB $itk_option(-plotforeground)]"
1065        ResetAxes
1066        set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1067        $_arcball quaternion $q
1068        if {$_settings(isHeightmap) } {
1069            SendCmd "camera reset"
1070            if { $_view(ortho)} {
1071                SendCmd "camera mode ortho"
1072            } else {
1073                SendCmd "camera mode persp"
1074            }
1075        }
1076        DoRotate
1077        PanCamera
1078        InitSettings axis-xgrid axis-ygrid axis-zgrid \
1079            axis-visible axisLabels
1080        InitSettings contour-opacity \
1081            heightmap-scale lighting \
1082            colormap field outline \
1083            edges contour-opacity wireframe
1084        set _reset 0
1085    }
1086    global readyForNextFrame
1087    set readyForNextFrame 0;            # Don't advance to the next frame
1088    set _buffering 0;                   # Turn off buffering.
1089
1090    # Actually write the commands to the server socket.  If it fails, we don't
1091    # care.  We're finished here.
1092    blt::busy hold $itk_component(hull)
1093    sendto $_outbuf;                       
1094    blt::busy release $itk_component(hull)
1095    set _outbuf "";                        # Clear the buffer.               
1096}
1097
1098# ----------------------------------------------------------------------
1099# USAGE: CurrentDatasets ?-all -visible? ?dataobjs?
1100#
1101# Returns a list of server IDs for the current datasets being displayed.  This
1102# is normally a single ID, but it might be a list of IDs if the current data
1103# object has multiple components.
1104# ----------------------------------------------------------------------
1105itcl::body Rappture::VtkHeightmapViewer::CurrentDatasets {args} {
1106    set flag [lindex $args 0]
1107    switch -- $flag {
1108        "-all" {
1109            if { [llength $args] > 1 } {
1110                error "CurrentDatasets: can't specify dataobj after \"-all\""
1111            }
1112            set dlist [get -objects]
1113        }
1114        "-visible" {
1115            if { [llength $args] > 1 } {
1116                set dlist {}
1117                set args [lrange $args 1 end]
1118                foreach dataobj $args {
1119                    if { [info exists _obj2ovride($dataobj-raise)] } {
1120                        lappend dlist $dataobj
1121                    }
1122                }
1123            } else {
1124                set dlist [get -visible]
1125            }
1126        }           
1127        default {
1128            set dlist $args
1129        }
1130    }
1131    set rlist ""
1132    foreach dataobj $dlist {
1133        foreach comp [$dataobj components] {
1134            set tag $dataobj-$comp
1135            if { [info exists _datasets($tag)] && $_datasets($tag) } {
1136                lappend rlist $tag
1137            }
1138        }
1139    }
1140    return $rlist
1141}
1142
1143# ----------------------------------------------------------------------
1144# USAGE: Zoom in
1145# USAGE: Zoom out
1146# USAGE: Zoom reset
1147#
1148# Called automatically when the user clicks on one of the zoom
1149# controls for this widget.  Changes the zoom for the current view.
1150# ----------------------------------------------------------------------
1151itcl::body Rappture::VtkHeightmapViewer::Zoom {option} {
1152    switch -- $option {
1153        "in" {
1154            set _view(zoom) [expr {$_view(zoom)*1.25}]
1155            SendCmd "camera zoom $_view(zoom)"
1156        }
1157        "out" {
1158            set _view(zoom) [expr {$_view(zoom)*0.8}]
1159            SendCmd "camera zoom $_view(zoom)"
1160        }
1161        "reset" {
1162            array set _view {
1163                qw      0.36
1164                qx      0.25
1165                qy      0.50
1166                qz      0.70
1167                zoom    1.0
1168                xpan   0
1169                ypan   0
1170            }
1171            SendCmd "camera reset all"
1172            if { $_first != "" } {
1173                set location [$_first hints camera]
1174                if { $location != "" } {
1175                    array set _view $location
1176                }
1177            }
1178            set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1179            $_arcball quaternion $q
1180            DoRotate
1181        }
1182    }
1183}
1184
1185itcl::body Rappture::VtkHeightmapViewer::PanCamera {} {
1186    set x $_view(xpan)
1187    set y $_view(ypan)
1188    SendCmd "camera pan $x $y"
1189}
1190
1191
1192# ----------------------------------------------------------------------
1193# USAGE: Rotate click <x> <y>
1194# USAGE: Rotate drag <x> <y>
1195# USAGE: Rotate release <x> <y>
1196#
1197# Called automatically when the user clicks/drags/releases in the
1198# plot area.  Moves the plot according to the user's actions.
1199# ----------------------------------------------------------------------
1200itcl::body Rappture::VtkHeightmapViewer::Rotate {option x y} {
1201    switch -- $option {
1202        "click" {
1203            $itk_component(view) configure -cursor fleur
1204            set _click(x) $x
1205            set _click(y) $y
1206        }
1207        "drag" {
1208            if {[array size _click] == 0} {
1209                Rotate click $x $y
1210            } else {
1211                set w [winfo width $itk_component(view)]
1212                set h [winfo height $itk_component(view)]
1213                if {$w <= 0 || $h <= 0} {
1214                    return
1215                }
1216
1217                if {[catch {
1218                    # this fails sometimes for no apparent reason
1219                    set dx [expr {double($x-$_click(x))/$w}]
1220                    set dy [expr {double($y-$_click(y))/$h}]
1221                }]} {
1222                    return
1223                }
1224                if { $dx == 0 && $dy == 0 } {
1225                    return
1226                }
1227                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1228                EventuallyRotate $q
1229                set _click(x) $x
1230                set _click(y) $y
1231            }
1232        }
1233        "release" {
1234            Rotate drag $x $y
1235            $itk_component(view) configure -cursor ""
1236            catch {unset _click}
1237        }
1238        default {
1239            error "bad option \"$option\": should be click, drag, release"
1240        }
1241    }
1242}
1243
1244itcl::body Rappture::VtkHeightmapViewer::Pick {x y} {
1245    foreach tag [CurrentDatasets -visible] {
1246        SendCmd "dataset getscalar pixel $x $y $tag"
1247    }
1248}
1249
1250# ----------------------------------------------------------------------
1251# USAGE: $this Pan click x y
1252#        $this Pan drag x y
1253#        $this Pan release x y
1254#
1255# Called automatically when the user clicks on one of the zoom
1256# controls for this widget.  Changes the zoom for the current view.
1257# ----------------------------------------------------------------------
1258itcl::body Rappture::VtkHeightmapViewer::Pan {option x y} {
1259    switch -- $option {
1260        "set" {
1261            set w [winfo width $itk_component(view)]
1262            set h [winfo height $itk_component(view)]
1263            set x [expr $x / double($w)]
1264            set y [expr $y / double($h)]
1265            set _view(xpan) [expr $_view(xpan) + $x]
1266            set _view(ypan) [expr $_view(ypan) + $y]
1267            PanCamera
1268            return
1269        }
1270        "click" {
1271            set _click(x) $x
1272            set _click(y) $y
1273            $itk_component(view) configure -cursor hand1
1274        }
1275        "drag" {
1276            if { ![info exists _click(x)] } {
1277                set _click(x) $x
1278            }
1279            if { ![info exists _click(y)] } {
1280                set _click(y) $y
1281            }
1282            set w [winfo width $itk_component(view)]
1283            set h [winfo height $itk_component(view)]
1284            set dx [expr ($_click(x) - $x)/double($w)]
1285            set dy [expr ($_click(y) - $y)/double($h)]
1286            set _click(x) $x
1287            set _click(y) $y
1288            set _view(xpan) [expr $_view(xpan) - $dx]
1289            set _view(ypan) [expr $_view(ypan) - $dy]
1290            PanCamera
1291        }
1292        "release" {
1293            Pan drag $x $y
1294            $itk_component(view) configure -cursor ""
1295        }
1296        default {
1297            error "unknown option \"$option\": should set, click, drag, or release"
1298        }
1299    }
1300}
1301
1302# ----------------------------------------------------------------------
1303# USAGE: InitSettings <what> ?<value>?
1304#
1305# Used internally to update rendering settings whenever parameters
1306# change in the popup settings panel.  Sends the new settings off
1307# to the back end.
1308# ----------------------------------------------------------------------
1309itcl::body Rappture::VtkHeightmapViewer::InitSettings { args } {
1310    foreach spec $args {
1311        if { [info exists _settings($_first-$spec)] } {
1312            # Reset global setting with dataobj specific setting
1313            set _settings($spec) $_settings($_first-$spec)
1314        }
1315        AdjustSetting $spec
1316    }
1317}
1318
1319#
1320# AdjustSetting --
1321#
1322#       Changes/updates a specific setting in the widget.  There are
1323#       usually user-setable option.  Commands are sent to the render
1324#       server.
1325#
1326itcl::body Rappture::VtkHeightmapViewer::AdjustSetting {what {value ""}} {
1327    if { ![isconnected] } {
1328        return
1329    }
1330    switch -- $what {
1331        "contour-opacity" {
1332            set val $_settings(contour-opacity)
1333            set sval [expr { 0.01 * double($val) }]
1334            foreach dataset [CurrentDatasets -all] {
1335                SendCmd "heightmap opacity $sval $dataset"
1336            }
1337        }
1338        "wireframe" {
1339            set bool $_settings(wireframe)
1340            foreach dataset [CurrentDatasets -all] {
1341                SendCmd "heightmap wireframe $bool $dataset"
1342            }
1343        }
1344        "colormap-visible" {
1345            set bool $_settings(colormap-visible)
1346            foreach dataset [CurrentDatasets -all] {
1347                SendCmd "heightmap surface $bool $dataset"
1348            }
1349        }
1350        "isolines-visible" {
1351            set bool $_settings(isolines-visible)
1352            foreach dataset [CurrentDatasets -all] {
1353                SendCmd "heightmap isolines $bool $dataset"
1354            }
1355        }
1356        "lighting" {
1357            if { $_settings(isHeightmap) } {
1358                set bool $_settings(lighting)
1359                SendCmd "heightmap lighting $bool"
1360            } else {
1361                SendCmd "heightmap lighting 0"
1362            }
1363        }
1364        "edges" {
1365            set bool $_settings(edges)
1366            foreach dataset [CurrentDatasets -all] {
1367                SendCmd "heightmap edges $bool $dataset"
1368            }
1369        }
1370        "axis-visible" {
1371            set bool $_settings(axis-visible)
1372            SendCmd "axis visible all $bool"
1373        }
1374        "axisLabels" {
1375            set bool $_settings(axisLabels)
1376            SendCmd "axis labels all $bool"
1377        }
1378        "axis-xgrid" - "axis-ygrid" - "axis-zgrid" {
1379            set axis [string range $what 5 5]
1380            set bool $_settings($what)
1381            SendCmd "axis grid $axis $bool"
1382        }
1383        "axis-flymode" {
1384            set mode [$itk_component(axis-flymode) value]
1385            set mode [$itk_component(axis-flymode) translate $mode]
1386            set _settings($what) $mode
1387            SendCmd "axis flymode $mode"
1388        }
1389        "axis-minticks" {
1390            set bool $_settings(axis-minticks)
1391            foreach axis { x y z } {
1392                SendCmd "axis minticks ${axis} $bool"
1393            }
1394        }
1395        "isolines" {
1396            set n $_settings($what)
1397            EventuallyContour $n
1398        }
1399        "isolines-visible" {
1400            set bool $_settings($what)
1401            foreach dataset [CurrentDatasets -all] {
1402                SendCmd "heightmap isolines $bool $dataset"
1403            }
1404        }
1405        "colormap-visible" {
1406            set bool $_settings($what)
1407            foreach dataset [CurrentDatasets -all] {
1408                SendCmd "heightmap surface $bool $dataset"
1409            }
1410        }
1411        "background" {
1412            set bgcolor [$itk_component(background) value]
1413            array set fgcolors {
1414                "black" "white"
1415                "white" "black"
1416                "grey"  "black"
1417            }
1418            configure -plotbackground $bgcolor \
1419                -plotforeground $fgcolors($bgcolor)
1420            $itk_component(view) delete "legend"
1421            DrawLegend $_currentFieldName
1422        }
1423        "isoline-color" {
1424            set color [$itk_component(isolinecolor) value]
1425            if { $color == "none" } {
1426                if { $_settings(isolines-visible) } {
1427                    SendCmd "heightmap isolines 0"
1428                    set _settings(isolines-visible) 0
1429                }
1430            } else {
1431                if { !$_settings(isolines-visible) } {
1432                    SendCmd "heightmap isolines 1"
1433                    set _settings(isolines-visible) 1
1434                }
1435                SendCmd "heightmap isolinecolor [Color2RGB $color]"
1436            }
1437            DrawLegend $_currentFieldName
1438        }
1439        "colormap" {
1440            set color [$itk_component(colormap) value]
1441            set _settings(colormap) $color
1442            if { $color == "none" } {
1443                if { $_settings(colormap-visible) } {
1444                    SendCmd "heightmap surface 0"
1445                    set _settings(colormap-visible) 0
1446                }
1447            } else {
1448                if { !$_settings(colormap-visible) } {
1449                    SendCmd "heightmap surface 1"
1450                    set _settings(colormap-visible) 1
1451                }
1452                ResetColormap $color
1453                SendCmd "heightmap colormap $_currentColormap"
1454            }
1455            EventuallyRequestLegend
1456        }
1457        "contour-opacity" {
1458            set val $_settings(contour-opacity)
1459            set sval [expr { 0.01 * double($val) }]
1460            foreach dataset [CurrentDatasets -all] {
1461                SendCmd "heightmap opacity $sval $dataset"
1462            }
1463        }
1464        "heightmap-scale" {
1465            if { $_settings(isHeightmap) } {
1466                set scale [GetHeightmapScale]
1467                foreach dataset [CurrentDatasets -all] {
1468                    SendCmd "heightmap heightscale $scale $dataset"
1469                    set _comp2scale($dataset) $scale
1470                }
1471                ResetAxes
1472            }
1473        }
1474        "lighting" {
1475            if { $_settings(isHeightmap) } {
1476                set bool $_settings(lighting)
1477                SendCmd "heightmap lighting $bool"
1478            } else {
1479                SendCmd "heightmap lighting 0"
1480            }
1481        }
1482        "field" {
1483            set new   [$itk_component(field) value]
1484            set value [$itk_component(field) translate $new]
1485            set _settings(field) $value
1486            if { [info exists _fields($new)] } {
1487                set _colorMode scalar
1488                set _currentFieldName $new
1489            } else {
1490                puts stderr "unknown field \"$new\""
1491                return
1492            }
1493            EventuallyRequestLegend
1494        }
1495        "stretchToFit" {
1496            set bool $_settings(stretchToFit)
1497            set _settings(x-scale) 1.0
1498            set _settings(y-scale) 1.0
1499            set _settings(z-scale) 1.0
1500            if { $bool } {
1501                set w $_width
1502                set h $_height
1503                set xr [expr $_limits(xmax) - $_limits(xmin)]
1504                set yr [expr $_limits(ymax) - $_limits(ymin)]
1505                if { $h < $w } {
1506                    set xs [expr (double($w)*$yr) / (double($h)*$xr)]
1507                    set _settings(x-scale) $xs
1508                } else {
1509                    set ys [expr (double($h)*$xr) / (double($w)*$yr)]
1510                    set _settings(y-scale) $ys
1511                    set _settings(z-scale) $ys
1512                }
1513                set heightScale [GetHeightmapScale]
1514                if {$heightScale == 0} {
1515                    SendCmd "camera aspect window"
1516                } else {
1517                    SendCmd "camera aspect square"
1518                }
1519            } else {
1520                SendCmd "camera aspect native"
1521            }
1522        }
1523        "outline" {
1524            set bool $_settings(outline)
1525            SendCmd "dataset outline $bool"
1526        }
1527        "isHeightmap" {
1528            set bool $_settings(isHeightmap)
1529            if { $bool } {
1530                $itk_component(lighting) configure -state normal
1531            } else {
1532                $itk_component(lighting) configure -state disabled
1533            }
1534            if {[isconnected]} {
1535                set _settings(lighting) $bool
1536                # Fix heightmap scale: 0 for contours, 1 for heightmaps.
1537                if { $bool } {
1538                    set _settings(heightmap-scale) 50
1539                } else {
1540                    set _settings(heightmap-scale) 50
1541                }
1542                SendCmd "heightmap lighting $bool"
1543                set scale [GetHeightmapScale]
1544                foreach dataset [CurrentDatasets -all] {
1545                    SendCmd "heightmap heightscale $scale $dataset"
1546                    set _comp2scale($dataset) $scale
1547                }
1548                if {$_settings(stretchToFit)} {
1549                    if {$scale == 0} {
1550                        SendCmd "camera aspect window"
1551                    } else {
1552                        SendCmd "camera aspect square"
1553                    }
1554                }
1555                ResetAxes
1556                # Fix the mouse bindings for rotation/panning and the
1557                # camera mode. Ideally we'd create a bindtag for these.
1558                set c $itk_component(view)
1559                if { $bool } {
1560                    # Bindings for rotation via mouse
1561                    bind $c <ButtonPress-1> \
1562                        [itcl::code $this Rotate click %x %y]
1563                    bind $c <B1-Motion> \
1564                        [itcl::code $this Rotate drag %x %y]
1565                    bind $c <ButtonRelease-1> \
1566                        [itcl::code $this Rotate release %x %y]
1567                    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1568                    $_arcball quaternion $q
1569                    if {$_view(ortho)} {
1570                        SendCmd "camera mode ortho"
1571                    } else {
1572                        SendCmd "camera mode persp"
1573                    }
1574                    SendCmd "camera orient $q"
1575                } else {
1576                    set _settings(heightmap-scale) 0
1577                    bind $c <ButtonPress-1> {}
1578                    bind $c <B1-Motion> {}
1579                    bind $c <ButtonRelease-1> {}
1580                    SendCmd "camera mode image"
1581                }
1582            }
1583        }       
1584        "legendVisible" {
1585            if { !$_settings(legendVisible) } {
1586                $itk_component(view) delete legend
1587            }
1588            DrawLegend $_currentFieldName
1589        }
1590        default {
1591            error "don't know how to fix $what"
1592        }
1593    }
1594}
1595
1596#
1597# RequestLegend --
1598#
1599#       Request a new legend from the server.  The size of the legend
1600#       is determined from the height of the canvas. 
1601#
1602# This should be called when
1603#       1.  A new current colormap is set.
1604#       2.  Window is resized.
1605#       3.  The limits of the data have changed.  (Just need a redraw).
1606#       4.  Number of isolines have changed. (Just need a redraw).
1607#       5.  Legend becomes visible (Just need a redraw).
1608#
1609itcl::body Rappture::VtkHeightmapViewer::RequestLegend {} {
1610    set _legendPending 0
1611    set font "Arial 8"
1612    set lineht [font metrics $font -linespace]
1613    set c $itk_component(view)
1614    set w 12
1615    set h [expr {$_height - 2 * ($lineht + 2)}]
1616    if { $h < 1} {
1617        return
1618    }
1619    if { [info exists _fields($_currentFieldName)] } {
1620        set title [lindex $_fields($_currentFieldName) 0]
1621        if { $title != "component" } {
1622            set h [expr $h - ($lineht + 2)]
1623        }
1624    } else {
1625        return
1626    }
1627    # Set the legend on the first heightmap dataset.
1628    if { $_currentColormap != ""  } {
1629        set cmap $_currentColormap
1630        SendCmdNoWait "legend $cmap scalar $title {} $w $h 0"
1631    }
1632}
1633
1634#
1635# ResetAxes --
1636#
1637#       Set axis z bounds and range
1638#
1639itcl::body Rappture::VtkHeightmapViewer::ResetAxes {} {
1640    if { ![info exists _limits(zmin)] || ![info exists _limits(zmax)] ||
1641         ![info exists _fields($_currentFieldName)]} {
1642        SendCmd "dataset maprange all"
1643        SendCmd "axis autorange z on"
1644        SendCmd "axis autobounds z on"
1645        return
1646    }
1647
1648    set dataRange   [expr $_limits(zmax) - $_limits(zmin)]
1649    set boundsRange [expr $_limits(xmax) - $_limits(xmin)]
1650    set r [expr $_limits(ymax) - $_limits(ymin)]
1651    if {$r > $boundsRange} {
1652        set boundsRange $r
1653    }
1654    if {$dataRange < 1.0e-10} {
1655        set dataScale 1.0
1656    } else {
1657        set dataScale [expr $boundsRange / $dataRange]
1658    }
1659    set heightScale [GetHeightmapScale]
1660    set bMin [expr $heightScale * $dataScale * $_limits(zmin)]
1661    set bMax [expr $heightScale * $dataScale * $_limits(zmax)]
1662    set fieldName [lindex $_fields($_currentFieldName) 0]
1663    SendCmd "dataset maprange explicit $_limits(zmin) $_limits(zmax) $fieldName"
1664    SendCmd "axis bounds z $bMin $bMax"
1665    SendCmd "axis range z $_limits(zmin) $_limits(zmax)"
1666}
1667
1668#
1669# SetCurrentColormap --
1670#
1671itcl::body Rappture::VtkHeightmapViewer::SetCurrentColormap { stylelist } {
1672    array set style {
1673        -color BCGYR
1674        -levels 10
1675        -opacity 1.0
1676    }
1677    array set style $stylelist
1678
1679    set name "$style(-color):$style(-levels):$style(-opacity)"
1680    if { ![info exists _colormaps($name)] } {
1681        set stylelist [array get style]
1682        BuildColormap $name $stylelist
1683        set _colormaps($name) $stylelist
1684    }
1685    set _currentColormap $name
1686}
1687
1688itcl::body Rappture::VtkHeightmapViewer::ColorsToColormap { colors } {
1689    switch -- $colors {
1690        "grey-to-blue" {
1691            return {
1692                0.0                      0.200 0.200 0.200
1693                0.14285714285714285      0.400 0.400 0.400
1694                0.2857142857142857       0.600 0.600 0.600
1695                0.42857142857142855      0.900 0.900 0.900
1696                0.5714285714285714       0.800 1.000 1.000
1697                0.7142857142857143       0.600 1.000 1.000
1698                0.8571428571428571       0.400 0.900 1.000
1699                1.0                      0.000 0.600 0.800
1700            }
1701        }
1702        "blue-to-grey" {
1703            return {
1704                0.0                     0.000 0.600 0.800
1705                0.14285714285714285     0.400 0.900 1.000
1706                0.2857142857142857      0.600 1.000 1.000
1707                0.42857142857142855     0.800 1.000 1.000
1708                0.5714285714285714      0.900 0.900 0.900
1709                0.7142857142857143      0.600 0.600 0.600
1710                0.8571428571428571      0.400 0.400 0.400
1711                1.0                     0.200 0.200 0.200
1712            }
1713        }
1714        "blue" {
1715            return {
1716                0.0                     0.900 1.000 1.000
1717                0.1111111111111111      0.800 0.983 1.000
1718                0.2222222222222222      0.700 0.950 1.000
1719                0.3333333333333333      0.600 0.900 1.000
1720                0.4444444444444444      0.500 0.833 1.000
1721                0.5555555555555556      0.400 0.750 1.000
1722                0.6666666666666666      0.300 0.650 1.000
1723                0.7777777777777778      0.200 0.533 1.000
1724                0.8888888888888888      0.100 0.400 1.000
1725                1.0                     0.000 0.250 1.000
1726            }
1727        }
1728        "brown-to-blue" {
1729            return {
1730                0.0                             0.200   0.100   0.000
1731                0.09090909090909091             0.400   0.187   0.000
1732                0.18181818181818182             0.600   0.379   0.210
1733                0.2727272727272727              0.800   0.608   0.480
1734                0.36363636363636365             0.850   0.688   0.595
1735                0.45454545454545453             0.950   0.855   0.808
1736                0.5454545454545454              0.800   0.993   1.000
1737                0.6363636363636364              0.600   0.973   1.000
1738                0.7272727272727273              0.400   0.940   1.000
1739                0.8181818181818182              0.200   0.893   1.000
1740                0.9090909090909091              0.000   0.667   0.800
1741                1.0                             0.000   0.480   0.600
1742            }
1743        }
1744        "blue-to-brown" {
1745            return {
1746                0.0                             0.000   0.480   0.600
1747                0.09090909090909091             0.000   0.667   0.800
1748                0.18181818181818182             0.200   0.893   1.000
1749                0.2727272727272727              0.400   0.940   1.000
1750                0.36363636363636365             0.600   0.973   1.000
1751                0.45454545454545453             0.800   0.993   1.000
1752                0.5454545454545454              0.950   0.855   0.808
1753                0.6363636363636364              0.850   0.688   0.595
1754                0.7272727272727273              0.800   0.608   0.480
1755                0.8181818181818182              0.600   0.379   0.210
1756                0.9090909090909091              0.400   0.187   0.000
1757                1.0                             0.200   0.100   0.000
1758            }
1759        }
1760        "blue-to-orange" {
1761            return {
1762                0.0                             0.000   0.167   1.000
1763                0.09090909090909091             0.100   0.400   1.000
1764                0.18181818181818182             0.200   0.600   1.000
1765                0.2727272727272727              0.400   0.800   1.000
1766                0.36363636363636365             0.600   0.933   1.000
1767                0.45454545454545453             0.800   1.000   1.000
1768                0.5454545454545454              1.000   1.000   0.800
1769                0.6363636363636364              1.000   0.933   0.600
1770                0.7272727272727273              1.000   0.800   0.400
1771                0.8181818181818182              1.000   0.600   0.200
1772                0.9090909090909091              1.000   0.400   0.100
1773                1.0                             1.000   0.167   0.000
1774            }
1775        }
1776        "orange-to-blue" {
1777            return {
1778                0.0                             1.000   0.167   0.000
1779                0.09090909090909091             1.000   0.400   0.100
1780                0.18181818181818182             1.000   0.600   0.200
1781                0.2727272727272727              1.000   0.800   0.400
1782                0.36363636363636365             1.000   0.933   0.600
1783                0.45454545454545453             1.000   1.000   0.800
1784                0.5454545454545454              0.800   1.000   1.000
1785                0.6363636363636364              0.600   0.933   1.000
1786                0.7272727272727273              0.400   0.800   1.000
1787                0.8181818181818182              0.200   0.600   1.000
1788                0.9090909090909091              0.100   0.400   1.000
1789                1.0                             0.000   0.167   1.000
1790            }
1791        }
1792        "rainbow" {
1793            set clist {
1794                "#EE82EE"
1795                "#4B0082"
1796                "blue"
1797                "#008000"
1798                "yellow"
1799                "#FFA500"
1800                "red"
1801            }
1802        }
1803        "BGYOR" {
1804            set clist {
1805                "blue"
1806                "#008000"
1807                "yellow"
1808                "#FFA500"
1809                "red"
1810            }
1811        }
1812        "ROYGB" {
1813            set clist {
1814                "red"
1815                "#FFA500"
1816                "yellow"
1817                "#008000"
1818                "blue"
1819            }
1820        }
1821        "RYGCB" {
1822            set clist {
1823                "red"
1824                "yellow"
1825                "green"
1826                "cyan"
1827                "blue"
1828            }
1829        }
1830        "BCGYR" {
1831            set clist {
1832                "blue"
1833                "cyan"
1834                "green"
1835                "yellow"
1836                "red"
1837            }
1838        }
1839        "spectral" {
1840            return {
1841                0.0 0.150 0.300 1.000
1842                0.1 0.250 0.630 1.000
1843                0.2 0.450 0.850 1.000
1844                0.3 0.670 0.970 1.000
1845                0.4 0.880 1.000 1.000
1846                0.5 1.000 1.000 0.750
1847                0.6 1.000 0.880 0.600
1848                0.7 1.000 0.680 0.450
1849                0.8 0.970 0.430 0.370
1850                0.9 0.850 0.150 0.196
1851                1.0 0.650 0.000 0.130
1852            }
1853        }
1854        "green-to-magenta" {
1855            return {
1856                0.0 0.000 0.316 0.000
1857                0.06666666666666667 0.000 0.526 0.000
1858                0.13333333333333333 0.000 0.737 0.000
1859                0.2 0.000 0.947 0.000
1860                0.26666666666666666 0.316 1.000 0.316
1861                0.3333333333333333 0.526 1.000 0.526
1862                0.4 0.737 1.000 0.737
1863                0.4666666666666667 1.000 1.000 1.000
1864                0.5333333333333333 1.000 0.947 1.000
1865                0.6 1.000 0.737 1.000
1866                0.6666666666666666 1.000 0.526 1.000
1867                0.7333333333333333 1.000 0.316 1.000
1868                0.8 0.947 0.000 0.947
1869                0.8666666666666667 0.737 0.000 0.737
1870                0.9333333333333333 0.526 0.000 0.526
1871                1.0 0.316 0.000 0.316
1872            }
1873        }
1874        "greyscale" {
1875            return {
1876                0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0
1877            }
1878        }
1879        "nanohub" {
1880            set clist "white yellow green cyan blue magenta"
1881        }
1882        default {
1883            set clist $colors
1884        }
1885    }
1886    set cmap {}
1887    for {set i 0} {$i < [llength $clist]} {incr i} {
1888        set x [expr {double($i)/([llength $clist]-1)}]
1889        set color [lindex $clist $i]
1890        append cmap "$x [Color2RGB $color] "
1891    }
1892    return $cmap
1893}
1894
1895#
1896# BuildColormap --
1897#
1898itcl::body Rappture::VtkHeightmapViewer::BuildColormap { name stylelist } {
1899    array set style $stylelist
1900    set cmap [ColorsToColormap $style(-color)]
1901    if { [llength $cmap] == 0 } {
1902        set cmap "0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0"
1903    }
1904    if { ![info exists _settings(contour-opacity)] } {
1905        set _settings(contour-opacity) $style(-opacity)
1906    }
1907    set max $_settings(contour-opacity)
1908
1909    set wmap "0.0 1.0 1.0 1.0"
1910    SendCmd "colormap add $name { $cmap } { $wmap }"
1911}
1912
1913# ----------------------------------------------------------------------
1914# CONFIGURATION OPTION: -mode
1915# ----------------------------------------------------------------------
1916itcl::configbody Rappture::VtkHeightmapViewer::mode {
1917    switch -- $itk_option(-mode) {
1918        "heightmap" {
1919            set _settings(isHeightmap) 1
1920        }
1921        "contour" {
1922            set _settings(isHeightmap) 0
1923        }
1924        default {
1925            error "unknown mode settings \"$itk_option(-mode)\""
1926        }
1927    }
1928    AdjustSetting isHeightmap
1929}
1930
1931# ----------------------------------------------------------------------
1932# CONFIGURATION OPTION: -plotbackground
1933# ----------------------------------------------------------------------
1934itcl::configbody Rappture::VtkHeightmapViewer::plotbackground {
1935    if { [isconnected] } {
1936        SendCmd "screen bgcolor [Color2RGB $itk_option(-plotbackground)]"
1937        $itk_component(view) configure -background $itk_option(-plotbackground)
1938    }
1939}
1940
1941# ----------------------------------------------------------------------
1942# CONFIGURATION OPTION: -plotforeground
1943# ----------------------------------------------------------------------
1944itcl::configbody Rappture::VtkHeightmapViewer::plotforeground {
1945    if { [isconnected] } {
1946        SendCmd "axis color all [Color2RGB $itk_option(-plotforeground)]"
1947    }
1948}
1949
1950itcl::body Rappture::VtkHeightmapViewer::limits { dataobj } {
1951    foreach { limits(xmin) limits(xmax) } [$dataobj limits x] break
1952    foreach { limits(ymin) limits(ymax) } [$dataobj limits y] break
1953    foreach { limits(zmin) limits(zmax) } [$dataobj limits v] break
1954    return [array get limits]
1955}
1956
1957itcl::body Rappture::VtkHeightmapViewer::BuildContourTab {} {
1958
1959    set fg [option get $itk_component(hull) font Font]
1960    #set bfg [option get $itk_component(hull) boldFont Font]
1961
1962    set inner [$itk_component(main) insert end \
1963        -title "Contour Settings" \
1964        -icon [Rappture::icon volume-on]]
1965    $inner configure -borderwidth 4
1966
1967    checkbutton $inner.legend \
1968        -text "Legend" \
1969        -variable [itcl::scope _settings(legendVisible)] \
1970        -command [itcl::code $this AdjustSetting legendVisible] \
1971        -font "Arial 9"
1972
1973    checkbutton $inner.wireframe \
1974        -text "Wireframe" \
1975        -variable [itcl::scope _settings(wireframe)] \
1976        -command [itcl::code $this AdjustSetting wireframe] \
1977        -font "Arial 9"
1978
1979    itk_component add lighting {
1980        checkbutton $inner.lighting \
1981            -text "Enable Lighting" \
1982            -variable [itcl::scope _settings(lighting)] \
1983            -command [itcl::code $this AdjustSetting lighting] \
1984            -font "Arial 9"
1985    } {
1986        ignore -font
1987    }
1988
1989    checkbutton $inner.edges \
1990        -text "Edges" \
1991        -variable [itcl::scope _settings(edges)] \
1992        -command [itcl::code $this AdjustSetting edges] \
1993        -font "Arial 9"
1994
1995    checkbutton $inner.outline \
1996        -text "Outline" \
1997        -variable [itcl::scope _settings(outline)] \
1998        -command [itcl::code $this AdjustSetting outline] \
1999        -font "Arial 9"
2000
2001    checkbutton $inner.stretch \
2002        -text "Stretch to fit" \
2003        -variable [itcl::scope _settings(stretchToFit)] \
2004        -command [itcl::code $this AdjustSetting stretchToFit] \
2005        -font "Arial 9"
2006
2007    label $inner.field_l -text "Field" -font "Arial 9"
2008    itk_component add field {
2009        Rappture::Combobox $inner.field -width 10 -editable no
2010    }
2011    bind $inner.field <<Value>> \
2012        [itcl::code $this AdjustSetting field]
2013
2014    label $inner.colormap_l -text "Colormap" -font "Arial 9"
2015    itk_component add colormap {
2016        Rappture::Combobox $inner.colormap -width 10 -editable no
2017    }
2018    $inner.colormap choices insert end \
2019        "BCGYR"              "BCGYR"            \
2020        "BGYOR"              "BGYOR"            \
2021        "blue"               "blue"             \
2022        "blue-to-brown"      "blue-to-brown"    \
2023        "blue-to-orange"     "blue-to-orange"   \
2024        "blue-to-grey"       "blue-to-grey"     \
2025        "green-to-magenta"   "green-to-magenta" \
2026        "greyscale"          "greyscale"        \
2027        "nanohub"            "nanohub"          \
2028        "rainbow"            "rainbow"          \
2029        "spectral"           "spectral"         \
2030        "ROYGB"              "ROYGB"            \
2031        "RYGCB"              "RYGCB"            \
2032        "brown-to-blue"      "brown-to-blue"    \
2033        "grey-to-blue"       "grey-to-blue"     \
2034        "orange-to-blue"     "orange-to-blue"   \
2035        "none"               "none"
2036
2037    $itk_component(colormap) value "BCGYR"
2038    bind $inner.colormap <<Value>> \
2039        [itcl::code $this AdjustSetting colormap]
2040
2041    label $inner.isolinecolor_l -text "Isolines" -font "Arial 9"
2042    itk_component add isolinecolor {
2043        Rappture::Combobox $inner.isolinecolor -width 10 -editable no
2044    }
2045    $inner.isolinecolor choices insert end \
2046        "black"              "black"            \
2047        "blue"               "blue"             \
2048        "cyan"               "cyan"             \
2049        "green"              "green"            \
2050        "grey"               "grey"             \
2051        "magenta"            "magenta"          \
2052        "orange"             "orange"           \
2053        "red"                "red"              \
2054        "white"              "white"            \
2055        "none"               "none"
2056
2057    $itk_component(isolinecolor) value "red"
2058    bind $inner.isolinecolor <<Value>> \
2059        [itcl::code $this AdjustSetting isoline-color]
2060
2061    label $inner.background_l -text "Background" -font "Arial 9"
2062    itk_component add background {
2063        Rappture::Combobox $inner.background -width 10 -editable no
2064    }
2065    $inner.background choices insert end \
2066        "black"              "black"            \
2067        "white"              "white"            \
2068        "grey"               "grey"             
2069
2070    $itk_component(background) value "white"
2071    bind $inner.background <<Value>> [itcl::code $this AdjustSetting background]
2072
2073    label $inner.opacity_l -text "Opacity" -font "Arial 9"
2074    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
2075        -variable [itcl::scope _settings(contour-opacity)] \
2076        -width 10 \
2077        -showvalue off \
2078        -command [itcl::code $this AdjustSetting contour-opacity]
2079
2080    label $inner.scale_l -text "Scale" -font "Arial 9"
2081    ::scale $inner.scale -from 0 -to 100 -orient horizontal \
2082        -variable [itcl::scope _settings(heightmap-scale)] \
2083        -width 10 \
2084        -showvalue off \
2085        -command [itcl::code $this AdjustSetting heightmap-scale]
2086
2087    blt::table $inner \
2088        0,0 $inner.colormap_l -anchor w -pady 2  \
2089        0,1 $inner.colormap   -anchor w -pady 2 -fill x  \
2090        1,0 $inner.isolinecolor_l  -anchor w -pady 2  \
2091        1,1 $inner.isolinecolor    -anchor w -pady 2 -fill x  \
2092        2,0 $inner.background_l -anchor w -pady 2 \
2093        2,1 $inner.background -anchor w -pady 2  -fill x \
2094        4,0 $inner.legend     -anchor w -pady 2 -cspan 2 \
2095        5,0 $inner.wireframe  -anchor w -pady 2 -cspan 2\
2096        6,0 $inner.lighting   -anchor w -pady 2 -cspan 2 \
2097        7,0 $inner.edges      -anchor w -pady 2 -cspan 2 \
2098        8,0 $inner.legend     -anchor w -pady 2 -cspan 2 \
2099        9,0 $inner.stretch    -anchor w -pady 2 -cspan 2 \
2100        10,0 $inner.outline    -anchor w -pady 2 -cspan 2 \
2101        11,0 $inner.opacity_l -anchor w -pady 2 \
2102        11,1 $inner.opacity   -fill x   -pady 2 \
2103        12,0 $inner.scale_l   -anchor w -pady 2 -cspan 2 \
2104        12,1 $inner.scale     -fill x   -pady 2 -cspan 2 \
2105
2106    if { [array size _fields] > 1 } {
2107        blt::table $inner \
2108            3,0 $inner.field_l   -anchor w -pady 2 \
2109            3,1 $inner.field     -anchor w -pady 2 -fill x
2110    }
2111    blt::table configure $inner r* c* -resize none
2112    blt::table configure $inner r13 c1 -resize expand
2113}
2114
2115itcl::body Rappture::VtkHeightmapViewer::BuildAxisTab {} {
2116
2117    set fg [option get $itk_component(hull) font Font]
2118    #set bfg [option get $itk_component(hull) boldFont Font]
2119
2120    set inner [$itk_component(main) insert end \
2121        -title "Axis Settings" \
2122        -icon [Rappture::icon axis1]]
2123    $inner configure -borderwidth 4
2124
2125    checkbutton $inner.visible \
2126        -text "Axes" \
2127        -variable [itcl::scope _settings(axis-visible)] \
2128        -command [itcl::code $this AdjustSetting axis-visible] \
2129        -font "Arial 9"
2130    checkbutton $inner.labels \
2131        -text "Axis Labels" \
2132        -variable [itcl::scope _settings(axisLabels)] \
2133        -command [itcl::code $this AdjustSetting axisLabels] \
2134        -font "Arial 9"
2135    label $inner.grid_l -text "Grid" -font "Arial 9"
2136    checkbutton $inner.gridx \
2137        -text "X" \
2138        -variable [itcl::scope _settings(axis-xgrid)] \
2139        -command [itcl::code $this AdjustSetting axis-xgrid] \
2140        -font "Arial 9"
2141    checkbutton $inner.gridy \
2142        -text "Y" \
2143        -variable [itcl::scope _settings(axis-ygrid)] \
2144        -command [itcl::code $this AdjustSetting axis-ygrid] \
2145        -font "Arial 9"
2146    checkbutton $inner.gridz \
2147        -text "Z" \
2148        -variable [itcl::scope _settings(axis-zgrid)] \
2149        -command [itcl::code $this AdjustSetting axis-zgrid] \
2150        -font "Arial 9"
2151    checkbutton $inner.minorticks \
2152        -text "Minor Ticks" \
2153        -variable [itcl::scope _settings(axis-minticks)] \
2154        -command [itcl::code $this AdjustSetting axis-minticks] \
2155        -font "Arial 9"
2156
2157
2158    label $inner.mode_l -text "Mode" -font "Arial 9"
2159
2160    itk_component add axis-flymode {
2161        Rappture::Combobox $inner.mode -width 10 -editable no
2162    }
2163    $inner.mode choices insert end \
2164        "static_triad"    "static" \
2165        "closest_triad"   "closest" \
2166        "furthest_triad"  "furthest" \
2167        "outer_edges"     "outer"         
2168    $itk_component(axis-flymode) value "static"
2169    bind $inner.mode <<Value>> [itcl::code $this AdjustSetting axis-flymode]
2170
2171    blt::table $inner \
2172        0,0 $inner.visible -anchor w -cspan 4 \
2173        1,0 $inner.labels  -anchor w -cspan 4 \
2174        2,0 $inner.minorticks  -anchor w -cspan 4 \
2175        4,0 $inner.grid_l  -anchor w \
2176        4,1 $inner.gridx   -anchor w \
2177        4,2 $inner.gridy   -anchor w \
2178        4,3 $inner.gridz   -anchor w \
2179        5,0 $inner.mode_l  -anchor w -padx { 2 0 } \
2180        5,1 $inner.mode    -fill x -cspan 3
2181
2182    blt::table configure $inner r* c* -resize none
2183    blt::table configure $inner r7 c6 -resize expand
2184    blt::table configure $inner r3 -height 0.125i
2185}
2186
2187
2188itcl::body Rappture::VtkHeightmapViewer::BuildCameraTab {} {
2189    set inner [$itk_component(main) insert end \
2190        -title "Camera Settings" \
2191        -icon [Rappture::icon camera]]
2192    $inner configure -borderwidth 4
2193
2194    set labels { qx qy qz qw xpan ypan zoom }
2195    set row 0
2196    foreach tag $labels {
2197        label $inner.${tag}label -text $tag -font "Arial 9"
2198        entry $inner.${tag} -font "Arial 9"  -bg white \
2199            -textvariable [itcl::scope _view($tag)]
2200        bind $inner.${tag} <KeyPress-Return> \
2201            [itcl::code $this camera set ${tag}]
2202        blt::table $inner \
2203            $row,0 $inner.${tag}label -anchor e -pady 2 \
2204            $row,1 $inner.${tag} -anchor w -pady 2
2205        blt::table configure $inner r$row -resize none
2206        incr row
2207    }
2208    checkbutton $inner.ortho \
2209        -text "Orthographic Projection" \
2210        -variable [itcl::scope _view(ortho)] \
2211        -command [itcl::code $this camera set ortho] \
2212        -font "Arial 9"
2213    blt::table $inner \
2214            $row,0 $inner.ortho -columnspan 2 -anchor w -pady 2
2215    blt::table configure $inner r$row -resize none
2216    incr row
2217
2218    blt::table configure $inner c0 c1 -resize none
2219    blt::table configure $inner c2 -resize expand
2220    blt::table configure $inner r$row -resize expand
2221}
2222
2223#
2224#  camera --
2225#
2226itcl::body Rappture::VtkHeightmapViewer::camera {option args} {
2227    switch -- $option {
2228        "show" {
2229            puts [array get _view]
2230        }
2231        "set" {
2232            set who [lindex $args 0]
2233            set x $_view($who)
2234            set code [catch { string is double $x } result]
2235            if { $code != 0 || !$result } {
2236                return
2237            }
2238            switch -- $who {
2239                "ortho" {
2240                    if {$_view(ortho)} {
2241                        SendCmd "camera mode ortho"
2242                    } else {
2243                        SendCmd "camera mode persp"
2244                    }
2245                }
2246                "xpan" - "ypan" {
2247                    PanCamera
2248                }
2249                "qx" - "qy" - "qz" - "qw" {
2250                    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
2251                    $_arcball quaternion $q
2252                    EventuallyRotate $q
2253                }
2254                "zoom" {
2255                    SendCmd "camera zoom $_view(zoom)"
2256                }
2257            }
2258        }
2259    }
2260}
2261
2262itcl::body Rappture::VtkHeightmapViewer::GetVtkData { args } {
2263    set bytes ""
2264    foreach dataobj [get] {
2265        foreach comp [$dataobj components] {
2266            set tag $dataobj-$comp
2267            set contents [ConvertToVtkData $dataobj $comp]
2268            #set contents [$dataobj vtkdata $comp]
2269            append bytes "$contents\n\n"
2270        }
2271    }
2272    return [list .vtk $bytes]
2273}
2274
2275itcl::body Rappture::VtkHeightmapViewer::GetImage { args } {
2276    if { [image width $_image(download)] > 0 &&
2277         [image height $_image(download)] > 0 } {
2278        set bytes [$_image(download) data -format "jpeg -quality 100"]
2279        set bytes [Rappture::encoding::decode -as b64 $bytes]
2280        return [list .jpg $bytes]
2281    }
2282    return ""
2283}
2284
2285itcl::body Rappture::VtkHeightmapViewer::BuildDownloadPopup { popup command } {
2286    Rappture::Balloon $popup \
2287        -title "[Rappture::filexfer::label downloadWord] as..."
2288    set inner [$popup component inner]
2289    label $inner.summary -text "" -anchor w
2290    radiobutton $inner.vtk_button -text "VTK data file" \
2291        -variable [itcl::scope _downloadPopup(format)] \
2292        -font "Arial 9 " \
2293        -value vtk 
2294    Rappture::Tooltip::for $inner.vtk_button "Save as VTK data file."
2295    radiobutton $inner.image_button -text "Image File" \
2296        -variable [itcl::scope _downloadPopup(format)] \
2297        -font "Arial 9 " \
2298        -value image
2299    Rappture::Tooltip::for $inner.image_button \
2300        "Save as digital image."
2301
2302    button $inner.ok -text "Save" \
2303        -highlightthickness 0 -pady 2 -padx 3 \
2304        -command $command \
2305        -compound left \
2306        -image [Rappture::icon download]
2307
2308    button $inner.cancel -text "Cancel" \
2309        -highlightthickness 0 -pady 2 -padx 3 \
2310        -command [list $popup deactivate] \
2311        -compound left \
2312        -image [Rappture::icon cancel]
2313
2314    blt::table $inner \
2315        0,0 $inner.summary -cspan 2  \
2316        1,0 $inner.vtk_button -anchor w -cspan 2 -padx { 4 0 } \
2317        2,0 $inner.image_button -anchor w -cspan 2 -padx { 4 0 } \
2318        4,1 $inner.cancel -width .9i -fill y \
2319        4,0 $inner.ok -padx 2 -width .9i -fill y
2320    blt::table configure $inner r3 -height 4
2321    blt::table configure $inner r4 -pady 4
2322    raise $inner.image_button
2323    $inner.vtk_button invoke
2324    return $inner
2325}
2326
2327itcl::body Rappture::VtkHeightmapViewer::SetObjectStyle { dataobj comp } {
2328    # Parse style string.
2329    set tag $dataobj-$comp
2330    array set style {
2331        -color BCGYR
2332        -edges 0
2333        -edgecolor black
2334        -lighting 1
2335        -linewidth 1.0
2336        -levels 10
2337        -visible 1
2338    }
2339    if { $_currentColormap == "" } {
2340        set stylelist [$dataobj style $comp]
2341        if { $stylelist != "" } {
2342            array set style $stylelist
2343            set stylelist [array get style]
2344            SetCurrentColormap $stylelist
2345        }
2346        $itk_component(colormap) value $style(-color)
2347    }
2348    set _numContours $style(-levels)
2349    set scale [GetHeightmapScale]
2350    SendCmd "heightmap add numcontours $_numContours $scale $tag"
2351    set _comp2scale($tag) $_settings(heightmap-scale)
2352    SendCmd "heightmap edges $_settings(edges) $tag"
2353    SendCmd "heightmap wireframe $_settings(wireframe) $tag"
2354    SendCmd "heightmap colormap $_currentColormap $tag"
2355}
2356
2357itcl::body Rappture::VtkHeightmapViewer::IsValidObject { dataobj } {
2358    if {[catch {$dataobj isa Rappture::Field} valid] != 0 || !$valid} {
2359        return 0
2360    }
2361    return 1
2362}
2363
2364# ----------------------------------------------------------------------
2365# USAGE: ReceiveLegend <colormap> <title> <min> <max> <size>
2366#
2367# Invoked automatically whenever the "legend" command comes in from
2368# the rendering server.  Indicates that binary image data with the
2369# specified <size> will follow.
2370# ----------------------------------------------------------------------
2371itcl::body Rappture::VtkHeightmapViewer::ReceiveLegend { colormap title min max size } {
2372    #puts stderr "ReceiveLegend colormap=$colormap title=$title range=$min,$max size=$size"
2373    set _title $title
2374    regsub {\(mag\)} $title "" _title
2375    if { [IsConnected] } {
2376        set bytes [ReceiveBytes $size]
2377        if { ![info exists _image(legend)] } {
2378            set _image(legend) [image create photo]
2379        }
2380        $_image(legend) configure -data $bytes
2381        #puts stderr "read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
2382        if { [catch {DrawLegend $_title} errs] != 0 } {
2383            global errorInfo
2384            puts stderr "errs=$errs errorInfo=$errorInfo"
2385        }
2386    }
2387}
2388
2389#
2390# DrawLegend --
2391#
2392#       Draws the legend in it's own canvas which resides to the right
2393#       of the contour plot area.
2394#
2395itcl::body Rappture::VtkHeightmapViewer::DrawLegend { name } {
2396    set c $itk_component(view)
2397    set w [winfo width $c]
2398    set h [winfo height $c]
2399    set font "Arial 8"
2400    set lineht [font metrics $font -linespace]
2401   
2402    if { $name == "component" } {
2403        set title ""
2404    } else {
2405        if { [info exists _fields($name)] } {
2406            foreach { title units } $_fields($name) break
2407            if { $units != "" } {
2408                set title [format "%s (%s)" $title $units]
2409            }
2410        } else {
2411            set title $name
2412        }
2413    }
2414    set x [expr $w - 2]
2415    if { !$_settings(legendVisible) } {
2416        $c delete legend
2417        return
2418    }
2419    if { [$c find withtag "legend"] == "" } {
2420        set y 2
2421        # If there's a legend title, create a text item for the title.
2422        if { $title != "" } {
2423            $c create text $x $y \
2424                -anchor ne \
2425                -fill $itk_option(-plotforeground) -tags "title legend" \
2426                -font $font
2427            incr y $lineht
2428        }
2429        $c create text $x $y \
2430            -anchor ne \
2431            -fill $itk_option(-plotforeground) -tags "zmax legend" \
2432            -font $font
2433        incr y $lineht
2434        $c create image $x $y \
2435            -anchor ne \
2436            -image $_image(legend) -tags "colormap legend"
2437        $c create text $x [expr {$h-2}] \
2438            -anchor se \
2439            -fill $itk_option(-plotforeground) -tags "zmin legend" \
2440            -font $font
2441        #$c bind colormap <Enter> [itcl::code $this EnterLegend %x %y]
2442        $c bind colormap <Leave> [itcl::code $this LeaveLegend]
2443        $c bind colormap <Motion> [itcl::code $this MotionLegend %x %y]
2444    }
2445    $c delete isoline
2446    set x2 $x
2447    set iw [image width $_image(legend)]
2448    set ih [image height $_image(legend)]
2449    set x1 [expr $x2 - ($iw*12)/10]
2450    set color [$itk_component(isolinecolor) value]
2451    # Draw the isolines on the legend.
2452    if { $color != "none"  && $_numContours > 0 } {
2453        set pixels [blt::vector create \#auto]
2454        set values [blt::vector create \#auto]
2455        set range [image height $_image(legend)]
2456        # Order of pixels is max to min (max is at top of legend).
2457        $pixels seq $ih 0 $_numContours
2458        set offset [expr 2 + $lineht]
2459        # If there's a legend title, increase the offset by the line height.
2460        if { $title != "" } {
2461            incr offset $lineht
2462        }
2463        $pixels expr {round($pixels + $offset)}
2464        # Order of values is min to max.
2465        $values seq $_limits(zmin) $_limits(zmax) $_numContours
2466        set tags "isoline legend"
2467        foreach pos [$pixels range 0 end] value [$values range end 0] {
2468            set y1 [expr int($pos)]
2469            set id [$c create line $x1 $y1 $x2 $y1 -fill $color -tags $tags]
2470            $c bind $id <Enter> [itcl::code $this EnterIsoline %x %y $value]
2471            $c bind $id <Leave> [itcl::code $this LeaveIsoline]
2472        }
2473        blt::vector destroy $pixels $values
2474    }
2475
2476    $c bind title <ButtonPress> [itcl::code $this Combo post]
2477    $c bind title <Enter> [itcl::code $this Combo activate]
2478    $c bind title <Leave> [itcl::code $this Combo deactivate]
2479    # Reset the item coordinates according the current size of the plot.
2480    $c itemconfigure title -text $title
2481    if { [info exists _limits(zmin)] && $_limits(zmin) != "" } {
2482        $c itemconfigure zmin -text [format %g $_limits(zmin)]
2483    }
2484    if { [info exists _limits(zmax)] && $_limits(zmax) != "" } {
2485        $c itemconfigure zmax -text [format %g $_limits(zmax)]
2486    }
2487    set y 2
2488    # If there's a legend title, move the title to the correct position
2489    if { $title != "" } {
2490        $c coords title $x $y
2491        incr y $lineht
2492    }
2493    $c coords zmax $x $y
2494    incr y $lineht
2495    $c coords colormap $x $y
2496    $c coords zmin $x [expr {$h - 2}]
2497}
2498
2499#
2500# EnterIsoline --
2501#
2502itcl::body Rappture::VtkHeightmapViewer::EnterIsoline { x y value } {
2503    SetIsolineTip $x $y $value
2504}
2505
2506#
2507# LeaveIsoline --
2508#
2509itcl::body Rappture::VtkHeightmapViewer::LeaveIsoline { } {
2510    Rappture::Tooltip::tooltip cancel
2511    .rappturetooltip configure -icon ""
2512}
2513
2514#
2515# SetIsolineTip --
2516#
2517itcl::body Rappture::VtkHeightmapViewer::SetIsolineTip { x y value } {
2518    set c $itk_component(view)
2519    set w [winfo width $c]
2520    set h [winfo height $c]
2521    set font "Arial 8"
2522    set lineht [font metrics $font -linespace]
2523   
2524    if { [info exists _fields($_title)] } {
2525        foreach { title units } $_fields($_title) break
2526        if { $units != "" } {
2527            set title [format "%s (%s)" $title $units]
2528        }
2529    } else {
2530        set title $_title
2531    }
2532    set imgHeight [image height $_image(legend)]
2533    set coords [$c coords colormap]
2534    set imgX [expr $w - [image width $_image(legend)] - 2]
2535    set imgY [expr $y - 2 * ($lineht + 2)]
2536
2537    .rappturetooltip configure -icon ""
2538
2539    # Compute the value of the point
2540    set tipx [expr $x + 15]
2541    set tipy [expr $y - 5]
2542    Rappture::Tooltip::text $c "Isoline $value"
2543    Rappture::Tooltip::tooltip show $c +$tipx,+$tipy   
2544}
2545
2546
2547#
2548# EnterLegend --
2549#
2550itcl::body Rappture::VtkHeightmapViewer::EnterLegend { x y } {
2551    SetLegendTip $x $y
2552}
2553
2554#
2555# MotionLegend --
2556#
2557itcl::body Rappture::VtkHeightmapViewer::MotionLegend { x y } {
2558    Rappture::Tooltip::tooltip cancel
2559    set c $itk_component(view)
2560    SetLegendTip $x $y
2561}
2562
2563#
2564# LeaveLegend --
2565#
2566itcl::body Rappture::VtkHeightmapViewer::LeaveLegend { } {
2567    Rappture::Tooltip::tooltip cancel
2568    .rappturetooltip configure -icon ""
2569}
2570
2571#
2572# SetLegendTip --
2573#
2574itcl::body Rappture::VtkHeightmapViewer::SetLegendTip { x y } {
2575    set c $itk_component(view)
2576    set w [winfo width $c]
2577    set h [winfo height $c]
2578    set font "Arial 8"
2579    set lineht [font metrics $font -linespace]
2580   
2581    set imgHeight [image height $_image(legend)]
2582    set coords [$c coords colormap]
2583    set imgX [expr $w - [image width $_image(legend)] - 2]
2584    set imgY [expr $y - 2 * ($lineht + 2)]
2585
2586    if { [info exists _fields($_title)] } {
2587        foreach { title units } $_fields($_title) break
2588        if { $units != "" } {
2589            set title [format "%s (%s)" $title $units]
2590        }
2591    } else {
2592        set title $_title
2593    }
2594    # Make a swatch of the selected color
2595    if { [catch { $_image(legend) get 10 $imgY } pixel] != 0 } {
2596        #puts stderr "out of range: $imgY"
2597        return
2598    }
2599    if { ![info exists _image(swatch)] } {
2600        set _image(swatch) [image create photo -width 24 -height 24]
2601    }
2602    set color [eval format "\#%02x%02x%02x" $pixel]
2603    $_image(swatch) put black  -to 0 0 23 23
2604    $_image(swatch) put $color -to 1 1 22 22
2605    .rappturetooltip configure -icon $_image(swatch)
2606
2607    # Compute the value of the point
2608    if { [info exists _limits(zmax)] && [info exists _limits(zmin)] } {
2609        set t [expr 1.0 - (double($imgY) / double($imgHeight-1))]
2610        set value [expr $t * ($_limits(zmax) - $_limits(zmin)) + $_limits(zmin)]
2611    } else {
2612        set value 0.0
2613    }
2614    set tipx [expr $x + 15]
2615    set tipy [expr $y - 5]
2616    Rappture::Tooltip::text $c "$title $value"
2617    Rappture::Tooltip::tooltip show $c +$tipx,+$tipy   
2618}
2619
2620# ----------------------------------------------------------------------
2621# USAGE: _dropdown post
2622# USAGE: _dropdown unpost
2623# USAGE: _dropdown select
2624#
2625# Used internally to handle the dropdown list for this combobox.  The
2626# post/unpost options are invoked when the list is posted or unposted
2627# to manage the relief of the controlling button.  The select option
2628# is invoked whenever there is a selection from the list, to assign
2629# the value back to the gauge.
2630# ----------------------------------------------------------------------
2631itcl::body Rappture::VtkHeightmapViewer::Combo {option} {
2632    set c $itk_component(view)
2633    switch -- $option {
2634        post {
2635            foreach { x1 y1 x2 y2 } [$c bbox title] break
2636            set x1 [expr [winfo width $itk_component(view)] - [winfo reqwidth $itk_component(fieldmenu)]]
2637            set x [expr $x1 + [winfo rootx $itk_component(view)]]
2638            set y [expr $y2 + [winfo rooty $itk_component(view)]]
2639            tk_popup $itk_component(fieldmenu) $x $y
2640        }
2641        activate {
2642            $c itemconfigure title -fill red
2643        }
2644        deactivate {
2645            $c itemconfigure title -fill $itk_option(-plotforeground)
2646        }
2647        invoke {
2648            $itk_component(field) value $_currentFieldName
2649            AdjustSetting field
2650        }
2651        default {
2652            error "bad option \"$option\": should be post, unpost, select"
2653        }
2654    }
2655}
2656
2657itcl::body Rappture::VtkHeightmapViewer::GetHeightmapScale {} {
2658    if {  $_settings(isHeightmap) } {
2659        set val $_settings(heightmap-scale)
2660        set sval [expr { $val >= 50 ? double($val)/50.0 : 1.0/(2.0-(double($val)/50.0)) }]
2661        return $sval
2662    }
2663    set sval 0
2664}
2665
2666itcl::body Rappture::VtkHeightmapViewer::ResetColormap { color } {
2667    array set style {
2668        -color BCGYR
2669        -levels 10
2670        -opacity 1.0
2671    }
2672    if { [info exists _colormap($_currentColormap)] } {
2673        array set style $_colormap($_currentColormap)
2674    }
2675    set style(-color) $color
2676    SetCurrentColormap [array get style]
2677}
2678
Note: See TracBrowser for help on using the repository browser.