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

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