[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 | # ====================================================================== |
---|
| 18 | package require Itcl |
---|
| 19 | |
---|
[3330] | 20 | namespace eval Rappture { |
---|
| 21 | # forward declaration |
---|
| 22 | } |
---|
[14] | 23 | |
---|
| 24 | itcl::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 | # ---------------------------------------------------------------------- |
---|
| 109 | itcl::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 | # ---------------------------------------------------------------------- |
---|
| 130 | itcl::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 | # ---------------------------------------------------------------------- |
---|
| 150 | itcl::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 | # ---------------------------------------------------------------------- |
---|
| 228 | itcl::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] | 249 | itcl::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 | # ---------------------------------------------------------------------- |
---|
| 266 | itcl::body Rappture::Mesh::points {} { |
---|
[3475] | 267 | return "" |
---|
[14] | 268 | } |
---|
| 269 | |
---|
[3917] | 270 | # |
---|
| 271 | # units -- |
---|
| 272 | # |
---|
| 273 | # Returns the units of the given axis. |
---|
| 274 | # |
---|
| 275 | itcl::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 | # |
---|
| 287 | itcl::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 | # ---------------------------------------------------------------------- |
---|
| 301 | itcl::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] | 340 | itcl::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] | 356 | itcl::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 | # ---------------------------------------------------------------------- |
---|
| 375 | itcl::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] | 384 | itcl::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 | # ---------------------------------------------------------------------- |
---|
| 398 | itcl::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 | # ---------------------------------------------------------------------- |
---|
| 415 | itcl::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] | 430 | itcl::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] | 445 | itcl::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] | 454 | itcl::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] | 463 | itcl::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] | 501 | itcl::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] | 779 | itcl::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] | 802 | itcl::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] | 834 | itcl::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] | 866 | itcl::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 | |
---|
| 900 | itcl::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 | |
---|
| 934 | itcl::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 | |
---|
| 968 | itcl::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] | 1002 | itcl::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] | 1031 | itcl::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] | 1060 | itcl::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] | 1089 | itcl::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] | 1118 | itcl::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] | 1174 | itcl::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] | 1351 | itcl::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 | |
---|
| 1443 | itcl::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 | |
---|
| 1471 | itcl::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 | } |
---|