source: trunk/gui/scripts/mesh.tcl @ 95

Last change on this file since 95 was 95, checked in by mmc, 17 years ago
  • Fixed an annoying bug in the scroller that would cause the device to jitter up and down in some cases. (1-barrier case of app-rtd)
  • Fixed cloud/mesh objects to allow different units for each of the various axes.
  • Fixed the install.tcl script to avoid popping up the notice about Rappture being installed when tclsh is running the script.
File size: 9.7 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: mesh - represents a structured mesh for a device
3#
4#  This object represents a mesh in an XML description of simulator
5#  output.  A mesh is a structured arrangement of points, as elements
6#  composed of nodes representing coordinates.  This is a little
7#  different from a cloud, which is an unstructured arrangement
8#  (shotgun blast) of points.
9# ======================================================================
10#  AUTHOR:  Michael McLennan, Purdue University
11#  Copyright (c) 2004-2005
12#  Purdue Research Foundation, West Lafayette, IN
13# ======================================================================
14package require Itcl
15package require vtk
16
17namespace eval Rappture { # forward declaration }
18
19itcl::class Rappture::Mesh {
20    constructor {xmlobj path} { # defined below }
21    destructor { # defined below }
22
23    public method points {}
24    public method elements {}
25    public method mesh {}
26    public method size {{what -points}}
27    public method dimensions {}
28    public method limits {which}
29    public method hints {{key ""}}
30
31    public proc fetch {xmlobj path}
32    public proc release {obj}
33
34    private variable _xmlobj ""  ;# ref to XML obj with device data
35    private variable _mesh ""    ;# lib obj representing this mesh
36
37    private variable _units "m m m" ;# system of units for x, y, z
38    private variable _limits        ;# limits xmin, xmax, ymin, ymax, ...
39
40    private common _xp2obj       ;# used for fetch/release ref counting
41    private common _obj2ref      ;# used for fetch/release ref counting
42}
43
44# ----------------------------------------------------------------------
45# USAGE: Rappture::Mesh::fetch <xmlobj> <path>
46#
47# Clients use this instead of a constructor to fetch the Mesh for
48# a particular <path> in the <xmlobj>.  When the client is done with
49# the mesh, he calls "release" to decrement the reference count.
50# When the mesh is no longer needed, it is cleaned up automatically.
51# ----------------------------------------------------------------------
52itcl::body Rappture::Mesh::fetch {xmlobj path} {
53    set handle "$xmlobj|$path"
54    if {[info exists _xp2obj($handle)]} {
55        set obj $_xp2obj($handle)
56        incr _obj2ref($obj)
57        return $obj
58    }
59
60    set obj [Rappture::Mesh ::#auto $xmlobj $path]
61    set _xp2obj($handle) $obj
62    set _obj2ref($obj) 1
63    return $obj
64}
65
66# ----------------------------------------------------------------------
67# USAGE: Rappture::Mesh::release <obj>
68#
69# Clients call this when they're no longer using a Mesh fetched
70# previously by the "fetch" proc.  This decrements the reference
71# count for the mesh and destroys the object when it is no longer
72# in use.
73# ----------------------------------------------------------------------
74itcl::body Rappture::Mesh::release {obj} {
75    if {[info exists _obj2ref($obj)]} {
76        incr _obj2ref($obj) -1
77        if {$_obj2ref($obj) <= 0} {
78            unset _obj2ref($obj)
79            foreach handle [array names _xp2obj] {
80                if {$_xp2obj($handle) == $obj} {
81                    unset _xp2obj($handle)
82                }
83            }
84            itcl::delete object $obj
85        }
86    } else {
87        error "can't find reference count for $obj"
88    }
89}
90
91# ----------------------------------------------------------------------
92# CONSTRUCTOR
93# ----------------------------------------------------------------------
94itcl::body Rappture::Mesh::constructor {xmlobj path} {
95    if {![Rappture::library isvalid $xmlobj]} {
96        error "bad value \"$xmlobj\": should be Rappture::library"
97    }
98    set _xmlobj $xmlobj
99    set _mesh [$xmlobj element -as object $path]
100
101    set u [$_mesh get units]
102    if {"" != $u} {
103        while {[llength $u] < 3} {
104            lappend u [lindex $u end]
105        }
106        set _units $u
107    }
108
109    # create the vtk objects containing points and connectivity
110    vtkPoints $this-points
111    vtkVoxel $this-vox
112    vtkUnstructuredGrid $this-grid
113
114    foreach lim {xmin xmax ymin ymax zmin zmax} {
115        set _limits($lim) ""
116    }
117
118    #
119    # Extract each node and add it to the points list.
120    #
121    foreach comp [$xmlobj children -type node $path] {
122        set xyz [$xmlobj get $path.$comp]
123
124        # make sure we have x,y,z
125        while {[llength $xyz] < 3} {
126            lappend xyz "0"
127        }
128
129        # extract each point and add it to the points list
130        foreach {x y z} $xyz break
131        foreach dim {x y z} units $_units {
132            set v [Rappture::Units::convert [set $dim] \
133                -context $units -to $units -units off]
134
135            set $dim $v  ;# save back to real x/y/z variable
136
137            if {"" == $_limits(${dim}min)} {
138                set _limits(${dim}min) $v
139                set _limits(${dim}max) $v
140            } else {
141                if {$v < $_limits(${dim}min)} { set _limits(${dim}min) $v }
142                if {$v > $_limits(${dim}max)} { set _limits(${dim}max) $v }
143            }
144        }
145        $this-points InsertNextPoint $x $y $z
146    }
147    $this-grid SetPoints $this-points
148
149    #
150    # Extract each element and add it to the mesh.
151    #
152    foreach comp [$xmlobj children -type element $path] {
153        set nlist [$_mesh get $comp.nodes]
154        set i 0
155        foreach n $nlist {
156            [$this-vox GetPointIds] SetId $i $n
157            incr i
158        }
159        $this-grid InsertNextCell [$this-vox GetCellType] \
160            [$this-vox GetPointIds]
161    }
162}
163
164# ----------------------------------------------------------------------
165# DESTRUCTOR
166# ----------------------------------------------------------------------
167itcl::body Rappture::Mesh::destructor {} {
168    # don't destroy the _xmlobj! we don't own it!
169    itcl::delete object $_mesh
170
171    rename $this-points ""
172    rename $this-vox ""
173    rename $this-grid ""
174}
175
176# ----------------------------------------------------------------------
177# USAGE: points
178#
179# Returns the vtk object containing the points for this mesh.
180# ----------------------------------------------------------------------
181itcl::body Rappture::Mesh::points {} {
182    # not implemented
183    return $this-points
184}
185
186# ----------------------------------------------------------------------
187# USAGE: elements
188#
189# Returns a list of the form {plist r plist r ...} for each element
190# in this mesh.  Each plist is a list of {x y x y ...} coordinates
191# for the mesh.
192# ----------------------------------------------------------------------
193itcl::body Rappture::Mesh::elements {} {
194    # build a map for region number => region type
195    foreach comp [$_mesh children -type region] {
196        set id [$_mesh element -as id $comp]
197        set regions($id) [$_mesh get $comp]
198    }
199    set regions() "unknown"
200
201    set rlist ""
202    foreach comp [$_mesh children -type element] {
203        set rid [$_mesh get $comp.region]
204
205        #
206        # HACK ALERT!
207        #
208        # Prophet puts out nodes in a funny "Z" shaped order,
209        # not in proper clockwise fashion.  Switch the last
210        # two nodes for now to make them correct.
211        #
212        set nlist [$_mesh get $comp.nodes]
213        set n2 [lindex $nlist 2]
214        set n3 [lindex $nlist 3]
215        set nlist [lreplace $nlist 2 3 $n3 $n2]
216        lappend nlist [lindex $nlist 0]
217
218        set plist ""
219        foreach nid $nlist {
220            eval lappend plist [$_mesh get node($nid)]
221        }
222        lappend rlist $plist $regions($rid)
223    }
224    return $rlist
225}
226
227# ----------------------------------------------------------------------
228# USAGE: mesh
229#
230# Returns the vtk object representing the mesh.
231# ----------------------------------------------------------------------
232itcl::body Rappture::Mesh::mesh {} {
233    return $this-grid
234}
235
236# ----------------------------------------------------------------------
237# USAGE: size ?-points|-elements?
238#
239# Returns the number of points in this mesh.
240# ----------------------------------------------------------------------
241itcl::body Rappture::Mesh::size {{what -points}} {
242    switch -- $what {
243        -points {
244            return [$this-points GetNumberOfPoints]
245        }
246        -elements {
247            return [$this-points GetNumberOfCells]
248        }
249        default {
250            error "bad option \"$what\": should be -points or -elements"
251        }
252    }
253}
254
255# ----------------------------------------------------------------------
256# USAGE: dimensions
257#
258# Returns the number of dimensions for this object: 1, 2, or 3.
259# ----------------------------------------------------------------------
260itcl::body Rappture::Mesh::dimensions {} {
261    # count the dimensions with real limits
262    set dims 0
263    foreach d {x y z} {
264        if {$_limits(${d}min) != $_limits(${d}max)} {
265            incr dims
266        }
267    }
268    return $dims
269}
270
271# ----------------------------------------------------------------------
272# USAGE: limits x|y|z
273#
274# Returns the {min max} values for the limits of the specified axis.
275# ----------------------------------------------------------------------
276itcl::body Rappture::Mesh::limits {which} {
277    if {![info exists _limits(${which}min)]} {
278        error "bad axis \"$which\": should be x, y, z"
279    }
280    return [list $_limits(${which}min) $_limits(${which}max)]
281}
282
283# ----------------------------------------------------------------------
284# USAGE: hints ?<keyword>?
285#
286# Returns a list of key/value pairs for various hints about plotting
287# this field.  If a particular <keyword> is specified, then it returns
288# the hint for that <keyword>, if it exists.
289# ----------------------------------------------------------------------
290itcl::body Rappture::Mesh::hints {{keyword ""}} {
291    foreach key {label color units} {
292        set str [$_mesh get $key]
293        if {"" != $str} {
294            set hints($key) $str
295        }
296    }
297
298    if {$keyword != ""} {
299        if {[info exists hints($keyword)]} {
300            return $hints($keyword)
301        }
302        return ""
303    }
304    return [array get hints]
305}
Note: See TracBrowser for help on using the repository browser.