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

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

Added popup options for the "download" button. Right now this works
only for <curve> objects. You can select between CSV and PDF output.
Will add other formats later.

Fixed a few "after cancel" errors that were happening when you switch
between inputs in the structure demo.

Fixed the colors and fonts for the new bug report window.

File size: 43.1 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 args}
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        -description ""
340    }
341    foreach {opt val} $settings {
342        if {![info exists params($opt)]} {
343            error "bad setting \"$opt\": should be [join [lsort [array names params]] {, }]"
344        }
345        set params($opt) $val
346    }
347    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
348        # can't handle -autocolors yet
349        set params(-color) black
350    }
351
352    set pos [lsearch -exact $dataobj $_dlist]
353    if {$pos < 0} {
354        lappend _dlist $dataobj
355        set _obj2color($dataobj) $params(-color)
356        set _obj2width($dataobj) $params(-width)
357        set _obj2raise($dataobj) $params(-raise)
358
359        after cancel [itcl::code $this _rebuild]
360        after idle [itcl::code $this _rebuild]
361    }
362}
363
364# ----------------------------------------------------------------------
365# USAGE: get
366#
367# Clients use this to query the list of objects being plotted, in
368# order from bottom to top of this result.
369# ----------------------------------------------------------------------
370itcl::body Rappture::ContourResult::get {} {
371    # put the dataobj list in order according to -raise options
372    set dlist $_dlist
373    foreach obj $dlist {
374        if {[info exists _obj2raise($obj)] && $_obj2raise($obj)} {
375            set i [lsearch -exact $dlist $obj]
376            if {$i >= 0} {
377                set dlist [lreplace $dlist $i $i]
378                lappend dlist $obj
379            }
380        }
381    }
382    return $dlist
383}
384
385# ----------------------------------------------------------------------
386# USAGE: delete ?<dataobj1> <dataobj2> ...?
387#
388# Clients use this to delete a dataobj from the plot.  If no dataobjs
389# are specified, then all dataobjs are deleted.
390# ----------------------------------------------------------------------
391itcl::body Rappture::ContourResult::delete {args} {
392    if {[llength $args] == 0} {
393        set args $_dlist
394    }
395
396    # delete all specified dataobjs
397    set changed 0
398    foreach dataobj $args {
399        set pos [lsearch -exact $_dlist $dataobj]
400        if {$pos >= 0} {
401            set _dlist [lreplace $_dlist $pos $pos]
402            catch {unset _obj2color($dataobj)}
403            catch {unset _obj2width($dataobj)}
404            catch {unset _obj2raise($dataobj)}
405            set changed 1
406        }
407    }
408
409    # if anything changed, then rebuild the plot
410    if {$changed} {
411        after cancel [itcl::code $this _rebuild]
412        after idle [itcl::code $this _rebuild]
413    }
414}
415
416# ----------------------------------------------------------------------
417# USAGE: scale ?<data1> <data2> ...?
418#
419# Sets the default limits for the overall plot according to the
420# limits of the data for all of the given <data> objects.  This
421# accounts for all objects--even those not showing on the screen.
422# Because of this, the limits are appropriate for all objects as
423# the user scans through data in the ResultSet viewer.
424# ----------------------------------------------------------------------
425itcl::body Rappture::ContourResult::scale {args} {
426    foreach val {xmin xmax ymin ymax zmin zmax vmin vmax} {
427        set _limits($val) ""
428    }
429    foreach obj $args {
430        foreach axis {x y z v} {
431            foreach {min max} [$obj limits $axis] break
432            if {"" != $min && "" != $max} {
433                if {"" == $_limits(${axis}min)} {
434                    set _limits(${axis}min) $min
435                    set _limits(${axis}max) $max
436                } else {
437                    if {$min < $_limits(${axis}min)} {
438                        set _limits(${axis}min) $min
439                    }
440                    if {$max > $_limits(${axis}max)} {
441                        set _limits(${axis}max) $max
442                    }
443                }
444            }
445        }
446    }
447    _fixLimits
448}
449
450# ----------------------------------------------------------------------
451# USAGE: download coming
452# USAGE: download controls <downloadCommand>
453# USAGE: download now
454#
455# Clients use this method to create a downloadable representation
456# of the plot.  Returns a list of the form {ext string}, where
457# "ext" is the file extension (indicating the type of data) and
458# "string" is the data itself.
459# ----------------------------------------------------------------------
460itcl::body Rappture::ContourResult::download {option args} {
461    switch $option {
462        coming {
463            if {[catch {blt::winop snap $itk_component(area) $_download}]} {
464                $_download configure -width 1 -height 1
465                $_download put #000000
466            }
467        }
468        controls {
469            # no controls for this download yet
470            return ""
471        }
472        now {
473            #
474            # Hack alert!  Need data in binary format,
475            # so we'll save to a file and read it back.
476            #
477            set tmpfile /tmp/image[pid].jpg
478            $_download write $tmpfile -format jpeg
479            set fid [open $tmpfile r]
480            fconfigure $fid -encoding binary -translation binary
481            set bytes [read $fid]
482            close $fid
483            file delete -force $tmpfile
484
485            return [list .jpg $bytes]
486        }
487        default {
488            error "bad option \"$option\": should be coming, controls, now"
489        }
490    }
491}
492
493# ----------------------------------------------------------------------
494# USAGE: _rebuild
495#
496# Called automatically whenever something changes that affects the
497# data in the widget.  Clears any existing data and rebuilds the
498# widget to display new data.
499# ----------------------------------------------------------------------
500itcl::body Rappture::ContourResult::_rebuild {} {
501    _clear
502    set id 0
503
504    # determine the dimensionality from the topmost (raised) object
505    set dlist [get]
506    set dataobj [lindex $dlist end]
507    if {$dataobj != ""} {
508        set _dims [lindex [lsort [$dataobj components -dimensions]] end]
509    } else {
510        set _dims "0D"
511    }
512
513    #
514    # LOOKUP TABLE FOR COLOR CONTOURS
515    #
516    # use vmin/vmax if possible, otherwise get from data
517    if {$_limits(vmin) == "" || $_limits(vmax) == ""} {
518        foreach {v0 v1} [$pd GetScalarRange] break
519    } else {
520        set v0 $_limits(vmin)
521        set v1 $_limits(vmax)
522    }
523
524    set lu $this-lookup$id
525    vtkLookupTable $lu
526    $lu SetTableRange $v0 $v1
527    $lu SetHueRange 0.66667 0.0
528    $lu Build
529
530    lappend _obj2vtk($dataobj) $lu
531
532    if {$_dims == "3D"} {
533        #
534        # 3D LIGHTS (on both sides of all three axes)
535        #
536        set x0 $_limits(xmin)
537        set x1 $_limits(xmax)
538        set xm [expr {0.5*($x0+$x1)}]
539        set y0 $_limits(ymin)
540        set y1 $_limits(ymax)
541        set ym [expr {0.5*($y0+$y1)}]
542        set z0 $_limits(zmin)
543        set z1 $_limits(zmax)
544        set zm [expr {0.5*($z0+$z1)}]
545        set xr [expr {$x1-$x0}]
546        set yr [expr {$y1-$y0}]
547        set zr [expr {$z1-$z0}]
548
549        set lt $this-light$id
550        vtkLight $lt
551        $lt SetColor 1 1 1
552        $lt SetAttenuationValues 0 0 0
553        $lt SetFocalPoint $xm $ym $zm
554        $lt SetLightTypeToHeadlight
555        $this-ren AddLight $lt
556        lappend _lights($this-ren) $lt
557
558    } else {
559    }
560
561    # scan through all data objects and build the contours
562    set firstobj 1
563    foreach dataobj [get] {
564        foreach comp [$dataobj components] {
565            #
566            # Add color contours.
567            #
568            if {$firstobj} {
569                if {$_dims == "3D"} {
570                    pack $itk_component(slicers) -side bottom -padx 4 -pady 4
571                    pack $itk_component(reset) -side left
572                    pack $itk_component(zoomin) -side left
573                    pack $itk_component(zoomout) -side left
574
575                    #
576                    # 3D DATA SET
577                    #
578                    set mesh [$dataobj mesh $comp]
579                    if {"" == $mesh} {
580                        set x [expr {[winfo rootx $itk_component(area)]+10}]
581                        set y [expr {[winfo rooty $itk_component(area)]+10}]
582                        Rappture::Tooltip::cue @$x,$y "This data requires the visualization server, and that appears to be down.  Please try your simulation again later."
583                        return
584                    }
585                    switch -- [$mesh GetClassName] {
586                      vtkPoints {
587                        # handle cloud of 3D points
588                        set pd $this-polydata$id
589                        vtkPolyData $pd
590                        $pd SetPoints $mesh
591                        [$pd GetPointData] SetScalars [$dataobj values $comp]
592
593                        set tr $this-triangles$id
594                        vtkDelaunay3D $tr
595                        $tr SetInput $pd
596                        $tr SetTolerance 0.0000000000001
597                        set source [$tr GetOutput]
598
599                        set mp $this-mapper$id
600                        vtkPolyDataMapper $mp
601
602                        lappend _obj2vtk($dataobj) $pd $tr $mp
603                      }
604                      vtkUnstructuredGrid {
605                        # handle 3D grid with connectivity
606                        set gr $this-grdata$id
607                        vtkUnstructuredGrid $gr
608                        $gr ShallowCopy $mesh
609                        [$gr GetPointData] SetScalars [$dataobj values $comp]
610                        set source $gr
611
612                        lappend _obj2vtk($dataobj) $gr
613                      }
614                      vtkRectilinearGrid {
615                        # handle 3D grid with connectivity
616                        set gr $this-grdata$id
617                        vtkRectilinearGrid $gr
618                        $gr ShallowCopy $mesh
619                        [$gr GetPointData] SetScalars [$dataobj values $comp]
620                        set source $gr
621
622                        lappend _obj2vtk($dataobj) $gr
623                      }
624                      default {
625                        error "don't know how to handle [$mesh GetClassName] data"
626                      }
627                    }
628
629                    #
630                    # 3D ISOSURFACES
631                    #
632                    set iso $this-iso$id
633                    vtkContourFilter $iso
634                      $iso SetInput $source
635
636                    set mp $this-isomap$id
637                    vtkPolyDataMapper $mp
638                      $mp SetInput [$iso GetOutput]
639
640                    set ac $this-isoactor$id
641                    vtkActor $ac
642                      $ac SetMapper $mp
643                      [$ac GetProperty] SetOpacity 0.3
644                      [$ac GetProperty] SetDiffuse 0.5
645                      [$ac GetProperty] SetAmbient 0.7
646                      [$ac GetProperty] SetSpecular 10.0
647                      [$ac GetProperty] SetSpecularPower 200.0
648                    $this-ren AddActor $ac
649
650                    lappend _obj2vtk($dataobj) $iso $mp $ac
651                    lappend _actors($this-ren) $ac
652
653                    catch {unset style}
654                    array set style [lindex [$dataobj components -style $comp] 0]
655                    if {[info exists style(-color)]} {
656                        $mp ScalarVisibilityOff  ;# take color from actor
657                        eval [$ac GetProperty] SetColor [_color2rgb $style(-color)]
658                    }
659
660                    if {[info exists style(-opacity)]} {
661                        [$ac GetProperty] SetOpacity $style(-opacity)
662                    }
663
664                    set levels 5
665                    if {[info exists style(-levels)]} {
666                        set levels $style(-levels)
667                    }
668                    if {$levels == 1} {
669                        $iso SetValue 0 [expr {0.5*($v1-$v0)+$v0}]
670                    } else {
671                        $iso GenerateValues [expr {$levels+2}] $v0 $v1
672                    }
673
674                    #
675                    # 3D CUT PLANES
676                    #
677                    if {$id == 0} {
678                        foreach axis {x y z} norm {{1 0 0} {0 1 0} {0 0 1}} {
679                            set pl $this-${axis}cutplane$id
680                            vtkPlane $pl
681                            eval $pl SetNormal $norm
682                            set _slicer(${axis}plane) $pl
683
684                            set ct $this-${axis}cutter$id
685                            vtkCutter $ct
686                            $ct SetInput $source
687                            $ct SetCutFunction $pl
688
689                            set mp $this-${axis}cutmapper$id
690                            vtkPolyDataMapper $mp
691                            $mp SetInput [$ct GetOutput]
692                            $mp SetScalarRange $v0 $v1
693                            $mp SetLookupTable $lu
694
695                            lappend _obj2vtk($dataobj) $pl $ct $mp
696
697                            set ac $this-${axis}actor$id
698                            vtkActor $ac
699                            $ac VisibilityOff
700                            $ac SetMapper $mp
701                            $ac SetPosition 0 0 0
702                            [$ac GetProperty] SetColor 0 0 0
703                            set _slicer(${axis}slice) $ac
704
705                            $this-ren AddActor $ac
706                            lappend _actors($this-ren) $ac
707                            lappend _obj2vtk($dataobj) $ac
708                        }
709
710                        #
711                        # CUT PLANE READOUT
712                        #
713                        set tx $this-text$id
714                        vtkTextMapper $tx
715                        set tp [$tx GetTextProperty]
716                        eval $tp SetColor [_color2rgb $itk_option(-plotforeground)]
717                        $tp SetVerticalJustificationToTop
718                        set _slicer(readout) $tx
719
720                        set txa $this-texta$id
721                        vtkActor2D $txa
722                        $txa SetMapper $tx
723                        [$txa GetPositionCoordinate] \
724                            SetCoordinateSystemToNormalizedDisplay
725                        [$txa GetPositionCoordinate] SetValue 0.02 0.98
726
727                        $this-ren AddActor $txa
728                        lappend _actors($this-ren) $txa
729
730                        lappend _obj2vtk($dataobj) $tx $txa
731
732                        # turn off all slicers by default
733                        foreach axis {x y z} {
734                            $itk_component(${axis}slicer) configure -state normal
735                            $itk_component(${axis}slicer) set 50
736                            _slice move $axis 50
737                            _slice axis $axis off
738                        }
739                    }
740
741                } else {
742                    pack forget $itk_component(slicers)
743                    pack $itk_component(reset) -side top
744                    pack $itk_component(zoomin) -side top
745                    pack $itk_component(zoomout) -side top
746
747                    set pd $this-polydata$id
748                    vtkPolyData $pd
749                    $pd SetPoints [$dataobj mesh $comp]
750                    [$pd GetPointData] SetScalars [$dataobj values $comp]
751
752                    set tr $this-triangles$id
753                    vtkDelaunay2D $tr
754                    $tr SetInput $pd
755                    $tr SetTolerance 0.0000000000001
756                    set source [$tr GetOutput]
757
758                    set mp $this-mapper$id
759                    vtkPolyDataMapper $mp
760                    $mp SetInput $source
761                    $mp SetScalarRange $v0 $v1
762                    $mp SetLookupTable $lu
763
764                    set ac $this-actor$id
765                    vtkActor $ac
766                    $ac SetMapper $mp
767                    $ac SetPosition 0 0 0
768                    [$ac GetProperty] SetColor 0 0 0
769                    $this-ren AddActor $ac
770                    lappend _actors($this-ren) $ac
771
772                    lappend _obj2vtk($dataobj) $pd $tr $mp $ac
773                }
774            } else {
775                #
776                # Add color lines
777                #
778                set cf $this-clfilter$id
779                vtkContourFilter $cf
780                $cf SetInput $source
781                $cf GenerateValues 20 $v0 $v1
782
783                set mp $this-clmapper$id
784                vtkPolyDataMapper $mp
785                $mp SetInput [$cf GetOutput]
786                $mp SetScalarRange $v0 $v1
787                $mp SetLookupTable $lu
788
789                set ac $this-clactor$id
790                vtkActor $ac
791                $ac SetMapper $mp
792                [$ac GetProperty] SetColor 1 1 1
793                $ac SetPosition 0 0 0
794                $this-ren AddActor $ac
795                lappend _actors($this-ren) $ac
796
797                lappend _obj2vtk($dataobj) $cf $mp $ac
798            }
799
800            #
801            # Add an outline around the data
802            #
803            if {$id == 0} {
804                set olf $this-olfilter$id
805                vtkOutlineFilter $olf
806                $olf SetInput $source
807
808                set olm $this-olmapper$id
809                vtkPolyDataMapper $olm
810                $olm SetInput [$olf GetOutput]
811
812                set ola $this-olactor$id
813                vtkActor $ola
814                $ola SetMapper $olm
815                eval [$ola GetProperty] SetColor [_color2rgb $itk_option(-plotforeground)]
816                $this-ren AddActor $ola
817                lappend _actors($this-ren) $ola
818
819                lappend _obj2vtk($dataobj) $olf $olm $ola
820
821                if {$_dims == "3D"} {
822                    # pick a good scale factor for text
823                    if {$xr < $yr} {
824                        set tscale [expr {0.1*$xr}]
825                    } else {
826                        set tscale [expr {0.1*$yr}]
827                    }
828
829                    foreach {i axis px py pz rx ry rz} {
830                        0  x   $xm   0   0   90   0   0
831                        1  y     0 $ym   0   90 -90   0
832                        2  z   $x1   0 $zm   90   0 -45
833                    } {
834                        set length "[expr {[set ${axis}1]-[set ${axis}0]}]"
835
836                        set vtx $this-${axis}label$id
837                        vtkVectorText $vtx
838                        $vtx SetText "$axis"
839
840                        set vmp $this-${axis}lmap$id
841                        vtkPolyDataMapper $vmp
842                        $vmp SetInput [$vtx GetOutput]
843
844                        set vac $this-${axis}lact$id
845                        vtkActor $vac
846                        $vac SetMapper $vmp
847                        $vac SetPosition [expr $px] [expr $py] [expr $pz]
848                        $vac SetOrientation $rx $ry $rz
849                        $vac SetScale $tscale
850                        $this-ren AddActor $vac
851
852                        lappend _obj2vtk($dataobj) $vtx $vmp $vac
853                        lappend _actors($this-ren) $vac
854
855                        $vmp Update
856                        foreach {xx0 xx1 yy0 yy1 zz0 zz1} [$vac GetBounds] break
857                        switch -- $axis {
858                          x {
859                            set dx [expr {-0.5*($xx1-$xx0)}]
860                            set dy 0
861                            set dz [expr {1.3*($zz0-$zz1)}]
862                          }
863                          y {
864                            set dx 0
865                            set dy [expr {0.5*($yy1-$yy0)}]
866                            set dz [expr {$zz0-$zz1}]
867                          }
868                          z {
869                            set dx [expr {0.2*$tscale}]
870                            set dy $dx
871                            set dz [expr {-0.5*($zz1-$zz0)}]
872                          }
873                        }
874                        $vac AddPosition $dx $dy $dz
875                    }
876                }
877            }
878
879            #
880            # Add a legend with the scale.
881            #
882            if {$id == 0} {
883                set lg $this-legend$id
884                vtkScalarBarActor $lg
885                $lg SetLookupTable $lu
886                [$lg GetPositionCoordinate] SetCoordinateSystemToNormalizedViewport
887                [$lg GetPositionCoordinate] SetValue 0.1 0.1
888                $lg SetOrientationToHorizontal
889                $lg SetWidth 0.8
890                $lg SetHeight 1.0
891
892                set tp [$lg GetLabelTextProperty]
893                eval $tp SetColor [_color2rgb $itk_option(-plotforeground)]
894                $tp BoldOff
895                $tp ItalicOff
896                $tp ShadowOff
897                #eval $tp SetShadowColor [_color2rgb gray]
898
899                $this-ren2 AddActor2D $lg
900                lappend _actors($this-ren2) $lg
901                lappend _obj2vtk($dataobj) $lg
902            }
903
904            incr id
905        }
906        set firstobj 0
907    }
908    _fixLimits
909    _zoom reset
910
911    # prevent interactions -- use our own
912    blt::busy hold $itk_component(area) -cursor left_ptr
913    bind $itk_component(area)_Busy <ButtonPress> \
914        [itcl::code $this _move click %x %y]
915    bind $itk_component(area)_Busy <B1-Motion> \
916        [itcl::code $this _move drag %x %y]
917    bind $itk_component(area)_Busy <ButtonRelease> \
918        [itcl::code $this _move release %x %y]
919}
920
921# ----------------------------------------------------------------------
922# USAGE: _clear
923#
924# Used internally to clear the drawing area and tear down all vtk
925# objects in the current scene.
926# ----------------------------------------------------------------------
927itcl::body Rappture::ContourResult::_clear {} {
928    # clear out any old constructs
929    foreach ren [array names _actors] {
930        foreach actor $_actors($ren) {
931            $ren RemoveActor $actor
932        }
933        set _actors($ren) ""
934    }
935    foreach ren [array names _lights] {
936        foreach light $_lights($ren) {
937            $ren RemoveLight $light
938            rename $light ""
939        }
940        set _lights($ren) ""
941    }
942    foreach dataobj [array names _obj2vtk] {
943        foreach cmd $_obj2vtk($dataobj) {
944            rename $cmd ""
945        }
946        set _obj2vtk($dataobj) ""
947    }
948    set _slicer(xplane) ""
949    set _slicer(yplane) ""
950    set _slicer(zplane) ""
951    set _slicer(xslice) ""
952    set _slicer(yslice) ""
953    set _slicer(zslice) ""
954    set _slicer(readout) ""
955}
956
957# ----------------------------------------------------------------------
958# USAGE: _zoom in
959# USAGE: _zoom out
960# USAGE: _zoom reset
961#
962# Called automatically when the user clicks on one of the zoom
963# controls for this widget.  Changes the zoom for the current view.
964# ----------------------------------------------------------------------
965itcl::body Rappture::ContourResult::_zoom {option} {
966    switch -- $option {
967        in {
968            [$this-ren GetActiveCamera] Zoom 1.25
969            $this-renWin Render
970        }
971        out {
972            [$this-ren GetActiveCamera] Zoom 0.8
973            $this-renWin Render
974        }
975        reset {
976            if {$_dims == "3D"} {
977                [$this-ren GetActiveCamera] SetViewAngle 30
978                $this-ren ResetCamera
979                _3dView 45 45
980            } else {
981                $this-ren ResetCamera
982                [$this-ren GetActiveCamera] Zoom 1.5
983            }
984            $this-renWin Render
985            $this-renWin2 Render
986        }
987    }
988}
989
990# ----------------------------------------------------------------------
991# USAGE: _move click <x> <y>
992# USAGE: _move drag <x> <y>
993# USAGE: _move release <x> <y>
994#
995# Called automatically when the user clicks/drags/releases in the
996# plot area.  Moves the plot according to the user's actions.
997# ----------------------------------------------------------------------
998itcl::body Rappture::ContourResult::_move {option x y} {
999    switch -- $option {
1000        click {
1001            blt::busy configure $itk_component(area) -cursor fleur
1002            set _click(x) $x
1003            set _click(y) $y
1004            set _click(theta) $_view(theta)
1005            set _click(phi) $_view(phi)
1006        }
1007        drag {
1008            if {[array size _click] == 0} {
1009                _move click $x $y
1010            } else {
1011                set w [winfo width $itk_component(plot)]
1012                set h [winfo height $itk_component(plot)]
1013                set dx [expr {double($x-$_click(x))/$w}]
1014                set dy [expr {double($y-$_click(y))/$h}]
1015
1016                if {$_dims == "2D"} {
1017                    #
1018                    # Shift the contour plot in 2D
1019                    #
1020                    foreach actor $_actors($this-ren) {
1021                        foreach {ax ay az} [$actor GetPosition] break
1022                        $actor SetPosition [expr {$ax+$dx}] [expr {$ay-$dy}] 0
1023                    }
1024                    $this-renWin Render
1025                } elseif {$_dims == "3D"} {
1026                    #
1027                    # Rotate the camera in 3D
1028                    #
1029                    set theta [expr {$_view(theta) - $dy*180}]
1030                    if {$theta < 2} { set theta 2 }
1031                    if {$theta > 178} { set theta 178 }
1032                    set phi [expr {$_view(phi) - $dx*360}]
1033
1034                    _3dView $theta $phi
1035                    $this-renWin Render
1036                }
1037                set _click(x) $x
1038                set _click(y) $y
1039            }
1040        }
1041        release {
1042            _move drag $x $y
1043            blt::busy configure $itk_component(area) -cursor left_ptr
1044            catch {unset _click}
1045        }
1046        default {
1047            error "bad option \"$option\": should be click, drag, release"
1048        }
1049    }
1050}
1051
1052# ----------------------------------------------------------------------
1053# USAGE: _slice axis x|y|z ?on|off|toggle?
1054# USAGE: _slice move x|y|z <newval>
1055#
1056# Called automatically when the user drags the slider to move the
1057# cut plane that slices 3D data.  Gets the current value from the
1058# slider and moves the cut plane to the appropriate point in the
1059# data set.
1060# ----------------------------------------------------------------------
1061itcl::body Rappture::ContourResult::_slice {option args} {
1062    if {$_slicer(xplane) == ""} {
1063        # no slicer? then bail out!
1064        return
1065    }
1066    switch -- $option {
1067        axis {
1068            if {[llength $args] < 1 || [llength $args] > 2} {
1069                error "wrong # args: should be \"_slice axis x|y|z ?on|off|toggle?\""
1070            }
1071            set axis [lindex $args 0]
1072            set op [lindex $args 1]
1073            if {$op == ""} { set op "on" }
1074
1075            if {[$itk_component(${axis}slice) cget -relief] == "raised"} {
1076                set current "off"
1077            } else {
1078                set current "on"
1079            }
1080
1081            if {$op == "toggle"} {
1082                if {$current == "on"} { set op "off" } else { set op "on" }
1083            }
1084
1085            if {$op} {
1086                $itk_component(${axis}slicer) configure -state normal
1087                $_slicer(${axis}slice) VisibilityOn
1088                $itk_component(${axis}slice) configure -relief sunken
1089            } else {
1090                $itk_component(${axis}slicer) configure -state disabled
1091                $_slicer(${axis}slice) VisibilityOff
1092                $itk_component(${axis}slice) configure -relief raised
1093            }
1094            $this-renWin Render
1095        }
1096        move {
1097            if {[llength $args] != 2} {
1098                error "wrong # args: should be \"_slice move x|y|z newval\""
1099            }
1100            set axis [lindex $args 0]
1101            set newval [lindex $args 1]
1102
1103            set xm [expr {0.5*($_limits(xmax)+$_limits(xmin))}]
1104            set ym [expr {0.5*($_limits(ymax)+$_limits(ymin))}]
1105            set zm [expr {0.5*($_limits(zmax)+$_limits(zmin))}]
1106
1107            set newval [expr {0.01*($newval-50)
1108                *($_limits(${axis}max)-$_limits(${axis}min))
1109                  + 0.5*($_limits(${axis}max)+$_limits(${axis}min))}]
1110
1111            # show the current value in the readout
1112            if {$_slicer(readout) != ""} {
1113                $_slicer(readout) SetInput "$axis = $newval"
1114            }
1115
1116            # keep a little inside the volume, or the slice will disappear!
1117            if {$newval == $_limits(${axis}min)} {
1118                set range [expr {$_limits(${axis}max)-$_limits(${axis}min)}]
1119                set newval [expr {$newval + 1e-6*$range}]
1120            }
1121
1122            # xfer new value to the proper dimension and move the cut plane
1123            set ${axis}m $newval
1124            $_slicer(${axis}plane) SetOrigin $xm $ym $zm
1125
1126            $this-renWin Render
1127        }
1128        default {
1129            error "bad option \"$option\": should be axis or move"
1130        }
1131    }
1132}
1133
1134# ----------------------------------------------------------------------
1135# USAGE: _3dView <theta> <phi>
1136#
1137# Used internally to change the position of the camera for 3D data
1138# sets.  Sets the camera according to the angles <theta> (angle from
1139# the z-axis) and <phi> (angle from the x-axis in the x-y plane).
1140# Both angles are in degrees.
1141# ----------------------------------------------------------------------
1142itcl::body Rappture::ContourResult::_3dView {theta phi} {
1143    set deg2rad 0.0174532927778
1144    set xn [expr {sin($theta*$deg2rad)*cos($phi*$deg2rad)}]
1145    set yn [expr {sin($theta*$deg2rad)*sin($phi*$deg2rad)}]
1146    set zn [expr {cos($theta*$deg2rad)}]
1147
1148    set xm [expr {0.5*($_limits(xmax)+$_limits(xmin))}]
1149    set ym [expr {0.5*($_limits(ymax)+$_limits(ymin))}]
1150    set zm [expr {0.5*($_limits(zmax)+$_limits(zmin))}]
1151
1152    set cam [$this-ren GetActiveCamera]
1153    set zoom [$cam GetViewAngle]
1154    $cam SetViewAngle 30
1155
1156    $cam SetFocalPoint $xm $ym $zm
1157    $cam SetPosition [expr {$xm-$xn}] [expr {$ym-$yn}] [expr {$zm+$zn}]
1158    $cam ComputeViewPlaneNormal
1159    $cam SetViewUp 0 0 1  ;# z-dir is up
1160    $cam OrthogonalizeViewUp
1161    $this-ren ResetCamera
1162    $cam SetViewAngle $zoom
1163
1164    set _view(theta) $theta
1165    set _view(phi) $phi
1166}
1167
1168# ----------------------------------------------------------------------
1169# USAGE: _fixLimits
1170#
1171# Used internally to apply automatic limits to the axes for the
1172# current plot.
1173# ----------------------------------------------------------------------
1174itcl::body Rappture::ContourResult::_fixLimits {} {
1175    $this-ren ResetCamera
1176    [$this-ren GetActiveCamera] Zoom 1.5
1177    $this-renWin Render
1178    $this-renWin2 Render
1179}
1180
1181# ----------------------------------------------------------------------
1182# USAGE: _slicertip <axis>
1183#
1184# Used internally to generate a tooltip for the x/y/z slicer controls.
1185# Returns a message that includes the current slicer value.
1186# ----------------------------------------------------------------------
1187itcl::body Rappture::ContourResult::_slicertip {axis} {
1188    set val [$itk_component(${axis}slicer) get]
1189    set val [expr {0.01*($val-50)
1190        *($_limits(${axis}max)-$_limits(${axis}min))
1191          + 0.5*($_limits(${axis}max)+$_limits(${axis}min))}]
1192    return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val"
1193}
1194
1195# ----------------------------------------------------------------------
1196# USAGE: _color2rgb <color>
1197#
1198# Used internally to convert a color name to a set of {r g b} values
1199# needed for vtk.  Each r/g/b component is scaled in the range 0-1.
1200# ----------------------------------------------------------------------
1201itcl::body Rappture::ContourResult::_color2rgb {color} {
1202    foreach {r g b} [winfo rgb $itk_component(hull) $color] break
1203    set r [expr {$r/65535.0}]
1204    set g [expr {$g/65535.0}]
1205    set b [expr {$b/65535.0}]
1206    return [list $r $g $b]
1207}
1208
1209# ----------------------------------------------------------------------
1210# CONFIGURATION OPTION: -plotbackground
1211# ----------------------------------------------------------------------
1212itcl::configbody Rappture::ContourResult::plotbackground {
1213    foreach {r g b} [_color2rgb $itk_option(-plotbackground)] break
1214    $this-ren SetBackground $r $g $b
1215    $this-renWin Render
1216    $this-ren2 SetBackground $r $g $b
1217    $this-renWin2 Render
1218}
1219
1220# ----------------------------------------------------------------------
1221# CONFIGURATION OPTION: -plotforeground
1222# ----------------------------------------------------------------------
1223itcl::configbody Rappture::ContourResult::plotforeground {
1224    after cancel [itcl::code $this _rebuild]
1225    after idle [itcl::code $this _rebuild]
1226}
Note: See TracBrowser for help on using the repository browser.