source: trunk/gui/scripts/resultviewer.tcl @ 438

Last change on this file since 438 was 436, checked in by mmc, 19 years ago

Added the nanovis viewer for 3D fields. This connects to the machine:port
specified by nanovis_server directive in the user's "resources" file.
If it can't connect for some reason, it falls back to the older Vtk
visualization widget.

File size: 15.4 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: ResultViewer - plots a collection of related results
3#
4#  This widget plots a collection of results that all represent
5#  the same quantity, but for various ranges of input values.  It
6#  is normally used as part of an Analyzer, to plot the various
7#  results selected by a ResultSet.
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2005  Purdue Research Foundation
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 Img
17
18itcl::class Rappture::ResultViewer {
19    inherit itk::Widget
20
21    itk_option define -width width Width 4i
22    itk_option define -height height Height 4i
23    itk_option define -colors colors Colors ""
24    itk_option define -clearcommand clearCommand ClearCommand ""
25    itk_option define -simulatecommand simulateCommand SimulateCommand ""
26
27    constructor {args} { # defined below }
28    destructor { # defined below }
29
30    public method add {index xmlobj path}
31    public method clear {{index ""}}
32    public method value {xmlobj}
33
34    public method plot {option args}
35    public method download {option}
36
37    protected method _plotAdd {xmlobj {settings ""}}
38    protected method _fixScale {args}
39    protected proc _xml2data {xmlobj path}
40
41    private variable _dispatcher ""  ;# dispatchers for !events
42    private variable _mode ""        ;# current plotting mode (xy, etc.)
43    private variable _mode2widget    ;# maps plotting mode => widget
44    private variable _dataslots ""   ;# list of all data objects in this widget
45    private variable _plotlist ""    ;# list of indices plotted in _dataslots
46}
47                                                                               
48itk::usual ResultViewer {
49    keep -background -foreground -cursor -font
50}
51
52# ----------------------------------------------------------------------
53# CONSTRUCTOR
54# ----------------------------------------------------------------------
55itcl::body Rappture::ResultViewer::constructor {args} {
56    # create a dispatcher for events
57    Rappture::dispatcher _dispatcher
58    $_dispatcher register !scale
59    $_dispatcher dispatch $this !scale \
60        [itcl::code $this _fixScale]
61
62    eval itk_initialize $args
63}
64
65# ----------------------------------------------------------------------
66# DESTRUCTOR
67# ----------------------------------------------------------------------
68itcl::body Rappture::ResultViewer::destructor {} {
69    foreach slot $_dataslots {
70        foreach obj $slot {
71            itcl::delete object $obj
72        }
73    }
74}
75
76# ----------------------------------------------------------------------
77# USAGE: add <index> <xmlobj> <path>
78#
79# Adds a new result to this result viewer at the specified <index>.
80# Data is taken from the <xmlobj> object at the <path>.
81# ----------------------------------------------------------------------
82itcl::body Rappture::ResultViewer::add {index xmlobj path} {
83    set dobj [_xml2data $xmlobj $path]
84
85    #
86    # If the index doesn't exist, then fill in empty slots and
87    # make it exist.
88    #
89    for {set i [llength $_dataslots]} {$i <= $index} {incr i} {
90        lappend _dataslots ""
91    }
92    set slot [lindex $_dataslots $index]
93    lappend slot $dobj
94    set _dataslots [lreplace $_dataslots $index $index $slot]
95
96    $_dispatcher event -idle !scale
97}
98
99# ----------------------------------------------------------------------
100# USAGE: clear ?<index>?
101#
102# Clears one or all results in this result viewer.
103# ----------------------------------------------------------------------
104itcl::body Rappture::ResultViewer::clear {{index ""}} {
105    if {"" != $index} {
106        # clear one result
107        if {$index >= 0 && $index < [llength $_dataslots]} {
108            set slot [lindex $_dataslots $index]
109            foreach dobj $slot {
110                itcl::delete object $dobj
111            }
112            set _dataslots [lreplace $_dataslots $index $index ""]
113        }
114    } else {
115        # clear all results
116        plot clear
117        foreach slot $_dataslots {
118            foreach dobj $slot {
119                itcl::delete object $dobj
120            }
121        }
122        set _dataslots ""
123    }
124}
125
126# ----------------------------------------------------------------------
127# USAGE: value <xmlobj>
128#
129# Convenience method for showing a single value.  Loads the value
130# into the widget via add/clear, then immediately plots the value.
131# This makes the widget consistent with other widgets, such as
132# the DeviceEditor, etc.
133# ----------------------------------------------------------------------
134itcl::body Rappture::ResultViewer::value {xmlobj} {
135    clear
136    if {"" != $xmlobj} {
137        add 0 $xmlobj ""
138        plot add 0 ""
139    }
140}
141
142# ----------------------------------------------------------------------
143# USAGE: plot add ?<index> <settings> <index> <settings> ...?
144# USAGE: plot clear
145#
146# Used to manipulate the contents of this viewer.  The "plot clear"
147# command clears the current viewer.  Data is still stored in the
148# widget, but the results are not shown on screen.  The "plot add"
149# command adds the data at the specified <index> to the plot.  If
150# the optional <settings> are specified, then they are applied
151# to the plot; otherwise, default settings are used.
152# ----------------------------------------------------------------------
153itcl::body Rappture::ResultViewer::plot {option args} {
154    switch -- $option {
155        add {
156            foreach {index opts} $args {
157                set reset "-color autoreset"
158                set slot [lindex $_dataslots $index]
159                foreach dobj $slot {
160                    set settings ""
161                    # start with color reset, only for first object in series
162                    if {"" != $reset} {
163                        set settings $reset
164                        set reset ""
165                    }
166                    # add default settings from data object
167                    if {[catch {$dobj hints style} style] == 0} {
168                        eval lappend settings $style
169                    }
170                    # add override settings passed in here
171                    eval lappend settings $opts
172
173                    _plotAdd $dobj $settings
174                }
175            }
176        }
177        clear {
178            # clear the contents of the current mode
179            if {"" != $_mode} {
180                $_mode2widget($_mode) delete
181            }
182            set _plotlist ""
183        }
184        default {
185            error "bad option \"$option\": should be add or clear"
186        }
187    }
188}
189
190# ----------------------------------------------------------------------
191# USAGE: _plotAdd <dataobj> <settings>
192#
193# Used internally to add a <dataobj> representing some data to
194# the plot at the top of this widget.  The data is added to the
195# current plot.  Use the "clear" function to clear before adding
196# new data.
197# ----------------------------------------------------------------------
198itcl::body Rappture::ResultViewer::_plotAdd {dataobj {settings ""}} {
199    switch -- [$dataobj info class] {
200        ::Rappture::Curve {
201            set mode "xy"
202            if {![info exists _mode2widget($mode)]} {
203                set w $itk_interior.xy
204                Rappture::XyResult $w
205                set _mode2widget($mode) $w
206            }
207        }
208        ::Rappture::Field {
209            set dims [lindex [lsort [$dataobj components -dimensions]] end]
210            switch -- $dims {
211                1D {
212                    set mode "xy"
213                    if {![info exists _mode2widget($mode)]} {
214                        set w $itk_interior.xy
215                        Rappture::XyResult $w
216                        set _mode2widget($mode) $w
217                    }
218                }
219                2D {
220                    set mode "contour"
221                    if {![info exists _mode2widget($mode)]} {
222                        set w $itk_interior.contour
223                        Rappture::ContourResult $w
224                        set _mode2widget($mode) $w
225                    }
226                }
227                3D {
228                    set mode "field3D"
229                    if {![info exists _mode2widget($mode)]} {
230                        set w $itk_interior.field3D
231                        Rappture::Field3DResult $w
232                        set _mode2widget($mode) $w
233                    }
234                }
235                default {
236                    error "can't handle [$dataobj components -dimensions] field"
237                }
238            }
239        }
240        ::Rappture::Mesh {
241            switch -- [$dataobj dimensions] {
242                2 {
243                    set mode "mesh"
244                    if {![info exists _mode2widget($mode)]} {
245                        set w $itk_interior.mesh
246                        Rappture::MeshResult $w
247                        set _mode2widget($mode) $w
248                    }
249                }
250                default {
251                    error "can't handle [$dataobj dimensions]D field"
252                }
253            }
254        }
255        ::Rappture::Table {
256            set cols [Rappture::EnergyLevels::columns $dataobj]
257            if {"" != $cols} {
258                set mode "energies"
259                if {![info exists _mode2widget($mode)]} {
260                    set w $itk_interior.energies
261                    Rappture::EnergyLevels $w
262                    set _mode2widget($mode) $w
263                }
264            }
265        }
266        ::Rappture::LibraryObj {
267            switch -- [$dataobj element -as type] {
268                string - log {
269                    set mode "log"
270                    if {![info exists _mode2widget($mode)]} {
271                        set w $itk_interior.log
272                        Rappture::TextResult $w
273                        set _mode2widget($mode) $w
274                    }
275                }
276                structure {
277                    set mode "structure"
278                    if {![info exists _mode2widget($mode)]} {
279                        set w $itk_interior.struct
280                        Rappture::DeviceResult $w
281                        set _mode2widget($mode) $w
282                    }
283                }
284                number - integer - boolean - choice {
285                    set mode "value"
286                    if {![info exists _mode2widget($mode)]} {
287                        set w $itk_interior.value
288                        Rappture::ValueResult $w
289                        set _mode2widget($mode) $w
290                    }
291                }
292            }
293        }
294        ::Rappture::Image {
295            set mode "image"
296            if {![info exists _mode2widget($mode)]} {
297                set w $itk_interior.image
298                Rappture::ImageResult $w
299                set _mode2widget($mode) $w
300            }
301        }
302        ::Rappture::Sequence {
303            set mode "sequence"
304            if {![info exists _mode2widget($mode)]} {
305                set w $itk_interior.image
306                Rappture::SequenceResult $w
307                set _mode2widget($mode) $w
308            }
309        }
310        default {
311            error "don't know how to plot <$type> data"
312        }
313    }
314
315    if {$mode != $_mode && $_mode != ""} {
316        set nactive [llength [$_mode2widget($_mode) get]]
317        if {$nactive > 0} {
318            return  ;# mixing data that doesn't mix -- ignore it!
319        }
320    }
321
322    # are we plotting in a new mode? then change widgets
323    if {$_mode2widget($mode) != [pack slaves $itk_interior]} {
324        # remove any current window
325        foreach w [pack slaves $itk_interior] {
326            pack forget $w
327        }
328        pack $_mode2widget($mode) -expand yes -fill both
329
330        set _mode $mode
331        $_dispatcher event -idle !scale
332    }
333    $_mode2widget($mode) add $dataobj $settings
334}
335
336# ----------------------------------------------------------------------
337# USAGE: _fixScale ?<eventArgs>...?
338#
339# Invoked automatically whenever a new dataset is added to fix the
340# overall scales of the viewer.  This makes the visualizer consistent
341# across all <dataobj> in this widget, so that it can plot all
342# available data.
343# ----------------------------------------------------------------------
344itcl::body Rappture::ResultViewer::_fixScale {args} {
345    if {"" != $_mode} {
346        set dlist ""
347        foreach slot $_dataslots {
348            foreach dobj $slot {
349                lappend dlist $dobj
350            }
351        }
352        eval $_mode2widget($_mode) scale $dlist
353    }
354}
355
356# ----------------------------------------------------------------------
357# USAGE: download coming
358# USAGE: download now
359#
360# Clients use this method to create a downloadable representation
361# of the plot.  Returns a list of the form {ext string}, where
362# "ext" is the file extension (indicating the type of data) and
363# "string" is the data itself.
364# ----------------------------------------------------------------------
365itcl::body Rappture::ResultViewer::download {option} {
366    if {"" == $_mode} {
367        return ""
368    }
369    return [$_mode2widget($_mode) download $option]
370}
371
372# ----------------------------------------------------------------------
373# USAGE: _xml2data <xmlobj> <path>
374#
375# Used internally to create a data object for the data at the
376# specified <path> in the <xmlobj>.
377# ----------------------------------------------------------------------
378itcl::body Rappture::ResultViewer::_xml2data {xmlobj path} {
379    set type [$xmlobj element -as type $path]
380    switch -- $type {
381        curve {
382            return [Rappture::Curve ::#auto $xmlobj $path]
383        }
384        field {
385            return [Rappture::Field ::#auto $xmlobj $path]
386        }
387        mesh {
388            return [Rappture::Mesh ::#auto $xmlobj $path]
389        }
390        table {
391            return [Rappture::Table ::#auto $xmlobj $path]
392        }
393        image {
394            return [Rappture::Image ::#auto $xmlobj $path]
395        }
396        sequence {
397            return [Rappture::Sequence ::#auto $xmlobj $path]
398        }
399        string - log {
400            return [$xmlobj element -as object $path]
401        }
402        structure {
403            return [$xmlobj element -as object $path]
404        }
405        number - integer - boolean - choice {
406            return [$xmlobj element -as object $path]
407        }
408        time - status {
409            return ""
410        }
411    }
412    error "don't know how to plot <$type> data"
413}
414
415# ----------------------------------------------------------------------
416# CONFIGURATION OPTION: -width
417# ----------------------------------------------------------------------
418itcl::configbody Rappture::ResultViewer::width {
419    set w [winfo pixels $itk_component(hull) $itk_option(-width)]
420    set h [winfo pixels $itk_component(hull) $itk_option(-height)]
421    if {$w == 0 || $h == 0} {
422        pack propagate $itk_component(hull) yes
423    } else {
424        component hull configure -width $w -height $h
425        pack propagate $itk_component(hull) no
426    }
427}
428
429# ----------------------------------------------------------------------
430# CONFIGURATION OPTION: -height
431# ----------------------------------------------------------------------
432itcl::configbody Rappture::ResultViewer::height {
433    set h [winfo pixels $itk_component(hull) $itk_option(-height)]
434    set w [winfo pixels $itk_component(hull) $itk_option(-width)]
435    if {$w == 0 || $h == 0} {
436        pack propagate $itk_component(hull) yes
437    } else {
438        component hull configure -width $w -height $h
439        pack propagate $itk_component(hull) no
440    }
441}
Note: See TracBrowser for help on using the repository browser.