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

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

These was are all related to the omenwire example.

o Added validity test for fields, meshes, clouds, and unirect2ds. There is

now a "isvalid" method that viewers should use to verify that the data object
can be plotted.

In some cases with fields this means that the widget won't even be created.
The resultviewer tests for the dimensionality which is by default 0.

o Thanks to Leif for pointing this out, it's not enough to check if the field

is valid. Individual components of the field may be invalid. Added check so
that viewers are never passed the names of invalid field components.

o Changed many "error" commands to just print to stderr and tolerantly deal

with the error.

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