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

Last change on this file since 17 was 17, checked in by mmc, 18 years ago

Added a capability to MainWin? to syncCutBuffer with the
application. The VNC Java client uses the cutbuffer
instead of the selection for Copy/Paste? to desktop, and
this mechanism keeps the two in sync so Copy/Paste? works
properly. Also, added Cut/Copy/Paste? menus to the right
mouse button of various widgets.

Fixed 3D plotting to work with the vtkCutter so it works
better. Also, added support for 3D meshes in addition
to clouds. Meshes store connectivity, so they are better
at representing holes in data. Fixed the 3D plotter so
that rotate is more intuitive, and added lights so you can
see your data better at any angle.

Fixed the loader so that it can load elements with the ""
value, and so that it doesn't duplicate entries found
more than once by *.xml pattern matching.

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"  ;# system of units for this mesh
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        set _units $u
104    }
105
106    # create the vtk objects containing points and connectivity
107    vtkPoints $this-points
108    vtkVoxel $this-vox
109    vtkUnstructuredGrid $this-grid
110
111    foreach lim {xmin xmax ymin ymax zmin zmax} {
112        set _limits($lim) ""
113    }
114
115    #
116    # Extract each node and add it to the points list.
117    #
118    foreach comp [$xmlobj children -type node $path] {
119        set xyz [$xmlobj get $path.$comp]
120
121        # make sure we have x,y,z
122        while {[llength $xyz] < 3} {
123            lappend xyz "0"
124        }
125
126        # extract each point and add it to the points list
127        foreach {x y z} $xyz break
128        foreach dim {x y z} {
129            set v [Rappture::Units::convert [set $dim] \
130                -context $_units -to $_units -units off]
131
132            set $dim $v  ;# save back to real x/y/z variable
133
134            if {"" == $_limits(${dim}min)} {
135                set _limits(${dim}min) $v
136                set _limits(${dim}max) $v
137            } else {
138                if {$v < $_limits(${dim}min)} { set _limits(${dim}min) $v }
139                if {$v > $_limits(${dim}max)} { set _limits(${dim}max) $v }
140            }
141        }
142        $this-points InsertNextPoint $x $y $z
143    }
144    $this-grid SetPoints $this-points
145
146    #
147    # Extract each element and add it to the mesh.
148    #
149    foreach comp [$xmlobj children -type element $path] {
150        set nlist [$_mesh get $comp.nodes]
151        set i 0
152        foreach n $nlist {
153            [$this-vox GetPointIds] SetId $i $n
154            incr i
155        }
156        $this-grid InsertNextCell [$this-vox GetCellType] \
157            [$this-vox GetPointIds]
158    }
159}
160
161# ----------------------------------------------------------------------
162# DESTRUCTOR
163# ----------------------------------------------------------------------
164itcl::body Rappture::Mesh::destructor {} {
165    # don't destroy the _xmlobj! we don't own it!
166    itcl::delete object $_mesh
167
168    rename $this-points ""
169    rename $this-vox ""
170    rename $this-grid ""
171}
172
173# ----------------------------------------------------------------------
174# USAGE: points
175#
176# Returns the vtk object containing the points for this mesh.
177# ----------------------------------------------------------------------
178itcl::body Rappture::Mesh::points {} {
179    # not implemented
180    return $this-points
181}
182
183# ----------------------------------------------------------------------
184# USAGE: elements
185#
186# Returns a list of the form {plist r plist r ...} for each element
187# in this mesh.  Each plist is a list of {x y x y ...} coordinates
188# for the mesh.
189# ----------------------------------------------------------------------
190itcl::body Rappture::Mesh::elements {} {
191    # build a map for region number => region type
192    foreach comp [$_mesh children -type region] {
193        set id [$_mesh element -as id $comp]
194        set regions($id) [$_mesh get $comp]
195    }
196    set regions() "unknown"
197
198    set rlist ""
199    foreach comp [$_mesh children -type element] {
200        set rid [$_mesh get $comp.region]
201
202        #
203        # HACK ALERT!
204        #
205        # Prophet puts out nodes in a funny "Z" shaped order,
206        # not in proper clockwise fashion.  Switch the last
207        # two nodes for now to make them correct.
208        #
209        set nlist [$_mesh get $comp.nodes]
210        set n2 [lindex $nlist 2]
211        set n3 [lindex $nlist 3]
212        set nlist [lreplace $nlist 2 3 $n3 $n2]
213        lappend nlist [lindex $nlist 0]
214
215        set plist ""
216        foreach nid $nlist {
217            eval lappend plist [$_mesh get node($nid)]
218        }
219        lappend rlist $plist $regions($rid)
220    }
221    return $rlist
222}
223
224# ----------------------------------------------------------------------
225# USAGE: mesh
226#
227# Returns the vtk object representing the mesh.
228# ----------------------------------------------------------------------
229itcl::body Rappture::Mesh::mesh {} {
230    return $this-grid
231}
232
233# ----------------------------------------------------------------------
234# USAGE: size ?-points|-elements?
235#
236# Returns the number of points in this mesh.
237# ----------------------------------------------------------------------
238itcl::body Rappture::Mesh::size {{what -points}} {
239    switch -- $what {
240        -points {
241            return [$this-points GetNumberOfPoints]
242        }
243        -elements {
244            return [$this-points GetNumberOfCells]
245        }
246        default {
247            error "bad option \"$what\": should be -points or -elements"
248        }
249    }
250}
251
252# ----------------------------------------------------------------------
253# USAGE: dimensions
254#
255# Returns the number of dimensions for this object: 1, 2, or 3.
256# ----------------------------------------------------------------------
257itcl::body Rappture::Mesh::dimensions {} {
258    # count the dimensions with real limits
259    set dims 0
260    foreach d {x y z} {
261        if {$_limits(${d}min) != $_limits(${d}max)} {
262            incr dims
263        }
264    }
265    return $dims
266}
267
268# ----------------------------------------------------------------------
269# USAGE: limits x|y|z
270#
271# Returns the {min max} values for the limits of the specified axis.
272# ----------------------------------------------------------------------
273itcl::body Rappture::Mesh::limits {which} {
274    if {![info exists _limits(${which}min)]} {
275        error "bad axis \"$which\": should be x, y, z"
276    }
277    return [list $_limits(${which}min) $_limits(${which}max)]
278}
279
280# ----------------------------------------------------------------------
281# USAGE: hints ?<keyword>?
282#
283# Returns a list of key/value pairs for various hints about plotting
284# this field.  If a particular <keyword> is specified, then it returns
285# the hint for that <keyword>, if it exists.
286# ----------------------------------------------------------------------
287itcl::body Rappture::Mesh::hints {{keyword ""}} {
288    foreach key {label color units} {
289        set str [$_mesh get $key]
290        if {"" != $str} {
291            set hints($key) $str
292        }
293    }
294
295    if {$keyword != ""} {
296        if {[info exists hints($keyword)]} {
297            return $hints($keyword)
298        }
299        return ""
300    }
301    return [array get hints]
302}
Note: See TracBrowser for help on using the repository browser.