1 | # -*- mode: tcl; indent-tabs-mode: nil -*- |
---|
2 | |
---|
3 | # ---------------------------------------------------------------------- |
---|
4 | # COMPONENT: transferfunctioneditor - Rudimentary editor for 3D volume |
---|
5 | # transfer functions |
---|
6 | # |
---|
7 | # This class is used to modify transfer functions used in volume rendering |
---|
8 | # on 3D scalar/vector datasets. |
---|
9 | # |
---|
10 | # ====================================================================== |
---|
11 | # AUTHOR: Michael McLennan, Purdue University |
---|
12 | # Copyright (c) 2004-2012 HUBzero Foundation, LLC |
---|
13 | # |
---|
14 | # See the file "license.terms" for information on usage and |
---|
15 | # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
16 | # ====================================================================== |
---|
17 | package require Itk |
---|
18 | package require BLT |
---|
19 | package require Img |
---|
20 | |
---|
21 | itcl::class Rappture::TransferFunctionEditor { |
---|
22 | private variable _nextId 0; # Used to create unique marker names |
---|
23 | private variable _values; # Relative values for each marker. |
---|
24 | private variable _limits; # Over limits of transfer function. |
---|
25 | private variable _labels; # Label id for each marker. |
---|
26 | private variable _ticks; # Tick id for each marker. |
---|
27 | private variable _canvas "" |
---|
28 | private variable _name ""; # Name of transfer function. |
---|
29 | private variable _activeMotion 0 |
---|
30 | private variable _activePress 0 |
---|
31 | private variable _id2name |
---|
32 | private common _normalIcon [Rappture::icon nvlegendmark] |
---|
33 | private common _activeIcon [Rappture::icon nvlegendmark2] |
---|
34 | public variable command "" |
---|
35 | |
---|
36 | private method SetAbsoluteValue { name x } |
---|
37 | private method GetAbsoluteValue { name } |
---|
38 | private method ContinueDrag { name x y } |
---|
39 | private method EnterTick { name } |
---|
40 | private method GetOverlappingMarkers { x y } |
---|
41 | private method GetScreenPosition { name } |
---|
42 | private method LeaveTick { name } |
---|
43 | private method NewMarker { x y state } |
---|
44 | private method SetRelativeValue { name x } |
---|
45 | private method GetRelativeValue { name } |
---|
46 | private method RemoveDuplicateMarkers {name x y} |
---|
47 | private method SetScreenPosition { name } |
---|
48 | private method SetVisibility { name bool } |
---|
49 | private method StartDrag { name x y } |
---|
50 | private method StopDrag { name x y } |
---|
51 | private method Activate { name } |
---|
52 | private method Deactivate { name } |
---|
53 | private method UpdateViewer {} |
---|
54 | |
---|
55 | constructor {c name args} {} |
---|
56 | destructor {} |
---|
57 | public method limits { min max } |
---|
58 | public method names {} |
---|
59 | public method name {} |
---|
60 | public method values {} |
---|
61 | public method absoluteValues {} |
---|
62 | public method removeMarkers { list } |
---|
63 | public method addMarkers { values } |
---|
64 | public method hideMarkers { {list {}} } |
---|
65 | public method showMarkers { {limits {}} } |
---|
66 | } |
---|
67 | |
---|
68 | itcl::body Rappture::TransferFunctionEditor::constructor {c name args} { |
---|
69 | set _canvas $c |
---|
70 | set _name $name |
---|
71 | set _limits [list 0.0 1.0] |
---|
72 | $c bind transfunc <ButtonRelease-1> \ |
---|
73 | [itcl::code $this NewMarker %x %y normal] |
---|
74 | eval configure $args |
---|
75 | } |
---|
76 | |
---|
77 | itcl::body Rappture::TransferFunctionEditor::limits { min max } { |
---|
78 | set _limits [list $min $max] |
---|
79 | } |
---|
80 | |
---|
81 | itcl::body Rappture::TransferFunctionEditor::names {} { |
---|
82 | return [lsort [array names _values]] |
---|
83 | } |
---|
84 | |
---|
85 | itcl::body Rappture::TransferFunctionEditor::values {} { |
---|
86 | set list {} |
---|
87 | foreach name [array names _ticks] { |
---|
88 | lappend list [GetRelativeValue $name] |
---|
89 | } |
---|
90 | return [lsort -real $list] |
---|
91 | } |
---|
92 | |
---|
93 | itcl::body Rappture::TransferFunctionEditor::absoluteValues {} { |
---|
94 | set list {} |
---|
95 | foreach name [array names _values] { |
---|
96 | lappend list [GetAbsoluteValue $name] |
---|
97 | } |
---|
98 | return $list |
---|
99 | } |
---|
100 | |
---|
101 | itcl::body Rappture::TransferFunctionEditor::NewMarker { x y state } { |
---|
102 | foreach id [$_canvas find overlapping \ |
---|
103 | [expr $x-5] [expr $y-5] [expr $x+5] [expr $y+5]] { |
---|
104 | if { [info exists _id2name($id)] } { |
---|
105 | puts stderr "Too close to existing marker" |
---|
106 | return; # Too close to existing marker |
---|
107 | } |
---|
108 | } |
---|
109 | set name "tick[incr _nextId]" |
---|
110 | set w [winfo width $_canvas] |
---|
111 | set h [winfo height $_canvas] |
---|
112 | |
---|
113 | set _ticks($name) [$_canvas create image 0 $h \ |
---|
114 | -image $_normalIcon -anchor s \ |
---|
115 | -tags "tick $_name $this" -state $state] |
---|
116 | set _labels($name) [$_canvas create text 0 $h \ |
---|
117 | -anchor n -fill white -font "Helvetica 8" \ |
---|
118 | -tags "$this $_name" -state $state] |
---|
119 | set _id2name($_ticks($name)) $name |
---|
120 | $_canvas bind $_ticks($name) <Enter> [itcl::code $this EnterTick $name] |
---|
121 | $_canvas bind $_ticks($name) <Leave> [itcl::code $this LeaveTick $name] |
---|
122 | $_canvas bind $_ticks($name) <ButtonPress-1> \ |
---|
123 | [itcl::code $this StartDrag $name %x %y] |
---|
124 | $_canvas bind $_ticks($name) <B1-Motion> \ |
---|
125 | [itcl::code $this ContinueDrag $name %x %y] |
---|
126 | $_canvas bind $_ticks($name) <ButtonRelease-1> \ |
---|
127 | [itcl::code $this StopDrag $name %x %y] |
---|
128 | |
---|
129 | SetRelativeValue $name [expr {double($x-10)/($w-20)}] |
---|
130 | if { $state == "normal" } { |
---|
131 | UpdateViewer |
---|
132 | } |
---|
133 | return $name |
---|
134 | } |
---|
135 | |
---|
136 | itcl::body Rappture::TransferFunctionEditor::destructor {} { |
---|
137 | $_canvas delete $_name |
---|
138 | } |
---|
139 | |
---|
140 | itcl::body Rappture::TransferFunctionEditor::name {} { |
---|
141 | return $_name |
---|
142 | } |
---|
143 | |
---|
144 | itcl::body Rappture::TransferFunctionEditor::Activate { name } { |
---|
145 | if { $_activePress || $_activeMotion } { |
---|
146 | $_canvas itemconfigure $_labels($name) -state normal |
---|
147 | $_canvas itemconfigure $_ticks($name) -image $_activeIcon |
---|
148 | $_canvas itemconfigure title -state hidden |
---|
149 | } |
---|
150 | } |
---|
151 | |
---|
152 | itcl::body Rappture::TransferFunctionEditor::Deactivate { name } { |
---|
153 | if { $_activePress || $_activeMotion } { |
---|
154 | #puts stderr "do nothing for Deactivate" |
---|
155 | } else { |
---|
156 | $_canvas itemconfigure $_labels($name) -state hidden |
---|
157 | $_canvas itemconfigure $_ticks($name) -image $_normalIcon |
---|
158 | $_canvas itemconfigure title -state normal |
---|
159 | } |
---|
160 | } |
---|
161 | |
---|
162 | itcl::body Rappture::TransferFunctionEditor::SetVisibility { name bool } { |
---|
163 | if { $bool } { |
---|
164 | $_canvas itemconfigure $_ticks($name) -state normal |
---|
165 | $_canvas raise $_ticks($name) |
---|
166 | } else { |
---|
167 | $_canvas itemconfigure $_ticks($name) -state hidden |
---|
168 | } |
---|
169 | } |
---|
170 | |
---|
171 | itcl::body Rappture::TransferFunctionEditor::GetScreenPosition { name } { |
---|
172 | set x [GetRelativeValue $name] |
---|
173 | if { $x < 0.0 } { |
---|
174 | set x 0.0 |
---|
175 | } elseif { $x > 1.0 } { |
---|
176 | set x 1.0 |
---|
177 | } |
---|
178 | set low 10 |
---|
179 | set w [winfo width $_canvas] |
---|
180 | set high [expr {$w - 10}] |
---|
181 | set x [expr {round($x*($high - $low) + $low)}] |
---|
182 | return $x |
---|
183 | } |
---|
184 | |
---|
185 | itcl::body Rappture::TransferFunctionEditor::SetScreenPosition { name } { |
---|
186 | set value $_values($name) |
---|
187 | set x [GetScreenPosition $name] |
---|
188 | set absval [GetAbsoluteValue $name] |
---|
189 | set y 31 |
---|
190 | $_canvas itemconfigure $_labels($name) -text [format %.2g $absval] |
---|
191 | $_canvas coords $_ticks($name) $x [expr {$y+3}] |
---|
192 | $_canvas coords $_labels($name) $x [expr {$y+5}] |
---|
193 | } |
---|
194 | |
---|
195 | itcl::body Rappture::TransferFunctionEditor::GetAbsoluteValue { name } { |
---|
196 | foreach {min max} $_limits break |
---|
197 | return [expr {($_values($name) * ($max - $min)) + $min}] |
---|
198 | } |
---|
199 | |
---|
200 | itcl::body Rappture::TransferFunctionEditor::SetAbsoluteValue { name value } { |
---|
201 | foreach {min max} $_limits break |
---|
202 | set absval $value |
---|
203 | set relval [expr {($absval - $min) / ($max - $min)}] |
---|
204 | set _values($name) $relval |
---|
205 | set y 31 |
---|
206 | $_canvas itemconfigure $_label -text [format %.2g $absval] |
---|
207 | set x [GetScreenPosition $name] |
---|
208 | $_canvas coords $_ticks($name) $x [expr {$y+3}] |
---|
209 | $_canvas coords $_labels($name) $x [expr {$y+5}] |
---|
210 | return $absval |
---|
211 | } |
---|
212 | |
---|
213 | itcl::body Rappture::TransferFunctionEditor::GetRelativeValue { name } { |
---|
214 | return $_values($name) |
---|
215 | } |
---|
216 | |
---|
217 | itcl::body Rappture::TransferFunctionEditor::SetRelativeValue { name value } { |
---|
218 | set _values($name) $value |
---|
219 | set x [GetScreenPosition $name] |
---|
220 | set y 31 |
---|
221 | set absval [GetAbsoluteValue $name] |
---|
222 | $_canvas itemconfigure $_labels($name) -text [format %.2g $absval] |
---|
223 | $_canvas coords $_ticks($name) $x [expr {$y+3}] |
---|
224 | $_canvas coords $_labels($name) $x [expr {$y+5}] |
---|
225 | } |
---|
226 | |
---|
227 | itcl::body Rappture::TransferFunctionEditor::EnterTick { name } { |
---|
228 | set _activeMotion 1 |
---|
229 | Activate $name |
---|
230 | $_canvas raise $_ticks($name) |
---|
231 | } |
---|
232 | |
---|
233 | itcl::body Rappture::TransferFunctionEditor::LeaveTick { name } { |
---|
234 | set _activeMotion 0 |
---|
235 | Deactivate $name |
---|
236 | } |
---|
237 | |
---|
238 | itcl::body Rappture::TransferFunctionEditor::StartDrag { name x y } { |
---|
239 | $_canvas raise $_ticks($name) |
---|
240 | set _activePress 1 |
---|
241 | Activate $name |
---|
242 | $_canvas itemconfigure limits -state hidden |
---|
243 | $_canvas itemconfigure title -state hidden |
---|
244 | } |
---|
245 | |
---|
246 | itcl::body Rappture::TransferFunctionEditor::StopDrag { name x y } { |
---|
247 | ContinueDrag $name $x $y |
---|
248 | RemoveDuplicateMarkers $name $x $y |
---|
249 | set _activePress 0 |
---|
250 | Deactivate $name |
---|
251 | $_canvas itemconfigure limits -state normal |
---|
252 | $_canvas itemconfigure title -state normal |
---|
253 | } |
---|
254 | |
---|
255 | itcl::body Rappture::TransferFunctionEditor::ContinueDrag { name x y } { |
---|
256 | set w [winfo width $_canvas] |
---|
257 | SetRelativeValue $name [expr {double($x-10)/($w-20)}] |
---|
258 | UpdateViewer |
---|
259 | $_canvas raise $_ticks($name) |
---|
260 | set _activePress 1 |
---|
261 | Activate $name |
---|
262 | $_canvas itemconfigure limits -state hidden |
---|
263 | $_canvas itemconfigure title -state hidden |
---|
264 | } |
---|
265 | |
---|
266 | itcl::body Rappture::TransferFunctionEditor::GetOverlappingMarkers { x y } { |
---|
267 | set list {} |
---|
268 | foreach id [$_canvas find overlapping $x $y $x $y] { |
---|
269 | if { [info exists _id2name($id)] } { |
---|
270 | lappend list $_id2name($id) |
---|
271 | } |
---|
272 | } |
---|
273 | return $list |
---|
274 | } |
---|
275 | |
---|
276 | itcl::body Rappture::TransferFunctionEditor::hideMarkers { {list {}} } { |
---|
277 | if { $list == "" } { |
---|
278 | set list [array names _values] |
---|
279 | } |
---|
280 | foreach name $list { |
---|
281 | SetVisibility $name 0 |
---|
282 | } |
---|
283 | } |
---|
284 | |
---|
285 | itcl::body Rappture::TransferFunctionEditor::showMarkers { {limits {}} } { |
---|
286 | if { $limits != "" } { |
---|
287 | set _limits $limits |
---|
288 | foreach name [array names _values] { |
---|
289 | SetScreenPosition $name |
---|
290 | } |
---|
291 | } |
---|
292 | foreach name [array names _values] { |
---|
293 | SetVisibility $name 1 |
---|
294 | } |
---|
295 | } |
---|
296 | |
---|
297 | itcl::body Rappture::TransferFunctionEditor::RemoveDuplicateMarkers {name x y} { |
---|
298 | foreach marker [GetOverlappingMarkers $x $y] { |
---|
299 | if { $marker != $name } { |
---|
300 | Activate $marker |
---|
301 | set markerx [GetScreenPosition $marker] |
---|
302 | if { ($x < ($markerx-3)) || ($x > ($markerx+3)) } { |
---|
303 | continue |
---|
304 | } |
---|
305 | $_canvas delete $_ticks($marker) |
---|
306 | $_canvas delete $_labels($marker) |
---|
307 | array unset _ticks $marker |
---|
308 | array unset _labels $marker |
---|
309 | array unset _values $marker |
---|
310 | bell |
---|
311 | } |
---|
312 | } |
---|
313 | } |
---|
314 | |
---|
315 | itcl::body Rappture::TransferFunctionEditor::addMarkers { values } { |
---|
316 | foreach value $values { |
---|
317 | set name [NewMarker 0 0 hidden] |
---|
318 | SetRelativeValue $name $value |
---|
319 | } |
---|
320 | } |
---|
321 | |
---|
322 | itcl::body Rappture::TransferFunctionEditor::removeMarkers { names } { |
---|
323 | if { $names == "" } { |
---|
324 | set names [array names _values] |
---|
325 | } |
---|
326 | foreach name $names { |
---|
327 | $_canvas delete $_ticks($name) |
---|
328 | $_canvas delete $_labels($name) |
---|
329 | array unset _ticks $name |
---|
330 | array unset _labels $name |
---|
331 | array unset _values $name |
---|
332 | } |
---|
333 | UpdateViewer |
---|
334 | } |
---|
335 | |
---|
336 | itcl::body Rappture::TransferFunctionEditor::UpdateViewer {} { |
---|
337 | # Tell the nanovis/flowvis client to update its transfer functions |
---|
338 | # now that a marker position has changed. |
---|
339 | if { $command != "" } { |
---|
340 | eval uplevel \#0 $command |
---|
341 | } |
---|
342 | } |
---|