source: trunk/gui/scripts/vtkheightmapviewer.tcl @ 3498

Last change on this file since 3498 was 3498, checked in by ldelgass, 12 years ago

Delay Rebuild until window size larger than 1x1 - copying this code from
VTK viewers to nanovis viewers. Helps get proper aspect for initial camera
reset. There is still a problem with the updir coming too late (needs to come
before camera reset).

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