source: trunk/gui/scripts/vtkisosurfaceviewer.tcl @ 3966

Last change on this file since 3966 was 3966, checked in by ldelgass, 11 years ago

Allow overriding viewer for DICOM (with about.view), fixes for styles in
isosurface viewer. Also, make isosurface opaque if there is only one level
as translucency is expensive to render.

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