source: trunk/gui/scripts/vtkmeshviewer.tcl @ 4136

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

Add preliminary VTK-based viewer for mesh results

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