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

Last change on this file since 3582 was 3581, checked in by gah, 11 years ago

fix regression: was not comparing pattern when compiling list of matching components

File size: 47.9 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2
3# ----------------------------------------------------------------------
4#  COMPONENT: field - extracts data from an XML description of a field
5#
6#  This object represents one field in an XML description of a device.
7#  It simplifies the process of extracting data vectors that represent
8#  the field.
9# ======================================================================
10#  AUTHOR:  Michael McLennan, Purdue University
11#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
12#
13#  See the file "license.terms" for information on usage and
14#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15# ======================================================================
16
17# TODO:
18#
19#  o How to describe vector values in a field? 
20#       <components>3</components>
21#       <values></values>
22#
23#    Does anything need to know the limits for each component of the vector?
24#
25
26#
27# Possible field dataset types:
28#
29# 2D Datasets
30#       vtk             (range of z-axis is zero).
31#       unirect2d       (deprecated except where extents > 1)
32#       cloud           (x,y point coordinates) (deprecated)
33#       mesh
34# 3D Datasets
35#       vtk
36#       unirect3d
37#       cloud           (x,y,z coordinates) (deprecated)
38#       mesh
39#       dx              (FIXME: make dx-to-vtk converter work)
40#       ucd avs
41#
42# Viewers:
43#       Format     Dim  Description                     Viewer          Server
44#       vtk         2   vtk file data.                  contour         vtkvis
45#       vtk         3   vtk file data.                  isosurface      vtkvis
46#       mesh        2   points-on-mesh                  heightmap       vtkvis
47#       mesh        3   points-on-mesh                  isosurface      vtkvis
48#       dx          3   DX                              volume          nanovis
49#       unirect2d   2   unirect3d + extents > 1 flow    flow            nanovis
50#       unirect3d   3   unirect2d + extents > 1 flow    flow            nanovis
51#       
52# With <views>, can specify which viewer for a specific datasets.  So it's OK
53# to if the same dataset can be viewed in more than one way.
54#  o Any 2D dataset can be viewed as a contour/heightmap.
55#  o Any 3D dataset can be viewed as a isosurface. 
56#  o Any 2D dataset with vector data can be streamlines. 
57#  o Any 3D uniform rectilinear dataset can be viewed as a volume.
58#  o Any 3D dataset with vector data can be streamlines or flow.
59#
60# Need <views> to properly do things like qdot: volume with a polydata
61# transparent shell.  The view will combine the two objects <field> and
62# <drawing> (??) into a single viewer.
63#
64package require Itcl
65package require BLT
66
67namespace eval Rappture {
68    # forward declaration
69}
70
71itcl::class Rappture::Field {
72    private variable _dim 0;            # Dimension of the mesh
73    private variable _xmlobj "";        # ref to XML obj with field data
74    private variable _limits;           # maps axis name => {z0 z1} limits
75    private variable _field ""
76    private variable _comp2fldName ;    # cname => field names.
77    private variable _fld2Components;   # field name => number of components
78    private variable _fld2Label;        # field name => label
79    private variable _fld2Units;        # field name => units
80    private variable _hints
81    private variable _viewer "";        # Hints which viewer to use
82    private variable _xv "";            # For 1D meshes only.  Holds the points
83    private variable _isValid 0;        # Indicates if the field contains
84                                        # valid data.
85    private variable _isValidComponent
86    constructor {xmlobj path} {
87        # defined below
88    }
89    destructor {
90        # defined below
91    }
92    public method blob { cname }
93    public method components {args}
94    public method controls {option args}
95    public method extents {{cname -overall}}
96    public method fieldlimits {}
97    public method flowhints { cname }
98    public method hints {{key ""}}
99    public method isunirect2d {}
100    public method isunirect3d {}
101    public method limits {axis}
102    public method mesh {{cname -overall}}
103    public method style { cname }
104    public method type {}
105    public method values { cname }
106    public method vtkdata {cname}
107
108    public method fieldnames { cname } {
109        if { ![info exists _comp2fldName($cname)] } {
110            return ""
111        }
112        return $_comp2fldName($cname)
113    }
114    public method fieldinfo { fname } {
115        lappend out $_fld2Label($fname)
116        lappend out $_fld2Units($fname)
117        lappend out $_fld2Components($fname)
118        return $out
119    }
120    public method isvalid {} {
121        return $_isValid
122    }
123    public method viewer {} {
124        return $_viewer
125    }
126
127    protected method Build {}
128    protected method _getValue {expr}
129
130    private variable _path "";          # Path of this object in the XML
131    private variable _units ""   ;      # system of units for this field
132    private variable _zmax 0     ;# length of the device
133
134    private variable _comp2dims  ;# maps component name => dimensionality
135    private variable _comp2xy    ;# maps component name => x,y vectors
136    private variable _comp2vtk   ;# maps component name => vtk file data
137    private variable _comp2dx    ;# maps component name => OpenDX data
138    private variable _comp2unirect2d ;# maps component name => unirect2d obj
139    private variable _comp2unirect3d ;# maps component name => unirect3d obj
140    private variable _comp2style ;# maps component name => style settings
141    private variable _comp2cntls ;# maps component name => x,y control points
142    private variable _comp2extents
143    private variable _comp2limits;      #  Array of limits per component
144    private variable _type ""
145    private variable _comp2flowhints
146    private variable _comp2mesh
147    private common _counter 0    ;# counter for unique vector names
148
149    private method BuildPointsOnMesh { cname }
150    private method ConvertToVtkData { cname }
151    private method ReadVtkDataSet { cname contents }
152    private method AvsToVtk { cname contents }
153    private variable _values ""
154}
155
156# ----------------------------------------------------------------------
157# CONSTRUCTOR
158# ----------------------------------------------------------------------
159itcl::body Rappture::Field::constructor {xmlobj path} {
160    package require vtk
161    if {![Rappture::library isvalid $xmlobj]} {
162        error "bad value \"$xmlobj\": should be Rappture::library"
163    }
164    set _xmlobj $xmlobj
165    set _path $path
166    set _field [$xmlobj element -as object $path]
167    set _units [$_field get units]
168
169    set xunits [$xmlobj get units]
170    if {"" == $xunits || "arbitrary" == $xunits} {
171        set xunits "um"
172    }
173
174    # determine the overall size of the device
175    set z0 [set z1 0]
176    foreach elem [$_xmlobj children components] {
177        switch -glob -- $elem {
178            box* {
179                if {![regexp {[0-9]$} $elem]} {
180                    set elem "${elem}0"
181                }
182                set z0 [$_xmlobj get components.$elem.corner0]
183                set z0 [Rappture::Units::convert $z0 \
184                    -context $xunits -to $xunits -units off]
185
186                set z1 [$_xmlobj get components.$elem.corner1]
187                set z1 [Rappture::Units::convert $z1 \
188                    -context $xunits -to $xunits -units off]
189
190                set _limits($elem) [list $z0 $z1]
191            }
192        }
193    }
194    set _zmax $z1
195
196    # build up vectors for various components of the field
197    Build
198}
199
200# ----------------------------------------------------------------------
201# DESTRUCTOR
202# ----------------------------------------------------------------------
203itcl::body Rappture::Field::destructor {} {
204    itcl::delete object $_field
205    # don't destroy the _xmlobj! we don't own it!
206
207    foreach name [array names _comp2xy] {
208        eval blt::vector destroy $_comp2xy($name)
209    }
210    foreach name [array names _comp2unirect2d] {
211        itcl::delete object $_comp2unirect2d($name)
212    }
213    foreach name [array names _comp2unirect3d] {
214        itcl::delete object $_comp2unirect3d($name)
215    }
216    foreach name [array names _comp2flowhints] {
217        itcl::delete object $_comp2flowhints($name)
218    }
219    foreach name [array names _comp2mesh] {
220        # Data is in the form of a mesh and a vector.
221        foreach { mesh vector } $_comp2mesh($name) break
222        # Release the mesh (may be shared)
223        set class [$mesh info class]
224        ${class}::release $mesh
225        # Destroy the vector
226        blt::vector destroy $vector
227    }
228}
229
230# ----------------------------------------------------------------------
231# USAGE: components ?-name|-dimensions|-style? ?<pattern>?
232#
233# Returns a list of names or types for the various components of
234# this field.  If the optional glob-style <pattern> is specified,
235# then it returns only the components with names matching the pattern.
236# ----------------------------------------------------------------------
237itcl::body Rappture::Field::components {args} {
238    Rappture::getopts args params {
239        flag what -name default
240        flag what -dimensions
241        flag what -style
242        flag what -particles
243        flag what -flow
244        flag what -box
245    }
246
247    set pattern *
248    if {[llength $args] > 0} {
249        set pattern [lindex $args 0]
250        set args [lrange $args 1 end]
251    }
252    if {[llength $args] > 0} {
253        error "wrong # args: should be \"components ?switches? ?pattern?\""
254    }
255
256    # There's only one dimension of the field.  Components can't have
257    # different dimensions in the same field.  They would by definition be
258    # using different meshes and viewers.
259    if { $params(what) == "-dimensions" } {
260        return "${_dim}D"
261    }
262    # BE CAREFUL: return component names in proper order
263    set rlist ""
264    set components {}
265    # First compile a list of valid components that match the pattern
266    foreach cname [$_field children -type component] {
267        if { ![info exists _isValidComponent($cname)] } {
268            continue
269        }
270        if { [string match $pattern $cname] } {
271            lappend components $cname
272        }
273    }
274    # Now handle the tests.
275    switch -- $params(what) {
276        -name {
277            set rlist $components
278        }
279        -style {
280            foreach cname $components {
281                if { [info exists _comp2style($cname)] } {
282                    lappend rlist $_comp2style($cname)
283                }
284            }
285        }
286    }
287    return $rlist
288}
289
290# ----------------------------------------------------------------------
291# USAGE: mesh ?<name>?
292#
293# Returns a list {xvec yvec} for the specified field component <name>.
294# If the name is not specified, then it returns the vectors for the
295# overall field (sum of all components).
296# ----------------------------------------------------------------------
297itcl::body Rappture::Field::mesh {{cname -overall}} {
298    if {$cname == "-overall" || $cname == "component0"} {
299        set cname [lindex [components -name] 0]
300    }
301    if {[info exists _comp2xy($cname)]} {
302        return [lindex $_comp2xy($cname) 0]  ;# return xv
303    }
304    if { [info exists _comp2vtk($cname)] } {
305        # FIXME: extract mesh from VTK file data.
306        if { $_comp2dims($cname) == "1D" } {
307            return $_xv
308        }
309        error "method \"mesh\" is not implemented for VTK file data"
310    }
311    if {[info exists _comp2dx($cname)]} {
312        return ""  ;# no mesh -- it's embedded in the value data
313    }
314    if {[info exists _comp2mesh($cname)]} {
315        return ""  ;# no mesh -- it's embedded in the value data
316    }
317    if {[info exists _comp2unirect2d($cname)]} {
318        set mobj [lindex $_comp2unirect2d($cname) 0]
319        return [$mobj mesh]
320    }
321    if {[info exists _comp2unirect3d($cname)]} {
322        set mobj [lindex $_comp2unirect3d($cname) 0]
323        return [$mobj mesh]
324    }
325    error "can't get field mesh: Unknown component \"$cname\": should be one of [join [lsort [array names _comp2dims]] {, }]"
326}
327
328# ----------------------------------------------------------------------
329# USAGE: values ?<name>?
330#
331# Returns a list {xvec yvec} for the specified field component <name>.
332# If the name is not specified, then it returns the vectors for the
333# overall field (sum of all components).
334# ----------------------------------------------------------------------
335itcl::body Rappture::Field::values {cname} {
336    if {$cname == "component0"} {
337        set cname "component"
338    }
339    if {[info exists _comp2xy($cname)]} {
340        return [lindex $_comp2xy($cname) 1]  ;# return yv
341    }
342    # VTK file data
343    if { [info exists _comp2vtk($cname)] } {
344        # FIXME: extract the values from the VTK file data
345        if { $_comp2dims($cname) == "1D" } {
346            return $_values
347        }
348        error "method \"values\" is not implemented for vtk file data"
349    }
350    # Points-on-mesh
351    if { [info exists _comp2mesh($cname)] } {
352        set vector [lindex $_comp2mesh($cname) 1]
353        return [$vector range 0 end]
354    }
355    if {[info exists _comp2dx($cname)]} {
356        return $_comp2dx($cname)  ;# return gzipped, base64-encoded DX data
357    }
358    if {[info exists _comp2unirect2d($cname)]} {
359        return [$_comp2unirect2d($cname) values]
360    }
361    if {[info exists _comp2unirect3d($cname)]} {
362        return [$_comp2unirect3d($cname) blob]
363    }
364    error "can't get field values. Unknown component \"$cname\": should be [join [lsort [array names _comp2dims]] {, }]"
365}
366
367# ----------------------------------------------------------------------
368# USAGE: blob ?<name>?
369#
370# Returns a string representing the blob of data for the mesh and values.
371# ----------------------------------------------------------------------
372itcl::body Rappture::Field::blob {cname} {
373    if {$cname == "component0"} {
374        set cname "component"
375    }
376    if {[info exists _comp2xy($cname)]} {
377        return ""
378    }
379    if { [info exists _comp2vtk($cname)] } {
380        error "blob not implemented for VTK file data"
381    }
382    if {[info exists _comp2dx($cname)]} {
383        return $_comp2dx($cname)  ;# return gzipped, base64-encoded DX data
384    }
385    if {[info exists _comp2unirect2d($cname)]} {
386        set blob [$_comp2unirect2d($cname) blob]
387        lappend blob "values" $_values
388        return $blob
389    }
390    if {[info exists _comp2unirect3d($cname)]} {
391        return [$_comp2unirect3d($cname) blob]
392    }
393    error "can't get field blob: Unknown component \"$cname\": should be one of [join [lsort [array names _comp2dims]] {, }]"
394}
395
396# ----------------------------------------------------------------------
397# USAGE: limits <axis>
398#
399# Returns a list {min max} representing the limits for the specified
400# axis.
401# ----------------------------------------------------------------------
402itcl::body Rappture::Field::limits {which} {
403    set min ""
404    set max ""
405    blt::vector tmp zero
406
407    foreach cname [array names _comp2dims] {
408        switch -- $_comp2dims($cname) {
409            1D {
410                switch -- $which {
411                    x - xlin {
412                        set pos 0; set log 0; set axis x
413                    }
414                    xlog {
415                        set pos 0; set log 1; set axis x
416                    }
417                    y - ylin - v - vlin {
418                        set pos 1; set log 0; set axis y
419                    }
420                    ylog - vlog {
421                        set pos 1; set log 1; set axis y
422                    }
423                    default {
424                        error "bad axis \"$which\": should be x, xlin, xlog, y, ylin, ylog, v, vlin, vlog"
425                    }
426                }
427
428                set vname [lindex $_comp2xy($cname) $pos]
429                $vname variable vec
430
431                if {$log} {
432                    # on a log scale, use abs value and ignore 0's
433                    $vname dup tmp
434                    $vname dup zero
435                    zero expr {tmp == 0}            ;# find the 0's
436                    tmp expr {abs(tmp)}             ;# get the abs value
437                    tmp expr {tmp + zero*max(tmp)}  ;# replace 0's with abs max
438                    set axisMin [blt::vector expr min(tmp)]
439                    set axisMax [blt::vector expr max(tmp)]
440                } else {
441                    set axisMin $vec(min)
442                    set axisMax $vec(max)
443                }
444
445                if {"" == $min} {
446                    set min $axisMin
447                } elseif {$axisMin < $min} {
448                    set min $axisMin
449                }
450                if {"" == $max} {
451                    set max $axisMax
452                } elseif {$axisMax > $max} {
453                    set max $axisMax
454                }
455            }
456            2D - 3D {
457                if {[info exists _comp2unirect3d($cname)]} {
458                    set limits [$_comp2unirect3d($cname) limits $which]
459                    foreach {axisMin axisMax} $limits break
460                    set axis v
461                } elseif {[info exists _comp2limits($cname)]} {
462                    array set limits $_comp2limits($cname)
463                    switch -- $which {
464                        x - xlin - xlog {
465                            set axis x
466                            foreach {axisMin axisMax} $limits(x) break
467                        }
468                        y - ylin - ylog {
469                            set axis y
470                            foreach {axisMin axisMax} $limits(y) break
471                        }
472                        z - zlin - zlog {
473                            set axis z
474                            foreach {axisMin axisMax} $limits(z) break
475                        }
476                        v - vlin - vlog {
477                            set axis v
478                            foreach {axisMin axisMax} $limits(v) break
479                        }
480                        default {
481                            if { ![info exists limits($which)] } {
482                                error "limits: unknown axis \"$which\""
483                            }
484                            set axis v
485                            foreach {axisMin axisMax} $limits($which) break
486                        }
487                    }
488                } else {
489                    set axisMin 0  ;# HACK ALERT! must be OpenDX data
490                    set axisMax 1
491                    set axis v
492                }
493            }
494        }
495        if { "" == $min || $axisMin < $min } {
496            set min $axisMin
497        }
498        if { "" == $max || $axisMax > $max } {
499            set max $axisMax
500        }
501    }
502    blt::vector destroy tmp zero
503    set val [$_field get "${axis}axis.min"]
504    if {"" != $val && "" != $min} {
505        if {$val > $min} {
506            # tool specified this min -- don't go any lower
507            set min $val
508        }
509    }
510    set val [$_field get "${axis}axis.max"]
511    if {"" != $val && "" != $max} {
512        if {$val < $max} {
513            # tool specified this max -- don't go any higher
514            set max $val
515        }
516    }
517    return [list $min $max]
518}
519
520
521# ----------------------------------------------------------------------
522# USAGE: fieldlimits
523#
524# Returns a list {min max} representing the limits for the specified
525# axis.
526# ----------------------------------------------------------------------
527itcl::body Rappture::Field::fieldlimits {} {
528    foreach cname [array names _comp2limits] {
529        array set limits $_comp2limits($cname)
530        foreach fname $_comp2fldName($cname) {
531            if { ![info exists limits($fname)] } {
532                puts stderr "ERROR: field \"$fname\" unknown in \"$cname\""
533                continue
534            }
535            foreach {min max} $limits($fname) break
536            if { ![info exists overall($fname)] } {
537                set overall($fname) $limits($fname)
538                continue
539            }
540            foreach {omin omax} $overall($fname) break
541            if { $min < $omin } {
542                set omin $min
543            }
544            if { $max > $omax } {
545                set omax $max
546            }
547            set overall($fname) [list $min $max]
548        }
549    }
550    if { [info exists overall] } {
551        return [array get overall]
552    }
553    return ""
554}
555 
556# ----------------------------------------------------------------------
557# USAGE: controls get ?<name>?
558# USAGE: controls validate <path> <value>
559# USAGE: controls put <path> <value>
560#
561# Returns a list {path1 x1 y1 val1  path2 x2 y2 val2 ...} representing
562# control points for the specified field component <name>.
563# ----------------------------------------------------------------------
564itcl::body Rappture::Field::controls {option args} {
565    switch -- $option {
566        get {
567            set cname [lindex $args 0]
568            if {[info exists _comp2cntls($cname)]} {
569                return $_comp2cntls($cname)
570            }
571            return ""
572        }
573        validate {
574            set path [lindex $args 0]
575            set value [lindex $args 1]
576            set units [$_xmlobj get $path.units]
577
578            if {"" != $units} {
579                set nv [Rappture::Units::convert \
580                    $value -context $units -to $units -units off]
581            } else {
582                set nv $value
583            }
584            if {![string is double $nv]
585                  || [regexp -nocase {^(inf|nan)$} $nv]} {
586                error "Value out of range"
587            }
588
589            set rawmin [$_xmlobj get $path.min]
590            if {"" != $rawmin} {
591                set minv $rawmin
592                if {"" != $units} {
593                    set minv [Rappture::Units::convert \
594                        $minv -context $units -to $units -units off]
595                    set nv [Rappture::Units::convert \
596                        $value -context $units -to $units -units off]
597                }
598                # fix for the case when the user tries to
599                # compare values like minv=-500 nv=-0600
600                set nv [format "%g" $nv]
601                set minv [format "%g" $minv]
602
603                if {$nv < $minv} {
604                    error "Minimum value allowed here is $rawmin"
605                }
606            }
607
608            set rawmax [$_xmlobj get $path.max]
609            if {"" != $rawmax} {
610                set maxv $rawmax
611                if {"" != $units} {
612                    set maxv [Rappture::Units::convert \
613                        $maxv -context $units -to $units -units off]
614                    set nv [Rappture::Units::convert \
615                        $value -context $units -to $units -units off]
616                }
617                # fix for the case when the user tries to
618                # compare values like maxv=-500 nv=-0600
619                set nv [format "%g" $nv]
620                set maxv [format "%g" $maxv]
621
622                if {$nv > $maxv} {
623                    error "Maximum value allowed here is $rawmax"
624                }
625            }
626
627            return "ok"
628        }
629        put {
630            set path [lindex $args 0]
631            set value [lindex $args 1]
632            $_xmlobj put $path.current $value
633            Build
634        }
635        default {
636            error "bad field controls option \"$option\": should be get or put"
637        }
638    }
639}
640
641# ----------------------------------------------------------------------
642# USAGE: hints ?<keyword>?
643#
644# Returns a list of key/value pairs for various hints about plotting
645# this field.  If a particular <keyword> is specified, then it returns
646# the hint for that <keyword>, if it exists.
647# ----------------------------------------------------------------------
648itcl::body Rappture::Field::hints {{keyword ""}} {
649    if { ![info exists _hints] } {
650        foreach {key path} {
651            camera          camera.position
652            color           about.color
653            default         about.default
654            group           about.group
655            label           about.label
656            scale           about.scale
657            seeds           about.seeds
658            style           about.style
659            type            about.type
660            xlabel          about.xaxis.label
661            ylabel          about.yaxis.label
662            zlabel          about.zaxis.label
663            xunits          about.xaxis.units
664            yunits          about.yaxis.units
665            zunits          about.zaxis.units
666            units           units
667            updir           updir
668            vectors         about.vectors
669        } {
670            set str [$_field get $path]
671            if { "" != $str } {
672                set _hints($key) $str
673            }
674        }
675        foreach {key path} {
676            toolid          tool.id
677            toolname        tool.name
678            toolcommand     tool.execute
679            tooltitle       tool.title
680            toolrevision    tool.version.application.revision
681        } {
682            set str [$_xmlobj get $path]
683            if { "" != $str } {
684                set _hints($key) $str
685            }
686        }
687        # Set toolip and path hints
688        set _hints(path) $_path
689        if { [info exists _hints(group)] && [info exists _hints(label)] } {
690            # pop-up help for each curve
691            set _hints(tooltip) $_hints(label)
692        }
693    }
694    if { $keyword != "" } {
695        if {[info exists _hints($keyword)]} {
696            return $_hints($keyword)
697        }
698        return ""
699    }
700    return [array get _hints]
701}
702
703# ----------------------------------------------------------------------
704# USAGE: Build
705#
706# Used internally to build up the vector representation for the
707# field when the object is first constructed, or whenever the field
708# data changes.  Discards any existing vectors and builds everything
709# from scratch.
710# ----------------------------------------------------------------------
711itcl::body Rappture::Field::Build {} {
712
713    # Discard any existing data
714    foreach name [array names _comp2xy] {
715        eval blt::vector destroy $_comp2xy($name)
716    }
717    array unset _comp2vtk
718    foreach name [array names _comp2unirect2d] {
719        eval itcl::delete object $_comp2unirect2d($name)
720    }
721    foreach name [array names _comp2unirect3d] {
722        eval itcl::delete object $_comp2unirect3d($name)
723    }
724    catch {unset _comp2xy}
725    catch {unset _comp2dx}
726    catch {unset _comp2dims}
727    catch {unset _comp2style}
728    array unset _comp2unirect2d
729    array unset _comp2unirect3d
730    array unset _comp2extents
731    array unset _dataobj2type
732    #
733    # Scan through the components of the field and create
734    # vectors for each part.
735    #
736    array unset _isValidComponent
737    foreach cname [$_field children -type component] {
738        set type ""
739        if { ([$_field element $cname.constant] != "" &&
740              [$_field element $cname.domain] != "") ||
741              [$_field element $cname.xy] != "" } {
742            set type "1D"
743        } elseif { [$_field element $cname.mesh] != "" &&
744                   [$_field element $cname.values] != ""} {
745            set type "points-on-mesh"
746        } elseif { [$_field element $cname.vtk] != ""} {
747            set viewer [$_field get "about.view"]
748            set type "vtk"
749            if { $viewer != "" } {
750                set _viewer $viewer
751            }
752        } elseif {[$_field element $cname.opendx] != ""} {
753            global env
754            if { [info exists env(VTKVOLUME)] } {
755                set type "vtkvolume"
756            } else {
757                set type "opendx"
758            }
759        } elseif {[$_field element $cname.dx] != ""} {
760            global env
761            if { [info exists env(VTKVOLUME)] } {
762                set type "vtkvolume"
763            } else {
764                set type "dx"
765            }
766        } elseif {[$_field element $cname.ucd] != ""} {
767            set type "ucd"
768        }
769        set _comp2style($cname) ""
770        if { $type == "" } {
771            puts stderr "WARNING: ignoring field component \"$_path.$cname\": no data found."
772            continue
773        }
774        # Save the extents of the component
775        if { [$_field element $cname.extents] != "" } {
776            set extents [$_field get $cname.extents]
777        } else {
778            set extents 1
779        }
780        set _comp2extents($cname) $extents
781        set _type $type
782        if {$type == "1D"} {
783            #
784            # 1D data can be represented as 2 BLT vectors,
785            # one for x and the other for y.
786            #
787            set xv ""
788            set yv ""
789
790            set val [$_field get $cname.constant]
791            if {$val != ""} {
792                set domain [$_field get $cname.domain]
793                if {$domain == "" || ![info exists _limits($domain)]} {
794                    set z0 0
795                    set z1 $_zmax
796                } else {
797                    foreach {z0 z1} $_limits($domain) { break }
798                }
799                set xv [blt::vector create x$_counter]
800                $xv append $z0 $z1
801
802                foreach {val pcomp} [_getValue $val] break
803                set yv [blt::vector create y$_counter]
804                $yv append $val $val
805
806                if {$pcomp != ""} {
807                    set zm [expr {0.5*($z0+$z1)}]
808                    set _comp2cntls($cname) \
809                        [list $pcomp $zm $val "$val$_units"]
810                }
811            } else {
812                set xydata [$_field get $cname.xy]
813                if {"" != $xydata} {
814                    set xv [blt::vector create x$_counter]
815                    set yv [blt::vector create y$_counter]
816                    set tmp [blt::vector create \#auto]
817                    $tmp set $xydata
818                    $tmp split $xv $yv
819                    blt::vector destroy $tmp
820                }
821            }
822
823            if {$xv != "" && $yv != ""} {
824                # sort x-coords in increasing order
825                $xv sort $yv
826                set _comp2dims($cname) "1D"
827                set _comp2xy($cname) [list $xv $yv]
828                incr _counter
829            }
830        } elseif {$type == "points-on-mesh"} {
831            if { ![BuildPointsOnMesh $cname] } {
832                continue;               # Ignore this component
833            }
834        } elseif {$type == "vtk"} {
835            set contents [$_field get $cname.vtk]
836            if { $contents == "" } {
837                puts stderr "WARNING: no data fo \"$_path.$cname.vtk\""
838                continue;               # Ignore this component
839            }
840            ReadVtkDataSet $cname $contents
841            set _comp2vtk($cname) $contents
842            set _comp2style($cname) [$_field get $cname.style]
843            incr _counter
844        } elseif {$type == "dx" || $type == "opendx" } {
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 _viewer "nanovis"
851            set _dim 3
852            set _type "dx"
853            set _comp2dims($cname) "3D"
854            set contents [$_field get -decode no $cname.$type]
855            if { $contents == "" } {
856                puts stderr "WARNING: no data for \"$_path.$cname.$type\""
857                continue;               # Ignore this component
858            }
859            set _comp2dx($cname) $contents
860            if 0 {
861                set hdr "@@RP-ENC:zb64\n"
862                set data  [$_field get -decode no $cname.$type]
863                set data "$hdr$data"
864                set data  [Rappture::encoding::decode $data]
865                set data  [Rappture::DxToVtk $data]
866                set f [open /tmp/$_path.$cname.vtk "w"]
867                puts $f $data
868                close $f
869            }
870            set _comp2style($cname) [$_field get $cname.style]
871            if {[$_field element $cname.flow] != ""} {
872                set _comp2flowhints($cname) \
873                    [Rappture::FlowHints ::\#auto $_field $cname $_units]
874            }
875            incr _counter
876        } elseif { $type == "ucd"} {
877            set contents [$_field get $cname.ucd]
878            if { $contents == "" } {
879                continue;               # Ignore this compoennt
880            }
881            set vtkdata [AvsToVtk $cname $contents]
882            ReadVtkDataSet $cname $vtkdata
883            set _comp2vtk($cname) $vtkdata
884            set _comp2style($cname) [$_field get $cname.style]
885            incr _counter
886        }
887        set _isValidComponent($cname) 1
888    }
889    if { [array size _isValidComponent] == 0 } {
890        puts stderr "WARNING: no valid components for field \"$_path\""
891        return 0
892    }
893    # Sanity check.  Verify that all components of the field have the same
894    # dimension.
895    set dim ""
896    foreach cname [array names _comp2dims] {
897        if { $dim == "" } {
898            set dim $_comp2dims($cname)
899            continue
900        }
901        if { $dim != $_comp2dims($cname) } {
902            puts stderr "WARNING: field can't have components of different dimensions: [join [array get _comp2dims] ,]"
903            return 0
904        }
905    }
906    # FIXME: about.scalars and about.vectors are temporary.  With views
907    #        the label and units for each field will be specified there.
908    #
909    # FIXME: Test that every <field><component> has the same field names,
910    #        units, components.
911    #
912    # Override what we found in the VTK file with names that the user
913    # selected.  We override the field label and units.
914    foreach { fname label units } [$_field get about.scalars] {
915        if { ![info exists _fld2Name($fname)] } {
916            set _fld2Name($fname) $fname
917            set _fld2Components($fname) 1
918        }
919        set _fld2Label($fname) $label
920        set _fld2Units($fname) $units
921    }
922    foreach { fname label units } [$_field get about.vectors] {
923        if { ![info exists _fld2Name($fname)] } {
924            set _fld2Name($fname) $fname
925            # We're just marking the field as vector (> 1) for now.
926            set _fld2Components($fname) 3
927        }
928        set _fld2Label($fname) $label
929        set _fld2Units($fname) $units
930    }
931    set _isValid 1
932    return 1
933}
934
935# ----------------------------------------------------------------------
936# USAGE: _getValue <expr>
937#
938# Used internally to get the value for an expression <expr>.  Returns
939# a list of the form {val parameterPath}, where val is the numeric
940# value of the expression, and parameterPath is the XML path to the
941# parameter representing the value, or "" if the <expr> does not
942# depend on any parameters.
943# ----------------------------------------------------------------------
944itcl::body Rappture::Field::_getValue {expr} {
945    #
946    # First, look for the expression among the <parameter>'s
947    # associated with the device.
948    #
949    set found 0
950    foreach pcomp [$_xmlobj children parameters] {
951        set id [$_xmlobj element -as id parameters.$pcomp]
952        if {[string equal $id $expr]} {
953            set val [$_xmlobj get parameters.$pcomp.current]
954            if {"" == $val} {
955                set val [$_xmlobj get parameters.$pcomp.default]
956            }
957            if {"" != $val} {
958                set expr $val
959                set found 1
960                break
961            }
962        }
963    }
964    if {$found} {
965        set pcomp "parameters.$pcomp"
966    } else {
967        set pcomp ""
968    }
969
970    if {$_units != ""} {
971        set expr [Rappture::Units::convert $expr \
972            -context $_units -to $_units -units off]
973    }
974
975    return [list $expr $pcomp]
976}
977
978#
979# isunirect2d  --
980#
981# Returns if the field is a unirect2d object. 
982#
983itcl::body Rappture::Field::isunirect2d { } {
984    return [expr [array size _comp2unirect2d] > 0]
985}
986
987#
988# isunirect3d  --
989#
990# Returns if the field is a unirect3d object. 
991#
992itcl::body Rappture::Field::isunirect3d { } {
993    return [expr [array size _comp2unirect3d] > 0]
994}
995
996#
997# flowhints  --
998#
999# Returns the hints associated with a flow vector field. 
1000#
1001itcl::body Rappture::Field::flowhints { cname } {
1002    if { [info exists _comp2flowhints($cname)] } {
1003        return $_comp2flowhints($cname)
1004    }
1005    return ""
1006}
1007
1008#
1009# style  --
1010#
1011# Returns the style associated with a component of the field. 
1012#
1013itcl::body Rappture::Field::style { cname } {
1014    if { [info exists _comp2style($cname)] } {
1015        return $_comp2style($cname)
1016    }
1017    return ""
1018}
1019
1020#
1021# type  --
1022#
1023# Returns the style associated with a component of the field. 
1024#
1025itcl::body Rappture::Field::type {} {
1026    return $_type
1027}
1028
1029#
1030# extents --
1031#
1032# Returns if the field is a unirect2d object. 
1033#
1034itcl::body Rappture::Field::extents {{cname -overall}} {
1035    if {$cname == "-overall" } {
1036        set max 0
1037        foreach cname [$_field children -type component] {
1038            if { ![info exists _comp2unirect3d($cname)] &&
1039                 ![info exists _comp2extents($cname)] } {
1040                continue
1041            }
1042            set value $_comp2extents($cname)
1043            if { $max < $value } {
1044                set max $value
1045            }
1046        }
1047        return $max
1048    }
1049    if { $cname == "component0"} {
1050        set cname [lindex [components -name] 0]
1051    }
1052    return $_comp2extents($cname)
1053}
1054
1055itcl::body Rappture::Field::ConvertToVtkData { cname } {
1056    set ds ""
1057    switch -- [typeof $cname] {
1058        "unirect2d" {
1059            foreach { x1 x2 xN y1 y2 yN } [$dataobj mesh $cname] break
1060            set spacingX [expr {double($x2 - $x1)/double($xN - 1)}]
1061            set spacingY [expr {double($y2 - $y1)/double($yN - 1)}]
1062           
1063            set ds [vtkImageData $this-grdataTemp]
1064            $ds SetDimensions $xN $yN 1
1065            $ds SetOrigin $x1 $y1 0
1066            $ds SetSpacing $spacingX $spacingY 0
1067            set arr [vtkDoubleArray $this-arrTemp]
1068            foreach {val} [$dataobj values $cname] {
1069                $arr InsertNextValue $val
1070            }
1071            [$ds GetPointData] SetScalars $arr
1072        }
1073        "unirect3d" {
1074            foreach { x1 x2 xN y1 y2 yN z1 z2 zN } [$dataobj mesh $cname] break
1075            set spacingX [expr {double($x2 - $x1)/double($xN - 1)}]
1076            set spacingY [expr {double($y2 - $y1)/double($yN - 1)}]
1077            set spacingZ [expr {double($z2 - $z1)/double($zN - 1)}]
1078           
1079            set ds [vtkImageData $this-grdataTemp]
1080            $ds SetDimensions $xN $yN $zN
1081            $ds SetOrigin $x1 $y1 $z1
1082            $ds SetSpacing $spacingX $spacingY $spacingZ
1083            set arr [vtkDoubleArray $this-arrTemp]
1084            foreach {val} [$dataobj values $cname] {
1085                $arr InsertNextValue $val
1086            }
1087            [$ds GetPointData] SetScalars $val
1088        }
1089        "contour" {
1090            return [$dataobj blob $cname]
1091        }
1092        "dx" {
1093            return [Rappture::DxToVtk $_comp2dx($cname)]
1094        }
1095        default {
1096            set mesh [$dataobj mesh $cname]
1097            switch -- [$mesh GetClassName] {
1098                vtkPoints {
1099                    # handle cloud of points
1100                    set ds [vtkPolyData $this-polydataTemp]
1101                    $ds SetPoints $mesh
1102                    [$ds GetPointData] SetScalars [$dataobj values $cname]
1103                }
1104                vtkPolyData {
1105                    set ds [vtkPolyData $this-polydataTemp]
1106                    $ds ShallowCopy $mesh
1107                    [$ds GetPointData] SetScalars [$dataobj values $cname]
1108                }
1109                vtkUnstructuredGrid {
1110                    # handle 3D grid with connectivity
1111                    set ds [vtkUnstructuredGrid $this-grdataTemp]
1112                    $ds ShallowCopy $mesh
1113                    [$ds GetPointData] SetScalars [$dataobj values $cname]
1114                }
1115                vtkRectilinearGrid {
1116                    # handle 3D grid with connectivity
1117                    set ds [vtkRectilinearGrid $this-grdataTemp]
1118                    $ds ShallowCopy $mesh
1119                    [$ds GetPointData] SetScalars [$dataobj values $cname]
1120                }
1121                default {
1122                    error "don't know how to handle [$mesh GetClassName] data"
1123                }
1124            }
1125        }
1126    }
1127
1128    if {"" != $ds} {
1129        set writer [vtkDataSetWriter $this-dsWriterTmp]
1130        $writer SetInput $ds
1131        $writer SetFileTypeToASCII
1132        $writer WriteToOutputStringOn
1133        $writer Write
1134        set out [$writer GetOutputString]
1135        $ds Delete
1136        $writer Delete
1137    } else {
1138        set out ""
1139        error "No DataSet to write"
1140    }
1141
1142    append out "\n"
1143    return $out
1144}
1145
1146itcl::body Rappture::Field::ReadVtkDataSet { cname contents } {
1147    package require vtk
1148
1149    set reader $this-datasetreader
1150    vtkDataSetReader $reader
1151
1152    # Write the contents to a file just in case it's binary.
1153    set tmpfile file[pid].vtk
1154    set f [open "$tmpfile" "w"]
1155    fconfigure $f -translation binary -encoding binary
1156    puts $f $contents
1157    close $f
1158
1159    $reader SetFileName $tmpfile
1160    $reader ReadAllScalarsOn
1161    $reader ReadAllVectorsOn
1162    $reader ReadAllFieldsOn
1163    $reader Update
1164    set dataset [$reader GetOutput]
1165    set limits {}
1166    foreach {xmin xmax ymin ymax zmin zmax} [$dataset GetBounds] break
1167    # Figure out the dimension of the mesh from the bounds.
1168    set _dim 0
1169    if { $xmax > $xmin } {
1170        incr _dim
1171    }
1172    if { $ymax > $ymin } {
1173        incr _dim
1174    }
1175    if { $zmax > $zmin } {
1176        incr _dim
1177    }
1178    if { $_viewer == "" } {
1179        if { $_dim == 2 } {
1180            set _viewer contour
1181        } else {
1182            set _viewer isosurface
1183        }
1184    }
1185    set _comp2dims($cname) ${_dim}D
1186    if { $_dim < 2 } {
1187        set points [$dataset GetPoints]
1188        set numPoints [$points GetNumberOfPoints]
1189        set xv [blt::vector create \#auto]
1190        for { set i 0 } { $i < $numPoints } { incr i } {
1191            set point [$points GetPoint 0]
1192            $xv append [lindex $point 0]
1193        }
1194        set yv [blt::vector create \#auto]
1195        $yv seq 0 1 [$xv length]
1196        set _comp2xy($cname) [list $xv $yv]
1197    }
1198    lappend limits x [list $xmin $xmax]
1199    lappend limits y [list $ymin $ymax]
1200    lappend limits z [list $zmin $zmax]
1201    set dataAttrs [$dataset GetPointData]
1202    if { $_dim == 1 } {
1203        set numArrays [$dataAttrs GetNumberOfArrays]
1204    }
1205    if { $dataAttrs == ""} {
1206        puts stderr "WARNING: no point data found in \"$_path\""
1207        return 0
1208    }
1209    set vmin 0
1210    set vmax 1
1211    set numArrays [$dataAttrs GetNumberOfArrays]
1212    if { $numArrays > 0 } {
1213        set array [$dataAttrs GetArray 0]
1214        foreach {vmin vmax} [$array GetRange] break
1215
1216        for {set i 0} {$i < [$dataAttrs GetNumberOfArrays] } {incr i} {
1217            set array [$dataAttrs GetArray $i]
1218            set fname  [$dataAttrs GetArrayName $i]
1219            foreach {min max} [$array GetRange] break
1220            lappend limits $fname [list $min $max]
1221            set _fld2Units($fname) ""
1222            set _fld2Label($fname) $fname
1223            set _fld2Components($fname) [$array GetNumberOfComponents]
1224            lappend _comp2fldName($cname) $fname
1225        }
1226    }
1227    lappend limits v [list $vmin $vmax]
1228    set _comp2limits($cname) $limits
1229    file delete $tmpfile
1230    rename $reader ""
1231}
1232
1233#
1234# vtkdata --
1235#
1236#       Returns a string representing the mesh and field data for a specific
1237#       component in the legacy VTK file format.
1238#
1239itcl::body Rappture::Field::vtkdata {cname} {
1240    if {$cname == "component0"} {
1241        set cname "component"
1242    }
1243    # DX: Convert DX to VTK
1244    if {[info exists _comp2dx($cname)]} {
1245        return [Rappture::DxToVtk $_comp2dx($cname)]
1246    }
1247    # Unirect3d: isosurface
1248    if {[info exists _comp2unirect3d($cname)]} {
1249        return [$_comp2unirect3d($cname) vtkdata]
1250    }
1251    # VTK file data:
1252    if { [info exists _comp2vtk($cname)] } {
1253        return $_comp2vtk($cname)
1254    }
1255    # Points on mesh:  Construct VTK file output.
1256    if { [info exists _comp2mesh($cname)] } {
1257        # Data is in the form mesh and vector
1258        foreach {mesh vector} $_comp2mesh($cname) break
1259        set label $cname
1260        regsub -all { } $label {_} label
1261        append out "# vtk DataFile Version 3.0\n"
1262        append out "[hints label]\n"
1263        append out "ASCII\n"
1264        append out [$mesh vtkdata]
1265        append out "POINT_DATA [$vector length]\n"
1266        append out "SCALARS $label double 1\n"
1267        append out "LOOKUP_TABLE default\n"
1268        append out "[$vector range 0 end]\n"
1269        return $out
1270    }
1271    error "can't find vtkdata for $cname. This method should only be called by the vtkheightmap widget"
1272}
1273
1274#
1275# BuildPointsOnMesh --
1276#
1277#       Parses the field XML description to build a mesh and values vector
1278#       representing the field.  Right now we handle the deprecated types
1279#       of "cloud", "unirect2d", and "unirect3d" (mostly for flows).
1280#
1281itcl::body Rappture::Field::BuildPointsOnMesh {cname} {
1282    #
1283    # More complex 2D/3D data is represented by a mesh
1284    # object and an associated vector for field values.
1285    #
1286    set path [$_field get $cname.mesh]
1287    if {[$_xmlobj element $path] == ""} {
1288        # Unknown mesh designated.
1289        return 0
1290    }
1291    set _viewer [$_field get "about.view"]
1292    set element [$_xmlobj element -as type $path]
1293    set name $cname
1294    regsub -all { } $name {_} name
1295    set _fld2Label($name) $name
1296    set label [hints zlabel]
1297    if { $label != "" } {
1298        set _fld2Label($name) $label
1299    }
1300    set _fld2Units($name) [hints zunits]
1301    set _fld2Components($name) 1
1302    lappend _comp2fldName($cname) $name
1303
1304    # Handle bizarre cases that hopefully will be deprecated.
1305    if { $element == "unirect3d" } {
1306        # Special case: unirect3d (should be deprecated) + flow.
1307        if { [$_field element $cname.extents] != "" } {
1308            set extents [$_field get $cname.extents]
1309        } else {
1310            set extents 1
1311        }
1312        set _dim 3
1313        if { $_viewer == "" } {
1314            set _viewer flowvis
1315        }
1316        set _comp2dims($cname) "3D"
1317        set _comp2unirect3d($cname) \
1318            [Rappture::Unirect3d \#auto $_xmlobj $_field $cname $extents]
1319        set _comp2style($cname) [$_field get $cname.style]
1320        if {[$_field element $cname.flow] != ""} {
1321            set _comp2flowhints($cname) \
1322                [Rappture::FlowHints ::\#auto $_field $cname $_units]
1323        }
1324        incr _counter
1325        return 1
1326    }
1327    if { $element == "unirect2d" && [$_field element $cname.flow] != "" } {
1328        # Special case: unirect2d (normally deprecated) + flow.
1329        if { [$_field element $cname.extents] != "" } {
1330            set extents [$_field get $cname.extents]
1331        } else {
1332            set extents 1
1333        }
1334        set _dim 2
1335        if { $_viewer == "" } {
1336            set _viewer "flowvis"
1337        }
1338        set _comp2dims($cname) "2D"
1339        set _comp2unirect2d($cname) \
1340            [Rappture::Unirect2d \#auto $_xmlobj $path]
1341        set _comp2style($cname) [$_field get $cname.style]
1342        set _comp2flowhints($cname) \
1343            [Rappture::FlowHints ::\#auto $_field $cname $_units]
1344        set _values [$_field get $cname.values]
1345        set limits {}
1346        foreach axis { x y } {
1347            lappend limits $axis [$_comp2unirect2d($cname) limits $axis]
1348        }
1349        set xv [blt::vector create \#auto]
1350        $xv set $_values
1351        lappend limits $cname [$xv limits]
1352        lappend limits v [$xv limits]
1353        blt::vector destroy $xv
1354        set _comp2limits($cname) $limits
1355        incr _counter
1356        return 1
1357    }
1358    switch -- $element {
1359        "cloud" {
1360            set mesh [Rappture::Cloud::fetch $_xmlobj $path]
1361        }
1362        "mesh" {
1363            set mesh [Rappture::Mesh::fetch $_xmlobj $path]
1364        }           
1365        "unirect2d" {
1366            if { $_viewer == "" } {
1367                set _viewer "heightmap"
1368            }
1369            set mesh [Rappture::Unirect2d::fetch $_xmlobj $path]
1370        }
1371    }
1372    if { ![$mesh isvalid] } {
1373        return 0
1374    }
1375    set _dim [$mesh dimensions]
1376    if {$_dim == 1} {
1377        # Is this used anywhere?
1378        #
1379        # OOPS!  This is 1D data
1380        # Forget the cloud/field -- store BLT vectors
1381        #
1382        # Is there a natural growth path in generating output from 1D to
1383        # higher dimensions?  If there isn't, let's kill this in favor
1384        # or explicitly using a <curve> instead.  Otherwise, the features
1385        # (methods such as xmarkers) or the <curve> need to be added
1386        # to the <field>.
1387        #
1388        set xv [blt::vector create x$_counter]
1389        set yv [blt::vector create y$_counter]
1390       
1391        $yv set [$mesh points]
1392        $xv seq 0 1 [$yv length]
1393        # sort x-coords in increasing order
1394        $xv sort $yv
1395       
1396        set _comp2dims($cname) "1D"
1397        set _comp2xy($cname) [list $xv $yv]
1398        incr _counter
1399        return 1
1400    }
1401    if {$_dim == 2} {
1402        set _type "heightmap"
1403        set v [blt::vector create \#auto]
1404        $v set [$_field get $cname.values]
1405        if { [$v length] == 0 } {
1406            return 0
1407        }
1408        set _comp2dims($cname) "[$mesh dimensions]D"
1409        set _comp2mesh($cname) [list $mesh $v]
1410        set _comp2style($cname) [$_field get $cname.style]
1411        incr _counter
1412        array unset _comp2limits $cname
1413        lappend _comp2limits($cname) x [$mesh limits x]
1414        lappend _comp2limits($cname) y [$mesh limits y]
1415        lappend _comp2limits($cname) $cname [$v limits]
1416        lappend _comp2limits($cname) v [$v limits]
1417        return 1
1418    }
1419    if {$_dim == 3} {
1420        #
1421        # 3D data: Store cloud/field as components
1422        #
1423        set values [$_field get $cname.values]
1424        set farray [vtkFloatArray ::vals$_counter]
1425        foreach v $values {
1426            if {"" != $_units} {
1427                set v [Rappture::Units::convert $v \
1428                           -context $_units -to $_units -units off]
1429            }
1430            $farray InsertNextValue $v
1431        }
1432        if { $_viewer == "" } {
1433            set _viewer "isosurface"
1434        }
1435        set _type "isosurface"
1436        set v [blt::vector create \#auto]
1437        $v set [$_field get $cname.values]
1438        if { [$v length] == 0 } {
1439            return 0
1440        }
1441        set _comp2dims($cname) "[$mesh dimensions]D"
1442        set _comp2mesh($cname) [list $mesh $v]
1443        set _comp2style($cname) [$_field get $cname.style]
1444        incr _counter
1445        lappend _comp2limits($cname) x [$mesh limits x]
1446        lappend _comp2limits($cname) y [$mesh limits y]
1447        lappend _comp2limits($cname) z [$mesh limits z]
1448        lappend _comp2limits($cname) $cname [$v limits]
1449        lappend _comp2limits($cname) v [$v limits]
1450        return 1
1451    }
1452    error "unhandled case in field dim=$_dim element=$element"
1453}
1454
1455itcl::body Rappture::Field::AvsToVtk { cname contents } {
1456    package require vtk
1457
1458    set reader $this-datasetreader
1459    vtkAVSucdReader $reader
1460
1461    # Write the contents to a file just in case it's binary.
1462    set tmpfile $cname[pid].ucd
1463    set f [open "$tmpfile" "w"]
1464    fconfigure $f -translation binary -encoding binary
1465    puts $f $contents
1466    close $f
1467    $reader SetFileName $tmpfile
1468    $reader Update
1469    file delete $tmpfile
1470
1471    set output [$reader GetOutput]
1472    set pointData [$output GetPointData]
1473    set _scalars {}
1474    for { set i 0 } { $i < [$pointData GetNumberOfArrays] } { incr i } {
1475        set name [$pointData GetArrayName $i]
1476        lappend _scalars $name $name "???"
1477    }
1478    set tmpfile $cname[pid].vtk
1479    set writer $this-datasetwriter
1480    vtkDataSetWriter $writer
1481    $writer SetInputConnection [$reader GetOutputPort]
1482    $writer SetFileName $tmpfile
1483    $writer Write
1484    rename $reader ""
1485    rename $writer ""
1486
1487    set f [open "$tmpfile" "r"]
1488    fconfigure $f -translation binary -encoding binary
1489    set vtkdata [read $f]
1490    close $f
1491    file delete $tmpfile
1492    return $vtkdata
1493}
Note: See TracBrowser for help on using the repository browser.