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

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

remove dead code

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