source: branches/uiuc_vtk_viewers/gui/scripts/vtkisosurfaceviewer.tcl @ 5051

Last change on this file since 5051 was 5051, checked in by dkearney, 6 years ago

removing the _ignoreRangeUpdate because newer implementations of the min/max range syncing does not cause a loop between changing the legend values and the gauge values.

added a -range flag to InitSettings? in ::Rebuild so the custom ranges are set.i dont think this works fully because some of the adjustments are inside the ToggleCustomRange? method, which isn't called by AdjustSetting? -range.

remove the trace on the crange widget's textvariable in favor of just calling the ToggleCustomRange? method where it needs to be called.

tried using the crange widget's (checkbutton) invoke command to turn on the checkbutton and call its -command script. the invoke command is a toggle, not just a "turn on" command and doesn't work the same as select.

changed the order of turning on the custom range checkbutton and setting the min or max gauge value. we should first signal that the custom range is being enabled from the legend min/max editor, then adjust the value in the min or max gauge, then enable the custom range checkbutton, labels, gauges. lastly call AdjustSetting? -range to redraw / recalculate isosurfaces and update the legend labels with the new min and max values.

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