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

Last change on this file since 113 was 113, checked in by mmc, 19 years ago

Fixed 3D volume rendering to work for prisms, pyramids,
and tetrahedra, in addition to the boxes (voxels) originally
implemented.

File size: 11.0 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 method _getVtkElement {npts}
35
36    private variable _xmlobj ""  ;# ref to XML obj with device data
37    private variable _mesh ""    ;# lib obj representing this mesh
38    private variable _pts2elem   ;# maps # points => vtk element
39
40    private variable _units "m m m" ;# system of units for x, y, z
41    private variable _limits        ;# limits xmin, xmax, ymin, ymax, ...
42
43    private common _xp2obj       ;# used for fetch/release ref counting
44    private common _obj2ref      ;# used for fetch/release ref counting
45}
46
47# ----------------------------------------------------------------------
48# USAGE: Rappture::Mesh::fetch <xmlobj> <path>
49#
50# Clients use this instead of a constructor to fetch the Mesh for
51# a particular <path> in the <xmlobj>.  When the client is done with
52# the mesh, he calls "release" to decrement the reference count.
53# When the mesh is no longer needed, it is cleaned up automatically.
54# ----------------------------------------------------------------------
55itcl::body Rappture::Mesh::fetch {xmlobj path} {
56    set handle "$xmlobj|$path"
57    if {[info exists _xp2obj($handle)]} {
58        set obj $_xp2obj($handle)
59        incr _obj2ref($obj)
60        return $obj
61    }
62
63    set obj [Rappture::Mesh ::#auto $xmlobj $path]
64    set _xp2obj($handle) $obj
65    set _obj2ref($obj) 1
66    return $obj
67}
68
69# ----------------------------------------------------------------------
70# USAGE: Rappture::Mesh::release <obj>
71#
72# Clients call this when they're no longer using a Mesh fetched
73# previously by the "fetch" proc.  This decrements the reference
74# count for the mesh and destroys the object when it is no longer
75# in use.
76# ----------------------------------------------------------------------
77itcl::body Rappture::Mesh::release {obj} {
78    if {[info exists _obj2ref($obj)]} {
79        incr _obj2ref($obj) -1
80        if {$_obj2ref($obj) <= 0} {
81            unset _obj2ref($obj)
82            foreach handle [array names _xp2obj] {
83                if {$_xp2obj($handle) == $obj} {
84                    unset _xp2obj($handle)
85                }
86            }
87            itcl::delete object $obj
88        }
89    } else {
90        error "can't find reference count for $obj"
91    }
92}
93
94# ----------------------------------------------------------------------
95# CONSTRUCTOR
96# ----------------------------------------------------------------------
97itcl::body Rappture::Mesh::constructor {xmlobj path} {
98    if {![Rappture::library isvalid $xmlobj]} {
99        error "bad value \"$xmlobj\": should be Rappture::library"
100    }
101    set _xmlobj $xmlobj
102    set _mesh [$xmlobj element -as object $path]
103
104    set u [$_mesh get units]
105    if {"" != $u} {
106        while {[llength $u] < 3} {
107            lappend u [lindex $u end]
108        }
109        set _units $u
110    }
111
112    # create the vtk objects containing points and connectivity
113    vtkPoints $this-points
114    vtkUnstructuredGrid $this-grid
115
116    foreach lim {xmin xmax ymin ymax zmin zmax} {
117        set _limits($lim) ""
118    }
119
120    #
121    # Extract each node and add it to the points list.
122    #
123    foreach comp [$xmlobj children -type node $path] {
124        set xyz [$xmlobj get $path.$comp]
125
126        # make sure we have x,y,z
127        while {[llength $xyz] < 3} {
128            lappend xyz "0"
129        }
130
131        # extract each point and add it to the points list
132        foreach {x y z} $xyz break
133        foreach dim {x y z} units $_units {
134            set v [Rappture::Units::convert [set $dim] \
135                -context $units -to $units -units off]
136
137            set $dim $v  ;# save back to real x/y/z variable
138
139            if {"" == $_limits(${dim}min)} {
140                set _limits(${dim}min) $v
141                set _limits(${dim}max) $v
142            } else {
143                if {$v < $_limits(${dim}min)} { set _limits(${dim}min) $v }
144                if {$v > $_limits(${dim}max)} { set _limits(${dim}max) $v }
145            }
146        }
147        $this-points InsertNextPoint $x $y $z
148    }
149    $this-grid SetPoints $this-points
150
151    #
152    # Extract each element and add it to the mesh.
153    #
154    foreach comp [$xmlobj children -type element $path] {
155        set nlist [$_mesh get $comp.nodes]
156        set elem [_getVtkElement [llength $nlist]]
157
158        set i 0
159        foreach n $nlist {
160            [$elem GetPointIds] SetId $i $n
161            incr i
162        }
163        $this-grid InsertNextCell [$elem GetCellType] [$elem GetPointIds]
164    }
165}
166
167# ----------------------------------------------------------------------
168# DESTRUCTOR
169# ----------------------------------------------------------------------
170itcl::body Rappture::Mesh::destructor {} {
171    # don't destroy the _xmlobj! we don't own it!
172    itcl::delete object $_mesh
173
174    rename $this-points ""
175    rename $this-grid ""
176
177    foreach type [array names _pts2elem] {
178        rename $_pts2elem($type) ""
179    }
180}
181
182# ----------------------------------------------------------------------
183# USAGE: points
184#
185# Returns the vtk object containing the points for this mesh.
186# ----------------------------------------------------------------------
187itcl::body Rappture::Mesh::points {} {
188    # not implemented
189    return $this-points
190}
191
192# ----------------------------------------------------------------------
193# USAGE: elements
194#
195# Returns a list of the form {plist r plist r ...} for each element
196# in this mesh.  Each plist is a list of {x y x y ...} coordinates
197# for the mesh.
198# ----------------------------------------------------------------------
199itcl::body Rappture::Mesh::elements {} {
200    # build a map for region number => region type
201    foreach comp [$_mesh children -type region] {
202        set id [$_mesh element -as id $comp]
203        set regions($id) [$_mesh get $comp]
204    }
205    set regions() "unknown"
206
207    set rlist ""
208    foreach comp [$_mesh children -type element] {
209        set rid [$_mesh get $comp.region]
210
211        #
212        # HACK ALERT!
213        #
214        # Prophet puts out nodes in a funny "Z" shaped order,
215        # not in proper clockwise fashion.  Switch the last
216        # two nodes for now to make them correct.
217        #
218        set nlist [$_mesh get $comp.nodes]
219        set n2 [lindex $nlist 2]
220        set n3 [lindex $nlist 3]
221        set nlist [lreplace $nlist 2 3 $n3 $n2]
222        lappend nlist [lindex $nlist 0]
223
224        set plist ""
225        foreach nid $nlist {
226            eval lappend plist [$_mesh get node($nid)]
227        }
228        lappend rlist $plist $regions($rid)
229    }
230    return $rlist
231}
232
233# ----------------------------------------------------------------------
234# USAGE: mesh
235#
236# Returns the vtk object representing the mesh.
237# ----------------------------------------------------------------------
238itcl::body Rappture::Mesh::mesh {} {
239    return $this-grid
240}
241
242# ----------------------------------------------------------------------
243# USAGE: size ?-points|-elements?
244#
245# Returns the number of points in this mesh.
246# ----------------------------------------------------------------------
247itcl::body Rappture::Mesh::size {{what -points}} {
248    switch -- $what {
249        -points {
250            return [$this-points GetNumberOfPoints]
251        }
252        -elements {
253            return [$this-points GetNumberOfCells]
254        }
255        default {
256            error "bad option \"$what\": should be -points or -elements"
257        }
258    }
259}
260
261# ----------------------------------------------------------------------
262# USAGE: dimensions
263#
264# Returns the number of dimensions for this object: 1, 2, or 3.
265# ----------------------------------------------------------------------
266itcl::body Rappture::Mesh::dimensions {} {
267    # count the dimensions with real limits
268    set dims 0
269    foreach d {x y z} {
270        if {$_limits(${d}min) != $_limits(${d}max)} {
271            incr dims
272        }
273    }
274    return $dims
275}
276
277# ----------------------------------------------------------------------
278# USAGE: limits x|y|z
279#
280# Returns the {min max} values for the limits of the specified axis.
281# ----------------------------------------------------------------------
282itcl::body Rappture::Mesh::limits {which} {
283    if {![info exists _limits(${which}min)]} {
284        error "bad axis \"$which\": should be x, y, z"
285    }
286    return [list $_limits(${which}min) $_limits(${which}max)]
287}
288
289# ----------------------------------------------------------------------
290# USAGE: hints ?<keyword>?
291#
292# Returns a list of key/value pairs for various hints about plotting
293# this field.  If a particular <keyword> is specified, then it returns
294# the hint for that <keyword>, if it exists.
295# ----------------------------------------------------------------------
296itcl::body Rappture::Mesh::hints {{keyword ""}} {
297    foreach key {label color units} {
298        set str [$_mesh get $key]
299        if {"" != $str} {
300            set hints($key) $str
301        }
302    }
303
304    if {$keyword != ""} {
305        if {[info exists hints($keyword)]} {
306            return $hints($keyword)
307        }
308        return ""
309    }
310    return [array get hints]
311}
312
313# ----------------------------------------------------------------------
314# USAGE: _getVtkElement <npts>
315#
316# Used internally to find (or allocate, if necessary) a vtk element
317# that can be used to build up a mesh.  The element depends on the
318# number of points passed in.  4 points is a tetrahedron, 5 points
319# is a pyramid, etc.
320# ----------------------------------------------------------------------
321itcl::body Rappture::Mesh::_getVtkElement {npts} {
322    if {![info exists _pts2elem($npts)]} {
323        switch -- $npts {
324            4 {
325                set _pts2elem($npts) $this-elem4
326                vtkTetra $_pts2elem($npts)
327            }
328            5 {
329                set _pts2elem($npts) $this-elem5
330                vtkPyramid $_pts2elem($npts)
331            }
332            6 {
333                set _pts2elem($npts) $this-elem6
334                vtkWedge $_pts2elem($npts)
335            }
336            8 {
337                set _pts2elem($npts) $this-elem8
338                vtkVoxel $_pts2elem($npts)
339            }
340        }
341    }
342    return $_pts2elem($npts)
343}
Note: See TracBrowser for help on using the repository browser.