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

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

Some changes to sync nanovis viewer with release branch

File size: 89.8 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: nanovisviewer - 3D volume rendering
4#
5#  This widget performs volume rendering on 3D scalar/vector datasets.
6#  It connects to the Nanovis server running on a rendering farm,
7#  transmits data, and displays the results.
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
11#
12#  See the file "license.terms" for information on usage and
13#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14# ======================================================================
15package require Itk
16package require BLT
17package require Img
18
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 _first "" ;        # This is the topmost volume.
152    private variable _current "";       # Currently selected component
153    private variable _volcomponents   ; # Array of components found
154    private variable _componentsList   ; # Array of components found
155    private variable _cname2style
156    private variable _cname2transferFunction
157    private variable _cname2defaultcolormap
158    private variable _cname2defaultalphamap
159
160    common _downloadPopup          ;# download options from popup
161    private common _hardcopy
162    private variable _width 0
163    private variable _height 0
164    private variable _resizePending 0
165    private variable _resizeLegendPending 0
166}
167
168itk::usual NanovisViewer {
169    keep -background -foreground -cursor -font
170    keep -plotbackground -plotforeground
171}
172
173# ----------------------------------------------------------------------
174# CONSTRUCTOR
175# ----------------------------------------------------------------------
176itcl::body Rappture::NanovisViewer::constructor {hostlist args} {
177    set _serverType "nanovis"
178
179    # Draw legend event
180    $_dispatcher register !legend
181    $_dispatcher dispatch $this !legend "[itcl::code $this FixLegend]; list"
182
183    # Send transfer functions event
184    $_dispatcher register !send_transfunc
185    $_dispatcher dispatch $this !send_transfunc \
186        "[itcl::code $this SendTransferFunctions]; list"
187
188    # Rebuild event
189    $_dispatcher register !rebuild
190    $_dispatcher dispatch $this !rebuild "[itcl::code $this Rebuild]; list"
191
192    # Resize event
193    $_dispatcher register !resize
194    $_dispatcher dispatch $this !resize "[itcl::code $this DoResize]; list"
195
196    #
197    # Populate parser with commands handle incoming requests
198    #
199    $_parser alias image [itcl::code $this ReceiveImage]
200    $_parser alias legend [itcl::code $this ReceiveLegend]
201    $_parser alias data [itcl::code $this ReceiveData]
202
203    # Initialize the view to some default parameters.
204    array set _view {
205        -qw      0.853553
206        -qx      -0.353553
207        -qy      0.353553
208        -qz      0.146447
209        -xpan    0
210        -ypan    0
211        -zoom    1.0
212    }
213    set _arcball [blt::arcball create 100 100]
214    $_arcball quaternion [ViewToQuaternion]
215
216    set _limits(v) [list 0.0 1.0]
217    set _reset 1
218
219    array set _settings {
220        -ambient                60
221        -axesvisible            1
222        -background             black
223        -colormap               "default"
224        -cutplanesvisible       0
225        -diffuse                40
226        -gridvisible            0
227        -isosurfaceshading      0
228        -legendvisible          1
229        -light2side             1
230        -opacity                50
231        -outlinevisible         0
232        -qw                     0.853553
233        -qx                     -0.353553
234        -qy                     0.353553
235        -qz                     0.146447
236        -specularexponent       90
237        -specularlevel          30
238        -thickness              350
239        -volume                 1
240        -volumevisible          1
241        -xcutplaneposition      50
242        -xcutplanevisible       1
243        -xpan                   0
244        -ycutplaneposition      50
245        -ycutplanevisible       1
246        -ypan                   0
247        -zcutplaneposition      50
248        -zcutplanevisible       1
249        -zoom                   1.0
250    }
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 "version" "$Rappture::version"
676            lappend info "build" "$Rappture::build"
677            lappend info "svnurl" "$Rappture::svnurl"
678            lappend info "installdir" "$Rappture::installdir"
679            lappend info "hub" [exec hostname]
680            lappend info "client" "nanovisviewer"
681            lappend info "user" $user
682            lappend info "session" $session
683            SendCmd "clientinfo [list $info]"
684        }
685
686        set w [winfo width $itk_component(3dview)]
687        set h [winfo height $itk_component(3dview)]
688        EventuallyResize $w $h
689    }
690    return $result
691}
692
693#
694# isconnected --
695#
696#       Indicates if we are currently connected to the visualization server.
697#
698itcl::body Rappture::NanovisViewer::isconnected {} {
699    return [VisViewer::IsConnected]
700}
701
702#
703# disconnect --
704#
705itcl::body Rappture::NanovisViewer::disconnect {} {
706    Disconnect
707}
708
709#
710# Disconnect --
711#
712#       Clients use this method to disconnect from the current rendering
713#       server.
714#
715itcl::body Rappture::NanovisViewer::Disconnect {} {
716    VisViewer::Disconnect
717
718    # disconnected -- no more data sitting on server
719    array unset _serverDatasets
720}
721
722# ----------------------------------------------------------------------
723# USAGE: SendTransferFunctions
724# ----------------------------------------------------------------------
725itcl::body Rappture::NanovisViewer::SendTransferFunctions {} {
726    foreach cname [array names _volcomponents] {
727        ComputeTransferFunction $cname
728    }
729    FixLegend
730}
731
732# ----------------------------------------------------------------------
733# USAGE: ReceiveImage -bytes <size> -type <type> -token <token>
734#
735# Invoked automatically whenever the "image" command comes in from
736# the rendering server.  Indicates that binary image data with the
737# specified <size> will follow.
738# ----------------------------------------------------------------------
739itcl::body Rappture::NanovisViewer::ReceiveImage { args } {
740    array set info {
741        -token "???"
742        -bytes 0
743        -type image
744    }
745    array set info $args
746    set bytes [ReceiveBytes $info(-bytes)]
747    ReceiveEcho <<line "<read $info(-bytes) bytes"
748    if { $info(-type) == "image" } {
749        ReceiveEcho "for [image width $_image(plot)]x[image height $_image(plot)] image>"       
750        $_image(plot) configure -data $bytes
751    } elseif { $info(-type) == "print" } {
752        set tag $this-print-$info(-token)
753        set _hardcopy($tag) $bytes
754    }
755}
756
757#
758# DrawLegend --
759#
760itcl::body Rappture::NanovisViewer::DrawLegend { cname } {
761    set c $itk_component(legend)
762    set w [winfo width $c]
763    set h [winfo height $c]
764    set lx 10
765    set ly [expr {$h - 1}]
766    if {"" == [$c find withtag colorbar]} {
767        $c create image 10 10 -anchor nw \
768            -image $_image(legend) -tags colorbar
769        $c create text $lx $ly -anchor sw \
770            -fill $itk_option(-plotforeground) -tags "limits text vmin"
771        $c create text [expr {$w-$lx}] $ly -anchor se \
772            -fill $itk_option(-plotforeground) -tags "limits text vmax"
773        $c create text [expr {$w/2}] $ly -anchor s \
774            -fill $itk_option(-plotforeground) -tags "limits text title"
775        $c lower colorbar
776        $c bind colorbar <ButtonRelease-1> [itcl::code $this AddNewMarker %x %y]
777    }
778
779    # Display the markers used by the current transfer function.
780    HideAllMarkers
781    $_transferFunctionEditors($cname) showMarkers $_limits($cname)
782
783    foreach {min max} $_limits($cname) break
784    $c itemconfigure vmin -text [format %g $min]
785    $c coords vmin $lx $ly
786
787    $c itemconfigure vmax -text [format %g $max]
788    $c coords vmax [expr {$w-$lx}] $ly
789
790    set title [$_first hints label]
791    set units [$_first hints units]
792    if { $units != "" } {
793        set title "$title ($units)"
794    }
795    $c itemconfigure title -text $title
796    $c coords title [expr {$w/2}] $ly
797
798    # The colormap may have changed. Resync the slicers with the colormap.
799    set datasets [CurrentDatasets -cutplanes]
800
801    # Adjust the cutplane for only the first component in the topmost volume
802    # (i.e. the first volume designated in the field).
803    set tag [lindex $datasets 0]
804    foreach axis {x y z} {
805        # Turn off cutplanes for all volumes
806        SendCmd "cutplane state 0 $axis"
807        if { $_settings(-${axis}cutplanevisible) } {
808            # Turn on cutplane for this particular volume and set the position
809            SendCmd "cutplane state 1 $axis $tag"
810            set pos [expr {0.01*$_settings(-${axis}cutplaneposition)}]
811            SendCmd "cutplane position $pos $axis $tag"
812        }
813    }
814}
815
816#
817#
818# ReceiveLegend --
819#
820#       The procedure is the response from the render server to each "legend"
821#       command.  The server sends back a "legend" command invoked our
822#       the slave interpreter.  The purpose is to collect data of the image
823#       representing the legend in the canvas.  In addition, the
824#       active transfer function is displayed.
825#
826#
827itcl::body Rappture::NanovisViewer::ReceiveLegend { cname vmin vmax size } {
828    if { ![isconnected] } {
829        return
830    }
831    set bytes [ReceiveBytes $size]
832    $_image(legend) configure -data $bytes
833    ReceiveEcho <<line "<read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
834
835    DrawLegend $_current
836}
837
838#
839# ReceiveData --
840#
841#       The procedure is the response from the render server to each "data
842#       follows" command.  The server sends back a "data" command invoked our
843#       the slave interpreter.  The purpose is to collect the min/max of the
844#       volume sent to the render server.  Since the client (nanovisviewer)
845#       doesn't parse 3D data formats, we rely on the server (nanovis) to
846#       tell us what the limits are.  Once we've received the limits to all
847#       the data we've sent (tracked by _recvdDatasets) we can then determine
848#       what the transfer functions are for these volumes.
849#
850#
851#       Note: There is a considerable tradeoff in having the server report
852#             back what the data limits are.  It means that much of the code
853#             having to do with transfer-functions has to wait for the data
854#             to come back, since the isomarkers are calculated based upon
855#             the data limits.  The client code is much messier because of
856#             this.  The alternative is to parse any of the 3D formats on the
857#             client side.
858#
859itcl::body Rappture::NanovisViewer::ReceiveData { args } {
860    if { ![isconnected] } {
861        return
862    }
863
864    # Arguments from server are name value pairs. Stuff them in an array.
865    array set info $args
866
867    set tag $info(tag)
868    set parts [split $tag -]
869
870    #
871    # Volumes don't exist until we're told about them.
872    #
873    set dataobj [lindex $parts 0]
874    set _serverDatasets($tag) 1
875    if { $_settings(-volumevisible) && $dataobj == $_first } {
876        SendCmd "volume state 1 $tag"
877    }
878    set _limits($tag) [list $info(min)  $info(max)]
879    set _limits(v)    [list $info(vmin) $info(vmax)]
880
881    unset _recvdDatasets($tag)
882    if { [array size _recvdDatasets] == 0 } {
883        updateTransferFunctions
884    }
885}
886
887# ----------------------------------------------------------------------
888# USAGE: Rebuild
889#
890# Called automatically whenever something changes that affects the
891# data in the widget.  Clears any existing data and rebuilds the
892# widget to display new data.
893# ----------------------------------------------------------------------
894itcl::body Rappture::NanovisViewer::Rebuild {} {
895    set w [winfo width $itk_component(3dview)]
896    set h [winfo height $itk_component(3dview)]
897    if { $w < 2 || $h < 2 } {
898        $_dispatcher event -idle !rebuild
899        return
900    }
901
902    # Turn on buffering of commands to the server.  We don't want to
903    # be preempted by a server disconnect/reconnect (which automatically
904    # generates a new call to Rebuild).   
905    StartBufferingCommands
906
907    if { $_width != $w || $_height != $h || $_reset } {
908        set _width $w
909        set _height $h
910        $_arcball resize $w $h
911        DoResize
912    }
913
914    foreach dataobj [get] {
915        foreach cname [$dataobj components] {
916            set tag $dataobj-$cname
917            if { ![info exists _serverDatasets($tag)] } {
918                # Send the data as one huge base64-encoded mess -- yuck!
919                if { [$dataobj type] == "dx" } {
920                    if { ![$dataobj isvalid] } {
921                        puts stderr "??? $dataobj is invalid"
922                    }
923                    set data [$dataobj blob $cname]
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 -ambient -diffuse -specularlevel \
979            -specularexponent -opacity -isosurfaceshading -gridvisible \
980            -axesvisible -xcutplanevisible -ycutplanevisible -zcutplanevisible \
981            -current
982
983        if {"" != $_first} {
984            set axis [$_first hints updir]
985            if { "" != $axis } {
986                SendCmd "up $axis"
987            }
988            set location [$_first hints camera]
989            if { $location != "" } {
990                array set _view $location
991            }
992        }
993    }
994    # Outline seems to need to be reset every update.
995    InitSettings -outlinevisible -cutplanesvisible
996    # nothing to send -- activate the proper ivol
997    SendCmd "volume state 0"
998    if {"" != $_first} {
999        set datasets [array names _serverDatasets $_first-*]
1000        if { $datasets != "" } {
1001            SendCmd "volume state 1 $datasets"
1002        }
1003        # If the first volume already exists on the server, then make sure
1004        # we display the proper transfer function in the legend.
1005        set cname [lindex [$_first components] 0]
1006        if { [info exists _serverDatasets($_first-$cname)] } {
1007            updateTransferFunctions
1008        }
1009    }
1010    # Actually write the commands to the server socket.  If it fails, we don't
1011    # care.  We're finished here.
1012    blt::busy hold $itk_component(hull)
1013    StopBufferingCommands
1014    blt::busy release $itk_component(hull)
1015    set _reset 0
1016}
1017
1018# ----------------------------------------------------------------------
1019# USAGE: CurrentDatasets ?-cutplanes?
1020#
1021# Returns a list of volume server IDs for the current volume being
1022# displayed.  This is normally a single ID, but it might be a list
1023# of IDs if the current data object has multiple components.
1024# ----------------------------------------------------------------------
1025itcl::body Rappture::NanovisViewer::CurrentDatasets {{what -all}} {
1026    set rlist ""
1027    if { $_first == "" } {
1028        return
1029    }
1030    foreach cname [$_first components] {
1031        set tag $_first-$cname
1032        if { [info exists _serverDatasets($tag)] && $_serverDatasets($tag) } {
1033            array set styles {
1034                -cutplanes 1
1035            }
1036            array set styles [lindex [$_first components -style $cname] 0]
1037            if { $what != "-cutplanes" || $styles(-cutplanes) } {
1038                lappend rlist $tag
1039            }
1040        }
1041    }
1042    return $rlist
1043}
1044
1045# ----------------------------------------------------------------------
1046# USAGE: Zoom in
1047# USAGE: Zoom out
1048# USAGE: Zoom reset
1049#
1050# Called automatically when the user clicks on one of the zoom
1051# controls for this widget.  Changes the zoom for the current view.
1052# ----------------------------------------------------------------------
1053itcl::body Rappture::NanovisViewer::Zoom {option} {
1054    switch -- $option {
1055        "in" {
1056            set _view(-zoom) [expr {$_view(-zoom)*1.25}]
1057            set _settings(-zoom) $_view(-zoom)
1058            SendCmd "camera zoom $_view(-zoom)"
1059        }
1060        "out" {
1061            set _view(-zoom) [expr {$_view(-zoom)*0.8}]
1062            set _settings(-zoom) $_view(-zoom)
1063            SendCmd "camera zoom $_view(-zoom)"
1064        }
1065        "reset" {
1066            array set _view {
1067                -qw      0.853553
1068                -qx      -0.353553
1069                -qy      0.353553
1070                -qz      0.146447
1071                -xpan    0
1072                -ypan    0
1073                -zoom    1.0
1074            }
1075            if { $_first != "" } {
1076                set location [$_first hints camera]
1077                if { $location != "" } {
1078                    array set _view $location
1079                }
1080            }
1081            set q [ViewToQuaternion]         
1082            $_arcball quaternion $q
1083            SendCmd "camera orient $q"
1084            SendCmd "camera reset"
1085            set _settings(-qw)    $_view(-qw)
1086            set _settings(-qx)    $_view(-qx)
1087            set _settings(-qy)    $_view(-qy)
1088            set _settings(-qz)    $_view(-qz)
1089            set _settings(-xpan)  $_view(-xpan)
1090            set _settings(-ypan)  $_view(-ypan)
1091            set _settings(-zoom)  $_view(-zoom)
1092        }
1093    }
1094}
1095
1096itcl::body Rappture::NanovisViewer::PanCamera {} {
1097    set x $_view(-xpan)
1098    set y $_view(-ypan)
1099    SendCmd "camera pan $x $y"
1100}
1101
1102
1103# ----------------------------------------------------------------------
1104# USAGE: Rotate click <x> <y>
1105# USAGE: Rotate drag <x> <y>
1106# USAGE: Rotate release <x> <y>
1107#
1108# Called automatically when the user clicks/drags/releases in the
1109# plot area.  Moves the plot according to the user's actions.
1110# ----------------------------------------------------------------------
1111itcl::body Rappture::NanovisViewer::Rotate {option x y} {
1112    switch -- $option {
1113        click {
1114            $itk_component(3dview) configure -cursor fleur
1115            set _click(x) $x
1116            set _click(y) $y
1117        }
1118        drag {
1119            if {[array size _click] == 0} {
1120                Rotate click $x $y
1121            } else {
1122                set w [winfo width $itk_component(3dview)]
1123                set h [winfo height $itk_component(3dview)]
1124                if {$w <= 0 || $h <= 0} {
1125                    return
1126                }
1127
1128                if {[catch {
1129                    # this fails sometimes for no apparent reason
1130                    set dx [expr {double($x-$_click(x))/$w}]
1131                    set dy [expr {double($y-$_click(y))/$h}]
1132                }]} {
1133                    return
1134                }
1135
1136                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1137                foreach { _view(-qw) _view(-qx) _view(-qy) _view(-qz) } $q break
1138                set _settings(-qw) $_view(-qw)
1139                set _settings(-qx) $_view(-qx)
1140                set _settings(-qy) $_view(-qy)
1141                set _settings(-qz) $_view(-qz)
1142                SendCmd "camera orient $q"
1143
1144                set _click(x) $x
1145                set _click(y) $y
1146            }
1147        }
1148        release {
1149            Rotate drag $x $y
1150            $itk_component(3dview) configure -cursor ""
1151            catch {unset _click}
1152        }
1153        default {
1154            error "bad option \"$option\": should be click, drag, release"
1155        }
1156    }
1157}
1158
1159# ----------------------------------------------------------------------
1160# USAGE: $this Pan click x y
1161#        $this Pan drag x y
1162#        $this Pan release x y
1163#
1164# Called automatically when the user clicks on one of the zoom
1165# controls for this widget.  Changes the zoom for the current view.
1166# ----------------------------------------------------------------------
1167itcl::body Rappture::NanovisViewer::Pan {option x y} {
1168    # Experimental stuff
1169    set w [winfo width $itk_component(3dview)]
1170    set h [winfo height $itk_component(3dview)]
1171    if { $option == "set" } {
1172        set x [expr $x / double($w)]
1173        set y [expr $y / double($h)]
1174        set _view(-xpan) [expr $_view(-xpan) + $x]
1175        set _view(-ypan) [expr $_view(-ypan) + $y]
1176        PanCamera
1177        set _settings(-xpan) $_view(-xpan)
1178        set _settings(-ypan) $_view(-ypan)
1179        return
1180    }
1181    if { $option == "click" } {
1182        set _click(x) $x
1183        set _click(y) $y
1184        $itk_component(3dview) configure -cursor hand1
1185    }
1186    if { $option == "drag" || $option == "release" } {
1187        set dx [expr ($_click(x) - $x)/double($w)]
1188        set dy [expr ($_click(y) - $y)/double($h)]
1189        set _click(x) $x
1190        set _click(y) $y
1191        set _view(-xpan) [expr $_view(-xpan) - $dx]
1192        set _view(-ypan) [expr $_view(-ypan) - $dy]
1193        PanCamera
1194        set _settings(-xpan) $_view(-xpan)
1195        set _settings(-ypan) $_view(-ypan)
1196    }
1197    if { $option == "release" } {
1198        $itk_component(3dview) configure -cursor ""
1199    }
1200}
1201
1202# ----------------------------------------------------------------------
1203# USAGE: InitSettings <what> ?<value>?
1204#
1205# Used internally to update rendering settings whenever parameters
1206# change in the popup settings panel.  Sends the new settings off
1207# to the back end.
1208# ----------------------------------------------------------------------
1209itcl::body Rappture::NanovisViewer::InitSettings { args } {
1210    foreach arg $args {
1211        AdjustSetting $arg
1212    }
1213}
1214
1215# ----------------------------------------------------------------------
1216# USAGE: AdjustSetting <what> ?<value>?
1217#
1218# Used internally to update rendering settings whenever parameters
1219# change in the popup settings panel.  Sends the new settings off
1220# to the back end.
1221# ----------------------------------------------------------------------
1222itcl::body Rappture::NanovisViewer::AdjustSetting {what {value ""}} {
1223    if {![isconnected]} {
1224        return
1225    }
1226    switch -- $what {
1227        "-ambient" {
1228            # Other parts of the code use the ambient setting to
1229            # tell if the component settings have been initialized
1230            if { ![info exists _settings($_current${what})] } {
1231                InitComponentSettings $_current
1232            }
1233            set _settings($_current${what}) $_settings($what)
1234            set val $_settings($what)
1235            set val [expr {0.01*$val}]
1236            foreach tag [GetDatasetsWithComponent $_current] {
1237                SendCmd "volume shading ambient $val $tag"
1238            }
1239        }
1240        "-axesvisible" {
1241            SendCmd "axis visible $_settings($what)"
1242        }
1243        "-background" {
1244            set bgcolor [$itk_component(background) value]
1245            array set fgcolors {
1246                "black" "white"
1247                "white" "black"
1248                "grey"  "black"
1249            }
1250            configure -plotbackground $bgcolor \
1251                -plotforeground $fgcolors($bgcolor)
1252            DrawLegend $_current
1253        }
1254        "-colormap" {
1255            set color [$itk_component(colormap) value]
1256            set _settings($what) $color
1257            set _settings($_current${what}) $color
1258            ResetColormap $_current $color
1259        }
1260        "-current" {
1261            set cname [$itk_component(volcomponents) value]
1262            SwitchComponent $cname
1263        }
1264        "-cutplanesvisible" {
1265            set bool $_settings($what)
1266            set datasets [CurrentDatasets -cutplanes]
1267            set tag [lindex $datasets 0]
1268            SendCmd "cutplane visible $bool $tag"
1269        }
1270        "-diffuse" {
1271            set _settings($_current${what}) $_settings($what)
1272            set val $_settings($what)
1273            set val [expr {0.01*$val}]
1274            foreach tag [GetDatasetsWithComponent $_current] {
1275                SendCmd "volume shading diffuse $val $tag"
1276            }
1277        }
1278        "-gridvisible" {
1279            SendCmd "grid visible $_settings($what)"
1280        }
1281        "-isosurfaceshading" {
1282            SendCmd "volume shading isosurface $_settings($what)"
1283        }
1284        "-legendvisible" {
1285            if { $_settings($what) } {
1286                blt::table $itk_component(plotarea) \
1287                    0,0 $itk_component(3dview) -fill both \
1288                    1,0 $itk_component(legend) -fill x
1289                blt::table configure $itk_component(plotarea) r1 -resize none
1290            } else {
1291                blt::table forget $itk_component(legend)
1292            }
1293        }
1294        "-light2side" {
1295            set _settings($_current${what}) $_settings($what)
1296            set val $_settings($what)
1297            foreach tag [GetDatasetsWithComponent $_current] {
1298                SendCmd "volume shading light2side $val $tag"
1299            }
1300        }
1301        "-opacity" {
1302            set _settings($_current${what}) $_settings($what)
1303            set val $_settings($what)
1304            set sval [expr { 0.01 * double($val) }]
1305            foreach tag [GetDatasetsWithComponent $_current] {
1306                SendCmd "volume shading opacity $sval $tag"
1307            }
1308        }
1309        "-outlinevisible" {
1310            SendCmd "volume outline state $_settings($what)"
1311        }
1312        "-outlinecolor" {
1313            set rgb [Color2RGB $_settings($what)]
1314            SendCmd "volume outline color $rgb"
1315        }
1316        "-specularlevel" {
1317            set _settings($_current${what}) $_settings($what)
1318            set val $_settings($what)
1319            set val [expr {0.01*$val}]
1320            foreach tag [GetDatasetsWithComponent $_current] {
1321                SendCmd "volume shading specularLevel $val $tag"
1322            }
1323        }
1324        "-specularexponent" {
1325            set _settings($_current${what}) $_settings($what)
1326            set val $_settings($what)
1327            foreach tag [GetDatasetsWithComponent $_current] {
1328                SendCmd "volume shading specularExp $val $tag"
1329            }
1330        }
1331        "-thickness" {
1332            set val $_settings($what)
1333            set _settings($_current${what}) $val
1334            updateTransferFunctions
1335        }
1336        "-volume" {
1337            # This is the global volume visibility control.  It controls the
1338            # visibility of all the all volumes.  Whenever it's changed, you
1339            # have to synchronize each of the local controls (see below) with
1340            # this.
1341            set datasets [CurrentDatasets]
1342            set bool $_settings($what)
1343            SendCmd "volume data state $bool $datasets"
1344            foreach cname $_componentsList {
1345                set _settings($cname-volumevisible) $bool
1346            }
1347            set _settings(-volumevisible) $bool
1348        }
1349        "-volumevisible" {
1350            # This is the component specific control.  It changes the
1351            # visibility of only the current component.
1352            set _settings($_current${what}) $_settings($what)
1353            foreach tag [GetDatasetsWithComponent $_current] {
1354                SendCmd "volume data state $_settings($what) $tag"
1355            }
1356        }
1357        "-xcutplanevisible" - "-ycutplanevisible" - "-zcutplanevisible" {
1358            set axis [string range $what 1 1]
1359            set bool $_settings($what)
1360            set datasets [CurrentDatasets -cutplanes]
1361            set tag [lindex $datasets 0]
1362            SendCmd "cutplane state $bool $axis $tag"
1363            if { $bool } {
1364                $itk_component(${axis}CutScale) configure -state normal \
1365                    -troughcolor white
1366            } else {
1367                $itk_component(${axis}CutScale) configure -state disabled \
1368                    -troughcolor grey82
1369            }
1370        }
1371        default {
1372            error "don't know how to fix $what"
1373        }
1374    }
1375}
1376
1377# ----------------------------------------------------------------------
1378# USAGE: FixLegend
1379#
1380# Used internally to update the legend area whenever it changes size
1381# or when the field changes.  Asks the server to send a new legend
1382# for the current field.
1383# ----------------------------------------------------------------------
1384itcl::body Rappture::NanovisViewer::FixLegend {} {
1385    set _resizeLegendPending 0
1386    set lineht [font metrics $itk_option(-font) -linespace]
1387    set w [expr {$_width-20}]
1388    set h [expr {[winfo height $itk_component(legend)]-20-$lineht}]
1389    if {$w > 0 && $h > 0 && $_first != "" } {
1390        if { [info exists _cname2transferFunction($_current)] } {
1391            SendCmd "legend $_current $w $h"
1392        }
1393    }
1394}
1395
1396#
1397# NameTransferFunction --
1398#
1399#       Creates a transfer function name based on the <style> settings in the
1400#       library run.xml file. This placeholder will be used later to create
1401#       and send the actual transfer function once the data info has been sent
1402#       to us by the render server. [We won't know the volume limits until the
1403#       server parses the 3D data and sends back the limits via ReceiveData.]
1404#
1405itcl::body Rappture::NanovisViewer::NameTransferFunction { dataobj cname } {
1406    array set styles {
1407        -color BCGYR
1408        -levels 6
1409        -markers ""
1410    }
1411    set tag $dataobj-$cname
1412    array set styles [lindex [$dataobj components -style $cname] 0]
1413    if { ![info exists _cname2transferFunction($cname)] } {
1414        # Get the colormap right now, since it doesn't change with marker
1415        # changes.
1416        set cmap [ColorsToColormap $styles(-color)]
1417        set wmap [list 0.0 0.0 1.0 1.0]
1418        set _cname2transferFunction($cname) [list $cmap $wmap]
1419        SendCmd [list transfunc define $cname $cmap $wmap]
1420    }
1421    SendCmd "volume shading transfunc $cname $tag"
1422    if { ![info exists _transferFunctionEditors($cname)] } {
1423        set _transferFunctionEditors($cname) \
1424            [Rappture::TransferFunctionEditor ::\#auto $itk_component(legend) \
1425                 $cname \
1426                 -command [itcl::code $this updateTransferFunctions]]
1427    }
1428    set _dataset2style($tag) $cname
1429    lappend _style2datasets($cname) $tag
1430    return $cname
1431}
1432
1433#
1434# ComputeTransferFunction --
1435#
1436#       Computes and sends the transfer function to the render server.  It's
1437#       assumed that the volume data limits are known and that the global
1438#       transfer-functions slider values have been set up.  Both parts are
1439#       needed to compute the relative value (location) of the marker, and
1440#       the alpha map of the transfer function.
1441#
1442itcl::body Rappture::NanovisViewer::ComputeTransferFunction { cname } {
1443    foreach {cmap wmap} $_cname2transferFunction($cname) break
1444
1445    # We have to parse the style attributes for a volume using this
1446    # transfer-function *once*.  This sets up the initial isomarkers for the
1447    # transfer function.  The user may add/delete markers, so we have to
1448    # maintain a list of markers for each transfer-function.  We use the one
1449    # of the volumes (the first in the list) using the transfer-function as a
1450    # reference.
1451    if { ![info exists _parsedFunction($cname)] } {
1452        array set styles {
1453            -color BCGYR
1454            -levels 6
1455            -markers ""
1456        }
1457        # Accumulate the style from all the datasets using it.
1458        foreach tag [GetDatasetsWithComponent $cname] {
1459            foreach {dataobj cname} [split [lindex $tag 0] -] break
1460            array set styles [lindex [$dataobj components -style $cname] 0]
1461        }
1462        eval $_transferFunctionEditors($cname) limits $_limits($cname)
1463        # Have to defer creation of isomarkers until we have data limits
1464        if { [info exists styles(-markers)] &&
1465             [llength $styles(-markers)] > 0 } {
1466            ParseMarkersOption $cname $styles(-markers)
1467        } else {
1468            ParseLevelsOption $cname $styles(-levels)
1469        }
1470       
1471    }
1472    set wmap [ComputeAlphamap $cname]
1473    set _cname2transferFunction($cname) [list $cmap $wmap]
1474    SendCmd [list transfunc define $cname $cmap $wmap]
1475}
1476
1477itcl::body Rappture::NanovisViewer::AddNewMarker { x y } {
1478    if { ![info exists _transferFunctionEditors($_current)] } {
1479        continue
1480    }
1481    # Add a new marker to the current transfer function
1482    $_transferFunctionEditors($_current) newMarker $x $y normal
1483    $itk_component(legend) itemconfigure labels -fill $itk_option(-plotforeground)
1484}
1485
1486itcl::body Rappture::NanovisViewer::RemoveMarker { x y } {
1487    if { ![info exists _transferFunctionEditors($_current)] } {
1488        continue
1489    }
1490    # Add a new marker to the current transfer function
1491    $_transferFunctionEditors($_current) deleteMarker $x $y
1492}
1493
1494# ----------------------------------------------------------------------
1495# CONFIGURATION OPTION: -plotbackground
1496# ----------------------------------------------------------------------
1497itcl::configbody Rappture::NanovisViewer::plotbackground {
1498    if { [isconnected] } {
1499        set color $itk_option(-plotbackground)
1500        set rgb [Color2RGB $color]
1501        SendCmd "screen bgcolor $rgb"
1502        $itk_component(legend) configure -background $color
1503    }
1504}
1505
1506# ----------------------------------------------------------------------
1507# CONFIGURATION OPTION: -plotforeground
1508# ----------------------------------------------------------------------
1509itcl::configbody Rappture::NanovisViewer::plotforeground {
1510    if { [isconnected] } {
1511        set color $itk_option(-plotforeground)
1512        set rgb [Color2RGB $color]
1513        SendCmd "volume outline color $rgb"
1514        SendCmd "grid axiscolor $rgb"
1515        SendCmd "grid linecolor $rgb"
1516        $itk_component(legend) itemconfigure labels -fill $color
1517        $itk_component(legend) itemconfigure limits -fill $color
1518    }
1519}
1520
1521# ----------------------------------------------------------------------
1522# CONFIGURATION OPTION: -plotoutline
1523# ----------------------------------------------------------------------
1524itcl::configbody Rappture::NanovisViewer::plotoutline {
1525    # Must check if we are connected because this routine is called from the
1526    # class body when the -plotoutline itk_option is defined.  At that point
1527    # the NanovisViewer class constructor hasn't been called, so we can't
1528    # start sending commands to visualization server.
1529    if { [isconnected] } {
1530        if {"" == $itk_option(-plotoutline)} {
1531            SendCmd "volume outline state off"
1532        } else {
1533            SendCmd "volume outline state on"
1534            SendCmd "volume outline color [Color2RGB $itk_option(-plotoutline)]"
1535        }
1536    }
1537}
1538
1539#
1540# The -levels option takes a single value that represents the number
1541# of evenly distributed markers based on the current data range. Each
1542# marker is a relative value from 0.0 to 1.0.
1543#
1544itcl::body Rappture::NanovisViewer::ParseLevelsOption { cname levels } {
1545    set c $itk_component(legend)
1546    set list {}
1547    regsub -all "," $levels " " levels
1548    if {[string is int $levels]} {
1549        for {set i 1} { $i <= $levels } {incr i} {
1550            lappend list [expr {double($i)/($levels+1)}]
1551        }
1552    } else {
1553        foreach x $levels {
1554            lappend list $x
1555        }
1556    }
1557    set _parsedFunction($cname) 1
1558    $_transferFunctionEditors($cname) addMarkers $list
1559    $itk_component(legend) itemconfigure labels -fill $itk_option(-plotforeground)
1560}
1561
1562#
1563# The -markers option takes a list of zero or more values (the values
1564# may be separated either by spaces or commas) that have the following
1565# format:
1566#
1567#   N%  Percent of current total data range.  Converted to
1568#       to a relative value between 0.0 and 1.0.
1569#   N   Absolute value of marker.  If the marker is outside of
1570#       the current range, it will be displayed on the outer
1571#       edge of the legends, but it range it represents will
1572#       not be seen.
1573#
1574itcl::body Rappture::NanovisViewer::ParseMarkersOption { cname markers } {
1575    set c $itk_component(legend)
1576    set list {}
1577    foreach { min max } $_limits($cname) break
1578    regsub -all "," $markers " " markers
1579    foreach marker $markers {
1580        set n [scan $marker "%g%s" value suffix]
1581        if { $n == 2 && $suffix == "%" } {
1582            # $n% : Set relative value (0..1).
1583            lappend list [expr {$value * 0.01}]
1584        } else {
1585            # $n : absolute value, compute relative
1586            lappend list  [expr {(double($value)-$min)/($max-$min)]}
1587        }
1588    }
1589    set _parsedFunction($cname) 1
1590    $_transferFunctionEditors($cname) addMarkers $list
1591    $itk_component(legend) itemconfigure labels -fill $itk_option(-plotforeground)
1592}
1593
1594# ----------------------------------------------------------------------
1595# USAGE: UndateTransferFuncs
1596# ----------------------------------------------------------------------
1597itcl::body Rappture::NanovisViewer::updateTransferFunctions {} {
1598    $_dispatcher event -idle !send_transfunc
1599}
1600
1601itcl::body Rappture::NanovisViewer::limits { cname } {
1602    set _limits(min) 0.0
1603    set _limits(max) 1.0
1604    if { ![info exists _style2datasets($cname)] } {
1605        return [array get _limits]
1606    }
1607    set min ""; set max ""
1608    foreach tag [GetDatasetsWithComponent $cname] {
1609        if { ![info exists _limits($tag)] } {
1610            continue
1611        }
1612        foreach {amin amax} $_limits($tag) break
1613        if { $min == "" || $min > $amin } {
1614            set min $amin
1615        }
1616        if { $max == "" || $max < $amax } {
1617            set max $amax
1618        }
1619    }
1620    if { $min != "" } {
1621        set _limits(min) $min
1622    }
1623    if { $max != "" } {
1624        set _limits(max) $max
1625    }
1626    return [list $_limits(min) $_limits(max)]
1627}
1628
1629
1630itcl::body Rappture::NanovisViewer::BuildViewTab {} {
1631    set fg [option get $itk_component(hull) font Font]
1632    #set bfg [option get $itk_component(hull) boldFont Font]
1633
1634    set inner [$itk_component(main) insert end \
1635        -title "View Settings" \
1636        -icon [Rappture::icon wrench]]
1637    $inner configure -borderwidth 4
1638
1639    set ::Rappture::NanovisViewer::_settings(-isosurfaceshading) 0
1640    checkbutton $inner.isosurface \
1641        -text "Isosurface shading" \
1642        -variable [itcl::scope _settings(-isosurfaceshading)] \
1643        -command [itcl::code $this AdjustSetting -isosurfaceshading] \
1644        -font "Arial 9"
1645
1646    checkbutton $inner.axes \
1647        -text "Axes" \
1648        -variable [itcl::scope _settings(-axesvisible)] \
1649        -command [itcl::code $this AdjustSetting -axesvisible] \
1650        -font "Arial 9"
1651
1652    checkbutton $inner.grid \
1653        -text "Grid" \
1654        -variable [itcl::scope _settings(-gridvisible)] \
1655        -command [itcl::code $this AdjustSetting -gridvisible] \
1656        -font "Arial 9"
1657
1658    checkbutton $inner.outline \
1659        -text "Outline" \
1660        -variable [itcl::scope _settings(-outlinevisible)] \
1661        -command [itcl::code $this AdjustSetting -outlinevisible] \
1662        -font "Arial 9"
1663
1664    checkbutton $inner.legend \
1665        -text "Legend" \
1666        -variable [itcl::scope _settings(-legendvisible)] \
1667        -command [itcl::code $this AdjustSetting -legendvisible] \
1668        -font "Arial 9"
1669
1670    checkbutton $inner.volume \
1671        -text "Volume" \
1672        -variable [itcl::scope _settings(-volume)] \
1673        -command [itcl::code $this AdjustSetting -volume] \
1674        -font "Arial 9"
1675
1676    label $inner.background_l -text "Background" -font "Arial 9"
1677    itk_component add background {
1678        Rappture::Combobox $inner.background -width 10 -editable no
1679    }
1680    $inner.background choices insert end \
1681        "black"              "black"            \
1682        "white"              "white"            \
1683        "grey"               "grey"             
1684
1685    $itk_component(background) value $_settings(-background)
1686    bind $inner.background <<Value>> \
1687        [itcl::code $this AdjustSetting -background]
1688
1689    blt::table $inner \
1690        0,0 $inner.axes  -cspan 2 -anchor w \
1691        1,0 $inner.grid  -cspan 2 -anchor w \
1692        2,0 $inner.outline  -cspan 2 -anchor w \
1693        3,0 $inner.volume  -cspan 2 -anchor w \
1694        4,0 $inner.legend  -cspan 2 -anchor w \
1695        5,0 $inner.background_l       -anchor e -pady 2 \
1696        5,1 $inner.background                   -fill x \
1697
1698    if 0 {
1699    bind $inner <Map> [itcl::code $this GetVolumeInfo $inner]
1700    }
1701    blt::table configure $inner r* -resize none
1702    blt::table configure $inner r6 -resize expand
1703}
1704
1705itcl::body Rappture::NanovisViewer::BuildVolumeTab {} {
1706    set inner [$itk_component(main) insert end \
1707        -title "Volume Settings" \
1708        -icon [Rappture::icon volume-on]]
1709    $inner configure -borderwidth 4
1710
1711    set fg [option get $itk_component(hull) font Font]
1712    #set bfg [option get $itk_component(hull) boldFont Font]
1713
1714    label $inner.lighting_l \
1715        -text "Lighting / Material Properties" \
1716        -font "Arial 9 bold"
1717
1718    checkbutton $inner.light2side -text "Two-sided lighting" -font $fg \
1719        -variable [itcl::scope _settings(-light2side)] \
1720        -command [itcl::code $this AdjustSetting -light2side]
1721
1722    checkbutton $inner.visibility -text "Visible" -font $fg \
1723        -variable [itcl::scope _settings(-volumevisible)] \
1724        -command [itcl::code $this AdjustSetting -volumevisible] \
1725
1726    label $inner.ambient_l -text "Ambient" -font $fg
1727    ::scale $inner.ambient -from 0 -to 100 -orient horizontal \
1728        -variable [itcl::scope _settings(-ambient)] \
1729        -showvalue off -command [itcl::code $this AdjustSetting -ambient] \
1730        -troughcolor grey92
1731
1732    label $inner.diffuse_l -text "Diffuse" -font $fg
1733    ::scale $inner.diffuse -from 0 -to 100 -orient horizontal \
1734        -variable [itcl::scope _settings(-diffuse)] \
1735        -showvalue off -command [itcl::code $this AdjustSetting -diffuse] \
1736        -troughcolor grey92
1737
1738    label $inner.specularLevel_l -text "Specular" -font $fg
1739    ::scale $inner.specularLevel -from 0 -to 100 -orient horizontal \
1740        -variable [itcl::scope _settings(-specularlevel)] \
1741        -showvalue off \
1742        -command [itcl::code $this AdjustSetting -specularlevel] \
1743        -troughcolor grey92
1744
1745    label $inner.specularExponent_l -text "Shininess" -font $fg
1746    ::scale $inner.specularExponent -from 10 -to 128 -orient horizontal \
1747        -variable [itcl::scope _settings(-specularexponent)] \
1748        -showvalue off \
1749        -command [itcl::code $this AdjustSetting -specularexponent] \
1750        -troughcolor grey92
1751
1752    label $inner.opacity_l -text "Opacity" -font $fg
1753    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1754        -variable [itcl::scope _settings(-opacity)] \
1755        -showvalue off -command [itcl::code $this AdjustSetting -opacity] \
1756        -troughcolor grey92
1757
1758    label $inner.transferfunction_l \
1759        -text "Transfer Function" -font "Arial 9 bold"
1760
1761    label $inner.thin -text "Thin" -font $fg
1762    ::scale $inner.thickness -from 0 -to 1000 -orient horizontal \
1763        -variable [itcl::scope _settings(-thickness)] \
1764        -showvalue off -command [itcl::code $this AdjustSetting -thickness] \
1765        -troughcolor grey92
1766
1767    label $inner.thick -text "Thick" -font $fg
1768
1769    label $inner.colormap_l -text "Colormap" -font $fg
1770    itk_component add colormap {
1771        Rappture::Combobox $inner.colormap -width 10 -editable no
1772    }
1773
1774    $inner.colormap choices insert end [GetColormapList -includeDefault -includeNone]
1775    bind $inner.colormap <<Value>> \
1776        [itcl::code $this AdjustSetting -colormap]
1777    $itk_component(colormap) value "default"
1778    set _settings(-colormap) "default"
1779
1780    label $inner.volcomponents_l -text "Component" -font $fg
1781    itk_component add volcomponents {
1782        Rappture::Combobox $inner.volcomponents -editable no
1783    }
1784    bind $inner.volcomponents <<Value>> \
1785        [itcl::code $this AdjustSetting -current]
1786
1787    blt::table $inner \
1788        0,0 $inner.volcomponents_l -anchor e -cspan 2 \
1789        0,2 $inner.volcomponents             -cspan 3 -fill x \
1790        1,1 $inner.lighting_l -anchor w -cspan 4 \
1791        2,1 $inner.ambient_l       -anchor e -pady 2 \
1792        2,2 $inner.ambient                   -cspan 3 -fill x \
1793        3,1 $inner.diffuse_l       -anchor e -pady 2 \
1794        3,2 $inner.diffuse                   -cspan 3 -fill x \
1795        4,1 $inner.specularLevel_l -anchor e -pady 2 \
1796        4,2 $inner.specularLevel             -cspan 3 -fill x \
1797        5,1 $inner.specularExponent_l -anchor e -pady 2 \
1798        5,2 $inner.specularExponent          -cspan 3 -fill x \
1799        6,1 $inner.light2side -cspan 3 -anchor w \
1800        7,1 $inner.visibility -cspan 3 -anchor w \
1801        8,1 $inner.transferfunction_l -anchor w              -cspan 4 \
1802        9,1 $inner.opacity_l -anchor e -pady 2 \
1803        9,2 $inner.opacity                    -cspan 3 -fill x \
1804        10,1 $inner.colormap_l       -anchor e \
1805        10,2 $inner.colormap                  -padx 2 -cspan 3 -fill x \
1806        11,1 $inner.thin             -anchor e \
1807        11,2 $inner.thickness                 -cspan 2 -fill x \
1808        11,4 $inner.thick -anchor w 
1809
1810    blt::table configure $inner c* r* -resize none
1811    blt::table configure $inner r* -pady { 2 0 }
1812    blt::table configure $inner c2 c3 r12 -resize expand
1813    blt::table configure $inner c0 -width .1i
1814}
1815
1816itcl::body Rappture::NanovisViewer::BuildCutplanesTab {} {
1817    set inner [$itk_component(main) insert end \
1818        -title "Cutplane Settings" \
1819        -icon [Rappture::icon cutbutton]]
1820    $inner configure -borderwidth 4
1821
1822    checkbutton $inner.visible \
1823        -text "Show Cutplanes" \
1824        -variable [itcl::scope _settings(-cutplanesvisible)] \
1825        -command [itcl::code $this AdjustSetting -cutplanesvisible] \
1826        -font "Arial 9"
1827
1828    # X-value slicer...
1829    itk_component add xCutButton {
1830        Rappture::PushButton $inner.xbutton \
1831            -onimage [Rappture::icon x-cutplane] \
1832            -offimage [Rappture::icon x-cutplane] \
1833            -command [itcl::code $this AdjustSetting -xcutplanevisible] \
1834            -variable [itcl::scope _settings(-xcutplanevisible)]
1835    }
1836    Rappture::Tooltip::for $itk_component(xCutButton) \
1837        "Toggle the X cut plane on/off"
1838    $itk_component(xCutButton) select
1839
1840    itk_component add xCutScale {
1841        ::scale $inner.xval -from 100 -to 0 \
1842            -width 10 -orient vertical -showvalue off \
1843            -borderwidth 1 -highlightthickness 0 \
1844            -command [itcl::code $this Slice move x] \
1845            -variable [itcl::scope _settings(-xcutplaneposition)]
1846    } {
1847        usual
1848        ignore -borderwidth -highlightthickness
1849    }
1850    # Set the default cutplane value before disabling the scale.
1851    $itk_component(xCutScale) set 50
1852    $itk_component(xCutScale) configure -state disabled
1853    Rappture::Tooltip::for $itk_component(xCutScale) \
1854        "@[itcl::code $this SlicerTip x]"
1855
1856    # Y-value slicer...
1857    itk_component add yCutButton {
1858        Rappture::PushButton $inner.ybutton \
1859            -onimage [Rappture::icon y-cutplane] \
1860            -offimage [Rappture::icon y-cutplane] \
1861            -command [itcl::code $this AdjustSetting -ycutplanevisible] \
1862            -variable [itcl::scope _settings(-ycutplanevisible)]
1863    }
1864    Rappture::Tooltip::for $itk_component(yCutButton) \
1865        "Toggle the Y cut plane on/off"
1866    $itk_component(yCutButton) select
1867
1868    itk_component add yCutScale {
1869        ::scale $inner.yval -from 100 -to 0 \
1870            -width 10 -orient vertical -showvalue off \
1871            -borderwidth 1 -highlightthickness 0 \
1872            -command [itcl::code $this Slice move y] \
1873            -variable [itcl::scope _settings(-ycutplaneposition)]
1874    } {
1875        usual
1876        ignore -borderwidth -highlightthickness
1877    }
1878    Rappture::Tooltip::for $itk_component(yCutScale) \
1879        "@[itcl::code $this SlicerTip y]"
1880    # Set the default cutplane value before disabling the scale.
1881    $itk_component(yCutScale) set 50
1882    $itk_component(yCutScale) configure -state disabled
1883
1884    # Z-value slicer...
1885    itk_component add zCutButton {
1886        Rappture::PushButton $inner.zbutton \
1887            -onimage [Rappture::icon z-cutplane] \
1888            -offimage [Rappture::icon z-cutplane] \
1889            -command [itcl::code $this AdjustSetting -zcutplanevisible] \
1890            -variable [itcl::scope _settings(-zcutplanevisible)]
1891    }
1892    Rappture::Tooltip::for $itk_component(zCutButton) \
1893        "Toggle the Z cut plane on/off"
1894    $itk_component(zCutButton) select
1895
1896    itk_component add zCutScale {
1897        ::scale $inner.zval -from 100 -to 0 \
1898            -width 10 -orient vertical -showvalue off \
1899            -borderwidth 1 -highlightthickness 0 \
1900            -command [itcl::code $this Slice move z] \
1901            -variable [itcl::scope _settings(-zcutplaneposition)]
1902    } {
1903        usual
1904        ignore -borderwidth -highlightthickness
1905    }
1906    $itk_component(zCutScale) set 50
1907    $itk_component(zCutScale) configure -state disabled
1908    Rappture::Tooltip::for $itk_component(zCutScale) \
1909        "@[itcl::code $this SlicerTip z]"
1910
1911    blt::table $inner \
1912        0,1 $inner.visible              -anchor w -pady 2 -cspan 4 \
1913        1,1 $itk_component(xCutScale) \
1914        1,2 $itk_component(yCutScale) \
1915        1,3 $itk_component(zCutScale) \
1916        2,1 $itk_component(xCutButton) \
1917        2,2 $itk_component(yCutButton) \
1918        2,3 $itk_component(zCutButton)
1919
1920    blt::table configure $inner r0 r1 r2 c* -resize none
1921    blt::table configure $inner r3 c4 -resize expand
1922    blt::table configure $inner c0 -width 2
1923    blt::table configure $inner c1 c2 c3 -padx 2
1924}
1925
1926itcl::body Rappture::NanovisViewer::BuildCameraTab {} {
1927    set inner [$itk_component(main) insert end \
1928        -title "Camera Settings" \
1929        -icon [Rappture::icon camera]]
1930    $inner configure -borderwidth 4
1931
1932    label $inner.view_l -text "view" -font "Arial 9"
1933    set f [frame $inner.view]
1934    foreach side { front back left right top bottom } {
1935        button $f.$side  -image [Rappture::icon view$side] \
1936            -command [itcl::code $this SetOrientation $side]
1937        Rappture::Tooltip::for $f.$side "Change the view to $side"
1938        pack $f.$side -side left
1939    }
1940
1941    blt::table $inner \
1942        0,0 $inner.view_l -anchor e -pady 2 \
1943        0,1 $inner.view -anchor w -pady 2
1944
1945    set row 1
1946    set labels { qw qx qy qz xpan ypan zoom }
1947    foreach tag $labels {
1948        label $inner.${tag}label -text $tag -font "Arial 9"
1949        entry $inner.${tag} -font "Arial 9"  -bg white \
1950            -textvariable [itcl::scope _settings(-$tag)]
1951        bind $inner.${tag} <Return> \
1952            [itcl::code $this camera set -${tag}]
1953        bind $inner.${tag} <KP_Enter> \
1954            [itcl::code $this camera set -${tag}]
1955        blt::table $inner \
1956            $row,0 $inner.${tag}label -anchor e -pady 2 \
1957            $row,1 $inner.${tag} -anchor w -pady 2
1958        blt::table configure $inner r$row -resize none
1959        incr row
1960    }
1961
1962    blt::table configure $inner c* r* -resize none
1963    blt::table configure $inner c2 -resize expand
1964    blt::table configure $inner r$row -resize expand
1965}
1966
1967# ----------------------------------------------------------------------
1968# USAGE: Slice move x|y|z <newval>
1969#
1970# Called automatically when the user drags the slider to move the
1971# cut plane that slices 3D data.  Gets the current value from the
1972# slider and moves the cut plane to the appropriate point in the
1973# data set.
1974# ----------------------------------------------------------------------
1975itcl::body Rappture::NanovisViewer::Slice {option args} {
1976    switch -- $option {
1977        move {
1978            if {[llength $args] != 2} {
1979                error "wrong # args: should be \"Slice move x|y|z newval\""
1980            }
1981            set axis [lindex $args 0]
1982            set newval [lindex $args 1]
1983
1984            set newpos [expr {0.01*$newval}]
1985            set datasets [CurrentDatasets -cutplanes]
1986            set tag [lindex $datasets 0]
1987            SendCmd "cutplane position $newpos $axis $tag"
1988        }
1989        default {
1990            error "bad option \"$option\": should be axis, move, or volume"
1991        }
1992    }
1993}
1994
1995# ----------------------------------------------------------------------
1996# USAGE: SlicerTip <axis>
1997#
1998# Used internally to generate a tooltip for the x/y/z slicer controls.
1999# Returns a message that includes the current slicer value.
2000# ----------------------------------------------------------------------
2001itcl::body Rappture::NanovisViewer::SlicerTip {axis} {
2002    set val [$itk_component(${axis}CutScale) get]
2003    return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
2004}
2005
2006
2007itcl::body Rappture::NanovisViewer::DoResize {} {
2008    $_arcball resize $_width $_height
2009    SendCmd "screen size $_width $_height"
2010    set _resizePending 0
2011}
2012
2013itcl::body Rappture::NanovisViewer::EventuallyResize { w h } {
2014    set _width $w
2015    set _height $h
2016    $_arcball resize $w $h
2017    if { !$_resizePending } {
2018        $_dispatcher event -idle !resize
2019        set _resizePending 1
2020    }
2021}
2022
2023itcl::body Rappture::NanovisViewer::EventuallyRedrawLegend {} {
2024    if { !$_resizeLegendPending } {
2025        $_dispatcher event -idle !legend
2026        set _resizeLegendPending 1
2027    }
2028}
2029
2030#  camera --
2031#
2032itcl::body Rappture::NanovisViewer::camera {option args} {
2033    switch -- $option {
2034        "show" {
2035            puts [array get _view]
2036        }
2037        "set" {
2038            set what [lindex $args 0]
2039            set x $_settings($what)
2040            set code [catch { string is double $x } result]
2041            if { $code != 0 || !$result } {
2042                set _settings($what) $_view($what)
2043                return
2044            }
2045            switch -- $what {
2046                "-xpan" - "-ypan" {
2047                    set _view($what) $_settings($what)
2048                    PanCamera
2049                }
2050                "-qx" - "-qy" - "-qz" - "-qw" {
2051                    set _view($what) $_settings($what)
2052                    set q [ViewToQuaternion]
2053                    $_arcball quaternion $q
2054                    SendCmd "camera orient $q"
2055                }
2056                "-zoom" {
2057                    set _view($what) $_settings($what)
2058                    SendCmd "camera zoom $_view($what)"
2059                }
2060            }
2061        }
2062    }
2063}
2064
2065itcl::body Rappture::NanovisViewer::GetVolumeInfo { w } {
2066    set flowobj ""
2067    foreach key [array names _obj2flow] {
2068        set flowobj $_obj2flow($key)
2069        break
2070    }
2071    if { $flowobj == "" } {
2072        return
2073    }
2074    if { [winfo exists $w.frame] } {
2075        destroy $w.frame
2076    }
2077    set inner [frame $w.frame]
2078    blt::table $w \
2079        5,0 $inner -fill both -cspan 2 -anchor nw
2080    array set hints [$dataobj hints]
2081
2082    label $inner.volumes -text "Volumes" -font "Arial 9 bold"
2083    blt::table $inner \
2084        1,0 $inner.volumes  -anchor w \
2085    blt::table configure $inner c0 c1 -resize none
2086    blt::table configure $inner c2 -resize expand
2087
2088    set row 3
2089    set volumes [get]
2090    if { [llength $volumes] > 0 } {
2091        blt::table $inner $row,0 $inner.volumes  -anchor w
2092        incr row
2093    }
2094    foreach vol $volumes {
2095        array unset info
2096        array set info $vol
2097        set name $info(name)
2098        if { ![info exists _settings(-volumevisible-$name)] } {
2099            set _settings(-volumevisible-$name) $info(hide)
2100        }
2101        checkbutton $inner.vol$row -text $info(label) \
2102            -variable [itcl::scope _settings(-volumevisible-$name)] \
2103            -onvalue 0 -offvalue 1 \
2104            -command [itcl::code $this ToggleVolume $key $name] \
2105            -font "Arial 9"
2106        Rappture::Tooltip::for $inner.vol$row $info(description)
2107        blt::table $inner $row,0 $inner.vol$row -anchor w
2108        if { !$_settings(-volume-$name) } {
2109            $inner.vol$row select
2110        }
2111        incr row
2112    }
2113    blt::table configure $inner r* -resize none
2114    blt::table configure $inner r$row -resize expand
2115    blt::table configure $inner c3 -resize expand
2116    event generate [winfo parent [winfo parent $w]] <Configure>
2117}
2118
2119itcl::body Rappture::NanovisViewer::ToggleVolume { tag name } {
2120    set bool $_settings(-volumevisible-$name)
2121    SendCmd "volume state $bool $name"
2122}
2123
2124itcl::body Rappture::NanovisViewer::SetOrientation { side } {
2125    array set positions {
2126        front "1 0 0 0"
2127        back  "0 0 1 0"
2128        left  "0.707107 0 -0.707107 0"
2129        right "0.707107 0 0.707107 0"
2130        top   "0.707107 -0.707107 0 0"
2131        bottom "0.707107 0.707107 0 0"
2132    }
2133    foreach name { -qw -qx -qy -qz } value $positions($side) {
2134        set _view($name) $value
2135    }
2136    set q [ViewToQuaternion]
2137    $_arcball quaternion $q
2138    SendCmd "camera orient $q"
2139    SendCmd "camera reset"
2140    set _view(-xpan) 0
2141    set _view(-ypan) 0
2142    set _view(-zoom) 1.0
2143    set _settings(-xpan) $_view(-xpan)
2144    set _settings(-ypan) $_view(-ypan)
2145    set _settings(-zoom) $_view(-zoom)
2146}
2147
2148
2149#
2150# InitComponentSettings --
2151#
2152#    Initializes the volume settings for a specific component. This should
2153#    match what's used as global settings above. This is called the first
2154#    time we try to switch to a given component in SwitchComponent below.
2155#
2156itcl::body Rappture::NanovisViewer::InitComponentSettings { cname } {
2157    # Expanding component name for key.
2158    array set _settings [subst {
2159        $cname-ambient           60
2160        $cname-colormap          default
2161        $cname-diffuse           40
2162        $cname-light2side        1
2163        $cname-opacity           50
2164        $cname-specularexponent  90
2165        $cname-specularlevel     30
2166        $cname-thickness         350
2167        $cname-volumevisible     1
2168    }]
2169}
2170
2171#
2172# SwitchComponent --
2173#
2174#    This is called when the current component is changed by the dropdown
2175#    menu in the volume tab.  It synchronizes the global volume settings
2176#    with the settings of the new current component.
2177#
2178itcl::body Rappture::NanovisViewer::SwitchComponent { cname } {
2179    if { ![info exists _settings($cname-ambient)] } {
2180        InitComponentSettings $cname
2181    }
2182    # _settings variables change widgets, except for colormap
2183    set _settings(-ambient)          $_settings($cname-ambient)
2184    set _settings(-colormap)         $_settings($cname-colormap)
2185    set _settings(-diffuse)          $_settings($cname-diffuse)
2186    set _settings(-light2side)       $_settings($cname-light2side)
2187    set _settings(-opacity)          $_settings($cname-opacity)
2188    set _settings(-specularexponent) $_settings($cname-specularexponent)
2189    set _settings(-specularlevel)    $_settings($cname-specularlevel)
2190    set _settings(-thickness)        $_settings($cname-thickness)
2191    set _settings(-volumevisible)    $_settings($cname-volumevisible)
2192    $itk_component(colormap) value   $_settings($cname-colormap)
2193    set _current $cname;                # Reset the current component
2194}
2195
2196#
2197# BuildVolumeComponents --
2198#
2199#    This is called from the "scale" method which is called when a new
2200#    dataset is added or deleted.  It repopulates the dropdown menu of
2201#    volume component names.  It sets the current component to the first
2202#    component in the list (of components found).  Finally, if there is
2203#    only one component, don't display the label or the combobox in the
2204#    volume settings tab.
2205#
2206itcl::body Rappture::NanovisViewer::BuildVolumeComponents {} {
2207    $itk_component(volcomponents) choices delete 0 end
2208    foreach name $_componentsList {
2209        $itk_component(volcomponents) choices insert end $name $name
2210    }
2211    set _current [lindex $_componentsList 0]
2212    $itk_component(volcomponents) value $_current
2213    set parent [winfo parent $itk_component(volcomponents)]
2214    if { [llength $_componentsList] <= 1 } {
2215        # Unpack the components label and dropdown if there's only one
2216        # component.
2217        blt::table forget $parent.volcomponents_l $parent.volcomponents
2218    } else {
2219        # Pack the components label and dropdown into the table there's
2220        # more than one component to select.
2221        blt::table $parent \
2222            0,0 $parent.volcomponents_l -anchor e -cspan 2 \
2223            0,2 $parent.volcomponents -cspan 3 -fill x
2224    }
2225}
2226
2227#
2228# GetDatasetsWithComponents --
2229#
2230#    Returns a list of all the datasets (known by the combination of their
2231#    data object and component name) that match the given component name.
2232#    For example, this is used where we want to change the settings of
2233#    volumes that have the current component.
2234#
2235itcl::body Rappture::NanovisViewer::GetDatasetsWithComponent { cname } {
2236    if { ![info exists _volcomponents($cname)] } {
2237        return ""
2238    }
2239    set list ""
2240    foreach tag $_volcomponents($cname) {
2241        if { ![info exists _serverDatasets($tag)] } {
2242            continue
2243        }
2244        lappend list $tag
2245    }
2246    return $list
2247}
2248
2249#
2250# HideAllMarkers --
2251#
2252#    Hide all the markers in all the transfer functions.  Can't simply
2253#    delete and recreate markers from the <style> since the user may have
2254#    created, deleted, or moved markers.
2255#
2256itcl::body Rappture::NanovisViewer::HideAllMarkers {} {
2257    foreach cname [array names _transferFunctionEditors] {
2258        $_transferFunctionEditors($cname) hideMarkers
2259    }
2260}
2261
2262itcl::body Rappture::NanovisViewer::GetColormap { cname color } {
2263    if { $color == "default" } {
2264        return $_cname2defaultcolormap($cname)
2265    }
2266    return [ColorsToColormap $color]
2267}
2268
2269itcl::body Rappture::NanovisViewer::GetAlphamap { cname name } {
2270    if { $name == "default" } {
2271        return $_cname2defaultalphamap($cname)
2272    }
2273    return [NameToAlphamap $name]
2274}
2275
2276itcl::body Rappture::NanovisViewer::ResetColormap { cname color } {
2277    # Get the current transfer function
2278    if { ![info exists _cname2transferFunction($cname)] } {
2279        return
2280    }
2281    foreach { cmap wmap } $_cname2transferFunction($cname) break
2282    set cmap [GetColormap $cname $color]
2283    set _cname2transferFunction($cname) [list $cmap $wmap]
2284    SendCmd [list transfunc define $cname $cmap $wmap]
2285    EventuallyRedrawLegend
2286}
2287
2288itcl::body Rappture::NanovisViewer::ComputeAlphamap { cname } {
2289    if { ![info exists _transferFunctionEditors($cname)] } {
2290        return [list 0.0 0.0 1.0 1.0]
2291    }
2292    if { ![info exists _settings($cname-ambient)] } {
2293        InitComponentSettings $cname
2294    }
2295
2296    set isovalues [$_transferFunctionEditors($cname) values]
2297
2298    # Currently using volume shading opacity to scale opacity in
2299    # the volume shader. The transfer function always sets full
2300    # opacity
2301    set max 1.0
2302
2303    # Use the component-wise thickness setting from the slider
2304    # settings widget
2305    # Scale values between 0.00001 and 0.01000
2306    set delta [expr {double($_settings($cname-thickness)) * 0.0001}]
2307   
2308    set first [lindex $isovalues 0]
2309    set last [lindex $isovalues end]
2310    set wmap ""
2311    if { $first == "" || $first != 0.0 } {
2312        lappend wmap 0.0 0.0
2313    }
2314    foreach x $isovalues {
2315        set x1 [expr {$x-$delta-0.00001}]
2316        set x2 [expr {$x-$delta}]
2317        set x3 [expr {$x+$delta}]
2318        set x4 [expr {$x+$delta+0.00001}]
2319        if { $x1 < 0.0 } {
2320            set x1 0.0
2321        } elseif { $x1 > 1.0 } {
2322            set x1 1.0
2323        }
2324        if { $x2 < 0.0 } {
2325            set x2 0.0
2326        } elseif { $x2 > 1.0 } {
2327            set x2 1.0
2328        }
2329        if { $x3 < 0.0 } {
2330            set x3 0.0
2331        } elseif { $x3 > 1.0 } {
2332            set x3 1.0
2333        }
2334        if { $x4 < 0.0 } {
2335            set x4 0.0
2336        } elseif { $x4 > 1.0 } {
2337            set x4 1.0
2338        }
2339        # add spikes in the middle
2340        lappend wmap $x1 0.0
2341        lappend wmap $x2 $max
2342        lappend wmap $x3 $max
2343        lappend wmap $x4 0.0
2344    }
2345    if { $last == "" || $last != 1.0 } {
2346        lappend wmap 1.0 0.0
2347    }
2348    return $wmap
2349}
2350
2351
2352itcl::body Rappture::NanovisViewer::NameToAlphamap { name } {
2353    switch -- $name {
2354        "ramp-up" {
2355            set wmap {
2356                0.0 0.0
2357                1.0 1.0
2358            }
2359        }
2360        "ramp-down" {
2361            set wmap {
2362                0.0 1.0
2363                1.0 0.0
2364            }
2365        }
2366        "vee" {
2367            set wmap {
2368                0.0 1.0
2369                0.5 0.0
2370                1.0 1.0
2371            }
2372        }
2373        "tent-1" {
2374            set wmap {
2375                0.0 0.0
2376                0.5 1.0
2377                1.0 0.0
2378            }
2379        }
2380        "tent-2" {
2381            set wmap {
2382                0.0 0.0
2383                0.25 1.0
2384                0.5 0.0
2385                0.75 1.0
2386                1.0 0.0
2387            }
2388        }
2389        "tent-3" {
2390            set wmap {
2391                0.0 0.0
2392                0.16666 1.0
2393                0.33333 0.0
2394                0.5     1.0
2395                0.66666 0.0
2396                0.83333 1.0
2397                1.0 0.0
2398            }
2399        }
2400        "tent-4" {
2401            set wmap {
2402                0.0     0.0
2403                0.125   1.0
2404                0.25    0.0
2405                0.375   1.0
2406                0.5     0.0       
2407                0.625   1.0
2408                0.75    0.0
2409                0.875   1.0
2410                1.0     0.0
2411            }
2412        }
2413        "sinusoid-1" {
2414            set wmap {
2415                0.0                     0.000 0.600 0.800
2416                0.14285714285714285     0.400 0.900 1.000
2417                0.2857142857142857      0.600 1.000 1.000
2418                0.42857142857142855     0.800 1.000 1.000
2419                0.5714285714285714      0.900 0.900 0.900
2420                0.7142857142857143      0.600 0.600 0.600
2421                0.8571428571428571      0.400 0.400 0.400
2422                1.0                     0.200 0.200 0.200
2423            }
2424        }
2425        "sinusoid-2" {
2426            set wmap {
2427                0.0                     0.900 1.000 1.000
2428                0.1111111111111111      0.800 0.983 1.000
2429                0.2222222222222222      0.700 0.950 1.000
2430                0.3333333333333333      0.600 0.900 1.000
2431                0.4444444444444444      0.500 0.833 1.000
2432                0.5555555555555556      0.400 0.750 1.000
2433                0.6666666666666666      0.300 0.650 1.000
2434                0.7777777777777778      0.200 0.533 1.000
2435                0.8888888888888888      0.100 0.400 1.000
2436                1.0                     0.000 0.250 1.000
2437            }
2438        }
2439        "sinusoid-6" {
2440            set wmap {
2441                0.0                             0.200   0.100   0.000
2442                0.09090909090909091             0.400   0.187   0.000
2443                0.18181818181818182             0.600   0.379   0.210
2444                0.2727272727272727              0.800   0.608   0.480
2445                0.36363636363636365             0.850   0.688   0.595
2446                0.45454545454545453             0.950   0.855   0.808
2447                0.5454545454545454              0.800   0.993   1.000
2448                0.6363636363636364              0.600   0.973   1.000
2449                0.7272727272727273              0.400   0.940   1.000
2450                0.8181818181818182              0.200   0.893   1.000
2451                0.9090909090909091              0.000   0.667   0.800
2452                1.0                             0.000   0.480   0.600
2453            }
2454        }
2455        "sinusoid-10" {
2456            set wmap {
2457                0.0                             0.000   0.480   0.600
2458                0.09090909090909091             0.000   0.667   0.800
2459                0.18181818181818182             0.200   0.893   1.000
2460                0.2727272727272727              0.400   0.940   1.000
2461                0.36363636363636365             0.600   0.973   1.000
2462                0.45454545454545453             0.800   0.993   1.000
2463                0.5454545454545454              0.950   0.855   0.808
2464                0.6363636363636364              0.850   0.688   0.595
2465                0.7272727272727273              0.800   0.608   0.480
2466                0.8181818181818182              0.600   0.379   0.210
2467                0.9090909090909091              0.400   0.187   0.000
2468                1.0                             0.200   0.100   0.000
2469            }
2470        }
2471        "step-2" {
2472            set wmap {
2473                0.0                             0.000   0.167   1.000
2474                0.09090909090909091             0.100   0.400   1.000
2475                0.18181818181818182             0.200   0.600   1.000
2476                0.2727272727272727              0.400   0.800   1.000
2477                0.36363636363636365             0.600   0.933   1.000
2478                0.45454545454545453             0.800   1.000   1.000
2479                0.5454545454545454              1.000   1.000   0.800
2480                0.6363636363636364              1.000   0.933   0.600
2481                0.7272727272727273              1.000   0.800   0.400
2482                0.8181818181818182              1.000   0.600   0.200
2483                0.9090909090909091              1.000   0.400   0.100
2484                1.0                             1.000   0.167   0.000
2485            }
2486        }
2487        "step-5" {
2488            set wmap {
2489                0.0                             1.000   0.167   0.000
2490                0.09090909090909091             1.000   0.400   0.100
2491                0.18181818181818182             1.000   0.600   0.200
2492                0.2727272727272727              1.000   0.800   0.400
2493                0.36363636363636365             1.000   0.933   0.600
2494                0.45454545454545453             1.000   1.000   0.800
2495                0.5454545454545454              0.800   1.000   1.000
2496                0.6363636363636364              0.600   0.933   1.000
2497                0.7272727272727273              0.400   0.800   1.000
2498                0.8181818181818182              0.200   0.600   1.000
2499                0.9090909090909091              0.100   0.400   1.000
2500                1.0                             0.000   0.167   1.000
2501            }
2502        }
2503        "step-12" {
2504            set wmap {
2505                "#EE82EE"
2506                "#4B0082"
2507                "blue"
2508                "#008000"
2509                "yellow"
2510                "#FFA500"
2511                "red"
2512            }
2513        }
2514        default {
2515        }
2516    }
2517    return ""
2518}
2519
2520
Note: See TracBrowser for help on using the repository browser.