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

Last change on this file since 2727 was 2727, checked in by gah, 12 years ago
File size: 36.2 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 _comp2vtkstreamlines
590    array unset _comp2unirect2d
591    array unset _comp2unirect3d
592    array unset _comp2extents
593    array unset _dataobj2type
594    #
595    # Scan through the components of the field and create
596    # vectors for each part.
597    #
598    foreach cname [$_field children -type component] {
599        set type ""
600        if { ([$_field element $cname.constant] != "" &&
601            [$_field element $cname.domain] != "") ||
602            [$_field element $cname.xy] != ""} {
603            set type "1D"
604        } elseif {[$_field element $cname.mesh] != "" &&
605            [$_field element $cname.values] != ""} {
606            set type "points-on-mesh"
607        } elseif {[$_field element $cname.vtk] != ""} {
608            if { [$_field get "about.view"] == "streamlines" } {
609                set type "vtkstreamlines"
610            } else {
611                set type "vtk"
612            }
613        } elseif {[$_field element $cname.opendx] != ""} {
614            global env
615            if { [info exists env(VTKVOLUME)] } {
616                set type "vtkvolume"
617            } else {
618                set type "dx"
619            }
620        } elseif {[$_field element $cname.dx] != ""} {
621            global env
622            if { [info exists env(VTKVOLUME)] } {
623                set type "vtkvolume"
624            } else {
625                set type "dx"
626            }
627        }
628        set _comp2style($cname) ""
629       
630        # Save the extents of the component
631        if { [$_field element $cname.extents] != "" } {
632            set extents [$_field get $cname.extents]
633        } else {
634            set extents 1
635        }
636        set _comp2extents($cname) $extents
637        set _type $type
638        if {$type == "1D"} {
639            #
640            # 1D data can be represented as 2 BLT vectors,
641            # one for x and the other for y.
642            #
643            set xv ""
644            set yv ""
645
646            set val [$_field get $cname.constant]
647            if {$val != ""} {
648                set domain [$_field get $cname.domain]
649                if {$domain == "" || ![info exists _limits($domain)]} {
650                    set z0 0
651                    set z1 $_zmax
652                } else {
653                    foreach {z0 z1} $_limits($domain) { break }
654                }
655                set xv [blt::vector create x$_counter]
656                $xv append $z0 $z1
657
658                foreach {val pcomp} [_getValue $val] break
659                set yv [blt::vector create y$_counter]
660                $yv append $val $val
661
662                if {$pcomp != ""} {
663                    set zm [expr {0.5*($z0+$z1)}]
664                    set _comp2cntls($cname) \
665                        [list $pcomp $zm $val "$val$_units"]
666                }
667            } else {
668                set xydata [$_field get $cname.xy]
669                if {"" != $xydata} {
670                    set xv [blt::vector create x$_counter]
671                    set yv [blt::vector create y$_counter]
672                    set tmp [blt::vector create \#auto]
673                    $tmp set $xydata
674                    $tmp split $xv $yv
675                    blt::vector destroy $tmp
676                }
677            }
678
679            if {$xv != "" && $yv != ""} {
680                # sort x-coords in increasing order
681                $xv sort $yv
682
683                set _comp2dims($cname) "1D"
684                set _comp2xy($cname) [list $xv $yv]
685                incr _counter
686            }
687        } elseif {$type == "points-on-mesh"} {
688            #
689            # More complex 2D/3D data is represented by a mesh
690            # object and an associated vtkFloatArray for field
691            # values.
692            #
693            set path [$_field get $cname.mesh]
694            if {[$_xmlobj element $path] != ""} {
695                set element [$_xmlobj element -as type $path]
696                if { $element == "unirect2d" } {
697                    set _comp2dims($cname) "2D"
698                    set _comp2unirect2d($cname) \
699                        [Rappture::Unirect2d \#auto $_xmlobj $_field $cname \
700                             $extents]
701                    set _comp2style($cname) [$_field get $cname.style]
702                    if {[$_field element $cname.flow] != ""} {
703                        set _comp2flowhints($cname) \
704                            [Rappture::FlowHints ::\#auto $_field $cname $_units]
705                    }
706                    incr _counter
707                } elseif { $element == "unirect3d" } {
708                    set _comp2dims($cname) "3D"
709                    set _comp2unirect3d($cname) \
710                        [Rappture::Unirect3d \#auto $_xmlobj $_field $cname \
711                            $extents]
712                    set _comp2style($cname) [$_field get $cname.style]
713                    if {[$_field element $cname.flow] != ""} {
714                        set _comp2flowhints($cname) \
715                            [Rappture::FlowHints ::\#auto $_field $cname $_units]
716                    }
717                    incr _counter
718                } elseif { $element == "cloud" || $element == "mesh" } {
719                    switch -- $element {
720                        cloud {
721                            set mobj [Rappture::Cloud::fetch $_xmlobj $path]
722                        }
723                        mesh {
724                            set mobj [Rappture::Mesh::fetch $_xmlobj $path]
725                        }
726                    }
727                    if {[$mobj dimensions] > 1} {
728                        #
729                        # 2D/3D data
730                        # Store cloud/field as components
731                        #
732                        set values [$_field get $cname.values]
733                        set farray [vtkFloatArray ::vals$_counter]
734
735                        foreach v $values {
736                            if {"" != $_units} {
737                                set v [Rappture::Units::convert $v \
738                                   -context $_units -to $_units -units off]
739                            }
740                            $farray InsertNextValue $v
741                        }
742
743                        set _comp2dims($cname) "[$mobj dimensions]D"
744                        set _comp2vtk($cname) [list $mobj $farray]
745                        set _comp2style($cname) [$_field get $cname.style]
746                        incr _counter
747                    } else {
748                        #
749                        # OOPS!  This is 1D data
750                        # Forget the cloud/field -- store BLT vectors
751                        #
752                        set xv [blt::vector create x$_counter]
753                        set yv [blt::vector create y$_counter]
754
755                        set vtkpts [$mobj points]
756                        set max [$vtkpts GetNumberOfPoints]
757                        for {set i 0} {$i < $max} {incr i} {
758                            set xval [lindex [$vtkpts GetPoint $i] 0]
759                            $xv append $xval
760                        }
761                        set class [$mobj info class]
762                        ${class}::release $mobj
763
764                        set values [$_field get $cname.values]
765                        foreach yval $values {
766                            if {"" != $_units} {
767                                set yval [Rappture::Units::convert $yval \
768                                      -context $_units -to $_units -units off]
769                            }
770                            $yv append $yval
771                        }
772
773                        # sort x-coords in increasing order
774                        $xv sort $yv
775
776                        set _comp2dims($cname) "1D"
777                        set _comp2xy($cname) [list $xv $yv]
778                        incr _counter
779                    }
780                }
781            } else {
782                puts "WARNING: can't find mesh $path for field component"
783            }
784        } elseif {$type == "vtk"} {
785            #
786            # Extract native vtk data from the XML and use a reader
787            # to load it.
788            #
789            vtkRectilinearGridReader $this-gr
790            $this-gr SetInputString [$_field get $cname.vtk]
791
792
793            set _comp2dims($cname) "[$mobj dimensions]D"
794            set _comp2vtk($cname) [list $mobj $farray]
795            set _comp2style($cname) [$_field get $cname.style]
796            incr _counter
797        } elseif {$type == "vtkstreamlines"} {
798            set _comp2dims($cname) "3D"
799            # Allow redirects to another element.
800            set vtkdata [$_field get $cname.vtk]
801            if { ![string match "!*" $vtkdata] } {
802                set _comp2vtkstreamlines($cname) $vtkdata
803            } else {
804                set path [string range $vtkdata 1 end]
805                if { [$_xmlobj element $path] == "" } {
806                    error "bad redirection path \"$path\""
807                }
808                puts stderr path=$path
809                set element [$_xmlobj element -as type $path]
810                if { $element != "vtk" } {
811                    error "bad path \"$path\": must redirect to a vtk element"
812                }
813                set _comp2vtkstreamlines($cname) [$_xmlobj get $path]
814            }
815            set _comp2style($cname) [$_field get $cname.style]
816            incr _counter
817        } elseif {$type == "vtkvolume"} {
818            set _comp2dims($cname) "3D"
819            # Allow redirects to another element.
820            set data [$_field get -decode no $cname.dx]
821            set data [Rappture::encoding::decode -as zb64 $data]
822            if 1 {
823            set file "/tmp/junk.dx"
824            set f [open $file "w"]
825            puts $f $data
826            close $f
827            }
828            set data [Rappture::ConvertDxToVtk $data]
829            if 1 {
830            set file "/tmp/junk.vtk"
831            set f [open $file "w"]
832            puts $f $data
833            close $f
834            }
835            set _comp2vtkvolume($cname) $data
836            set _comp2style($cname) [$_field get $cname.style]
837            incr _counter
838        } elseif {$type == "vtkstreamlines2"} {
839            set _comp2dims($cname) "3D"
840            set _comp2vtkstreamlines($cname) [$_field get $cname.vtk]
841            set _comp2style($cname) [$_field get $cname.style]
842            incr _counter
843        } elseif {$type == "dx" } {
844            #
845            # HACK ALERT!  Extract gzipped, base64-encoded OpenDX
846            # data.  Assume that it's 3D.  Pass it straight
847            # off to the NanoVis visualizer.
848            #
849            set _comp2dims($cname) "3D"
850            set _comp2dx($cname)  [$_field get -decode no $cname.dx]
851            if 1 {
852            set data  [$_field get -decode yes $cname.dx]
853            set file "/tmp/junk.dx"
854            set f [open $file "w"]
855            puts $f $data
856            close $f
857            if { [string match "<ODX>*" $data] } {
858                set data [string range $data 5 end]
859                set _comp2dx($cname) \
860                        [Rappture::encoding::encode -as zb64 $data]
861            }
862            }
863            set _comp2style($cname) [$_field get $cname.style]
864            if {[$_field element $cname.flow] != ""} {
865                set _comp2flowhints($cname) \
866                    [Rappture::FlowHints ::\#auto $_field $cname $_units]
867            }
868            incr _counter
869        } elseif {$type == "opendx"} {
870            #
871            # HACK ALERT!  Extract gzipped, base64-encoded OpenDX
872            # data.  Assume that it's 3D.  Pass it straight
873            # off to the NanoVis visualizer.
874            #
875            set _comp2dims($cname) "3D"
876            set data [$_field get -decode yes $cname.opendx]
877            set data "<ODX>$data"
878            set data [Rappture::encoding::encode -as zb64 $data]
879            set _comp2dx($cname) $data
880            set _comp2style($cname) [$_field get $cname.style]
881            if {[$_field element $cname.flow] != ""} {
882                set _comp2flowhints($cname) \
883                    [Rapture::FlowHints ::\#auto $_field $cname $_units]
884            }
885            incr _counter
886        }
887    }
888}
889
890# ----------------------------------------------------------------------
891# USAGE: _getValue <expr>
892#
893# Used internally to get the value for an expression <expr>.  Returns
894# a list of the form {val parameterPath}, where val is the numeric
895# value of the expression, and parameterPath is the XML path to the
896# parameter representing the value, or "" if the <expr> does not
897# depend on any parameters.
898# ----------------------------------------------------------------------
899itcl::body Rappture::Field::_getValue {expr} {
900    #
901    # First, look for the expression among the <parameter>'s
902    # associated with the device.
903    #
904    set found 0
905    foreach pcomp [$_xmlobj children parameters] {
906        set id [$_xmlobj element -as id parameters.$pcomp]
907        if {[string equal $id $expr]} {
908            set val [$_xmlobj get parameters.$pcomp.current]
909            if {"" == $val} {
910                set val [$_xmlobj get parameters.$pcomp.default]
911            }
912            if {"" != $val} {
913                set expr $val
914                set found 1
915                break
916            }
917        }
918    }
919    if {$found} {
920        set pcomp "parameters.$pcomp"
921    } else {
922        set pcomp ""
923    }
924
925    if {$_units != ""} {
926        set expr [Rappture::Units::convert $expr \
927            -context $_units -to $_units -units off]
928    }
929
930    return [list $expr $pcomp]
931}
932
933#
934# isunirect2d  --
935#
936# Returns if the field is a unirect2d object. 
937#
938itcl::body Rappture::Field::isunirect2d { } {
939    return [expr [array size _comp2unirect2d] > 0]
940}
941
942#
943# isunirect3d  --
944#
945# Returns if the field is a unirect3d object. 
946#
947itcl::body Rappture::Field::isunirect3d { } {
948    return [expr [array size _comp2unirect3d] > 0]
949}
950
951#
952# flowhints  --
953#
954# Returns the hints associated with a flow vector field. 
955#
956itcl::body Rappture::Field::flowhints { cname } {
957    if { [info exists _comp2flowhints($cname)] } {
958        return $_comp2flowhints($cname)
959    }
960    return ""
961}
962
963#
964# style  --
965#
966# Returns the style associated with a component of the field. 
967#
968itcl::body Rappture::Field::style { cname } {
969    if { [info exists _comp2style($cname)] } {
970        return $_comp2style($cname)
971    }
972    return ""
973}
974
975#
976# type  --
977#
978# Returns the style associated with a component of the field. 
979#
980itcl::body Rappture::Field::type {} {
981    return $_type
982}
983
984#
985# extents --
986#
987# Returns if the field is a unirect2d object. 
988#
989itcl::body Rappture::Field::extents {{what -overall}} {
990    if {$what == "-overall" } {
991        set max 0
992        foreach cname [$_field children -type component] {
993            if { ![info exists _comp2unirect3d($cname)] &&
994                 ![info exists _comp2extents($cname)] } {
995                continue
996            }
997            set value $_comp2extents($cname)
998            if { $max < $value } {
999                set max $value
1000            }
1001        }
1002        return $max
1003    }
1004    if { $what == "component0"} {
1005        set what [lindex [components -name] 0]
1006    }
1007    return $_comp2extents($what)
1008}
1009
1010# ----------------------------------------------------------------------
1011# USAGE: blob ?<name>?
1012#
1013# Returns a string representing the blob of data for the mesh and values.
1014# ----------------------------------------------------------------------
1015itcl::body Rappture::Field::vtkdata {{what -overall}} {
1016    if {$what == "component0"} {
1017        set what "component"
1018    }
1019    if {[info exists _comp2xy($what)]} {
1020        return ""
1021    }
1022    if { [info exists _comp2vtk($what)] } {
1023        return ""
1024    }
1025    if { [info exists _comp2vtkstreamlines($what)] } {
1026        # Return the contents of the vtk file.
1027        return $_comp2vtkstreamlines($what)
1028    }
1029    if { [info exists _comp2vtkvolume($what)] } {
1030        # Return the contents of the vtk file.
1031        return $_comp2vtkvolume($what)
1032    }
1033    if {[info exists _comp2dx($what)]} {
1034        return $_comp2dx($what)
1035    }
1036    if {[info exists _comp2unirect2d($what)]} {
1037        return [$_comp2unirect2d($what) blob]
1038    }
1039    if {[info exists _comp2unirect3d($what)]} {
1040        return [$_comp2unirect3d($what) blob]
1041    }
1042    error "bad option \"$what\": should be [join [lsort [array names _comp2dims]] {, }]"
1043}
Note: See TracBrowser for help on using the repository browser.