source: trunk/gui/scripts/contourresult.tcl @ 438

Last change on this file since 438 was 413, checked in by mmc, 19 years ago
  • Added <description> capability to output objects, including axes.
  • Fixed the ResultSet? so that it is more compact and supports the simulation number as a parameter. This is useful when there are datasets with wildly varying parameters.
File size: 42.5 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: contourresult - contour plot in a ResultSet
3#
4#  This widget is a contour plot for 2D meshes with a scalar value.
5#  It is normally used in the ResultViewer to show results from the
6#  run of a Rappture tool.  Use the "add" and "delete" methods to
7#  control the dataobjs showing on the plot.
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2005  Purdue Research Foundation
11#
12#  See the file "license.terms" for information on usage and
13#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14# ======================================================================
15package require Itk
16package require vtk
17package require vtkinteraction
18package require BLT
19package require Img
20
21option add *ContourResult.width 4i widgetDefault
22option add *ContourResult.height 4i widgetDefault
23option add *ContourResult.foreground black widgetDefault
24option add *ContourResult.controlBackground gray widgetDefault
25option add *ContourResult.controlDarkBackground #999999 widgetDefault
26option add *ContourResult.plotBackground black widgetDefault
27option add *ContourResult.plotForeground white widgetDefault
28option add *ContourResult.font \
29    -*-helvetica-medium-r-normal-*-*-120-* widgetDefault
30
31itcl::class Rappture::ContourResult {
32    inherit itk::Widget
33
34    itk_option define -plotforeground plotForeground Foreground ""
35    itk_option define -plotbackground plotBackground Background ""
36
37    constructor {args} { # defined below }
38    destructor { # defined below }
39
40    public method add {dataobj {settings ""}}
41    public method get {}
42    public method delete {args}
43    public method scale {args}
44    public method download {option}
45
46    protected method _rebuild {}
47    protected method _clear {}
48    protected method _zoom {option}
49    protected method _move {option x y}
50    protected method _slice {option args}
51    protected method _3dView {theta phi}
52    protected method _fixLimits {}
53    protected method _slicertip {axis}
54    protected method _color2rgb {color}
55
56    private variable _dlist ""     ;# list of data objects
57    private variable _dims ""      ;# dimensionality of data objects
58    private variable _obj2color    ;# maps dataobj => plotting color
59    private variable _obj2width    ;# maps dataobj => line width
60    private variable _obj2raise    ;# maps dataobj => raise flag 0/1
61    private variable _obj2vtk      ;# maps dataobj => vtk objects
62    private variable _actors       ;# list of actors for each renderer
63    private variable _lights       ;# list of lights for each renderer
64    private variable _click        ;# info used for _move operations
65    private variable _slicer       ;# vtk transform used for 3D slice plane
66    private variable _limits       ;# autoscale min/max for all axes
67    private variable _view         ;# view params for 3D view
68    private variable _download ""  ;# snapshot for download
69}
70
71itk::usual ContourResult {
72    keep -background -foreground -cursor -font
73    keep -plotbackground -plotforeground
74}
75
76# ----------------------------------------------------------------------
77# CONSTRUCTOR
78# ----------------------------------------------------------------------
79itcl::body Rappture::ContourResult::constructor {args} {
80    option add hull.width hull.height
81    pack propagate $itk_component(hull) no
82
83    set _slicer(xplane) ""
84    set _slicer(yplane) ""
85    set _slicer(zplane) ""
86    set _slicer(xslice) ""
87    set _slicer(yslice) ""
88    set _slicer(zslice) ""
89    set _slicer(readout) ""
90    set _view(theta) 0
91    set _view(phi) 0
92
93    itk_component add controls {
94        frame $itk_interior.cntls
95    } {
96        usual
97        rename -background -controlbackground controlBackground Background
98    }
99    pack $itk_component(controls) -side right -fill y
100
101    itk_component add zoom {
102        frame $itk_component(controls).zoom
103    } {
104        usual
105        rename -background -controlbackground controlBackground Background
106    }
107    pack $itk_component(zoom) -side top
108
109    itk_component add reset {
110        button $itk_component(zoom).reset \
111            -borderwidth 1 -padx 1 -pady 1 \
112            -bitmap [Rappture::icon reset] \
113            -command [itcl::code $this _zoom reset]
114    } {
115        usual
116        ignore -borderwidth
117        rename -highlightbackground -controlbackground controlBackground Background
118    }
119    pack $itk_component(reset) -padx 4 -pady 4
120    Rappture::Tooltip::for $itk_component(reset) "Reset the view to the default zoom level"
121
122    itk_component add zoomin {
123        button $itk_component(zoom).zin \
124            -borderwidth 1 -padx 1 -pady 1 \
125            -bitmap [Rappture::icon zoomin] \
126            -command [itcl::code $this _zoom in]
127    } {
128        usual
129        ignore -borderwidth
130        rename -highlightbackground -controlbackground controlBackground Background
131    }
132    pack $itk_component(zoomin) -padx 4 -pady 4
133    Rappture::Tooltip::for $itk_component(zoomin) "Zoom in"
134
135    itk_component add zoomout {
136        button $itk_component(zoom).zout \
137            -borderwidth 1 -padx 1 -pady 1 \
138            -bitmap [Rappture::icon zoomout] \
139            -command [itcl::code $this _zoom out]
140    } {
141        usual
142        ignore -borderwidth
143        rename -highlightbackground -controlbackground controlBackground Background
144    }
145    pack $itk_component(zoomout) -padx 4 -pady 4
146    Rappture::Tooltip::for $itk_component(zoomout) "Zoom out"
147
148    #
149    # Create slicer controls...
150    #
151    itk_component add slicers {
152        frame $itk_component(controls).slicers
153    } {
154        usual
155        rename -background -controlbackground controlBackground Background
156    }
157    pack $itk_component(slicers) -side bottom -padx 4 -pady 4
158    grid rowconfigure $itk_component(slicers) 1 -weight 1
159
160    #
161    # X-value slicer...
162    #
163    itk_component add xslice {
164        label $itk_component(slicers).xslice \
165            -borderwidth 1 -relief raised -padx 1 -pady 1 \
166            -bitmap [Rappture::icon x]
167    } {
168        usual
169        ignore -borderwidth
170        rename -highlightbackground -controlbackground controlBackground Background
171    }
172    bind $itk_component(xslice) <ButtonPress> \
173        [itcl::code $this _slice axis x toggle]
174    Rappture::Tooltip::for $itk_component(xslice) \
175        "Toggle the X cut plane on/off"
176    grid $itk_component(xslice) -row 0 -column 0 -sticky ew -padx 1
177
178    itk_component add xslicer {
179        ::scale $itk_component(slicers).xval -from 100 -to 0 \
180            -width 10 -orient vertical -showvalue off -state disabled \
181            -borderwidth 1 -highlightthickness 0 \
182            -command [itcl::code $this _slice move x]
183    } {
184        usual
185        ignore -borderwidth
186        ignore -highlightthickness
187        rename -highlightbackground -controlbackground controlBackground Background
188        rename -troughcolor -controldarkbackground controlDarkBackground Background
189    }
190    grid $itk_component(xslicer) -row 1 -column 0 -padx 1
191    Rappture::Tooltip::for $itk_component(xslicer) \
192        "@[itcl::code $this _slicertip x]"
193
194    #
195    # Y-value slicer...
196    #
197    itk_component add yslice {
198        label $itk_component(slicers).yslice \
199            -borderwidth 1 -relief raised -padx 1 -pady 1 \
200            -bitmap [Rappture::icon y]
201    } {
202        usual
203        ignore -borderwidth
204        rename -highlightbackground -controlbackground controlBackground Background
205    }
206    bind $itk_component(yslice) <ButtonPress> \
207        [itcl::code $this _slice axis y toggle]
208    Rappture::Tooltip::for $itk_component(yslice) \
209        "Toggle the Y cut plane on/off"
210    grid $itk_component(yslice) -row 0 -column 1 -sticky ew -padx 1
211
212    itk_component add yslicer {
213        ::scale $itk_component(slicers).yval -from 100 -to 0 \
214            -width 10 -orient vertical -showvalue off -state disabled \
215            -borderwidth 1 -highlightthickness 0 \
216            -command [itcl::code $this _slice move y]
217    } {
218        usual
219        ignore -borderwidth
220        ignore -highlightthickness
221        rename -highlightbackground -controlbackground controlBackground Background
222        rename -troughcolor -controldarkbackground controlDarkBackground Background
223    }
224    grid $itk_component(yslicer) -row 1 -column 1 -padx 1
225    Rappture::Tooltip::for $itk_component(yslicer) \
226        "@[itcl::code $this _slicertip y]"
227
228    #
229    # Z-value slicer...
230    #
231    itk_component add zslice {
232        label $itk_component(slicers).zslice \
233            -borderwidth 1 -relief raised -padx 1 -pady 1 \
234            -bitmap [Rappture::icon z]
235    } {
236        usual
237        ignore -borderwidth
238        rename -highlightbackground -controlbackground controlBackground Background
239    }
240    grid $itk_component(zslice) -row 0 -column 2 -sticky ew -padx 1
241    bind $itk_component(zslice) <ButtonPress> \
242        [itcl::code $this _slice axis z toggle]
243    Rappture::Tooltip::for $itk_component(zslice) \
244        "Toggle the Z cut plane on/off"
245
246    itk_component add zslicer {
247        ::scale $itk_component(slicers).zval -from 100 -to 0 \
248            -width 10 -orient vertical -showvalue off -state disabled \
249            -borderwidth 1 -highlightthickness 0 \
250            -command [itcl::code $this _slice move z]
251    } {
252        usual
253        ignore -borderwidth
254        ignore -highlightthickness
255        rename -highlightbackground -controlbackground controlBackground Background
256        rename -troughcolor -controldarkbackground controlDarkBackground Background
257    }
258    grid $itk_component(zslicer) -row 1 -column 2 -padx 1
259    Rappture::Tooltip::for $itk_component(zslicer) \
260        "@[itcl::code $this _slicertip z]"
261
262    #
263    # RENDERING AREA
264    #
265    itk_component add area {
266        frame $itk_interior.area
267    }
268    pack $itk_component(area) -expand yes -fill both
269
270    vtkRenderer $this-ren
271    vtkRenderWindow $this-renWin
272    $this-renWin AddRenderer $this-ren
273    $this-renWin LineSmoothingOn
274    $this-renWin PolygonSmoothingOn
275    vtkRenderWindowInteractor $this-iren
276    $this-iren SetRenderWindow $this-renWin
277
278    itk_component add plot {
279        vtkTkRenderWidget $itk_component(area).plot -rw $this-renWin \
280            -width 1 -height 1
281    } {
282    }
283    pack $itk_component(plot) -expand yes -fill both
284
285
286    vtkRenderer $this-ren2
287    vtkRenderWindow $this-renWin2
288    $this-renWin2 AddRenderer $this-ren2
289    vtkRenderWindowInteractor $this-iren2
290    $this-iren2 SetRenderWindow $this-renWin2
291
292    itk_component add legend {
293        vtkTkRenderWidget $itk_component(area).legend -rw $this-renWin2 \
294            -width 1 -height 40
295    } {
296    }
297    pack $itk_component(legend) -side bottom -fill x
298
299    #
300    # Create a photo for download snapshots
301    #
302    set _download [image create photo]
303
304    eval itk_initialize $args
305}
306
307# ----------------------------------------------------------------------
308# DESTRUCTOR
309# ----------------------------------------------------------------------
310itcl::body Rappture::ContourResult::destructor {} {
311    _clear
312    after cancel [itcl::code $this _rebuild]
313
314    rename $this-renWin ""
315    rename $this-ren ""
316    rename $this-iren ""
317
318    rename $this-renWin2 ""
319    rename $this-ren2 ""
320    rename $this-iren2 ""
321
322    image delete $_download
323}
324
325# ----------------------------------------------------------------------
326# USAGE: add <dataobj> ?<settings>?
327#
328# Clients use this to add a data object to the plot.  The optional
329# <settings> are used to configure the plot.  Allowed settings are
330# -color, -brightness, -width, -linestyle, and -raise.
331# ----------------------------------------------------------------------
332itcl::body Rappture::ContourResult::add {dataobj {settings ""}} {
333    array set params {
334        -color auto
335        -width 1
336        -linestyle solid
337        -brightness 0
338        -raise 0
339    }
340    foreach {opt val} $settings {
341        if {![info exists params($opt)]} {
342            error "bad setting \"$opt\": should be [join [lsort [array names params]] {, }]"
343        }
344        set params($opt) $val
345    }
346    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
347        # can't handle -autocolors yet
348        set params(-color) black
349    }
350
351    set pos [lsearch -exact $dataobj $_dlist]
352    if {$pos < 0} {
353        lappend _dlist $dataobj
354        set _obj2color($dataobj) $params(-color)
355        set _obj2width($dataobj) $params(-width)
356        set _obj2raise($dataobj) $params(-raise)
357
358        after cancel [itcl::code $this _rebuild]
359        after idle [itcl::code $this _rebuild]
360    }
361}
362
363# ----------------------------------------------------------------------
364# USAGE: get
365#
366# Clients use this to query the list of objects being plotted, in
367# order from bottom to top of this result.
368# ----------------------------------------------------------------------
369itcl::body Rappture::ContourResult::get {} {
370    # put the dataobj list in order according to -raise options
371    set dlist $_dlist
372    foreach obj $dlist {
373        if {[info exists _obj2raise($obj)] && $_obj2raise($obj)} {
374            set i [lsearch -exact $dlist $obj]
375            if {$i >= 0} {
376                set dlist [lreplace $dlist $i $i]
377                lappend dlist $obj
378            }
379        }
380    }
381    return $dlist
382}
383
384# ----------------------------------------------------------------------
385# USAGE: delete ?<dataobj1> <dataobj2> ...?
386#
387# Clients use this to delete a dataobj from the plot.  If no dataobjs
388# are specified, then all dataobjs are deleted.
389# ----------------------------------------------------------------------
390itcl::body Rappture::ContourResult::delete {args} {
391    if {[llength $args] == 0} {
392        set args $_dlist
393    }
394
395    # delete all specified dataobjs
396    set changed 0
397    foreach dataobj $args {
398        set pos [lsearch -exact $_dlist $dataobj]
399        if {$pos >= 0} {
400            set _dlist [lreplace $_dlist $pos $pos]
401            catch {unset _obj2color($dataobj)}
402            catch {unset _obj2width($dataobj)}
403            catch {unset _obj2raise($dataobj)}
404            set changed 1
405        }
406    }
407
408    # if anything changed, then rebuild the plot
409    if {$changed} {
410        after cancel [itcl::code $this _rebuild]
411        after idle [itcl::code $this _rebuild]
412    }
413}
414
415# ----------------------------------------------------------------------
416# USAGE: scale ?<data1> <data2> ...?
417#
418# Sets the default limits for the overall plot according to the
419# limits of the data for all of the given <data> objects.  This
420# accounts for all objects--even those not showing on the screen.
421# Because of this, the limits are appropriate for all objects as
422# the user scans through data in the ResultSet viewer.
423# ----------------------------------------------------------------------
424itcl::body Rappture::ContourResult::scale {args} {
425    foreach val {xmin xmax ymin ymax zmin zmax vmin vmax} {
426        set _limits($val) ""
427    }
428    foreach obj $args {
429        foreach axis {x y z v} {
430            foreach {min max} [$obj limits $axis] break
431            if {"" != $min && "" != $max} {
432                if {"" == $_limits(${axis}min)} {
433                    set _limits(${axis}min) $min
434                    set _limits(${axis}max) $max
435                } else {
436                    if {$min < $_limits(${axis}min)} {
437                        set _limits(${axis}min) $min
438                    }
439                    if {$max > $_limits(${axis}max)} {
440                        set _limits(${axis}max) $max
441                    }
442                }
443            }
444        }
445    }
446    _fixLimits
447}
448
449# ----------------------------------------------------------------------
450# USAGE: download coming
451# USAGE: download now
452#
453# Clients use this method to create a downloadable representation
454# of the plot.  Returns a list of the form {ext string}, where
455# "ext" is the file extension (indicating the type of data) and
456# "string" is the data itself.
457# ----------------------------------------------------------------------
458itcl::body Rappture::ContourResult::download {option} {
459    switch $option {
460        coming {
461            if {[catch {blt::winop snap $itk_component(area) $_download}]} {
462                $_download configure -width 1 -height 1
463                $_download put #000000
464            }
465        }
466        now {
467            #
468            # Hack alert!  Need data in binary format,
469            # so we'll save to a file and read it back.
470            #
471            set tmpfile /tmp/image[pid].jpg
472            $_download write $tmpfile -format jpeg
473            set fid [open $tmpfile r]
474            fconfigure $fid -encoding binary -translation binary
475            set bytes [read $fid]
476            close $fid
477            file delete -force $tmpfile
478
479            return [list .jpg $bytes]
480        }
481        default {
482            error "bad option \"$option\": should be coming, now"
483        }
484    }
485}
486
487# ----------------------------------------------------------------------
488# USAGE: _rebuild
489#
490# Called automatically whenever something changes that affects the
491# data in the widget.  Clears any existing data and rebuilds the
492# widget to display new data.
493# ----------------------------------------------------------------------
494itcl::body Rappture::ContourResult::_rebuild {} {
495    _clear
496    set id 0
497
498    # determine the dimensionality from the topmost (raised) object
499    set dlist [get]
500    set dataobj [lindex $dlist end]
501    if {$dataobj != ""} {
502        set _dims [lindex [lsort [$dataobj components -dimensions]] end]
503    } else {
504        set _dims "0D"
505    }
506
507    #
508    # LOOKUP TABLE FOR COLOR CONTOURS
509    #
510    # use vmin/vmax if possible, otherwise get from data
511    if {$_limits(vmin) == "" || $_limits(vmax) == ""} {
512        foreach {v0 v1} [$pd GetScalarRange] break
513    } else {
514        set v0 $_limits(vmin)
515        set v1 $_limits(vmax)
516    }
517
518    set lu $this-lookup$id
519    vtkLookupTable $lu
520    $lu SetTableRange $v0 $v1
521    $lu SetHueRange 0.66667 0.0
522    $lu Build
523
524    lappend _obj2vtk($dataobj) $lu
525
526    if {$_dims == "3D"} {
527        #
528        # 3D LIGHTS (on both sides of all three axes)
529        #
530        set x0 $_limits(xmin)
531        set x1 $_limits(xmax)
532        set xm [expr {0.5*($x0+$x1)}]
533        set y0 $_limits(ymin)
534        set y1 $_limits(ymax)
535        set ym [expr {0.5*($y0+$y1)}]
536        set z0 $_limits(zmin)
537        set z1 $_limits(zmax)
538        set zm [expr {0.5*($z0+$z1)}]
539        set xr [expr {$x1-$x0}]
540        set yr [expr {$y1-$y0}]
541        set zr [expr {$z1-$z0}]
542
543        set lt $this-light$id
544        vtkLight $lt
545        $lt SetColor 1 1 1
546        $lt SetAttenuationValues 0 0 0
547        $lt SetFocalPoint $xm $ym $zm
548        $lt SetLightTypeToHeadlight
549        $this-ren AddLight $lt
550        lappend _lights($this-ren) $lt
551
552    } else {
553    }
554
555    # scan through all data objects and build the contours
556    set firstobj 1
557    foreach dataobj [get] {
558        foreach comp [$dataobj components] {
559            #
560            # Add color contours.
561            #
562            if {$firstobj} {
563                if {$_dims == "3D"} {
564                    pack $itk_component(slicers) -side bottom -padx 4 -pady 4
565                    pack $itk_component(reset) -side left
566                    pack $itk_component(zoomin) -side left
567                    pack $itk_component(zoomout) -side left
568
569                    #
570                    # 3D DATA SET
571                    #
572                    set mesh [$dataobj mesh $comp]
573                    switch -- [$mesh GetClassName] {
574                      vtkPoints {
575                        # handle cloud of 3D points
576                        set pd $this-polydata$id
577                        vtkPolyData $pd
578                        $pd SetPoints $mesh
579                        [$pd GetPointData] SetScalars [$dataobj values $comp]
580
581                        set tr $this-triangles$id
582                        vtkDelaunay3D $tr
583                        $tr SetInput $pd
584                        $tr SetTolerance 0.0000000000001
585                        set source [$tr GetOutput]
586
587                        set mp $this-mapper$id
588                        vtkPolyDataMapper $mp
589
590                        lappend _obj2vtk($dataobj) $pd $tr $mp
591                      }
592                      vtkUnstructuredGrid {
593                        # handle 3D grid with connectivity
594                        set gr $this-grdata$id
595                        vtkUnstructuredGrid $gr
596                        $gr ShallowCopy $mesh
597                        [$gr GetPointData] SetScalars [$dataobj values $comp]
598                        set source $gr
599
600                        lappend _obj2vtk($dataobj) $gr
601                      }
602                      vtkRectilinearGrid {
603                        # handle 3D grid with connectivity
604                        set gr $this-grdata$id
605                        vtkRectilinearGrid $gr
606                        $gr ShallowCopy $mesh
607                        [$gr GetPointData] SetScalars [$dataobj values $comp]
608                        set source $gr
609
610                        lappend _obj2vtk($dataobj) $gr
611                      }
612                      default {
613                        error "don't know how to handle [$mesh GetClassName] data"
614                      }
615                    }
616
617                    #
618                    # 3D ISOSURFACES
619                    #
620                    set iso $this-iso$id
621                    vtkContourFilter $iso
622                      $iso SetInput $source
623
624                    set mp $this-isomap$id
625                    vtkPolyDataMapper $mp
626                      $mp SetInput [$iso GetOutput]
627
628                    set ac $this-isoactor$id
629                    vtkActor $ac
630                      $ac SetMapper $mp
631                      [$ac GetProperty] SetOpacity 0.3
632                      [$ac GetProperty] SetDiffuse 0.5
633                      [$ac GetProperty] SetAmbient 0.7
634                      [$ac GetProperty] SetSpecular 10.0
635                      [$ac GetProperty] SetSpecularPower 200.0
636                    $this-ren AddActor $ac
637
638                    lappend _obj2vtk($dataobj) $iso $mp $ac
639                    lappend _actors($this-ren) $ac
640
641                    catch {unset style}
642                    array set style [lindex [$dataobj components -style $comp] 0]
643                    if {[info exists style(-color)]} {
644                        $mp ScalarVisibilityOff  ;# take color from actor
645                        eval [$ac GetProperty] SetColor [_color2rgb $style(-color)]
646                    }
647
648                    if {[info exists style(-opacity)]} {
649                        [$ac GetProperty] SetOpacity $style(-opacity)
650                    }
651
652                    set levels 5
653                    if {[info exists style(-levels)]} {
654                        set levels $style(-levels)
655                    }
656                    if {$levels == 1} {
657                        $iso SetValue 0 [expr {0.5*($v1-$v0)+$v0}]
658                    } else {
659                        $iso GenerateValues [expr {$levels+2}] $v0 $v1
660                    }
661
662                    #
663                    # 3D CUT PLANES
664                    #
665                    if {$id == 0} {
666                        foreach axis {x y z} norm {{1 0 0} {0 1 0} {0 0 1}} {
667                            set pl $this-${axis}cutplane$id
668                            vtkPlane $pl
669                            eval $pl SetNormal $norm
670                            set _slicer(${axis}plane) $pl
671
672                            set ct $this-${axis}cutter$id
673                            vtkCutter $ct
674                            $ct SetInput $source
675                            $ct SetCutFunction $pl
676
677                            set mp $this-${axis}cutmapper$id
678                            vtkPolyDataMapper $mp
679                            $mp SetInput [$ct GetOutput]
680                            $mp SetScalarRange $v0 $v1
681                            $mp SetLookupTable $lu
682
683                            lappend _obj2vtk($dataobj) $pl $ct $mp
684
685                            set ac $this-${axis}actor$id
686                            vtkActor $ac
687                            $ac VisibilityOff
688                            $ac SetMapper $mp
689                            $ac SetPosition 0 0 0
690                            [$ac GetProperty] SetColor 0 0 0
691                            set _slicer(${axis}slice) $ac
692
693                            $this-ren AddActor $ac
694                            lappend _actors($this-ren) $ac
695                            lappend _obj2vtk($dataobj) $ac
696                        }
697
698                        #
699                        # CUT PLANE READOUT
700                        #
701                        set tx $this-text$id
702                        vtkTextMapper $tx
703                        set tp [$tx GetTextProperty]
704                        eval $tp SetColor [_color2rgb $itk_option(-plotforeground)]
705                        $tp SetVerticalJustificationToTop
706                        set _slicer(readout) $tx
707
708                        set txa $this-texta$id
709                        vtkActor2D $txa
710                        $txa SetMapper $tx
711                        [$txa GetPositionCoordinate] \
712                            SetCoordinateSystemToNormalizedDisplay
713                        [$txa GetPositionCoordinate] SetValue 0.02 0.98
714
715                        $this-ren AddActor $txa
716                        lappend _actors($this-ren) $txa
717
718                        lappend _obj2vtk($dataobj) $tx $txa
719
720                        # turn off all slicers by default
721                        foreach axis {x y z} {
722                            $itk_component(${axis}slicer) configure -state normal
723                            $itk_component(${axis}slicer) set 50
724                            _slice move $axis 50
725                            _slice axis $axis off
726                        }
727                    }
728
729                } else {
730                    pack forget $itk_component(slicers)
731                    pack $itk_component(reset) -side top
732                    pack $itk_component(zoomin) -side top
733                    pack $itk_component(zoomout) -side top
734
735                    set pd $this-polydata$id
736                    vtkPolyData $pd
737                    $pd SetPoints [$dataobj mesh $comp]
738                    [$pd GetPointData] SetScalars [$dataobj values $comp]
739
740                    set tr $this-triangles$id
741                    vtkDelaunay2D $tr
742                    $tr SetInput $pd
743                    $tr SetTolerance 0.0000000000001
744                    set source [$tr GetOutput]
745
746                    set mp $this-mapper$id
747                    vtkPolyDataMapper $mp
748                    $mp SetInput $source
749                    $mp SetScalarRange $v0 $v1
750                    $mp SetLookupTable $lu
751
752                    set ac $this-actor$id
753                    vtkActor $ac
754                    $ac SetMapper $mp
755                    $ac SetPosition 0 0 0
756                    [$ac GetProperty] SetColor 0 0 0
757                    $this-ren AddActor $ac
758                    lappend _actors($this-ren) $ac
759
760                    lappend _obj2vtk($dataobj) $pd $tr $mp $ac
761                }
762            } else {
763                #
764                # Add color lines
765                #
766                set cf $this-clfilter$id
767                vtkContourFilter $cf
768                $cf SetInput $source
769                $cf GenerateValues 20 $v0 $v1
770
771                set mp $this-clmapper$id
772                vtkPolyDataMapper $mp
773                $mp SetInput [$cf GetOutput]
774                $mp SetScalarRange $v0 $v1
775                $mp SetLookupTable $lu
776
777                set ac $this-clactor$id
778                vtkActor $ac
779                $ac SetMapper $mp
780                [$ac GetProperty] SetColor 1 1 1
781                $ac SetPosition 0 0 0
782                $this-ren AddActor $ac
783                lappend _actors($this-ren) $ac
784
785                lappend _obj2vtk($dataobj) $cf $mp $ac
786            }
787
788            #
789            # Add an outline around the data
790            #
791            if {$id == 0} {
792                set olf $this-olfilter$id
793                vtkOutlineFilter $olf
794                $olf SetInput $source
795
796                set olm $this-olmapper$id
797                vtkPolyDataMapper $olm
798                $olm SetInput [$olf GetOutput]
799
800                set ola $this-olactor$id
801                vtkActor $ola
802                $ola SetMapper $olm
803                eval [$ola GetProperty] SetColor [_color2rgb $itk_option(-plotforeground)]
804                $this-ren AddActor $ola
805                lappend _actors($this-ren) $ola
806
807                lappend _obj2vtk($dataobj) $olf $olm $ola
808
809                if {$_dims == "3D"} {
810                    # pick a good scale factor for text
811                    if {$xr < $yr} {
812                        set tscale [expr {0.1*$xr}]
813                    } else {
814                        set tscale [expr {0.1*$yr}]
815                    }
816
817                    foreach {i axis px py pz rx ry rz} {
818                        0  x   $xm   0   0   90   0   0
819                        1  y     0 $ym   0   90 -90   0
820                        2  z   $x1   0 $zm   90   0 -45
821                    } {
822                        set length "[expr {[set ${axis}1]-[set ${axis}0]}]"
823
824                        set vtx $this-${axis}label$id
825                        vtkVectorText $vtx
826                        $vtx SetText "$axis"
827
828                        set vmp $this-${axis}lmap$id
829                        vtkPolyDataMapper $vmp
830                        $vmp SetInput [$vtx GetOutput]
831
832                        set vac $this-${axis}lact$id
833                        vtkActor $vac
834                        $vac SetMapper $vmp
835                        $vac SetPosition [expr $px] [expr $py] [expr $pz]
836                        $vac SetOrientation $rx $ry $rz
837                        $vac SetScale $tscale
838                        $this-ren AddActor $vac
839
840                        lappend _obj2vtk($dataobj) $vtx $vmp $vac
841                        lappend _actors($this-ren) $vac
842
843                        $vmp Update
844                        foreach {xx0 xx1 yy0 yy1 zz0 zz1} [$vac GetBounds] break
845                        switch -- $axis {
846                          x {
847                            set dx [expr {-0.5*($xx1-$xx0)}]
848                            set dy 0
849                            set dz [expr {1.3*($zz0-$zz1)}]
850                          }
851                          y {
852                            set dx 0
853                            set dy [expr {0.5*($yy1-$yy0)}]
854                            set dz [expr {$zz0-$zz1}]
855                          }
856                          z {
857                            set dx [expr {0.2*$tscale}]
858                            set dy $dx
859                            set dz [expr {-0.5*($zz1-$zz0)}]
860                          }
861                        }
862                        $vac AddPosition $dx $dy $dz
863                    }
864                }
865            }
866
867            #
868            # Add a legend with the scale.
869            #
870            if {$id == 0} {
871                set lg $this-legend$id
872                vtkScalarBarActor $lg
873                $lg SetLookupTable $lu
874                [$lg GetPositionCoordinate] SetCoordinateSystemToNormalizedViewport
875                [$lg GetPositionCoordinate] SetValue 0.1 0.1
876                $lg SetOrientationToHorizontal
877                $lg SetWidth 0.8
878                $lg SetHeight 1.0
879
880                set tp [$lg GetLabelTextProperty]
881                eval $tp SetColor [_color2rgb $itk_option(-plotforeground)]
882                $tp BoldOff
883                $tp ItalicOff
884                $tp ShadowOff
885                #eval $tp SetShadowColor [_color2rgb gray]
886
887                $this-ren2 AddActor2D $lg
888                lappend _actors($this-ren2) $lg
889                lappend _obj2vtk($dataobj) $lg
890            }
891
892            incr id
893        }
894        set firstobj 0
895    }
896    _fixLimits
897    _zoom reset
898
899    # prevent interactions -- use our own
900    blt::busy hold $itk_component(area) -cursor left_ptr
901    bind $itk_component(area)_Busy <ButtonPress> \
902        [itcl::code $this _move click %x %y]
903    bind $itk_component(area)_Busy <B1-Motion> \
904        [itcl::code $this _move drag %x %y]
905    bind $itk_component(area)_Busy <ButtonRelease> \
906        [itcl::code $this _move release %x %y]
907}
908
909# ----------------------------------------------------------------------
910# USAGE: _clear
911#
912# Used internally to clear the drawing area and tear down all vtk
913# objects in the current scene.
914# ----------------------------------------------------------------------
915itcl::body Rappture::ContourResult::_clear {} {
916    # clear out any old constructs
917    foreach ren [array names _actors] {
918        foreach actor $_actors($ren) {
919            $ren RemoveActor $actor
920        }
921        set _actors($ren) ""
922    }
923    foreach ren [array names _lights] {
924        foreach light $_lights($ren) {
925            $ren RemoveLight $light
926            rename $light ""
927        }
928        set _lights($ren) ""
929    }
930    foreach dataobj [array names _obj2vtk] {
931        foreach cmd $_obj2vtk($dataobj) {
932            rename $cmd ""
933        }
934        set _obj2vtk($dataobj) ""
935    }
936    set _slicer(xplane) ""
937    set _slicer(yplane) ""
938    set _slicer(zplane) ""
939    set _slicer(xslice) ""
940    set _slicer(yslice) ""
941    set _slicer(zslice) ""
942    set _slicer(readout) ""
943}
944
945# ----------------------------------------------------------------------
946# USAGE: _zoom in
947# USAGE: _zoom out
948# USAGE: _zoom reset
949#
950# Called automatically when the user clicks on one of the zoom
951# controls for this widget.  Changes the zoom for the current view.
952# ----------------------------------------------------------------------
953itcl::body Rappture::ContourResult::_zoom {option} {
954    switch -- $option {
955        in {
956            [$this-ren GetActiveCamera] Zoom 1.25
957            $this-renWin Render
958        }
959        out {
960            [$this-ren GetActiveCamera] Zoom 0.8
961            $this-renWin Render
962        }
963        reset {
964            if {$_dims == "3D"} {
965                [$this-ren GetActiveCamera] SetViewAngle 30
966                $this-ren ResetCamera
967                _3dView 45 45
968            } else {
969                $this-ren ResetCamera
970                [$this-ren GetActiveCamera] Zoom 1.5
971            }
972            $this-renWin Render
973            $this-renWin2 Render
974        }
975    }
976}
977
978# ----------------------------------------------------------------------
979# USAGE: _move click <x> <y>
980# USAGE: _move drag <x> <y>
981# USAGE: _move release <x> <y>
982#
983# Called automatically when the user clicks/drags/releases in the
984# plot area.  Moves the plot according to the user's actions.
985# ----------------------------------------------------------------------
986itcl::body Rappture::ContourResult::_move {option x y} {
987    switch -- $option {
988        click {
989            blt::busy configure $itk_component(area) -cursor fleur
990            set _click(x) $x
991            set _click(y) $y
992            set _click(theta) $_view(theta)
993            set _click(phi) $_view(phi)
994        }
995        drag {
996            if {[array size _click] == 0} {
997                _move click $x $y
998            } else {
999                set w [winfo width $itk_component(plot)]
1000                set h [winfo height $itk_component(plot)]
1001                set dx [expr {double($x-$_click(x))/$w}]
1002                set dy [expr {double($y-$_click(y))/$h}]
1003
1004                if {$_dims == "2D"} {
1005                    #
1006                    # Shift the contour plot in 2D
1007                    #
1008                    foreach actor $_actors($this-ren) {
1009                        foreach {ax ay az} [$actor GetPosition] break
1010                        $actor SetPosition [expr {$ax+$dx}] [expr {$ay-$dy}] 0
1011                    }
1012                    $this-renWin Render
1013                } elseif {$_dims == "3D"} {
1014                    #
1015                    # Rotate the camera in 3D
1016                    #
1017                    set theta [expr {$_view(theta) - $dy*180}]
1018                    if {$theta < 2} { set theta 2 }
1019                    if {$theta > 178} { set theta 178 }
1020                    set phi [expr {$_view(phi) - $dx*360}]
1021
1022                    _3dView $theta $phi
1023                    $this-renWin Render
1024                }
1025                set _click(x) $x
1026                set _click(y) $y
1027            }
1028        }
1029        release {
1030            _move drag $x $y
1031            blt::busy configure $itk_component(area) -cursor left_ptr
1032            catch {unset _click}
1033        }
1034        default {
1035            error "bad option \"$option\": should be click, drag, release"
1036        }
1037    }
1038}
1039
1040# ----------------------------------------------------------------------
1041# USAGE: _slice axis x|y|z ?on|off|toggle?
1042# USAGE: _slice move x|y|z <newval>
1043#
1044# Called automatically when the user drags the slider to move the
1045# cut plane that slices 3D data.  Gets the current value from the
1046# slider and moves the cut plane to the appropriate point in the
1047# data set.
1048# ----------------------------------------------------------------------
1049itcl::body Rappture::ContourResult::_slice {option args} {
1050    if {$_slicer(xplane) == ""} {
1051        # no slicer? then bail out!
1052        return
1053    }
1054    switch -- $option {
1055        axis {
1056            if {[llength $args] < 1 || [llength $args] > 2} {
1057                error "wrong # args: should be \"_slice axis x|y|z ?on|off|toggle?\""
1058            }
1059            set axis [lindex $args 0]
1060            set op [lindex $args 1]
1061            if {$op == ""} { set op "on" }
1062
1063            if {[$itk_component(${axis}slice) cget -relief] == "raised"} {
1064                set current "off"
1065            } else {
1066                set current "on"
1067            }
1068
1069            if {$op == "toggle"} {
1070                if {$current == "on"} { set op "off" } else { set op "on" }
1071            }
1072
1073            if {$op} {
1074                $itk_component(${axis}slicer) configure -state normal
1075                $_slicer(${axis}slice) VisibilityOn
1076                $itk_component(${axis}slice) configure -relief sunken
1077            } else {
1078                $itk_component(${axis}slicer) configure -state disabled
1079                $_slicer(${axis}slice) VisibilityOff
1080                $itk_component(${axis}slice) configure -relief raised
1081            }
1082            $this-renWin Render
1083        }
1084        move {
1085            if {[llength $args] != 2} {
1086                error "wrong # args: should be \"_slice move x|y|z newval\""
1087            }
1088            set axis [lindex $args 0]
1089            set newval [lindex $args 1]
1090
1091            set xm [expr {0.5*($_limits(xmax)+$_limits(xmin))}]
1092            set ym [expr {0.5*($_limits(ymax)+$_limits(ymin))}]
1093            set zm [expr {0.5*($_limits(zmax)+$_limits(zmin))}]
1094
1095            set newval [expr {0.01*($newval-50)
1096                *($_limits(${axis}max)-$_limits(${axis}min))
1097                  + 0.5*($_limits(${axis}max)+$_limits(${axis}min))}]
1098
1099            # show the current value in the readout
1100            if {$_slicer(readout) != ""} {
1101                $_slicer(readout) SetInput "$axis = $newval"
1102            }
1103
1104            # keep a little inside the volume, or the slice will disappear!
1105            if {$newval == $_limits(${axis}min)} {
1106                set range [expr {$_limits(${axis}max)-$_limits(${axis}min)}]
1107                set newval [expr {$newval + 1e-6*$range}]
1108            }
1109
1110            # xfer new value to the proper dimension and move the cut plane
1111            set ${axis}m $newval
1112            $_slicer(${axis}plane) SetOrigin $xm $ym $zm
1113
1114            $this-renWin Render
1115        }
1116        default {
1117            error "bad option \"$option\": should be axis or move"
1118        }
1119    }
1120}
1121
1122# ----------------------------------------------------------------------
1123# USAGE: _3dView <theta> <phi>
1124#
1125# Used internally to change the position of the camera for 3D data
1126# sets.  Sets the camera according to the angles <theta> (angle from
1127# the z-axis) and <phi> (angle from the x-axis in the x-y plane).
1128# Both angles are in degrees.
1129# ----------------------------------------------------------------------
1130itcl::body Rappture::ContourResult::_3dView {theta phi} {
1131    set deg2rad 0.0174532927778
1132    set xn [expr {sin($theta*$deg2rad)*cos($phi*$deg2rad)}]
1133    set yn [expr {sin($theta*$deg2rad)*sin($phi*$deg2rad)}]
1134    set zn [expr {cos($theta*$deg2rad)}]
1135
1136    set xm [expr {0.5*($_limits(xmax)+$_limits(xmin))}]
1137    set ym [expr {0.5*($_limits(ymax)+$_limits(ymin))}]
1138    set zm [expr {0.5*($_limits(zmax)+$_limits(zmin))}]
1139
1140    set cam [$this-ren GetActiveCamera]
1141    set zoom [$cam GetViewAngle]
1142    $cam SetViewAngle 30
1143
1144    $cam SetFocalPoint $xm $ym $zm
1145    $cam SetPosition [expr {$xm-$xn}] [expr {$ym-$yn}] [expr {$zm+$zn}]
1146    $cam ComputeViewPlaneNormal
1147    $cam SetViewUp 0 0 1  ;# z-dir is up
1148    $cam OrthogonalizeViewUp
1149    $this-ren ResetCamera
1150    $cam SetViewAngle $zoom
1151
1152    set _view(theta) $theta
1153    set _view(phi) $phi
1154}
1155
1156# ----------------------------------------------------------------------
1157# USAGE: _fixLimits
1158#
1159# Used internally to apply automatic limits to the axes for the
1160# current plot.
1161# ----------------------------------------------------------------------
1162itcl::body Rappture::ContourResult::_fixLimits {} {
1163    $this-ren ResetCamera
1164    [$this-ren GetActiveCamera] Zoom 1.5
1165    $this-renWin Render
1166    $this-renWin2 Render
1167}
1168
1169# ----------------------------------------------------------------------
1170# USAGE: _slicertip <axis>
1171#
1172# Used internally to generate a tooltip for the x/y/z slicer controls.
1173# Returns a message that includes the current slicer value.
1174# ----------------------------------------------------------------------
1175itcl::body Rappture::ContourResult::_slicertip {axis} {
1176    set val [$itk_component(${axis}slicer) get]
1177    set val [expr {0.01*($val-50)
1178        *($_limits(${axis}max)-$_limits(${axis}min))
1179          + 0.5*($_limits(${axis}max)+$_limits(${axis}min))}]
1180    return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val"
1181}
1182
1183# ----------------------------------------------------------------------
1184# USAGE: _color2rgb <color>
1185#
1186# Used internally to convert a color name to a set of {r g b} values
1187# needed for vtk.  Each r/g/b component is scaled in the range 0-1.
1188# ----------------------------------------------------------------------
1189itcl::body Rappture::ContourResult::_color2rgb {color} {
1190    foreach {r g b} [winfo rgb $itk_component(hull) $color] break
1191    set r [expr {$r/65535.0}]
1192    set g [expr {$g/65535.0}]
1193    set b [expr {$b/65535.0}]
1194    return [list $r $g $b]
1195}
1196
1197# ----------------------------------------------------------------------
1198# CONFIGURATION OPTION: -plotbackground
1199# ----------------------------------------------------------------------
1200itcl::configbody Rappture::ContourResult::plotbackground {
1201    foreach {r g b} [_color2rgb $itk_option(-plotbackground)] break
1202    $this-ren SetBackground $r $g $b
1203    $this-renWin Render
1204    $this-ren2 SetBackground $r $g $b
1205    $this-renWin2 Render
1206}
1207
1208# ----------------------------------------------------------------------
1209# CONFIGURATION OPTION: -plotforeground
1210# ----------------------------------------------------------------------
1211itcl::configbody Rappture::ContourResult::plotforeground {
1212    after cancel [itcl::code $this _rebuild]
1213    after idle [itcl::code $this _rebuild]
1214}
Note: See TracBrowser for help on using the repository browser.