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

Last change on this file since 4190 was 4188, checked in by gah, 10 years ago

change names of options to begin with minus. To follows the use of options in <style>. Still hate this all. Style needs to be deprecated with views

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