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

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