source: branches/r9/gui/scripts/mesh.tcl @ 4919

Last change on this file since 4919 was 4919, checked in by gah, 6 years ago
File size: 48.3 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2
3# ----------------------------------------------------------------------
4#  COMPONENT: mesh - represents a structured mesh for a device
5#
6#  This object represents a mesh in an XML description of simulator
7#  output.  A mesh is a structured arrangement of points, as elements
8#  composed of nodes representing coordinates.  This is a little
9#  different from a cloud, which is an unstructured arrangement
10#  (shotgun blast) of points.
11# ======================================================================
12#  AUTHOR:  Michael McLennan, Purdue University
13#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
14#
15#  See the file "license.terms" for information on usage and
16#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
17# ======================================================================
18package require Itcl
19
20namespace eval Rappture {
21    # forward declaration
22}
23
24itcl::class Rappture::Mesh {
25    private variable _xmlobj ""  ;      # Ref to XML obj with device data
26    private variable _mesh ""    ;      # Lib obj representing this mesh
27    private variable _dim       0;      # Dimension of mesh (1, 2, or 3)
28    private variable _type "";          # Indicates the type of mesh.
29    private variable _axis2units;       # System of units for x, y, z
30    private variable _axis2labels;      #
31    private variable _hints
32    private variable _limits        ;   # Array of mesh limits. Keys are
33                                        # xmin, xmax, ymin, ymax, ...
34    private variable _numPoints 0   ;   # # of points in mesh
35    private variable _numCells 0;       # # of cells in mesh
36    private variable _vtkdata "";       # Mesh in vtk file format.
37    private variable _isValid 0;        # Indicates if the mesh is valid.
38    constructor {xmlobj path} {
39        # defined below
40    }
41    destructor {
42        # defined below
43    }
44    public method points {}
45    public method elements {}
46    public method mesh {{-type "vtk"}}
47    public method size {{what -points}}
48    public method dimensions {}
49    public method limits {which}
50    public method units { axis }
51    public method label { axis }
52    public method hints {{key ""}}
53    public method isvalid {} {
54        return $_isValid
55    }
56    public proc fetch {xmlobj path}
57    public proc release {obj}
58    public method vtkdata {{what -partial}}
59    public method type {} {
60        return $_type
61    }
62    public method numpoints {} {
63        return $_numPoints
64    }
65    public method numcells {} {
66        return $_numCells
67    }
68
69    private common _xp2obj       ;      # used for fetch/release ref counting
70    private common _obj2ref      ;      # used for fetch/release ref counting
71    private variable _xv        ""
72    private variable _yv        ""
73    private variable _zv        ""
74    private variable _xCoords   "";     # For the blt contour only
75    private variable _yCoords   "";     # For the blt contour only
76   
77    private method ReadNodesElements {path}
78    private method GetCellCount { xNum yNum zNum }
79    private method GetDimension { path }
80    private method GetDouble { path }
81    private method GetInt { path }
82    private method InitHints {}
83    private method ReadGrid { path }
84    private method ReadUnstructuredGrid { path }
85    private method ReadVtk { path }
86    private method WriteTriangles { path xv yv zv triangles }
87    private method WriteQuads { path xv yv zv quads }
88    private method WriteVertices { path xv yv zv vertices }
89    private method WriteLines { path xv yv zv lines }
90    private method WritePolygons { path xv yv zv polygons }
91    private method WriteTriangleStrips { path xv yv zv trianglestrips }
92    private method WriteTetrahedrons { path xv yv zv tetrahedrons }
93    private method WriteHexahedrons { path xv yv zv hexhedrons }
94    private method WriteWedges { path xv yv zv wedges }
95    private method WritePyramids { path xv yv zv pyramids }
96    private method WriteHybridCells { path xv yv zv cells celltypes }
97    private method WritePointCloud { path xv yv zv }
98    private method GetCellType { name }
99    private method GetNumIndices { type }
100}
101
102# ----------------------------------------------------------------------
103# USAGE: Rappture::Mesh::fetch <xmlobj> <path>
104#
105# Clients use this instead of a constructor to fetch the Mesh for
106# a particular <path> in the <xmlobj>.  When the client is done with
107# the mesh, he calls "release" to decrement the reference count.
108# When the mesh is no longer needed, it is cleaned up automatically.
109# ----------------------------------------------------------------------
110itcl::body Rappture::Mesh::fetch {xmlobj path} {
111    set handle "$xmlobj|$path"
112    if {[info exists _xp2obj($handle)]} {
113        set obj $_xp2obj($handle)
114        incr _obj2ref($obj)
115        return $obj
116    }
117    set obj [Rappture::Mesh ::#auto $xmlobj $path]
118    set _xp2obj($handle) $obj
119    set _obj2ref($obj) 1
120    return $obj
121}
122
123# ----------------------------------------------------------------------
124# USAGE: Rappture::Mesh::release <obj>
125#
126# Clients call this when they're no longer using a Mesh fetched
127# previously by the "fetch" proc.  This decrements the reference
128# count for the mesh and destroys the object when it is no longer
129# in use.
130# ----------------------------------------------------------------------
131itcl::body Rappture::Mesh::release {obj} {
132    if {[info exists _obj2ref($obj)]} {
133        incr _obj2ref($obj) -1
134        if {$_obj2ref($obj) <= 0} {
135            unset _obj2ref($obj)
136            foreach handle [array names _xp2obj] {
137                if {$_xp2obj($handle) == $obj} {
138                    unset _xp2obj($handle)
139                }
140            }
141            itcl::delete object $obj
142        }
143    } else {
144        error "can't find reference count for $obj"
145    }
146}
147
148# ----------------------------------------------------------------------
149# CONSTRUCTOR
150# ----------------------------------------------------------------------
151itcl::body Rappture::Mesh::constructor {xmlobj path} {
152    package require vtk
153    if {![Rappture::library isvalid $xmlobj]} {
154        error "bad value \"$xmlobj\": should be Rappture::library"
155    }
156    set _xmlobj $xmlobj
157    set _mesh [$xmlobj element -as object $path]
158
159    # Initialize mesh bounds to empty
160    foreach axis {x y z} {
161        set _limits($axis) ""
162    }
163    set units [$_mesh get units]
164    set first [lindex $units 0]
165    foreach u $units axis { x y z } {
166        if { $u != "" } {
167            set _axis2units($axis) $u
168        } else {
169            set _axis2units($axis) $first
170        }
171    }
172    foreach label [$_mesh get labels] axis { x y z } {
173        if { $label != "" } {
174            set _axis2labels($axis) $label
175        } else {
176            set _axis2labels($axis) [string toupper $axis]
177        }
178    }
179
180    # Meshes comes in a variety of flavors
181    #
182    # Dimensionality is determined from the <dimension> tag. 
183    #
184    # <vtk> described mesh
185    # <element> +  <node> definitions
186    # <grid>            rectangular mesh
187    # <unstructured>    homogeneous cell type mesh.
188
189    # Check that only one mesh type was defined.
190    set subcount 0
191    foreach cname [$_mesh children] {
192        foreach type { vtk grid unstructured } {
193            if { $cname == $type } {
194                incr subcount
195                break
196            }
197        }
198    }
199    if {[$_mesh element "node"] != "" ||
200        [$_mesh element "element"] != ""} {
201        incr subcount
202    }
203
204    if { $subcount == 0 } {
205        puts stderr "WARNING: no mesh specified for \"$path\"."
206        return
207    }
208    if { $subcount > 1 } {
209        puts stderr "WARNING: too many mesh types specified for \"$path\"."
210        return
211    }
212    set result 0
213    if { [$_mesh element "vtk"] != ""} {
214        set result [ReadVtk $path]
215    } elseif {[$_mesh element "grid"] != "" } {
216        set result [ReadGrid $path]
217    } elseif {[$_mesh element "unstructured"] != "" } {
218        set result [ReadUnstructuredGrid $path]
219    } elseif {[$_mesh element "node"] != "" && [$_mesh element "element"] != ""} {
220        set result [ReadNodesElements $path]
221    }
222    set _isValid $result
223    InitHints
224}
225
226# ----------------------------------------------------------------------
227# DESTRUCTOR
228# ----------------------------------------------------------------------
229itcl::body Rappture::Mesh::destructor {} {
230    # don't destroy the _xmlobj! we don't own it!
231    itcl::delete object $_mesh
232
233    if { $_xCoords != "" } {
234        blt::vector destroy $_xCoords
235    }
236    if { $_yCoords != "" } {
237        blt::vector destroy $_yCoords
238    }
239}
240
241#
242# vtkdata --
243#
244#       This is called by the field object to generate a VTK file to send to
245#       the remote render server.  Returns the vtkDataSet object containing
246#       (at this point) just the mesh.  The field object doesn't know (or
247#       care) what type of mesh is used.  The field object will add field
248#       arrays before generating output to send to the remote render server.
249#
250itcl::body Rappture::Mesh::vtkdata {{what -partial}} {
251    if {$what == "-full"} {
252        append out "# vtk DataFile Version 3.0\n"
253        append out "[hints label]\n"
254        append out "ASCII\n"
255        append out $_vtkdata
256        return $out
257    } else {
258        return $_vtkdata
259    }
260}
261
262# ----------------------------------------------------------------------
263# USAGE: points
264#
265# Returns the vtk object containing the points for this mesh.
266# ----------------------------------------------------------------------
267itcl::body Rappture::Mesh::points {} {
268    return ""
269}
270
271#
272# units --
273#
274#       Returns the units of the given axis.
275#
276itcl::body Rappture::Mesh::units { axis } {
277    if { ![info exists _axis2units($axis)] } {
278        return ""
279    }
280    return $_axis2units($axis)
281}
282
283#
284# label --
285#
286#       Returns the label of the given axis.
287#
288itcl::body Rappture::Mesh::label { axis } {
289    if { ![info exists _axis2labels($axis)] } {
290        return ""
291    }
292    return $_axis2labels($axis)
293}
294
295# ----------------------------------------------------------------------
296# USAGE: elements
297#
298# Returns a list of the form {plist r plist r ...} for each element
299# in this mesh.  Each plist is a list of {x y x y ...} coordinates
300# for the mesh.
301# ----------------------------------------------------------------------
302itcl::body Rappture::Mesh::elements {} {
303    # build a map for region number => region type
304    foreach comp [$_mesh children -type region] {
305        set id [$_mesh element -as id $comp]
306        set regions($id) [$_mesh get $comp]
307    }
308    set regions() "unknown"
309
310    set rlist ""
311    foreach comp [$_mesh children -type element] {
312        set rid [$_mesh get $comp.region]
313
314        #
315        # HACK ALERT!
316        #
317        # Prophet puts out nodes in a funny "Z" shaped order,
318        # not in proper clockwise fashion.  Switch the last
319        # two nodes for now to make them correct.
320        #
321        set nlist [$_mesh get $comp.nodes]
322        set n2 [lindex $nlist 2]
323        set n3 [lindex $nlist 3]
324        set nlist [lreplace $nlist 2 3 $n3 $n2]
325        lappend nlist [lindex $nlist 0]
326
327        set plist ""
328        foreach nid $nlist {
329            eval lappend plist [$_mesh get node($nid)]
330        }
331        lappend rlist $plist $regions($rid)
332    }
333    return $rlist
334}
335
336# ----------------------------------------------------------------------
337# USAGE: mesh
338#
339# Returns the vtk object representing the mesh.
340# ----------------------------------------------------------------------
341itcl::body Rappture::Mesh::mesh { {type "vtk"} } {
342    switch $type {
343        "vtk" {
344            return ""
345        }
346        default {
347            error "Requested mesh type \"$type\" is unknown."
348        }
349    }
350}
351
352# ----------------------------------------------------------------------
353# USAGE: size ?-points|-elements?
354#
355# Returns the number of points in this mesh.
356# ----------------------------------------------------------------------
357itcl::body Rappture::Mesh::size {{what -points}} {
358    switch -- $what {
359        -points {
360            return $_numPoints
361        }
362        -elements {
363            return $_numCells
364        }
365        default {
366            error "bad option \"$what\": should be -points or -elements"
367        }
368    }
369}
370
371# ----------------------------------------------------------------------
372# USAGE: dimensions
373#
374# Returns the number of dimensions for this object: 1, 2, or 3.
375# ----------------------------------------------------------------------
376itcl::body Rappture::Mesh::dimensions {} {
377    return $_dim
378}
379
380# ----------------------------------------------------------------------
381# USAGE: limits x|y|z
382#
383# Returns the {min max} coords for the limits of the specified axis.
384# ----------------------------------------------------------------------
385itcl::body Rappture::Mesh::limits {axis} {
386    if {![info exists _limits($axis)]} {
387        error "bad axis \"$which\": should be x, y, z"
388    }
389    return $_limits($axis)
390}
391
392# ----------------------------------------------------------------------
393# USAGE: hints ?<keyword>?
394#
395# Returns a list of key/value pairs for various hints about plotting
396# this field.  If a particular <keyword> is specified, then it returns
397# the hint for that <keyword>, if it exists.
398# ----------------------------------------------------------------------
399itcl::body Rappture::Mesh::hints {{keyword ""}} {
400    if {$keyword != ""} {
401        if {[info exists _hints($keyword)]} {
402            return $_hints($keyword)
403        }
404        return ""
405    }
406    return [array get _hints]
407}
408
409# ----------------------------------------------------------------------
410# USAGE: InitHints
411#
412# Returns a list of key/value pairs for various hints about plotting
413# this mesh.  If a particular <keyword> is specified, then it returns
414# the hint for that <keyword>, if it exists.
415# ----------------------------------------------------------------------
416itcl::body Rappture::Mesh::InitHints {} {
417    foreach {key path} {
418        camera       camera.position
419        color        about.color
420        label        about.label
421        style        about.style
422        units        units
423    } {
424        set str [$_mesh get $path]
425        if {"" != $str} {
426            set _hints($key) $str
427        }
428    }
429    foreach {key path} {
430        toolid          tool.id
431        toolname        tool.name
432        toolcommand     tool.execute
433        tooltitle       tool.title
434        toolrevision    tool.version.application.revision
435    } {
436        set str [$_xmlobj get $path]
437        if { "" != $str } {
438            set _hints($key) $str
439        }
440    }
441}
442
443itcl::body Rappture::Mesh::GetDimension { path } {
444    set string [$_xmlobj get $path.dim]
445    if { $string == "" } {
446        puts stderr "WARNING: no tag <dim> found in mesh \"$path\"."
447        return 0
448    }
449    if { [scan $string "%d" _dim] == 1 } {
450        if { $_dim == 1 || $_dim == 2 || $_dim == 3 } {
451            return 1
452        }
453    }
454    puts stderr "WARNING: bad <dim> tag value \"$string\": should be 1, 2 or 3."
455    return 0
456}
457
458itcl::body Rappture::Mesh::GetDouble { path } {
459    set string [$_xmlobj get $path]
460    if { [scan $string "%g" value] != 1 } {
461        puts stderr "ERROR: can't get double value \"$string\" of \"$path\""
462        return 0.0
463    }
464    return $value
465}
466
467itcl::body Rappture::Mesh::GetInt { path } {
468    set string [$_xmlobj get $path]
469    if { [scan $string "%d" value] != 1 } {
470        puts stderr "ERROR: can't get integer value \"$string\" of \"$path\""
471        return 0.0
472    }
473    return $value
474}
475
476itcl::body Rappture::Mesh::ReadVtk { path } {
477    set _type "vtk"
478
479    if { ![GetDimension $path] } {
480        return 0
481    }
482    # Create a VTK file with the mesh in it. 
483    set _vtkdata [$_xmlobj get $path.vtk]
484    append out "# vtk DataFile Version 3.0\n"
485    append out "mesh\n"
486    append out "ASCII\n"
487    append out "$_vtkdata\n"
488
489     # Write the contents to a file just in case it's binary.
490    set tmpfile file[pid].vtk
491    set f [open "$tmpfile" "w"]
492    fconfigure $f -translation binary -encoding binary
493    puts $f $out
494    close $f
495
496    # Read the data back into a vtk dataset and query the bounds.
497    set reader $this-datasetreader
498    vtkDataSetReader $reader
499    $reader SetFileName $tmpfile
500    $reader Update
501    set output [$reader GetOutput]
502    set _numPoints [$output GetNumberOfPoints]
503    set _numCells [$output GetNumberOfCells]
504    foreach { xmin xmax ymin ymax zmin zmax } [$output GetBounds] break
505    set _limits(x) [list $xmin $xmax]
506    set _limits(y) [list $ymin $ymax]
507    set _limits(z) [list $zmin $zmax]
508    file delete $tmpfile
509    rename $output ""
510    rename $reader ""
511    return 1
512}
513
514itcl::body Rappture::Mesh::GetCellCount { xNum yNum zNum } {
515    set numCells 1
516    if { $xNum > 1 } {
517        set numCells [expr $numCells * ($xNum - 1)]
518    }
519    if { $yNum > 1 } {
520        set numCells [expr $numCells * ($yNum - 1)]
521    }
522    if { $zNum > 1 } {
523        set numCells [expr $numCells * ($zNum - 1)]
524    }
525    return $numCells
526}
527
528itcl::body Rappture::Mesh::ReadGrid { path } {
529    set _type "grid"
530
531    if { ![GetDimension $path] } {
532        return 0
533    }
534    set numUniform 0
535    set numRectilinear 0
536    set numCurvilinear 0
537    foreach axis { x y z } {
538        set min    [$_xmlobj get "$path.grid.${axis}axis.min"]
539        set max    [$_xmlobj get "$path.grid.${axis}axis.max"]
540        set num    [$_xmlobj get "$path.grid.${axis}axis.numpoints"]
541        set coords [$_xmlobj get "$path.grid.${axis}coords"]
542        set dim    [$_xmlobj get "$path.grid.${axis}dim"]
543        if { $min != "" && $max != "" && $num != "" && $num > 0 } {
544            set ${axis}Min $min
545            set ${axis}Max $max
546            set ${axis}Num $num
547            if {$min > $max} {
548                puts stderr "ERROR: grid $axis min can't be greater than max"
549                return 0
550            }
551            incr numUniform
552        } elseif { $coords != "" } {
553            incr numRectilinear
554            set ${axis}Coords $coords
555        } elseif { $dim != "" } {
556            set ${axis}Num $dim
557            incr numCurvilinear
558        }
559    }
560    set _dim [expr $numRectilinear + $numUniform + $numCurvilinear]
561    if { $_dim == 0 } {
562        # No data found.
563        puts stderr "WARNING: bad grid \"$path\": no data found"
564        return 0
565    }
566    if { $numCurvilinear > 0 } {
567        # This is the 2D/3D curilinear case. We found <xdim>, <ydim>, or <zdim>
568        if { $numRectilinear > 0 || $numUniform > 0 } {
569            puts stderr "WARNING: bad grid \"$path\": can't mix curvilinear and rectilinear grids."
570            return 0
571        }
572        set points [$_xmlobj get $path.grid.points]
573        if { $points == "" } {
574            puts stderr "WARNING: bad grid \"$path\": no <points> found."
575            return 0
576        }
577        if { ![info exists xNum] } {
578            puts stderr "WARNING: bad grid \"$path\": invalid dimensions for curvilinear grid: missing <xdim> from grid description."
579            return 0
580        }
581        set all [blt::vector create \#auto]
582        set xv [blt::vector create \#auto]
583        set yv [blt::vector create \#auto]
584        set zv [blt::vector create \#auto]
585        $all set $points
586        set numCoords [$all length]
587        if { [info exists zNum] } {
588            set _dim 3
589            set _numPoints [expr $xNum * $yNum * $zNum]
590            set _numCells [GetCellCount $xNum $yNum $zNum]
591            if { ($_numPoints * 3) != $numCoords } {
592                puts stderr "WARNING: bad grid \"$path\": \# of points does not match dimensions $xNum * $yNum * $zNum"
593                return 0
594            }
595            if { ($numCoords % 3) != 0 } {
596                puts stderr "WARNING: bad grid \"$path\": wrong \# of coordinates for 3D grid"
597                return 0
598            }
599            $all split $xv $yv $zv
600            foreach axis {x y z} {
601                set vector [set ${axis}v]
602                set _limits($axis) [$vector limits]
603            }
604            append out "DATASET STRUCTURED_GRID\n"
605            append out "DIMENSIONS $xNum $yNum $zNum\n"
606            append out "POINTS $_numPoints double\n"
607            append out [$all range 0 end]
608            append out "\n"
609            set _vtkdata $out
610        } elseif { [info exists yNum] } {
611            set _dim 2
612            set _numPoints [expr $xNum * $yNum]
613            set _numCells [GetCellCount $xNum $yNum 1]
614            if { ($_numPoints * 2) != $numCoords } {
615                puts stderr "WARNING: bad grid \"$path\": \# of points does not match dimensions $xNum * $yNum"
616                return 0
617            }
618            if { ($numCoords % 2) != 0 } {
619                puts stderr "WARNING: bad grid \"$path\": wrong \# of coordinates for 2D grid"
620                return 0
621            }
622            foreach axis {x y} {
623                set vector [set ${axis}v]
624                set _limits($axis) [$vector limits]
625            }
626            set _limits(z) [list 0 0]
627            $zv seq 0 0 [$xv length]
628            $all merge $xv $yv $zv
629            append out "DATASET STRUCTURED_GRID\n"
630            append out "DIMENSIONS $xNum $yNum 1\n"
631            append out "POINTS $_numPoints double\n"
632            append out [$all range 0 end]
633            append out "\n"
634            set _vtkdata $out
635        } else {
636            set _dim 1
637            set _numPoints $xNum
638            set _numCells [GetCellCount $xNum 1 1]
639            if { $_numPoints != $numCoords } {
640                puts stderr "WARNING: bad grid \"$path\": \# of points does not match $xNum"
641                return 0
642            }
643            set _limits(x) [$xv limits]
644            set _limits(y) [list 0 0]
645            set _limits(z) [list 0 0]
646            $yv seq 0 0 [$xv length]
647            $zv seq 0 0 [$xv length]
648            $all merge $xv $yv $zv
649            append out "DATASET STRUCTURED_GRID\n"
650            append out "DIMENSIONS $xNum 1 1\n"
651            append out "POINTS $_numPoints double\n"
652            append out [$all range 0 end]
653            append out "\n"
654            set _vtkdata $out
655        }
656        blt::vector destroy $all $xv $yv $zv
657        return 1
658    }
659    if { $numRectilinear == 0 && $numUniform > 0} {
660        # This is the special case where all axes 2D/3D are uniform. 
661        # This results in a STRUCTURED_POINTS
662        if { $_dim == 1 } {
663            set xSpacing 0
664            if { $xNum > 1 } {
665                set xSpacing [expr ($xMax - $xMin) / double($xNum - 1)]
666            }
667            set _numPoints $xNum
668            set _numCells [GetCellCount $xNum 1 1]
669            append out "DATASET STRUCTURED_POINTS\n"
670            append out "DIMENSIONS $xNum 1 1\n"
671            append out "ORIGIN $xMin 0 0\n"
672            append out "SPACING $xSpacing 0 0\n"
673            set _vtkdata $out
674            set _limits(x) [list $xMin $xMax]
675            set _limits(y) [list 0 0]
676            set _limits(z) [list 0 0]
677        } elseif { $_dim == 2 } {
678            set xSpacing 0
679            set ySpacing 0
680            if { $xNum > 1 } {
681                set xSpacing [expr ($xMax - $xMin) / double($xNum - 1)]
682            }
683            if { $yNum > 1 } {
684                set ySpacing [expr ($yMax - $yMin) / double($yNum - 1)]
685            }
686            set _numPoints [expr $xNum * $yNum]
687            set _numCells [GetCellCount $xNum $yNum 1]
688            append out "DATASET STRUCTURED_POINTS\n"
689            append out "DIMENSIONS $xNum $yNum 1\n"
690            append out "ORIGIN $xMin $yMin 0\n"
691            append out "SPACING $xSpacing $ySpacing 0\n"
692            set _vtkdata $out
693            foreach axis {x y} {
694                set _limits($axis) [list [set ${axis}Min] [set ${axis}Max]]
695            }
696            set _limits(z) [list 0 0]
697        } elseif { $_dim == 3 } {
698            set xSpacing 0
699            set ySpacing 0
700            set zSpacing 0
701            if {$xNum > 1} {
702                set xSpacing [expr ($xMax - $xMin) / double($xNum - 1)]
703            }
704            if {$yNum > 1} {
705                set ySpacing [expr ($yMax - $yMin) / double($yNum - 1)]
706            }
707            if {$zNum > 1} {
708                set zSpacing [expr ($zMax - $zMin) / double($zNum - 1)]
709            }
710            set _numPoints [expr $xNum * $yNum * $zNum]
711            set _numCells [GetCellCount $xNum $yNum $zNum]
712            append out "DATASET STRUCTURED_POINTS\n"
713            append out "DIMENSIONS $xNum $yNum $zNum\n"
714            append out "ORIGIN $xMin $yMin $zMin\n"
715            append out "SPACING $xSpacing $ySpacing $zSpacing\n"
716            set _vtkdata $out
717            foreach axis {x y z} {
718                set _limits($axis) [list [set ${axis}Min] [set ${axis}Max]]
719            }
720        } else {
721            puts stderr "WARNING: bad grid \"$path\": bad dimension \"$_dim\""
722            return 0
723        }
724        return 1
725    }
726    # This is the hybrid case.  Some axes are uniform, others are nonuniform.
727    set xv [blt::vector create \#auto]
728    if { [info exists xMin] } {
729        $xv seq $xMin $xMax $xNum
730    } else {
731        $xv set [$_xmlobj get $path.grid.xcoords]
732        set xMin [$xv min]
733        set xMax [$xv max]
734        set xNum [$xv length]
735    }
736    set yv [blt::vector create \#auto]
737    if { $_dim > 1 } {
738        if { [info exists yMin] } {
739            $yv seq $yMin $yMax $yNum
740        } else {
741            $yv set [$_xmlobj get $path.grid.ycoords]
742            set yMin [$yv min]
743            set yMax [$yv max]
744            set yNum [$yv length]
745        }
746    } else {
747        set yNum 1
748    }
749    set zv [blt::vector create \#auto]
750    if { $_dim == 3 } {
751        if { [info exists zMin] } {
752            $zv seq $zMin $zMax $zNum
753        }  else {
754            $zv set [$_xmlobj get $path.grid.zcoords]
755            set zMin [$zv min]
756            set zMax [$zv max]
757            set zNum [$zv length]
758        }
759    } else {
760        set zNum 1
761    }
762    if { $_dim == 3 } {
763        set _numPoints [expr $xNum * $yNum * $zNum]
764        set _numCells [GetCellCount $xNum $yNum $zNum]
765        append out "DATASET RECTILINEAR_GRID\n"
766        append out "DIMENSIONS $xNum $yNum $zNum\n"
767        append out "X_COORDINATES $xNum double\n"
768        append out [$xv range 0 end]
769        append out "\n"
770        append out "Y_COORDINATES $yNum double\n"
771        append out [$yv range 0 end]
772        append out "\n"
773        append out "Z_COORDINATES $zNum double\n"
774        append out [$zv range 0 end]
775        append out "\n"
776        set _vtkdata $out
777        foreach axis {x y z} {
778            if { [info exists ${axis}Min] } {
779                set _limits($axis) [list [set ${axis}Min] [set ${axis}Max]]
780            }
781        }
782    } elseif { $_dim == 2 } {
783        set _numPoints [expr $xNum * $yNum]
784        set _numCells [GetCellCount $xNum $yNum 1]
785        append out "DATASET RECTILINEAR_GRID\n"
786        append out "DIMENSIONS $xNum $yNum 1\n"
787        append out "X_COORDINATES $xNum double\n"
788        append out [$xv range 0 end]
789        append out "\n"
790        append out "Y_COORDINATES $yNum double\n"
791        append out [$yv range 0 end]
792        append out "\n"
793        append out "Z_COORDINATES 1 double\n"
794        append out "0\n"
795        foreach axis {x y} {
796            if { [info exists ${axis}Min] } {
797                set _limits($axis) [list [set ${axis}Min] [set ${axis}Max]]
798            }
799        }
800        set _limits(z) [list 0 0]
801        set _vtkdata $out
802    } elseif { $_dim == 1 } {
803        set _numPoints $xNum
804        set _numCells [GetCellCount $xNum 1 1]
805        append out "DATASET RECTILINEAR_GRID\n"
806        append out "DIMENSIONS $xNum 1 1\n"
807        append out "X_COORDINATES $xNum double\n"
808        append out [$xv range 0 end]
809        append out "\n"
810        append out "Y_COORDINATES 1 double\n"
811        append out "0\n"
812        append out "Z_COORDINATES 1 double\n"
813        append out "0\n"
814        if { [info exists xMin] } {
815            set _limits(x) [list $xMin $xMax]
816        }
817        set _limits(y) [list 0 0]
818        set _limits(z) [list 0 0]
819        set _vtkdata $out
820    } else {
821        puts stderr "WARNING: bad grid \"$path\": invalid dimension \"$_dim\""
822        return 0
823    }
824    blt::vector destroy $xv $yv $zv
825    return 1
826}
827
828itcl::body Rappture::Mesh::WritePointCloud { path xv yv zv } {
829    set _type "cloud"
830    set _numPoints [$xv length]
831    append out "DATASET POLYDATA\n"
832    append out "POINTS $_numPoints double\n"
833    foreach x [$xv range 0 end] y [$yv range 0 end] z [$zv range 0 end] {
834        append out "$x $y $z\n"
835    }
836    set _vtkdata $out
837    set _limits(x) [$xv limits]
838    if { $_dim > 1 } {
839        set _limits(y) [$yv limits]
840    } else {
841        set _limits(y) [list 0 0]
842    }
843    if { $_dim == 3 } {
844        set _limits(z) [$zv limits]
845    } else {
846        set _limits(z) [list 0 0]
847    }
848    return 1
849}
850
851itcl::body Rappture::Mesh::WriteTriangles { path xv yv zv triangles } {
852    set _type "triangles"
853    set _numPoints [$xv length]
854    set _numCells 0
855    set data {}
856    set celltypes {}
857    foreach { a b c } $triangles {
858        append data " 3 $a $b $c\n"
859        append celltypes "5\n"
860        incr _numCells
861    }
862    append out "DATASET UNSTRUCTURED_GRID\n"
863    append out "POINTS $_numPoints double\n"
864    foreach x [$xv range 0 end] y [$yv range 0 end] z [$zv range 0 end] {
865        append out " $x $y $z\n"
866    }
867    set count [expr $_numCells * 4]
868    append out "CELLS $_numCells $count\n"
869    append out $data
870    append out "CELL_TYPES $_numCells\n"
871    append out $celltypes
872    set _limits(x) [$xv limits]
873    set _limits(y) [$yv limits]
874    if { $_dim == 3 } {
875        set _limits(z) [$zv limits]
876    } else {
877        set _limits(z) [list 0 0]
878    }
879    set _vtkdata $out
880    return 1
881}
882
883itcl::body Rappture::Mesh::WriteQuads { path xv yv zv quads } {
884    set _type "quads"
885    set _numPoints [$xv length]
886    set _numCells 0
887    set data {}
888    set celltypes {}
889    foreach { a b c d } $quads {
890        append data " 4 $a $b $c $d\n"
891        append celltypes "9\n"
892        incr _numCells
893    }
894    append out "DATASET UNSTRUCTURED_GRID\n"
895    append out "POINTS $_numPoints double\n"
896    foreach x [$xv range 0 end] y [$yv range 0 end] z [$zv range 0 end] {
897        append out " $x $y $z\n"
898    }
899    set count [expr $_numCells * 5]
900    append out "CELLS $_numCells $count\n"
901    append out $data
902    append out "CELL_TYPES $_numCells\n"
903    append out $celltypes
904    set _limits(x) [$xv limits]
905    set _limits(y) [$yv limits]
906    if { $_dim == 3 } {
907        set _limits(z) [$zv limits]
908    } else {
909        set _limits(z) [list 0 0]
910    }
911    set _vtkdata $out
912    return 1
913}
914
915itcl::body Rappture::Mesh::WriteVertices { path xv yv zv vertices } {
916    set _type "vertices"
917    set _numPoints [$xv length]
918    set _numCells 0
919    set data {}
920    set lines [split $vertices \n]
921    set count 0
922    foreach { line } $lines {
923        set numIndices [llength $line]
924        if { $numIndices == 0 } {
925            continue
926        }
927        append data " $numIndices $line\n"
928        incr _numCells
929        set count [expr $count + $numIndices + 1]
930    }
931    append out "DATASET POLYDATA\n"
932    append out "POINTS $_numPoints double\n"
933    foreach x [$xv range 0 end] y [$yv range 0 end] z [$zv range 0 end] {
934        append out " $x $y $z\n"
935    }
936    append out "VERTICES $_numCells $count\n"
937    append out $data
938    set _limits(x) [$xv limits]
939    set _limits(y) [$yv limits]
940    if { $_dim == 3 } {
941        set _limits(z) [$zv limits]
942    } else {
943        set _limits(z) [list 0 0]
944    }
945    set _vtkdata $out
946    return 1
947}
948
949itcl::body Rappture::Mesh::WriteLines { path xv yv zv polylines } {
950    set _type "lines"
951    set _numPoints [$xv length]
952    set _numCells 0
953    set data {}
954    set lines [split $polylines \n]
955    set count 0
956    foreach { line } $lines {
957        set numIndices [llength $line]
958        if { $numIndices == 0 } {
959            continue
960        }
961        append data " $numIndices $line\n"
962        incr _numCells
963        set count [expr $count + $numIndices + 1]
964    }
965    append out "DATASET POLYDATA\n"
966    append out "POINTS $_numPoints double\n"
967    foreach x [$xv range 0 end] y [$yv range 0 end] z [$zv range 0 end] {
968        append out " $x $y $z\n"
969    }
970    append out "LINES $_numCells $count\n"
971    append out $data
972    set _limits(x) [$xv limits]
973    set _limits(y) [$yv limits]
974    if { $_dim == 3 } {
975        set _limits(z) [$zv limits]
976    } else {
977        set _limits(z) [list 0 0]
978    }
979    set _vtkdata $out
980    return 1
981}
982
983itcl::body Rappture::Mesh::WritePolygons { path xv yv zv polygons } {
984    set _type "polygons"
985    set _numPoints [$xv length]
986    set _numCells 0
987    set data {}
988    set lines [split $polygons \n]
989    set count 0
990    foreach { line } $lines {
991        set numIndices [llength $line]
992        if { $numIndices == 0 } {
993            continue
994        }
995        append data " $numIndices $line\n"
996        incr _numCells
997        set count [expr $count + $numIndices + 1]
998    }
999    append out "DATASET POLYDATA\n"
1000    append out "POINTS $_numPoints double\n"
1001    foreach x [$xv range 0 end] y [$yv range 0 end] z [$zv range 0 end] {
1002        append out " $x $y $z\n"
1003    }
1004    append out "POLYGONS $_numCells $count\n"
1005    append out $data
1006    set _limits(x) [$xv limits]
1007    set _limits(y) [$yv limits]
1008    if { $_dim == 3 } {
1009        set _limits(z) [$zv limits]
1010    } else {
1011        set _limits(z) [list 0 0]
1012    }
1013    set _vtkdata $out
1014    return 1
1015}
1016
1017itcl::body Rappture::Mesh::WriteTriangleStrips { path xv yv zv trianglestrips } {
1018    set _type "trianglestrips"
1019    set _numPoints [$xv length]
1020    set _numCells 0
1021    set data {}
1022    set lines [split $trianglestrips \n]
1023    set count 0
1024    foreach { line } $lines {
1025        set numIndices [llength $line]
1026        if { $numIndices == 0 } {
1027            continue
1028        }
1029        append data " $numIndices $line\n"
1030        incr _numCells
1031        set count [expr $count + $numIndices + 1]
1032    }
1033    append out "DATASET POLYDATA\n"
1034    append out "POINTS $_numPoints double\n"
1035    foreach x [$xv range 0 end] y [$yv range 0 end] z [$zv range 0 end] {
1036        append out " $x $y $z\n"
1037    }
1038    append out "TRIANGLE_STRIPS $_numCells $count\n"
1039    append out $data
1040    set _limits(x) [$xv limits]
1041    set _limits(y) [$yv limits]
1042    if { $_dim == 3 } {
1043        set _limits(z) [$zv limits]
1044    } else {
1045        set _limits(z) [list 0 0]
1046    }
1047    set _vtkdata $out
1048    return 1
1049}
1050
1051itcl::body Rappture::Mesh::WriteTetrahedrons { path xv yv zv tetras } {
1052    set _type "tetrahedrons"
1053    set _numPoints [$xv length]
1054    set _numCells 0
1055    set data {}
1056    set celltypes {}
1057    foreach { a b c d } $tetras {
1058        append data " 4 $a $b $c $d\n"
1059        append celltypes "10\n"
1060        incr _numCells
1061    }
1062    append out "DATASET UNSTRUCTURED_GRID\n"
1063    append out "POINTS $_numPoints double\n"
1064    foreach x [$xv range 0 end] y [$yv range 0 end] z [$zv range 0 end] {
1065        append out " $x $y $z\n"
1066    }
1067    set count [expr $_numCells * 5]
1068    append out "CELLS $_numCells $count\n"
1069    append out $data
1070    append out "CELL_TYPES $_numCells\n"
1071    append out $celltypes
1072    set _limits(x) [$xv limits]
1073    set _limits(y) [$yv limits]
1074    set _limits(z) [$zv limits]
1075
1076    set _vtkdata $out
1077    return 1
1078}
1079
1080itcl::body Rappture::Mesh::WriteHexahedrons { path xv yv zv hexas } {
1081    set _type "hexahedrons"
1082    set _numPoints [$xv length]
1083    set _numCells 0
1084    set data {}
1085    set celltypes {}
1086    foreach { a b c d e f g h } $hexas {
1087        append data " 8 $a $b $c $d $e $f $g $h\n"
1088        append celltypes "12\n"
1089        incr _numCells
1090    }
1091    append out "DATASET UNSTRUCTURED_GRID\n"
1092    append out "POINTS $_numPoints double\n"
1093    foreach x [$xv range 0 end] y [$yv range 0 end] z [$zv range 0 end] {
1094        append out " $x $y $z\n"
1095    }
1096    set count [expr $_numCells * 9]
1097    append out "CELLS $_numCells $count\n"
1098    append out $data
1099    append out "CELL_TYPES $_numCells\n"
1100    append out $celltypes
1101    set _limits(x) [$xv limits]
1102    set _limits(y) [$yv limits]
1103    set _limits(z) [$zv limits]
1104
1105    set _vtkdata $out
1106    return 1
1107}
1108
1109itcl::body Rappture::Mesh::WriteWedges { path xv yv zv wedges } {
1110    set _type "wedges"
1111    set _numPoints [$xv length]
1112    set _numCells 0
1113    set data {}
1114    set celltypes {}
1115    foreach { a b c d e f } $wedges {
1116        append data " 6 $a $b $c $d $e $f\n"
1117        append celltypes "13\n"
1118        incr _numCells
1119    }
1120    append out "DATASET UNSTRUCTURED_GRID\n"
1121    append out "POINTS $_numPoints double\n"
1122    foreach x [$xv range 0 end] y [$yv range 0 end] z [$zv range 0 end] {
1123        append out " $x $y $z\n"
1124    }
1125    set count [expr $_numCells * 7]
1126    append out "CELLS $_numCells $count\n"
1127    append out $data
1128    append out "CELL_TYPES $_numCells\n"
1129    append out $celltypes
1130    set _limits(x) [$xv limits]
1131    set _limits(y) [$yv limits]
1132    set _limits(z) [$zv limits]
1133
1134    set _vtkdata $out
1135    return 1
1136}
1137
1138itcl::body Rappture::Mesh::WritePyramids { path xv yv zv pyramids } {
1139    set _type "pyramids"
1140    set _numPoints [$xv length]
1141    set _numCells 0
1142    set data {}
1143    set celltypes {}
1144    foreach { a b c d e } $pyramids {
1145        append data " 5 $a $b $c $d $e\n"
1146        append celltypes "14\n"
1147        incr _numCells
1148    }
1149    append out "DATASET UNSTRUCTURED_GRID\n"
1150    append out "POINTS $_numPoints double\n"
1151    foreach x [$xv range 0 end] y [$yv range 0 end] z [$zv range 0 end] {
1152        append out " $x $y $z\n"
1153    }
1154    set count [expr $_numCells * 6]
1155    append out "CELLS $_numCells $count\n"
1156    append out $data
1157    append out "CELL_TYPES $_numCells\n"
1158    append out $celltypes
1159    set _limits(x) [$xv limits]
1160    set _limits(y) [$yv limits]
1161    set _limits(z) [$zv limits]
1162
1163    set _vtkdata $out
1164    return 1
1165}
1166
1167itcl::body Rappture::Mesh::WriteHybridCells { path xv yv zv cells celltypes } {
1168    set _type "unstructured"
1169    set lines [split $cells \n]
1170    set numCellTypes [llength $celltypes]
1171    if { $numCellTypes == 1 } {
1172        set celltype [GetCellType $celltypes]
1173    }
1174
1175    set _numPoints [$xv length]
1176    set data {}
1177    set count 0
1178    set _numCells 0
1179    set celltypes {}
1180    foreach line $lines {
1181        set length [llength $line]
1182        if { $length == 0 } {
1183            continue
1184        }
1185        if { $numCellTypes > 1 } {
1186            set cellType [GetCellType [lindex $cellTypes $_numCells]]
1187        }
1188        set numIndices [GetNumIndices $celltype]
1189        if { $numIndices > 0 && $numIndices != $length } {
1190            puts stderr "WARNING: bad unstructured grid \"$path\": wrong \# of indices specified for celltype $celltype on line \"$line\""
1191            return 0
1192        } else {
1193            set numIndices $length
1194        }
1195        append data " $numIndices $line\n"
1196        lappend celltypes $celltype
1197        incr count $length;         # Include the indices
1198        incr count;                 # and the number of indices
1199        incr _numCells
1200    }
1201    append out "DATASET UNSTRUCTURED_GRID\n"
1202    append out "POINTS $_numPoints double\n"
1203    set all [blt::vector create \#auto]
1204    $all merge $xv $yv $zv
1205    append out [$all range 0 end]
1206    blt::vector destroy $all
1207    append out "CELLS $_numCells $count\n"
1208    append out $data
1209    append out "CELL_TYPES $_numCells\n"
1210    append out $celltypes
1211    set _limits(x) [$xv limits]
1212    set _limits(y) [$yv limits]
1213    if { $_dim < 3 } {
1214        set _limits(z) [list 0 0]
1215    } else {
1216        set _limits(z) [$zv limits]
1217    }
1218
1219    set _vtkdata $out
1220    return 1
1221}
1222
1223itcl::body Rappture::Mesh::ReadUnstructuredGrid { path } {
1224    set _type "unstructured"
1225
1226    if { ![GetDimension $path] } {
1227        return 0
1228    }
1229    # Step 1: Verify that there's only one cell tag of any kind.
1230    set numCells 0
1231    foreach type {
1232        cells
1233        hexahedrons
1234        lines
1235        polygons
1236        pyramids
1237        quads
1238        tetrahedrons
1239        triangles
1240        trianglestrips
1241        vertices
1242        wedges
1243    } {
1244        set data [$_xmlobj get $path.unstructured.$type]
1245        if { $data != "" } {
1246            incr numCells
1247        }
1248    }
1249    # The generic <cells> tag requires there be a <celltypes> tag too.
1250    set celltypes [$_xmlobj get $path.unstructured.celltypes]
1251    if { $numCells == 0 && $celltypes != "" } {
1252        puts stderr "WARNING: bad unstuctured grid \"$path\": no <cells> description found."
1253        return 0
1254    }
1255    if { $numCells > 1 } {
1256        puts stderr "WARNING: bad unstructured grid \"$path\": too many <cells>, <triangles>, <quads>... descriptions found: should be only one."
1257        return 0
1258    }
1259    foreach type {
1260        cells
1261        hexahedrons
1262        lines
1263        polygons
1264        pyramids
1265        quads
1266        tetrahedrons
1267        triangles
1268        trianglestrips
1269        vertices
1270        wedges
1271    } {
1272        set data [$_xmlobj get $path.unstructured.$type]
1273        if { $data != "" } {
1274            break
1275        }
1276    }
1277    # Step 2: Allow points to be specified as <points> or
1278    #         <xcoords>, <ycoords>, <zcoords>.  Split and convert into
1279    #         3 vectors, one for each coordinate.
1280    if { $_dim == 1 } {
1281        set xcoords [$_xmlobj get $path.unstructured.xcoords]
1282        set ycoords [$_xmlobj get $path.unstructured.ycoords]
1283        set zcoords [$_xmlobj get $path.unstructured.zcoords]
1284        set data    [$_xmlobj get $path.unstructured.points]
1285        if { $ycoords != "" } {
1286            put stderr "can't specify <ycoords> with a 1D mesh"
1287            return 0
1288        }
1289        if { $zcoords != "" } {
1290            put stderr "can't specify <zcoords> with a 1D mesh"
1291            return 0
1292        }
1293        if { $xcoords != "" } {
1294            set xv [blt::vector create \#auto]
1295            $xv set $xcoords
1296        } elseif { $data != "" } {
1297            Rappture::ReadPoints $data dim points
1298            if { $points == "" } {
1299                puts stderr "WARNING: bad unstructured grid \"$path\": no <points> found."
1300                return 0
1301            }
1302            if { $dim != 1 } {
1303                puts stderr "WARNING: bad unstructured grid \"$path\": \# of coordinates per point is \"$dim\": does not agree with dimension specified for mesh \"$_dim\""
1304                return 0
1305            }
1306            set xv [blt::vector create \#auto]
1307            $xv set $points
1308        } else {
1309            puts stderr "WARNING: bad unstructured grid \"$path\": no points specified."
1310            return 0
1311        }
1312        set yv [blt::vector create \#auto]
1313        set zv [blt::vector create \#auto]
1314        $yv seq 0 0 [$xv length];       # Make an all zeroes vector.
1315        $zv seq 0 0 [$xv length];       # Make an all zeroes vector.
1316    } elseif { $_dim == 2 } {
1317        set xcoords [$_xmlobj get $path.unstructured.xcoords]
1318        set ycoords [$_xmlobj get $path.unstructured.ycoords]
1319        set zcoords [$_xmlobj get $path.unstructured.zcoords]
1320        set data    [$_xmlobj get $path.unstructured.points]
1321        if { $zcoords != "" } {
1322            put stderr "can't specify <zcoords> with a 2D mesh"
1323            return 0
1324        }
1325        if { $xcoords != "" && $ycoords != "" } {
1326            set xv [blt::vector create \#auto]
1327            set yv [blt::vector create \#auto]
1328            $xv set $xcoords
1329            $yv set $ycoords
1330        } elseif { $data != "" } {
1331            Rappture::ReadPoints $data dim points
1332            if { $points == "" } {
1333                puts stderr "WARNING: bad unstructured grid \"$path\": no <points> found."
1334                return 0
1335            }
1336            if { $dim != 2 } {
1337                puts stderr "WARNING: bad unstructured grid \"$path\": \# of coordinates per point is \"$dim\": does not agree with dimension specified for mesh \"$_dim\""
1338                return 0
1339            }
1340            set all [blt::vector create \#auto]
1341            set xv [blt::vector create \#auto]
1342            set yv [blt::vector create \#auto]
1343            $all set $points
1344            $all split $xv $yv
1345            blt::vector destroy $all
1346        } else {
1347            puts stderr "WARNING: bad unstructured grid \"$path\": no points specified."
1348            return 0
1349        }
1350        set zv [blt::vector create \#auto]
1351        $zv seq 0 0 [$xv length];       # Make an all zeroes vector.
1352    } elseif { $_dim == 3 } {
1353        set xcoords [$_xmlobj get $path.unstructured.xcoords]
1354        set ycoords [$_xmlobj get $path.unstructured.ycoords]
1355        set zcoords [$_xmlobj get $path.unstructured.zcoords]
1356        set data    [$_xmlobj get $path.unstructured.points]
1357        if { $xcoords != "" && $ycoords != "" && $zcoords != "" } {
1358            set xv [blt::vector create \#auto]
1359            set yv [blt::vector create \#auto]
1360            set zv [blt::vector create \#auto]
1361            $xv set $xcoords
1362            $yv set $ycoords
1363            $zv set $zcoords
1364        } elseif { $data != "" }  {
1365            Rappture::ReadPoints $data dim points
1366            if { $points == "" } {
1367                puts stderr "WARNING: bad unstructured grid \"$path\": no <points> found."
1368                return 0
1369            }
1370            if { $dim != 3 } {
1371                puts stderr "WARNING: bad unstructured grid \"$path\": \# of coordinates per point is \"$dim\": does not agree with dimension specified for mesh \"$_dim\""
1372                return 0
1373            }
1374            set all [blt::vector create \#auto]
1375            set xv [blt::vector create \#auto]
1376            set yv [blt::vector create \#auto]
1377            set zv [blt::vector create \#auto]
1378            $all set $points
1379            $all split $xv $yv $zv
1380            blt::vector destroy $all
1381        } else {
1382            puts stderr "WARNING: bad unstructured grid \"$path\": no points specified."
1383            return 0
1384        }
1385    }
1386    set _numPoints [$xv length]
1387
1388    # Step 3: Write the points and cells as vtk data.
1389    if { $numCells == 0 } {
1390        set result [WritePointCloud $path $xv $yv $zv]
1391    } elseif { $type == "cells" } {
1392        set cells [$_xmlobj get $path.unstructured.cells]
1393        if { $cells == "" } {
1394            puts stderr "WARNING: bad unstructured grid \"$path\": no cells found."
1395            return 0
1396        }
1397        set result [WriteHybridCells $path $xv $yv $zv $cells $celltypes]
1398    } else {
1399        set cmd "Write[string totitle $type]"
1400        set cells [$_xmlobj get $path.unstructured.$type]
1401        if { $cells == "" } {
1402            puts stderr "WARNING: bad unstructured grid \"$path\": no cells found."
1403            return 0
1404        }
1405        set result [$cmd $path $xv $yv $zv $cells]
1406    }
1407    # Clean up.
1408    blt::vector destroy $xv $yv $zv
1409    return $result
1410}
1411
1412# ----------------------------------------------------------------------
1413# USAGE: ReadNodesElements <path>
1414#
1415# Used internally to build a mesh representation based on nodes and
1416# elements stored in the XML.
1417# ----------------------------------------------------------------------
1418itcl::body Rappture::Mesh::ReadNodesElements {path} {
1419    set _type "nodeselements"
1420    set count 0
1421
1422    # Scan for nodes.  Each node represents a vertex.
1423    set data {}
1424    foreach cname [$_xmlobj children -type node $path] {
1425        append data "[$_xmlobj get $path.$cname]\n"
1426    }   
1427    Rappture::ReadPoints $data _dim points
1428    if { $_dim == 2 } {
1429        set all [blt::vector create \#auto]
1430        set xv [blt::vector create \#auto]
1431        set yv [blt::vector create \#auto]
1432        set zv [blt::vector create \#auto]
1433        $all set $points
1434        $all split $xv $yv
1435        set _numPoints [$xv length]
1436        set _limits(x) [$xv limits]
1437        set _limits(y) [$yv limits]
1438        set _limits(z) [list 0 0]
1439        # 2D Dataset. All Z coordinates are 0
1440        $zv seq 0.0 0.0 $_numPoints
1441        $all merge $xv $yv $zv
1442        set points [$all range 0 end]
1443        blt::vector destroy $all $xv $yv $zv
1444    } elseif { $_dim == 3 } {
1445        set all [blt::vector create \#auto]
1446        set xv [blt::vector create \#auto]
1447        set yv [blt::vector create \#auto]
1448        set zv [blt::vector create \#auto]
1449        $all set $points
1450        $all split $xv $yv $zv
1451        set _numPoints [$xv length]
1452        set _limits(x) [$xv limits]
1453        set _limits(y) [$yv limits]
1454        set _limits(z) [$zv limits]
1455        set points [$all range 0 end]
1456        blt::vector destroy $all $xv $yv $zv
1457    } else {
1458        error "bad dimension \"$_dim\" for nodes mesh"
1459    }
1460    array set node2celltype {
1461        3 5
1462        4 10
1463        8 12
1464        6 13
1465        5 14
1466    }
1467    set count 0
1468    set _numCells 0
1469    set celltypes {}
1470    set data {}
1471    # Next scan for elements.  Each element represents a cell.
1472    foreach cname [$_xmlobj children -type element $path] {
1473        set nodeList [$_mesh get $cname.nodes]
1474        set numNodes [llength $nodeList]
1475        if { ![info exists node2celltype($numNodes)] } {
1476            puts stderr "WARNING: bad nodes/elements mesh \$path\": unknown number of indices \"$_numNodes\": should be 3, 4, 5, 6, or 8"
1477            return 0
1478        }
1479        set celltype $node2celltype($numNodes)
1480        append celltypes "  $celltype\n"
1481        if { $celltype == 12 } {
1482            # Formerly used voxels instead of hexahedrons. We're converting
1483            # it here to be backward compatible and still fault-tolerant of
1484            # non-axis aligned cells.
1485            set newList {}
1486            foreach i { 0 1 3 2 4 5 7 6 } {
1487                lappend newList [lindex $nodeList $i]
1488            }
1489            set nodeList $newList
1490        }
1491        append data "  $numNodes $nodeList\n"
1492        incr _numCells
1493        incr count $numNodes
1494        incr count;                     # One extra for the VTK celltype id.
1495    }
1496
1497    append out "DATASET UNSTRUCTURED_GRID\n"
1498    append out "POINTS $_numPoints double\n"
1499    append out $points
1500    append out "\n"
1501    append out "CELLS $_numCells $count\n"
1502    append out $data
1503    append out "CELL_TYPES $_numCells\n"
1504    append out $celltypes
1505    append out "\n"
1506    set _vtkdata $out
1507    set _isValid 1
1508}
1509
1510itcl::body Rappture::Mesh::GetCellType { name } {
1511    array set name2type {
1512        "vertex"          1
1513        "polyvertex"      2
1514        "line"            3
1515        "polyline"        4
1516        "triangle"        5
1517        "trianglestrip"   6
1518        "polygon"         7
1519        "pixel"           8
1520        "quad"            9
1521        "tetrahedron"     10
1522        "voxel"           11
1523        "hexahedron"      12
1524        "wedge"           13
1525        "pyramid"         14
1526        "pentagonalprism" 15
1527        "hexagonalprism"  16
1528    }
1529    if { [info exists name2type($name)] } {
1530        return $name2type($name)
1531    }
1532    if { [string is int $name] == 1 && $name >= 1 && $name <= 16 } {
1533        return $name
1534    }
1535    error "invalid celltype \"$name\""
1536}
1537
1538itcl::body Rappture::Mesh::GetNumIndices { type } {
1539    array set type2indices {
1540        1       1
1541        2       0
1542        3       2
1543        4       0
1544        5       3
1545        6       0
1546        7       0
1547        8       4
1548        9       4
1549        10      4
1550        11      8
1551        12      8
1552        13      6
1553        14      5
1554        15      10
1555        16      12
1556    }
1557    if { [info exists type2indices($type)] } {
1558        return $type2indices($type)
1559    }
1560    error "invalid celltype \"$type\""
1561}
Note: See TracBrowser for help on using the repository browser.