source: trunk/gui/scripts/vtkglyphviewer.tcl @ 5092

Last change on this file since 5092 was 5092, checked in by ldelgass, 9 years ago

Add update in Rebuild to allow initial canvas size to be set. We don't want to
do this in the constructor since that can cause an error when the add method is
called before the constructor returns.

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