source: branches/1.3/gui/scripts/vtkmeshviewer.tcl @ 4523

Last change on this file since 4523 was 4523, checked in by ldelgass, 7 years ago

Set mesh back to opaque by default. Mesh viewer shows only boundary faces, so
there aren't any interior cells to be seen. User can still set opacity.

File size: 62.0 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: vtkmeshviewer - Vtk mesh viewer
4#
5#  It connects to the Vtk server running on a rendering farm,
6#  transmits data, and displays the results.
7# ======================================================================
8#  AUTHOR:  Michael McLennan, Purdue University
9#  Copyright (c) 2004-2014  HUBzero Foundation, LLC
10#
11#  See the file "license.terms" for information on usage and
12#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13# ======================================================================
14package require Itk
15package require BLT
16#package require Img
17
18option add *VtkMeshViewer.width 4i widgetDefault
19option add *VtkMeshViewer*cursor crosshair widgetDefault
20option add *VtkMeshViewer.height 4i widgetDefault
21option add *VtkMeshViewer.foreground black widgetDefault
22option add *VtkMeshViewer.controlBackground gray widgetDefault
23option add *VtkMeshViewer.controlDarkBackground #999999 widgetDefault
24option add *VtkMeshViewer.plotBackground black widgetDefault
25option add *VtkMeshViewer.plotForeground white widgetDefault
26option add *VtkMeshViewer.font \
27    -*-helvetica-medium-r-normal-*-12-* widgetDefault
28
29# must use this name -- plugs into Rappture::resources::load
30proc VtkMeshViewer_init_resources {} {
31    Rappture::resources::register \
32        vtkvis_server Rappture::VtkMeshViewer::SetServerList
33}
34
35itcl::class Rappture::VtkMeshViewer {
36    inherit Rappture::VisViewer
37
38    itk_option define -plotforeground plotForeground Foreground ""
39    itk_option define -plotbackground plotBackground Background ""
40
41    constructor { hostlist args } {
42        Rappture::VisViewer::constructor $hostlist
43    } {
44        # defined below
45    }
46    destructor {
47        # defined below
48    }
49    public proc SetServerList { namelist } {
50        Rappture::VisViewer::SetServerList "vtkvis" $namelist
51    }
52    public method add {dataobj {settings ""}}
53    public method camera {option args}
54    public method delete {args}
55    public method disconnect {}
56    public method download {option args}
57    public method get {args}
58    public method isconnected {}
59    public method limits { colormap }
60    public method parameters {title args} {
61        # do nothing
62    }
63    public method scale {args}
64
65    protected method Connect {}
66    protected method CurrentDatasets {args}
67    protected method Disconnect {}
68    protected method DoResize {}
69    protected method DoRotate {}
70    protected method AdjustSetting {what {value ""}}
71    protected method InitSettings { args  }
72    protected method Pan {option x y}
73    protected method Pick {x y}
74    protected method Rebuild {}
75    protected method ReceiveDataset { args }
76    protected method ReceiveImage { args }
77    protected method Rotate {option x y}
78    protected method Zoom {option}
79
80    # The following methods are only used by this class.
81    private method BuildAxisTab {}
82    private method BuildCameraTab {}
83    private method BuildCutawayTab {}
84    private method BuildDownloadPopup { widget command }
85    private method BuildPolydataTab {}
86    private method EventuallyResize { w h }
87    private method EventuallyRotate { q }
88    private method EventuallySetPolydataOpacity {}
89    private method GetImage { args }
90    private method GetVtkData { args }
91    private method IsValidObject { dataobj }
92    private method PanCamera {}
93    private method SetObjectStyle { dataobj }
94    private method SetOrientation { side }
95    private method SetPolydataOpacity {}
96    private method Slice {option args}
97
98    private variable _arcball ""
99    private variable _dlist "";         # list of data objects
100    private variable _obj2datasets
101    private variable _obj2ovride;       # maps dataobj => style override
102    private variable _datasets;         # contains all the dataobj-component
103                                        # datasets in the server
104    private variable _colormaps;        # contains all the colormaps
105                                        # in the server.
106    private variable _dataset2style;    # maps dataobj-component to transfunc
107    private variable _style2datasets;   # maps tf back to list of
108                                        # dataobj-components using the tf.
109    private variable _click;            # info used for rotate operations
110    private variable _limits;           # autoscale min/max for all axes
111    private variable _view;             # view params for 3D view
112    private variable _settings
113    private variable _widget
114    private variable _style;            # Array of current component styles.
115    private variable _initialStyle;     # Array of initial component styles.
116    private variable _reset 1;          # Indicates that server was reset and
117                                        # needs to be reinitialized.
118
119    private variable _first "";         # This is the topmost dataset.
120    private variable _start 0
121    private variable _title ""
122
123    common _downloadPopup;              # download options from popup
124    private common _hardcopy
125    private variable _width 0
126    private variable _height 0
127    private variable _resizePending 0
128    private variable _rotatePending 0
129    private variable _polydataOpacityPending 0
130    private variable _rotateDelay 150
131    private variable _opacityDelay 150
132}
133
134itk::usual VtkMeshViewer {
135    keep -background -foreground -cursor -font
136    keep -plotbackground -plotforeground
137}
138
139# ----------------------------------------------------------------------
140# CONSTRUCTOR
141# ----------------------------------------------------------------------
142itcl::body Rappture::VtkMeshViewer::constructor {hostlist args} {
143    package require vtk
144    set _serverType "vtkvis"
145
146    # Rebuild event
147    $_dispatcher register !rebuild
148    $_dispatcher dispatch $this !rebuild "[itcl::code $this Rebuild]; list"
149
150    # Resize event
151    $_dispatcher register !resize
152    $_dispatcher dispatch $this !resize "[itcl::code $this DoResize]; list"
153
154    # Rotate event
155    $_dispatcher register !rotate
156    $_dispatcher dispatch $this !rotate "[itcl::code $this DoRotate]; list"
157
158    # Polydata opacity event
159    $_dispatcher register !polydataOpacity
160    $_dispatcher dispatch $this !polydataOpacity \
161        "[itcl::code $this SetPolydataOpacity]; list"
162    #
163    # Populate parser with commands handle incoming requests
164    #
165    $_parser alias image    [itcl::code $this ReceiveImage]
166    $_parser alias dataset  [itcl::code $this ReceiveDataset]
167
168    # Initialize the view to some default parameters.
169    array set _view {
170        qw              0.853553
171        qx              -0.353553
172        qy              0.353553
173        qz              0.146447
174        zoom            1.0
175        xpan            0
176        ypan            0
177        ortho           0
178    }
179    set _arcball [blt::arcball create 100 100]
180    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
181    $_arcball quaternion $q
182
183    set _limits(zmin) 0.0
184    set _limits(zmax) 1.0
185
186    array set _settings {
187        -axesvisible            1
188        -axislabels             1
189        -outline                0
190        -polydataedges          0
191        -polydatalighting       1
192        -polydataopacity        1.0
193        -polydatavisible        1
194        -polydatawireframe      0
195        -xcutaway               0
196        -xdirection             -1
197        -xgrid                  0
198        -xposition              0
199        -ycutaway               0
200        -ydirection             -1
201        -ygrid                  0
202        -yposition              0
203        -zcutaway               0
204        -zdirection             -1
205        -zgrid                  0
206        -zposition              0
207    }
208    array set _widget {
209        -polydataopacity        1.0
210    }       
211    itk_component add view {
212        canvas $itk_component(plotarea).view \
213            -highlightthickness 0 -borderwidth 0
214    } {
215        usual
216        ignore -highlightthickness -borderwidth  -background
217    }
218
219    itk_component add fieldmenu {
220        menu $itk_component(plotarea).menu -bg black -fg white -relief flat \
221            -tearoff no
222    } {
223        usual
224        ignore -background -foreground -relief -tearoff
225    }
226
227    set c $itk_component(view)
228    bind $c <Configure> [itcl::code $this EventuallyResize %w %h]
229    bind $c <4> [itcl::code $this Zoom in 0.25]
230    bind $c <5> [itcl::code $this Zoom out 0.25]
231    bind $c <KeyPress-Left>  [list %W xview scroll 10 units]
232    bind $c <KeyPress-Right> [list %W xview scroll -10 units]
233    bind $c <KeyPress-Up>    [list %W yview scroll 10 units]
234    bind $c <KeyPress-Down>  [list %W yview scroll -10 units]
235    bind $c <Enter> "focus %W"
236    bind $c <Control-F1> [itcl::code $this ToggleConsole]
237
238    # Fix the scrollregion in case we go off screen
239    $c configure -scrollregion [$c bbox all]
240
241    set _map(id) [$c create image 0 0 -anchor nw -image $_image(plot)]
242    set _map(cwidth) -1
243    set _map(cheight) -1
244    set _map(zoom) 1.0
245    set _map(original) ""
246
247    set f [$itk_component(main) component controls]
248    itk_component add reset {
249        button $f.reset -borderwidth 1 -padx 1 -pady 1 \
250            -highlightthickness 0 \
251            -image [Rappture::icon reset-view] \
252            -command [itcl::code $this Zoom reset]
253    } {
254        usual
255        ignore -highlightthickness
256    }
257    pack $itk_component(reset) -side top -padx 2 -pady 2
258    Rappture::Tooltip::for $itk_component(reset) \
259        "Reset the view to the default zoom level"
260
261    itk_component add zoomin {
262        button $f.zin -borderwidth 1 -padx 1 -pady 1 \
263            -highlightthickness 0 \
264            -image [Rappture::icon zoom-in] \
265            -command [itcl::code $this Zoom in]
266    } {
267        usual
268        ignore -highlightthickness
269    }
270    pack $itk_component(zoomin) -side top -padx 2 -pady 2
271    Rappture::Tooltip::for $itk_component(zoomin) "Zoom in"
272
273    itk_component add zoomout {
274        button $f.zout -borderwidth 1 -padx 1 -pady 1 \
275            -highlightthickness 0 \
276            -image [Rappture::icon zoom-out] \
277            -command [itcl::code $this Zoom out]
278    } {
279        usual
280        ignore -highlightthickness
281    }
282    pack $itk_component(zoomout) -side top -padx 2 -pady 2
283    Rappture::Tooltip::for $itk_component(zoomout) "Zoom out"
284
285    BuildPolydataTab
286    BuildAxisTab
287    #BuildCutawayTab
288    BuildCameraTab
289
290    # Hack around the Tk panewindow.  The problem is that the requested
291    # size of the 3d view isn't set until an image is retrieved from
292    # the server.  So the panewindow uses the tiny size.
293    set w 10000
294    pack forget $itk_component(view)
295    blt::table $itk_component(plotarea) \
296        0,0 $itk_component(view) -fill both -reqwidth $w
297    blt::table configure $itk_component(plotarea) c1 -resize none
298
299    # Bindings for rotation via mouse
300    bind $itk_component(view) <ButtonPress-1> \
301        [itcl::code $this Rotate click %x %y]
302    bind $itk_component(view) <B1-Motion> \
303        [itcl::code $this Rotate drag %x %y]
304    bind $itk_component(view) <ButtonRelease-1> \
305        [itcl::code $this Rotate release %x %y]
306    bind $itk_component(view) <Configure> \
307        [itcl::code $this EventuallyResize %w %h]
308
309    # Bindings for panning via mouse
310    bind $itk_component(view) <ButtonPress-2> \
311        [itcl::code $this Pan click %x %y]
312    bind $itk_component(view) <B2-Motion> \
313        [itcl::code $this Pan drag %x %y]
314    bind $itk_component(view) <ButtonRelease-2> \
315        [itcl::code $this Pan release %x %y]
316
317    #bind $itk_component(view) <ButtonRelease-3> \
318    #    [itcl::code $this Pick %x %y]
319
320    # Bindings for panning via keyboard
321    bind $itk_component(view) <KeyPress-Left> \
322        [itcl::code $this Pan set -10 0]
323    bind $itk_component(view) <KeyPress-Right> \
324        [itcl::code $this Pan set 10 0]
325    bind $itk_component(view) <KeyPress-Up> \
326        [itcl::code $this Pan set 0 -10]
327    bind $itk_component(view) <KeyPress-Down> \
328        [itcl::code $this Pan set 0 10]
329    bind $itk_component(view) <Shift-KeyPress-Left> \
330        [itcl::code $this Pan set -2 0]
331    bind $itk_component(view) <Shift-KeyPress-Right> \
332        [itcl::code $this Pan set 2 0]
333    bind $itk_component(view) <Shift-KeyPress-Up> \
334        [itcl::code $this Pan set 0 -2]
335    bind $itk_component(view) <Shift-KeyPress-Down> \
336        [itcl::code $this Pan set 0 2]
337
338    # Bindings for zoom via keyboard
339    bind $itk_component(view) <KeyPress-Prior> \
340        [itcl::code $this Zoom out]
341    bind $itk_component(view) <KeyPress-Next> \
342        [itcl::code $this Zoom in]
343
344    bind $itk_component(view) <Enter> "focus $itk_component(view)"
345
346    if {[string equal "x11" [tk windowingsystem]]} {
347        # Bindings for zoom via mouse
348        bind $itk_component(view) <4> [itcl::code $this Zoom out]
349        bind $itk_component(view) <5> [itcl::code $this Zoom in]
350    }
351
352    set _image(download) [image create photo]
353
354    eval itk_initialize $args
355    Connect
356}
357
358# ----------------------------------------------------------------------
359# DESTRUCTOR
360# ----------------------------------------------------------------------
361itcl::body Rappture::VtkMeshViewer::destructor {} {
362    Disconnect
363    $_dispatcher cancel !rebuild
364    $_dispatcher cancel !resize
365    $_dispatcher cancel !rotate
366    image delete $_image(plot)
367    image delete $_image(download)
368    catch { blt::arcball destroy $_arcball }
369}
370
371itcl::body Rappture::VtkMeshViewer::DoResize {} {
372    if { $_width < 2 } {
373        set _width 500
374    }
375    if { $_height < 2 } {
376        set _height 500
377    }
378    set _start [clock clicks -milliseconds]
379    SendCmd "screen size $_width $_height"
380
381    set _resizePending 0
382}
383
384itcl::body Rappture::VtkMeshViewer::DoRotate {} {
385    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
386    SendCmd "camera orient $q"
387    set _rotatePending 0
388}
389
390itcl::body Rappture::VtkMeshViewer::EventuallyResize { w h } {
391    set _width $w
392    set _height $h
393    $_arcball resize $w $h
394    if { !$_resizePending } {
395        set _resizePending 1
396        $_dispatcher event -after 200 !resize
397    }
398}
399
400itcl::body Rappture::VtkMeshViewer::EventuallyRotate { q } {
401    foreach { _view(qw) _view(qx) _view(qy) _view(qz) } $q break
402    if { !$_rotatePending } {
403        set _rotatePending 1
404        $_dispatcher event -after $_rotateDelay !rotate
405    }
406}
407
408itcl::body Rappture::VtkMeshViewer::SetPolydataOpacity {} {
409    set _polydataOpacityPending 0
410    set val $_settings(-polydataopacity)
411    SendCmd "polydata opacity $val"
412}
413
414itcl::body Rappture::VtkMeshViewer::EventuallySetPolydataOpacity {} {
415    if { !$_polydataOpacityPending } {
416        set _polydataOpacityPending 1
417        $_dispatcher event -after $_opacityDelay !polydataOpacity
418    }
419}
420
421# ----------------------------------------------------------------------
422# USAGE: add <dataobj> ?<settings>?
423#
424# Clients use this to add a data object to the plot.  The optional
425# <settings> are used to configure the plot.  Allowed settings are
426# -color, -brightness, -width, -linestyle, and -raise.
427# ----------------------------------------------------------------------
428itcl::body Rappture::VtkMeshViewer::add {dataobj {settings ""}} {
429    array set params {
430        -color auto
431        -width 1
432        -linestyle solid
433        -brightness 0
434        -raise 0
435        -description ""
436        -param ""
437        -type ""
438    }
439    array set params $settings
440    set params(-description) ""
441    set params(-param) ""
442    array set params $settings
443
444    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
445        # can't handle -autocolors yet
446        set params(-color) black
447    }
448    set pos [lsearch -exact $_dlist $dataobj]
449    if {$pos < 0} {
450        lappend _dlist $dataobj
451    }
452    set _obj2ovride($dataobj-color) $params(-color)
453    set _obj2ovride($dataobj-width) $params(-width)
454    set _obj2ovride($dataobj-raise) $params(-raise)
455    $_dispatcher event -idle !rebuild
456}
457
458# ----------------------------------------------------------------------
459# USAGE: delete ?<dataobj1> <dataobj2> ...?
460#
461#       Clients use this to delete a dataobj from the plot.  If no dataobjs
462#       are specified, then all dataobjs are deleted.  No data objects are
463#       deleted.  They are only removed from the display list.
464#
465# ----------------------------------------------------------------------
466itcl::body Rappture::VtkMeshViewer::delete {args} {
467    if { [llength $args] == 0} {
468        set args $_dlist
469    }
470    # Delete all specified dataobjs
471    set changed 0
472    foreach dataobj $args {
473        set pos [lsearch -exact $_dlist $dataobj]
474        if { $pos < 0 } {
475            continue;                   # Don't know anything about it.
476        }
477        # Remove it from the dataobj list.
478        set _dlist [lreplace $_dlist $pos $pos]
479        array unset _obj2ovride $dataobj-*
480        set changed 1
481    }
482    # If anything changed, then rebuild the plot
483    if { $changed } {
484        $_dispatcher event -idle !rebuild
485    }
486}
487
488# ----------------------------------------------------------------------
489# USAGE: get ?-objects?
490# USAGE: get ?-visible?
491# USAGE: get ?-image view?
492#
493# Clients use this to query the list of objects being plotted, in
494# order from bottom to top of this result.  The optional "-image"
495# flag can also request the internal images being shown.
496# ----------------------------------------------------------------------
497itcl::body Rappture::VtkMeshViewer::get {args} {
498    if {[llength $args] == 0} {
499        set args "-objects"
500    }
501
502    set op [lindex $args 0]
503    switch -- $op {
504        "-objects" {
505            # put the dataobj list in order according to -raise options
506            set dlist {}
507            foreach dataobj $_dlist {
508                if { ![IsValidObject $dataobj] } {
509                    continue
510                }
511                if {[info exists _obj2ovride($dataobj-raise)] &&
512                    $_obj2ovride($dataobj-raise)} {
513                    set dlist [linsert $dlist 0 $dataobj]
514                } else {
515                    lappend dlist $dataobj
516                }
517            }
518            return $dlist
519        }
520        "-visible" {
521            set dlist {}
522            foreach dataobj $_dlist {
523                if { ![IsValidObject $dataobj] } {
524                    continue
525                }
526                if { ![info exists _obj2ovride($dataobj-raise)] } {
527                    # No setting indicates that the object isn't visible.
528                    continue
529                }
530                # Otherwise use the -raise parameter to put the object to
531                # the front of the list.
532                if { $_obj2ovride($dataobj-raise) } {
533                    set dlist [linsert $dlist 0 $dataobj]
534                } else {
535                    lappend dlist $dataobj
536                }
537            }
538            return $dlist
539        }           
540        -image {
541            if {[llength $args] != 2} {
542                error "wrong # args: should be \"get -image view\""
543            }
544            switch -- [lindex $args end] {
545                view {
546                    return $_image(plot)
547                }
548                default {
549                    error "bad image name \"[lindex $args end]\": should be view"
550                }
551            }
552        }
553        default {
554            error "bad option \"$op\": should be -objects or -image"
555        }
556    }
557}
558
559# ----------------------------------------------------------------------
560# USAGE: scale ?<data1> <data2> ...?
561#
562# Sets the default limits for the overall plot according to the
563# limits of the data for all of the given <data> objects.  This
564# accounts for all objects--even those not showing on the screen.
565# Because of this, the limits are appropriate for all objects as
566# the user scans through data in the ResultSet viewer.
567# ----------------------------------------------------------------------
568itcl::body Rappture::VtkMeshViewer::scale {args} {
569    foreach dataobj $args {
570        array set bounds [limits $dataobj]
571        if {![info exists _limits(xmin)] || $_limits(xmin) > $bounds(xmin)} {
572            set _limits(xmin) $bounds(xmin)
573        }
574        if {![info exists _limits(xmax)] || $_limits(xmax) < $bounds(xmax)} {
575            set _limits(xmax) $bounds(xmax)
576        }
577
578        if {![info exists _limits(ymin)] || $_limits(ymin) > $bounds(ymin)} {
579            set _limits(ymin) $bounds(ymin)
580        }
581        if {![info exists _limits(ymax)] || $_limits(ymax) < $bounds(ymax)} {
582            set _limits(ymax) $bounds(ymax)
583        }
584
585        if {![info exists _limits(zmin)] || $_limits(zmin) > $bounds(zmin)} {
586            set _limits(zmin) $bounds(zmin)
587        }
588        if {![info exists _limits(zmax)] || $_limits(zmax) < $bounds(zmax)} {
589            set _limits(zmax) $bounds(zmax)
590        }
591    }
592}
593
594# ----------------------------------------------------------------------
595# USAGE: download coming
596# USAGE: download controls <downloadCommand>
597# USAGE: download now
598#
599# Clients use this method to create a downloadable representation
600# of the plot.  Returns a list of the form {ext string}, where
601# "ext" is the file extension (indicating the type of data) and
602# "string" is the data itself.
603# ----------------------------------------------------------------------
604itcl::body Rappture::VtkMeshViewer::download {option args} {
605    switch $option {
606        coming {
607            if {[catch {
608                blt::winop snap $itk_component(plotarea) $_image(download)
609            }]} {
610                $_image(download) configure -width 1 -height 1
611                $_image(download) put #000000
612            }
613        }
614        controls {
615            set popup .vtkviewerdownload
616            if { ![winfo exists .vtkviewerdownload] } {
617                set inner [BuildDownloadPopup $popup [lindex $args 0]]
618            } else {
619                set inner [$popup component inner]
620            }
621            set _downloadPopup(image_controls) $inner.image_frame
622            set num [llength [get]]
623            set num [expr {($num == 1) ? "1 result" : "$num results"}]
624            set word [Rappture::filexfer::label downloadWord]
625            $inner.summary configure -text "$word $num in the following format:"
626            update idletasks            ;# Fix initial sizes
627            return $popup
628        }
629        now {
630            set popup .vtkviewerdownload
631            if {[winfo exists .vtkviewerdownload]} {
632                $popup deactivate
633            }
634            switch -- $_downloadPopup(format) {
635                "image" {
636                    return [$this GetImage [lindex $args 0]]
637                }
638                "vtk" {
639                    return [$this GetVtkData [lindex $args 0]]
640                }
641            }
642            return ""
643        }
644        default {
645            error "bad option \"$option\": should be coming, controls, now"
646        }
647    }
648}
649
650# ----------------------------------------------------------------------
651# USAGE: Connect ?<host:port>,<host:port>...?
652#
653# Clients use this method to establish a connection to a new
654# server, or to reestablish a connection to the previous server.
655# Any existing connection is automatically closed.
656# ----------------------------------------------------------------------
657itcl::body Rappture::VtkMeshViewer::Connect {} {
658    global readyForNextFrame
659    set readyForNextFrame 1
660    set _hosts [GetServerList "vtkvis"]
661    if { "" == $_hosts } {
662        return 0
663    }
664    set result [VisViewer::Connect $_hosts]
665    if { $result } {
666        if { $_reportClientInfo }  {
667            # Tell the server the viewer, hub, user and session.
668            # Do this immediately on connect before buffering any commands
669            global env
670
671            set info {}
672            set user "???"
673            if { [info exists env(USER)] } {
674                set user $env(USER)
675            }
676            set session "???"
677            if { [info exists env(SESSION)] } {
678                set session $env(SESSION)
679            }
680            lappend info "hub" [exec hostname]
681            lappend info "client" "vtkmeshviewer"
682            lappend info "user" $user
683            lappend info "session" $session
684            SendCmd "clientinfo [list $info]"
685        }
686
687        set w [winfo width $itk_component(view)]
688        set h [winfo height $itk_component(view)]
689        EventuallyResize $w $h
690    }
691    return $result
692}
693
694#
695# isconnected --
696#
697#       Indicates if we are currently connected to the visualization server.
698#
699itcl::body Rappture::VtkMeshViewer::isconnected {} {
700    return [VisViewer::IsConnected]
701}
702
703#
704# disconnect --
705#
706itcl::body Rappture::VtkMeshViewer::disconnect {} {
707    Disconnect
708    set _reset 1
709}
710
711#
712# Disconnect --
713#
714#       Clients use this method to disconnect from the current rendering
715#       server.
716#
717itcl::body Rappture::VtkMeshViewer::Disconnect {} {
718    VisViewer::Disconnect
719
720    # disconnected -- no more data sitting on server
721    array unset _datasets
722    array unset _data
723    array unset _colormaps
724    global readyForNextFrame
725    set readyForNextFrame 1
726}
727
728# ----------------------------------------------------------------------
729# USAGE: ReceiveImage -bytes <size> -type <type> -token <token>
730#
731# Invoked automatically whenever the "image" command comes in from
732# the rendering server.  Indicates that binary image data with the
733# specified <size> will follow.
734# ----------------------------------------------------------------------
735itcl::body Rappture::VtkMeshViewer::ReceiveImage { args } {
736    global readyForNextFrame
737    set readyForNextFrame 1
738    array set info {
739        -token "???"
740        -bytes 0
741        -type image
742    }
743    array set info $args
744    set bytes [ReceiveBytes $info(-bytes)]
745    if { $info(-type) == "image" } {
746        if 0 {
747            set f [open "last.ppm" "w"]
748            fconfigure $f -encoding binary
749            puts -nonewline $f $bytes
750            close $f
751        }
752        $_image(plot) configure -data $bytes
753        set time [clock seconds]
754        set date [clock format $time]
755        if { $_start > 0 } {
756            set finish [clock clicks -milliseconds]
757            set _start 0
758        }
759    } elseif { $info(type) == "print" } {
760        set tag $this-print-$info(-token)
761        set _hardcopy($tag) $bytes
762    }
763}
764
765#
766# ReceiveDataset --
767#
768itcl::body Rappture::VtkMeshViewer::ReceiveDataset { args } {
769    if { ![isconnected] } {
770        return
771    }
772    set option [lindex $args 0]
773    switch -- $option {
774        "scalar" {
775            set option [lindex $args 1]
776            switch -- $option {
777                "world" {
778                    foreach { x y z value tag } [lrange $args 2 end] break
779                }
780                "pixel" {
781                    foreach { x y value tag } [lrange $args 2 end] break
782                }
783            }
784        }
785        "vector" {
786            set option [lindex $args 1]
787            switch -- $option {
788                "world" {
789                    foreach { x y z vx vy vz tag } [lrange $args 2 end] break
790                }
791                "pixel" {
792                    foreach { x y vx vy vz tag } [lrange $args 2 end] break
793                }
794            }
795        }
796        "names" {
797            foreach { name } [lindex $args 1] {
798                #puts stderr "Dataset: $name"
799            }
800        }
801        default {
802            error "unknown dataset option \"$option\" from server"
803        }
804    }
805}
806
807# ----------------------------------------------------------------------
808# USAGE: Rebuild
809#
810# Called automatically whenever something changes that affects the
811# data in the widget.  Clears any existing data and rebuilds the
812# widget to display new data.
813# ----------------------------------------------------------------------
814itcl::body Rappture::VtkMeshViewer::Rebuild {} {
815
816    set w [winfo width $itk_component(view)]
817    set h [winfo height $itk_component(view)]
818    if { $w < 2 || $h < 2 } {
819        $_dispatcher event -idle !rebuild
820        return
821    }
822
823    # Turn on buffering of commands to the server.  We don't want to
824    # be preempted by a server disconnect/reconnect (which automatically
825    # generates a new call to Rebuild).   
826    StartBufferingCommands
827
828    if { $_reset } {
829        set _width $w
830        set _height $h
831        $_arcball resize $w $h
832        DoResize
833        InitSettings -xgrid -ygrid -zgrid -axismode -axesvisible -axislabels
834        StopBufferingCommands
835        SendCmd "imgflush"
836        StartBufferingCommands
837    }
838
839    set _limits(zmin) ""
840    set _limits(zmax) ""
841    set _first ""
842    SendCmd "dataset visible 0"
843    set count 0
844    foreach dataobj [get -objects] {
845        if { [info exists _obj2ovride($dataobj-raise)] &&  $_first == "" } {
846            set _first $dataobj
847        }
848        set _obj2datasets($dataobj) ""
849        set tag $dataobj
850        if { ![info exists _datasets($tag)] } {
851            set bytes [$dataobj vtkdata -full]
852            if { $bytes == "" } {
853                continue
854            }
855            set length [string length $bytes]
856            if { $_reportClientInfo }  {
857                set info {}
858                lappend info "tool_id"       [$dataobj hints toolId]
859                lappend info "tool_name"     [$dataobj hints toolName]
860                lappend info "tool_version"  [$dataobj hints toolRevision]
861                lappend info "tool_title"    [$dataobj hints toolTitle]
862                lappend info "dataset_label" [$dataobj hints label]
863                lappend info "dataset_size"  $length
864                lappend info "dataset_tag"   $tag
865                SendCmd [list "clientinfo" $info]
866            }
867            SendCmd "dataset add $tag data follows $length"
868            append _outbuf $bytes
869            set _datasets($tag) 1
870            SetObjectStyle $dataobj
871        }
872        lappend _obj2datasets($dataobj) $tag
873        if { [info exists _obj2ovride($dataobj-raise)] } {
874            SendCmd "dataset visible 1 $tag"
875            EventuallySetPolydataOpacity
876        }
877    }
878    if {"" != $_first} {
879        set location [$_first hints camera]
880        if { $location != "" } {
881            array set view $location
882        }
883
884        foreach axis { x y z } {
885            set label [$_first label ${axis}]
886            if { $label != "" } {
887                SendCmd [list axis name $axis $label]
888            }
889            set units [$_first units ${axis}]
890            if { $units != "" } {
891                SendCmd [list axis units $axis $units]
892            }
893        }
894    }
895    InitSettings -outline
896    if { $_reset } {
897        # These are settings that rely on a dataset being loaded.
898        InitSettings -polydataedges -polydatalighting -polydataopacity \
899            -polydatavisible -polydatawireframe
900 
901        SendCmd "axis lformat all %g"
902        # Too many major ticks, so turn off minor ticks
903        SendCmd "axis minticks all 0"
904
905        set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
906        $_arcball quaternion $q
907        SendCmd "camera reset"
908        if { $_view(ortho)} {
909            SendCmd "camera mode ortho"
910        } else {
911            SendCmd "camera mode persp"
912        }
913        DoRotate
914        PanCamera
915        Zoom reset
916    }
917
918    set _reset 0
919    global readyForNextFrame
920    set readyForNextFrame 0;            # Don't advance to the next frame
921                                        # until we get an image.
922
923    # Actually write the commands to the server socket.  If it fails, we don't
924    # care.  We're finished here.
925    blt::busy hold $itk_component(hull)
926    StopBufferingCommands
927    blt::busy release $itk_component(hull)
928}
929
930# ----------------------------------------------------------------------
931# USAGE: CurrentDatasets ?-all -visible? ?dataobjs?
932#
933# Returns a list of server IDs for the current datasets being displayed.  This
934# is normally a single ID, but it might be a list of IDs if the current data
935# object has multiple components.
936# ----------------------------------------------------------------------
937itcl::body Rappture::VtkMeshViewer::CurrentDatasets {args} {
938    set flag [lindex $args 0]
939    switch -- $flag {
940        "-all" {
941            if { [llength $args] > 1 } {
942                error "CurrentDatasets: can't specify dataobj after \"-all\""
943            }
944            set dlist [get -objects]
945        }
946        "-visible" {
947            if { [llength $args] > 1 } {
948                set dlist {}
949                set args [lrange $args 1 end]
950                foreach dataobj $args {
951                    if { [info exists _obj2ovride($dataobj-raise)] } {
952                        lappend dlist $dataobj
953                    }
954                }
955            } else {
956                set dlist [get -visible]
957            }
958        }           
959        default {
960            set dlist $args
961        }
962    }
963    set rlist ""
964    foreach tag $dlist {
965        if { [info exists _datasets($tag)] && $_datasets($tag) } {
966            lappend rlist $tag
967        }
968    }
969    return $rlist
970}
971
972# ----------------------------------------------------------------------
973# USAGE: Zoom in
974# USAGE: Zoom out
975# USAGE: Zoom reset
976#
977# Called automatically when the user clicks on one of the zoom
978# controls for this widget.  Changes the zoom for the current view.
979# ----------------------------------------------------------------------
980itcl::body Rappture::VtkMeshViewer::Zoom {option} {
981    switch -- $option {
982        "in" {
983            set _view(zoom) [expr {$_view(zoom)*1.25}]
984            SendCmd "camera zoom $_view(zoom)"
985        }
986        "out" {
987            set _view(zoom) [expr {$_view(zoom)*0.8}]
988            SendCmd "camera zoom $_view(zoom)"
989        }
990        "reset" {
991            array set _view {
992                qw      0.853553
993                qx      -0.353553
994                qy      0.353553
995                qz      0.146447
996                zoom    1.0
997                xpan    0
998                ypan    0
999            }
1000            if { $_first != "" } {
1001                set location [$_first hints camera]
1002                if { $location != "" } {
1003                    array set _view $location
1004                }
1005            }
1006            set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1007            $_arcball quaternion $q
1008            DoRotate
1009            SendCmd "camera reset"
1010        }
1011    }
1012}
1013
1014itcl::body Rappture::VtkMeshViewer::PanCamera {} {
1015    set x $_view(xpan)
1016    set y $_view(ypan)
1017    SendCmd "camera pan $x $y"
1018}
1019
1020# ----------------------------------------------------------------------
1021# USAGE: Rotate click <x> <y>
1022# USAGE: Rotate drag <x> <y>
1023# USAGE: Rotate release <x> <y>
1024#
1025# Called automatically when the user clicks/drags/releases in the
1026# plot area.  Moves the plot according to the user's actions.
1027# ----------------------------------------------------------------------
1028itcl::body Rappture::VtkMeshViewer::Rotate {option x y} {
1029    switch -- $option {
1030        "click" {
1031            $itk_component(view) configure -cursor fleur
1032            set _click(x) $x
1033            set _click(y) $y
1034        }
1035        "drag" {
1036            if {[array size _click] == 0} {
1037                Rotate click $x $y
1038            } else {
1039                set w [winfo width $itk_component(view)]
1040                set h [winfo height $itk_component(view)]
1041                if {$w <= 0 || $h <= 0} {
1042                    return
1043                }
1044
1045                if {[catch {
1046                    # this fails sometimes for no apparent reason
1047                    set dx [expr {double($x-$_click(x))/$w}]
1048                    set dy [expr {double($y-$_click(y))/$h}]
1049                }]} {
1050                    return
1051                }
1052                if { $dx == 0 && $dy == 0 } {
1053                    return
1054                }
1055                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1056                EventuallyRotate $q
1057                set _click(x) $x
1058                set _click(y) $y
1059            }
1060        }
1061        "release" {
1062            Rotate drag $x $y
1063            $itk_component(view) configure -cursor ""
1064            catch {unset _click}
1065        }
1066        default {
1067            error "bad option \"$option\": should be click, drag, release"
1068        }
1069    }
1070}
1071
1072itcl::body Rappture::VtkMeshViewer::Pick {x y} {
1073    foreach tag [CurrentDatasets -visible] {
1074        SendCmd "dataset getscalar pixel $x $y $tag"
1075    }
1076}
1077
1078# ----------------------------------------------------------------------
1079# USAGE: $this Pan click x y
1080#        $this Pan drag x y
1081#        $this Pan release x y
1082#
1083# Called automatically when the user clicks on one of the zoom
1084# controls for this widget.  Changes the zoom for the current view.
1085# ----------------------------------------------------------------------
1086itcl::body Rappture::VtkMeshViewer::Pan {option x y} {
1087    switch -- $option {
1088        "set" {
1089            set w [winfo width $itk_component(view)]
1090            set h [winfo height $itk_component(view)]
1091            set x [expr $x / double($w)]
1092            set y [expr $y / double($h)]
1093            set _view(xpan) [expr $_view(xpan) + $x]
1094            set _view(ypan) [expr $_view(ypan) + $y]
1095            PanCamera
1096            return
1097        }
1098        "click" {
1099            set _click(x) $x
1100            set _click(y) $y
1101            $itk_component(view) configure -cursor hand1
1102        }
1103        "drag" {
1104            if { ![info exists _click(x)] } {
1105                set _click(x) $x
1106            }
1107            if { ![info exists _click(y)] } {
1108                set _click(y) $y
1109            }
1110            set w [winfo width $itk_component(view)]
1111            set h [winfo height $itk_component(view)]
1112            set dx [expr ($_click(x) - $x)/double($w)]
1113            set dy [expr ($_click(y) - $y)/double($h)]
1114            set _click(x) $x
1115            set _click(y) $y
1116            set _view(xpan) [expr $_view(xpan) - $dx]
1117            set _view(ypan) [expr $_view(ypan) - $dy]
1118            PanCamera
1119        }
1120        "release" {
1121            Pan drag $x $y
1122            $itk_component(view) configure -cursor ""
1123        }
1124        default {
1125            error "unknown option \"$option\": should set, click, drag, or release"
1126        }
1127    }
1128}
1129
1130# ----------------------------------------------------------------------
1131# USAGE: InitSettings <what> ?<value>?
1132#
1133# Used internally to update rendering settings whenever parameters
1134# change in the popup settings panel.  Sends the new settings off
1135# to the back end.
1136# ----------------------------------------------------------------------
1137itcl::body Rappture::VtkMeshViewer::InitSettings { args } {
1138    foreach setting $args {
1139        AdjustSetting $setting
1140    }
1141}
1142
1143#
1144# AdjustSetting --
1145#
1146#       Changes/updates a specific setting in the widget.  There are
1147#       usually user-setable option.  Commands are sent to the render
1148#       server.
1149#
1150itcl::body Rappture::VtkMeshViewer::AdjustSetting {what {value ""}} {
1151    if { ![isconnected] } {
1152        return
1153    }
1154    switch -- $what {
1155        "-outline" {
1156            set bool $_settings($what)
1157            # Only display a outline for the currently visible sets.
1158            SendCmd "outline visible 0"
1159            foreach dataset [CurrentDatasets -visible] {
1160                SendCmd "outline visible $bool $dataset"
1161            }
1162        }
1163        "-polydataopacity" {
1164            EventuallySetPolydataOpacity
1165        }
1166        "-polydatawireframe" {
1167            set bool $_settings($what)
1168            SendCmd "polydata wireframe $bool"
1169        }
1170        "-polydatavisible" {
1171            set bool $_settings($what)
1172            # Only change visibility of data sets marked "visible".
1173            foreach dataset [CurrentDatasets -visible] {
1174                SendCmd "polydata visible $bool $dataset"
1175            }
1176        }
1177        "-polydatalighting" {
1178            set bool $_settings($what)
1179            SendCmd "polydata lighting $bool"
1180        }
1181        "-polydataedges" {
1182            set bool $_settings($what)
1183            SendCmd "polydata edges $bool"
1184        }
1185        "-axesvisible" {
1186            set bool $_settings($what)
1187            SendCmd "axis visible all $bool"
1188        }
1189        "-axislabels" {
1190            set bool $_settings($what)
1191            SendCmd "axis labels all $bool"
1192        }
1193        "-xgrid" {
1194            set bool $_settings($what)
1195            SendCmd "axis grid x $bool"
1196        }
1197        "-ygrid" {
1198            set bool $_settings($what)
1199            SendCmd "axis grid y $bool"
1200        }
1201        "-zgrid" {
1202            set bool $_settings($what)
1203            SendCmd "axis grid z $bool"
1204        }
1205        "-axismode" {
1206            set mode [$itk_component(axismode) value]
1207            set mode [$itk_component(axismode) translate $mode]
1208            SendCmd "axis flymode $mode"
1209        }
1210        "-xcutaway" - "-ycutaway" - "-zcutaway" {
1211            set axis [string range $what 1 1]
1212            set bool $_settings($what)
1213            if { $bool } {
1214                set pos [expr $_settings(-${axis}position) * 0.01]
1215                set dir $_settings(-${axis}direction)
1216                $itk_component(${axis}CutScale) configure -state normal \
1217                    -troughcolor white
1218                SendCmd "renderer clipplane $axis $pos $dir"
1219            } else {
1220                $itk_component(${axis}CutScale) configure -state disabled \
1221                    -troughcolor grey82
1222                SendCmd "renderer clipplane $axis 1 -1"
1223            }
1224        }
1225        "-xposition" - "-yposition" - "-zposition" {
1226            set axis [string range $what 1 1]
1227            set pos [expr $_settings($what) * 0.01]
1228            SendCmd "renderer clipplane ${axis} $pos -1"
1229        }
1230        "-xdirection" - "-ydirection" - "-zdirection" {
1231            set axis [string range $what 1 1]
1232            puts stderr "direction not implemented"
1233        }
1234        default {
1235            error "don't know how to fix $what"
1236        }
1237    }
1238}
1239
1240# ----------------------------------------------------------------------
1241# CONFIGURATION OPTION: -plotbackground
1242# ----------------------------------------------------------------------
1243itcl::configbody Rappture::VtkMeshViewer::plotbackground {
1244    if { [isconnected] } {
1245        foreach {r g b} [Color2RGB $itk_option(-plotbackground)] break
1246        SendCmd "screen bgcolor $r $g $b"
1247    }
1248}
1249
1250# ----------------------------------------------------------------------
1251# CONFIGURATION OPTION: -plotforeground
1252# ----------------------------------------------------------------------
1253itcl::configbody Rappture::VtkMeshViewer::plotforeground {
1254    if { [isconnected] } {
1255        foreach {r g b} [Color2RGB $itk_option(-plotforeground)] break
1256        #fix this!
1257        #SendCmd "color background $r $g $b"
1258    }
1259}
1260
1261itcl::body Rappture::VtkMeshViewer::limits { dataobj } {
1262    set tag $dataobj
1263    if { ![info exists _limits($tag)] } {
1264        set data [$dataobj vtkdata -full]
1265        if { $data == "" } {
1266            continue
1267        }
1268        set tmpfile file[pid].vtk
1269        set f [open "$tmpfile" "w"]
1270        fconfigure $f -translation binary -encoding binary
1271        puts $f $data
1272        close $f
1273        set reader [vtkDataSetReader $tag-xvtkDataSetReader]
1274        $reader SetFileName $tmpfile
1275        $reader Update
1276        file delete $tmpfile
1277        set output [$reader GetOutput]
1278        set _limits($tag) [$output GetBounds]
1279        rename $output ""
1280        rename $reader ""
1281    }
1282    foreach { xMin xMax yMin yMax zMin zMax} $_limits($tag) break
1283    if {![info exists limits(xmin)] || $limits(xmin) > $xMin} {
1284        set limits(xmin) $xMin
1285    }
1286    if {![info exists limits(xmax)] || $limits(xmax) < $xMax} {
1287        set limits(xmax) $xMax
1288    }
1289    if {![info exists limits(ymin)] || $limits(ymin) > $yMin} {
1290        set limits(ymin) $xMin
1291    }
1292    if {![info exists limits(ymax)] || $limits(ymax) < $yMax} {
1293        set limits(ymax) $yMax
1294    }
1295    if {![info exists limits(zmin)] || $limits(zmin) > $zMin} {
1296        set limits(zmin) $zMin
1297    }
1298    if {![info exists limits(zmax)] || $limits(zmax) < $zMax} {
1299        set limits(zmax) $zMax
1300    }
1301
1302    return [array get limits]
1303}
1304
1305itcl::body Rappture::VtkMeshViewer::BuildPolydataTab {} {
1306
1307    set fg [option get $itk_component(hull) font Font]
1308    #set bfg [option get $itk_component(hull) boldFont Font]
1309
1310    set inner [$itk_component(main) insert end \
1311        -title "Mesh Settings" \
1312        -icon [Rappture::icon mesh]]
1313    $inner configure -borderwidth 4
1314
1315    checkbutton $inner.mesh \
1316        -text "Show Mesh" \
1317        -variable [itcl::scope _settings(-polydatavisible)] \
1318        -command [itcl::code $this AdjustSetting -polydatavisible] \
1319        -font "Arial 9" -anchor w
1320
1321    checkbutton $inner.outline \
1322        -text "Show Outline" \
1323        -variable [itcl::scope _settings(-outline)] \
1324        -command [itcl::code $this AdjustSetting -outline] \
1325        -font "Arial 9" -anchor w
1326
1327    checkbutton $inner.wireframe \
1328        -text "Show Wireframe" \
1329        -variable [itcl::scope _settings(-polydatawireframe)] \
1330        -command [itcl::code $this AdjustSetting -polydatawireframe] \
1331        -font "Arial 9" -anchor w
1332
1333    checkbutton $inner.lighting \
1334        -text "Enable Lighting" \
1335        -variable [itcl::scope _settings(-polydatalighting)] \
1336        -command [itcl::code $this AdjustSetting -polydatalighting] \
1337        -font "Arial 9" -anchor w
1338
1339    checkbutton $inner.edges \
1340        -text "Show Edges" \
1341        -variable [itcl::scope _settings(-polydataedges)] \
1342        -command [itcl::code $this AdjustSetting -polydataedges] \
1343        -font "Arial 9" -anchor w
1344
1345    itk_component add field_l {
1346        label $inner.field_l -text "Field" -font "Arial 9"
1347    } {
1348        ignore -font
1349    }
1350    itk_component add field {
1351        Rappture::Combobox $inner.field -width 10 -editable no
1352    }
1353    bind $inner.field <<Value>> \
1354        [itcl::code $this AdjustSetting -field]
1355
1356    label $inner.opacity_l -text "Opacity" -font "Arial 9" -anchor w
1357    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1358        -variable [itcl::scope _widget(-polydataopacity)] \
1359        -width 10 \
1360        -showvalue off \
1361        -command [itcl::code $this AdjustSetting -polydataopacity]
1362    $inner.opacity set [expr $_settings(-polydataopacity) * 100.0]
1363
1364    blt::table $inner \
1365        0,0 $inner.mesh      -cspan 2  -anchor w -pady 2 \
1366        1,0 $inner.outline   -cspan 2  -anchor w -pady 2 \
1367        2,0 $inner.wireframe -cspan 2  -anchor w -pady 2 \
1368        3,0 $inner.lighting  -cspan 2  -anchor w -pady 2 \
1369        4,0 $inner.edges     -cspan 2  -anchor w -pady 2 \
1370        5,0 $inner.opacity_l -anchor w -pady 2 \
1371        5,1 $inner.opacity   -fill x   -pady 2
1372
1373    blt::table configure $inner r* c* -resize none
1374    blt::table configure $inner r7 c1 -resize expand
1375}
1376
1377itcl::body Rappture::VtkMeshViewer::BuildAxisTab {} {
1378
1379    set fg [option get $itk_component(hull) font Font]
1380    #set bfg [option get $itk_component(hull) boldFont Font]
1381
1382    set inner [$itk_component(main) insert end \
1383        -title "Axis Settings" \
1384        -icon [Rappture::icon axis1]]
1385    $inner configure -borderwidth 4
1386
1387    checkbutton $inner.visible \
1388        -text "Show Axes" \
1389        -variable [itcl::scope _settings(-axesvisible)] \
1390        -command [itcl::code $this AdjustSetting -axesvisible] \
1391        -font "Arial 9"
1392
1393    checkbutton $inner.labels \
1394        -text "Show Axis Labels" \
1395        -variable [itcl::scope _settings(-axislabels)] \
1396        -command [itcl::code $this AdjustSetting -axislabels] \
1397        -font "Arial 9"
1398
1399    checkbutton $inner.gridx \
1400        -text "Show X Grid" \
1401        -variable [itcl::scope _settings(-xgrid)] \
1402        -command [itcl::code $this AdjustSetting -xgrid] \
1403        -font "Arial 9"
1404    checkbutton $inner.gridy \
1405        -text "Show Y Grid" \
1406        -variable [itcl::scope _settings(-ygrid)] \
1407        -command [itcl::code $this AdjustSetting -ygrid] \
1408        -font "Arial 9"
1409    checkbutton $inner.gridz \
1410        -text "Show Z Grid" \
1411        -variable [itcl::scope _settings(-zgrid)] \
1412        -command [itcl::code $this AdjustSetting -zgrid] \
1413        -font "Arial 9"
1414
1415    label $inner.mode_l -text "Mode" -font "Arial 9"
1416
1417    itk_component add axismode {
1418        Rappture::Combobox $inner.mode -width 10 -editable no
1419    }
1420    $inner.mode choices insert end \
1421        "static_triad"    "static" \
1422        "closest_triad"   "closest" \
1423        "furthest_triad"  "farthest" \
1424        "outer_edges"     "outer"         
1425    $itk_component(axismode) value "static"
1426    bind $inner.mode <<Value>> [itcl::code $this AdjustSetting -axismode]
1427
1428    blt::table $inner \
1429        0,0 $inner.visible -anchor w -cspan 2 \
1430        1,0 $inner.labels  -anchor w -cspan 2 \
1431        2,0 $inner.gridx   -anchor w -cspan 2 \
1432        3,0 $inner.gridy   -anchor w -cspan 2 \
1433        4,0 $inner.gridz   -anchor w -cspan 2 \
1434        5,0 $inner.mode_l  -anchor w -cspan 2 -padx { 2 0 } \
1435        6,0 $inner.mode    -fill x   -cspan 2
1436
1437    blt::table configure $inner r* c* -resize none
1438    blt::table configure $inner r7 c1 -resize expand
1439}
1440
1441itcl::body Rappture::VtkMeshViewer::BuildCameraTab {} {
1442    set inner [$itk_component(main) insert end \
1443        -title "Camera Settings" \
1444        -icon [Rappture::icon camera]]
1445    $inner configure -borderwidth 4
1446
1447    label $inner.view_l -text "view" -font "Arial 9"
1448    set f [frame $inner.view]
1449    foreach side { front back left right top bottom } {
1450        button $f.$side  -image [Rappture::icon view$side] \
1451            -command [itcl::code $this SetOrientation $side]
1452        Rappture::Tooltip::for $f.$side "Change the view to $side"
1453        pack $f.$side -side left
1454    }
1455
1456    blt::table $inner \
1457        0,0 $inner.view_l -anchor e -pady 2 \
1458        0,1 $inner.view -anchor w -pady 2
1459
1460    set labels { qx qy qz qw xpan ypan zoom }
1461    set row 1
1462    foreach tag $labels {
1463        label $inner.${tag}label -text $tag -font "Arial 9"
1464        entry $inner.${tag} -font "Arial 9"  -bg white \
1465            -textvariable [itcl::scope _view($tag)]
1466        bind $inner.${tag} <KeyPress-Return> \
1467            [itcl::code $this camera set ${tag}]
1468        blt::table $inner \
1469            $row,0 $inner.${tag}label -anchor e -pady 2 \
1470            $row,1 $inner.${tag} -anchor w -pady 2
1471        blt::table configure $inner r$row -resize none
1472        incr row
1473    }
1474    checkbutton $inner.ortho \
1475        -text "Orthographic Projection" \
1476        -variable [itcl::scope _view(ortho)] \
1477        -command [itcl::code $this camera set ortho] \
1478        -font "Arial 9"
1479    blt::table $inner \
1480            $row,0 $inner.ortho -cspan 2 -anchor w -pady 2
1481    blt::table configure $inner r$row -resize none
1482    incr row
1483
1484    blt::table configure $inner c* r* -resize none
1485    blt::table configure $inner c2 -resize expand
1486    blt::table configure $inner r$row -resize expand
1487}
1488
1489itcl::body Rappture::VtkMeshViewer::BuildCutawayTab {} {
1490
1491    set fg [option get $itk_component(hull) font Font]
1492   
1493    set inner [$itk_component(main) insert end \
1494        -title "Cutaway Along Axis" \
1495        -icon [Rappture::icon cutbutton]]
1496
1497    $inner configure -borderwidth 4
1498
1499    # X-value slicer...
1500    itk_component add xCutButton {
1501        Rappture::PushButton $inner.xbutton \
1502            -onimage [Rappture::icon x-cutplane] \
1503            -offimage [Rappture::icon x-cutplane] \
1504            -command [itcl::code $this AdjustSetting -xcutaway] \
1505            -variable [itcl::scope _settings(-xcutaway)]
1506    }
1507    Rappture::Tooltip::for $itk_component(xCutButton) \
1508        "Toggle the X-axis cutaway on/off"
1509
1510    itk_component add xCutScale {
1511        ::scale $inner.xval -from 100 -to 0 \
1512            -width 10 -orient vertical -showvalue yes \
1513            -borderwidth 1 -highlightthickness 0 \
1514            -command [itcl::code $this Slice move x] \
1515            -variable [itcl::scope _settings(-xposition)]
1516    } {
1517        usual
1518        ignore -borderwidth -highlightthickness
1519    }
1520    # Set the default cutaway value before disabling the scale.
1521    $itk_component(xCutScale) set 100
1522    $itk_component(xCutScale) configure -state disabled
1523    Rappture::Tooltip::for $itk_component(xCutScale) \
1524        "@[itcl::code $this Slice tooltip x]"
1525
1526    itk_component add xDirButton {
1527        Rappture::PushButton $inner.xdir \
1528            -onimage [Rappture::icon arrow-down] \
1529            -onvalue -1 \
1530            -offimage [Rappture::icon arrow-up] \
1531            -offvalue 1 \
1532            -command [itcl::code $this AdjustSetting -xdirection] \
1533            -variable [itcl::scope _settings(-xdirection)]
1534    }
1535    set _settings(-xdirection) -1
1536    Rappture::Tooltip::for $itk_component(xDirButton) \
1537        "Toggle the direction of the X-axis cutaway"
1538
1539    # Y-value slicer...
1540    itk_component add yCutButton {
1541        Rappture::PushButton $inner.ybutton \
1542            -onimage [Rappture::icon y-cutplane] \
1543            -offimage [Rappture::icon y-cutplane] \
1544            -command [itcl::code $this AdjustSetting -ycutaway] \
1545            -variable [itcl::scope _settings(-ycutaway)]
1546    }
1547    Rappture::Tooltip::for $itk_component(yCutButton) \
1548        "Toggle the Y-axis cutaway on/off"
1549
1550    itk_component add yCutScale {
1551        ::scale $inner.yval -from 100 -to 0 \
1552            -width 10 -orient vertical -showvalue yes \
1553            -borderwidth 1 -highlightthickness 0 \
1554            -command [itcl::code $this Slice move y] \
1555            -variable [itcl::scope _settings(-yposition)]
1556    } {
1557        usual
1558        ignore -borderwidth -highlightthickness
1559    }
1560    Rappture::Tooltip::for $itk_component(yCutScale) \
1561        "@[itcl::code $this Slice tooltip y]"
1562    # Set the default cutaway value before disabling the scale.
1563    $itk_component(yCutScale) set 100
1564    $itk_component(yCutScale) configure -state disabled
1565
1566    itk_component add yDirButton {
1567        Rappture::PushButton $inner.ydir \
1568            -onimage [Rappture::icon arrow-down] \
1569            -onvalue -1 \
1570            -offimage [Rappture::icon arrow-up] \
1571            -offvalue 1 \
1572            -command [itcl::code $this AdjustSetting -ydirection] \
1573            -variable [itcl::scope _settings(-ydirection)]
1574    }
1575    Rappture::Tooltip::for $itk_component(yDirButton) \
1576        "Toggle the direction of the Y-axis cutaway"
1577    set _settings(-ydirection) -1
1578
1579    # Z-value slicer...
1580    itk_component add zCutButton {
1581        Rappture::PushButton $inner.zbutton \
1582            -onimage [Rappture::icon z-cutplane] \
1583            -offimage [Rappture::icon z-cutplane] \
1584            -command [itcl::code $this AdjustSetting -zcutaway] \
1585            -variable [itcl::scope _settings(-zcutaway)]
1586    }
1587    Rappture::Tooltip::for $itk_component(zCutButton) \
1588        "Toggle the Z-axis cutaway on/off"
1589
1590    itk_component add zCutScale {
1591        ::scale $inner.zval -from 100 -to 0 \
1592            -width 10 -orient vertical -showvalue yes \
1593            -borderwidth 1 -highlightthickness 0 \
1594            -command [itcl::code $this Slice move z] \
1595            -variable [itcl::scope _settings(-zposition)]
1596    } {
1597        usual
1598        ignore -borderwidth -highlightthickness
1599    }
1600    $itk_component(zCutScale) set 100
1601    $itk_component(zCutScale) configure -state disabled
1602    Rappture::Tooltip::for $itk_component(zCutScale) \
1603        "@[itcl::code $this Slice tooltip z]"
1604
1605    itk_component add zDirButton {
1606        Rappture::PushButton $inner.zdir \
1607            -onimage [Rappture::icon arrow-down] \
1608            -onvalue -1 \
1609            -offimage [Rappture::icon arrow-up] \
1610            -offvalue 1 \
1611            -command [itcl::code $this AdjustSetting -zdirection] \
1612            -variable [itcl::scope _settings(-zdirection)]
1613    }
1614    set _settings(-zdirection) -1
1615    Rappture::Tooltip::for $itk_component(zDirButton) \
1616        "Toggle the direction of the Z-axis cutaway"
1617
1618    blt::table $inner \
1619        0,0 $itk_component(xCutButton)  -anchor e -padx 2 -pady 2 \
1620        1,0 $itk_component(xCutScale)   -fill y \
1621        0,1 $itk_component(yCutButton)  -anchor e -padx 2 -pady 2 \
1622        1,1 $itk_component(yCutScale)   -fill y \
1623        0,2 $itk_component(zCutButton)  -anchor e -padx 2 -pady 2 \
1624        1,2 $itk_component(zCutScale)   -fill y \
1625
1626    blt::table configure $inner r* c* -resize none
1627    blt::table configure $inner r1 c3 -resize expand
1628}
1629
1630#
1631#  camera --
1632#
1633itcl::body Rappture::VtkMeshViewer::camera {option args} {
1634    switch -- $option {
1635        "show" {
1636            puts [array get _view]
1637        }
1638        "set" {
1639            set who [lindex $args 0]
1640            set x $_view($who)
1641            set code [catch { string is double $x } result]
1642            if { $code != 0 || !$result } {
1643                return
1644            }
1645            switch -- $who {
1646                "ortho" {
1647                    if {$_view(ortho)} {
1648                        SendCmd "camera mode ortho"
1649                    } else {
1650                        SendCmd "camera mode persp"
1651                    }
1652                }
1653                "xpan" - "ypan" {
1654                    PanCamera
1655                }
1656                "qx" - "qy" - "qz" - "qw" {
1657                    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1658                    $_arcball quaternion $q
1659                    EventuallyRotate $q
1660                }
1661                "zoom" {
1662                    SendCmd "camera zoom $_view(zoom)"
1663                }
1664            }
1665        }
1666    }
1667}
1668
1669itcl::body Rappture::VtkMeshViewer::GetVtkData { args } {
1670    set bytes ""
1671    foreach dataobj [get] {
1672        set contents [$dataobj vtkdata -full]
1673        append bytes "$contents\n"
1674    }
1675    return [list .vtk $bytes]
1676}
1677
1678itcl::body Rappture::VtkMeshViewer::GetImage { args } {
1679    if { [image width $_image(download)] > 0 &&
1680         [image height $_image(download)] > 0 } {
1681        set bytes [$_image(download) data -format "jpeg -quality 100"]
1682        set bytes [Rappture::encoding::decode -as b64 $bytes]
1683        return [list .jpg $bytes]
1684    }
1685    return ""
1686}
1687
1688itcl::body Rappture::VtkMeshViewer::BuildDownloadPopup { popup command } {
1689    Rappture::Balloon $popup \
1690        -title "[Rappture::filexfer::label downloadWord] as..."
1691    set inner [$popup component inner]
1692    label $inner.summary -text "" -anchor w
1693    radiobutton $inner.vtk_button -text "VTK data file" \
1694        -variable [itcl::scope _downloadPopup(format)] \
1695        -font "Helvetica 9 " \
1696        -value vtk 
1697    Rappture::Tooltip::for $inner.vtk_button "Save as VTK data file."
1698    radiobutton $inner.image_button -text "Image File" \
1699        -variable [itcl::scope _downloadPopup(format)] \
1700        -value image
1701    Rappture::Tooltip::for $inner.image_button \
1702        "Save as digital image."
1703
1704    button $inner.ok -text "Save" \
1705        -highlightthickness 0 -pady 2 -padx 3 \
1706        -command $command \
1707        -compound left \
1708        -image [Rappture::icon download]
1709
1710    button $inner.cancel -text "Cancel" \
1711        -highlightthickness 0 -pady 2 -padx 3 \
1712        -command [list $popup deactivate] \
1713        -compound left \
1714        -image [Rappture::icon cancel]
1715
1716    blt::table $inner \
1717        0,0 $inner.summary -cspan 2  \
1718        1,0 $inner.vtk_button -anchor w -cspan 2 -padx { 4 0 } \
1719        2,0 $inner.image_button -anchor w -cspan 2 -padx { 4 0 } \
1720        4,1 $inner.cancel -width .9i -fill y \
1721        4,0 $inner.ok -padx 2 -width .9i -fill y
1722    blt::table configure $inner r3 -height 4
1723    blt::table configure $inner r4 -pady 4
1724    raise $inner.image_button
1725    $inner.vtk_button invoke
1726    return $inner
1727}
1728
1729itcl::body Rappture::VtkMeshViewer::SetObjectStyle { dataobj } {
1730    # Parse style string.
1731    set tag $dataobj
1732    set type [$dataobj type]
1733    set color [$dataobj hints color]
1734    set style [$dataobj hints style]
1735    if { $dataobj != $_first } {
1736        set settings(-polydatawireframe) 1
1737    }
1738
1739    array set settings {
1740        -cloudstyle mesh
1741        -color white
1742        -edgecolor black
1743        -linewidth 1.0
1744        -outline 0
1745        -polydataedges 1
1746        -polydatalighting 1
1747        -polydataopacity 1.0
1748        -polydatavisible 1
1749        -polydatawireframe 0
1750    }
1751    if {$type == "cloud"} {
1752        set settings(-cloudstyle) points
1753        set settings(-polydataedges) 0
1754        set settings(-edgecolor) white
1755    }
1756    array set settings $style
1757    if {$color != ""} {
1758        set settings(-color) $color
1759    }
1760    SendCmd "outline add $tag"
1761    SendCmd "outline color [Color2RGB $settings(-color)] $tag"
1762    SendCmd "outline visible $settings(-outline) $tag"
1763    set _settings(-outline) $settings(-outline)
1764
1765    SendCmd "polydata add $tag"
1766    SendCmd "polydata visible $settings(-polydatavisible) $tag"
1767    SendCmd "polydata cloudstyle $settings(-cloudstyle) $tag"
1768    set _settings(-polydatavisible) $settings(-polydatavisible)
1769    SendCmd "polydata edges $settings(-polydataedges) $tag"
1770    set _settings(-polydataedges) $settings(-polydataedges)
1771    SendCmd "polydata color [Color2RGB $settings(-color)] $tag"
1772
1773    SendCmd "polydata lighting $settings(-polydatalighting) $tag"
1774    set _settings(-polydatalighting) $settings(-polydatalighting)
1775    SendCmd "polydata linecolor [Color2RGB $settings(-edgecolor)] $tag"
1776    SendCmd "polydata linewidth $settings(-linewidth) $tag"
1777    SendCmd "polydata opacity $settings(-polydataopacity) $tag"
1778    set _settings(-polydataopacity) $settings(-polydataopacity)
1779    set _widget(-polydataopacity) [expr 100.0 * $settings(-polydataopacity)]
1780    SendCmd "polydata wireframe $settings(-polydatawireframe) $tag"
1781    set _settings(-polydatawireframe) $settings(-polydatawireframe)
1782    set havePolyData 1
1783}
1784
1785itcl::body Rappture::VtkMeshViewer::IsValidObject { dataobj } {
1786    if {[catch {$dataobj isa Rappture::Mesh} valid] != 0 || !$valid} {
1787        return 0
1788    }
1789    return 1
1790}
1791
1792# ----------------------------------------------------------------------
1793# USAGE: Slice move x|y|z <newval>
1794#
1795# Called automatically when the user drags the slider to move the
1796# cut plane that slices 3D data.  Gets the current value from the
1797# slider and moves the cut plane to the appropriate point in the
1798# data set.
1799# ----------------------------------------------------------------------
1800itcl::body Rappture::VtkMeshViewer::Slice {option args} {
1801    switch -- $option {
1802        "move" {
1803            set axis [lindex $args 0]
1804            set newval [lindex $args 1]
1805            if {[llength $args] != 2} {
1806                error "wrong # args: should be \"Slice move x|y|z newval\""
1807            }
1808            set newpos [expr {0.01*$newval}]
1809            SendCmd "renderer clipplane $axis $newpos -1"
1810        }
1811        "tooltip" {
1812            set axis [lindex $args 0]
1813            set val [$itk_component(${axis}CutScale) get]
1814            return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
1815        }
1816        default {
1817            error "bad option \"$option\": should be axis, move, or tooltip"
1818        }
1819    }
1820}
1821
1822itcl::body Rappture::VtkMeshViewer::SetOrientation { side } {
1823    array set positions {
1824        front "1 0 0 0"
1825        back  "0 0 1 0"
1826        left  "0.707107 0 -0.707107 0"
1827        right "0.707107 0 0.707107 0"
1828        top   "0.707107 -0.707107 0 0"
1829        bottom "0.707107 0.707107 0 0"
1830    }
1831    foreach name { qw qx qy qz } value $positions($side) {
1832        set _view($name) $value
1833    }
1834    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1835    $_arcball quaternion $q
1836    SendCmd "camera orient $q"
1837    SendCmd "camera reset"
1838    set _view(xpan) 0
1839    set _view(ypan) 0
1840    set _view(zoom) 1.0
1841}
1842
Note: See TracBrowser for help on using the repository browser.