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

Last change on this file since 3421 was 3421, checked in by gah, 11 years ago

push SendCmd? into base class w/ buffering

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