source: branches/1.7/gui/scripts/vtkisosurfaceviewer.tcl @ 6238

Last change on this file since 6238 was 6238, checked in by ldelgass, 6 years ago

merge r6235:6236 from trunk (streamlines scaling)

File size: 110.3 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: vtkisosurfaceviewer - Vtk 3D contour object viewer
4#
5#  It connects to the Vtkvis server running on a rendering farm,
6#  transmits data, and displays the results.
7# ======================================================================
8#  AUTHOR:  Michael McLennan, Purdue University
9#  Copyright (c) 2004-2016  HUBzero Foundation, LLC
10#
11#  See the file "license.terms" for information on usage and
12#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13# ======================================================================
14package require Itk
15package require BLT
16#package require Img
17
18option add *VtkIsosurfaceViewer.width 4i widgetDefault
19option add *VtkIsosurfaceViewer*cursor crosshair widgetDefault
20option add *VtkIsosurfaceViewer.height 4i widgetDefault
21option add *VtkIsosurfaceViewer.foreground black widgetDefault
22option add *VtkIsosurfaceViewer.controlBackground gray widgetDefault
23option add *VtkIsosurfaceViewer.controlDarkBackground #999999 widgetDefault
24option add *VtkIsosurfaceViewer.plotBackground black widgetDefault
25option add *VtkIsosurfaceViewer.plotForeground white widgetDefault
26option add *VtkIsosurfaceViewer.font \
27    -*-helvetica-medium-r-normal-*-12-* widgetDefault
28
29# must use this name -- plugs into Rappture::resources::load
30proc VtkIsosurfaceViewer_init_resources {} {
31    Rappture::resources::register \
32        vtkvis_server Rappture::VtkIsosurfaceViewer::SetServerList
33}
34
35itcl::class Rappture::VtkIsosurfaceViewer {
36    inherit Rappture::VisViewer
37
38    itk_option define -plotforeground plotForeground Foreground ""
39    itk_option define -plotbackground plotBackground Background ""
40
41    constructor { args } {
42        Rappture::VisViewer::constructor
43    } {
44        # defined below
45    }
46    destructor {
47        # defined below
48    }
49    public proc SetServerList { namelist } {
50        Rappture::VisViewer::SetServerList "vtkvis" $namelist
51    }
52    public method add {dataobj {settings ""}}
53    public method camera {option args}
54    public method delete {args}
55    public method disconnect {}
56    public method download {option args}
57    public method get {args}
58    public method isconnected {}
59    public method parameters {title args} {
60        # do nothing
61    }
62    public method scale {args}
63
64    # The following methods are only used by this class.
65    private method AdjustSetting {what {value ""}}
66    private method BuildAxisTab {}
67    private method BuildCameraTab {}
68    private method BuildColormap { name }
69    private method BuildCutplanesTab {}
70    private method BuildDownloadPopup { widget command }
71    private method BuildIsosurfaceTab {}
72    private method Connect {}
73    private method CurrentDatasets {args}
74    private method DisableMouseRotationBindings {}
75    private method Disconnect {}
76    private method DoChangeContourLevels {}
77    private method DoResize {}
78    private method DoRotate {}
79    private method DrawLegend {}
80    private method EnterLegend { x y }
81    private method EventuallyChangeContourLevels {}
82    private method EventuallyRequestLegend {}
83    private method EventuallyResize { w h }
84    private method EventuallyRotate { q }
85    private method EventuallySetCutplane { axis args }
86    private method GenerateContourList {}
87    private method GetImage { args }
88    private method GetVtkData { args }
89    private method InitSettings { args }
90    private method IsValidObject { dataobj }
91    private method LeaveLegend {}
92    private method LegendB1Motion {status x y}
93    private method LegendPointToValue { x y }
94    private method LegendProbeSingleContour { x y }
95    private method LegendRangeAction { option args }
96    private method LegendRangeValidate { widget which value }
97    private method LegendTitleAction { option }
98    private method MotionLegend { x y }
99    private method MouseOver2Which {}
100    private method Pan {option x y}
101    private method PanCamera {}
102    private method Pick {x y}
103    private method QuaternionToView { q } {
104        foreach { _view(-qw) _view(-qx) _view(-qy) _view(-qz) } $q break
105    }
106    private method Rebuild {}
107    private method ReceiveDataset { args }
108    private method ReceiveImage { args }
109    private method ReceiveLegend { colormap title vmin vmax size }
110    private method RequestLegend {}
111    private method Rotate {option x y}
112    private method SetCurrentColormap { color }
113    private method SetCurrentFieldName { dataobj }
114    private method SetLegendTip { x y }
115    private method SetMinMaxGauges { min max }
116    private method SetObjectStyle { dataobj comp }
117    private method SetOrientation { side }
118    private method SetupKeyboardBindings {}
119    private method SetupMousePanningBindings {}
120    private method SetupMouseRotationBindings {}
121    private method SetupMouseZoomBindings {}
122    private method Slice {option args}
123    private method ToggleCustomRange { args }
124    private method ViewToQuaternion {} {
125        return [list $_view(-qw) $_view(-qx) $_view(-qy) $_view(-qz)]
126    }
127    private method Zoom {option}
128
129    private variable _arcball ""
130
131    private variable _dlist "";         # list of data objects
132    private variable _obj2ovride;       # maps dataobj => style override
133    private variable _datasets;         # contains all the dataobj-component
134                                        # datasets in the server
135    private variable _colormaps;        # contains all the colormaps
136                                        # in the server.
137    # The name of the current colormap used.  The colormap is global to all
138    # heightmaps displayed.
139    private variable _currentColormap ""
140    private variable _currentNumContours -1
141
142    private variable _click;            # info used for rotate operations
143    private variable _limits;           # autoscale min/max for all axes
144    private variable _view;             # view params for 3D view
145    private variable _settings
146    private variable _changed
147    private variable _reset 1;          # Connection to server has been reset.
148
149    private variable _first "";         # This is the topmost dataset.
150    private variable _start 0
151    private variable _title ""
152    private variable _isolines
153    private variable _contourList
154    private variable _currentLimits ""
155    private variable _widget
156    private variable _width 0
157    private variable _height 0
158    private variable _resizePending 0
159    private variable _legendPending 0
160    private variable _rotatePending 0
161    private variable _cutplanePending 0
162    private variable _field      ""
163    private variable _colorMode "scalar"; # Mode of colormap (vmag or scalar)
164    private variable _fields
165    private variable _curFldName ""
166    private variable _curFldLabel ""
167    private variable _mouseOver "";     # what called LegendRangeAction:
168                                        # vmin or vmax
169    private variable _customRangeClick 1; # what called ToggleCustomRange
170
171    private common _downloadPopup;      # download options from popup
172    private common _hardcopy
173}
174
175itk::usual VtkIsosurfaceViewer {
176    keep -background -foreground -cursor -font
177    keep -plotbackground -plotforeground
178}
179
180# ----------------------------------------------------------------------
181# CONSTRUCTOR
182# ----------------------------------------------------------------------
183itcl::body Rappture::VtkIsosurfaceViewer::constructor {args} {
184    set _serverType "vtkvis"
185
186    #DebugOn
187    EnableWaitDialog 900
188
189    # Rebuild event
190    $_dispatcher register !rebuild
191    $_dispatcher dispatch $this !rebuild "[itcl::code $this Rebuild]; list"
192
193    # Resize event
194    $_dispatcher register !resize
195    $_dispatcher dispatch $this !resize "[itcl::code $this DoResize]; list"
196
197    # Legend event
198    $_dispatcher register !legend
199    $_dispatcher dispatch $this !legend "[itcl::code $this RequestLegend]; list"
200
201    # Rotate event
202    $_dispatcher register !rotate
203    $_dispatcher dispatch $this !rotate "[itcl::code $this DoRotate]; list"
204
205    # Contour levels event
206    $_dispatcher register !contours
207    $_dispatcher dispatch $this !contours \
208        "[itcl::code $this DoChangeContourLevels]; list"
209
210    # X-Cutplane event
211    $_dispatcher register !xcutplane
212    $_dispatcher dispatch $this !xcutplane \
213        "[itcl::code $this AdjustSetting -xcutplaneposition]; list"
214
215    # Y-Cutplane event
216    $_dispatcher register !ycutplane
217    $_dispatcher dispatch $this !ycutplane \
218        "[itcl::code $this AdjustSetting -ycutplaneposition]; list"
219
220    # Z-Cutplane event
221    $_dispatcher register !zcutplane
222    $_dispatcher dispatch $this !zcutplane \
223        "[itcl::code $this AdjustSetting -zcutplaneposition]; list"
224
225    #
226    # Populate parser with commands handle incoming requests
227    #
228    $_parser alias image [itcl::code $this ReceiveImage]
229    $_parser alias legend [itcl::code $this ReceiveLegend]
230    $_parser alias dataset [itcl::code $this ReceiveDataset]
231
232    # Initialize the view to some default parameters.
233    array set _view {
234        -ortho    0
235        -qw       0.853553
236        -qx       -0.353553
237        -qy       0.353553
238        -qz       0.146447
239        -xpan     0
240        -ypan     0
241        -zoom     1.0
242    }
243    set _arcball [blt::arcball create 100 100]
244    $_arcball quaternion [ViewToQuaternion]
245
246    array set _contourList {
247        numLevels       10
248        reqValues       ""
249        updatePending   0
250        values          ""
251    }
252    array set _settings {
253        -axesvisible            1
254        -axislabels             1
255        -axisminorticks         1
256        -axismode               "static"
257        -background             black
258        -colormap               BCGYR
259        -colormapvisible        1
260        -customrange            0
261        -customrangemin         0
262        -customrangemax         1
263        -cutplaneedges          0
264        -cutplanelighting       1
265        -cutplaneopacity        1.0
266        -cutplanepreinterp      1
267        -cutplanesvisible       0
268        -cutplanewireframe      0
269        -field                  "Default"
270        -isolinecolor           white
271        -isosurfaceedges        0
272        -isosurfacelighting     1
273        -isosurfaceopacity      0.6
274        -isosurfacevisible      1
275        -isosurfacewireframe    0
276        -legendvisible          1
277        -numcontours            10
278        -outline                0
279        -xcutplaneposition      50
280        -xcutplanevisible       1
281        -xgrid                  0
282        -ycutplaneposition      50
283        -ycutplanevisible       1
284        -ygrid                  0
285        -zcutplaneposition      50
286        -zcutplanevisible       1
287        -zgrid                  0
288    }
289    array set _changed {
290        -colormap               0
291        -cutplaneedges          0
292        -cutplanelighting       0
293        -cutplaneopacity        0
294        -cutplanepreinterp      0
295        -cutplanesvisible       0
296        -cutplanewireframe      0
297        -isosurfaceedges        0
298        -isosurfacelighting     0
299        -isosurfaceopacity      0
300        -isosurfacevisible      0
301        -isosurfacewireframe    0
302        -numcontours            0
303        -outline                0
304        -xcutplaneposition      0
305        -xcutplanevisible       0
306        -ycutplaneposition      0
307        -ycutplanevisible       0
308        -zcutplaneposition      0
309        -zcutplanevisible       0
310    }
311    array set _widget {
312        -isosurfaceopacity      60
313        -cutplaneopacity        100
314    }
315
316    itk_component add view {
317        canvas $itk_component(plotarea).view \
318            -highlightthickness 0 -borderwidth 0
319    } {
320        usual
321        ignore -highlightthickness -borderwidth -background
322    }
323
324    itk_component add fieldmenu {
325        menu $itk_component(plotarea).menu -bg black -fg white -relief flat \
326            -tearoff 0
327    } {
328        usual
329        ignore -background -foreground -relief -tearoff
330    }
331
332    # add an editor for adjusting the legend min and max values
333    itk_component add editor {
334        Rappture::Editor $itk_interior.editor \
335            -activatecommand [itcl::code $this LegendRangeAction activate] \
336            -validatecommand [itcl::code $this LegendRangeAction validate] \
337            -applycommand [itcl::code $this LegendRangeAction apply]
338    }
339
340    set c $itk_component(view)
341    bind $c <Configure> [itcl::code $this EventuallyResize %w %h]
342    bind $c <Control-F1> [itcl::code $this ToggleConsole]
343
344    # Fix the scrollregion in case we go off screen
345    $c configure -scrollregion [$c bbox all]
346
347    set _map(id) [$c create image 0 0 -anchor nw -image $_image(plot)]
348    set _map(cwidth) -1
349    set _map(cheight) -1
350    set _map(zoom) 1.0
351    set _map(original) ""
352
353    set f [$itk_component(main) component controls]
354    itk_component add reset {
355        button $f.reset -borderwidth 1 -padx 1 -pady 1 \
356            -highlightthickness 0 \
357            -image [Rappture::icon reset-view] \
358            -command [itcl::code $this Zoom reset]
359    } {
360        usual
361        ignore -highlightthickness
362    }
363    pack $itk_component(reset) -side top -padx 2 -pady 2
364    Rappture::Tooltip::for $itk_component(reset) \
365        "Reset the view to the default zoom level"
366
367    itk_component add zoomin {
368        button $f.zin -borderwidth 1 -padx 1 -pady 1 \
369            -highlightthickness 0 \
370            -image [Rappture::icon zoom-in] \
371            -command [itcl::code $this Zoom in]
372    } {
373        usual
374        ignore -highlightthickness
375    }
376    pack $itk_component(zoomin) -side top -padx 2 -pady 2
377    Rappture::Tooltip::for $itk_component(zoomin) "Zoom in"
378
379    itk_component add zoomout {
380        button $f.zout -borderwidth 1 -padx 1 -pady 1 \
381            -highlightthickness 0 \
382            -image [Rappture::icon zoom-out] \
383            -command [itcl::code $this Zoom out]
384    } {
385        usual
386        ignore -highlightthickness
387    }
388    pack $itk_component(zoomout) -side top -padx 2 -pady 2
389    Rappture::Tooltip::for $itk_component(zoomout) "Zoom out"
390
391    itk_component add contour {
392        Rappture::PushButton $f.contour \
393            -onimage [Rappture::icon volume-on] \
394            -offimage [Rappture::icon volume-off] \
395            -variable [itcl::scope _settings(-isosurfacevisible)] \
396            -command [itcl::code $this AdjustSetting -isosurfacevisible]
397    }
398    $itk_component(contour) select
399    Rappture::Tooltip::for $itk_component(contour) \
400        "Hide the isosurface"
401    pack $itk_component(contour) -padx 2 -pady 2
402
403    itk_component add cutplane {
404        Rappture::PushButton $f.cutplane \
405            -onimage [Rappture::icon cutbutton] \
406            -offimage [Rappture::icon cutbutton] \
407            -variable [itcl::scope _settings(-cutplanesvisible)] \
408            -command [itcl::code $this AdjustSetting -cutplanesvisible]
409    }
410    Rappture::Tooltip::for $itk_component(cutplane) \
411        "Show the cutplanes"
412    pack $itk_component(cutplane) -padx 2 -pady 2
413
414    if { [catch {
415        BuildIsosurfaceTab
416        BuildCutplanesTab
417        BuildAxisTab
418        BuildCameraTab
419    } errs] != 0 } {
420        puts stderr errs=$errs
421    }
422
423    # Legend
424    set _image(legend) [image create photo]
425    itk_component add legend {
426        canvas $itk_component(plotarea).legend -width 50 -highlightthickness 0
427    } {
428        usual
429        ignore -highlightthickness
430        rename -background -plotbackground plotBackground Background
431    }
432
433    # Hack around the Tk panewindow.  The problem is that the requested
434    # size of the 3d view isn't set until an image is retrieved from
435    # the server.  So the panewindow uses the tiny size.
436    set w 10000
437    pack forget $itk_component(view)
438    blt::table $itk_component(plotarea) \
439        0,0 $itk_component(view) -fill both -reqwidth $w
440    blt::table configure $itk_component(plotarea) c1 -resize none
441
442    SetupMouseRotationBindings
443    SetupMousePanningBindings
444    SetupMouseZoomBindings
445    SetupKeyboardBindings
446
447    #bind $itk_component(view) <ButtonRelease-3> \
448    #    [itcl::code $this Pick %x %y]
449
450    set _image(download) [image create photo]
451
452    eval itk_initialize $args
453
454    Connect
455}
456
457# ----------------------------------------------------------------------
458# DESTRUCTOR
459# ----------------------------------------------------------------------
460itcl::body Rappture::VtkIsosurfaceViewer::destructor {} {
461    Disconnect
462    image delete $_image(plot)
463    image delete $_image(download)
464    catch { blt::arcball destroy $_arcball }
465}
466
467itcl::body Rappture::VtkIsosurfaceViewer::SetupMouseRotationBindings {} {
468    # Bindings for rotation via mouse
469    bind $itk_component(view) <ButtonPress-1> \
470        [itcl::code $this Rotate click %x %y]
471    bind $itk_component(view) <B1-Motion> \
472        [itcl::code $this Rotate drag %x %y]
473    bind $itk_component(view) <ButtonRelease-1> \
474        [itcl::code $this Rotate release %x %y]
475}
476
477itcl::body Rappture::VtkIsosurfaceViewer::DisableMouseRotationBindings {} {
478    # Bindings for rotation via mouse
479    bind $itk_component(view) <ButtonPress-1> ""
480    bind $itk_component(view) <B1-Motion> ""
481    bind $itk_component(view) <ButtonRelease-1> ""
482}
483
484itcl::body Rappture::VtkIsosurfaceViewer::SetupMousePanningBindings {} {
485    # Bindings for panning via mouse
486    bind $itk_component(view) <ButtonPress-2> \
487        [itcl::code $this Pan click %x %y]
488    bind $itk_component(view) <B2-Motion> \
489        [itcl::code $this Pan drag %x %y]
490    bind $itk_component(view) <ButtonRelease-2> \
491        [itcl::code $this Pan release %x %y]
492}
493
494itcl::body Rappture::VtkIsosurfaceViewer::SetupMouseZoomBindings {} {
495    if {[string equal "x11" [tk windowingsystem]]} {
496        # Bindings for zoom via mouse
497        bind $itk_component(view) <4> [itcl::code $this Zoom out]
498        bind $itk_component(view) <5> [itcl::code $this Zoom in]
499    }
500}
501
502itcl::body Rappture::VtkIsosurfaceViewer::SetupKeyboardBindings {} {
503    # Bindings for panning via keyboard
504    bind $itk_component(view) <KeyPress-Left> \
505        [itcl::code $this Pan set -10 0]
506    bind $itk_component(view) <KeyPress-Right> \
507        [itcl::code $this Pan set 10 0]
508    bind $itk_component(view) <KeyPress-Up> \
509        [itcl::code $this Pan set 0 -10]
510    bind $itk_component(view) <KeyPress-Down> \
511        [itcl::code $this Pan set 0 10]
512    bind $itk_component(view) <Shift-KeyPress-Left> \
513        [itcl::code $this Pan set -2 0]
514    bind $itk_component(view) <Shift-KeyPress-Right> \
515        [itcl::code $this Pan set 2 0]
516    bind $itk_component(view) <Shift-KeyPress-Up> \
517        [itcl::code $this Pan set 0 -2]
518    bind $itk_component(view) <Shift-KeyPress-Down> \
519        [itcl::code $this Pan set 0 2]
520
521    # Bindings for zoom via keyboard
522    bind $itk_component(view) <KeyPress-Prior> \
523        [itcl::code $this Zoom out]
524    bind $itk_component(view) <KeyPress-Next> \
525        [itcl::code $this Zoom in]
526
527    bind $itk_component(view) <Enter> "focus $itk_component(view)"
528}
529
530itcl::body Rappture::VtkIsosurfaceViewer::DoResize {} {
531    if { $_width < 2 } {
532        set _width 500
533    }
534    if { $_height < 2 } {
535        set _height 500
536    }
537    set _start [clock clicks -milliseconds]
538    SendCmd "screen size $_width $_height"
539
540    EventuallyRequestLegend
541    set _resizePending 0
542}
543
544itcl::body Rappture::VtkIsosurfaceViewer::DoChangeContourLevels {} {
545    GenerateContourList
546    SendCmd [list contour3d contourlist $_contourList(values)]
547    SendCmd [list camera reset]
548    DrawLegend
549    set _contourList(updatePending) 0
550}
551
552itcl::body Rappture::VtkIsosurfaceViewer::DoRotate {} {
553    SendCmd "camera orient [ViewToQuaternion]"
554    set _rotatePending 0
555}
556
557itcl::body Rappture::VtkIsosurfaceViewer::EventuallyRequestLegend {} {
558    if { !$_legendPending } {
559        set _legendPending 1
560        $_dispatcher event -idle !legend
561    }
562}
563
564itcl::body Rappture::VtkIsosurfaceViewer::EventuallyResize { w h } {
565    set _width $w
566    set _height $h
567    $_arcball resize $w $h
568    if { !$_resizePending } {
569        set _resizePending 1
570        $_dispatcher event -after 400 !resize
571    }
572}
573
574itcl::body Rappture::VtkIsosurfaceViewer::EventuallyRotate { q } {
575    QuaternionToView $q
576    if { !$_rotatePending } {
577        set _rotatePending 1
578        $_dispatcher event -after 100 !rotate
579    }
580}
581
582itcl::body Rappture::VtkIsosurfaceViewer::EventuallySetCutplane { axis args } {
583    if { !$_cutplanePending } {
584        set _cutplanePending 1
585        $_dispatcher event -after 100 !${axis}cutplane
586    }
587}
588
589itcl::body Rappture::VtkIsosurfaceViewer::EventuallyChangeContourLevels {} {
590    set n $_contourList(numLevels)
591    set _contourList(values) ""
592    if { !$_contourList(updatePending) } {
593        set _contourList(updatePending) 1
594        $_dispatcher event -after 100 !contours
595    }
596}
597
598# ----------------------------------------------------------------------
599# USAGE: add <dataobj> ?<settings>?
600#
601# Clients use this to add a data object to the plot.  The optional
602# <settings> are used to configure the plot.  Allowed settings are
603# -color, -brightness, -width, -linestyle, and -raise.
604# ----------------------------------------------------------------------
605itcl::body Rappture::VtkIsosurfaceViewer::add {dataobj {settings ""}} {
606    if { ![$dataobj isvalid] } {
607        return;                         # Object doesn't contain valid data.
608    }
609    array set params {
610        -color auto
611        -width 1
612        -linestyle solid
613        -brightness 0
614        -raise 0
615        -description ""
616        -param ""
617        -type ""
618    }
619    array set params $settings
620    set params(-description) ""
621    set params(-param) ""
622    array set params $settings
623
624    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
625        # can't handle -autocolors yet
626        set params(-color) black
627    }
628    set pos [lsearch -exact $_dlist $dataobj]
629    if {$pos < 0} {
630        lappend _dlist $dataobj
631    }
632    set _obj2ovride($dataobj-color) $params(-color)
633    set _obj2ovride($dataobj-width) $params(-width)
634    set _obj2ovride($dataobj-raise) $params(-raise)
635    $_dispatcher event -idle !rebuild
636}
637
638# ----------------------------------------------------------------------
639# USAGE: delete ?<dataobj1> <dataobj2> ...?
640#
641# Clients use this to delete a dataobj from the plot.  If no dataobjs
642# are specified, then all dataobjs are deleted.  No data objects are
643# deleted.  They are only removed from the display list.
644# ----------------------------------------------------------------------
645itcl::body Rappture::VtkIsosurfaceViewer::delete {args} {
646    if { [llength $args] == 0} {
647        set args $_dlist
648    }
649    # Delete all specified dataobjs
650    set changed 0
651    foreach dataobj $args {
652        set pos [lsearch -exact $_dlist $dataobj]
653        if { $pos < 0 } {
654            continue;                   # Don't know anything about it.
655        }
656        # Remove it from the dataobj list.
657        set _dlist [lreplace $_dlist $pos $pos]
658        array unset _obj2ovride $dataobj-*
659        array unset _settings $dataobj-*
660        set changed 1
661    }
662    # If anything changed, then rebuild the plot
663    if { $changed } {
664        $_dispatcher event -idle !rebuild
665    }
666}
667
668# ----------------------------------------------------------------------
669# USAGE: get ?-objects?
670# USAGE: get ?-visible?
671# USAGE: get ?-image view?
672#
673# Clients use this to query the list of objects being plotted, in
674# order from bottom to top of this result.  The optional "-image"
675# flag can also request the internal images being shown.
676# ----------------------------------------------------------------------
677itcl::body Rappture::VtkIsosurfaceViewer::get {args} {
678    if {[llength $args] == 0} {
679        set args "-objects"
680    }
681
682    set op [lindex $args 0]
683    switch -- $op {
684        "-objects" {
685            # put the dataobj list in order according to -raise options
686            set dlist {}
687            foreach dataobj $_dlist {
688                if { ![IsValidObject $dataobj] } {
689                    continue
690                }
691                if {[info exists _obj2ovride($dataobj-raise)] &&
692                    $_obj2ovride($dataobj-raise)} {
693                    set dlist [linsert $dlist 0 $dataobj]
694                } else {
695                    lappend dlist $dataobj
696                }
697            }
698            return $dlist
699        }
700        "-visible" {
701            set dlist {}
702            foreach dataobj $_dlist {
703                if { ![IsValidObject $dataobj] } {
704                    continue
705                }
706                if { ![info exists _obj2ovride($dataobj-raise)] } {
707                    # No setting indicates that the object isn't visible.
708                    continue
709                }
710                # Otherwise use the -raise parameter to put the object to
711                # the front of the list.
712                if { $_obj2ovride($dataobj-raise) } {
713                    set dlist [linsert $dlist 0 $dataobj]
714                } else {
715                    lappend dlist $dataobj
716                }
717            }
718            return $dlist
719        }
720        -image {
721            if {[llength $args] != 2} {
722                error "wrong # args: should be \"get -image view\""
723            }
724            switch -- [lindex $args end] {
725                view {
726                    return $_image(plot)
727                }
728                default {
729                    error "bad image name \"[lindex $args end]\": should be view"
730                }
731            }
732        }
733        default {
734            error "bad option \"$op\": should be -objects or -image"
735        }
736    }
737}
738
739# ----------------------------------------------------------------------
740# USAGE: scale ?<data1> <data2> ...?
741#
742# Sets the default limits for the overall plot according to the
743# limits of the data for all of the given <data> objects.  This
744# accounts for all objects--even those not showing on the screen.
745# Because of this, the limits are appropriate for all objects as
746# the user scans through data in the ResultSet viewer.
747# ----------------------------------------------------------------------
748itcl::body Rappture::VtkIsosurfaceViewer::scale { args } {
749    foreach dataobj $args {
750        if { ![$dataobj isvalid] } {
751            continue;                   # Object doesn't contain valid data.
752        }
753        foreach axis { x y z } {
754            set lim [$dataobj limits $axis]
755            if { ![info exists _limits($axis)] } {
756                set _limits($axis) $lim
757                continue
758            }
759            foreach {min max} $lim break
760            foreach {amin amax} $_limits($axis) break
761            if { $amin > $min } {
762                set amin $min
763            }
764            if { $amax < $max } {
765                set amax $max
766            }
767            set _limits($axis) [list $amin $amax]
768        }
769        foreach { fname lim } [$dataobj fieldlimits] {
770            if { ![info exists _limits($fname)] } {
771                set _limits($fname) $lim
772
773                # set reasonable defaults for
774                # customrangevmin and customrangevmax
775                foreach {min max} $lim break
776                SetMinMaxGauges $min $max
777                set _settings(-customrangemin) $min
778                set _settings(-customrangemax) $max
779
780                continue
781            }
782            foreach {min max} $lim break
783            foreach {fmin fmax} $_limits($fname) break
784            if { ! $_settings(-customrange) } {
785                SetMinMaxGauges $fmin $fmax
786            }
787            if { $fmin > $min } {
788                set fmin $min
789            }
790            if { $fmax < $max } {
791                set fmax $max
792            }
793            set _limits($fname) [list $fmin $fmax]
794        }
795    }
796}
797
798# ----------------------------------------------------------------------
799# USAGE: download coming
800# USAGE: download controls <downloadCommand>
801# USAGE: download now
802#
803# Clients use this method to create a downloadable representation
804# of the plot.  Returns a list of the form {ext string}, where
805# "ext" is the file extension (indicating the type of data) and
806# "string" is the data itself.
807# ----------------------------------------------------------------------
808itcl::body Rappture::VtkIsosurfaceViewer::download {option args} {
809    switch $option {
810        coming {
811            if {[catch {
812                blt::winop snap $itk_component(plotarea) $_image(download)
813            }]} {
814                $_image(download) configure -width 1 -height 1
815                $_image(download) put #000000
816            }
817        }
818        controls {
819            set popup .vtkviewerdownload
820            if { ![winfo exists .vtkviewerdownload] } {
821                set inner [BuildDownloadPopup $popup [lindex $args 0]]
822            } else {
823                set inner [$popup component inner]
824            }
825            set _downloadPopup(image_controls) $inner.image_frame
826            set num [llength [get]]
827            set num [expr {($num == 1) ? "1 result" : "$num results"}]
828            set word [Rappture::filexfer::label downloadWord]
829            $inner.summary configure -text "$word $num in the following format:"
830            update idletasks            ;# Fix initial sizes
831            return $popup
832        }
833        now {
834            set popup .vtkviewerdownload
835            if {[winfo exists .vtkviewerdownload]} {
836                $popup deactivate
837            }
838            switch -- $_downloadPopup(format) {
839                "image" {
840                    return [$this GetImage [lindex $args 0]]
841                }
842                "vtk" {
843                    return [$this GetVtkData [lindex $args 0]]
844                }
845            }
846            return ""
847        }
848        default {
849            error "bad option \"$option\": should be coming, controls, now"
850        }
851    }
852}
853
854# ----------------------------------------------------------------------
855# USAGE: Connect ?<host:port>,<host:port>...?
856#
857# Clients use this method to establish a connection to a new
858# server, or to reestablish a connection to the previous server.
859# Any existing connection is automatically closed.
860# ----------------------------------------------------------------------
861itcl::body Rappture::VtkIsosurfaceViewer::Connect {} {
862    set _hosts [GetServerList "vtkvis"]
863    if { "" == $_hosts } {
864        return 0
865    }
866    set _reset 1
867    set result [VisViewer::Connect $_hosts]
868    if { $result } {
869        if { $_reportClientInfo }  {
870            # Tell the server the viewer, hub, user and session.
871            # Do this immediately on connect before buffering any commands
872            global env
873
874            set info {}
875            set user "???"
876            if { [info exists env(USER)] } {
877                set user $env(USER)
878            }
879            set session "???"
880            if { [info exists env(SESSION)] } {
881                set session $env(SESSION)
882            }
883            lappend info "version" "$Rappture::version"
884            lappend info "build" "$Rappture::build"
885            lappend info "svnurl" "$Rappture::svnurl"
886            lappend info "installdir" "$Rappture::installdir"
887            lappend info "hub" [exec hostname]
888            lappend info "client" "vtkisosurfaceviewer"
889            lappend info "user" $user
890            lappend info "session" $session
891            SendCmd "clientinfo [list $info]"
892        }
893
894        set w [winfo width $itk_component(view)]
895        set h [winfo height $itk_component(view)]
896        EventuallyResize $w $h
897    }
898    return $result
899}
900
901#
902# isconnected --
903#
904# Indicates if we are currently connected to the visualization server.
905#
906itcl::body Rappture::VtkIsosurfaceViewer::isconnected {} {
907    return [VisViewer::IsConnected]
908}
909
910#
911# disconnect --
912#
913itcl::body Rappture::VtkIsosurfaceViewer::disconnect {} {
914    Disconnect
915    set _reset 1
916}
917
918#
919# Disconnect --
920#
921# Clients use this method to disconnect from the current rendering server.
922#
923itcl::body Rappture::VtkIsosurfaceViewer::Disconnect {} {
924    VisViewer::Disconnect
925
926    $_dispatcher cancel !rebuild
927    $_dispatcher cancel !resize
928    $_dispatcher cancel !rotate
929    $_dispatcher cancel !xcutplane
930    $_dispatcher cancel !ycutplane
931    $_dispatcher cancel !zcutplane
932    $_dispatcher cancel !legend
933    # disconnected -- no more data sitting on server
934    array unset _datasets
935    array unset _colormaps
936}
937
938# ----------------------------------------------------------------------
939# USAGE: ReceiveImage -bytes <size> -type <type> -token <token>
940#
941# Invoked automatically whenever the "image" command comes in from
942# the rendering server.  Indicates that binary image data with the
943# specified <size> will follow.
944# ----------------------------------------------------------------------
945itcl::body Rappture::VtkIsosurfaceViewer::ReceiveImage { args } {
946    array set info {
947        -token "???"
948        -bytes 0
949        -type image
950    }
951    array set info $args
952    set bytes [ReceiveBytes $info(-bytes)]
953    if { $info(-type) == "image" } {
954        if 0 {
955            set f [open "last.ppm" "w"]
956            fconfigure $f -encoding binary
957            puts -nonewline $f $bytes
958            close $f
959        }
960        $_image(plot) configure -data $bytes
961        #set time [clock seconds]
962        #set date [clock format $time]
963        #set w [image width $_image(plot)]
964        #set h [image height $_image(plot)]
965        #puts stderr "$date: received image ${w}x${h} image"
966        if { $_start > 0 } {
967            set finish [clock clicks -milliseconds]
968            #puts stderr "round trip time [expr $finish -$_start] milliseconds"
969            set _start 0
970        }
971    } elseif { $info(type) == "print" } {
972        set tag $this-print-$info(-token)
973        set _hardcopy($tag) $bytes
974    }
975}
976
977#
978# ReceiveDataset --
979#
980itcl::body Rappture::VtkIsosurfaceViewer::ReceiveDataset { args } {
981    if { ![isconnected] } {
982        return
983    }
984    set option [lindex $args 0]
985    switch -- $option {
986        "scalar" {
987            set option [lindex $args 1]
988            switch -- $option {
989                "world" {
990                    foreach { x y z value tag } [lrange $args 2 end] break
991                }
992                "pixel" {
993                    foreach { x y value tag } [lrange $args 2 end] break
994                }
995            }
996        }
997        "vector" {
998            set option [lindex $args 1]
999            switch -- $option {
1000                "world" {
1001                    foreach { x y z vx vy vz tag } [lrange $args 2 end] break
1002                }
1003                "pixel" {
1004                    foreach { x y vx vy vz tag } [lrange $args 2 end] break
1005                }
1006            }
1007        }
1008        "names" {
1009            foreach { name } [lindex $args 1] {
1010                #puts stderr "Dataset: $name"
1011            }
1012        }
1013        default {
1014            error "unknown dataset option \"$option\" from server"
1015        }
1016    }
1017}
1018
1019# ----------------------------------------------------------------------
1020# USAGE: Rebuild
1021#
1022# Called automatically whenever something changes that affects the
1023# data in the widget.  Clears any existing data and rebuilds the
1024# widget to display new data.
1025# ----------------------------------------------------------------------
1026itcl::body Rappture::VtkIsosurfaceViewer::Rebuild {} {
1027    set w [winfo width $itk_component(view)]
1028    set h [winfo height $itk_component(view)]
1029    if { $w < 2 || $h < 2 } {
1030        update
1031        $_dispatcher event -idle !rebuild
1032        return
1033    }
1034
1035    # Turn on buffering of commands to the server.  We don't want to
1036    # be preempted by a server disconnect/reconnect (which automatically
1037    # generates a new call to Rebuild).
1038    StartBufferingCommands
1039
1040    if { $_reset } {
1041        set _width $w
1042        set _height $h
1043        $_arcball resize $w $h
1044        DoResize
1045
1046        # Reset the camera and other view parameters
1047        $_arcball quaternion [ViewToQuaternion]
1048        InitSettings -ortho
1049        DoRotate
1050        PanCamera
1051        set _first ""
1052        InitSettings -background \
1053            -xgrid -ygrid -zgrid -axismode \
1054            -axesvisible -axislabels -axisminorticks
1055        #SendCmd "axis lformat all %g"
1056        StopBufferingCommands
1057        SendCmd "imgflush"
1058        StartBufferingCommands
1059    }
1060    set _first ""
1061    SendCmd "dataset visible 0"
1062    eval scale $_dlist
1063    foreach dataobj [get -objects] {
1064        if { [info exists _obj2ovride($dataobj-raise)] &&  $_first == "" } {
1065            set _first $dataobj
1066            SetCurrentFieldName $dataobj
1067        }
1068        foreach comp [$dataobj components] {
1069            set tag $dataobj-$comp
1070            if { ![info exists _datasets($tag)] } {
1071                set bytes [$dataobj vtkdata $comp]
1072                if 0 {
1073                    set f [open "/tmp/isosurface.vtk" "w"]
1074                    fconfigure $f -translation binary -encoding binary
1075                    puts -nonewline $f $bytes
1076                    close $f
1077                }
1078                set length [string length $bytes]
1079                if { $_reportClientInfo }  {
1080                    set info {}
1081                    lappend info "tool_id"       [$dataobj hints toolid]
1082                    lappend info "tool_name"     [$dataobj hints toolname]
1083                    lappend info "tool_title"    [$dataobj hints tooltitle]
1084                    lappend info "tool_command"  [$dataobj hints toolcommand]
1085                    lappend info "tool_revision" [$dataobj hints toolrevision]
1086                    lappend info "dataset_label" [$dataobj hints label]
1087                    lappend info "dataset_size"  $length
1088                    lappend info "dataset_tag"   $tag
1089                    SendCmd "clientinfo [list $info]"
1090                }
1091                SendCmd "dataset add $tag data follows $length"
1092                SendData $bytes
1093                set _datasets($tag) 1
1094                SetObjectStyle $dataobj $comp
1095            }
1096            if { [info exists _obj2ovride($dataobj-raise)] } {
1097                SendCmd "contour3d visible 1 $tag"
1098            }
1099        }
1100    }
1101
1102    InitSettings -cutplanesvisible -isosurfacevisible -outline
1103    if { $_reset } {
1104        # These are settings that rely on a dataset being loaded.
1105        InitSettings \
1106            -field -range \
1107            -isosurfaceedges -isosurfacelighting -isosurfaceopacity \
1108            -isosurfacewireframe \
1109            -xcutplaneposition -ycutplaneposition -zcutplaneposition \
1110            -xcutplanevisible -ycutplanevisible -zcutplanevisible \
1111            -cutplanepreinterp -numcontours
1112
1113        Zoom reset
1114        foreach axis { x y z } {
1115            set label ""
1116            if { $_first != "" } {
1117                set label [$_first hints ${axis}label]
1118            }
1119            if { $label == "" } {
1120                set label [string toupper $axis]
1121            }
1122            # There may be a space in the axis label.
1123            SendCmd [list axis name $axis $label]
1124        }
1125        if { [array size _fields] < 2 } {
1126            catch {blt::table forget $itk_component(field) $itk_component(field_l)}
1127        }
1128        set _reset 0
1129    }
1130    # Redraw the legend even if we're using the same colormap. The position
1131    # of the isolines may have changed because the range of data changed.
1132    DrawLegend
1133
1134    # Actually write the commands to the server socket.  If it fails, we don't
1135    # care.  We're finished here.
1136    blt::busy hold $itk_component(hull)
1137    StopBufferingCommands;              # Turn off buffering and send commands.
1138    blt::busy release $itk_component(hull)
1139}
1140
1141# ----------------------------------------------------------------------
1142# USAGE: CurrentDatasets ?-all -visible? ?dataobjs?
1143#
1144# Returns a list of server IDs for the current datasets being displayed.  This
1145# is normally a single ID, but it might be a list of IDs if the current data
1146# object has multiple components.
1147# ----------------------------------------------------------------------
1148itcl::body Rappture::VtkIsosurfaceViewer::CurrentDatasets {args} {
1149    set flag [lindex $args 0]
1150    switch -- $flag {
1151        "-all" {
1152            if { [llength $args] > 1 } {
1153                error "CurrentDatasets: can't specify dataobj after \"-all\""
1154            }
1155            set dlist [get -objects]
1156        }
1157        "-visible" {
1158            if { [llength $args] > 1 } {
1159                set dlist {}
1160                set args [lrange $args 1 end]
1161                foreach dataobj $args {
1162                    if { [info exists _obj2ovride($dataobj-raise)] } {
1163                        lappend dlist $dataobj
1164                    }
1165                }
1166            } else {
1167                set dlist [get -visible]
1168            }
1169        }
1170        default {
1171            set dlist $args
1172        }
1173    }
1174    set rlist ""
1175    foreach dataobj $dlist {
1176        foreach comp [$dataobj components] {
1177            set tag $dataobj-$comp
1178            if { [info exists _datasets($tag)] && $_datasets($tag) } {
1179                lappend rlist $tag
1180            }
1181        }
1182    }
1183    return $rlist
1184}
1185
1186# ----------------------------------------------------------------------
1187# USAGE: Zoom in
1188# USAGE: Zoom out
1189# USAGE: Zoom reset
1190#
1191# Called automatically when the user clicks on one of the zoom
1192# controls for this widget.  Changes the zoom for the current view.
1193# ----------------------------------------------------------------------
1194itcl::body Rappture::VtkIsosurfaceViewer::Zoom {option} {
1195    switch -- $option {
1196        "in" {
1197            set _view(-zoom) [expr {$_view(-zoom)*1.25}]
1198            SendCmd "camera zoom $_view(-zoom)"
1199        }
1200        "out" {
1201            set _view(-zoom) [expr {$_view(-zoom)*0.8}]
1202            SendCmd "camera zoom $_view(-zoom)"
1203        }
1204        "reset" {
1205            array set _view {
1206                -qw      0.853553
1207                -qx      -0.353553
1208                -qy      0.353553
1209                -qz      0.146447
1210                -xpan    0
1211                -ypan    0
1212                -zoom    1.0
1213            }
1214            if { $_first != "" } {
1215                set location [$_first hints camera]
1216                if { $location != "" } {
1217                    array set _view $location
1218                }
1219            }
1220            $_arcball quaternion [ViewToQuaternion]
1221            DoRotate
1222            SendCmd "camera reset"
1223        }
1224    }
1225}
1226
1227itcl::body Rappture::VtkIsosurfaceViewer::PanCamera {} {
1228    set x $_view(-xpan)
1229    set y $_view(-ypan)
1230    SendCmd "camera pan $x $y"
1231}
1232
1233# ----------------------------------------------------------------------
1234# USAGE: Rotate click <x> <y>
1235# USAGE: Rotate drag <x> <y>
1236# USAGE: Rotate release <x> <y>
1237#
1238# Called automatically when the user clicks/drags/releases in the
1239# plot area.  Moves the plot according to the user's actions.
1240# ----------------------------------------------------------------------
1241itcl::body Rappture::VtkIsosurfaceViewer::Rotate {option x y} {
1242    switch -- $option {
1243        "click" {
1244            $itk_component(view) configure -cursor fleur
1245            set _click(x) $x
1246            set _click(y) $y
1247        }
1248        "drag" {
1249            if {[array size _click] == 0} {
1250                Rotate click $x $y
1251            } else {
1252                set w [winfo width $itk_component(view)]
1253                set h [winfo height $itk_component(view)]
1254                if {$w <= 0 || $h <= 0} {
1255                    return
1256                }
1257
1258                if {[catch {
1259                    # this fails sometimes for no apparent reason
1260                    set dx [expr {double($x-$_click(x))/$w}]
1261                    set dy [expr {double($y-$_click(y))/$h}]
1262                }]} {
1263                    return
1264                }
1265                if { $dx == 0 && $dy == 0 } {
1266                    return
1267                }
1268                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1269                EventuallyRotate $q
1270                set _click(x) $x
1271                set _click(y) $y
1272            }
1273        }
1274        "release" {
1275            Rotate drag $x $y
1276            $itk_component(view) configure -cursor ""
1277            catch {unset _click}
1278        }
1279        default {
1280            error "bad option \"$option\": should be click, drag, release"
1281        }
1282    }
1283}
1284
1285itcl::body Rappture::VtkIsosurfaceViewer::Pick {x y} {
1286    foreach tag [CurrentDatasets -visible] {
1287        SendCmd "dataset getscalar pixel $x $y $tag"
1288    }
1289}
1290
1291# ----------------------------------------------------------------------
1292# USAGE: $this Pan click x y
1293#        $this Pan drag x y
1294#        $this Pan release x y
1295#
1296# Called automatically when the user clicks on one of the zoom
1297# controls for this widget.  Changes the zoom for the current view.
1298# ----------------------------------------------------------------------
1299itcl::body Rappture::VtkIsosurfaceViewer::Pan {option x y} {
1300    switch -- $option {
1301        "set" {
1302            set w [winfo width $itk_component(view)]
1303            set h [winfo height $itk_component(view)]
1304            set x [expr $x / double($w)]
1305            set y [expr $y / double($h)]
1306            set _view(-xpan) [expr $_view(-xpan) + $x]
1307            set _view(-ypan) [expr $_view(-ypan) + $y]
1308            PanCamera
1309            return
1310        }
1311        "click" {
1312            set _click(x) $x
1313            set _click(y) $y
1314            $itk_component(view) configure -cursor hand1
1315        }
1316        "drag" {
1317            if { ![info exists _click(x)] } {
1318                set _click(x) $x
1319            }
1320            if { ![info exists _click(y)] } {
1321                set _click(y) $y
1322            }
1323            set w [winfo width $itk_component(view)]
1324            set h [winfo height $itk_component(view)]
1325            set dx [expr ($_click(x) - $x)/double($w)]
1326            set dy [expr ($_click(y) - $y)/double($h)]
1327            set _click(x) $x
1328            set _click(y) $y
1329            set _view(-xpan) [expr $_view(-xpan) - $dx]
1330            set _view(-ypan) [expr $_view(-ypan) - $dy]
1331            PanCamera
1332        }
1333        "release" {
1334            Pan drag $x $y
1335            $itk_component(view) configure -cursor ""
1336        }
1337        default {
1338            error "unknown option \"$option\": should set, click, drag, or release"
1339        }
1340    }
1341}
1342
1343# ----------------------------------------------------------------------
1344# USAGE: InitSettings <what> ?<value>?
1345#
1346# Used internally to update rendering settings whenever parameters
1347# change in the popup settings panel.  Sends the new settings off
1348# to the back end.
1349# ----------------------------------------------------------------------
1350itcl::body Rappture::VtkIsosurfaceViewer::InitSettings { args } {
1351    foreach spec $args {
1352        if { [info exists _settings($_first${spec})] } {
1353            # Reset global setting with dataobj specific setting
1354            set _settings($spec) $_settings($_first${spec})
1355        }
1356        AdjustSetting $spec
1357    }
1358}
1359
1360#
1361# AdjustSetting --
1362#
1363# Changes/updates a specific setting in the widget.  There are
1364# usually user-setable option.  Commands are sent to the render
1365# server.
1366#
1367itcl::body Rappture::VtkIsosurfaceViewer::AdjustSetting {what {value ""}} {
1368    DebugTrace "Enter"
1369    if { ![isconnected] } {
1370        DebugTrace "Not connected"
1371        return
1372    }
1373    switch -- $what {
1374        "-axesvisible" {
1375            set bool $_settings($what)
1376            SendCmd "axis visible all $bool"
1377        }
1378        "-axislabels" {
1379            set bool $_settings($what)
1380            SendCmd "axis labels all $bool"
1381        }
1382        "-axisminorticks" {
1383            set bool $_settings($what)
1384            SendCmd "axis minticks all $bool"
1385        }
1386        "-axismode" {
1387            set mode [$itk_component(axisMode) value]
1388            set mode [$itk_component(axisMode) translate $mode]
1389            set _settings($what) $mode
1390            SendCmd "axis flymode $mode"
1391        }
1392        "-background" {
1393            set bgcolor [$itk_component(background) value]
1394            array set fgcolors {
1395                "black" "white"
1396                "white" "black"
1397                "grey"  "black"
1398            }
1399            configure -plotbackground $bgcolor \
1400                -plotforeground $fgcolors($bgcolor)
1401            $itk_component(view) delete "legend"
1402            DrawLegend
1403        }
1404        "-colormap" {
1405            set _changed($what) 1
1406            StartBufferingCommands
1407            set color [$itk_component(colormap) value]
1408            set _settings($what) $color
1409            if { $color == "none" } {
1410                if { $_settings(-colormapvisible) } {
1411                    SendCmd "contour3d colormode constant {}"
1412                    set _settings(-colormapvisible) 0
1413                }
1414            } else {
1415                if { !$_settings(-colormapvisible) } {
1416                    SendCmd "contour3d colormode $_colorMode $_curFldName"
1417                    set _settings(-colormapvisible) 1
1418                }
1419                SetCurrentColormap $color
1420            }
1421            StopBufferingCommands
1422            EventuallyRequestLegend
1423        }
1424        "-cutplaneedges" {
1425            set _changed($what) 1
1426            set bool $_settings($what)
1427            SendCmd "cutplane edges $bool"
1428        }
1429        "-cutplanelighting" {
1430            set _changed($what) 1
1431            set bool $_settings($what)
1432            SendCmd "cutplane lighting $bool"
1433        }
1434        "-cutplaneopacity" {
1435            set _changed($what) 1
1436            set _settings($what) [expr $_widget($what) * 0.01]
1437            SendCmd "cutplane opacity $_settings($what)"
1438        }
1439        "-cutplanepreinterp" {
1440            set _changed($what) 1
1441            set bool $_settings($what)
1442            SendCmd "cutplane preinterp $bool"
1443        }
1444        "-cutplanesvisible" {
1445            set _changed($what) 1
1446            set bool $_settings($what)
1447            SendCmd "cutplane visible 0"
1448            if { $bool } {
1449                foreach tag [CurrentDatasets -visible] {
1450                    SendCmd "cutplane visible $bool $tag"
1451                }
1452            }
1453            if { $bool } {
1454                Rappture::Tooltip::for $itk_component(cutplane) \
1455                    "Hide the cutplanes"
1456            } else {
1457                Rappture::Tooltip::for $itk_component(cutplane) \
1458                    "Show the cutplanes"
1459            }
1460        }
1461        "-cutplanewireframe" {
1462            set _changed($what) 1
1463            set bool $_settings($what)
1464            SendCmd "cutplane wireframe $bool"
1465        }
1466        "-field" {
1467            set label [$itk_component(field) value]
1468            set fname [$itk_component(field) translate $label]
1469            set _settings($what) $fname
1470            if { [info exists _fields($fname)] } {
1471                foreach { label units components } $_fields($fname) break
1472                if { $components > 1 } {
1473                    set _colorMode vmag
1474                } else {
1475                    set _colorMode scalar
1476                }
1477                set _curFldName $fname
1478                set _curFldLabel $label
1479            } else {
1480                puts stderr "unknown field \"$fname\""
1481                return
1482            }
1483            SendCmd "dataset scalar $_curFldName"
1484            if { ![info exists _limits($_curFldName)] } {
1485                SendCmd "dataset maprange all"
1486            } else {
1487                if { $_settings(-customrange) } {
1488                    set vmin [$itk_component(min) value]
1489                    set vmax [$itk_component(max) value]
1490                } else {
1491                    foreach { vmin vmax } $_limits($_curFldName) break
1492                    # set the min / max gauges with limits from the field
1493                    # the legend's min and max text will be updated
1494                    # when the legend is redrawn in DrawLegend
1495                    SetMinMaxGauges $vmin $vmax
1496                }
1497                SendCmd "dataset maprange explicit $vmin $vmax $_curFldName"
1498            }
1499            SendCmd "cutplane colormode $_colorMode $_curFldName"
1500            SendCmd "contour3d colormode $_colorMode $_curFldName"
1501            GenerateContourList
1502            SendCmd [list contour3d contourlist $_contourList(values)]
1503            SendCmd "camera reset"
1504            DrawLegend
1505        }
1506        "-isolinecolor" {
1507            set color [$itk_component(isolineColor) value]
1508            set _settings($what) $color
1509            DrawLegend
1510        }
1511        "-isosurfaceedges" {
1512            set _changed($what) 1
1513            set bool $_settings($what)
1514            SendCmd "contour3d edges $bool"
1515        }
1516        "-isosurfacelighting" {
1517            set _changed($what) 1
1518            set bool $_settings($what)
1519            SendCmd "contour3d lighting $bool"
1520        }
1521        "-isosurfaceopacity" {
1522            set _changed($what) 1
1523            set _settings($what) [expr $_widget($what) * 0.01]
1524            SendCmd "contour3d opacity $_settings($what)"
1525        }
1526        "-isosurfacevisible" {
1527            set _changed($what) 1
1528            set bool $_settings($what)
1529            SendCmd "contour3d visible 0"
1530            if { $bool } {
1531                foreach tag [CurrentDatasets -visible] {
1532                    SendCmd "contour3d visible $bool $tag"
1533                }
1534                Rappture::Tooltip::for $itk_component(contour) \
1535                    "Hide the isosurface"
1536            } else {
1537                Rappture::Tooltip::for $itk_component(contour) \
1538                    "Show the isosurface"
1539            }
1540        }
1541        "-isosurfacewireframe" {
1542            set _changed($what) 1
1543            set bool $_settings($what)
1544            SendCmd "contour3d wireframe $bool"
1545        }
1546        "-legendvisible" {
1547            if { !$_settings($what) } {
1548                $itk_component(view) delete legend
1549            }
1550            DrawLegend
1551        }
1552        "-numcontours" {
1553            set _changed($what) 1
1554            set _settings($what) [$itk_component(numcontours) value]
1555            if { $_contourList(numLevels) != $_settings($what) } {
1556                set _contourList(numLevels) $_settings($what)
1557                EventuallyChangeContourLevels
1558            }
1559        }
1560        "-ortho" {
1561            set bool $_view($what)
1562            if { $bool } {
1563                SendCmd "camera mode ortho"
1564            } else {
1565                SendCmd "camera mode persp"
1566            }
1567        }
1568        "-outline" {
1569            set _changed($what) 1
1570            set bool $_settings($what)
1571            SendCmd "outline visible 0"
1572            if { $bool } {
1573                foreach tag [CurrentDatasets -visible] {
1574                    SendCmd "outline visible $bool $tag"
1575                }
1576            }
1577        }
1578        "-range" {
1579            if { $_settings(-customrange) } {
1580                set vmin [$itk_component(min) value]
1581                set vmax [$itk_component(max) value]
1582            } else {
1583                foreach { vmin vmax } $_limits($_curFldName) break
1584            }
1585            GenerateContourList
1586            SendCmd [list contour3d contourlist $_contourList(values)]
1587            SendCmd "dataset maprange explicit $vmin $vmax $_curFldName"
1588            DrawLegend
1589        }
1590        "-xcutplanevisible" - "-ycutplanevisible" - "-zcutplanevisible" {
1591            set _changed($what) 1
1592            set axis [string tolower [string range $what 1 1]]
1593            set bool $_settings($what)
1594            if { $bool } {
1595                $itk_component(${axis}position) configure -state normal \
1596                    -troughcolor white
1597            } else {
1598                $itk_component(${axis}position) configure -state disabled \
1599                    -troughcolor grey82
1600            }
1601            SendCmd "cutplane axis $axis $bool"
1602        }
1603        "-xcutplaneposition" - "-ycutplaneposition" - "-zcutplaneposition" {
1604            set _changed($what) 1
1605            set axis [string tolower [string range $what 1 1]]
1606            set pos [expr $_settings($what) * 0.01]
1607            SendCmd "cutplane slice ${axis} ${pos}"
1608            set _cutplanePending 0
1609        }
1610        "-xgrid" - "-ygrid" - "-zgrid" {
1611            set axis [string tolower [string range $what 1 1]]
1612            set bool $_settings($what)
1613            SendCmd "axis grid $axis $bool"
1614        }
1615        default {
1616            error "don't know how to fix $what"
1617        }
1618    }
1619}
1620
1621#
1622# RequestLegend --
1623#
1624# Request a new legend from the server.  The size of the legend
1625# is determined from the height of the canvas.
1626#
1627# This should be called when
1628#   1.  A new current colormap is set.
1629#   2.  Window is resized.
1630#   3.  The limits of the data have changed.  (Just need a redraw).
1631#   4.  Number of isolines have changed. (Just need a redraw).
1632#   5.  Legend becomes visible (Just need a redraw).
1633#
1634itcl::body Rappture::VtkIsosurfaceViewer::RequestLegend {} {
1635    set _legendPending 0
1636    if { ![info exists _fields($_curFldName)] } {
1637        return
1638    }
1639    set fname $_curFldName
1640    set font "Arial 8"
1641    set lineht [font metrics $font -linespace]
1642    set w 12
1643    set h [expr {$_height - 2 * ($lineht + 2)}]
1644    if { $h < 1 } {
1645        return
1646    }
1647    if { [string match "component*" $fname] } {
1648        set title ""
1649    } else {
1650        if { [info exists _fields($fname)] } {
1651            foreach { title units } $_fields($fname) break
1652            if { $units != "" } {
1653                set title [format "%s (%s)" $title $units]
1654            }
1655        } else {
1656            set title $fname
1657        }
1658    }
1659    # If there's a title too, subtract one more line
1660    if { $title != "" } {
1661        incr h -$lineht
1662    }
1663    # Set the legend on the first dataset.
1664    if { $_currentColormap != "" } {
1665        set cmap $_currentColormap
1666        if { ![info exists _colormaps($cmap)] } {
1667            BuildColormap $cmap
1668            set _colormaps($cmap) 1
1669        }
1670        #SendCmd "legend $cmap $_colorMode $_curFldName {} $w $h 0"
1671        SendCmd "legend2 $cmap $w $h"
1672    }
1673}
1674
1675# ----------------------------------------------------------------------
1676# CONFIGURATION OPTION: -plotbackground
1677# ----------------------------------------------------------------------
1678itcl::configbody Rappture::VtkIsosurfaceViewer::plotbackground {
1679    if { [isconnected] } {
1680        set rgb [Color2RGB $itk_option(-plotbackground)]
1681        SendCmd "screen bgcolor $rgb"
1682    }
1683}
1684
1685# ----------------------------------------------------------------------
1686# CONFIGURATION OPTION: -plotforeground
1687# ----------------------------------------------------------------------
1688itcl::configbody Rappture::VtkIsosurfaceViewer::plotforeground {
1689    if { [isconnected] } {
1690        set rgb [Color2RGB $itk_option(-plotforeground)]
1691        SendCmd "axis color all $rgb"
1692        SendCmd "outline color $rgb"
1693        SendCmd "cutplane color $rgb"
1694    }
1695}
1696
1697itcl::body Rappture::VtkIsosurfaceViewer::BuildIsosurfaceTab {} {
1698    set fg [option get $itk_component(hull) font Font]
1699    #set bfg [option get $itk_component(hull) boldFont Font]
1700
1701    set inner [$itk_component(main) insert end \
1702        -title "Isosurface Settings" \
1703        -icon [Rappture::icon volume-on]]
1704    $inner configure -borderwidth 4
1705
1706    checkbutton $inner.contour \
1707        -text "Isosurfaces" \
1708        -variable [itcl::scope _settings(-isosurfacevisible)] \
1709        -command [itcl::code $this AdjustSetting -isosurfacevisible] \
1710        -font "Arial 9"
1711
1712    checkbutton $inner.wireframe \
1713        -text "Wireframe" \
1714        -variable [itcl::scope _settings(-isosurfacewireframe)] \
1715        -command [itcl::code $this AdjustSetting -isosurfacewireframe] \
1716        -font "Arial 9"
1717
1718    checkbutton $inner.lighting \
1719        -text "Enable Lighting" \
1720        -variable [itcl::scope _settings(-isosurfacelighting)] \
1721        -command [itcl::code $this AdjustSetting -isosurfacelighting] \
1722        -font "Arial 9"
1723
1724    checkbutton $inner.edges \
1725        -text "Edges" \
1726        -variable [itcl::scope _settings(-isosurfaceedges)] \
1727        -command [itcl::code $this AdjustSetting -isosurfaceedges] \
1728        -font "Arial 9"
1729
1730    checkbutton $inner.outline \
1731        -text "Outline" \
1732        -variable [itcl::scope _settings(-outline)] \
1733        -command [itcl::code $this AdjustSetting -outline] \
1734        -font "Arial 9"
1735
1736    checkbutton $inner.legend \
1737        -text "Legend" \
1738        -variable [itcl::scope _settings(-legendvisible)] \
1739        -command [itcl::code $this AdjustSetting -legendvisible] \
1740        -font "Arial 9"
1741
1742    label $inner.linecolor_l -text "Isolines" -font "Arial 9"
1743    itk_component add isolineColor {
1744        Rappture::Combobox $inner.linecolor -width 10 -editable 0
1745    }
1746    $inner.linecolor choices insert end \
1747        "black"              "black"            \
1748        "blue"               "blue"             \
1749        "cyan"               "cyan"             \
1750        "green"              "green"            \
1751        "grey"               "grey"             \
1752        "magenta"            "magenta"          \
1753        "orange"             "orange"           \
1754        "red"                "red"              \
1755        "white"              "white"            \
1756        "none"               "none"
1757
1758    $itk_component(isolineColor) value "white"
1759    bind $inner.linecolor <<Value>> \
1760        [itcl::code $this AdjustSetting -isolinecolor]
1761
1762    label $inner.background_l -text "Background" -font "Arial 9"
1763    itk_component add background {
1764        Rappture::Combobox $inner.background -width 10 -editable 0
1765    }
1766    $inner.background choices insert end \
1767        "black"              "black"            \
1768        "white"              "white"            \
1769        "grey"               "grey"
1770
1771    $itk_component(background) value $_settings(-background)
1772    bind $inner.background <<Value>> \
1773        [itcl::code $this AdjustSetting -background]
1774
1775    label $inner.opacity_l -text "Opacity" -font "Arial 9"
1776    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1777        -variable [itcl::scope _widget(-isosurfaceopacity)] \
1778        -width 10 \
1779        -showvalue off \
1780        -command [itcl::code $this AdjustSetting -isosurfaceopacity]
1781    $inner.opacity set [expr $_settings(-isosurfaceopacity) * 100.0]
1782
1783    itk_component add field_l {
1784        label $inner.field_l -text "Field" -font "Arial 9"
1785    } {
1786        ignore -font
1787    }
1788    itk_component add field {
1789        Rappture::Combobox $inner.field -width 10 -editable 0
1790    }
1791    bind $inner.field <<Value>> \
1792        [itcl::code $this AdjustSetting -field]
1793
1794    label $inner.colormap_l -text "Colormap" -font "Arial 9"
1795    itk_component add colormap {
1796        Rappture::Combobox $inner.colormap -width 10 -editable 0
1797    }
1798    $inner.colormap choices insert end [GetColormapList]
1799    $itk_component(colormap) value "BCGYR"
1800    bind $inner.colormap <<Value>> \
1801        [itcl::code $this AdjustSetting -colormap]
1802
1803    label $inner.numcontours_l -text "Number of Isosurfaces" -font "Arial 9"
1804    itk_component add numcontours {
1805        Rappture::Spinint $inner.numcontours \
1806            -min 0 -max 50 -font "arial 9"
1807    }
1808    $itk_component(numcontours) value $_settings(-numcontours)
1809    bind $itk_component(numcontours) <<Value>> \
1810        [itcl::code $this AdjustSetting -numcontours]
1811
1812    # add widgets for setting a custom range on the legend
1813
1814    itk_component add crange {
1815        checkbutton $inner.crange \
1816            -text "Use Custom Range:" \
1817            -variable [itcl::scope _settings(-customrange)] \
1818            -command [itcl::code $this ToggleCustomRange] \
1819            -font "Arial 9"
1820    }
1821
1822    itk_component add l_min {
1823        label $inner.l_min -text "Min" -font "Arial 9"
1824    }
1825    itk_component add min {
1826        Rappture::Gauge $inner.min -font "Arial 9" \
1827            -validatecommand [itcl::code $this LegendRangeValidate "" vmin]
1828    }
1829    bind $itk_component(min) <<Value>> \
1830        [itcl::code $this AdjustSetting -range]
1831
1832    itk_component add l_max {
1833        label $inner.l_max -text "Max" -font "Arial 9"
1834    }
1835    itk_component add max {
1836        Rappture::Gauge $inner.max -font "Arial 9" \
1837            -validatecommand [itcl::code $this LegendRangeValidate "" vmax]
1838    }
1839    bind $itk_component(max) <<Value>> \
1840        [itcl::code $this AdjustSetting -range]
1841
1842    $itk_component(min) configure -state disabled
1843    $itk_component(max) configure -state disabled
1844
1845    blt::table $inner \
1846        0,0 $inner.field_l      -anchor w -pady 2 \
1847        0,1 $inner.field        -anchor w -pady 2 -fill x \
1848        1,0 $inner.colormap_l   -anchor w -pady 2 \
1849        1,1 $inner.colormap     -anchor w -pady 2 -fill x \
1850        2,0 $inner.linecolor_l  -anchor w -pady 2 \
1851        2,1 $inner.linecolor    -anchor w -pady 2 -fill x \
1852        3,0 $inner.background_l -anchor w -pady 2 \
1853        3,1 $inner.background   -anchor w -pady 2 -fill x \
1854        4,0 $inner.numcontours_l -anchor w -pady 2 \
1855        4,1 $inner.numcontours  -anchor w -pady 2 \
1856        5,0 $inner.wireframe    -anchor w -pady 2 -cspan 2 \
1857        6,0 $inner.lighting     -anchor w -pady 2 -cspan 2 \
1858        7,0 $inner.edges        -anchor w -pady 2 -cspan 2 \
1859        8,0 $inner.outline      -anchor w -pady 2 -cspan 2 \
1860        9,0 $inner.legend       -anchor w -pady 2 \
1861        10,0 $inner.opacity_l   -anchor w -pady 2 \
1862        10,1 $inner.opacity     -fill x   -pady 2 -fill x \
1863        11,0 $inner.crange      -anchor w -pady 2 -cspan 2 \
1864        12,0 $inner.l_min       -anchor w -pady 2 \
1865        12,1 $inner.min         -anchor w -pady 2 -fill x \
1866        13,0 $inner.l_max       -anchor w -pady 2 \
1867        13,1 $inner.max         -anchor w -pady 2 -fill x \
1868
1869    blt::table configure $inner r* c* -resize none
1870    blt::table configure $inner r14 c1 -resize expand
1871}
1872
1873itcl::body Rappture::VtkIsosurfaceViewer::BuildAxisTab {} {
1874
1875    set fg [option get $itk_component(hull) font Font]
1876    #set bfg [option get $itk_component(hull) boldFont Font]
1877
1878    set inner [$itk_component(main) insert end \
1879        -title "Axis Settings" \
1880        -icon [Rappture::icon axis2]]
1881    $inner configure -borderwidth 4
1882
1883    checkbutton $inner.visible \
1884        -text "Axes" \
1885        -variable [itcl::scope _settings(-axesvisible)] \
1886        -command [itcl::code $this AdjustSetting -axesvisible] \
1887        -font "Arial 9"
1888
1889    checkbutton $inner.labels \
1890        -text "Axis Labels" \
1891        -variable [itcl::scope _settings(-axislabels)] \
1892        -command [itcl::code $this AdjustSetting -axislabels] \
1893        -font "Arial 9"
1894    label $inner.grid_l -text "Grid" -font "Arial 9"
1895    checkbutton $inner.xgrid \
1896        -text "X" \
1897        -variable [itcl::scope _settings(-xgrid)] \
1898        -command [itcl::code $this AdjustSetting -xgrid] \
1899        -font "Arial 9"
1900    checkbutton $inner.ygrid \
1901        -text "Y" \
1902        -variable [itcl::scope _settings(-ygrid)] \
1903        -command [itcl::code $this AdjustSetting -ygrid] \
1904        -font "Arial 9"
1905    checkbutton $inner.zgrid \
1906        -text "Z" \
1907        -variable [itcl::scope _settings(-zgrid)] \
1908        -command [itcl::code $this AdjustSetting -zgrid] \
1909        -font "Arial 9"
1910    checkbutton $inner.minorticks \
1911        -text "Minor Ticks" \
1912        -variable [itcl::scope _settings(-axisminorticks)] \
1913        -command [itcl::code $this AdjustSetting -axisminorticks] \
1914        -font "Arial 9"
1915
1916    label $inner.mode_l -text "Mode" -font "Arial 9"
1917
1918    itk_component add axisMode {
1919        Rappture::Combobox $inner.mode -width 10 -editable 0
1920    }
1921    $inner.mode choices insert end \
1922        "static_triad"    "static" \
1923        "closest_triad"   "closest" \
1924        "furthest_triad"  "farthest" \
1925        "outer_edges"     "outer"
1926    $itk_component(axisMode) value $_settings(-axismode)
1927    bind $inner.mode <<Value>> [itcl::code $this AdjustSetting -axismode]
1928
1929    blt::table $inner \
1930        0,0 $inner.visible    -anchor w -cspan 4 \
1931        1,0 $inner.labels     -anchor w -cspan 4 \
1932        2,0 $inner.minorticks -anchor w -cspan 4 \
1933        4,0 $inner.grid_l     -anchor w \
1934        4,1 $inner.xgrid      -anchor w \
1935        4,2 $inner.ygrid      -anchor w \
1936        4,3 $inner.zgrid      -anchor w \
1937        5,0 $inner.mode_l     -anchor w -padx { 2 0 } \
1938        5,1 $inner.mode       -fill x   -cspan 3
1939
1940    blt::table configure $inner r* c* -resize none
1941    blt::table configure $inner r7 c6 -resize expand
1942    blt::table configure $inner r3 -height 0.125i
1943}
1944
1945
1946itcl::body Rappture::VtkIsosurfaceViewer::BuildCameraTab {} {
1947    set inner [$itk_component(main) insert end \
1948        -title "Camera Settings" \
1949        -icon [Rappture::icon camera]]
1950    $inner configure -borderwidth 4
1951
1952    label $inner.view_l -text "view" -font "Arial 9"
1953    set f [frame $inner.view]
1954    foreach side { front back left right top bottom } {
1955        button $f.$side  -image [Rappture::icon view$side] \
1956            -command [itcl::code $this SetOrientation $side]
1957        Rappture::Tooltip::for $f.$side "Change the view to $side"
1958        pack $f.$side -side left
1959    }
1960
1961    blt::table $inner \
1962        0,0 $inner.view_l -anchor e -pady 2 \
1963        0,1 $inner.view -anchor w -pady 2
1964    blt::table configure $inner r0 -resize none
1965
1966    set labels { qx qy qz qw xpan ypan zoom }
1967    set row 1
1968    foreach tag $labels {
1969        label $inner.${tag}label -text $tag -font "Arial 9"
1970        entry $inner.${tag} -font "Arial 9"  -bg white \
1971            -textvariable [itcl::scope _view(-$tag)]
1972        bind $inner.${tag} <Return> \
1973            [itcl::code $this camera set -${tag}]
1974        bind $inner.${tag} <KP_Enter> \
1975            [itcl::code $this camera set -${tag}]
1976        blt::table $inner \
1977            $row,0 $inner.${tag}label -anchor e -pady 2 \
1978            $row,1 $inner.${tag} -anchor w -pady 2
1979        blt::table configure $inner r$row -resize none
1980        incr row
1981    }
1982    checkbutton $inner.ortho \
1983        -text "Orthographic Projection" \
1984        -variable [itcl::scope _view(-ortho)] \
1985        -command [itcl::code $this AdjustSetting -ortho] \
1986        -font "Arial 9"
1987    blt::table $inner \
1988            $row,0 $inner.ortho -cspan 2 -anchor w -pady 2
1989    blt::table configure $inner r$row -resize none
1990    incr row
1991
1992    blt::table configure $inner c* -resize none
1993    blt::table configure $inner c2 -resize expand
1994    blt::table configure $inner r$row -resize expand
1995}
1996
1997itcl::body Rappture::VtkIsosurfaceViewer::BuildCutplanesTab {} {
1998
1999    set fg [option get $itk_component(hull) font Font]
2000
2001    set inner [$itk_component(main) insert end \
2002        -title "Cutplane Settings" \
2003        -icon [Rappture::icon cutbutton]]
2004
2005    $inner configure -borderwidth 4
2006
2007    checkbutton $inner.visible \
2008        -text "Cutplanes" \
2009        -variable [itcl::scope _settings(-cutplanesvisible)] \
2010        -command [itcl::code $this AdjustSetting -cutplanesvisible] \
2011        -font "Arial 9"
2012
2013    checkbutton $inner.wireframe \
2014        -text "Wireframe" \
2015        -variable [itcl::scope _settings(-cutplanewireframe)] \
2016        -command [itcl::code $this AdjustSetting -cutplanewireframe] \
2017        -font "Arial 9"
2018
2019    checkbutton $inner.lighting \
2020        -text "Enable Lighting" \
2021        -variable [itcl::scope _settings(-cutplanelighting)] \
2022        -command [itcl::code $this AdjustSetting -cutplanelighting] \
2023        -font "Arial 9"
2024
2025    checkbutton $inner.edges \
2026        -text "Edges" \
2027        -variable [itcl::scope _settings(-cutplaneedges)] \
2028        -command [itcl::code $this AdjustSetting -cutplaneedges] \
2029        -font "Arial 9"
2030
2031    checkbutton $inner.preinterp \
2032        -text "Interpolate Scalars" \
2033        -variable [itcl::scope _settings(-cutplanepreinterp)] \
2034        -command [itcl::code $this AdjustSetting -cutplanepreinterp] \
2035        -font "Arial 9"
2036
2037    label $inner.opacity_l -text "Opacity" -font "Arial 9"
2038    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
2039        -variable [itcl::scope _widget(-cutplaneopacity)] \
2040        -width 10 \
2041        -showvalue off \
2042        -command [itcl::code $this AdjustSetting -cutplaneopacity]
2043    $inner.opacity set [expr $_settings(-cutplaneopacity) * 100.0]
2044
2045    # X-value slicer...
2046    itk_component add xbutton {
2047        Rappture::PushButton $inner.xbutton \
2048            -onimage [Rappture::icon x-cutplane-red] \
2049            -offimage [Rappture::icon x-cutplane-red] \
2050            -command [itcl::code $this AdjustSetting -xcutplanevisible] \
2051            -variable [itcl::scope _settings(-xcutplanevisible)] \
2052    }
2053    Rappture::Tooltip::for $itk_component(xbutton) \
2054        "Toggle the X-axis cutplane on/off"
2055    $itk_component(xbutton) select
2056    itk_component add xposition {
2057        ::scale $inner.xval -from 100 -to 0 \
2058            -width 10 -orient vertical -showvalue 1 \
2059            -borderwidth 1 -highlightthickness 0 \
2060            -command [itcl::code $this EventuallySetCutplane x] \
2061            -variable [itcl::scope _settings(-xcutplaneposition)] \
2062            -foreground red2 -font "Arial 9 bold"
2063    } {
2064        usual
2065        ignore -borderwidth -highlightthickness -foreground -font -background
2066    }
2067    # Set the default cutplane value before disabling the scale.
2068    $itk_component(xposition) set 50
2069    $itk_component(xposition) configure -state disabled
2070    Rappture::Tooltip::for $itk_component(xposition) \
2071        "@[itcl::code $this Slice tooltip x]"
2072
2073    # Y-value slicer...
2074    itk_component add ybutton {
2075        Rappture::PushButton $inner.ybutton \
2076            -onimage [Rappture::icon y-cutplane-green] \
2077            -offimage [Rappture::icon y-cutplane-green] \
2078            -command [itcl::code $this AdjustSetting -ycutplanevisible] \
2079            -variable [itcl::scope _settings(-ycutplanevisible)] \
2080    }
2081    Rappture::Tooltip::for $itk_component(ybutton) \
2082        "Toggle the Y-axis cutplane on/off"
2083    $itk_component(ybutton) select
2084
2085    itk_component add yposition {
2086        ::scale $inner.yval -from 100 -to 0 \
2087            -width 10 -orient vertical -showvalue 1 \
2088            -borderwidth 1 -highlightthickness 0 \
2089            -command [itcl::code $this EventuallySetCutplane y] \
2090            -variable [itcl::scope _settings(-ycutplaneposition)] \
2091            -foreground green3 -font "Arial 9 bold"
2092    } {
2093        usual
2094        ignore -borderwidth -highlightthickness -foreground -font
2095    }
2096    Rappture::Tooltip::for $itk_component(yposition) \
2097        "@[itcl::code $this Slice tooltip y]"
2098    # Set the default cutplane value before disabling the scale.
2099    $itk_component(yposition) set 50
2100    $itk_component(yposition) configure -state disabled
2101
2102    # Z-value slicer...
2103    itk_component add zbutton {
2104        Rappture::PushButton $inner.zbutton \
2105            -onimage [Rappture::icon z-cutplane-blue] \
2106            -offimage [Rappture::icon z-cutplane-blue] \
2107            -command [itcl::code $this AdjustSetting -zcutplanevisible] \
2108            -variable [itcl::scope _settings(-zcutplanevisible)] \
2109    } {
2110        usual
2111        ignore -foreground
2112    }
2113    Rappture::Tooltip::for $itk_component(zbutton) \
2114        "Toggle the Z-axis cutplane on/off"
2115    $itk_component(zbutton) select
2116
2117    itk_component add zposition {
2118        ::scale $inner.zval -from 100 -to 0 \
2119            -width 10 -orient vertical -showvalue 1 \
2120            -borderwidth 1 -highlightthickness 0 \
2121            -command [itcl::code $this EventuallySetCutplane z] \
2122            -variable [itcl::scope _settings(-zcutplaneposition)] \
2123            -foreground blue3 -font "Arial 9 bold"
2124    } {
2125        usual
2126        ignore -borderwidth -highlightthickness -foreground -font
2127    }
2128    $itk_component(zposition) set 50
2129    $itk_component(zposition) configure -state disabled
2130    Rappture::Tooltip::for $itk_component(zposition) \
2131        "@[itcl::code $this Slice tooltip z]"
2132
2133    blt::table $inner \
2134        0,0 $inner.visible   -anchor w -pady 2 -cspan 3 \
2135        1,0 $inner.lighting  -anchor w -pady 2 -cspan 3 \
2136        2,0 $inner.wireframe -anchor w -pady 2 -cspan 3 \
2137        3,0 $inner.edges     -anchor w -pady 2 -cspan 3 \
2138        4,0 $inner.preinterp -anchor w -pady 2 -cspan 3 \
2139        5,0 $inner.opacity_l -anchor w -pady 2 -cspan 1 \
2140        5,1 $inner.opacity   -fill x   -pady 2 -cspan 3 \
2141        6,0 $inner.xbutton   -anchor w -padx 2 -pady 2 \
2142        7,0 $inner.ybutton   -anchor w -padx 2 -pady 2 \
2143        8,0 $inner.zbutton   -anchor w -padx 2 -pady 2 \
2144        6,1 $inner.xval      -fill y -rspan 4 \
2145        6,2 $inner.yval      -fill y -rspan 4 \
2146        6,3 $inner.zval      -fill y -rspan 4 \
2147
2148    blt::table configure $inner r* c* -resize none
2149    blt::table configure $inner r9 c4 -resize expand
2150}
2151
2152#
2153# camera --
2154#
2155itcl::body Rappture::VtkIsosurfaceViewer::camera {option args} {
2156    switch -- $option {
2157        "show" {
2158            puts [array get _view]
2159        }
2160        "set" {
2161            set what [lindex $args 0]
2162            set x $_view($what)
2163            set code [catch { string is double $x } result]
2164            if { $code != 0 || !$result } {
2165                return
2166            }
2167            switch -- $what {
2168                "-ortho" {
2169                    if {$_view($what)} {
2170                        SendCmd "camera mode ortho"
2171                    } else {
2172                        SendCmd "camera mode persp"
2173                    }
2174                }
2175                "-xpan" - "-ypan" {
2176                    PanCamera
2177                }
2178                "-qx" - "-qy" - "-qz" - "-qw" {
2179                    set q [ViewToQuaternion]
2180                    $_arcball quaternion $q
2181                    EventuallyRotate $q
2182                }
2183                "-zoom" {
2184                    SendCmd "camera zoom $_view($what)"
2185                }
2186             }
2187        }
2188    }
2189}
2190
2191itcl::body Rappture::VtkIsosurfaceViewer::GetVtkData { args } {
2192    set bytes ""
2193    foreach dataobj [get] {
2194        foreach cname [$dataobj components] {
2195            set tag $dataobj-$cname
2196            set contents [$dataobj vtkdata $cname]
2197            append bytes "$contents\n"
2198        }
2199    }
2200    return [list .vtk $bytes]
2201}
2202
2203itcl::body Rappture::VtkIsosurfaceViewer::GetImage { args } {
2204    if { [image width $_image(download)] > 0 &&
2205         [image height $_image(download)] > 0 } {
2206        set bytes [$_image(download) data -format "jpeg -quality 100"]
2207        set bytes [Rappture::encoding::decode -as b64 $bytes]
2208        return [list .jpg $bytes]
2209    }
2210    return ""
2211}
2212
2213itcl::body Rappture::VtkIsosurfaceViewer::BuildDownloadPopup { popup command } {
2214    Rappture::Balloon $popup \
2215        -title "[Rappture::filexfer::label downloadWord] as..."
2216    set inner [$popup component inner]
2217    label $inner.summary -text "" -anchor w
2218    radiobutton $inner.vtk_button -text "VTK data file" \
2219        -variable [itcl::scope _downloadPopup(format)] \
2220        -font "Arial 9 " \
2221        -value vtk
2222    Rappture::Tooltip::for $inner.vtk_button "Save as VTK data file."
2223    radiobutton $inner.image_button -text "Image File" \
2224        -variable [itcl::scope _downloadPopup(format)] \
2225        -font "Arial 9 " \
2226        -value image
2227    Rappture::Tooltip::for $inner.image_button \
2228        "Save as digital image."
2229
2230    button $inner.ok -text "Save" \
2231        -highlightthickness 0 -pady 2 -padx 3 \
2232        -command $command \
2233        -compound left \
2234        -image [Rappture::icon download]
2235
2236    button $inner.cancel -text "Cancel" \
2237        -highlightthickness 0 -pady 2 -padx 3 \
2238        -command [list $popup deactivate] \
2239        -compound left \
2240        -image [Rappture::icon cancel]
2241
2242    blt::table $inner \
2243        0,0 $inner.summary -cspan 2  \
2244        1,0 $inner.vtk_button -anchor w -cspan 2 -padx { 4 0 } \
2245        2,0 $inner.image_button -anchor w -cspan 2 -padx { 4 0 } \
2246        4,1 $inner.cancel -width .9i -fill y \
2247        4,0 $inner.ok -padx 2 -width .9i -fill y
2248    blt::table configure $inner r3 -height 4
2249    blt::table configure $inner r4 -pady 4
2250    raise $inner.image_button
2251    $inner.vtk_button invoke
2252    return $inner
2253}
2254
2255itcl::body Rappture::VtkIsosurfaceViewer::SetObjectStyle { dataobj comp } {
2256    DebugTrace "Enter"
2257    # Parse style string.
2258    set tag $dataobj-$comp
2259    array set style {
2260        -color                  BCGYR
2261        -cutplaneedges          0
2262        -cutplanelighting       1
2263        -cutplaneopacity        1.0
2264        -cutplanepreinterp      1
2265        -cutplanesvisible       0
2266        -cutplanewireframe      0
2267        -edgecolor              black
2268        -edges                  0
2269        -isosurfacevisible      1
2270        -levels                 10
2271        -lighting               1
2272        -linewidth              1.0
2273        -opacity                0.6
2274        -outline                0
2275        -wireframe              0
2276        -xcutplaneposition      50
2277        -xcutplanevisible       1
2278        -ycutplaneposition      50
2279        -ycutplanevisible       1
2280        -zcutplaneposition      50
2281        -zcutplanevisible       1
2282    }
2283    if { $style(-levels) == 1 } {
2284        set style(-opacity) 1.0
2285    }
2286    array set style [$dataobj style $comp]
2287    #DebugTrace [array get style]
2288
2289    # This is too complicated.  We want to set the colormap, number of
2290    # isolines and opacity for the dataset.  They can be the default values,
2291    # the style hints loaded with the dataset, or set by user controls.  As
2292    # datasets get loaded, they first use the defaults that are overidden
2293    # by the style hints.  If the user changes the global controls, then that
2294    # overrides everything else.  I don't know what it means when global
2295    # controls are specified as style hints by each dataset.  It complicates
2296    # the code to handle aberrant cases.
2297
2298    if { $_changed(-isosurfaceedges) } {
2299        set style(-edges) $_settings(-isosurfaceedges)
2300    }
2301    if { $_changed(-isosurfacelighting) } {
2302        set style(-lighting) $_settings(-isosurfacelighting)
2303    }
2304    if { $_changed(-isosurfaceopacity) } {
2305        set style(-opacity) $_settings(-isosurfaceopacity)
2306    }
2307    if { $_changed(-isosurfacewireframe) } {
2308        set style(-wireframe) $_settings(-isosurfacewireframe)
2309    }
2310    if { $_changed(-numcontours) } {
2311        set style(-levels) $_settings(-numcontours)
2312    }
2313    if { $_changed(-colormap) } {
2314        set style(-color) $_settings(-colormap)
2315    }
2316    if { $_currentColormap == "" } {
2317        SetCurrentColormap $style(-color)
2318        $itk_component(colormap) value $style(-color)
2319    }
2320    if { $_contourList(numLevels) != $style(-levels) } {
2321        if { [llength $style(-levels)] > 1 } {
2322            set _contourList(reqValues) [lsort -real $style(-levels)]
2323        } else {
2324            set _settings(-numcontours) $style(-levels)
2325            $itk_component(numcontours) value $style(-levels)
2326            set _contourList(numLevels) $style(-levels)
2327        }
2328        EventuallyChangeContourLevels
2329    }
2330    foreach setting {-outline -isosurfacevisible -cutplanesvisible \
2331                     -xcutplanevisible -ycutplanevisible -zcutplanevisible \
2332                     -xcutplaneposition -ycutplaneposition -zcutplaneposition \
2333                     -cutplaneedges -cutplanelighting -cutplaneopacity \
2334                     -cutplanepreinterp -cutplanewireframe} {
2335        if {$_changed($setting)} {
2336            # User-modified UI setting overrides style
2337            set style($setting) $_settings($setting)
2338        } else {
2339            # Set UI control to style setting (tool provided or default)
2340            set _settings($setting) $style($setting)
2341        }
2342    }
2343
2344    SendCmd "cutplane add $tag"
2345    SendCmd "cutplane color [Color2RGB $itk_option(-plotforeground)] $tag"
2346    foreach axis {x y z} {
2347        set pos [expr $style(-${axis}cutplaneposition) * 0.01]
2348        set visible $style(-${axis}cutplanevisible)
2349        SendCmd "cutplane slice $axis $pos $tag"
2350        SendCmd "cutplane axis $axis $visible $tag"
2351    }
2352    SendCmd "cutplane edges $style(-cutplaneedges) $tag"
2353    SendCmd "cutplane lighting $style(-cutplanelighting) $tag"
2354    SendCmd "cutplane opacity $style(-cutplaneopacity) $tag"
2355    set _widget(-cutplaneopacity) [expr $style(-cutplaneopacity) * 100]
2356    SendCmd "cutplane preinterp $style(-cutplanepreinterp) $tag"
2357    SendCmd "cutplane wireframe $style(-cutplanewireframe) $tag"
2358    SendCmd "cutplane visible $style(-cutplanesvisible) $tag"
2359
2360    SendCmd "outline add $tag"
2361    SendCmd "outline color [Color2RGB $itk_option(-plotforeground)] $tag"
2362    SendCmd "outline visible $style(-outline) $tag"
2363
2364    GenerateContourList
2365    SendCmd [list contour3d add contourlist $_contourList(values) $tag]
2366    SendCmd "contour3d visible $style(-isosurfacevisible) $tag"
2367    SendCmd "contour3d edges $style(-edges) $tag"
2368    set _settings(-isosurfaceedges) $style(-edges)
2369    #SendCmd "contour3d color [Color2RGB $style(-color)] $tag"
2370    SendCmd "contour3d lighting $style(-lighting) $tag"
2371    set _settings(-isosurfacelighting) $style(-lighting)
2372    SendCmd "contour3d linecolor [Color2RGB $style(-edgecolor)] $tag"
2373    SendCmd "contour3d linewidth $style(-linewidth) $tag"
2374    SendCmd "contour3d opacity $style(-opacity) $tag"
2375    set _settings(-isosurfaceopacity) $style(-opacity)
2376    set _widget(-isosurfaceopacity) [expr $style(-opacity) * 100]
2377    SetCurrentColormap $style(-color)
2378    SendCmd "contour3d wireframe $style(-wireframe) $tag"
2379    set _settings(-isosurfacewireframe) $style(-wireframe)
2380}
2381
2382itcl::body Rappture::VtkIsosurfaceViewer::IsValidObject { dataobj } {
2383    if {[catch {$dataobj isa Rappture::Field} valid] != 0 || !$valid} {
2384        return 0
2385    }
2386    return 1
2387}
2388
2389#
2390# EnterLegend --
2391#
2392itcl::body Rappture::VtkIsosurfaceViewer::EnterLegend { x y } {
2393    SetLegendTip $x $y
2394}
2395
2396#
2397# MotionLegend --
2398#
2399itcl::body Rappture::VtkIsosurfaceViewer::MotionLegend { x y } {
2400    Rappture::Tooltip::tooltip cancel
2401    set c $itk_component(view)
2402    set cw [winfo width $c]
2403    set ch [winfo height $c]
2404    if { $x >= 0 && $x < $cw && $y >= 0 && $y < $ch } {
2405        SetLegendTip $x $y
2406    }
2407}
2408
2409#
2410# LeaveLegend --
2411#
2412itcl::body Rappture::VtkIsosurfaceViewer::LeaveLegend { } {
2413    Rappture::Tooltip::tooltip cancel
2414    .rappturetooltip configure -icon ""
2415}
2416
2417# ----------------------------------------------------------------------
2418# USAGE: LegendB1Motion press <x> <y>
2419# USAGE: LegendB1Motion motion <x> <y>
2420# USAGE: LegendB1Motion release <x> <y>
2421#
2422# Manage actions for Button 1 presses that happen over the legend.
2423# Pressing mouse Button 1 on the legend sends a command to the
2424# visualization server to show a specific isosurface.
2425# ----------------------------------------------------------------------
2426itcl::body Rappture::VtkIsosurfaceViewer::LegendB1Motion { status x y } {
2427
2428    switch -- $status {
2429        "press" {
2430            DisableMouseRotationBindings
2431            LegendProbeSingleContour $x $y
2432        }
2433        "motion" {
2434            DisableMouseRotationBindings
2435            LegendProbeSingleContour $x $y
2436        }
2437        "release" {
2438            AdjustSetting -range
2439            SetupMouseRotationBindings
2440        }
2441        default {
2442            error "bad option \"$option\": should be one of press, motion, release."
2443        }
2444    }
2445}
2446
2447# ----------------------------------------------------------------------
2448# USAGE: LegendPointToValue <x> <y>
2449#
2450# Convert an x,y point on the legend to a numeric field value.
2451# ----------------------------------------------------------------------
2452itcl::body Rappture::VtkIsosurfaceViewer::LegendPointToValue { x y } {
2453    set fname $_curFldName
2454
2455    set font "Arial 8"
2456    set lineht [font metrics $font -linespace]
2457
2458    set ih [image height $_image(legend)]
2459    set iy [expr $y - ($lineht + 2)]
2460
2461    # Compute the value of the point
2462    if { [info exists _limits($fname)] } {
2463        if { $_settings(-customrange) } {
2464            set vmin [$itk_component(min) value]
2465            set vmax [$itk_component(max) value]
2466        } else {
2467            foreach { vmin vmax } $_limits($fname) break
2468        }
2469        set t [expr 1.0 - (double($iy) / double($ih-1))]
2470        set value [expr $t * ($vmax - $vmin) + $vmin]
2471    } else {
2472        set value 0.0
2473    }
2474    return $value
2475}
2476
2477# ----------------------------------------------------------------------
2478# USAGE: LegendProbeSingleContour <x> <y>
2479#
2480# Calculate the isosurface value for the x,y point and send a commands
2481# to the visualization server to show that isosurface.
2482# ----------------------------------------------------------------------
2483itcl::body Rappture::VtkIsosurfaceViewer::LegendProbeSingleContour { x y } {
2484
2485    set value [LegendPointToValue $x $y]
2486    SendCmd [list contour3d contourlist $value]
2487}
2488
2489#
2490# SetLegendTip --
2491#
2492itcl::body Rappture::VtkIsosurfaceViewer::SetLegendTip { x y } {
2493    set fname $_curFldName
2494    set c $itk_component(view)
2495    set w [winfo width $c]
2496    set h [winfo height $c]
2497
2498    set font "Arial 8"
2499    set lineht [font metrics $font -linespace]
2500
2501    set ih [image height $_image(legend)]
2502    set iy [expr $y - ($lineht + 2)]
2503
2504    if { [string match "component*" $fname] } {
2505        set title ""
2506    } else {
2507        if { [info exists _fields($fname)] } {
2508            foreach { title units } $_fields($fname) break
2509            if { $units != "" } {
2510                set title [format "%s (%s)" $title $units]
2511            }
2512        } else {
2513            set title $fname
2514        }
2515    }
2516    # If there's a legend title, increase the offset by the line height.
2517    if { $title != "" } {
2518        incr iy -$lineht
2519    }
2520    # Make a swatch of the selected color
2521    if { [catch { $_image(legend) get 10 $iy } pixel] != 0 } {
2522        return
2523    }
2524    if { ![info exists _image(swatch)] } {
2525        set _image(swatch) [image create photo -width 24 -height 24]
2526    }
2527    set color [eval format "\#%02x%02x%02x" $pixel]
2528    $_image(swatch) put black  -to 0 0 23 23
2529    $_image(swatch) put $color -to 1 1 22 22
2530    .rappturetooltip configure -icon $_image(swatch)
2531
2532    # Compute the value of the point
2533    set value [LegendPointToValue $x $y]
2534
2535    # Setup the location of the tooltip
2536    set tx [expr $x + 15]
2537    set ty [expr $y - 5]
2538
2539    # Setup the text for the tooltip
2540    if { [info exists _isolines($y)] } {
2541        Rappture::Tooltip::text $c [format "$title %g (isosurface)" $_isolines($y)]
2542    } else {
2543        Rappture::Tooltip::text $c [format "$title %g" $value]
2544    }
2545
2546    # Show the tooltip
2547    Rappture::Tooltip::tooltip show $c +$tx,+$ty
2548}
2549
2550# ----------------------------------------------------------------------
2551# USAGE: Slice move x|y|z <newval>
2552#
2553# Called automatically when the user drags the slider to move the
2554# cut plane that slices 3D data.  Gets the current value from the
2555# slider and moves the cut plane to the appropriate point in the
2556# data set.
2557# ----------------------------------------------------------------------
2558itcl::body Rappture::VtkIsosurfaceViewer::Slice {option args} {
2559    switch -- $option {
2560        "move" {
2561            set axis [lindex $args 0]
2562            set newval [lindex $args 1]
2563            if {[llength $args] != 2} {
2564                error "wrong # args: should be \"Slice move x|y|z newval\""
2565            }
2566            set newpos [expr {0.01*$newval}]
2567            SendCmd "cutplane slice $axis $newpos"
2568        }
2569        "tooltip" {
2570            set axis [lindex $args 0]
2571            set val [$itk_component(${axis}position) get]
2572            return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
2573        }
2574        default {
2575            error "bad option \"$option\": should be axis, move, or tooltip"
2576        }
2577    }
2578}
2579
2580#
2581# ReceiveLegend --
2582#
2583# Invoked automatically whenever the "legend" command comes in from
2584# the rendering server.  Indicates that binary image data with the
2585# specified <size> will follow.
2586#
2587itcl::body Rappture::VtkIsosurfaceViewer::ReceiveLegend { colormap title min max size } {
2588    DebugTrace "Enter"
2589    set _title $title
2590    regsub {\(mag\)} $title "" _title
2591    if { [IsConnected] } {
2592        set bytes [ReceiveBytes $size]
2593        if { ![info exists _image(legend)] } {
2594            set _image(legend) [image create photo]
2595        }
2596        $_image(legend) configure -data $bytes
2597        #puts stderr "read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
2598        if { [catch {DrawLegend} errs] != 0 } {
2599            global errorInfo
2600            puts stderr "errs=$errs errorInfo=$errorInfo"
2601        }
2602    }
2603}
2604
2605#
2606# DrawLegend --
2607#
2608# Draws the legend on the canvas on the right side of the plot area.
2609#
2610itcl::body Rappture::VtkIsosurfaceViewer::DrawLegend {} {
2611    set fname $_curFldName
2612    set c $itk_component(view)
2613    set w [winfo width $c]
2614    set h [winfo height $c]
2615    set font "Arial 8"
2616    set lineht [font metrics $font -linespace]
2617
2618    if { [string match "component*" $fname] } {
2619        set title ""
2620    } else {
2621        if { [info exists _fields($fname)] } {
2622            foreach { title units } $_fields($fname) break
2623            if { $units != "" } {
2624                set title [format "%s (%s)" $title $units]
2625            }
2626        } else {
2627            set title $fname
2628        }
2629    }
2630    set x [expr $w - 2]
2631    if { !$_settings(-legendvisible) } {
2632        $c delete legend
2633        return
2634    }
2635    if { [$c find withtag "legend"] == "" } {
2636        set y 2
2637        # If there's a legend title, create a text item for the title.
2638        $c create text $x $y \
2639            -anchor ne \
2640            -fill $itk_option(-plotforeground) -tags "title legend" \
2641            -font $font
2642        if { $title != "" } {
2643            incr y $lineht
2644        }
2645        $c create text $x $y \
2646            -anchor ne \
2647            -fill $itk_option(-plotforeground) -tags "vmax legend" \
2648            -font $font
2649        incr y $lineht
2650        $c create image $x $y \
2651            -anchor ne \
2652            -image $_image(legend) -tags "colormap legend"
2653        $c create rectangle $x $y 1 1 \
2654            -fill "" -outline "" -tags "sensor legend"
2655        $c create text $x [expr {$h-2}] \
2656            -anchor se \
2657            -fill $itk_option(-plotforeground) -tags "vmin legend" \
2658            -font $font
2659        $c bind sensor <Enter> [itcl::code $this EnterLegend %x %y]
2660        $c bind sensor <Leave> [itcl::code $this LeaveLegend]
2661        $c bind sensor <Motion> [itcl::code $this MotionLegend %x %y]
2662#        $c bind sensor <ButtonPress-1>   [itcl::code $this LegendB1Motion press %x %y]
2663#        $c bind sensor <B1-Motion>       [itcl::code $this LegendB1Motion motion %x %y]
2664#        $c bind sensor <ButtonRelease-1> [itcl::code $this LegendB1Motion release %x %y]
2665    }
2666    $c delete isoline
2667    set x2 $x
2668    set iw [image width $_image(legend)]
2669    set ih [image height $_image(legend)]
2670    set x1 [expr $x2 - ($iw*12)/10]
2671    set color $_settings(-isolinecolor)
2672    # Draw the isolines on the legend.
2673    array unset _isolines
2674    if { $color != "none"  && [info exists _limits($_curFldName)] &&
2675         $_settings(-numcontours) > 0 } {
2676
2677        if { $_settings(-customrange) } {
2678            set vmin [$itk_component(min) value]
2679            set vmax [$itk_component(max) value]
2680        } else {
2681            foreach { vmin vmax } $_limits($_curFldName) break
2682        }
2683        set range [expr double($vmax - $vmin)]
2684        if { $range <= 0.0 } {
2685            set range 1.0;              # Min is greater or equal to max.
2686        }
2687        set tags "isoline legend"
2688        set offset [expr 2 + $lineht]
2689        if { $title != "" } {
2690            incr offset $lineht
2691        }
2692        foreach value $_contourList(values) {
2693            set norm [expr 1.0 - (($value - $vmin) / $range)]
2694            set y1 [expr int(round(($norm * $ih) + $offset))]
2695            for { set off 0 } { $off < 3 } { incr off } {
2696                set _isolines([expr $y1 + $off]) $value
2697                set _isolines([expr $y1 - $off]) $value
2698            }
2699            $c create line $x1 $y1 $x2 $y1 -fill $color -tags $tags
2700        }
2701    }
2702
2703    $c bind title <ButtonPress> [itcl::code $this LegendTitleAction post]
2704    $c bind title <Enter> [itcl::code $this LegendTitleAction enter]
2705    $c bind title <Leave> [itcl::code $this LegendTitleAction leave]
2706    # Reset the item coordinates according the current size of the plot.
2707    $c itemconfigure title -text $title
2708    if { [info exists _limits($_curFldName)] } {
2709        if { $_settings(-customrange) } {
2710            set vmin [$itk_component(min) value]
2711            set vmax [$itk_component(max) value]
2712        } else {
2713            foreach { vmin vmax } $_limits($_curFldName) break
2714        }
2715        $c itemconfigure vmin -text [format %g $vmin]
2716        $c itemconfigure vmax -text [format %g $vmax]
2717    }
2718    set y 2
2719    # If there's a legend title, move the title to the correct position
2720    if { $title != "" } {
2721        $c itemconfigure title -text $title
2722        $c coords title $x $y
2723        incr y $lineht
2724        $c raise title
2725    }
2726    $c coords vmax $x $y
2727    incr y $lineht
2728    $c coords colormap $x $y
2729    $c coords sensor [expr $x - $iw] $y $x [expr $y + $ih]
2730    $c raise sensor
2731    $c coords vmin $x [expr {$h - 2}]
2732
2733    $c bind vmin <ButtonPress> [itcl::code $this LegendRangeAction popup vmin]
2734    $c bind vmin <Enter> [itcl::code $this LegendRangeAction enter vmin]
2735    $c bind vmin <Leave> [itcl::code $this LegendRangeAction leave vmin]
2736
2737    $c bind vmax <ButtonPress> [itcl::code $this LegendRangeAction popup vmax]
2738    $c bind vmax <Enter> [itcl::code $this LegendRangeAction enter vmax]
2739    $c bind vmax <Leave> [itcl::code $this LegendRangeAction leave vmax]
2740}
2741
2742# ----------------------------------------------------------------------
2743# USAGE: LegendTitleAction post
2744# USAGE: LegendTitleAction enter
2745# USAGE: LegendTitleAction leave
2746# USAGE: LegendTitleAction save
2747#
2748# Used internally to handle the dropdown list for the fields menu combobox.
2749# The post option is invoked when the field title is pressed to launch the
2750# dropdown.  The enter option is invoked when the user mouses over the field
2751# title. The leave option is invoked when the user moves the mouse away
2752# from the field title.  The save option is invoked whenever there is a
2753# selection from the list, to alert the visualization server.
2754# ----------------------------------------------------------------------
2755itcl::body Rappture::VtkIsosurfaceViewer::LegendTitleAction {option} {
2756    set c $itk_component(view)
2757    switch -- $option {
2758        post {
2759            foreach { x1 y1 x2 y2 } [$c bbox title] break
2760            set cw [winfo width $itk_component(view)]
2761            set mw [winfo reqwidth $itk_component(fieldmenu)]
2762            set x1 [expr $cw - $mw]
2763            set x [expr $x1 + [winfo rootx $itk_component(view)]]
2764            set y [expr $y2 + [winfo rooty $itk_component(view)]]
2765            tk_popup $itk_component(fieldmenu) $x $y
2766        }
2767        enter {
2768            $c itemconfigure title -fill red
2769        }
2770        leave {
2771            $c itemconfigure title -fill $itk_option(-plotforeground)
2772        }
2773        save {
2774            $itk_component(field) value $_curFldLabel
2775            AdjustSetting -field
2776        }
2777        default {
2778            error "bad option \"$option\": should be post, enter, leave or save"
2779        }
2780    }
2781}
2782
2783# ----------------------------------------------------------------------
2784# USAGE: LegendRangeValidate <widget> <which> <value>
2785#
2786# Used internally to validate a legend range min/max value.
2787# Returns a boolean value telling if <value> was accepted (1) or rejected (0)
2788# If the value is rejected, a tooltip/warning message is popped up
2789# near the widget that asked for the validation, specified by <widget>
2790#
2791# <widget> is the widget where a tooltip/warning message should show up on
2792# <which> is either "vmin" or "vmax".
2793# <value> is the value to be validated.
2794# ----------------------------------------------------------------------
2795itcl::body Rappture::VtkIsosurfaceViewer::LegendRangeValidate {widget which value} {
2796    #check for a valid value
2797    if {[string is double $value] != 1} {
2798        set msg "should be valid number"
2799        if {$widget != ""} {
2800            Rappture::Tooltip::cue $widget $msg
2801        } else {
2802            # error "bad value \"$value\": $msg"
2803            error $msg
2804        }
2805        return 0
2806    }
2807
2808    switch -- $which {
2809        vmin {
2810            # check for min > max
2811            if {$value > [$itk_component(max) value]} {
2812                set msg "min > max, change max first"
2813                if {$widget != ""} {
2814                    Rappture::Tooltip::cue $widget $msg
2815                } else {
2816                    # error "bad value \"$value\": $msg"
2817                    error $msg
2818                }
2819                return 0
2820            }
2821        }
2822        vmax {
2823            # check for max < min
2824            if {$value < [$itk_component(min) value]} {
2825                set msg "max < min, change min first"
2826                if {$widget != ""} {
2827                    Rappture::Tooltip::cue $widget $msg
2828                } else {
2829                    # error "bad value \"$value\": $msg"
2830                    error $msg
2831                }
2832                return 0
2833            }
2834        }
2835        default {
2836            error "bad option \"$which\": should be vmin, vmax"
2837        }
2838    }
2839}
2840
2841itcl::body Rappture::VtkIsosurfaceViewer::MouseOver2Which {} {
2842    switch -- $_mouseOver {
2843        vmin {
2844            set which min
2845        }
2846        vmax {
2847            set which max
2848        }
2849        default {
2850            error "bad _mouseOver \"$_mouseOver\": should be vmin, vmax"
2851        }
2852    }
2853    return $which
2854}
2855
2856# ----------------------------------------------------------------------
2857# USAGE: LegendRangeAction enter <which>
2858# USAGE: LegendRangeAction leave <which>
2859#
2860# USAGE: LegendRangeAction popup <which>
2861# USAGE: LegendRangeAction activate
2862# USAGE: LegendRangeAction validate <value>
2863# USAGE: LegendRangeAction apply <value>
2864#
2865# Used internally to handle the mouseover and popup entry for the field range
2866# inputs.  The enter option is invoked when the user moves the mouse over the
2867# min or max field range. The leave option is invoked when the user moves the
2868# mouse away from the min or max field range. The popup option is invoked when
2869# the user click's on a field range. The popup option stores internally which
2870# widget is requesting a popup ( in the _mouseOver variable) and calls the
2871# activate command of the widget. The widget's activate command calls back to
2872# this method to get the xywh dimensions of the popup editor. After the user
2873# changes focus or sets the value in the editor, the editor calls this methods
2874# validate and apply options to set the value.
2875# ----------------------------------------------------------------------
2876itcl::body Rappture::VtkIsosurfaceViewer::LegendRangeAction {option args} {
2877    set c $itk_component(view)
2878
2879    switch -- $option {
2880        enter {
2881            set which [lindex $args 0]
2882            $c itemconfigure $which -fill red
2883        }
2884        leave {
2885            set which [lindex $args 0]
2886            $c itemconfigure $which -fill $itk_option(-plotforeground)
2887        }
2888        popup {
2889            DisableMouseRotationBindings
2890            set which [lindex $args 0]
2891            set _mouseOver $which
2892            $itk_component(editor) activate
2893        }
2894        activate {
2895            foreach { x1 y1 x2 y2 } [$c bbox $_mouseOver] break
2896            set which [MouseOver2Which]
2897            set info(text) [$itk_component($which) value]
2898            set info(x) [expr $x1 + [winfo rootx $c]]
2899            set info(y) [expr $y1 + [winfo rooty $c]]
2900            set info(w) [expr $x2 - $x1]
2901            set info(h) [expr $y2 - $y1]
2902            return [array get info]
2903        }
2904        validate {
2905            if {[llength $args] != 1} {
2906                error "wrong # args: should be \"editor validate value\""
2907            }
2908
2909            set value [lindex $args 0]
2910            if {[LegendRangeValidate $itk_component(editor) $_mouseOver $value] == 0} {
2911                return 0
2912            }
2913
2914            # value was good, apply it
2915            # reset the mouse rotation bindings
2916            SetupMouseRotationBindings
2917        }
2918        apply {
2919            if {[llength $args] != 1} {
2920                error "wrong # args: should be \"editor apply value\""
2921            }
2922            set value [string trim [lindex $args 0]]
2923
2924            set which [MouseOver2Which]
2925
2926            # only set custom range if value changed
2927            if {[$itk_component($which) value] != $value} {
2928                # set the flag stating the custom range came from the legend
2929                # change the value in the gauge
2930                # turn on crange to enable the labels and gauges
2931                # call AdjustSetting -range (inside ToggleCustomRange)
2932                # to update drawing and legend
2933                set _customRangeClick 0
2934                $itk_component($which) value $value
2935                $itk_component(crange) select
2936                ToggleCustomRange
2937            }
2938        }
2939        default {
2940            error "bad option \"$option\": should be enter, leave, activate, validate, apply"
2941        }
2942    }
2943}
2944
2945# ----------------------------------------------------------------------
2946# USAGE: ToggleCustomRange
2947#
2948# Called whenever the custom range is turned on or off. Used to save
2949# the custom min and custom max set by the user. When the -customrange
2950# setting is turned on, the range min and range max gauges are set
2951# with the last value set by the user, or the default range if no
2952# previous min and max were set.
2953#
2954# When the custom range is turned on, we check how it was turned on
2955# by querying _customRangeClick. If the variable is 1, this means
2956# the user clicked the crange checkbutton and we should pull the
2957# custom range values from our backup variables. If the variable is 0,
2958# the custom range was enabled through the user manipulating the
2959# min and max value in the legend.
2960# ----------------------------------------------------------------------
2961itcl::body Rappture::VtkIsosurfaceViewer::ToggleCustomRange {args} {
2962    if { ! $_settings(-customrange) } {
2963        # custom range was turned off
2964
2965        # disable the min/max labels and gauge widgets
2966        $itk_component(l_min) configure -state disabled
2967        $itk_component(min) configure -state disabled
2968        $itk_component(l_max) configure -state disabled
2969        $itk_component(max) configure -state disabled
2970
2971        # backup the custom range
2972        set _settings(-customrangemin) [$itk_component(min) value]
2973        set _settings(-customrangemax) [$itk_component(max) value]
2974
2975        # set the gauges to dataset's min and max
2976        foreach { vmin vmax } $_limits($_curFldName) break
2977        SetMinMaxGauges $vmin $vmax
2978    } else {
2979        # custom range was turned on
2980
2981        # enable the min/max labels and gauge widgets
2982        $itk_component(l_min) configure -state normal
2983        $itk_component(min) configure -state normal
2984        $itk_component(l_max) configure -state normal
2985        $itk_component(max) configure -state normal
2986
2987        # if the custom range is being turned on by clicking the
2988        # checkbox, restore the min and max gauges from the backup
2989        # variables. otherwise, new values for the min and max
2990        # widgets will be set later from the legend's editor.
2991        if { $_customRangeClick } {
2992            SetMinMaxGauges $_settings(-customrangemin) $_settings(-customrangemax)
2993        }
2994
2995        # reset the click flag
2996        set _customRangeClick 1
2997    }
2998    AdjustSetting -range
2999}
3000
3001# ----------------------------------------------------------------------
3002# USAGE: SetMinMaxGauges <min> <max>
3003#
3004# Set the min and max gauges in the correct order, avoiding the
3005# error where you try to set the min > max before updating the max or
3006# set the max < min before updating the min.
3007#
3008# There are five range cases to consider with our current range validation.
3009# For example:
3010# [2,3] -> [0,1]       : update min first, max last
3011# [2,3] -> [4,5]       : update max first, min last
3012# [2,3] -> [0,2.5]     : update min or max first
3013# [2,3] -> [2.5,5]     : update min or max first
3014# [2,3] -> [2.25,2.75] : update min or max first
3015#
3016# In 4 of the cases we can update min first and max last, so we only
3017# need to check the case where old max < new min, where we update
3018# max first and min last.
3019# ----------------------------------------------------------------------
3020itcl::body Rappture::VtkIsosurfaceViewer::SetMinMaxGauges {min max} {
3021
3022    if { [$itk_component(max) value] < $min} {
3023        # old max < new min
3024        # shift range toward right
3025        # extend max first, then update min
3026        $itk_component(max) value $max
3027        $itk_component(min) value $min
3028    } else {
3029        # extend min first, then update max
3030        $itk_component(min) value $min
3031        $itk_component(max) value $max
3032    }
3033}
3034
3035#
3036# SetCurrentColormap --
3037#
3038itcl::body Rappture::VtkIsosurfaceViewer::SetCurrentColormap { name } {
3039    # Keep track of the colormaps that we build.
3040    if { ![info exists _colormaps($name)] } {
3041        BuildColormap $name
3042        set _colormaps($name) 1
3043    }
3044    set _currentColormap $name
3045    SendCmd "contour3d colormap $_currentColormap"
3046    SendCmd "cutplane colormap $_currentColormap"
3047}
3048
3049#
3050# BuildColormap --
3051#
3052# Build the designated colormap on the server.
3053#
3054itcl::body Rappture::VtkIsosurfaceViewer::BuildColormap { name } {
3055    set cmap [ColorsToColormap $name]
3056    if { [llength $cmap] == 0 } {
3057        set cmap "0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0"
3058    }
3059    set amap "0.0 1.0 1.0 1.0"
3060    SendCmd "colormap add $name { $cmap } { $amap }"
3061}
3062
3063itcl::body Rappture::VtkIsosurfaceViewer::SetOrientation { side } {
3064    array set positions {
3065        front "1 0 0 0"
3066        back  "0 0 1 0"
3067        left  "0.707107 0 -0.707107 0"
3068        right "0.707107 0 0.707107 0"
3069        top   "0.707107 -0.707107 0 0"
3070        bottom "0.707107 0.707107 0 0"
3071    }
3072    foreach name { -qw -qx -qy -qz } value $positions($side) {
3073        set _view($name) $value
3074    }
3075    set q [ViewToQuaternion]
3076    $_arcball quaternion $q
3077    SendCmd "camera orient $q"
3078    SendCmd "camera reset"
3079    set _view(-xpan) 0
3080    set _view(-ypan) 0
3081    set _view(-zoom) 1.0
3082}
3083
3084itcl::body Rappture::VtkIsosurfaceViewer::GenerateContourList {} {
3085    if { ![info exists _limits($_curFldName)] } {
3086        puts stderr "no _curFldName"
3087        return ""
3088    }
3089    if { $_contourList(numLevels) < 1 } {
3090        # There are tools that set 0 levels to get cutplanes only
3091        #puts stderr "numLevels < 1"
3092        return ""
3093    }
3094    if { [llength $_contourList(reqValues)] > 1 } {
3095        set values $_contourList(reqValues)
3096    } else {
3097        # if custom range has been set, use the custom min and max
3098        # to generate contour list values
3099        if { $_settings(-customrange) } {
3100            set vmin [$itk_component(min) value]
3101            set vmax [$itk_component(max) value]
3102        } else {
3103            # use the field limits to calculate the contour list values
3104            foreach { vmin vmax } $_limits($_curFldName) break
3105        }
3106
3107        set v [blt::vector create \#auto]
3108        $v seq $vmin $vmax [expr $_contourList(numLevels)+2]
3109        $v delete end 0
3110        set values [$v range 0 end]
3111        blt::vector destroy $v
3112    }
3113    set _contourList(values) $values
3114}
3115
3116itcl::body Rappture::VtkIsosurfaceViewer::SetCurrentFieldName { dataobj } {
3117    set _first $dataobj
3118    $itk_component(field) choices delete 0 end
3119    $itk_component(fieldmenu) delete 0 end
3120    array unset _fields
3121    set _curFldName ""
3122    foreach cname [$_first components] {
3123        foreach fname [$_first fieldnames $cname] {
3124            if { [info exists _fields($fname)] } {
3125                continue
3126            }
3127            foreach { label units components } \
3128                [$_first fieldinfo $fname] break
3129            $itk_component(field) choices insert end "$fname" "$label"
3130            $itk_component(fieldmenu) add radiobutton -label "$label" \
3131                -value $label -variable [itcl::scope _curFldLabel] \
3132                -selectcolor red \
3133                -activebackground $itk_option(-plotbackground) \
3134                -activeforeground $itk_option(-plotforeground) \
3135                -font "Arial 8" \
3136                -command [itcl::code $this LegendTitleAction save]
3137            set _fields($fname) [list $label $units $components]
3138            if { $_curFldName == "" } {
3139                set _curFldName $fname
3140                set _curFldLabel $label
3141            }
3142        }
3143    }
3144    $itk_component(field) value $_curFldLabel
3145    if { $_settings(-customrange) } {
3146        set limits [list [$itk_component(min) value] [$itk_component(max) value]]
3147        SendCmd "dataset maprange explicit $limits $_curFldName"
3148        if { $limits != $_currentLimits } {
3149            set _currentLimits $limits
3150            EventuallyChangeContourLevels
3151        }
3152    } else {
3153        if { ![info exists _limits($_curFldName)] } {
3154            SendCmd "dataset maprange all"
3155        } else {
3156            set limits $_limits($_curFldName)
3157            SendCmd "dataset maprange explicit $limits $_curFldName"
3158            if { $limits != $_currentLimits } {
3159                set _currentLimits $limits
3160                EventuallyChangeContourLevels
3161            }
3162        }
3163    }
3164}
Note: See TracBrowser for help on using the repository browser.