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

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

fix up stats reporting in servers

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