source: trunk/gui/scripts/nanovisviewer.tcl @ 5642

Last change on this file since 5642 was 5642, checked in by ldelgass, 9 years ago

Don't need to rely on nanovis to return limits any more, so cleanup some old
code. Also sync up nanovis and flowvis viewers.

File size: 81.8 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: nanovisviewer - 3D volume rendering
4#
5#  This widget performs volume rendering on 3D scalar/vector datasets.
6#  It connects to the Nanovis server running on a rendering farm,
7#  transmits data, and displays the results.
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
11#
12#  See the file "license.terms" for information on usage and
13#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14# ======================================================================
15package require Itk
16package require BLT
17package require Img
18
19option add *NanovisViewer.width 4i widgetDefault
20option add *NanovisViewer*cursor crosshair widgetDefault
21option add *NanovisViewer.height 4i widgetDefault
22option add *NanovisViewer.foreground black widgetDefault
23option add *NanovisViewer.controlBackground gray widgetDefault
24option add *NanovisViewer.controlDarkBackground #999999 widgetDefault
25option add *NanovisViewer.plotBackground black widgetDefault
26option add *NanovisViewer.plotForeground white widgetDefault
27option add *NanovisViewer.plotOutline gray widgetDefault
28option add *NanovisViewer.font \
29    -*-helvetica-medium-r-normal-*-12-* widgetDefault
30
31# must use this name -- plugs into Rappture::resources::load
32proc NanovisViewer_init_resources {} {
33    Rappture::resources::register \
34        nanovis_server Rappture::NanovisViewer::SetServerList
35}
36
37itcl::class Rappture::NanovisViewer {
38    inherit Rappture::VisViewer
39
40    itk_option define -plotforeground plotForeground Foreground ""
41    itk_option define -plotbackground plotBackground Background ""
42    itk_option define -plotoutline plotOutline PlotOutline ""
43
44    constructor { hostlist args } {
45        Rappture::VisViewer::constructor $hostlist
46    } {
47        # defined below
48    }
49    destructor {
50        # defined below
51    }
52    public proc SetServerList { namelist } {
53        Rappture::VisViewer::SetServerList "nanovis" $namelist
54    }
55    public method add {dataobj {settings ""}}
56    public method camera {option args}
57    public method delete {args}
58    public method disconnect {}
59    public method download {option args}
60    public method get {args}
61    public method isconnected {}
62    public method parameters {title args} {
63        # do nothing
64    }
65    public method scale {args}
66    public method updateTransferFunctions {}
67
68    # The following methods are only used by this class.
69    private method AddNewMarker { x y }
70    private method AdjustSetting {what {value ""}}
71    private method BuildCameraTab {}
72    private method BuildCutplanesTab {}
73    private method BuildDownloadPopup { widget command }
74    private method BuildViewTab {}
75    private method BuildVolumeComponents {}
76    private method BuildVolumeTab {}
77    private method ComputeAlphamap { cname }
78    private method ComputeTransferFunction { cname }
79    private method Connect {}
80    private method CurrentDatasets {{what -all}}
81    private method Disconnect {}
82    private method DoResize {}
83    private method DrawLegend { cname }
84    private method EventuallyRedrawLegend { }
85    private method EventuallyResize { w h }
86    private method FixLegend {}
87    private method GetColormap { cname color }
88    private method GetDatasetsWithComponent { cname }
89    private method GetImage { args }
90    private method GetVtkData { args }
91    private method HideAllMarkers {}
92    private method InitComponentSettings { cname }
93    private method InitSettings { args }
94    private method NameTransferFunction { dataobj comp }
95    private method Pan {option x y}
96    private method PanCamera {}
97    private method ParseLevelsOption { cname levels }
98    private method ParseMarkersOption { cname markers }
99    private method QuaternionToView { q } {
100        foreach { _view(-qw) _view(-qx) _view(-qy) _view(-qz) } $q break
101    }
102    private method Rebuild {}
103    private method ReceiveData { args }
104    private method ReceiveImage { args }
105    private method ReceiveLegend { tf vmin vmax size }
106    private method RemoveMarker { x y }
107    private method ResetColormap { cname color }
108    private method Rotate {option x y}
109    private method SendTransferFunctions {}
110    private method SetObjectStyle { dataobj cname }
111    private method SetOrientation { side }
112    private method Slice {option args}
113    private method SlicerTip {axis}
114    private method SwitchComponent { cname }
115    private method ViewToQuaternion {} {
116        return [list $_view(-qw) $_view(-qx) $_view(-qy) $_view(-qz)]
117    }
118    private method Zoom {option}
119
120    private variable _arcball ""
121    private variable _dlist ""         ;# list of data objects
122    private variable _obj2ovride       ;# maps dataobj => style override
123    private variable _datasets         ;# contains all the dataobj-component
124                                       ;# to volumes in the server
125
126    private variable _reset 1          ;# Connection to server has been reset.
127    private variable _click            ;# Info used for rotate operations.
128    private variable _limits           ;# Autoscale min/max for all axes
129    private variable _view             ;# View params for 3D view
130    private variable _parsedFunction
131    private variable _transferFunctionEditors
132    private variable _settings
133    private variable _first ""         ;# This is the topmost volume.
134    private variable _current ""       ;# Currently selected component
135    private variable _volcomponents    ;# Maps component name to list of
136                                       ;# dataobj-component tags
137    private variable _componentsList   ;# List of components found
138    private variable _cname2transferFunction
139    private variable _cname2defaultcolormap
140    private variable _width 0
141    private variable _height 0
142    private variable _resizePending 0
143    private variable _resizeLegendPending 0
144
145    private common _downloadPopup      ;# download options from popup
146    private common _hardcopy
147}
148
149itk::usual NanovisViewer {
150    keep -background -foreground -cursor -font
151    keep -plotbackground -plotforeground
152}
153
154# ----------------------------------------------------------------------
155# CONSTRUCTOR
156# ----------------------------------------------------------------------
157itcl::body Rappture::NanovisViewer::constructor {hostlist args} {
158    set _serverType "nanovis"
159
160    # Draw legend event
161    $_dispatcher register !legend
162    $_dispatcher dispatch $this !legend "[itcl::code $this FixLegend]; list"
163
164    # Send transfer functions event
165    $_dispatcher register !send_transfunc
166    $_dispatcher dispatch $this !send_transfunc \
167        "[itcl::code $this SendTransferFunctions]; list"
168
169    # Rebuild event
170    $_dispatcher register !rebuild
171    $_dispatcher dispatch $this !rebuild "[itcl::code $this Rebuild]; list"
172
173    # Resize event
174    $_dispatcher register !resize
175    $_dispatcher dispatch $this !resize "[itcl::code $this DoResize]; list"
176
177    #
178    # Populate parser with commands handle incoming requests
179    #
180    $_parser alias image [itcl::code $this ReceiveImage]
181    $_parser alias legend [itcl::code $this ReceiveLegend]
182    $_parser alias data [itcl::code $this ReceiveData]
183
184    # Initialize the view to some default parameters.
185    array set _view {
186        -qw      0.853553
187        -qx      -0.353553
188        -qy      0.353553
189        -qz      0.146447
190        -xpan    0
191        -ypan    0
192        -zoom    1.0
193    }
194    set _arcball [blt::arcball create 100 100]
195    $_arcball quaternion [ViewToQuaternion]
196
197    set _reset 1
198
199    array set _settings [subst {
200        -ambient                60
201        -axesvisible            1
202        -background             black
203        -colormap               "default"
204        -cutplanesvisible       0
205        -diffuse                40
206        -gridvisible            0
207        -isosurfaceshading      0
208        -legendvisible          1
209        -light2side             1
210        -opacity                50
211        -outlinevisible         0
212        -qw                     $_view(-qw)
213        -qx                     $_view(-qx)
214        -qy                     $_view(-qy)
215        -qz                     $_view(-qz)
216        -specularexponent       90
217        -specularlevel          30
218        -thickness              350
219        -volume                 1
220        -volumevisible          1
221        -xcutplaneposition      50
222        -xcutplanevisible       1
223        -xpan                   $_view(-xpan)
224        -ycutplaneposition      50
225        -ycutplanevisible       1
226        -ypan                   $_view(-ypan)
227        -zcutplaneposition      50
228        -zcutplanevisible       1
229        -zoom                   $_view(-zoom)
230    }]
231
232    itk_component add 3dview {
233        label $itk_component(plotarea).view -image $_image(plot) \
234            -highlightthickness 0 -borderwidth 0
235    } {
236        usual
237        ignore -highlightthickness -borderwidth  -background
238    }
239    bind $itk_component(3dview) <Control-F1> [itcl::code $this ToggleConsole]
240
241    set f [$itk_component(main) component controls]
242    itk_component add reset {
243        button $f.reset -borderwidth 1 -padx 1 -pady 1 \
244            -highlightthickness 0 \
245            -image [Rappture::icon reset-view] \
246            -command [itcl::code $this Zoom reset]
247    } {
248        usual
249        ignore -highlightthickness
250    }
251    pack $itk_component(reset) -side top -padx 2 -pady 2
252    Rappture::Tooltip::for $itk_component(reset) \
253        "Reset the view to the default zoom level"
254
255    itk_component add zoomin {
256        button $f.zin -borderwidth 1 -padx 1 -pady 1 \
257            -highlightthickness 0 \
258            -image [Rappture::icon zoom-in] \
259            -command [itcl::code $this Zoom in]
260    } {
261        usual
262        ignore -highlightthickness
263    }
264    pack $itk_component(zoomin) -side top -padx 2 -pady 2
265    Rappture::Tooltip::for $itk_component(zoomin) "Zoom in"
266
267    itk_component add zoomout {
268        button $f.zout -borderwidth 1 -padx 1 -pady 1 \
269            -highlightthickness 0 \
270            -image [Rappture::icon zoom-out] \
271            -command [itcl::code $this Zoom out]
272    } {
273        usual
274        ignore -highlightthickness
275    }
276    pack $itk_component(zoomout) -side top -padx 2 -pady 2
277    Rappture::Tooltip::for $itk_component(zoomout) "Zoom out"
278
279    itk_component add volume {
280        Rappture::PushButton $f.volume \
281            -onimage [Rappture::icon volume-on] \
282            -offimage [Rappture::icon volume-off] \
283            -command [itcl::code $this AdjustSetting -volume] \
284            -variable [itcl::scope _settings(-volume)]
285    }
286    $itk_component(volume) select
287    Rappture::Tooltip::for $itk_component(volume) \
288        "Toggle the volume cloud on/off"
289    pack $itk_component(volume) -padx 2 -pady 2
290
291    itk_component add cutplane {
292        Rappture::PushButton $f.cutplane \
293            -onimage [Rappture::icon cutbutton] \
294            -offimage [Rappture::icon cutbutton] \
295            -variable [itcl::scope _settings(-cutplanesvisible)] \
296            -command [itcl::code $this AdjustSetting -cutplanesvisible]
297    }
298    Rappture::Tooltip::for $itk_component(cutplane) \
299        "Show/Hide cutplanes"
300    pack $itk_component(cutplane) -padx 2 -pady 2
301
302    if { [catch {
303        BuildViewTab
304        BuildVolumeTab
305        BuildCutplanesTab
306        BuildCameraTab
307    } errs] != 0 } {
308        global errorInfo
309        puts stderr "errs=$errs errorInfo=$errorInfo"
310    }
311
312    # Legend
313    set _image(legend) [image create photo]
314    itk_component add legend {
315        canvas $itk_component(plotarea).legend -height 50 -highlightthickness 0
316    } {
317        usual
318        ignore -highlightthickness
319        rename -background -plotbackground plotBackground Background
320    }
321    bind $itk_component(legend) <Configure> \
322        [itcl::code $this EventuallyRedrawLegend]
323    bind $itk_component(legend) <KeyPress-Delete> \
324        [itcl::code $this RemoveMarker %x %y]
325    bind $itk_component(legend) <Enter> \
326        [list focus $itk_component(legend)]
327
328    # Hack around the Tk panewindow.  The problem is that the requested
329    # size of the 3d view isn't set until an image is retrieved from
330    # the server.  So the panewindow uses the tiny size.
331    set w 10000
332    pack forget $itk_component(3dview)
333    blt::table $itk_component(plotarea) \
334        0,0 $itk_component(3dview) -fill both -reqwidth $w \
335        1,0 $itk_component(legend) -fill x
336    blt::table configure $itk_component(plotarea) r1 -resize none
337
338    # Bindings for rotation via mouse
339    bind $itk_component(3dview) <ButtonPress-1> \
340        [itcl::code $this Rotate click %x %y]
341    bind $itk_component(3dview) <B1-Motion> \
342        [itcl::code $this Rotate drag %x %y]
343    bind $itk_component(3dview) <ButtonRelease-1> \
344        [itcl::code $this Rotate release %x %y]
345
346    bind $itk_component(3dview) <Configure> \
347        [itcl::code $this EventuallyResize %w %h]
348
349    # Bindings for panning via mouse
350    bind $itk_component(3dview) <ButtonPress-2> \
351        [itcl::code $this Pan click %x %y]
352    bind $itk_component(3dview) <B2-Motion> \
353        [itcl::code $this Pan drag %x %y]
354    bind $itk_component(3dview) <ButtonRelease-2> \
355        [itcl::code $this Pan release %x %y]
356
357    # Bindings for panning via keyboard
358    bind $itk_component(3dview) <KeyPress-Left> \
359        [itcl::code $this Pan set -10 0]
360    bind $itk_component(3dview) <KeyPress-Right> \
361        [itcl::code $this Pan set 10 0]
362    bind $itk_component(3dview) <KeyPress-Up> \
363        [itcl::code $this Pan set 0 -10]
364    bind $itk_component(3dview) <KeyPress-Down> \
365        [itcl::code $this Pan set 0 10]
366    bind $itk_component(3dview) <Shift-KeyPress-Left> \
367        [itcl::code $this Pan set -2 0]
368    bind $itk_component(3dview) <Shift-KeyPress-Right> \
369        [itcl::code $this Pan set 2 0]
370    bind $itk_component(3dview) <Shift-KeyPress-Up> \
371        [itcl::code $this Pan set 0 -2]
372    bind $itk_component(3dview) <Shift-KeyPress-Down> \
373        [itcl::code $this Pan set 0 2]
374
375    # Bindings for zoom via keyboard
376    bind $itk_component(3dview) <KeyPress-Prior> \
377        [itcl::code $this Zoom out]
378    bind $itk_component(3dview) <KeyPress-Next> \
379        [itcl::code $this Zoom in]
380
381    bind $itk_component(3dview) <Enter> "focus $itk_component(3dview)"
382
383    if {[string equal "x11" [tk windowingsystem]]} {
384        # Bindings for zoom via mouse
385        bind $itk_component(3dview) <4> [itcl::code $this Zoom out]
386        bind $itk_component(3dview) <5> [itcl::code $this Zoom in]
387    }
388
389    set _image(download) [image create photo]
390
391    eval itk_initialize $args
392
393    EnableWaitDialog 900
394    Connect
395}
396
397# ----------------------------------------------------------------------
398# DESTRUCTOR
399# ----------------------------------------------------------------------
400itcl::body Rappture::NanovisViewer::destructor {} {
401    $_dispatcher cancel !rebuild
402    $_dispatcher cancel !send_transfunc
403    $_dispatcher cancel !resize
404    image delete $_image(plot)
405    image delete $_image(legend)
406    image delete $_image(download)
407    foreach cname [array names _transferFunctionEditors] {
408        itcl::delete object $_transferFunctionEditors($cname)
409    }
410    catch { blt::arcball destroy $_arcball }
411    array unset _settings
412}
413
414# ----------------------------------------------------------------------
415# USAGE: add <dataobj> ?<settings>?
416#
417# Clients use this to add a data object to the plot.  The optional
418# <settings> are used to configure the plot.  Allowed settings are
419# -color, -brightness, -width, -linestyle, and -raise.
420# ----------------------------------------------------------------------
421itcl::body Rappture::NanovisViewer::add {dataobj {settings ""}} {
422    if { ![$dataobj isvalid] } {
423        return;                         # Object doesn't contain valid data.
424    }
425    array set params {
426        -color auto
427        -width 1
428        -linestyle solid
429        -brightness 0
430        -raise 0
431        -description ""
432        -param ""
433    }
434    array set params $settings
435
436    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
437        # can't handle -autocolors yet
438        set params(-color) black
439    }
440    set pos [lsearch -exact $_dlist $dataobj]
441    if {$pos < 0} {
442        lappend _dlist $dataobj
443        set _obj2ovride($dataobj-color) $params(-color)
444        set _obj2ovride($dataobj-width) $params(-width)
445        set _obj2ovride($dataobj-raise) $params(-raise)
446        $_dispatcher event -idle !rebuild
447    }
448}
449
450# ----------------------------------------------------------------------
451# USAGE: get ?-objects?
452# USAGE: get ?-image 3dview|legend?
453#
454# Clients use this to query the list of objects being plotted, in
455# order from bottom to top of this result.  The optional "-image"
456# flag can also request the internal images being shown.
457# ----------------------------------------------------------------------
458itcl::body Rappture::NanovisViewer::get {args} {
459    if {[llength $args] == 0} {
460        set args "-objects"
461    }
462
463    set op [lindex $args 0]
464    switch -- $op {
465        -objects {
466            # put the dataobj list in order according to -raise options
467            set dlist $_dlist
468            foreach dataobj $dlist {
469                if {[info exists _obj2ovride($dataobj-raise)] &&
470                    $_obj2ovride($dataobj-raise)} {
471                    set i [lsearch -exact $dlist $dataobj]
472                    if {$i >= 0} {
473                        set dlist [lreplace $dlist $i $i]
474                        lappend dlist $dataobj
475                    }
476                }
477            }
478            return $dlist
479        }
480        -image {
481            if {[llength $args] != 2} {
482                error "wrong # args: should be \"get -image 3dview|legend\""
483            }
484            switch -- [lindex $args end] {
485                3dview {
486                    return $_image(plot)
487                }
488                legend {
489                    return $_image(legend)
490                }
491                default {
492                    error "bad image name \"[lindex $args end]\": should be 3dview or legend"
493                }
494            }
495        }
496        default {
497            error "bad option \"$op\": should be -objects or -image"
498        }
499    }
500}
501
502# ----------------------------------------------------------------------
503# USAGE: delete ?<dataobj1> <dataobj2> ...?
504#
505#       Clients use this to delete a dataobj from the plot.  If no dataobjs
506#       are specified, then all dataobjs are deleted.  No data objects are
507#       deleted.  They are only removed from the display list.
508#
509# ----------------------------------------------------------------------
510itcl::body Rappture::NanovisViewer::delete {args} {
511    if {[llength $args] == 0} {
512        set args $_dlist
513    }
514    # Delete all specified dataobjs
515    set changed 0
516    foreach dataobj $args {
517        set pos [lsearch -exact $_dlist $dataobj]
518        if { $pos >= 0 } {
519            set _dlist [lreplace $_dlist $pos $pos]
520            array unset _obj2ovride $dataobj-*
521            set changed 1
522        }
523    }
524    # If anything changed, then rebuild the plot
525    if {$changed} {
526        $_dispatcher event -idle !rebuild
527    }
528}
529
530# ----------------------------------------------------------------------
531# USAGE: scale ?<data1> <data2> ...?
532#
533# Sets the default limits for the overall plot according to the
534# limits of the data for all of the given <data> objects.  This
535# accounts for all objects--even those not showing on the screen.
536# Because of this, the limits are appropriate for all objects as
537# the user scans through data in the ResultSet viewer.
538# ----------------------------------------------------------------------
539itcl::body Rappture::NanovisViewer::scale {args} {
540    array set style {
541        -color    BCGYR
542        -levels   6
543        -markers  ""
544    }
545    array unset _limits
546    array unset _volcomponents
547    foreach dataobj $args {
548        if { ![$dataobj isvalid] } {
549            continue;                     # Object doesn't contain valid data.
550        }
551        foreach cname [$dataobj components] {
552            if { ![info exists _volcomponents($cname)] } {
553                lappend _componentsList $cname
554                array set style [lindex [$dataobj components -style $cname] 0]
555                set cmap [ColorsToColormap $style(-color)]
556                set _cname2defaultcolormap($cname) $cmap
557                set _settings($cname-colormap) $style(-color)
558            }
559            lappend _volcomponents($cname) $dataobj-$cname
560            array unset limits
561            array set limits [$dataobj valueLimits $cname]
562            set _limits($cname) $limits(v)
563        }
564        foreach axis {x y z} {
565            foreach { min max } [$dataobj limits $axis] break
566            if {"" != $min && "" != $max} {
567                if { ![info exists _limits($axis)] } {
568                    set _limits($axis) [list $min $max]
569                    continue
570                }
571                foreach {amin amax} $_limits($axis) break
572                if {$min < $amin} {
573                    set amin $min
574                }
575                if {$max > $amax} {
576                    set amax $max
577                }
578                set _limits($axis) [list $amin $amax]
579            }
580        }
581    }
582    BuildVolumeComponents
583}
584
585# ----------------------------------------------------------------------
586# USAGE: download coming
587# USAGE: download controls <downloadCommand>
588# USAGE: download now
589#
590# Clients use this method to create a downloadable representation
591# of the plot.  Returns a list of the form {ext string}, where
592# "ext" is the file extension (indicating the type of data) and
593# "string" is the data itself.
594# ----------------------------------------------------------------------
595itcl::body Rappture::NanovisViewer::download {option args} {
596    switch $option {
597        coming {
598            if {[catch {
599                blt::winop snap $itk_component(plotarea) $_image(download)
600            }]} {
601                $_image(download) configure -width 1 -height 1
602                $_image(download) put #000000
603            }
604        }
605        controls {
606            set popup .nanovisdownload
607            if { ![winfo exists $popup] } {
608                set inner [BuildDownloadPopup $popup [lindex $args 0]]
609            } else {
610                set inner [$popup component inner]
611            }
612            # FIXME: we only support download of current active component
613            #set num [llength [get]]
614            #set num [expr {($num == 1) ? "1 result" : "$num results"}]
615            set num "current field component"
616            set word [Rappture::filexfer::label downloadWord]
617            $inner.summary configure -text "$word $num in the following format:"
618            update idletasks            ;# Fix initial sizes
619            return $popup
620        }
621        now {
622            set popup .nanovisdownload
623            if { [winfo exists $popup] } {
624                $popup deactivate
625            }
626            switch -- $_downloadPopup(format) {
627                "image" {
628                    return [$this GetImage [lindex $args 0]]
629                }
630                "vtk" {
631                    return [$this GetVtkData [lindex $args 0]]
632                }
633                default {
634                    error "bad download format \"$_downloadPopup(format)\""
635                }
636            }
637        }
638        default {
639            error "bad option \"$option\": should be coming, controls, now"
640        }
641    }
642}
643
644# ----------------------------------------------------------------------
645# USAGE: Connect ?<host:port>,<host:port>...?
646#
647# Clients use this method to establish a connection to a new
648# server, or to reestablish a connection to the previous server.
649# Any existing connection is automatically closed.
650# ----------------------------------------------------------------------
651itcl::body Rappture::NanovisViewer::Connect {} {
652    set _hosts [GetServerList "nanovis"]
653    if { "" == $_hosts } {
654        return 0
655    }
656    set _reset 1
657    set result [VisViewer::Connect $_hosts]
658    if { $result } {
659        if { $_reportClientInfo }  {
660            # Tell the server the viewer, hub, user and session.
661            # Do this immediately on connect before buffering any commands
662            global env
663
664            set info {}
665            set user "???"
666            if { [info exists env(USER)] } {
667                set user $env(USER)
668            }
669            set session "???"
670            if { [info exists env(SESSION)] } {
671                set session $env(SESSION)
672            }
673            lappend info "version" "$Rappture::version"
674            lappend info "build" "$Rappture::build"
675            lappend info "svnurl" "$Rappture::svnurl"
676            lappend info "installdir" "$Rappture::installdir"
677            lappend info "hub" [exec hostname]
678            lappend info "client" "nanovisviewer"
679            lappend info "user" $user
680            lappend info "session" $session
681            SendCmd "clientinfo [list $info]"
682        }
683
684        set w [winfo width $itk_component(3dview)]
685        set h [winfo height $itk_component(3dview)]
686        EventuallyResize $w $h
687    }
688    return $result
689}
690
691#
692# isconnected --
693#
694#       Indicates if we are currently connected to the visualization server.
695#
696itcl::body Rappture::NanovisViewer::isconnected {} {
697    return [VisViewer::IsConnected]
698}
699
700#
701# disconnect --
702#
703itcl::body Rappture::NanovisViewer::disconnect {} {
704    Disconnect
705}
706
707#
708# Disconnect --
709#
710#       Clients use this method to disconnect from the current rendering
711#       server.
712#
713itcl::body Rappture::NanovisViewer::Disconnect {} {
714    VisViewer::Disconnect
715
716    # disconnected -- no more data sitting on server
717    array unset _datasets
718}
719
720# ----------------------------------------------------------------------
721# USAGE: SendTransferFunctions
722# ----------------------------------------------------------------------
723itcl::body Rappture::NanovisViewer::SendTransferFunctions {} {
724    foreach cname [array names _volcomponents] {
725        ComputeTransferFunction $cname
726    }
727    FixLegend
728}
729
730# ----------------------------------------------------------------------
731# USAGE: ReceiveImage -bytes <size> -type <type> -token <token>
732#
733# Invoked automatically whenever the "image" command comes in from
734# the rendering server.  Indicates that binary image data with the
735# specified <size> will follow.
736# ----------------------------------------------------------------------
737itcl::body Rappture::NanovisViewer::ReceiveImage { args } {
738    array set info {
739        -token "???"
740        -bytes 0
741        -type image
742    }
743    array set info $args
744    set bytes [ReceiveBytes $info(-bytes)]
745    switch -- $info(-type) {
746        "image" {
747            #puts stderr "received image [image width $_image(plot)]x[image height $_image(plot)]"
748            $_image(plot) configure -data $bytes
749        }
750        "print" {
751            set tag $this-print-$info(-token)
752            set _hardcopy($tag) $bytes
753        }
754        default {
755            puts stderr "unknown image type $info(-type)"
756        }
757    }
758}
759
760#
761# DrawLegend --
762#
763itcl::body Rappture::NanovisViewer::DrawLegend { cname } {
764    set c $itk_component(legend)
765    set w [winfo width $c]
766    set h [winfo height $c]
767    set lx 10
768    set ly [expr {$h - 1}]
769    if {"" == [$c find withtag colorbar]} {
770        $c create image 10 10 -anchor nw \
771            -image $_image(legend) -tags colorbar
772        $c create text $lx $ly -anchor sw \
773            -fill $itk_option(-plotforeground) -tags "limits text vmin"
774        $c create text [expr {$w-$lx}] $ly -anchor se \
775            -fill $itk_option(-plotforeground) -tags "limits text vmax"
776        $c create text [expr {$w/2}] $ly -anchor s \
777            -fill $itk_option(-plotforeground) -tags "title text"
778        $c lower colorbar
779        $c bind colorbar <ButtonRelease-1> [itcl::code $this AddNewMarker %x %y]
780    }
781
782    # Display the markers used by the current transfer function.
783    HideAllMarkers
784    $_transferFunctionEditors($cname) showMarkers $_limits($cname)
785
786    foreach {min max} $_limits($cname) break
787    $c itemconfigure vmin -text [format %g $min]
788    $c coords vmin $lx $ly
789
790    $c itemconfigure vmax -text [format %g $max]
791    $c coords vmax [expr {$w-$lx}] $ly
792
793    set title [$_first hints label]
794    set units [$_first hints units]
795    if { $units != "" } {
796        set title "$title ($units)"
797    }
798    $c itemconfigure title -text $title
799    $c coords title [expr {$w/2}] $ly
800
801    # The colormap may have changed. Resync the slicers with the colormap.
802    set datasets [CurrentDatasets -cutplanes]
803
804    # Adjust the cutplane for only the first component in the topmost volume
805    # (i.e. the first volume designated in the field).
806    set tag [lindex $datasets 0]
807    foreach axis {x y z} {
808        # Turn off cutplanes for all volumes
809        SendCmd "cutplane state 0 $axis"
810        if { $_settings(-${axis}cutplanevisible) } {
811            # Turn on cutplane for this particular volume and set the position
812            SendCmd "cutplane state 1 $axis $tag"
813            set pos [expr {0.01*$_settings(-${axis}cutplaneposition)}]
814            SendCmd "cutplane position $pos $axis $tag"
815        }
816    }
817}
818
819#
820# ReceiveLegend --
821#
822#       The procedure is the response from the render server to each "legend"
823#       command.  The server sends back a "legend" command invoked our
824#       the slave interpreter.  The purpose is to collect data of the image
825#       representing the legend in the canvas.  In addition, the
826#       active transfer function is displayed.
827#
828itcl::body Rappture::NanovisViewer::ReceiveLegend { cname vmin vmax size } {
829    if { ![isconnected] } {
830        return
831    }
832    set bytes [ReceiveBytes $size]
833    $_image(legend) configure -data $bytes
834    ReceiveEcho <<line "<read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
835
836    DrawLegend $_current
837}
838
839#
840# ReceiveData --
841#
842#       The procedure is the response from the render server to each "data
843#       follows" command.  The server sends back a "data" command invoked our
844#       the slave interpreter.  The purpose was to collect the min/max of the
845#       volume sent to the render server.  This is no longer needed since we
846#       already know the limits.
847#
848itcl::body Rappture::NanovisViewer::ReceiveData { args } {
849    if { ![isconnected] } {
850        return
851    }
852
853    # Arguments from server are name value pairs. Stuff them in an array.
854    array set info $args
855
856    set tag $info(tag)
857    set _limits($tag) [list $info(min) $info(max)]
858}
859
860# ----------------------------------------------------------------------
861# USAGE: Rebuild
862#
863# Called automatically whenever something changes that affects the
864# data in the widget.  Clears any existing data and rebuilds the
865# widget to display new data.
866# ----------------------------------------------------------------------
867itcl::body Rappture::NanovisViewer::Rebuild {} {
868    set w [winfo width $itk_component(3dview)]
869    set h [winfo height $itk_component(3dview)]
870    if { $w < 2 || $h < 2 } {
871        update
872        $_dispatcher event -idle !rebuild
873        return
874    }
875
876    # Turn on buffering of commands to the server.  We don't want to
877    # be preempted by a server disconnect/reconnect (which automatically
878    # generates a new call to Rebuild).
879    StartBufferingCommands
880
881    if { $_width != $w || $_height != $h || $_reset } {
882        set _width $w
883        set _height $h
884        $_arcball resize $w $h
885        DoResize
886    }
887
888    set _first ""
889    SendCmd "volume state 0"
890    foreach dataobj [get -objects] {
891        if { [info exists _obj2ovride($dataobj-raise)] &&  $_first == "" } {
892            set _first $dataobj
893        }
894        foreach cname [$dataobj components] {
895            set tag $dataobj-$cname
896            if { ![info exists _datasets($tag)] } {
897                if { [$dataobj type] == "dx" } {
898                    set data [$dataobj blob $cname]
899                } else {
900                    set data [$dataobj vtkdata $cname]
901                    if 0 {
902                        set f [open "/tmp/volume.vtk" "w"]
903                        fconfigure $f -translation binary -encoding binary
904                        puts -nonewline $f $data
905                        close $f
906                    }
907                }
908                set nbytes [string length $data]
909                if { $_reportClientInfo }  {
910                    set info {}
911                    lappend info "tool_id"       [$dataobj hints toolid]
912                    lappend info "tool_name"     [$dataobj hints toolname]
913                    lappend info "tool_title"    [$dataobj hints tooltitle]
914                    lappend info "tool_command"  [$dataobj hints toolcommand]
915                    lappend info "tool_revision" [$dataobj hints toolrevision]
916                    lappend info "dataset_label" [$dataobj hints label]
917                    lappend info "dataset_size"  $nbytes
918                    lappend info "dataset_tag"   $tag
919                    SendCmd "clientinfo [list $info]"
920                }
921                SendCmd "volume data follows $nbytes $tag"
922                SendData $data
923                set _datasets($tag) 1
924            }
925            SetObjectStyle $dataobj $cname
926            if { [info exists _obj2ovride($dataobj-raise)] } {
927                SendCmd "volume state 1 $tag"
928            }
929        }
930    }
931    # Outline seems to need to be reset every update.
932    InitSettings -outlinevisible -cutplanesvisible
933    if { $_reset } {
934        # Turn off cutplanes for all volumes
935        foreach axis {x y z} {
936            SendCmd "cutplane state 0 $axis"
937        }
938
939        InitSettings -axesvisible -gridvisible \
940            -light2side -isosurfaceshading -opacity \
941            -ambient -diffuse -specularlevel -specularexponent \
942            -xcutplanevisible -ycutplanevisible -zcutplanevisible \
943            -current
944
945        #
946        # Reset the camera and other view parameters
947        #
948        if {"" != $_first} {
949            set axis [$_first hints updir]
950            if { "" != $axis } {
951                SendCmd "up $axis"
952            }
953            set location [$_first hints camera]
954            if { $location != "" } {
955                array set _view $location
956            }
957        }
958        set _settings(-qw)    $_view(-qw)
959        set _settings(-qx)    $_view(-qx)
960        set _settings(-qy)    $_view(-qy)
961        set _settings(-qz)    $_view(-qz)
962        set _settings(-xpan)  $_view(-xpan)
963        set _settings(-ypan)  $_view(-ypan)
964        set _settings(-zoom)  $_view(-zoom)
965
966        set q [ViewToQuaternion]
967        $_arcball quaternion $q
968        SendCmd "camera orient $q"
969        SendCmd "camera reset"
970        PanCamera
971        SendCmd "camera zoom $_view(-zoom)"
972    }
973
974    if {"" != $_first} {
975        # Make sure we display the proper transfer function in the legend.
976        updateTransferFunctions
977    }
978    # Actually write the commands to the server socket.  If it fails, we don't
979    # care.  We're finished here.
980    blt::busy hold $itk_component(hull)
981    StopBufferingCommands
982    blt::busy release $itk_component(hull)
983    set _reset 0
984}
985
986# ----------------------------------------------------------------------
987# USAGE: CurrentDatasets ?-cutplanes?
988#
989# Returns a list of volume server IDs for the current volume being
990# displayed.  This is normally a single ID, but it might be a list
991# of IDs if the current data object has multiple components.
992# ----------------------------------------------------------------------
993itcl::body Rappture::NanovisViewer::CurrentDatasets {{what -all}} {
994    set rlist ""
995    if { $_first == "" } {
996        return
997    }
998    foreach cname [$_first components] {
999        set tag $_first-$cname
1000        if { [info exists _datasets($tag)] && $_datasets($tag) } {
1001            array set style {
1002                -cutplanes 1
1003            }
1004            array set style [lindex [$_first components -style $cname] 0]
1005            if { $what != "-cutplanes" || $style(-cutplanes) } {
1006                lappend rlist $tag
1007            }
1008        }
1009    }
1010    return $rlist
1011}
1012
1013# ----------------------------------------------------------------------
1014# USAGE: Zoom in
1015# USAGE: Zoom out
1016# USAGE: Zoom reset
1017#
1018# Called automatically when the user clicks on one of the zoom
1019# controls for this widget.  Changes the zoom for the current view.
1020# ----------------------------------------------------------------------
1021itcl::body Rappture::NanovisViewer::Zoom {option} {
1022    switch -- $option {
1023        "in" {
1024            set _view(-zoom) [expr {$_view(-zoom)*1.25}]
1025            set _settings(-zoom) $_view(-zoom)
1026            SendCmd "camera zoom $_view(-zoom)"
1027        }
1028        "out" {
1029            set _view(-zoom) [expr {$_view(-zoom)*0.8}]
1030            set _settings(-zoom) $_view(-zoom)
1031            SendCmd "camera zoom $_view(-zoom)"
1032        }
1033        "reset" {
1034            array set _view {
1035                -qw      0.853553
1036                -qx      -0.353553
1037                -qy      0.353553
1038                -qz      0.146447
1039                -xpan    0
1040                -ypan    0
1041                -zoom    1.0
1042            }
1043            if { $_first != "" } {
1044                set location [$_first hints camera]
1045                if { $location != "" } {
1046                    array set _view $location
1047                }
1048            }
1049            set q [ViewToQuaternion]
1050            $_arcball quaternion $q
1051            SendCmd "camera orient $q"
1052            SendCmd "camera reset"
1053            set _settings(-qw)    $_view(-qw)
1054            set _settings(-qx)    $_view(-qx)
1055            set _settings(-qy)    $_view(-qy)
1056            set _settings(-qz)    $_view(-qz)
1057            set _settings(-xpan)  $_view(-xpan)
1058            set _settings(-ypan)  $_view(-ypan)
1059            set _settings(-zoom)  $_view(-zoom)
1060        }
1061    }
1062}
1063
1064itcl::body Rappture::NanovisViewer::PanCamera {} {
1065    set x $_view(-xpan)
1066    set y $_view(-ypan)
1067    SendCmd "camera pan $x $y"
1068}
1069
1070# ----------------------------------------------------------------------
1071# USAGE: Rotate click <x> <y>
1072# USAGE: Rotate drag <x> <y>
1073# USAGE: Rotate release <x> <y>
1074#
1075# Called automatically when the user clicks/drags/releases in the
1076# plot area.  Moves the plot according to the user's actions.
1077# ----------------------------------------------------------------------
1078itcl::body Rappture::NanovisViewer::Rotate {option x y} {
1079    switch -- $option {
1080        click {
1081            $itk_component(3dview) configure -cursor fleur
1082            set _click(x) $x
1083            set _click(y) $y
1084        }
1085        drag {
1086            if {[array size _click] == 0} {
1087                Rotate click $x $y
1088            } else {
1089                set w [winfo width $itk_component(3dview)]
1090                set h [winfo height $itk_component(3dview)]
1091                if {$w <= 0 || $h <= 0} {
1092                    return
1093                }
1094
1095                if {[catch {
1096                    # this fails sometimes for no apparent reason
1097                    set dx [expr {double($x-$_click(x))/$w}]
1098                    set dy [expr {double($y-$_click(y))/$h}]
1099                }]} {
1100                    return
1101                }
1102
1103                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1104                QuaternionToView $q
1105                set _settings(-qw) $_view(-qw)
1106                set _settings(-qx) $_view(-qx)
1107                set _settings(-qy) $_view(-qy)
1108                set _settings(-qz) $_view(-qz)
1109                SendCmd "camera orient $q"
1110
1111                set _click(x) $x
1112                set _click(y) $y
1113            }
1114        }
1115        release {
1116            Rotate drag $x $y
1117            $itk_component(3dview) configure -cursor ""
1118            catch {unset _click}
1119        }
1120        default {
1121            error "bad option \"$option\": should be click, drag, release"
1122        }
1123    }
1124}
1125
1126# ----------------------------------------------------------------------
1127# USAGE: $this Pan click x y
1128#        $this Pan drag x y
1129#        $this Pan release x y
1130#
1131# Called automatically when the user clicks on one of the zoom
1132# controls for this widget.  Changes the zoom for the current view.
1133# ----------------------------------------------------------------------
1134itcl::body Rappture::NanovisViewer::Pan {option x y} {
1135    # Experimental stuff
1136    set w [winfo width $itk_component(3dview)]
1137    set h [winfo height $itk_component(3dview)]
1138    if { $option == "set" } {
1139        set x [expr $x / double($w)]
1140        set y [expr $y / double($h)]
1141        set _view(-xpan) [expr $_view(-xpan) + $x]
1142        set _view(-ypan) [expr $_view(-ypan) + $y]
1143        PanCamera
1144        set _settings(-xpan) $_view(-xpan)
1145        set _settings(-ypan) $_view(-ypan)
1146        return
1147    }
1148    if { $option == "click" } {
1149        set _click(x) $x
1150        set _click(y) $y
1151        $itk_component(3dview) configure -cursor hand1
1152    }
1153    if { $option == "drag" || $option == "release" } {
1154        set dx [expr ($_click(x) - $x)/double($w)]
1155        set dy [expr ($_click(y) - $y)/double($h)]
1156        set _click(x) $x
1157        set _click(y) $y
1158        set _view(-xpan) [expr $_view(-xpan) - $dx]
1159        set _view(-ypan) [expr $_view(-ypan) - $dy]
1160        PanCamera
1161        set _settings(-xpan) $_view(-xpan)
1162        set _settings(-ypan) $_view(-ypan)
1163    }
1164    if { $option == "release" } {
1165        $itk_component(3dview) configure -cursor ""
1166    }
1167}
1168
1169# ----------------------------------------------------------------------
1170# USAGE: InitSettings <what> ?<value>?
1171#
1172# Used internally to update rendering settings whenever parameters
1173# change in the popup settings panel.  Sends the new settings off
1174# to the back end.
1175# ----------------------------------------------------------------------
1176itcl::body Rappture::NanovisViewer::InitSettings { args } {
1177    foreach arg $args {
1178        AdjustSetting $arg
1179    }
1180}
1181
1182# ----------------------------------------------------------------------
1183# USAGE: AdjustSetting <what> ?<value>?
1184#
1185# Used internally to update rendering settings whenever parameters
1186# change in the popup settings panel.  Sends the new settings off
1187# to the back end.
1188# ----------------------------------------------------------------------
1189itcl::body Rappture::NanovisViewer::AdjustSetting {what {value ""}} {
1190    if {![isconnected]} {
1191        return
1192    }
1193    switch -- $what {
1194        "-ambient" {
1195            # Other parts of the code use the ambient setting to
1196            # tell if the component settings have been initialized
1197            if { ![info exists _settings($_current${what})] } {
1198                InitComponentSettings $_current
1199            }
1200            set _settings($_current${what}) $_settings($what)
1201            set val $_settings($what)
1202            set val [expr {0.01*$val}]
1203            foreach tag [GetDatasetsWithComponent $_current] {
1204                SendCmd "volume shading ambient $val $tag"
1205            }
1206        }
1207        "-axesvisible" {
1208            SendCmd "axis visible $_settings($what)"
1209        }
1210        "-background" {
1211            set bgcolor [$itk_component(background) value]
1212            array set fgcolors {
1213                "black" "white"
1214                "white" "black"
1215                "grey"  "black"
1216            }
1217            configure -plotbackground $bgcolor \
1218                -plotforeground $fgcolors($bgcolor)
1219            DrawLegend $_current
1220        }
1221        "-colormap" {
1222            set color [$itk_component(colormap) value]
1223            set _settings($what) $color
1224            set _settings($_current${what}) $color
1225            ResetColormap $_current $color
1226        }
1227        "-current" {
1228            set cname [$itk_component(volcomponents) value]
1229            SwitchComponent $cname
1230        }
1231        "-cutplanesvisible" {
1232            set bool $_settings($what)
1233            # We only set cutplanes on the first dataset.
1234            set datasets [CurrentDatasets -cutplanes]
1235            set tag [lindex $datasets 0]
1236            SendCmd "cutplane visible $bool $tag"
1237        }
1238        "-diffuse" {
1239            set _settings($_current${what}) $_settings($what)
1240            set val $_settings($what)
1241            set val [expr {0.01*$val}]
1242            foreach tag [GetDatasetsWithComponent $_current] {
1243                SendCmd "volume shading diffuse $val $tag"
1244            }
1245        }
1246        "-gridvisible" {
1247            SendCmd "grid visible $_settings($what)"
1248        }
1249        "-isosurfaceshading" {
1250            set val $_settings($what)
1251            foreach tag [GetDatasetsWithComponent $_current] {
1252                SendCmd "volume shading isosurface $val $tag"
1253            }
1254        }
1255        "-legendvisible" {
1256            if { $_settings($what) } {
1257                blt::table $itk_component(plotarea) \
1258                    0,0 $itk_component(3dview) -fill both \
1259                    1,0 $itk_component(legend) -fill x
1260                blt::table configure $itk_component(plotarea) r1 -resize none
1261            } else {
1262                blt::table forget $itk_component(legend)
1263            }
1264        }
1265        "-light2side" {
1266            set _settings($_current${what}) $_settings($what)
1267            set val $_settings($what)
1268            foreach tag [GetDatasetsWithComponent $_current] {
1269                SendCmd "volume shading light2side $val $tag"
1270            }
1271        }
1272        "-opacity" {
1273            set _settings($_current${what}) $_settings($what)
1274            set val $_settings($what)
1275            set sval [expr { 0.01 * double($val) }]
1276            foreach tag [GetDatasetsWithComponent $_current] {
1277                SendCmd "volume shading opacity $sval $tag"
1278            }
1279        }
1280        "-outlinecolor" {
1281            set rgb [Color2RGB $_settings($what)]
1282            SendCmd "volume outline color $rgb"
1283        }
1284        "-outlinevisible" {
1285            SendCmd "volume outline state $_settings($what)"
1286        }
1287        "-specularexponent" {
1288            set _settings($_current${what}) $_settings($what)
1289            set val $_settings($what)
1290            foreach tag [GetDatasetsWithComponent $_current] {
1291                SendCmd "volume shading specularExp $val $tag"
1292            }
1293        }
1294        "-specularlevel" {
1295            set _settings($_current${what}) $_settings($what)
1296            set val $_settings($what)
1297            set val [expr {0.01*$val}]
1298            foreach tag [GetDatasetsWithComponent $_current] {
1299                SendCmd "volume shading specularLevel $val $tag"
1300            }
1301        }
1302        "-thickness" {
1303            set val $_settings($what)
1304            set _settings($_current${what}) $val
1305            updateTransferFunctions
1306        }
1307        "-volume" {
1308            # This is the global volume visibility control.  It controls the
1309            # visibility of all the volumes.  Whenever it's changed, you have
1310            # to synchronize each of the local controls (see below) with this.
1311            set datasets [CurrentDatasets]
1312            set bool $_settings($what)
1313            SendCmd "volume data state $bool $datasets"
1314            foreach cname $_componentsList {
1315                set _settings($cname-volumevisible) $bool
1316            }
1317            set _settings(-volumevisible) $bool
1318        }
1319        "-volumevisible" {
1320            # This is the component specific control.  It changes the
1321            # visibility of only the current component.
1322            set _settings($_current${what}) $_settings($what)
1323            foreach tag [GetDatasetsWithComponent $_current] {
1324                SendCmd "volume data state $_settings($what) $tag"
1325            }
1326        }
1327        "-xcutplaneposition" - "-ycutplaneposition" - "-zcutplaneposition" {
1328            set axis [string range $what 1 1]
1329            set pos [expr $_settings($what) * 0.01]
1330            # We only set cutplanes on the first dataset.
1331            set datasets [CurrentDatasets -cutplanes]
1332            set tag [lindex $datasets 0]
1333            SendCmd "cutplane position $pos $axis $tag"
1334        }
1335        "-xcutplanevisible" - "-ycutplanevisible" - "-zcutplanevisible" {
1336            set axis [string range $what 1 1]
1337            set bool $_settings($what)
1338            # We only set cutplanes on the first dataset.
1339            set datasets [CurrentDatasets -cutplanes]
1340            set tag [lindex $datasets 0]
1341            SendCmd "cutplane state $bool $axis $tag"
1342            if { $bool } {
1343                $itk_component(${axis}CutScale) configure -state normal \
1344                    -troughcolor white
1345            } else {
1346                $itk_component(${axis}CutScale) configure -state disabled \
1347                    -troughcolor grey82
1348            }
1349        }
1350        default {
1351            error "don't know how to fix $what"
1352        }
1353    }
1354}
1355
1356# ----------------------------------------------------------------------
1357# USAGE: FixLegend
1358#
1359# Used internally to update the legend area whenever it changes size
1360# or when the field changes.  Asks the server to send a new legend
1361# for the current field.
1362# ----------------------------------------------------------------------
1363itcl::body Rappture::NanovisViewer::FixLegend {} {
1364    set _resizeLegendPending 0
1365    set lineht [font metrics $itk_option(-font) -linespace]
1366    set w [expr {$_width-20}]
1367    set h [expr {[winfo height $itk_component(legend)]-20-$lineht}]
1368    if {$w > 0 && $h > 0 && $_first != "" } {
1369        if { [info exists _cname2transferFunction($_current)] } {
1370            SendCmd "legend $_current $w $h"
1371        }
1372    }
1373}
1374
1375#
1376# NameTransferFunction --
1377#
1378#       Creates a transfer function name based on the <style> settings in the
1379#       library run.xml file. This placeholder will be used later to create
1380#       and send the actual transfer function once the data info has been sent
1381#       to us by the render server. [We won't know the volume limits until the
1382#       server parses the 3D data and sends back the limits via ReceiveData.]
1383#
1384itcl::body Rappture::NanovisViewer::NameTransferFunction { dataobj cname } {
1385    array set style {
1386        -color BCGYR
1387        -levels 6
1388        -markers ""
1389    }
1390    set tag $dataobj-$cname
1391    array set style [lindex [$dataobj components -style $cname] 0]
1392    if { ![info exists _cname2transferFunction($cname)] } {
1393        # Get the colormap right now, since it doesn't change with marker
1394        # changes.
1395        set cmap [ColorsToColormap $style(-color)]
1396        set amap [list 0.0 0.0 1.0 1.0]
1397        set _cname2transferFunction($cname) [list $cmap $amap]
1398        SendCmd [list transfunc define $cname $cmap $amap]
1399    }
1400    SendCmd "volume shading transfunc $cname $tag"
1401    if { ![info exists _transferFunctionEditors($cname)] } {
1402        set _transferFunctionEditors($cname) \
1403            [Rappture::TransferFunctionEditor ::\#auto $itk_component(legend) \
1404                 $cname \
1405                 -command [itcl::code $this updateTransferFunctions]]
1406    }
1407    return $cname
1408}
1409
1410#
1411# ComputeTransferFunction --
1412#
1413#       Computes and sends the transfer function to the render server.  It's
1414#       assumed that the volume data limits are known and that the global
1415#       transfer-functions slider values have been set up.  Both parts are
1416#       needed to compute the relative value (location) of the marker, and
1417#       the alpha map of the transfer function.
1418#
1419itcl::body Rappture::NanovisViewer::ComputeTransferFunction { cname } {
1420    foreach {cmap amap} $_cname2transferFunction($cname) break
1421
1422    # We have to parse the style attributes for a volume using this
1423    # transfer-function *once*.  This sets up the initial isomarkers for the
1424    # transfer function.  The user may add/delete markers, so we have to
1425    # maintain a list of markers for each transfer-function.  We use the one
1426    # of the volumes (the first in the list) using the transfer-function as a
1427    # reference.
1428    if { ![info exists _parsedFunction($cname)] } {
1429        array set style {
1430            -color BCGYR
1431            -levels 6
1432            -markers ""
1433        }
1434        # Accumulate the style from all the datasets using it.
1435        foreach tag [GetDatasetsWithComponent $cname] {
1436            foreach {dataobj cname} [split [lindex $tag 0] -] break
1437            array set style [lindex [$dataobj components -style $cname] 0]
1438        }
1439        eval $_transferFunctionEditors($cname) limits $_limits($cname)
1440        # Have to defer creation of isomarkers until we have data limits
1441        if { [info exists style(-markers)] &&
1442             [llength $style(-markers)] > 0 } {
1443            ParseMarkersOption $cname $style(-markers)
1444        } else {
1445            ParseLevelsOption $cname $style(-levels)
1446        }
1447
1448    }
1449    set amap [ComputeAlphamap $cname]
1450    set _cname2transferFunction($cname) [list $cmap $amap]
1451    SendCmd [list transfunc define $cname $cmap $amap]
1452}
1453
1454itcl::body Rappture::NanovisViewer::AddNewMarker { x y } {
1455    if { ![info exists _transferFunctionEditors($_current)] } {
1456        continue
1457    }
1458    # Add a new marker to the current transfer function
1459    $_transferFunctionEditors($_current) newMarker $x $y normal
1460    $itk_component(legend) itemconfigure labels -fill $itk_option(-plotforeground)
1461}
1462
1463itcl::body Rappture::NanovisViewer::RemoveMarker { x y } {
1464    if { ![info exists _transferFunctionEditors($_current)] } {
1465        continue
1466    }
1467    # Add a new marker to the current transfer function
1468    $_transferFunctionEditors($_current) deleteMarker $x $y
1469}
1470
1471# ----------------------------------------------------------------------
1472# CONFIGURATION OPTION: -plotbackground
1473# ----------------------------------------------------------------------
1474itcl::configbody Rappture::NanovisViewer::plotbackground {
1475    if { [isconnected] } {
1476        set color $itk_option(-plotbackground)
1477        set rgb [Color2RGB $color]
1478        SendCmd "screen bgcolor $rgb"
1479        $itk_component(legend) configure -background $color
1480    }
1481}
1482
1483# ----------------------------------------------------------------------
1484# CONFIGURATION OPTION: -plotforeground
1485# ----------------------------------------------------------------------
1486itcl::configbody Rappture::NanovisViewer::plotforeground {
1487    if { [isconnected] } {
1488        set color $itk_option(-plotforeground)
1489        set rgb [Color2RGB $color]
1490        SendCmd "volume outline color $rgb"
1491        SendCmd "grid axiscolor $rgb"
1492        SendCmd "grid linecolor $rgb"
1493        $itk_component(legend) itemconfigure text -fill $color
1494    }
1495}
1496
1497# ----------------------------------------------------------------------
1498# CONFIGURATION OPTION: -plotoutline
1499# ----------------------------------------------------------------------
1500itcl::configbody Rappture::NanovisViewer::plotoutline {
1501    # Must check if we are connected because this routine is called from the
1502    # class body when the -plotoutline itk_option is defined.  At that point
1503    # the NanovisViewer class constructor hasn't been called, so we can't
1504    # start sending commands to visualization server.
1505    if { [isconnected] } {
1506        if {"" == $itk_option(-plotoutline)} {
1507            SendCmd "volume outline state off"
1508        } else {
1509            SendCmd "volume outline state on"
1510            SendCmd "volume outline color [Color2RGB $itk_option(-plotoutline)]"
1511        }
1512    }
1513}
1514
1515#
1516# The -levels option takes a single value that represents the number
1517# of evenly distributed markers based on the current data range. Each
1518# marker is a relative value from 0.0 to 1.0.
1519#
1520itcl::body Rappture::NanovisViewer::ParseLevelsOption { cname levels } {
1521    set c $itk_component(legend)
1522    set list {}
1523    regsub -all "," $levels " " levels
1524    if {[string is int $levels]} {
1525        for {set i 1} { $i <= $levels } {incr i} {
1526            lappend list [expr {double($i)/($levels+1)}]
1527        }
1528    } else {
1529        foreach x $levels {
1530            lappend list $x
1531        }
1532    }
1533    set _parsedFunction($cname) 1
1534    $_transferFunctionEditors($cname) addMarkers $list
1535    $itk_component(legend) itemconfigure labels -fill $itk_option(-plotforeground)
1536}
1537
1538#
1539# The -markers option takes a list of zero or more values (the values
1540# may be separated either by spaces or commas) that have the following
1541# format:
1542#
1543#   N%  Percent of current total data range.  Converted to
1544#       to a relative value between 0.0 and 1.0.
1545#   N   Absolute value of marker.  If the marker is outside of
1546#       the current range, it will be displayed on the outer
1547#       edge of the legends, but it range it represents will
1548#       not be seen.
1549#
1550itcl::body Rappture::NanovisViewer::ParseMarkersOption { cname markers } {
1551    set c $itk_component(legend)
1552    set list {}
1553    foreach { min max } $_limits($cname) break
1554    regsub -all "," $markers " " markers
1555    foreach marker $markers {
1556        set n [scan $marker "%g%s" value suffix]
1557        if { $n == 2 && $suffix == "%" } {
1558            # $n% : Set relative value (0..1).
1559            lappend list [expr {$value * 0.01}]
1560        } else {
1561            # $n : absolute value, compute relative
1562            lappend list  [expr {(double($value)-$min)/($max-$min)]}
1563        }
1564    }
1565    set _parsedFunction($cname) 1
1566    $_transferFunctionEditors($cname) addMarkers $list
1567    $itk_component(legend) itemconfigure labels -fill $itk_option(-plotforeground)
1568}
1569
1570itcl::body Rappture::NanovisViewer::updateTransferFunctions {} {
1571    $_dispatcher event -idle !send_transfunc
1572}
1573
1574itcl::body Rappture::NanovisViewer::BuildViewTab {} {
1575    set fg [option get $itk_component(hull) font Font]
1576    #set bfg [option get $itk_component(hull) boldFont Font]
1577
1578    set inner [$itk_component(main) insert end \
1579        -title "View Settings" \
1580        -icon [Rappture::icon wrench]]
1581    $inner configure -borderwidth 4
1582
1583    checkbutton $inner.axes \
1584        -text "Axes" \
1585        -variable [itcl::scope _settings(-axesvisible)] \
1586        -command [itcl::code $this AdjustSetting -axesvisible] \
1587        -font "Arial 9"
1588
1589    checkbutton $inner.grid \
1590        -text "Grid" \
1591        -variable [itcl::scope _settings(-gridvisible)] \
1592        -command [itcl::code $this AdjustSetting -gridvisible] \
1593        -font "Arial 9"
1594
1595    checkbutton $inner.outline \
1596        -text "Outline" \
1597        -variable [itcl::scope _settings(-outlinevisible)] \
1598        -command [itcl::code $this AdjustSetting -outlinevisible] \
1599        -font "Arial 9"
1600
1601    checkbutton $inner.legend \
1602        -text "Legend" \
1603        -variable [itcl::scope _settings(-legendvisible)] \
1604        -command [itcl::code $this AdjustSetting -legendvisible] \
1605        -font "Arial 9"
1606
1607    checkbutton $inner.volume \
1608        -text "Volume" \
1609        -variable [itcl::scope _settings(-volume)] \
1610        -command [itcl::code $this AdjustSetting -volume] \
1611        -font "Arial 9"
1612
1613    label $inner.background_l -text "Background" -font "Arial 9"
1614    itk_component add background {
1615        Rappture::Combobox $inner.background -width 10 -editable no
1616    }
1617    $inner.background choices insert end \
1618        "black" "black" \
1619        "white" "white" \
1620        "grey"  "grey"
1621
1622    $itk_component(background) value $_settings(-background)
1623    bind $inner.background <<Value>> \
1624        [itcl::code $this AdjustSetting -background]
1625
1626    blt::table $inner \
1627        0,0 $inner.axes -cspan 2 -anchor w \
1628        1,0 $inner.grid -cspan 2 -anchor w \
1629        2,0 $inner.outline -cspan 2 -anchor w \
1630        3,0 $inner.volume -cspan 2 -anchor w \
1631        4,0 $inner.legend -cspan 2 -anchor w \
1632        5,0 $inner.background_l -anchor e -pady 2 \
1633        5,1 $inner.background -fill x
1634
1635    blt::table configure $inner r* -resize none
1636    blt::table configure $inner r6 -resize expand
1637}
1638
1639itcl::body Rappture::NanovisViewer::BuildVolumeTab {} {
1640    set inner [$itk_component(main) insert end \
1641        -title "Volume Settings" \
1642        -icon [Rappture::icon volume-on]]
1643    $inner configure -borderwidth 4
1644
1645    set fg [option get $itk_component(hull) font Font]
1646    #set bfg [option get $itk_component(hull) boldFont Font]
1647
1648    label $inner.lighting_l \
1649        -text "Lighting / Material Properties" \
1650        -font "Arial 9 bold"
1651
1652    checkbutton $inner.isosurface -text "Isosurface shading" -font $fg \
1653        -variable [itcl::scope _settings(-isosurfaceshading)] \
1654        -command [itcl::code $this AdjustSetting -isosurfaceshading]
1655
1656    checkbutton $inner.light2side -text "Two-sided lighting" -font $fg \
1657        -variable [itcl::scope _settings(-light2side)] \
1658        -command [itcl::code $this AdjustSetting -light2side]
1659
1660    checkbutton $inner.visibility -text "Visible" -font $fg \
1661        -variable [itcl::scope _settings(-volumevisible)] \
1662        -command [itcl::code $this AdjustSetting -volumevisible]
1663
1664    label $inner.ambient_l -text "Ambient" -font $fg
1665    ::scale $inner.ambient -from 0 -to 100 -orient horizontal \
1666        -variable [itcl::scope _settings(-ambient)] \
1667        -showvalue off -command [itcl::code $this AdjustSetting -ambient] \
1668        -troughcolor grey92
1669
1670    label $inner.diffuse_l -text "Diffuse" -font $fg
1671    ::scale $inner.diffuse -from 0 -to 100 -orient horizontal \
1672        -variable [itcl::scope _settings(-diffuse)] \
1673        -showvalue off -command [itcl::code $this AdjustSetting -diffuse] \
1674        -troughcolor grey92
1675
1676    label $inner.specularLevel_l -text "Specular" -font $fg
1677    ::scale $inner.specularLevel -from 0 -to 100 -orient horizontal \
1678        -variable [itcl::scope _settings(-specularlevel)] \
1679        -showvalue off \
1680        -command [itcl::code $this AdjustSetting -specularlevel] \
1681        -troughcolor grey92
1682
1683    label $inner.specularExponent_l -text "Shininess" -font $fg
1684    ::scale $inner.specularExponent -from 10 -to 128 -orient horizontal \
1685        -variable [itcl::scope _settings(-specularexponent)] \
1686        -showvalue off \
1687        -command [itcl::code $this AdjustSetting -specularexponent] \
1688        -troughcolor grey92
1689
1690    # Opacity
1691    label $inner.opacity_l -text "Opacity" -font $fg
1692    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1693        -variable [itcl::scope _settings(-opacity)] \
1694        -showvalue off -command [itcl::code $this AdjustSetting -opacity] \
1695        -troughcolor grey92
1696
1697    label $inner.transferfunction_l \
1698        -text "Transfer Function" -font "Arial 9 bold"
1699
1700    # Tooth thickness
1701    label $inner.thin -text "Thin" -font $fg
1702    ::scale $inner.thickness -from 0 -to 1000 -orient horizontal \
1703        -variable [itcl::scope _settings(-thickness)] \
1704        -showvalue off -command [itcl::code $this AdjustSetting -thickness] \
1705        -troughcolor grey92
1706    label $inner.thick -text "Thick" -font $fg
1707
1708    # Colormap
1709    label $inner.colormap_l -text "Colormap" -font $fg
1710    itk_component add colormap {
1711        Rappture::Combobox $inner.colormap -width 10 -editable no
1712    }
1713
1714    $inner.colormap choices insert end [GetColormapList -includeDefault -includeNone]
1715    bind $inner.colormap <<Value>> \
1716        [itcl::code $this AdjustSetting -colormap]
1717    $itk_component(colormap) value "default"
1718    set _settings(-colormap) "default"
1719
1720    # Component
1721    label $inner.volcomponents_l -text "Component" -font $fg
1722    itk_component add volcomponents {
1723        Rappture::Combobox $inner.volcomponents -editable no
1724    }
1725    bind $inner.volcomponents <<Value>> \
1726        [itcl::code $this AdjustSetting -current]
1727
1728    blt::table $inner \
1729        0,0 $inner.volcomponents_l -anchor e -cspan 2 \
1730        0,2 $inner.volcomponents -cspan 3 -fill x \
1731        1,1 $inner.lighting_l -anchor w -cspan 4 \
1732        2,1 $inner.ambient_l -anchor e \
1733        2,2 $inner.ambient -cspan 3 -fill x \
1734        3,1 $inner.diffuse_l -anchor e \
1735        3,2 $inner.diffuse -cspan 3 -fill x \
1736        4,1 $inner.specularLevel_l -anchor e \
1737        4,2 $inner.specularLevel -cspan 3 -fill x \
1738        5,1 $inner.specularExponent_l -anchor e \
1739        5,2 $inner.specularExponent -cspan 3 -fill x \
1740        6,1 $inner.light2side -cspan 3 -anchor w \
1741        7,1 $inner.visibility -cspan 3 -anchor w \
1742        8,1 $inner.transferfunction_l -anchor w -cspan 4 \
1743        9,1 $inner.opacity_l -anchor e \
1744        9,2 $inner.opacity -cspan 3 -fill x \
1745        10,1 $inner.colormap_l -anchor e \
1746        10,2 $inner.colormap -padx 2 -cspan 3 -fill x \
1747        11,1 $inner.thin -anchor e \
1748        11,2 $inner.thickness -cspan 2 -fill x \
1749        11,4 $inner.thick -anchor w
1750
1751    blt::table configure $inner c* r* -resize none
1752    blt::table configure $inner r* -pady { 2 0 }
1753    blt::table configure $inner c2 c3 r12 -resize expand
1754    blt::table configure $inner c0 -width .1i
1755}
1756
1757itcl::body Rappture::NanovisViewer::BuildCutplanesTab {} {
1758    set inner [$itk_component(main) insert end \
1759        -title "Cutplane Settings" \
1760        -icon [Rappture::icon cutbutton]]
1761    $inner configure -borderwidth 4
1762
1763    checkbutton $inner.visible \
1764        -text "Show Cutplanes" \
1765        -variable [itcl::scope _settings(-cutplanesvisible)] \
1766        -command [itcl::code $this AdjustSetting -cutplanesvisible] \
1767        -font "Arial 9"
1768
1769    # X-value slicer...
1770    itk_component add xCutButton {
1771        Rappture::PushButton $inner.xbutton \
1772            -onimage [Rappture::icon x-cutplane] \
1773            -offimage [Rappture::icon x-cutplane] \
1774            -command [itcl::code $this AdjustSetting -xcutplanevisible] \
1775            -variable [itcl::scope _settings(-xcutplanevisible)]
1776    }
1777    Rappture::Tooltip::for $itk_component(xCutButton) \
1778        "Toggle the X cut plane on/off"
1779    $itk_component(xCutButton) select
1780
1781    itk_component add xCutScale {
1782        ::scale $inner.xval -from 100 -to 0 \
1783            -width 10 -orient vertical -showvalue off \
1784            -borderwidth 1 -highlightthickness 0 \
1785            -command [itcl::code $this Slice move x] \
1786            -variable [itcl::scope _settings(-xcutplaneposition)]
1787    } {
1788        usual
1789        ignore -borderwidth -highlightthickness
1790    }
1791    # Set the default cutplane value before disabling the scale.
1792    $itk_component(xCutScale) set 50
1793    $itk_component(xCutScale) configure -state disabled
1794    Rappture::Tooltip::for $itk_component(xCutScale) \
1795        "@[itcl::code $this SlicerTip x]"
1796
1797    # Y-value slicer...
1798    itk_component add yCutButton {
1799        Rappture::PushButton $inner.ybutton \
1800            -onimage [Rappture::icon y-cutplane] \
1801            -offimage [Rappture::icon y-cutplane] \
1802            -command [itcl::code $this AdjustSetting -ycutplanevisible] \
1803            -variable [itcl::scope _settings(-ycutplanevisible)]
1804    }
1805    Rappture::Tooltip::for $itk_component(yCutButton) \
1806        "Toggle the Y cut plane on/off"
1807    $itk_component(yCutButton) select
1808
1809    itk_component add yCutScale {
1810        ::scale $inner.yval -from 100 -to 0 \
1811            -width 10 -orient vertical -showvalue off \
1812            -borderwidth 1 -highlightthickness 0 \
1813            -command [itcl::code $this Slice move y] \
1814            -variable [itcl::scope _settings(-ycutplaneposition)]
1815    } {
1816        usual
1817        ignore -borderwidth -highlightthickness
1818    }
1819    Rappture::Tooltip::for $itk_component(yCutScale) \
1820        "@[itcl::code $this SlicerTip y]"
1821    # Set the default cutplane value before disabling the scale.
1822    $itk_component(yCutScale) set 50
1823    $itk_component(yCutScale) configure -state disabled
1824
1825    # Z-value slicer...
1826    itk_component add zCutButton {
1827        Rappture::PushButton $inner.zbutton \
1828            -onimage [Rappture::icon z-cutplane] \
1829            -offimage [Rappture::icon z-cutplane] \
1830            -command [itcl::code $this AdjustSetting -zcutplanevisible] \
1831            -variable [itcl::scope _settings(-zcutplanevisible)]
1832    }
1833    Rappture::Tooltip::for $itk_component(zCutButton) \
1834        "Toggle the Z cut plane on/off"
1835    $itk_component(zCutButton) select
1836
1837    itk_component add zCutScale {
1838        ::scale $inner.zval -from 100 -to 0 \
1839            -width 10 -orient vertical -showvalue off \
1840            -borderwidth 1 -highlightthickness 0 \
1841            -command [itcl::code $this Slice move z] \
1842            -variable [itcl::scope _settings(-zcutplaneposition)]
1843    } {
1844        usual
1845        ignore -borderwidth -highlightthickness
1846    }
1847    $itk_component(zCutScale) set 50
1848    $itk_component(zCutScale) configure -state disabled
1849    Rappture::Tooltip::for $itk_component(zCutScale) \
1850        "@[itcl::code $this SlicerTip z]"
1851
1852    blt::table $inner \
1853        0,1 $inner.visible -anchor w -pady 2 -cspan 4 \
1854        1,1 $itk_component(xCutScale) \
1855        1,2 $itk_component(yCutScale) \
1856        1,3 $itk_component(zCutScale) \
1857        2,1 $itk_component(xCutButton) \
1858        2,2 $itk_component(yCutButton) \
1859        2,3 $itk_component(zCutButton)
1860
1861    blt::table configure $inner r0 r1 r2 c* -resize none
1862    blt::table configure $inner r3 c4 -resize expand
1863    blt::table configure $inner c0 -width 2
1864    blt::table configure $inner c1 c2 c3 -padx 2
1865}
1866
1867itcl::body Rappture::NanovisViewer::BuildCameraTab {} {
1868    set inner [$itk_component(main) insert end \
1869        -title "Camera Settings" \
1870        -icon [Rappture::icon camera]]
1871    $inner configure -borderwidth 4
1872
1873    label $inner.view_l -text "view" -font "Arial 9"
1874    set f [frame $inner.view]
1875    foreach side { front back left right top bottom } {
1876        button $f.$side  -image [Rappture::icon view$side] \
1877            -command [itcl::code $this SetOrientation $side]
1878        Rappture::Tooltip::for $f.$side "Change the view to $side"
1879        pack $f.$side -side left
1880    }
1881
1882    blt::table $inner \
1883        0,0 $inner.view_l -anchor e -pady 2 \
1884        0,1 $inner.view -anchor w -pady 2
1885    blt::table configure $inner r0 -resize none
1886
1887    set row 1
1888    set labels { qw qx qy qz xpan ypan zoom }
1889    foreach tag $labels {
1890        label $inner.${tag}label -text $tag -font "Arial 9"
1891        entry $inner.${tag} -font "Arial 9"  -bg white \
1892            -textvariable [itcl::scope _settings(-$tag)]
1893        bind $inner.${tag} <Return> \
1894            [itcl::code $this camera set -${tag}]
1895        bind $inner.${tag} <KP_Enter> \
1896            [itcl::code $this camera set -${tag}]
1897        blt::table $inner \
1898            $row,0 $inner.${tag}label -anchor e -pady 2 \
1899            $row,1 $inner.${tag} -anchor w -pady 2
1900        blt::table configure $inner r$row -resize none
1901        incr row
1902    }
1903
1904    blt::table configure $inner c* -resize none
1905    blt::table configure $inner c2 -resize expand
1906    blt::table configure $inner r$row -resize expand
1907}
1908
1909# ----------------------------------------------------------------------
1910# USAGE: Slice move x|y|z <newval>
1911#
1912# Called automatically when the user drags the slider to move the
1913# cut plane that slices 3D data.  Gets the current value from the
1914# slider and moves the cut plane to the appropriate point in the
1915# data set.
1916# ----------------------------------------------------------------------
1917itcl::body Rappture::NanovisViewer::Slice {option args} {
1918    switch -- $option {
1919        move {
1920            if {[llength $args] != 2} {
1921                error "wrong # args: should be \"Slice move x|y|z newval\""
1922            }
1923            set axis [lindex $args 0]
1924            set newval [lindex $args 1]
1925
1926            set newpos [expr {0.01*$newval}]
1927            set datasets [CurrentDatasets -cutplanes]
1928            set tag [lindex $datasets 0]
1929            SendCmd "cutplane position $newpos $axis $tag"
1930        }
1931        default {
1932            error "bad option \"$option\": should be axis, move, or volume"
1933        }
1934    }
1935}
1936
1937# ----------------------------------------------------------------------
1938# USAGE: SlicerTip <axis>
1939#
1940# Used internally to generate a tooltip for the x/y/z slicer controls.
1941# Returns a message that includes the current slicer value.
1942# ----------------------------------------------------------------------
1943itcl::body Rappture::NanovisViewer::SlicerTip {axis} {
1944    set val [$itk_component(${axis}CutScale) get]
1945    return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
1946}
1947
1948itcl::body Rappture::NanovisViewer::DoResize {} {
1949    $_arcball resize $_width $_height
1950    SendCmd "screen size $_width $_height"
1951    set _resizePending 0
1952}
1953
1954itcl::body Rappture::NanovisViewer::EventuallyResize { w h } {
1955    set _width $w
1956    set _height $h
1957    $_arcball resize $w $h
1958    if { !$_resizePending } {
1959        $_dispatcher event -idle !resize
1960        set _resizePending 1
1961    }
1962}
1963
1964itcl::body Rappture::NanovisViewer::EventuallyRedrawLegend {} {
1965    if { !$_resizeLegendPending } {
1966        $_dispatcher event -idle !legend
1967        set _resizeLegendPending 1
1968    }
1969}
1970
1971#  camera --
1972#
1973itcl::body Rappture::NanovisViewer::camera {option args} {
1974    switch -- $option {
1975        "show" {
1976            puts [array get _view]
1977        }
1978        "set" {
1979            set what [lindex $args 0]
1980            set x $_settings($what)
1981            set code [catch { string is double $x } result]
1982            if { $code != 0 || !$result } {
1983                set _settings($what) $_view($what)
1984                return
1985            }
1986            switch -- $what {
1987                "-xpan" - "-ypan" {
1988                    set _view($what) $_settings($what)
1989                    PanCamera
1990                }
1991                "-qx" - "-qy" - "-qz" - "-qw" {
1992                    set _view($what) $_settings($what)
1993                    set q [ViewToQuaternion]
1994                    $_arcball quaternion $q
1995                    SendCmd "camera orient $q"
1996                }
1997                "-zoom" {
1998                    set _view($what) $_settings($what)
1999                    SendCmd "camera zoom $_view($what)"
2000                }
2001            }
2002        }
2003    }
2004}
2005
2006itcl::body Rappture::NanovisViewer::GetVtkData { args } {
2007    # FIXME: We can only put one component of one dataset in a single
2008    # VTK file.  To download all components/results, we would need
2009    # to put them in an archive (e.g. zip or tar file)
2010    if { $_first != "" && $_current != "" } {
2011        set bytes [$_first vtkdata $_current]
2012        return [list .vtk $bytes]
2013    }
2014    puts stderr "Failed to get vtkdata"
2015    return ""
2016}
2017
2018itcl::body Rappture::NanovisViewer::GetImage { args } {
2019    if { [image width $_image(download)] > 0 &&
2020         [image height $_image(download)] > 0 } {
2021        set bytes [$_image(download) data -format "jpeg -quality 100"]
2022        set bytes [Rappture::encoding::decode -as b64 $bytes]
2023        return [list .jpg $bytes]
2024    }
2025    return ""
2026}
2027
2028itcl::body Rappture::NanovisViewer::BuildDownloadPopup { popup command } {
2029    Rappture::Balloon $popup \
2030        -title "[Rappture::filexfer::label downloadWord] as..."
2031    set inner [$popup component inner]
2032    label $inner.summary -text "" -anchor w
2033
2034    radiobutton $inner.vtk_button -text "VTK data file" \
2035        -variable [itcl::scope _downloadPopup(format)] \
2036        -font "Arial 9" \
2037        -value vtk
2038    Rappture::Tooltip::for $inner.vtk_button "Save as VTK data file."
2039
2040    radiobutton $inner.image_button -text "Image File" \
2041        -variable [itcl::scope _downloadPopup(format)] \
2042        -font "Arial 9 " \
2043        -value image
2044    Rappture::Tooltip::for $inner.image_button \
2045        "Save as digital image."
2046
2047    button $inner.ok -text "Save" \
2048        -highlightthickness 0 -pady 2 -padx 3 \
2049        -command $command \
2050        -compound left \
2051        -image [Rappture::icon download]
2052
2053    button $inner.cancel -text "Cancel" \
2054        -highlightthickness 0 -pady 2 -padx 3 \
2055        -command [list $popup deactivate] \
2056        -compound left \
2057        -image [Rappture::icon cancel]
2058
2059    blt::table $inner \
2060        0,0 $inner.summary -cspan 2  \
2061        1,0 $inner.vtk_button -anchor w -cspan 2 -padx { 4 0 } \
2062        2,0 $inner.image_button -anchor w -cspan 2 -padx { 4 0 } \
2063        4,1 $inner.cancel -width .9i -fill y \
2064        4,0 $inner.ok -padx 2 -width .9i -fill y
2065    blt::table configure $inner r3 -height 4
2066    blt::table configure $inner r4 -pady 4
2067    raise $inner.image_button
2068    $inner.vtk_button invoke
2069    return $inner
2070}
2071
2072itcl::body Rappture::NanovisViewer::SetOrientation { side } {
2073    array set positions {
2074        front "1 0 0 0"
2075        back  "0 0 1 0"
2076        left  "0.707107 0 -0.707107 0"
2077        right "0.707107 0 0.707107 0"
2078        top   "0.707107 -0.707107 0 0"
2079        bottom "0.707107 0.707107 0 0"
2080    }
2081    foreach name { -qw -qx -qy -qz } value $positions($side) {
2082        set _view($name) $value
2083    }
2084    set q [ViewToQuaternion]
2085    $_arcball quaternion $q
2086    SendCmd "camera orient $q"
2087    SendCmd "camera reset"
2088    set _view(-xpan) 0
2089    set _view(-ypan) 0
2090    set _view(-zoom) 1.0
2091    set _settings(-xpan) $_view(-xpan)
2092    set _settings(-ypan) $_view(-ypan)
2093    set _settings(-zoom) $_view(-zoom)
2094}
2095
2096#
2097# InitComponentSettings --
2098#
2099#    Initializes the volume settings for a specific component. This should
2100#    match what's used as global settings above. This is called the first
2101#    time we try to switch to a given component in SwitchComponent below.
2102#
2103itcl::body Rappture::NanovisViewer::InitComponentSettings { cname } {
2104    foreach {key value} {
2105        -ambient           60
2106        -colormap          "default"
2107        -diffuse           40
2108        -light2side        1
2109        -opacity           50
2110        -specularexponent  90
2111        -specularlevel     30
2112        -thickness         350
2113        -volumevisible     1
2114    } {
2115        set _settings($cname${key}) $value
2116    }
2117}
2118
2119#
2120# SwitchComponent --
2121#
2122#    This is called when the current component is changed by the dropdown
2123#    menu in the volume tab.  It synchronizes the global volume settings
2124#    with the settings of the new current component.
2125#
2126itcl::body Rappture::NanovisViewer::SwitchComponent { cname } {
2127    if { ![info exists _settings($cname-ambient)] } {
2128        InitComponentSettings $cname
2129    }
2130    # _settings variables change widgets, except for colormap
2131    set _settings(-ambient)          $_settings($cname-ambient)
2132    set _settings(-colormap)         $_settings($cname-colormap)
2133    set _settings(-diffuse)          $_settings($cname-diffuse)
2134    set _settings(-light2side)       $_settings($cname-light2side)
2135    set _settings(-opacity)          $_settings($cname-opacity)
2136    set _settings(-specularexponent) $_settings($cname-specularexponent)
2137    set _settings(-specularlevel)    $_settings($cname-specularlevel)
2138    set _settings(-thickness)        $_settings($cname-thickness)
2139    set _settings(-volumevisible)    $_settings($cname-volumevisible)
2140    $itk_component(colormap) value   $_settings($cname-colormap)
2141    set _current $cname;                # Reset the current component
2142}
2143
2144#
2145# BuildVolumeComponents --
2146#
2147#    This is called from the "scale" method which is called when a new
2148#    dataset is added or deleted.  It repopulates the dropdown menu of
2149#    volume component names.  It sets the current component to the first
2150#    component in the list (of components found).  Finally, if there is
2151#    only one component, don't display the label or the combobox in the
2152#    volume settings tab.
2153#
2154itcl::body Rappture::NanovisViewer::BuildVolumeComponents {} {
2155    $itk_component(volcomponents) choices delete 0 end
2156    foreach name $_componentsList {
2157        $itk_component(volcomponents) choices insert end $name $name
2158    }
2159    set _current [lindex $_componentsList 0]
2160    $itk_component(volcomponents) value $_current
2161    set parent [winfo parent $itk_component(volcomponents)]
2162    if { [llength $_componentsList] <= 1 } {
2163        # Unpack the components label and dropdown if there's only one
2164        # component.
2165        blt::table forget $parent.volcomponents_l $parent.volcomponents
2166    } else {
2167        # Pack the components label and dropdown into the table there's
2168        # more than one component to select.
2169        blt::table $parent \
2170            0,0 $parent.volcomponents_l -anchor e -cspan 2 \
2171            0,2 $parent.volcomponents -cspan 3 -fill x
2172    }
2173}
2174
2175#
2176# GetDatasetsWithComponents --
2177#
2178#    Returns a list of all the datasets (known by the combination of their
2179#    data object and component name) that match the given component name.
2180#    For example, this is used where we want to change the settings of
2181#    volumes that have the current component.
2182#
2183itcl::body Rappture::NanovisViewer::GetDatasetsWithComponent { cname } {
2184    if { ![info exists _volcomponents($cname)] } {
2185        return ""
2186    }
2187    set list ""
2188    foreach tag $_volcomponents($cname) {
2189        if { ![info exists _datasets($tag)] } {
2190            continue
2191        }
2192        lappend list $tag
2193    }
2194    return $list
2195}
2196
2197#
2198# HideAllMarkers --
2199#
2200#    Hide all the markers in all the transfer functions.  Can't simply
2201#    delete and recreate markers from the <style> since the user may have
2202#    created, deleted, or moved markers.
2203#
2204itcl::body Rappture::NanovisViewer::HideAllMarkers {} {
2205    foreach cname [array names _transferFunctionEditors] {
2206        $_transferFunctionEditors($cname) hideMarkers
2207    }
2208}
2209
2210itcl::body Rappture::NanovisViewer::GetColormap { cname color } {
2211    if { $color == "default" } {
2212        return $_cname2defaultcolormap($cname)
2213    }
2214    return [ColorsToColormap $color]
2215}
2216
2217itcl::body Rappture::NanovisViewer::ResetColormap { cname color } {
2218    # Get the current transfer function
2219    if { ![info exists _cname2transferFunction($cname)] } {
2220        return
2221    }
2222    foreach { cmap amap } $_cname2transferFunction($cname) break
2223    set cmap [GetColormap $cname $color]
2224    set _cname2transferFunction($cname) [list $cmap $amap]
2225    SendCmd [list transfunc define $cname $cmap $amap]
2226    EventuallyRedrawLegend
2227}
2228
2229itcl::body Rappture::NanovisViewer::ComputeAlphamap { cname } {
2230    if { ![info exists _transferFunctionEditors($cname)] } {
2231        return [list 0.0 0.0 1.0 1.0]
2232    }
2233    if { ![info exists _settings($cname-ambient)] } {
2234        InitComponentSettings $cname
2235    }
2236
2237    set isovalues [$_transferFunctionEditors($cname) values]
2238
2239    # Transfer function should be normalized with [0,1] range
2240    # The volume shading opacity setting is used to scale opacity
2241    # in the volume shader.
2242    set max 1.0
2243
2244    # Use the component-wise thickness setting from the slider
2245    # settings widget
2246    # Scale values between 0.00001 and 0.01000
2247    set delta [expr {double($_settings($cname-thickness)) * 0.0001}]
2248
2249    set first [lindex $isovalues 0]
2250    set last [lindex $isovalues end]
2251    set amap ""
2252    if { $first == "" || $first != 0.0 } {
2253        lappend amap 0.0 0.0
2254    }
2255    foreach x $isovalues {
2256        set x1 [expr {$x-$delta-0.00001}]
2257        set x2 [expr {$x-$delta}]
2258        set x3 [expr {$x+$delta}]
2259        set x4 [expr {$x+$delta+0.00001}]
2260        if { $x1 < 0.0 } {
2261            set x1 0.0
2262        } elseif { $x1 > 1.0 } {
2263            set x1 1.0
2264        }
2265        if { $x2 < 0.0 } {
2266            set x2 0.0
2267        } elseif { $x2 > 1.0 } {
2268            set x2 1.0
2269        }
2270        if { $x3 < 0.0 } {
2271            set x3 0.0
2272        } elseif { $x3 > 1.0 } {
2273            set x3 1.0
2274        }
2275        if { $x4 < 0.0 } {
2276            set x4 0.0
2277        } elseif { $x4 > 1.0 } {
2278            set x4 1.0
2279        }
2280        # add spikes in the middle
2281        lappend amap $x1 0.0
2282        lappend amap $x2 $max
2283        lappend amap $x3 $max
2284        lappend amap $x4 0.0
2285    }
2286    if { $last == "" || $last != 1.0 } {
2287        lappend amap 1.0 0.0
2288    }
2289    return $amap
2290}
2291
2292itcl::body Rappture::NanovisViewer::SetObjectStyle { dataobj cname } {
2293    array set style {
2294        -opacity 0.5
2295    }
2296    array set style [lindex [$dataobj components -style $cname] 0]
2297    # Some tools erroneously set -opacity to 1 in style, so
2298    # override the requested opacity for now
2299    set style(-opacity) 0.5
2300    set _settings($cname-opacity) [expr $style(-opacity) * 100.0]
2301    set tag $dataobj-$cname
2302    SendCmd "volume shading opacity $style(-opacity) $tag"
2303    NameTransferFunction $dataobj $cname
2304}
Note: See TracBrowser for help on using the repository browser.