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

Last change on this file since 1258 was 1258, checked in by gah, 16 years ago

removed debugging from pymolproxy, field object (dumping dx file)

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