source: trunk/gui/scripts/field.tcl @ 2652

Last change on this file since 2652 was 2616, checked in by gah, 13 years ago
File size: 33.3 KB
Line 
1
2# ----------------------------------------------------------------------
3#  COMPONENT: field - extracts data from an XML description of a field
4#
5#  This object represents one field in an XML description of a device.
6#  It simplifies the process of extracting data vectors that represent
7#  the field.
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 Itcl
16package require BLT
17
18namespace eval Rappture { # forward declaration }
19
20itcl::class Rappture::Field {
21    constructor {xmlobj path} { # defined below }
22    destructor { # defined below }
23
24    public method components {args}
25    public method mesh {{what -overall}}
26    public method values {{what -overall}}
27    public method blob {{what -overall}}
28    public method limits {axis}
29    public method controls {option args}
30    public method hints {{key ""}}
31    public method style { cname }
32    public method isunirect2d {}
33    public method isunirect3d {}
34    public method extents {{what -overall}}
35    public method flowhints { cname }
36    public method type {}
37
38    protected method _build {}
39    protected method _getValue {expr}
40
41    private variable _xmlobj ""  ;      # ref to XML obj with device data
42    private variable _path "";          # Path of this object in the XML
43    private variable _units ""   ;      # system of units for this field
44    private variable _limits     ;# maps box name => {z0 z1} limits
45    private variable _zmax 0     ;# length of the device
46
47    private variable _field ""   ;# lib obj representing this field
48    private variable _comp2dims  ;# maps component name => dimensionality
49    private variable _comp2xy    ;# maps component name => x,y vectors
50    private variable _comp2vtk   ;# maps component name => vtkFloatArray
51    private variable _comp2vtkstreamlines   ;# maps component name => vtkFloatArray
52    private variable _comp2dx    ;# maps component name => OpenDX data
53    private variable _comp2unirect2d ;# maps component name => unirect2d obj
54    private variable _comp2unirect3d ;# maps component name => unirect3d obj
55    private variable _comp2style ;# maps component name => style settings
56    private variable _comp2cntls ;# maps component name => x,y control points
57    private variable _comp2extents
58    private variable _type ""
59    private variable _comp2flowhints
60    private common _counter 0    ;# counter for unique vector names
61}
62
63# ----------------------------------------------------------------------
64# CONSTRUCTOR
65# ----------------------------------------------------------------------
66itcl::body Rappture::Field::constructor {xmlobj path} {
67    if {![Rappture::library isvalid $xmlobj]} {
68        error "bad value \"$xmlobj\": should be Rappture::library"
69    }
70    set _xmlobj $xmlobj
71    set _path $path
72    set _field [$xmlobj element -as object $path]
73    set _units [$_field get units]
74
75    set xunits [$xmlobj get units]
76    if {"" == $xunits || "arbitrary" == $xunits} {
77        set xunits "um"
78    }
79
80    # determine the overall size of the device
81    set z0 [set z1 0]
82    foreach elem [$_xmlobj children components] {
83        switch -glob -- $elem {
84            box* {
85                if {![regexp {[0-9]$} $elem]} {
86                    set elem "${elem}0"
87                }
88                set z0 [$_xmlobj get components.$elem.corner0]
89                set z0 [Rappture::Units::convert $z0 \
90                    -context $xunits -to $xunits -units off]
91
92                set z1 [$_xmlobj get components.$elem.corner1]
93                set z1 [Rappture::Units::convert $z1 \
94                    -context $xunits -to $xunits -units off]
95
96                set _limits($elem) [list $z0 $z1]
97            }
98        }
99    }
100    set _zmax $z1
101
102    # build up vectors for various components of the field
103    _build
104}
105
106# ----------------------------------------------------------------------
107# DESTRUCTOR
108# ----------------------------------------------------------------------
109itcl::body Rappture::Field::destructor {} {
110    itcl::delete object $_field
111    # don't destroy the _xmlobj! we don't own it!
112
113    foreach name [array names _comp2xy] {
114        eval blt::vector destroy $_comp2xy($name)
115    }
116    foreach name [array names _comp2vtk] {
117        set mobj [lindex $_comp2vtk($name) 0]
118        set class [$mobj info class]
119        ${class}::release $mobj
120
121        set fobj [lindex $_comp2vtk($name) 1]
122        rename $fobj ""
123    }
124    foreach name [array names _comp2unirect2d] {
125        itcl::delete object $_comp2unirect2d($name)
126    }
127    foreach name [array names _comp2unirect3d] {
128        itcl::delete object $_comp2unirect3d($name)
129    }
130    foreach name [array names _comp2flowhints] {
131        itcl::delete object $_comp2flowhints($name)
132    }
133}
134
135# ----------------------------------------------------------------------
136# USAGE: components ?-name|-dimensions|-style? ?<pattern>?
137#
138# Returns a list of names or types for the various components of
139# this field.  If the optional glob-style <pattern> is specified,
140# then it returns only the components with names matching the pattern.
141# ----------------------------------------------------------------------
142itcl::body Rappture::Field::components {args} {
143    Rappture::getopts args params {
144        flag what -name default
145        flag what -dimensions
146        flag what -style
147        flag what -particles
148        flag what -flow
149        flag what -box
150    }
151
152    set pattern *
153    if {[llength $args] > 0} {
154        set pattern [lindex $args 0]
155        set args [lrange $args 1 end]
156    }
157    if {[llength $args] > 0} {
158        error "wrong # args: should be \"components ?switches? ?pattern?\""
159    }
160
161    set rlist ""
162
163    # BE CAREFUL: return component names in proper order
164    foreach cname [$_field children -type component] {
165        if {[info exists _comp2dims($cname)]
166              && [string match $pattern $cname]} {
167
168            switch -- $params(what) {
169                -name { lappend rlist $cname }
170                -dimensions { lappend rlist $_comp2dims($cname) }
171                -style { lappend rlist $_comp2style($cname) }
172            }
173        }
174    }
175    return $rlist
176}
177
178# ----------------------------------------------------------------------
179# USAGE: mesh ?<name>?
180#
181# Returns a list {xvec yvec} for the specified field component <name>.
182# If the name is not specified, then it returns the vectors for the
183# overall field (sum of all components).
184# ----------------------------------------------------------------------
185itcl::body Rappture::Field::mesh {{what -overall}} {
186    if {$what == "-overall" || $what == "component0"} {
187        set what [lindex [components -name] 0]
188    }
189    if {[info exists _comp2xy($what)]} {
190        return [lindex $_comp2xy($what) 0]  ;# return xv
191    }
192    if { [info exists _comp2vtkstreamlines($what)] } {
193        error "mesh: not implemented for streamlines"
194        return [$mobj mesh]
195    }
196    if { [info exists _comp2vtk($what)] } {
197        set mobj [lindex $_comp2vtk($what) 0]
198        return [$mobj mesh]
199    }
200    if {[info exists _comp2dx($what)]} {
201        return ""  ;# no mesh -- it's embedded in the value data
202    }
203    if {[info exists _comp2unirect2d($what)]} {
204        set mobj [lindex $_comp2unirect2d($what) 0]
205        return [$mobj mesh]
206    }
207    if {[info exists _comp2unirect3d($what)]} {
208        set mobj [lindex $_comp2unirect3d($what) 0]
209        return [$mobj mesh]
210    }
211    error "bad option \"$what\": should be [join [lsort [array names _comp2dims]] {, }]"
212}
213
214# ----------------------------------------------------------------------
215# USAGE: values ?<name>?
216#
217# Returns a list {xvec yvec} for the specified field component <name>.
218# If the name is not specified, then it returns the vectors for the
219# overall field (sum of all components).
220# ----------------------------------------------------------------------
221itcl::body Rappture::Field::values {{what -overall}} {
222    if {$what == "component0"} {
223        set what "component"
224    }
225    if {[info exists _comp2xy($what)]} {
226        return [lindex $_comp2xy($what) 1]  ;# return yv
227    }
228    if { [info exists _comp2vtkstreamlines($what)] } {
229        # FIXME: Need to process the vtk file data to pull out the field's
230        # values.
231        error "vtkstreamlines: values not implements"
232        return [lindex $_comp2vtkstreamlines($what) 1]
233    }
234    if { [info exists _comp2vtk($what)] } {
235        return [lindex $_comp2vtk($what) 1]  ;# return vtkFloatArray
236    }
237    if {[info exists _comp2dx($what)]} {
238        return $_comp2dx($what)  ;# return gzipped, base64-encoded DX data
239    }
240    if {[info exists _comp2unirect2d($what)]} {
241        return [$_comp2unirect2d($what) values]
242    }
243    if {[info exists _comp2unirect3d($what)]} {
244        return [$_comp2unirect3d($what) blob]
245    }
246    error "bad option \"$what\": should be [join [lsort [array names _comp2dims]] {, }]"
247}
248
249# ----------------------------------------------------------------------
250# USAGE: blob ?<name>?
251#
252# Returns a string representing the blob of data for the mesh and values.
253# ----------------------------------------------------------------------
254itcl::body Rappture::Field::blob {{what -overall}} {
255    if {$what == "component0"} {
256        set what "component"
257    }
258    if {[info exists _comp2xy($what)]} {
259        return ""
260    }
261    if { [info exists _comp2vtk($what)] } {
262        return ""
263    }
264    if { [info exists _comp2vtkstreamlines($what)] } {
265        # Return the contents of the vtk file.
266        return $_comp2vtkstreamlines($what)
267    }
268    if {[info exists _comp2dx($what)]} {
269        return $_comp2dx($what)  ;# return gzipped, base64-encoded DX data
270    }
271    if {[info exists _comp2unirect2d($what)]} {
272        return [$_comp2unirect2d($what) blob]
273    }
274    if {[info exists _comp2unirect3d($what)]} {
275        return [$_comp2unirect3d($what) blob]
276    }
277    error "bad option \"$what\": should be [join [lsort [array names _comp2dims]] {, }]"
278}
279
280# ----------------------------------------------------------------------
281# USAGE: limits <axis>
282#
283# Returns a list {min max} representing the limits for the specified
284# axis.
285# ----------------------------------------------------------------------
286itcl::body Rappture::Field::limits {which} {
287    set min ""
288    set max ""
289
290    blt::vector tmp zero
291    foreach comp [array names _comp2dims] {
292        switch -- $_comp2dims($comp) {
293            1D {
294                switch -- $which {
295                    x - xlin { set pos 0; set log 0; set axis xaxis }
296                    xlog { set pos 0; set log 1; set axis xaxis }
297                    y - ylin - v - vlin { set pos 1; set log 0; set axis yaxis }
298                    ylog - vlog { set pos 1; set log 1; set axis yaxis }
299                    default {
300                        error "bad option \"$which\": should be x, xlin, xlog, y, ylin, ylog, v, vlin, vlog"
301                    }
302                }
303
304                set vname [lindex $_comp2xy($comp) $pos]
305                $vname variable vec
306
307                if {$log} {
308                    # on a log scale, use abs value and ignore 0's
309                    $vname dup tmp
310                    $vname dup zero
311                    zero expr {tmp == 0}            ;# find the 0's
312                    tmp expr {abs(tmp)}             ;# get the abs value
313                    tmp expr {tmp + zero*max(tmp)}  ;# replace 0's with abs max
314                    set vmin [blt::vector expr min(tmp)]
315                    set vmax [blt::vector expr max(tmp)]
316                } else {
317                    set vmin $vec(min)
318                    set vmax $vec(max)
319                }
320
321                if {"" == $min} {
322                    set min $vmin
323                } elseif {$vmin < $min} {
324                    set min $vmin
325                }
326                if {"" == $max} {
327                    set max $vmax
328                } elseif {$vmax > $max} {
329                    set max $vmax
330                }
331            }
332            2D - 3D {
333                if {[info exists _comp2unirect2d($comp)]} {
334                    set limits [$_comp2unirect2d($comp) limits $which]
335                    foreach {vmin vmax} $limits break
336                    set axis vaxis
337                } elseif {[info exists _comp2unirect3d($comp)]} {
338                    set limits [$_comp2unirect3d($comp) limits $which]
339                    foreach {vmin vmax} $limits break
340                    set axis vaxis
341                } elseif {[info exists _comp2vtk($comp)]} {
342                    foreach {xv yv} $_comp2vtk($comp) break
343                    switch -- $which {
344                        x - xlin - xlog {
345                            foreach {vmin vmax} [$xv limits x] break
346                            set axis xaxis
347                        }
348                        y - ylin - ylog {
349                            foreach {vmin vmax} [$xv limits y] break
350                            set axis yaxis
351                        }
352                        z - zlin - zlog {
353                            foreach {vmin vmax} [$xv limits z] break
354                            set axis zaxis
355                        }
356                        v - vlin - vlog {
357                            catch {unset style}
358                            array set style $_comp2style($comp)
359                            if {[info exists style(-min)] && [info exists style(-max)]} {
360                                # This component has its own hard-coded
361                                # min/max range.  Ignore it for overall limits.
362                                set vmin $min
363                                set vmax $max
364                            } else {
365                                foreach {vmin vmax} [$yv GetRange] break
366                            }
367                            set axis vaxis
368                        }
369                        default {
370                            error "bad option \"$which\": should be x, xlin, xlog, y, ylin, ylog, v, vlin, vlog"
371                        }
372                    }
373                } else {
374                    set vmin 0  ;# HACK ALERT! must be OpenDX data
375                    set vmax 1
376                    set axis vaxis
377                }
378            }
379        }
380        if {"" == $min} {
381            set min $vmin
382        } elseif {$vmin < $min} {
383            set min $vmin
384        }
385        if {"" == $max} {
386            set max $vmax
387        } elseif {$vmax > $max} {
388            set max $vmax
389        }
390    }
391    blt::vector destroy tmp zero
392
393    set val [$_field get $axis.min]
394    if {"" != $val && "" != $min} {
395        if {$val > $min} {
396            # tool specified this min -- don't go any lower
397            set min $val
398        }
399    }
400
401    set val [$_field get $axis.max]
402    if {"" != $val && "" != $max} {
403        if {$val < $max} {
404            # tool specified this max -- don't go any higher
405            set max $val
406        }
407    }
408    return [list $min $max]
409}
410
411# ----------------------------------------------------------------------
412# USAGE: controls get ?<name>?
413# USAGE: controls validate <path> <value>
414# USAGE: controls put <path> <value>
415#
416# Returns a list {path1 x1 y1 val1  path2 x2 y2 val2 ...} representing
417# control points for the specified field component <name>.
418# ----------------------------------------------------------------------
419itcl::body Rappture::Field::controls {option args} {
420    switch -- $option {
421        get {
422            set what [lindex $args 0]
423            if {[info exists _comp2cntls($what)]} {
424                return $_comp2cntls($what)
425            }
426            return ""
427        }
428        validate {
429            set path [lindex $args 0]
430            set value [lindex $args 1]
431            set units [$_xmlobj get $path.units]
432
433            if {"" != $units} {
434                set nv [Rappture::Units::convert \
435                    $value -context $units -to $units -units off]
436            } else {
437                set nv $value
438            }
439            if {![string is double $nv]
440                  || [regexp -nocase {^(inf|nan)$} $nv]} {
441                error "Value out of range"
442            }
443
444            set rawmin [$_xmlobj get $path.min]
445            if {"" != $rawmin} {
446                set minv $rawmin
447                if {"" != $units} {
448                    set minv [Rappture::Units::convert \
449                        $minv -context $units -to $units -units off]
450                    set nv [Rappture::Units::convert \
451                        $value -context $units -to $units -units off]
452                }
453                # fix for the case when the user tries to
454                # compare values like minv=-500 nv=-0600
455                set nv [format "%g" $nv]
456                set minv [format "%g" $minv]
457
458                if {$nv < $minv} {
459                    error "Minimum value allowed here is $rawmin"
460                }
461            }
462
463            set rawmax [$_xmlobj get $path.max]
464            if {"" != $rawmax} {
465                set maxv $rawmax
466                if {"" != $units} {
467                    set maxv [Rappture::Units::convert \
468                        $maxv -context $units -to $units -units off]
469                    set nv [Rappture::Units::convert \
470                        $value -context $units -to $units -units off]
471                }
472                # fix for the case when the user tries to
473                # compare values like maxv=-500 nv=-0600
474                set nv [format "%g" $nv]
475                set maxv [format "%g" $maxv]
476
477                if {$nv > $maxv} {
478                    error "Maximum value allowed here is $rawmax"
479                }
480            }
481
482            return "ok"
483        }
484        put {
485            set path [lindex $args 0]
486            set value [lindex $args 1]
487            $_xmlobj put $path.current $value
488            _build
489        }
490        default {
491            error "bad option \"$option\": should be get or put"
492        }
493    }
494}
495
496# ----------------------------------------------------------------------
497# USAGE: hints ?<keyword>?
498#
499# Returns a list of key/value pairs for various hints about plotting
500# this field.  If a particular <keyword> is specified, then it returns
501# the hint for that <keyword>, if it exists.
502# ----------------------------------------------------------------------
503itcl::body Rappture::Field::hints {{keyword ""}} {
504    foreach {key path} {
505        group   about.group
506        label   about.label
507        color   about.color
508        style   about.style
509        scale   about.scale
510        seeds   about.seeds
511        scalars about.scalars
512        vectors about.vectors
513        default about.default
514        units   units
515        updir   updir
516        camera  camera.position
517        type    about.type
518    } {
519        set str [$_field get $path]
520        if {"" != $str} {
521            set hints($key) $str
522        }
523    }
524    # Set tool and path hints
525    set hints(tool) [$_xmlobj get tool.name]
526    set hints(path) $_path
527    if 0 {
528        # to be compatible with curve objects
529        set hints(xlabel) "Position"
530    }
531    if {[info exists hints(group)] && [info exists hints(label)]} {
532        # pop-up help for each curve
533        set hints(tooltip) $hints(label)
534    }
535
536    if {$keyword != ""} {
537        if {[info exists hints($keyword)]} {
538            return $hints($keyword)
539        }
540        return ""
541    }
542    return [array get hints]
543}
544
545# ----------------------------------------------------------------------
546# USAGE: _build
547#
548# Used internally to build up the vector representation for the
549# field when the object is first constructed, or whenever the field
550# data changes.  Discards any existing vectors and builds everything
551# from scratch.
552# ----------------------------------------------------------------------
553itcl::body Rappture::Field::_build {} {
554    # discard any existing data
555    foreach name [array names _comp2xy] {
556        eval blt::vector destroy $_comp2xy($name)
557    }
558    foreach name [array names _comp2vtk] {
559        set mobj [lindex $_comp2vtk($name) 0]
560        set class [$mobj info class]
561        ${class}::release $mobj
562
563        set fobj [lindex $_comp2vtk($name) 1]
564        rename $fobj ""
565    }
566    foreach name [array names _comp2unirect2d] {
567        eval itcl::delete object $_comp2unirect2d($name)
568    }
569    foreach name [array names _comp2unirect3d] {
570        eval itcl::delete object $_comp2unirect3d($name)
571    }
572    catch {unset _comp2xy}
573    catch {unset _comp2vtk}
574    catch {unset _comp2dx}
575    catch {unset _comp2dims}
576    catch {unset _comp2style}
577    array unset _comp2vtkstreamlines
578    array unset _comp2unirect2d
579    array unset _comp2unirect3d
580    array unset _comp2extents
581    array unset _dataobj2type
582    #
583    # Scan through the components of the field and create
584    # vectors for each part.
585    #
586    foreach cname [$_field children -type component] {
587        set type ""
588        if { ([$_field element $cname.constant] != "" &&
589            [$_field element $cname.domain] != "") ||
590            [$_field element $cname.xy] != ""} {
591            set type "1D"
592        } elseif {[$_field element $cname.mesh] != "" &&
593            [$_field element $cname.values] != ""} {
594            set type "points-on-mesh"
595        } elseif {[$_field element $cname.vtk] != ""} {
596            if { [$_field get "about.view"] == "streamlines" } {
597                set type "vtkstreamlines"
598            } else {
599                set type "vtk"
600            }
601        } elseif {[$_field element $cname.opendx] != ""} {
602            set type "opendx"
603        } elseif {[$_field element $cname.dx] != ""} {
604            set type "dx"
605        }
606        set _comp2style($cname) ""
607       
608        # Save the extents of the component
609        if { [$_field element $cname.extents] != "" } {
610            set extents [$_field get $cname.extents]
611        } else {
612            set extents 1
613        }
614        set _comp2extents($cname) $extents
615        set _type $type
616        if {$type == "1D"} {
617            #
618            # 1D data can be represented as 2 BLT vectors,
619            # one for x and the other for y.
620            #
621            set xv ""
622            set yv ""
623
624            set val [$_field get $cname.constant]
625            if {$val != ""} {
626                set domain [$_field get $cname.domain]
627                if {$domain == "" || ![info exists _limits($domain)]} {
628                    set z0 0
629                    set z1 $_zmax
630                } else {
631                    foreach {z0 z1} $_limits($domain) { break }
632                }
633                set xv [blt::vector create x$_counter]
634                $xv append $z0 $z1
635
636                foreach {val pcomp} [_getValue $val] break
637                set yv [blt::vector create y$_counter]
638                $yv append $val $val
639
640                if {$pcomp != ""} {
641                    set zm [expr {0.5*($z0+$z1)}]
642                    set _comp2cntls($cname) \
643                        [list $pcomp $zm $val "$val$_units"]
644                }
645            } else {
646                set xydata [$_field get $cname.xy]
647                if {"" != $xydata} {
648                    set xv [blt::vector create x$_counter]
649                    set yv [blt::vector create y$_counter]
650                    set tmp [blt::vector create \#auto]
651                    $tmp set $xydata
652                    $tmp split $xv $yv
653                    blt::vector destroy $tmp
654                }
655            }
656
657            if {$xv != "" && $yv != ""} {
658                # sort x-coords in increasing order
659                $xv sort $yv
660
661                set _comp2dims($cname) "1D"
662                set _comp2xy($cname) [list $xv $yv]
663                incr _counter
664            }
665        } elseif {$type == "points-on-mesh"} {
666            #
667            # More complex 2D/3D data is represented by a mesh
668            # object and an associated vtkFloatArray for field
669            # values.
670            #
671            set path [$_field get $cname.mesh]
672            if {[$_xmlobj element $path] != ""} {
673                set element [$_xmlobj element -as type $path]
674                if { $element == "unirect2d" } {
675                    set _comp2dims($cname) "2D"
676                    set _comp2unirect2d($cname) \
677                        [Rappture::Unirect2d \#auto $_xmlobj $_field $cname \
678                             $extents]
679                    set _comp2style($cname) [$_field get $cname.style]
680                    if {[$_field element $cname.flow] != ""} {
681                        set _comp2flowhints($cname) \
682                            [Rappture::FlowHints ::\#auto $_field $cname $_units]
683                    }
684                    incr _counter
685                } elseif { $element == "unirect3d" } {
686                    set _comp2dims($cname) "3D"
687                    set _comp2unirect3d($cname) \
688                        [Rappture::Unirect3d \#auto $_xmlobj $_field $cname \
689                            $extents]
690                    set _comp2style($cname) [$_field get $cname.style]
691                    if {[$_field element $cname.flow] != ""} {
692                        set _comp2flowhints($cname) \
693                            [Rappture::FlowHints ::\#auto $_field $cname $_units]
694                    }
695                    incr _counter
696                } elseif { $element == "cloud" || $element == "mesh" } {
697                    switch -- $element {
698                        cloud {
699                            set mobj [Rappture::Cloud::fetch $_xmlobj $path]
700                        }
701                        mesh {
702                            set mobj [Rappture::Mesh::fetch $_xmlobj $path]
703                        }
704                    }
705                    if {[$mobj dimensions] > 1} {
706                        #
707                        # 2D/3D data
708                        # Store cloud/field as components
709                        #
710                        set values [$_field get $cname.values]
711                        set farray [vtkFloatArray ::vals$_counter]
712
713                        foreach v $values {
714                            if {"" != $_units} {
715                                set v [Rappture::Units::convert $v \
716                                   -context $_units -to $_units -units off]
717                            }
718                            $farray InsertNextValue $v
719                        }
720
721                        set _comp2dims($cname) "[$mobj dimensions]D"
722                        set _comp2vtk($cname) [list $mobj $farray]
723                        set _comp2style($cname) [$_field get $cname.style]
724                        incr _counter
725                    } else {
726                        #
727                        # OOPS!  This is 1D data
728                        # Forget the cloud/field -- store BLT vectors
729                        #
730                        set xv [blt::vector create x$_counter]
731                        set yv [blt::vector create y$_counter]
732
733                        set vtkpts [$mobj points]
734                        set max [$vtkpts GetNumberOfPoints]
735                        for {set i 0} {$i < $max} {incr i} {
736                            set xval [lindex [$vtkpts GetPoint $i] 0]
737                            $xv append $xval
738                        }
739                        set class [$mobj info class]
740                        ${class}::release $mobj
741
742                        set values [$_field get $cname.values]
743                        foreach yval $values {
744                            if {"" != $_units} {
745                                set yval [Rappture::Units::convert $yval \
746                                      -context $_units -to $_units -units off]
747                            }
748                            $yv append $yval
749                        }
750
751                        # sort x-coords in increasing order
752                        $xv sort $yv
753
754                        set _comp2dims($cname) "1D"
755                        set _comp2xy($cname) [list $xv $yv]
756                        incr _counter
757                    }
758                }
759            } else {
760                puts "WARNING: can't find mesh $path for field component"
761            }
762        } elseif {$type == "vtk"} {
763            #
764            # Extract native vtk data from the XML and use a reader
765            # to load it.
766            #
767            vtkRectilinearGridReader $this-gr
768            $this-gr SetInputString [$_field get $cname.vtk]
769
770
771            set _comp2dims($cname) "[$mobj dimensions]D"
772            set _comp2vtk($cname) [list $mobj $farray]
773            set _comp2style($cname) [$_field get $cname.style]
774            incr _counter
775        } elseif {$type == "vtkstreamlines"} {
776            set _comp2dims($cname) "3D"
777            # Allow redirects to another element.
778            set vtkdata [$_field get $cname.vtk]
779            if { ![string match "!*" $vtkdata] } {
780                set _comp2vtkstreamlines($cname) $vtkdata
781            } else {
782                set path [string range $vtkdata 1 end]
783                if { [$_xmlobj element $path] == "" } {
784                    error "bad redirection path \"$path\""
785                }
786                puts stderr path=$path
787                set element [$_xmlobj element -as type $path]
788                if { $element != "vtk" } {
789                    error "bad path \"$path\": must redirect to a vtk element"
790                }
791                set _comp2vtkstreamlines($cname) [$_xmlobj get $path]
792            }
793            set _comp2style($cname) [$_field get $cname.style]
794            incr _counter
795        } elseif {$type == "vtkstreamlines2"} {
796            set _comp2dims($cname) "3D"
797            set _comp2vtkstreamlines($cname) [$_field get $cname.vtk]
798            set _comp2style($cname) [$_field get $cname.style]
799            incr _counter
800        } elseif {$type == "dx"} {
801            #
802            # HACK ALERT!  Extract gzipped, base64-encoded OpenDX
803            # data.  Assume that it's 3D.  Pass it straight
804            # off to the NanoVis visualizer.
805            #
806            set _comp2dims($cname) "3D"
807            set _comp2dx($cname)  [$_field get -decode no $cname.dx]
808            set _comp2style($cname) [$_field get $cname.style]
809            if {[$_field element $cname.flow] != ""} {
810                set _comp2flowhints($cname) \
811                    [Rappture::FlowHints ::\#auto $_field $cname $_units]
812            }
813            incr _counter
814        } elseif {$type == "opendx"} {
815            #
816            # HACK ALERT!  Extract gzipped, base64-encoded OpenDX
817            # data.  Assume that it's 3D.  Pass it straight
818            # off to the NanoVis visualizer.
819            #
820            set _comp2dims($cname) "3D"
821            set data [$_field get -decode yes $cname.opendx]
822            set data "<ODX>$data"
823            set data [Rappture::encoding::encode -as zb64 $data]
824            set _comp2dx($cname) $data
825            set _comp2style($cname) [$_field get $cname.style]
826            if {[$_field element $cname.flow] != ""} {
827                set _comp2flowhints($cname) \
828                    [Rapture::FlowHints ::\#auto $_field $cname $_units]
829            }
830            incr _counter
831        }
832    }
833}
834
835# ----------------------------------------------------------------------
836# USAGE: _getValue <expr>
837#
838# Used internally to get the value for an expression <expr>.  Returns
839# a list of the form {val parameterPath}, where val is the numeric
840# value of the expression, and parameterPath is the XML path to the
841# parameter representing the value, or "" if the <expr> does not
842# depend on any parameters.
843# ----------------------------------------------------------------------
844itcl::body Rappture::Field::_getValue {expr} {
845    #
846    # First, look for the expression among the <parameter>'s
847    # associated with the device.
848    #
849    set found 0
850    foreach pcomp [$_xmlobj children parameters] {
851        set id [$_xmlobj element -as id parameters.$pcomp]
852        if {[string equal $id $expr]} {
853            set val [$_xmlobj get parameters.$pcomp.current]
854            if {"" == $val} {
855                set val [$_xmlobj get parameters.$pcomp.default]
856            }
857            if {"" != $val} {
858                set expr $val
859                set found 1
860                break
861            }
862        }
863    }
864    if {$found} {
865        set pcomp "parameters.$pcomp"
866    } else {
867        set pcomp ""
868    }
869
870    if {$_units != ""} {
871        set expr [Rappture::Units::convert $expr \
872            -context $_units -to $_units -units off]
873    }
874
875    return [list $expr $pcomp]
876}
877
878#
879# isunirect2d  --
880#
881# Returns if the field is a unirect2d object. 
882#
883itcl::body Rappture::Field::isunirect2d { } {
884    return [expr [array size _comp2unirect2d] > 0]
885}
886
887#
888# isunirect3d  --
889#
890# Returns if the field is a unirect3d object. 
891#
892itcl::body Rappture::Field::isunirect3d { } {
893    return [expr [array size _comp2unirect3d] > 0]
894}
895
896#
897# flowhints  --
898#
899# Returns the hints associated with a flow vector field. 
900#
901itcl::body Rappture::Field::flowhints { cname } {
902    if { [info exists _comp2flowhints($cname)] } {
903        return $_comp2flowhints($cname)
904    }
905    return ""
906}
907
908#
909# style  --
910#
911# Returns the style associated with a component of the field. 
912#
913itcl::body Rappture::Field::style { cname } {
914    if { [info exists _comp2style($cname)] } {
915        return $_comp2style($cname)
916    }
917    return ""
918}
919
920#
921# type  --
922#
923# Returns the style associated with a component of the field. 
924#
925itcl::body Rappture::Field::type {} {
926    return $_type
927}
928
929#
930# extents --
931#
932# Returns if the field is a unirect2d object. 
933#
934itcl::body Rappture::Field::extents {{what -overall}} {
935    if {$what == "-overall" } {
936        set max 0
937        foreach cname [$_field children -type component] {
938            if { ![info exists _comp2unirect3d($cname)] &&
939                 ![info exists _comp2extents($cname)] } {
940                continue
941            }
942            set value $_comp2extents($cname)
943            if { $max < $value } {
944                set max $value
945            }
946        }
947        return $max
948    }
949    if { $what == "component0"} {
950        set what [lindex [components -name] 0]
951    }
952    return $_comp2extents($what)
953}
Note: See TracBrowser for help on using the repository browser.