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

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

fix contour list generation

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