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

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