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

Last change on this file since 4528 was 4528, checked in by ldelgass, 10 years ago

Merge r4506 from trunk

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