source: trunk/gui/scripts/vtkviewer.tcl @ 3668

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

fix vtkviewer to add object type on creation

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