source: branches/1.3/gui/scripts/nanovisviewer.tcl @ 4768

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

merge r4767 from trunk

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