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