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

Last change on this file since 3623 was 3623, checked in by ldelgass, 11 years ago

Use contour list in heightmap viewer to remove min/max isolines.

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