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

Last change on this file since 4418 was 4418, checked in by ldelgass, 10 years ago

support vertices,lines,polygons,trianglestrips lists in unstructured grids

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