1 | # ---------------------------------------------------------------------- |
---|
2 | # COMPONENT: nanovisviewer - 3D volume rendering |
---|
3 | # |
---|
4 | # This widget performs volume rendering on 3D scalar/vector datasets. |
---|
5 | # It connects to the Nanovis server running on a rendering farm, |
---|
6 | # transmits data, and displays the results. |
---|
7 | # ====================================================================== |
---|
8 | # AUTHOR: Michael McLennan, Purdue University |
---|
9 | # Copyright (c) 2004-2005 Purdue Research Foundation |
---|
10 | # |
---|
11 | # See the file "license.terms" for information on usage and |
---|
12 | # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
13 | # ====================================================================== |
---|
14 | package require Itk |
---|
15 | package require BLT |
---|
16 | package require Img |
---|
17 | |
---|
18 | option add *NanovisViewer.width 4i widgetDefault |
---|
19 | option add *NanovisViewer*cursor crosshair widgetDefault |
---|
20 | option add *NanovisViewer.height 4i widgetDefault |
---|
21 | option add *NanovisViewer.foreground black widgetDefault |
---|
22 | option add *NanovisViewer.controlBackground gray widgetDefault |
---|
23 | option add *NanovisViewer.controlDarkBackground #999999 widgetDefault |
---|
24 | option add *NanovisViewer.plotBackground black widgetDefault |
---|
25 | option add *NanovisViewer.plotForeground white widgetDefault |
---|
26 | option add *NanovisViewer.plotOutline gray widgetDefault |
---|
27 | option add *NanovisViewer.font \ |
---|
28 | -*-helvetica-medium-r-normal-*-12-* widgetDefault |
---|
29 | |
---|
30 | itcl::class Rappture::NanovisViewer { |
---|
31 | inherit itk::Widget |
---|
32 | |
---|
33 | itk_option define -plotforeground plotForeground Foreground "" |
---|
34 | itk_option define -plotbackground plotBackground Background "" |
---|
35 | itk_option define -plotoutline plotOutline PlotOutline "" |
---|
36 | itk_option define -sendcommand sendCommand SendCommand "" |
---|
37 | itk_option define -receivecommand receiveCommand ReceiveCommand "" |
---|
38 | |
---|
39 | constructor {hostlist args} { # defined below } |
---|
40 | destructor { # defined below } |
---|
41 | |
---|
42 | public method add {dataobj {settings ""}} |
---|
43 | public method get {args} |
---|
44 | public method delete {args} |
---|
45 | public method scale {args} |
---|
46 | public method get_limits { { option ""} } { |
---|
47 | return [array get _limits] |
---|
48 | } |
---|
49 | public method download {option args} |
---|
50 | public method parameters {title args} { # do nothing } |
---|
51 | public method connect {{hostlist ""}} |
---|
52 | public method disconnect {} |
---|
53 | public method isconnected {} |
---|
54 | |
---|
55 | protected method _send {args} |
---|
56 | protected method _send_text {string} |
---|
57 | protected method _send_dataobjs {} |
---|
58 | protected method _send_transfuncs {} |
---|
59 | protected method _send_echo {channel {data ""}} |
---|
60 | protected method _receive {} |
---|
61 | protected method _receive_image {option size} |
---|
62 | protected method _receive_legend {ivol vmin vmax size} |
---|
63 | protected method _receive_data {args} |
---|
64 | protected method _receive_echo {channel {data ""}} |
---|
65 | |
---|
66 | protected method _rebuild {} |
---|
67 | protected method _currentVolumeIds {{what -all}} |
---|
68 | protected method _zoom {option} |
---|
69 | protected method _move {option x y} |
---|
70 | protected method _slice {option args} |
---|
71 | protected method _slicertip {axis} |
---|
72 | protected method _probe {option args} |
---|
73 | protected method _marker {index option args} |
---|
74 | |
---|
75 | protected method _state {comp} |
---|
76 | protected method _fixSettings {what {value ""}} |
---|
77 | protected method _fixLegend {} |
---|
78 | protected method _serverDown {} |
---|
79 | protected method _genTransfuncData {dataobj comp} |
---|
80 | public method update_transfer_function {} |
---|
81 | public method remove_duplicate_isomarker { m x } |
---|
82 | public method over_isomarker { m x } |
---|
83 | public method _addIsoMarker { x y } |
---|
84 | protected method _initIsoMarkers {dataobj comp} |
---|
85 | protected method _hideIsoMarkers {dataobj} |
---|
86 | protected method _showIsoMarkers {dataobj} |
---|
87 | protected method _color2rgb {color} |
---|
88 | protected method _euler2xyz {theta phi psi} |
---|
89 | |
---|
90 | private variable _dispatcher "" ;# dispatcher for !events |
---|
91 | |
---|
92 | private variable _nvhosts "" ;# list of hosts for nanovis server |
---|
93 | private variable _sid "" ;# socket connection to nanovis server |
---|
94 | private variable _parser "" ;# interpreter for incoming commands |
---|
95 | private variable _buffer ;# buffer for incoming/outgoing commands |
---|
96 | private variable _image ;# image displayed in plotting area |
---|
97 | |
---|
98 | private variable _dlist "" ;# list of data objects |
---|
99 | private variable _all_data_objs |
---|
100 | private variable _dims "" ;# dimensionality of data objects |
---|
101 | private variable _obj2style ;# maps dataobj => style settings |
---|
102 | private variable _obj2ovride ;# maps dataobj => style override |
---|
103 | private variable _obj2id ;# maps dataobj => volume ID in server |
---|
104 | private variable _id2obj ;# maps dataobj => volume ID in server |
---|
105 | private variable _sendobjs "" ;# list of data objs to send to server |
---|
106 | private variable _sendobjs2 "" ;# list of data objs to send to server |
---|
107 | private variable _receiveids ;# list of data objs to send to server |
---|
108 | private variable _opacity |
---|
109 | private variable _thickness |
---|
110 | |
---|
111 | private variable _click ;# info used for _move operations |
---|
112 | private variable _limits ;# autoscale min/max for all axes |
---|
113 | private variable _view ;# view params for 3D view |
---|
114 | |
---|
115 | private variable _isomarkers ;# array of isosurface level values 0..1 |
---|
116 | private common _isosurface ;# indicates to use isosurface shading |
---|
117 | } |
---|
118 | |
---|
119 | itk::usual NanovisViewer { |
---|
120 | keep -background -foreground -cursor -font |
---|
121 | keep -plotbackground -plotforeground |
---|
122 | } |
---|
123 | |
---|
124 | itcl::class Rappture::NanovisViewer::IsoMarker { |
---|
125 | private variable _value ""; # Absolute value of marker. |
---|
126 | private variable _label "" |
---|
127 | private variable _tick "" |
---|
128 | private variable _canvas "" |
---|
129 | private variable _nvobj "" |
---|
130 | private common _normalIcon "" |
---|
131 | private common _activeIcon "" |
---|
132 | private variable _active_motion 0 |
---|
133 | private variable _active_press 0 |
---|
134 | |
---|
135 | constructor {c obj args} { |
---|
136 | set _canvas $c |
---|
137 | set _nvobj $obj |
---|
138 | |
---|
139 | if { $_normalIcon == "" } { |
---|
140 | set normal_icon_data { |
---|
141 | R0lGODlhBwATAOcxAAAAAAEBAQICAgMDAwQEBAUFBQYGBgcHBwgICAkJCQoKCgsLCwwMDA0N |
---|
142 | DQ4ODg8PDxAQEBERERISEhMTExQUFBUVFRYWFhcXFxgYGBkZGRoaGhsbGxwcHB0dHR4eHh8f |
---|
143 | HyAgICEhISIiIiMjIyQkJCUlJSYmJicnJygoKCkpKSoqKisrKywsLC0tLS4uLi8vLzAwMDEx |
---|
144 | MTIyMjMzMzQ0NDU1NTY2Njc3Nzg4ODk5OTo6Ojs7Ozw8PD09PT4+Pj8/P0BAQEFBQUJCQkND |
---|
145 | Q0REREVFRUZGRkdHR0hISElJSUpKSktLS0xMTE1NTU5OTk9PT1BQUFFRUVJSUlNTU1RUVFVV |
---|
146 | VVZWVldXV1hYWFlZWVpaWltbW1xcXF1dXV5eXl9fX2BgYGFhYWJiYmNjY2RkZGVlZWZmZmdn |
---|
147 | Z2hoaGlpaWpqamtra2xsbG1tbW5ubm9vb3BwcHFxcXJycnNzc3R0dHV1dXZ2dnd3d3h4eHl5 |
---|
148 | eXp6ent7e3x8fH19fX5+fn9/f4CAgIGBgYKCgoODg4SEhIWFhYaGhoeHh4iIiImJiYqKiouL |
---|
149 | i4yMjI2NjY6Ojo+Pj5CQkJGRkZKSkpOTk5SUlJWVlZaWlpeXl5iYmJmZmZqampubm5ycnJ2d |
---|
150 | nZ6enp+fn6CgoKGhoaKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq6ysrK2tra6urq+v |
---|
151 | r7CwsLGxsbKysrOzs7S0tLW1tba2tre3t7i4uLm5ubq6uru7u7y8vL29vb6+vr+/v8DAwMHB |
---|
152 | wcLCwsPDw8TExMXFxcbGxsfHx8jIyMnJycrKysvLy8zMzM3Nzc7Ozs/Pz9DQ0NHR0dLS0tPT |
---|
153 | 09TU1NXV1dbW1tfX19jY2NnZ2dra2tvb29zc3N3d3d7e3t/f3+Dg4OHh4eLi4uPj4+Tk5OXl |
---|
154 | 5ebm5ufn5+jo6Onp6erq6uvr6+zs7O3t7e7u7u/v7/Dw8PHx8fLy8vPz8/T09PX19fb29vf3 |
---|
155 | 9/j4+Pn5+fr6+vv7+/z8/P39/f7+/v///yH+EUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEKAP8A |
---|
156 | LAAAAAAHABMAAAg2AP8JHEiwoMGDCBFmW0gw259sDR9GhDjQIUWBFidiXPhwYTZTpv6AXBjy |
---|
157 | j0iSJk9+BDnSo8uAADs= |
---|
158 | } |
---|
159 | set active_icon_data { |
---|
160 | R0lGODlhBwATAOcxAAAAAAEBAQICAgMDAwQEBAUFBQYGBgcHBwgICAkJCQoKCgsLCwwMDA0N |
---|
161 | DQ4ODg8PDxAQEBERERISEhMTExQUFBUVFRYWFhcXFxgYGBkZGRoaGhsbGxwcHB0dHR4eHh8f |
---|
162 | HyAgICEhISIiIiMjIyQkJCUlJSYmJicnJygoKCkpKSoqKisrKywsLC0tLS4uLi8vLzAwMDEx |
---|
163 | MTIyMjMzMzQ0NDU1NTY2Njc3Nzg4ODk5OTo6Ojs7Ozw8PD09PT4+Pj8/P0BAQEFBQUJCQkND |
---|
164 | Q0REREVFRUZGRkdHR0hISElJSUpKSktLS0xMTE1NTU5OTk9PT1BQUFFRUVJSUlNTU1RUVFVV |
---|
165 | VVZWVldXV1hYWFlZWVpaWltbW1xcXF1dXV5eXl9fX2BgYGFhYWJiYmNjY2RkZGVlZWZmZmdn |
---|
166 | Z2hoaGlpaWpqamtra2xsbG1tbW5ubm9vb3BwcHFxcXJycnNzc3R0dHV1dXZ2dnd3d3h4eHl5 |
---|
167 | eXp6ent7e3x8fH19fX5+fn9/f4CAgIGBgYKCgoODg4SEhIWFhYaGhoeHh4iIiImJiYqKiouL |
---|
168 | i4yMjI2NjY6Ojo+Pj5CQkJGRkZKSkpOTk5SUlJWVlZaWlpeXl5iYmJmZmZqampubm5ycnJ2d |
---|
169 | nZ6enp+fn6CgoKGhoaKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq6ysrK2tra6urq+v |
---|
170 | r7CwsLGxsbKysrOzs7S0tLW1tba2tre3t7i4uLm5ubq6uru7u7y8vL29vb6+vr+/v8DAwMHB |
---|
171 | wcLCwsPDw8TExMXFxcbGxsfHx8jIyMnJycrKysvLy8zMzM3Nzc7Ozs/Pz9DQ0NHR0dLS0tPT |
---|
172 | 09TU1NXV1dbW1tfX19jY2NnZ2dra2tvb29zc3N3d3d7e3t/f3+Dg4OHh4eLi4uPj4+Tk5OXl |
---|
173 | 5ebm5ufn5+jo6Onp6erq6uvr6+zs7O3t7e7u7u/v7/Dw8PHx8fLy8vPz8/T09PX19fb29vf3 |
---|
174 | 9/j4+Pn5+fr6+vv7+/z8/P39/f7+/v///yH+EUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEKAP8A |
---|
175 | LAAAAAAHABMAAAg2AP8JHEiwoMGDCBFmW0gwG4BsDR9GhDjQIUWBFidiXPhwYbY/fwCAXBgS |
---|
176 | gEiSJk9+BDnSo8uAADs= |
---|
177 | } |
---|
178 | set _normalIcon [image create photo -data $normal_icon_data] |
---|
179 | set _activeIcon [image create photo -data $active_icon_data] |
---|
180 | } |
---|
181 | set w [winfo width $_canvas] |
---|
182 | set h [winfo height $_canvas] |
---|
183 | set _tick [$c create image 0 $h \ |
---|
184 | -image $_normalIcon -anchor s \ |
---|
185 | -tags "$this $obj" -state hidden] |
---|
186 | set _label [$c create text 0 $h \ |
---|
187 | -anchor n -fill white -font "Helvetica 6" \ |
---|
188 | -tags "$this $obj" -state hidden] |
---|
189 | $c bind $_tick <Enter> [itcl::code $this handle_event "enter"] |
---|
190 | $c bind $_tick <Leave> [itcl::code $this handle_event "leave"] |
---|
191 | $c bind $_tick <ButtonPress-1> \ |
---|
192 | [itcl::code $this handle_event "start" %x %y] |
---|
193 | $c bind $_tick <B1-Motion> \ |
---|
194 | [itcl::code $this handle_event "update" %x %y] |
---|
195 | $c bind $_tick <ButtonRelease-1> \ |
---|
196 | [itcl::code $this handle_event "end" %x %y] |
---|
197 | } |
---|
198 | destructor { |
---|
199 | $_canvas delete $this |
---|
200 | } |
---|
201 | |
---|
202 | public method get_absolute_value {} { |
---|
203 | return $_value |
---|
204 | } |
---|
205 | public method get_relative_value {} { |
---|
206 | array set limits [$_nvobj get_limits] |
---|
207 | if { $limits(vmax) == $limits(vmin) } { |
---|
208 | set limits(vmin) 0.0 |
---|
209 | set limits(vmax) 1.0 |
---|
210 | } |
---|
211 | return [expr {($_value-$limits(vmin))/($limits(vmax) - $limits(vmin))}] |
---|
212 | } |
---|
213 | public method activate { bool } { |
---|
214 | if { $bool || $_active_press || $_active_motion } { |
---|
215 | $_canvas itemconfigure $_label -state normal |
---|
216 | $_canvas itemconfigure $_tick -image $_activeIcon |
---|
217 | } else { |
---|
218 | $_canvas itemconfigure $_label -state hidden |
---|
219 | $_canvas itemconfigure $_tick -image $_normalIcon |
---|
220 | } |
---|
221 | } |
---|
222 | public method show {} { |
---|
223 | set_absolute_value $_value |
---|
224 | $_canvas itemconfigure $_tick -state normal |
---|
225 | $_canvas raise $_tick |
---|
226 | } |
---|
227 | public method hide {} { |
---|
228 | $_canvas itemconfigure $_tick -state hidden |
---|
229 | } |
---|
230 | public method get_screen_position { } { |
---|
231 | set x [get_relative_value] |
---|
232 | if { $x < 0.0 } { |
---|
233 | set x 0.0 |
---|
234 | } elseif { $x > 1.0 } { |
---|
235 | set x 1.0 |
---|
236 | } |
---|
237 | set low 10 |
---|
238 | set w [winfo width $_canvas] |
---|
239 | set high [expr {$w - 10}] |
---|
240 | set x [expr {round($x*($high - $low) + $low)}] |
---|
241 | return $x |
---|
242 | } |
---|
243 | public method set_absolute_value { x } { |
---|
244 | set _value $x |
---|
245 | set y 31 |
---|
246 | $_canvas itemconfigure $_label -text [format %.4g $_value] |
---|
247 | set x [get_screen_position] |
---|
248 | $_canvas coords $_tick $x [expr {$y+3}] |
---|
249 | $_canvas coords $_label $x [expr {$y+5}] |
---|
250 | } |
---|
251 | public method set_relative_value { x } { |
---|
252 | array set limits [$_nvobj get_limits] |
---|
253 | if { $limits(vmax) == $limits(vmin) } { |
---|
254 | set limits(vmin) 0.0 |
---|
255 | set limits(vmax) 1.0 |
---|
256 | } |
---|
257 | set r [expr $limits(vmax) - $limits(vmin)] |
---|
258 | set_absolute_value [expr {($x * $r) + $limits(vmin)}] |
---|
259 | } |
---|
260 | public method handle_event { option args } { |
---|
261 | switch -- $option { |
---|
262 | enter { |
---|
263 | set _active_motion 1 |
---|
264 | activate yes |
---|
265 | $_canvas raise $_tick |
---|
266 | } |
---|
267 | leave { |
---|
268 | set _active_motion 0 |
---|
269 | activate no |
---|
270 | } |
---|
271 | start { |
---|
272 | $_canvas raise $_tick |
---|
273 | set _active_press 1 |
---|
274 | activate yes |
---|
275 | } |
---|
276 | update { |
---|
277 | set w [winfo width $_canvas] |
---|
278 | set x [lindex $args 0] |
---|
279 | set_relative_value [expr {double($x-10)/($w-20)}] |
---|
280 | $_nvobj over_isomarker $this $x |
---|
281 | $_nvobj update_transfer_function |
---|
282 | } |
---|
283 | end { |
---|
284 | set x [lindex $args 0] |
---|
285 | if { ![$_nvobj remove_duplicate_isomarker $this $x]} { |
---|
286 | eval handle_event update $args |
---|
287 | } |
---|
288 | set _active_press 0 |
---|
289 | activate no |
---|
290 | } |
---|
291 | default { |
---|
292 | error "bad option \"$option\": should be start, update, end" |
---|
293 | } |
---|
294 | } |
---|
295 | } |
---|
296 | } |
---|
297 | |
---|
298 | # ---------------------------------------------------------------------- |
---|
299 | # CONSTRUCTOR |
---|
300 | # ---------------------------------------------------------------------- |
---|
301 | itcl::body Rappture::NanovisViewer::constructor {hostlist args} { |
---|
302 | Rappture::dispatcher _dispatcher |
---|
303 | $_dispatcher register !legend |
---|
304 | $_dispatcher dispatch $this !legend "[itcl::code $this _fixLegend]; list" |
---|
305 | $_dispatcher register !serverDown |
---|
306 | $_dispatcher dispatch $this !serverDown "[itcl::code $this _serverDown]; list" |
---|
307 | |
---|
308 | set _buffer(in) "" |
---|
309 | set _buffer(out) "" |
---|
310 | |
---|
311 | # |
---|
312 | # Create a parser to handle incoming requests |
---|
313 | # |
---|
314 | set _parser [interp create -safe] |
---|
315 | foreach cmd [$_parser eval {info commands}] { |
---|
316 | $_parser hide $cmd |
---|
317 | } |
---|
318 | $_parser alias image [itcl::code $this _receive_image] |
---|
319 | $_parser alias legend [itcl::code $this _receive_legend] |
---|
320 | $_parser alias data [itcl::code $this _receive_data] |
---|
321 | |
---|
322 | # |
---|
323 | # Set up the widgets in the main body |
---|
324 | # |
---|
325 | option add hull.width hull.height |
---|
326 | pack propagate $itk_component(hull) no |
---|
327 | |
---|
328 | set _view(theta) 45 |
---|
329 | set _view(phi) 45 |
---|
330 | set _view(psi) 0 |
---|
331 | set _view(zoom) 1 |
---|
332 | set _view(xfocus) 0 |
---|
333 | set _view(yfocus) 0 |
---|
334 | set _view(zfocus) 0 |
---|
335 | set _obj2id(count) 0 |
---|
336 | set _id2obj(count) 0 |
---|
337 | set _limits(vmin) 0.0 |
---|
338 | set _limits(vmax) 1.0 |
---|
339 | |
---|
340 | itk_component add controls { |
---|
341 | frame $itk_interior.cntls |
---|
342 | } { |
---|
343 | usual |
---|
344 | rename -background -controlbackground controlBackground Background |
---|
345 | } |
---|
346 | pack $itk_component(controls) -side right -fill y |
---|
347 | |
---|
348 | itk_component add zoom { |
---|
349 | frame $itk_component(controls).zoom |
---|
350 | } { |
---|
351 | usual |
---|
352 | rename -background -controlbackground controlBackground Background |
---|
353 | } |
---|
354 | pack $itk_component(zoom) -side top |
---|
355 | |
---|
356 | itk_component add reset { |
---|
357 | button $itk_component(zoom).reset \ |
---|
358 | -borderwidth 1 -padx 1 -pady 1 \ |
---|
359 | -bitmap [Rappture::icon reset] \ |
---|
360 | -command [itcl::code $this _zoom reset] |
---|
361 | } { |
---|
362 | usual |
---|
363 | ignore -borderwidth |
---|
364 | rename -highlightbackground -controlbackground controlBackground Background |
---|
365 | } |
---|
366 | pack $itk_component(reset) -side left -padx {4 1} -pady 4 |
---|
367 | Rappture::Tooltip::for $itk_component(reset) "Reset the view to the default zoom level" |
---|
368 | |
---|
369 | itk_component add zoomin { |
---|
370 | button $itk_component(zoom).zin \ |
---|
371 | -borderwidth 1 -padx 1 -pady 1 \ |
---|
372 | -bitmap [Rappture::icon zoomin] \ |
---|
373 | -command [itcl::code $this _zoom in] |
---|
374 | } { |
---|
375 | usual |
---|
376 | ignore -borderwidth |
---|
377 | rename -highlightbackground -controlbackground controlBackground Background |
---|
378 | } |
---|
379 | pack $itk_component(zoomin) -side left -padx 1 -pady 4 |
---|
380 | Rappture::Tooltip::for $itk_component(zoomin) "Zoom in" |
---|
381 | |
---|
382 | itk_component add zoomout { |
---|
383 | button $itk_component(zoom).zout \ |
---|
384 | -borderwidth 1 -padx 1 -pady 1 \ |
---|
385 | -bitmap [Rappture::icon zoomout] \ |
---|
386 | -command [itcl::code $this _zoom out] |
---|
387 | } { |
---|
388 | usual |
---|
389 | ignore -borderwidth |
---|
390 | rename -highlightbackground -controlbackground controlBackground Background |
---|
391 | } |
---|
392 | pack $itk_component(zoomout) -side left -padx {1 4} -pady 4 |
---|
393 | Rappture::Tooltip::for $itk_component(zoomout) "Zoom out" |
---|
394 | |
---|
395 | # |
---|
396 | # Create slicer controls... |
---|
397 | # |
---|
398 | itk_component add slicers { |
---|
399 | frame $itk_component(controls).slicers |
---|
400 | } { |
---|
401 | usual |
---|
402 | rename -background -controlbackground controlBackground Background |
---|
403 | } |
---|
404 | pack $itk_component(slicers) -side bottom -padx 4 -pady 4 |
---|
405 | grid rowconfigure $itk_component(slicers) 1 -weight 1 |
---|
406 | # |
---|
407 | # X-value slicer... |
---|
408 | # |
---|
409 | itk_component add xslice { |
---|
410 | label $itk_component(slicers).xslice \ |
---|
411 | -borderwidth 1 -relief raised -padx 1 -pady 1 \ |
---|
412 | -bitmap [Rappture::icon x] |
---|
413 | } { |
---|
414 | usual |
---|
415 | ignore -borderwidth |
---|
416 | rename -highlightbackground -controlbackground controlBackground Background |
---|
417 | } |
---|
418 | bind $itk_component(xslice) <ButtonPress> \ |
---|
419 | [itcl::code $this _slice axis x toggle] |
---|
420 | Rappture::Tooltip::for $itk_component(xslice) \ |
---|
421 | "Toggle the X cut plane on/off" |
---|
422 | grid $itk_component(xslice) -row 1 -column 0 -sticky ew -padx 1 |
---|
423 | |
---|
424 | itk_component add xslicer { |
---|
425 | ::scale $itk_component(slicers).xval -from 100 -to 0 \ |
---|
426 | -width 10 -orient vertical -showvalue off \ |
---|
427 | -borderwidth 1 -highlightthickness 0 \ |
---|
428 | -command [itcl::code $this _slice move x] |
---|
429 | } { |
---|
430 | usual |
---|
431 | ignore -borderwidth |
---|
432 | ignore -highlightthickness |
---|
433 | rename -highlightbackground -controlbackground controlBackground Background |
---|
434 | rename -troughcolor -controldarkbackground controlDarkBackground Background |
---|
435 | } |
---|
436 | $itk_component(xslicer) set 50 |
---|
437 | $itk_component(xslicer) configure -state disabled |
---|
438 | grid $itk_component(xslicer) -row 2 -column 0 -padx 1 |
---|
439 | Rappture::Tooltip::for $itk_component(xslicer) \ |
---|
440 | "@[itcl::code $this _slicertip x]" |
---|
441 | |
---|
442 | # |
---|
443 | # Y-value slicer... |
---|
444 | # |
---|
445 | itk_component add yslice { |
---|
446 | label $itk_component(slicers).yslice \ |
---|
447 | -borderwidth 1 -relief raised -padx 1 -pady 1 \ |
---|
448 | -bitmap [Rappture::icon y] |
---|
449 | } { |
---|
450 | usual |
---|
451 | ignore -borderwidth |
---|
452 | rename -highlightbackground -controlbackground controlBackground Background |
---|
453 | } |
---|
454 | bind $itk_component(yslice) <ButtonPress> \ |
---|
455 | [itcl::code $this _slice axis y toggle] |
---|
456 | Rappture::Tooltip::for $itk_component(yslice) \ |
---|
457 | "Toggle the Y cut plane on/off" |
---|
458 | grid $itk_component(yslice) -row 1 -column 1 -sticky ew -padx 1 |
---|
459 | |
---|
460 | itk_component add yslicer { |
---|
461 | ::scale $itk_component(slicers).yval -from 100 -to 0 \ |
---|
462 | -width 10 -orient vertical -showvalue off \ |
---|
463 | -borderwidth 1 -highlightthickness 0 \ |
---|
464 | -command [itcl::code $this _slice move y] |
---|
465 | } { |
---|
466 | usual |
---|
467 | ignore -borderwidth |
---|
468 | ignore -highlightthickness |
---|
469 | rename -highlightbackground -controlbackground controlBackground Background |
---|
470 | rename -troughcolor -controldarkbackground controlDarkBackground Background |
---|
471 | } |
---|
472 | $itk_component(yslicer) set 50 |
---|
473 | $itk_component(yslicer) configure -state disabled |
---|
474 | grid $itk_component(yslicer) -row 2 -column 1 -padx 1 |
---|
475 | Rappture::Tooltip::for $itk_component(yslicer) \ |
---|
476 | "@[itcl::code $this _slicertip y]" |
---|
477 | |
---|
478 | # |
---|
479 | # Z-value slicer... |
---|
480 | # |
---|
481 | itk_component add zslice { |
---|
482 | label $itk_component(slicers).zslice \ |
---|
483 | -borderwidth 1 -relief raised -padx 1 -pady 1 \ |
---|
484 | -bitmap [Rappture::icon z] |
---|
485 | } { |
---|
486 | usual |
---|
487 | ignore -borderwidth |
---|
488 | rename -highlightbackground -controlbackground controlBackground Background |
---|
489 | } |
---|
490 | grid $itk_component(zslice) -row 1 -column 2 -sticky ew -padx 1 |
---|
491 | bind $itk_component(zslice) <ButtonPress> \ |
---|
492 | [itcl::code $this _slice axis z toggle] |
---|
493 | Rappture::Tooltip::for $itk_component(zslice) \ |
---|
494 | "Toggle the Z cut plane on/off" |
---|
495 | |
---|
496 | itk_component add zslicer { |
---|
497 | ::scale $itk_component(slicers).zval -from 100 -to 0 \ |
---|
498 | -width 10 -orient vertical -showvalue off \ |
---|
499 | -borderwidth 1 -highlightthickness 0 \ |
---|
500 | -command [itcl::code $this _slice move z] |
---|
501 | } { |
---|
502 | usual |
---|
503 | ignore -borderwidth |
---|
504 | ignore -highlightthickness |
---|
505 | rename -highlightbackground -controlbackground controlBackground Background |
---|
506 | rename -troughcolor -controldarkbackground controlDarkBackground Background |
---|
507 | } |
---|
508 | $itk_component(zslicer) set 50 |
---|
509 | $itk_component(zslicer) configure -state disabled |
---|
510 | grid $itk_component(zslicer) -row 2 -column 2 -padx 1 |
---|
511 | Rappture::Tooltip::for $itk_component(zslicer) \ |
---|
512 | "@[itcl::code $this _slicertip z]" |
---|
513 | |
---|
514 | # |
---|
515 | # Volume toggle... |
---|
516 | # |
---|
517 | itk_component add volume { |
---|
518 | label $itk_component(slicers).volume \ |
---|
519 | -borderwidth 1 -relief sunken -padx 1 -pady 1 \ |
---|
520 | -text "Volume" |
---|
521 | } { |
---|
522 | usual |
---|
523 | ignore -borderwidth |
---|
524 | rename -highlightbackground -controlbackground controlBackground Background |
---|
525 | } |
---|
526 | bind $itk_component(volume) <ButtonPress> \ |
---|
527 | [itcl::code $this _slice volume toggle] |
---|
528 | Rappture::Tooltip::for $itk_component(volume) \ |
---|
529 | "Toggle the volume cloud on/off" |
---|
530 | grid $itk_component(volume) -row 0 -column 0 -columnspan 3 \ |
---|
531 | -sticky ew -padx 1 -pady 3 |
---|
532 | |
---|
533 | # |
---|
534 | # Settings panel... |
---|
535 | # |
---|
536 | itk_component add settings { |
---|
537 | button $itk_component(controls).settings -text "Settings..." \ |
---|
538 | -borderwidth 1 -relief flat -overrelief raised \ |
---|
539 | -padx 2 -pady 1 \ |
---|
540 | -command [list $itk_component(controls).panel activate $itk_component(controls).settings left] |
---|
541 | } { |
---|
542 | usual |
---|
543 | ignore -borderwidth |
---|
544 | rename -background -controlbackground controlBackground Background |
---|
545 | rename -highlightbackground -controlbackground controlBackground Background |
---|
546 | } |
---|
547 | pack $itk_component(settings) -side top -pady 8 |
---|
548 | |
---|
549 | Rappture::Balloon $itk_component(controls).panel -title "Settings" |
---|
550 | set inner [$itk_component(controls).panel component inner] |
---|
551 | frame $inner.scales |
---|
552 | pack $inner.scales -side top -fill x |
---|
553 | grid columnconfigure $inner.scales 1 -weight 1 |
---|
554 | set fg [option get $itk_component(hull) font Font] |
---|
555 | |
---|
556 | label $inner.scales.diml -text "Dim" -font $fg |
---|
557 | grid $inner.scales.diml -row 0 -column 0 -sticky e |
---|
558 | ::scale $inner.scales.light -from 0 -to 100 -orient horizontal \ |
---|
559 | -showvalue off -command [itcl::code $this _fixSettings light] |
---|
560 | grid $inner.scales.light -row 0 -column 1 -sticky ew |
---|
561 | label $inner.scales.brightl -text "Bright" -font $fg |
---|
562 | grid $inner.scales.brightl -row 0 -column 2 -sticky w |
---|
563 | $inner.scales.light set 40 |
---|
564 | |
---|
565 | label $inner.scales.fogl -text "Fog" -font $fg |
---|
566 | grid $inner.scales.fogl -row 1 -column 0 -sticky e |
---|
567 | ::scale $inner.scales.transp -from 0 -to 100 -orient horizontal \ |
---|
568 | -showvalue off -command [itcl::code $this _fixSettings transp] |
---|
569 | grid $inner.scales.transp -row 1 -column 1 -sticky ew |
---|
570 | label $inner.scales.plasticl -text "Plastic" -font $fg |
---|
571 | grid $inner.scales.plasticl -row 1 -column 2 -sticky w |
---|
572 | $inner.scales.transp set 50 |
---|
573 | |
---|
574 | label $inner.scales.zerol -text "Clear" -font $fg |
---|
575 | grid $inner.scales.zerol -row 2 -column 0 -sticky e |
---|
576 | ::scale $inner.scales.opacity -from 0 -to 100 -orient horizontal \ |
---|
577 | -showvalue off -command [itcl::code $this _fixSettings opacity] |
---|
578 | grid $inner.scales.opacity -row 2 -column 1 -sticky ew |
---|
579 | label $inner.scales.onel -text "Opaque" -font $fg |
---|
580 | grid $inner.scales.onel -row 2 -column 2 -sticky w |
---|
581 | $inner.scales.opacity set 100 |
---|
582 | |
---|
583 | label $inner.scales.thinl -text "Thin" -font $fg |
---|
584 | grid $inner.scales.thinl -row 3 -column 0 -sticky e |
---|
585 | ::scale $inner.scales.thickness -from 0 -to 1000 -orient horizontal \ |
---|
586 | -showvalue off -command [itcl::code $this _fixSettings thickness] |
---|
587 | grid $inner.scales.thickness -row 3 -column 1 -sticky ew |
---|
588 | label $inner.scales.thickl -text "Thick" -font $fg |
---|
589 | grid $inner.scales.thickl -row 3 -column 2 -sticky w |
---|
590 | $inner.scales.thickness set 500 |
---|
591 | |
---|
592 | set ::Rappture::NanovisViewer::_isosurface($this) 1 |
---|
593 | ::checkbutton $inner.scales.isosurface \ |
---|
594 | -text "Isosurface shading" \ |
---|
595 | -variable ::Rappture::NanovisViewer::_isosurface($this) \ |
---|
596 | -command [itcl::code $this _fixSettings isosurface] |
---|
597 | grid $inner.scales.isosurface -row 4 -column 0 -columnspan 2 -sticky w |
---|
598 | |
---|
599 | |
---|
600 | # |
---|
601 | # RENDERING AREA |
---|
602 | # |
---|
603 | itk_component add area { |
---|
604 | frame $itk_interior.area |
---|
605 | } |
---|
606 | pack $itk_component(area) -expand yes -fill both |
---|
607 | |
---|
608 | set _image(legend) [image create photo] |
---|
609 | itk_component add legend { |
---|
610 | canvas $itk_component(area).legend -height 50 -highlightthickness 0 |
---|
611 | } { |
---|
612 | usual |
---|
613 | ignore -highlightthickness |
---|
614 | rename -background -plotbackground plotBackground Background |
---|
615 | } |
---|
616 | pack $itk_component(legend) -side bottom -fill x |
---|
617 | bind $itk_component(legend) <Configure> \ |
---|
618 | [list $_dispatcher event -idle !legend] |
---|
619 | |
---|
620 | set _image(plot) [image create photo] |
---|
621 | itk_component add 3dview { |
---|
622 | label $itk_component(area).vol -image $_image(plot) \ |
---|
623 | -highlightthickness 0 |
---|
624 | } { |
---|
625 | usual |
---|
626 | ignore -highlightthickness |
---|
627 | rename -background -plotbackground plotBackground Background |
---|
628 | } |
---|
629 | pack $itk_component(3dview) -expand yes -fill both |
---|
630 | |
---|
631 | # set up bindings for rotation |
---|
632 | bind $itk_component(3dview) <ButtonPress> \ |
---|
633 | [itcl::code $this _move click %x %y] |
---|
634 | bind $itk_component(3dview) <B1-Motion> \ |
---|
635 | [itcl::code $this _move drag %x %y] |
---|
636 | bind $itk_component(3dview) <ButtonRelease> \ |
---|
637 | [itcl::code $this _move release %x %y] |
---|
638 | bind $itk_component(3dview) <Configure> \ |
---|
639 | [itcl::code $this _send screen %w %h] |
---|
640 | |
---|
641 | set _image(download) [image create photo] |
---|
642 | |
---|
643 | eval itk_initialize $args |
---|
644 | |
---|
645 | connect $hostlist |
---|
646 | } |
---|
647 | |
---|
648 | # ---------------------------------------------------------------------- |
---|
649 | # DESTRUCTOR |
---|
650 | # ---------------------------------------------------------------------- |
---|
651 | itcl::body Rappture::NanovisViewer::destructor {} { |
---|
652 | set _sendobjs "" ;# stop any send in progress |
---|
653 | set _sendobjs2 "" ;# stop any send in progress |
---|
654 | after cancel [itcl::code $this _send_dataobjs] |
---|
655 | after cancel [itcl::code $this _rebuild] |
---|
656 | image delete $_image(plot) |
---|
657 | image delete $_image(legend) |
---|
658 | image delete $_image(download) |
---|
659 | interp delete $_parser |
---|
660 | } |
---|
661 | |
---|
662 | # ---------------------------------------------------------------------- |
---|
663 | # USAGE: add <dataobj> ?<settings>? |
---|
664 | # |
---|
665 | # Clients use this to add a data object to the plot. The optional |
---|
666 | # <settings> are used to configure the plot. Allowed settings are |
---|
667 | # -color, -brightness, -width, -linestyle, and -raise. |
---|
668 | # ---------------------------------------------------------------------- |
---|
669 | itcl::body Rappture::NanovisViewer::add {dataobj {settings ""}} { |
---|
670 | array set params { |
---|
671 | -color auto |
---|
672 | -width 1 |
---|
673 | -linestyle solid |
---|
674 | -brightness 0 |
---|
675 | -raise 0 |
---|
676 | -description "" |
---|
677 | -param "" |
---|
678 | } |
---|
679 | foreach {opt val} $settings { |
---|
680 | if {![info exists params($opt)]} { |
---|
681 | error "bad setting \"$opt\": should be [join [lsort [array names params]] {, }]" |
---|
682 | } |
---|
683 | set params($opt) $val |
---|
684 | } |
---|
685 | if {$params(-color) == "auto" || $params(-color) == "autoreset"} { |
---|
686 | # can't handle -autocolors yet |
---|
687 | set params(-color) black |
---|
688 | } |
---|
689 | |
---|
690 | set pos [lsearch -exact $dataobj $_dlist] |
---|
691 | if {$pos < 0} { |
---|
692 | lappend _dlist $dataobj |
---|
693 | set _all_data_objs($dataobj) 1 |
---|
694 | set _obj2ovride($dataobj-color) $params(-color) |
---|
695 | set _obj2ovride($dataobj-width) $params(-width) |
---|
696 | set _obj2ovride($dataobj-raise) $params(-raise) |
---|
697 | |
---|
698 | after cancel [itcl::code $this _rebuild] |
---|
699 | after idle [itcl::code $this _rebuild] |
---|
700 | } |
---|
701 | } |
---|
702 | |
---|
703 | # ---------------------------------------------------------------------- |
---|
704 | # USAGE: get ?-objects? |
---|
705 | # USAGE: get ?-image 3dview|legend? |
---|
706 | # |
---|
707 | # Clients use this to query the list of objects being plotted, in |
---|
708 | # order from bottom to top of this result. The optional "-image" |
---|
709 | # flag can also request the internal images being shown. |
---|
710 | # ---------------------------------------------------------------------- |
---|
711 | itcl::body Rappture::NanovisViewer::get {args} { |
---|
712 | if {[llength $args] == 0} { |
---|
713 | set args "-objects" |
---|
714 | } |
---|
715 | |
---|
716 | set op [lindex $args 0] |
---|
717 | switch -- $op { |
---|
718 | -objects { |
---|
719 | # put the dataobj list in order according to -raise options |
---|
720 | set dlist $_dlist |
---|
721 | foreach obj $dlist { |
---|
722 | if {[info exists _obj2ovride($obj-raise)] && $_obj2ovride($obj-raise)} { |
---|
723 | set i [lsearch -exact $dlist $obj] |
---|
724 | if {$i >= 0} { |
---|
725 | set dlist [lreplace $dlist $i $i] |
---|
726 | lappend dlist $obj |
---|
727 | } |
---|
728 | } |
---|
729 | } |
---|
730 | return $dlist |
---|
731 | } |
---|
732 | -image { |
---|
733 | if {[llength $args] != 2} { |
---|
734 | error "wrong # args: should be \"get -image 3dview|legend\"" |
---|
735 | } |
---|
736 | switch -- [lindex $args end] { |
---|
737 | 3dview { |
---|
738 | return $_image(plot) |
---|
739 | } |
---|
740 | legend { |
---|
741 | return $_image(legend) |
---|
742 | } |
---|
743 | default { |
---|
744 | error "bad image name \"[lindex $args end]\": should be 3dview or legend" |
---|
745 | } |
---|
746 | } |
---|
747 | } |
---|
748 | default { |
---|
749 | error "bad option \"$op\": should be -objects or -image" |
---|
750 | } |
---|
751 | } |
---|
752 | } |
---|
753 | |
---|
754 | # ---------------------------------------------------------------------- |
---|
755 | # USAGE: delete ?<dataobj1> <dataobj2> ...? |
---|
756 | # |
---|
757 | # Clients use this to delete a dataobj from the plot. If no dataobjs |
---|
758 | # are specified, then all dataobjs are deleted. |
---|
759 | # ---------------------------------------------------------------------- |
---|
760 | itcl::body Rappture::NanovisViewer::delete {args} { |
---|
761 | if {[llength $args] == 0} { |
---|
762 | set args $_dlist |
---|
763 | } |
---|
764 | |
---|
765 | # delete all specified dataobjs |
---|
766 | set changed 0 |
---|
767 | foreach dataobj $args { |
---|
768 | set pos [lsearch -exact $_dlist $dataobj] |
---|
769 | if {$pos >= 0} { |
---|
770 | set _dlist [lreplace $_dlist $pos $pos] |
---|
771 | foreach key [array names _obj2ovride $dataobj-*] { |
---|
772 | unset _obj2ovride($key) |
---|
773 | } |
---|
774 | set changed 1 |
---|
775 | } |
---|
776 | } |
---|
777 | |
---|
778 | # if anything changed, then rebuild the plot |
---|
779 | if {$changed} { |
---|
780 | after cancel [itcl::code $this _rebuild] |
---|
781 | after idle [itcl::code $this _rebuild] |
---|
782 | } |
---|
783 | } |
---|
784 | |
---|
785 | # ---------------------------------------------------------------------- |
---|
786 | # USAGE: scale ?<data1> <data2> ...? |
---|
787 | # |
---|
788 | # Sets the default limits for the overall plot according to the |
---|
789 | # limits of the data for all of the given <data> objects. This |
---|
790 | # accounts for all objects--even those not showing on the screen. |
---|
791 | # Because of this, the limits are appropriate for all objects as |
---|
792 | # the user scans through data in the ResultSet viewer. |
---|
793 | # ---------------------------------------------------------------------- |
---|
794 | itcl::body Rappture::NanovisViewer::scale {args} { |
---|
795 | foreach val {xmin xmax ymin ymax zmin zmax vmin vmax} { |
---|
796 | set _limits($val) "" |
---|
797 | } |
---|
798 | foreach obj $args { |
---|
799 | foreach axis {x y z v} { |
---|
800 | foreach {min max} [$obj limits $axis] break |
---|
801 | if {"" != $min && "" != $max} { |
---|
802 | if {"" == $_limits(${axis}min)} { |
---|
803 | set _limits(${axis}min) $min |
---|
804 | set _limits(${axis}max) $max |
---|
805 | } else { |
---|
806 | if {$min < $_limits(${axis}min)} { |
---|
807 | set _limits(${axis}min) $min |
---|
808 | } |
---|
809 | if {$max > $_limits(${axis}max)} { |
---|
810 | set _limits(${axis}max) $max |
---|
811 | } |
---|
812 | } |
---|
813 | } |
---|
814 | } |
---|
815 | } |
---|
816 | } |
---|
817 | |
---|
818 | # ---------------------------------------------------------------------- |
---|
819 | # USAGE: download coming |
---|
820 | # USAGE: download controls <downloadCommand> |
---|
821 | # USAGE: download now |
---|
822 | # |
---|
823 | # Clients use this method to create a downloadable representation |
---|
824 | # of the plot. Returns a list of the form {ext string}, where |
---|
825 | # "ext" is the file extension (indicating the type of data) and |
---|
826 | # "string" is the data itself. |
---|
827 | # ---------------------------------------------------------------------- |
---|
828 | itcl::body Rappture::NanovisViewer::download {option args} { |
---|
829 | switch $option { |
---|
830 | coming { |
---|
831 | if {[catch {blt::winop snap $itk_component(area) $_image(download)}]} { |
---|
832 | $_image(download) configure -width 1 -height 1 |
---|
833 | $_image(download) put #000000 |
---|
834 | } |
---|
835 | } |
---|
836 | controls { |
---|
837 | # no controls for this download yet |
---|
838 | return "" |
---|
839 | } |
---|
840 | now { |
---|
841 | # |
---|
842 | # Hack alert! Need data in binary format, |
---|
843 | # so we'll save to a file and read it back. |
---|
844 | # |
---|
845 | set tmpfile /tmp/image[pid].jpg |
---|
846 | $_image(download) write $tmpfile -format jpeg |
---|
847 | set fid [open $tmpfile r] |
---|
848 | fconfigure $fid -encoding binary -translation binary |
---|
849 | set bytes [read $fid] |
---|
850 | close $fid |
---|
851 | file delete -force $tmpfile |
---|
852 | |
---|
853 | return [list .jpg $bytes] |
---|
854 | } |
---|
855 | default { |
---|
856 | error "bad option \"$option\": should be coming, controls, now" |
---|
857 | } |
---|
858 | } |
---|
859 | } |
---|
860 | |
---|
861 | # ---------------------------------------------------------------------- |
---|
862 | # USAGE: connect ?<host:port>,<host:port>...? |
---|
863 | # |
---|
864 | # Clients use this method to establish a connection to a new |
---|
865 | # server, or to reestablish a connection to the previous server. |
---|
866 | # Any existing connection is automatically closed. |
---|
867 | # ---------------------------------------------------------------------- |
---|
868 | itcl::body Rappture::NanovisViewer::connect {{hostlist ""}} { |
---|
869 | disconnect |
---|
870 | |
---|
871 | if {"" != $hostlist} { set _nvhosts $hostlist } |
---|
872 | |
---|
873 | if {"" == $_nvhosts} { |
---|
874 | return 0 |
---|
875 | } |
---|
876 | |
---|
877 | blt::busy hold $itk_component(hull); update idletasks |
---|
878 | |
---|
879 | # HACK ALERT! punt on this for now |
---|
880 | set memorySize 10000 |
---|
881 | |
---|
882 | # |
---|
883 | # Connect to the nanovis server. Send the server some estimate |
---|
884 | # of the size of our job. If it's too busy, that server may |
---|
885 | # forward us to another. |
---|
886 | # |
---|
887 | set try [split $_nvhosts ,] |
---|
888 | foreach {hostname port} [split [lindex $try 0] :] break |
---|
889 | set try [lrange $try 1 end] |
---|
890 | |
---|
891 | while {1} { |
---|
892 | _send_echo <<line "connecting to $hostname:$port..." |
---|
893 | if {[catch {socket $hostname $port} sid]} { |
---|
894 | if {[llength $try] == 0} { |
---|
895 | return 0 |
---|
896 | } |
---|
897 | foreach {hostname port} [split [lindex $try 0] :] break |
---|
898 | set try [lrange $try 1 end] |
---|
899 | continue |
---|
900 | } |
---|
901 | fconfigure $sid -translation binary -encoding binary |
---|
902 | |
---|
903 | # send memory requirement to the load balancer |
---|
904 | puts -nonewline $sid [binary format I $memorySize] |
---|
905 | flush $sid |
---|
906 | |
---|
907 | # read back a reconnection order |
---|
908 | set data [read $sid 4] |
---|
909 | if {[binary scan $data cccc b1 b2 b3 b4] != 4} { |
---|
910 | error "couldn't read redirection request" |
---|
911 | } |
---|
912 | set addr [format "%u.%u.%u.%u" \ |
---|
913 | [expr {$b1 & 0xff}] \ |
---|
914 | [expr {$b2 & 0xff}] \ |
---|
915 | [expr {$b3 & 0xff}] \ |
---|
916 | [expr {$b4 & 0xff}]] |
---|
917 | _receive_echo <<line $addr |
---|
918 | |
---|
919 | if {[string equal $addr "0.0.0.0"]} { |
---|
920 | fconfigure $sid -buffering line |
---|
921 | fileevent $sid readable [itcl::code $this _receive] |
---|
922 | set _sid $sid |
---|
923 | blt::busy release $itk_component(hull) |
---|
924 | return 1 |
---|
925 | } |
---|
926 | set hostname $addr |
---|
927 | } |
---|
928 | blt::busy release $itk_component(hull) |
---|
929 | |
---|
930 | return 0 |
---|
931 | } |
---|
932 | |
---|
933 | # ---------------------------------------------------------------------- |
---|
934 | # USAGE: disconnect |
---|
935 | # |
---|
936 | # Clients use this method to disconnect from the current rendering |
---|
937 | # server. |
---|
938 | # ---------------------------------------------------------------------- |
---|
939 | itcl::body Rappture::NanovisViewer::disconnect {} { |
---|
940 | if {"" != $_sid} { |
---|
941 | catch {close $_sid} |
---|
942 | set _sid "" |
---|
943 | } |
---|
944 | |
---|
945 | set _buffer(in) "" |
---|
946 | set _buffer(out) "" |
---|
947 | |
---|
948 | # disconnected -- no more data sitting on server |
---|
949 | catch {unset _obj2id} |
---|
950 | array unset _id2obj |
---|
951 | set _obj2id(count) 0 |
---|
952 | set _id2obj(count) 0 |
---|
953 | set _sendobjs "" |
---|
954 | set _sendobjs2 "" |
---|
955 | } |
---|
956 | |
---|
957 | # ---------------------------------------------------------------------- |
---|
958 | # USAGE: isconnected |
---|
959 | # |
---|
960 | # Clients use this method to see if we are currently connected to |
---|
961 | # a server. |
---|
962 | # ---------------------------------------------------------------------- |
---|
963 | itcl::body Rappture::NanovisViewer::isconnected {} { |
---|
964 | return [expr {"" != $_sid}] |
---|
965 | } |
---|
966 | |
---|
967 | # ---------------------------------------------------------------------- |
---|
968 | # USAGE: _send <arg> <arg> ... |
---|
969 | # |
---|
970 | # Used internally to send commands off to the rendering server. |
---|
971 | # This is a more convenient form of _send_text, which actually |
---|
972 | # does the sending. |
---|
973 | # ---------------------------------------------------------------------- |
---|
974 | itcl::body Rappture::NanovisViewer::_send {args} { |
---|
975 | _send_text $args |
---|
976 | } |
---|
977 | |
---|
978 | # ---------------------------------------------------------------------- |
---|
979 | # USAGE: _send_text <string> |
---|
980 | # |
---|
981 | # Used internally to send commands off to the rendering server. |
---|
982 | # ---------------------------------------------------------------------- |
---|
983 | itcl::body Rappture::NanovisViewer::_send_text {string} { |
---|
984 | if {"" == $_sid} { |
---|
985 | $_dispatcher cancel !serverDown |
---|
986 | set x [expr {[winfo rootx $itk_component(area)]+10}] |
---|
987 | set y [expr {[winfo rooty $itk_component(area)]+10}] |
---|
988 | Rappture::Tooltip::cue @$x,$y "Connecting..." |
---|
989 | |
---|
990 | if {[catch {connect} ok] == 0 && $ok} { |
---|
991 | set w [winfo width $itk_component(3dview)] |
---|
992 | set h [winfo height $itk_component(3dview)] |
---|
993 | |
---|
994 | if {[catch {puts $_sid "screen $w $h"}]} { |
---|
995 | disconnect |
---|
996 | _receive_echo closed |
---|
997 | $_dispatcher event -after 750 !serverDown |
---|
998 | } else { |
---|
999 | _send_echo >>line "screen $w $h" |
---|
1000 | |
---|
1001 | set _view(theta) 45 |
---|
1002 | set _view(phi) 45 |
---|
1003 | set _view(psi) 0 |
---|
1004 | set _view(zoom) 1.0 |
---|
1005 | after idle [itcl::code $this _rebuild] |
---|
1006 | Rappture::Tooltip::cue hide |
---|
1007 | } |
---|
1008 | return |
---|
1009 | } |
---|
1010 | Rappture::Tooltip::cue @$x,$y "Can't connect to visualization server. This may be a network problem. Wait a few moments and try resetting the view." |
---|
1011 | return |
---|
1012 | } |
---|
1013 | if {"" != $_sid} { |
---|
1014 | # if we're transmitting objects, then buffer this command |
---|
1015 | if {[llength $_sendobjs] > 0} { |
---|
1016 | append _buffer(out) $string "\n" |
---|
1017 | } else { |
---|
1018 | if {[catch {puts $_sid $string}]} { |
---|
1019 | disconnect |
---|
1020 | _receive_echo closed |
---|
1021 | $_dispatcher event -after 750 !serverDown |
---|
1022 | } else { |
---|
1023 | foreach line [split $string \n] { |
---|
1024 | _send_echo >>line $line |
---|
1025 | } |
---|
1026 | } |
---|
1027 | } |
---|
1028 | } |
---|
1029 | } |
---|
1030 | |
---|
1031 | # ---------------------------------------------------------------------- |
---|
1032 | # USAGE: _send_dataobjs |
---|
1033 | # |
---|
1034 | # Used internally to send a series of volume objects off to the |
---|
1035 | # server. Sends each object, a little at a time, with updates in |
---|
1036 | # between so the interface doesn't lock up. |
---|
1037 | # ---------------------------------------------------------------------- |
---|
1038 | itcl::body Rappture::NanovisViewer::_send_dataobjs {} { |
---|
1039 | blt::busy hold $itk_component(hull); update idletasks |
---|
1040 | |
---|
1041 | foreach dataobj $_sendobjs { |
---|
1042 | foreach comp [$dataobj components] { |
---|
1043 | # send the data as one huge base64-encoded mess -- yuck! |
---|
1044 | set data [$dataobj values $comp] |
---|
1045 | |
---|
1046 | # tell the engine to expect some data |
---|
1047 | set cmdstr "volume data follows [string length $data]" |
---|
1048 | _send_echo >>line $cmdstr |
---|
1049 | if {[catch {puts $_sid $cmdstr} err]} { |
---|
1050 | disconnect |
---|
1051 | $_dispatcher event -after 750 !serverDown |
---|
1052 | return |
---|
1053 | } |
---|
1054 | |
---|
1055 | while {[string length $data] > 0} { |
---|
1056 | update |
---|
1057 | |
---|
1058 | set chunk [string range $data 0 8095] |
---|
1059 | set data [string range $data 8096 end] |
---|
1060 | |
---|
1061 | _send_echo >>line $chunk |
---|
1062 | if {[catch {puts -nonewline $_sid $chunk} err]} { |
---|
1063 | disconnect |
---|
1064 | $_dispatcher event -after 750 !serverDown |
---|
1065 | return |
---|
1066 | } |
---|
1067 | catch {flush $_sid} |
---|
1068 | } |
---|
1069 | _send_echo >>line "" |
---|
1070 | puts $_sid "" |
---|
1071 | |
---|
1072 | set volId $_obj2id(count) |
---|
1073 | incr _obj2id(count) |
---|
1074 | |
---|
1075 | set _id2obj($volId) [list $dataobj $comp] |
---|
1076 | set _obj2id($dataobj-$comp) $volId |
---|
1077 | set _receiveids($volId) 1 |
---|
1078 | } |
---|
1079 | } |
---|
1080 | set _sendobjs "" |
---|
1081 | blt::busy release $itk_component(hull) |
---|
1082 | |
---|
1083 | # activate the proper volume |
---|
1084 | set first [lindex [get] 0] |
---|
1085 | if {"" != $first} { |
---|
1086 | set axis [$first hints updir] |
---|
1087 | if {"" != $axis} { |
---|
1088 | _send up $axis |
---|
1089 | } |
---|
1090 | } |
---|
1091 | |
---|
1092 | # sync the state of slicers |
---|
1093 | set vols [_currentVolumeIds -cutplanes] |
---|
1094 | foreach axis {x y z} { |
---|
1095 | eval _send cutplane state [_state ${axis}slice] $axis $vols |
---|
1096 | set pos [expr {0.01*[$itk_component(${axis}slicer) get]}] |
---|
1097 | eval _send cutplane position $pos $axis $vols |
---|
1098 | } |
---|
1099 | eval _send volume data state [_state volume] $vols |
---|
1100 | |
---|
1101 | # if there are any commands in the buffer, send them now that we're done |
---|
1102 | _send_echo >>line $_buffer(out) |
---|
1103 | if {[catch {puts $_sid $_buffer(out)} err]} { |
---|
1104 | disconnect |
---|
1105 | $_dispatcher event -after 750 !serverDown |
---|
1106 | } |
---|
1107 | set _buffer(out) "" |
---|
1108 | |
---|
1109 | # $_dispatcher event -idle !legend |
---|
1110 | } |
---|
1111 | |
---|
1112 | # ---------------------------------------------------------------------- |
---|
1113 | # USAGE: _send_transfuncs |
---|
1114 | # ---------------------------------------------------------------------- |
---|
1115 | itcl::body Rappture::NanovisViewer::_send_transfuncs {} { |
---|
1116 | blt::busy hold $itk_component(hull); update idletasks |
---|
1117 | foreach dataobj $_sendobjs2 { |
---|
1118 | foreach comp [$dataobj components] { |
---|
1119 | # |
---|
1120 | # Determine the transfer function needed for this volume |
---|
1121 | # and make sure that it's defined on the server. |
---|
1122 | # |
---|
1123 | if { ![info exists _isomarkers($dataobj)] } { |
---|
1124 | _initIsoMarkers $dataobj $comp |
---|
1125 | } else { |
---|
1126 | _hideIsoMarkers $dataobj |
---|
1127 | } |
---|
1128 | foreach {sname cmap wmap} [_genTransfuncData $dataobj $comp] break |
---|
1129 | set cmdstr [list transfunc define $sname $cmap $wmap] |
---|
1130 | _send_echo >>line $cmdstr |
---|
1131 | if {[catch {puts $_sid $cmdstr} err]} { |
---|
1132 | disconnect |
---|
1133 | $_dispatcher event -after 750 !serverDown |
---|
1134 | return |
---|
1135 | } |
---|
1136 | set _obj2style($dataobj-$comp) $sname |
---|
1137 | } |
---|
1138 | } |
---|
1139 | set _sendobjs2 "" |
---|
1140 | blt::busy release $itk_component(hull) |
---|
1141 | |
---|
1142 | # activate the proper volume |
---|
1143 | set first [lindex [get] 0] |
---|
1144 | foreach key [array names _obj2id *-*] { |
---|
1145 | set state [string match $first-* $key] |
---|
1146 | _send volume state $state $_obj2id($key) |
---|
1147 | if {[info exists _obj2style($key)]} { |
---|
1148 | _send volume shading transfunc $_obj2style($key) $_obj2id($key) |
---|
1149 | } |
---|
1150 | } |
---|
1151 | _showIsoMarkers $first |
---|
1152 | # if there are any commands in the buffer, send them now that we're done |
---|
1153 | _send_echo >>line $_buffer(out) |
---|
1154 | if {[catch {puts $_sid $_buffer(out)} err]} { |
---|
1155 | disconnect |
---|
1156 | $_dispatcher event -after 750 !serverDown |
---|
1157 | } |
---|
1158 | set _buffer(out) "" |
---|
1159 | $_dispatcher event -idle !legend |
---|
1160 | } |
---|
1161 | |
---|
1162 | # ---------------------------------------------------------------------- |
---|
1163 | # USAGE: _send_echo <channel> ?<data>? |
---|
1164 | # |
---|
1165 | # Used internally to echo sent data to clients interested in |
---|
1166 | # this widget. If the -sendcommand option is set, then it is |
---|
1167 | # invoked in the global scope with the <channel> and <data> values |
---|
1168 | # as arguments. Otherwise, this does nothing. |
---|
1169 | # ---------------------------------------------------------------------- |
---|
1170 | itcl::body Rappture::NanovisViewer::_send_echo {channel {data ""}} { |
---|
1171 | if {[string length $itk_option(-sendcommand)] > 0} { |
---|
1172 | uplevel #0 $itk_option(-sendcommand) [list $channel $data] |
---|
1173 | } |
---|
1174 | } |
---|
1175 | |
---|
1176 | # ---------------------------------------------------------------------- |
---|
1177 | # USAGE: _receive |
---|
1178 | # |
---|
1179 | # Invoked automatically whenever a command is received from the |
---|
1180 | # rendering server. Reads the incoming command and executes it in |
---|
1181 | # a safe interpreter to handle the action. |
---|
1182 | # ---------------------------------------------------------------------- |
---|
1183 | itcl::body Rappture::NanovisViewer::_receive {} { |
---|
1184 | if {"" != $_sid} { |
---|
1185 | if {[gets $_sid line] < 0} { |
---|
1186 | disconnect |
---|
1187 | _receive_echo closed |
---|
1188 | $_dispatcher event -after 750 !serverDown |
---|
1189 | } elseif {[string equal [string range $line 0 2] "nv>"]} { |
---|
1190 | _receive_echo <<line $line |
---|
1191 | append _buffer(in) [string range $line 3 end] |
---|
1192 | if {[info complete $_buffer(in)]} { |
---|
1193 | set request $_buffer(in) |
---|
1194 | set _buffer(in) "" |
---|
1195 | $_parser eval $request |
---|
1196 | } |
---|
1197 | } else { |
---|
1198 | # this shows errors coming back from the engine |
---|
1199 | _receive_echo <<error $line |
---|
1200 | puts stderr $line |
---|
1201 | } |
---|
1202 | } |
---|
1203 | } |
---|
1204 | |
---|
1205 | # ---------------------------------------------------------------------- |
---|
1206 | # USAGE: _receive_image -bytes <size> |
---|
1207 | # |
---|
1208 | # Invoked automatically whenever the "image" command comes in from |
---|
1209 | # the rendering server. Indicates that binary image data with the |
---|
1210 | # specified <size> will follow. |
---|
1211 | # ---------------------------------------------------------------------- |
---|
1212 | itcl::body Rappture::NanovisViewer::_receive_image {option size} { |
---|
1213 | if {"" != $_sid} { |
---|
1214 | set bytes [read $_sid $size] |
---|
1215 | $_image(plot) configure -data $bytes |
---|
1216 | _receive_echo <<line "<read $size bytes for [image width $_image(plot)]x[image height $_image(plot)] image>" |
---|
1217 | } |
---|
1218 | } |
---|
1219 | |
---|
1220 | # ---------------------------------------------------------------------- |
---|
1221 | # USAGE: _receive_legend <volume> <vmin> <vmax> <size> |
---|
1222 | # |
---|
1223 | # Invoked automatically whenever the "legend" command comes in from |
---|
1224 | # the rendering server. Indicates that binary image data with the |
---|
1225 | # specified <size> will follow. |
---|
1226 | # ---------------------------------------------------------------------- |
---|
1227 | itcl::body Rappture::NanovisViewer::_receive_legend {ivol vmin vmax size} { |
---|
1228 | if {"" != $_sid} { |
---|
1229 | set bytes [read $_sid $size] |
---|
1230 | $_image(legend) configure -data $bytes |
---|
1231 | _receive_echo <<line "<read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>" |
---|
1232 | |
---|
1233 | set c $itk_component(legend) |
---|
1234 | set w [winfo width $c] |
---|
1235 | set h [winfo height $c] |
---|
1236 | if {"" == [$c find withtag transfunc]} { |
---|
1237 | $c create image 10 10 -anchor nw \ |
---|
1238 | -image $_image(legend) -tags transfunc |
---|
1239 | $c create text 10 [expr {$h-8}] -anchor sw \ |
---|
1240 | -fill $itk_option(-plotforeground) -tags vmin |
---|
1241 | $c create text [expr {$w-10}] [expr {$h-8}] -anchor se \ |
---|
1242 | -fill $itk_option(-plotforeground) -tags vmax |
---|
1243 | $c lower transfunc |
---|
1244 | $c bind transfunc <ButtonRelease-1> \ |
---|
1245 | [itcl::code $this _addIsoMarker %x %y] |
---|
1246 | } |
---|
1247 | $c itemconfigure vmin -text $vmin |
---|
1248 | $c coords vmin 10 [expr {$h-8}] |
---|
1249 | |
---|
1250 | $c itemconfigure vmax -text $vmax |
---|
1251 | $c coords vmax [expr {$w-10}] [expr {$h-8}] |
---|
1252 | set first [lindex [get] 0] |
---|
1253 | _showIsoMarkers $first |
---|
1254 | } |
---|
1255 | } |
---|
1256 | |
---|
1257 | # ---------------------------------------------------------------------- |
---|
1258 | # USAGE: _receive_data <volume> <vmin> <vmax> |
---|
1259 | # |
---|
1260 | # Invoked automatically whenever the "legend" command comes in from |
---|
1261 | # the rendering server. Indicates that binary image data with the |
---|
1262 | # specified <size> will follow. |
---|
1263 | # ---------------------------------------------------------------------- |
---|
1264 | itcl::body Rappture::NanovisViewer::_receive_data { args } { |
---|
1265 | if {"" != $_sid} { |
---|
1266 | array set info $args |
---|
1267 | set volume $info(id) |
---|
1268 | foreach { dataobj comp } $_id2obj($volume) break |
---|
1269 | if { ![info exists _limits($dataobj-vmin] } { |
---|
1270 | set _limits($dataobj-vmin) $info(min) |
---|
1271 | set _limits($dataobj-vmax) $info(max) |
---|
1272 | } else { |
---|
1273 | if { $_limits($dataobj-vmin) > $info(min) } { |
---|
1274 | set _limits($dataobj-vmin) $info(min) |
---|
1275 | } |
---|
1276 | if { $_limits($dataobj-vmax) > $info(max) } { |
---|
1277 | set _limits($dataobj-vmax) $info(max) |
---|
1278 | } |
---|
1279 | } |
---|
1280 | set _limits(vmin) $info(vmin) |
---|
1281 | set _limits(vmax) $info(vmax) |
---|
1282 | lappend _sendobjs2 $dataobj |
---|
1283 | unset _receiveids($info(id)) |
---|
1284 | if { [array size _receiveids] == 0 } { |
---|
1285 | after idle [itcl::code $this _send_transfuncs] |
---|
1286 | } |
---|
1287 | } |
---|
1288 | } |
---|
1289 | |
---|
1290 | # ---------------------------------------------------------------------- |
---|
1291 | # USAGE: _receive_echo <channel> ?<data>? |
---|
1292 | # |
---|
1293 | # Used internally to echo received data to clients interested in |
---|
1294 | # this widget. If the -receivecommand option is set, then it is |
---|
1295 | # invoked in the global scope with the <channel> and <data> values |
---|
1296 | # as arguments. Otherwise, this does nothing. |
---|
1297 | # ---------------------------------------------------------------------- |
---|
1298 | itcl::body Rappture::NanovisViewer::_receive_echo {channel {data ""}} { |
---|
1299 | if {[string length $itk_option(-receivecommand)] > 0} { |
---|
1300 | uplevel #0 $itk_option(-receivecommand) [list $channel $data] |
---|
1301 | } |
---|
1302 | } |
---|
1303 | |
---|
1304 | # ---------------------------------------------------------------------- |
---|
1305 | # USAGE: _rebuild |
---|
1306 | # |
---|
1307 | # Called automatically whenever something changes that affects the |
---|
1308 | # data in the widget. Clears any existing data and rebuilds the |
---|
1309 | # widget to display new data. |
---|
1310 | # ---------------------------------------------------------------------- |
---|
1311 | itcl::body Rappture::NanovisViewer::_rebuild {} { |
---|
1312 | # in the midst of sending data? then bail out |
---|
1313 | if {[llength $_sendobjs] > 0} { |
---|
1314 | return |
---|
1315 | } |
---|
1316 | |
---|
1317 | # |
---|
1318 | # Find any new data that needs to be sent to the server. |
---|
1319 | # Queue this up on the _sendobjs list, and send it out |
---|
1320 | # a little at a time. Do this first, before we rebuild |
---|
1321 | # the rest. |
---|
1322 | # |
---|
1323 | foreach dataobj [get] { |
---|
1324 | set comp [lindex [$dataobj components] 0] |
---|
1325 | if {![info exists _obj2id($dataobj-$comp)]} { |
---|
1326 | set i [lsearch -exact $_sendobjs $dataobj] |
---|
1327 | if {$i < 0} { |
---|
1328 | lappend _sendobjs $dataobj |
---|
1329 | } |
---|
1330 | } |
---|
1331 | } |
---|
1332 | if {[llength $_sendobjs] > 0} { |
---|
1333 | # send off new data objects |
---|
1334 | after idle [itcl::code $this _send_dataobjs] |
---|
1335 | } else { |
---|
1336 | # nothing to send -- activate the proper volume |
---|
1337 | set first [lindex [get] 0] |
---|
1338 | if {"" != $first} { |
---|
1339 | set axis [$first hints updir] |
---|
1340 | if {"" != $axis} { |
---|
1341 | _send up $axis |
---|
1342 | } |
---|
1343 | } |
---|
1344 | |
---|
1345 | _showIsoMarkers $first |
---|
1346 | update_transfer_function |
---|
1347 | |
---|
1348 | # sync the state of slicers |
---|
1349 | set vols [_currentVolumeIds -cutplanes] |
---|
1350 | foreach axis {x y z} { |
---|
1351 | eval _send cutplane state [_state ${axis}slice] $axis $vols |
---|
1352 | set pos [expr {0.01*[$itk_component(${axis}slicer) get]}] |
---|
1353 | eval _send cutplane position $pos $axis $vols |
---|
1354 | } |
---|
1355 | eval _send volume data state [_state volume] $vols |
---|
1356 | $_dispatcher event -idle !legend |
---|
1357 | } |
---|
1358 | |
---|
1359 | # |
---|
1360 | # Reset the camera and other view parameters |
---|
1361 | # |
---|
1362 | eval _send camera angle [_euler2xyz $_view(theta) $_view(phi) $_view(psi)] |
---|
1363 | _send camera zoom $_view(zoom) |
---|
1364 | |
---|
1365 | _fixSettings light |
---|
1366 | _fixSettings transp |
---|
1367 | _fixSettings isosurface |
---|
1368 | _fixSettings opacity |
---|
1369 | _fixSettings thickness |
---|
1370 | |
---|
1371 | if {"" == $itk_option(-plotoutline)} { |
---|
1372 | _send volume outline state off |
---|
1373 | } else { |
---|
1374 | _send volume outline state on |
---|
1375 | _send volume outline color [_color2rgb $itk_option(-plotoutline)] |
---|
1376 | } |
---|
1377 | _send volume axis label x "" |
---|
1378 | _send volume axis label y "" |
---|
1379 | _send volume axis label z "" |
---|
1380 | } |
---|
1381 | |
---|
1382 | # ---------------------------------------------------------------------- |
---|
1383 | # USAGE: _currentVolumeIds ?-cutplanes? |
---|
1384 | # |
---|
1385 | # Returns a list of volume server IDs for the current volume being |
---|
1386 | # displayed. This is normally a single ID, but it might be a list |
---|
1387 | # of IDs if the current data object has multiple components. |
---|
1388 | # ---------------------------------------------------------------------- |
---|
1389 | itcl::body Rappture::NanovisViewer::_currentVolumeIds {{what -all}} { |
---|
1390 | set rlist "" |
---|
1391 | |
---|
1392 | set first [lindex [get] 0] |
---|
1393 | foreach key [array names _obj2id *-*] { |
---|
1394 | if {[string match $first-* $key]} { |
---|
1395 | array set style { |
---|
1396 | -cutplanes 1 |
---|
1397 | } |
---|
1398 | foreach {dataobj comp} [split $key -] break |
---|
1399 | array set style [lindex [$dataobj components -style $comp] 0] |
---|
1400 | |
---|
1401 | if {$what != "-cutplanes" || $style(-cutplanes)} { |
---|
1402 | lappend rlist $_obj2id($key) |
---|
1403 | } |
---|
1404 | } |
---|
1405 | } |
---|
1406 | return $rlist |
---|
1407 | } |
---|
1408 | |
---|
1409 | # ---------------------------------------------------------------------- |
---|
1410 | # USAGE: _zoom in |
---|
1411 | # USAGE: _zoom out |
---|
1412 | # USAGE: _zoom reset |
---|
1413 | # |
---|
1414 | # Called automatically when the user clicks on one of the zoom |
---|
1415 | # controls for this widget. Changes the zoom for the current view. |
---|
1416 | # ---------------------------------------------------------------------- |
---|
1417 | itcl::body Rappture::NanovisViewer::_zoom {option} { |
---|
1418 | switch -- $option { |
---|
1419 | in { |
---|
1420 | set _view(zoom) [expr {$_view(zoom)*1.25}] |
---|
1421 | _send camera zoom $_view(zoom) |
---|
1422 | } |
---|
1423 | out { |
---|
1424 | set _view(zoom) [expr {$_view(zoom)*0.8}] |
---|
1425 | _send camera zoom $_view(zoom) |
---|
1426 | } |
---|
1427 | reset { |
---|
1428 | set _view(theta) 45 |
---|
1429 | set _view(phi) 45 |
---|
1430 | set _view(psi) 0 |
---|
1431 | set _view(zoom) 1.0 |
---|
1432 | eval _send camera angle [_euler2xyz $_view(theta) $_view(phi) $_view(psi)] |
---|
1433 | _send camera zoom $_view(zoom) |
---|
1434 | } |
---|
1435 | } |
---|
1436 | } |
---|
1437 | |
---|
1438 | # ---------------------------------------------------------------------- |
---|
1439 | # USAGE: _move click <x> <y> |
---|
1440 | # USAGE: _move drag <x> <y> |
---|
1441 | # USAGE: _move release <x> <y> |
---|
1442 | # |
---|
1443 | # Called automatically when the user clicks/drags/releases in the |
---|
1444 | # plot area. Moves the plot according to the user's actions. |
---|
1445 | # ---------------------------------------------------------------------- |
---|
1446 | itcl::body Rappture::NanovisViewer::_move {option x y} { |
---|
1447 | switch -- $option { |
---|
1448 | click { |
---|
1449 | $itk_component(3dview) configure -cursor fleur |
---|
1450 | set _click(x) $x |
---|
1451 | set _click(y) $y |
---|
1452 | set _click(theta) $_view(theta) |
---|
1453 | set _click(phi) $_view(phi) |
---|
1454 | } |
---|
1455 | drag { |
---|
1456 | if {[array size _click] == 0} { |
---|
1457 | _move click $x $y |
---|
1458 | } else { |
---|
1459 | set w [winfo width $itk_component(3dview)] |
---|
1460 | set h [winfo height $itk_component(3dview)] |
---|
1461 | if {$w <= 0 || $h <= 0} { |
---|
1462 | return |
---|
1463 | } |
---|
1464 | |
---|
1465 | if {[catch { |
---|
1466 | # this fails sometimes for no apparent reason |
---|
1467 | set dx [expr {double($x-$_click(x))/$w}] |
---|
1468 | set dy [expr {double($y-$_click(y))/$h}] |
---|
1469 | }]} { |
---|
1470 | return |
---|
1471 | } |
---|
1472 | |
---|
1473 | # |
---|
1474 | # Rotate the camera in 3D |
---|
1475 | # |
---|
1476 | if {$_view(psi) > 90 || $_view(psi) < -90} { |
---|
1477 | # when psi is flipped around, theta moves backwards |
---|
1478 | set dy [expr {-$dy}] |
---|
1479 | } |
---|
1480 | set theta [expr {$_view(theta) - $dy*180}] |
---|
1481 | while {$theta < 0} { set theta [expr {$theta+180}] } |
---|
1482 | while {$theta > 180} { set theta [expr {$theta-180}] } |
---|
1483 | |
---|
1484 | if {abs($theta) >= 30 && abs($theta) <= 160} { |
---|
1485 | set phi [expr {$_view(phi) - $dx*360}] |
---|
1486 | while {$phi < 0} { set phi [expr {$phi+360}] } |
---|
1487 | while {$phi > 360} { set phi [expr {$phi-360}] } |
---|
1488 | set psi $_view(psi) |
---|
1489 | } else { |
---|
1490 | set phi $_view(phi) |
---|
1491 | set psi [expr {$_view(psi) - $dx*360}] |
---|
1492 | while {$psi < -180} { set psi [expr {$psi+360}] } |
---|
1493 | while {$psi > 180} { set psi [expr {$psi-360}] } |
---|
1494 | } |
---|
1495 | |
---|
1496 | set _view(theta) $theta |
---|
1497 | set _view(phi) $phi |
---|
1498 | set _view(psi) $psi |
---|
1499 | eval _send camera angle [_euler2xyz $_view(theta) $_view(phi) $_view(psi)] |
---|
1500 | |
---|
1501 | set _click(x) $x |
---|
1502 | set _click(y) $y |
---|
1503 | } |
---|
1504 | } |
---|
1505 | release { |
---|
1506 | _move drag $x $y |
---|
1507 | $itk_component(3dview) configure -cursor "" |
---|
1508 | catch {unset _click} |
---|
1509 | } |
---|
1510 | default { |
---|
1511 | error "bad option \"$option\": should be click, drag, release" |
---|
1512 | } |
---|
1513 | } |
---|
1514 | } |
---|
1515 | |
---|
1516 | # ---------------------------------------------------------------------- |
---|
1517 | # USAGE: _slice axis x|y|z ?on|off|toggle? |
---|
1518 | # USAGE: _slice move x|y|z <newval> |
---|
1519 | # USAGE: _slice volume ?on|off|toggle? |
---|
1520 | # |
---|
1521 | # Called automatically when the user drags the slider to move the |
---|
1522 | # cut plane that slices 3D data. Gets the current value from the |
---|
1523 | # slider and moves the cut plane to the appropriate point in the |
---|
1524 | # data set. |
---|
1525 | # ---------------------------------------------------------------------- |
---|
1526 | itcl::body Rappture::NanovisViewer::_slice {option args} { |
---|
1527 | switch -- $option { |
---|
1528 | axis { |
---|
1529 | if {[llength $args] < 1 || [llength $args] > 2} { |
---|
1530 | error "wrong # args: should be \"_slice axis x|y|z ?on|off|toggle?\"" |
---|
1531 | } |
---|
1532 | set axis [lindex $args 0] |
---|
1533 | set op [lindex $args 1] |
---|
1534 | if {$op == ""} { set op "on" } |
---|
1535 | |
---|
1536 | set current [_state ${axis}slice] |
---|
1537 | if {$op == "toggle"} { |
---|
1538 | if {$current == "on"} { set op "off" } else { set op "on" } |
---|
1539 | } |
---|
1540 | |
---|
1541 | if {$op} { |
---|
1542 | $itk_component(${axis}slicer) configure -state normal |
---|
1543 | eval _send cutplane state on $axis [_currentVolumeIds -cutplanes] |
---|
1544 | $itk_component(${axis}slice) configure -relief sunken |
---|
1545 | } else { |
---|
1546 | $itk_component(${axis}slicer) configure -state disabled |
---|
1547 | eval _send cutplane state off $axis [_currentVolumeIds -cutplanes] |
---|
1548 | $itk_component(${axis}slice) configure -relief raised |
---|
1549 | } |
---|
1550 | } |
---|
1551 | move { |
---|
1552 | if {[llength $args] != 2} { |
---|
1553 | error "wrong # args: should be \"_slice move x|y|z newval\"" |
---|
1554 | } |
---|
1555 | set axis [lindex $args 0] |
---|
1556 | set newval [lindex $args 1] |
---|
1557 | |
---|
1558 | set newpos [expr {0.01*$newval}] |
---|
1559 | # set newval [expr {0.01*($newval-50) |
---|
1560 | # *($_limits(${axis}max)-$_limits(${axis}min)) |
---|
1561 | # + 0.5*($_limits(${axis}max)+$_limits(${axis}min))}] |
---|
1562 | |
---|
1563 | # show the current value in the readout |
---|
1564 | #puts "readout: $axis = $newval" |
---|
1565 | |
---|
1566 | eval _send cutplane position $newpos $axis [_currentVolumeIds -cutplanes] |
---|
1567 | } |
---|
1568 | volume { |
---|
1569 | if {[llength $args] > 1} { |
---|
1570 | error "wrong # args: should be \"_slice volume ?on|off|toggle?\"" |
---|
1571 | } |
---|
1572 | set op [lindex $args 0] |
---|
1573 | if {$op == ""} { set op "on" } |
---|
1574 | |
---|
1575 | set current [_state volume] |
---|
1576 | if {$op == "toggle"} { |
---|
1577 | if {$current == "on"} { set op "off" } else { set op "on" } |
---|
1578 | } |
---|
1579 | |
---|
1580 | if {$op} { |
---|
1581 | eval _send volume data state on [_currentVolumeIds] |
---|
1582 | $itk_component(volume) configure -relief sunken |
---|
1583 | } else { |
---|
1584 | eval _send volume data state off [_currentVolumeIds] |
---|
1585 | $itk_component(volume) configure -relief raised |
---|
1586 | } |
---|
1587 | } |
---|
1588 | default { |
---|
1589 | error "bad option \"$option\": should be axis, move, or volume" |
---|
1590 | } |
---|
1591 | } |
---|
1592 | } |
---|
1593 | |
---|
1594 | # ---------------------------------------------------------------------- |
---|
1595 | # USAGE: _slicertip <axis> |
---|
1596 | # |
---|
1597 | # Used internally to generate a tooltip for the x/y/z slicer controls. |
---|
1598 | # Returns a message that includes the current slicer value. |
---|
1599 | # ---------------------------------------------------------------------- |
---|
1600 | itcl::body Rappture::NanovisViewer::_slicertip {axis} { |
---|
1601 | set val [$itk_component(${axis}slicer) get] |
---|
1602 | # set val [expr {0.01*($val-50) |
---|
1603 | # *($_limits(${axis}max)-$_limits(${axis}min)) |
---|
1604 | # + 0.5*($_limits(${axis}max)+$_limits(${axis}min))}] |
---|
1605 | return "Move the [string toupper $axis] cut plane.\nCurrently: $axis = $val%" |
---|
1606 | } |
---|
1607 | |
---|
1608 | # ---------------------------------------------------------------------- |
---|
1609 | # USAGE: _state <component> |
---|
1610 | # |
---|
1611 | # Used internally to determine the state of a toggle button. |
---|
1612 | # The <component> is the itk component name of the button. |
---|
1613 | # Returns on/off for the state of the button. |
---|
1614 | # ---------------------------------------------------------------------- |
---|
1615 | itcl::body Rappture::NanovisViewer::_state {comp} { |
---|
1616 | if {[$itk_component($comp) cget -relief] == "sunken"} { |
---|
1617 | return "on" |
---|
1618 | } |
---|
1619 | return "off" |
---|
1620 | } |
---|
1621 | |
---|
1622 | # ---------------------------------------------------------------------- |
---|
1623 | # USAGE: _fixSettings <what> ?<value>? |
---|
1624 | # |
---|
1625 | # Used internally to update rendering settings whenever parameters |
---|
1626 | # change in the popup settings panel. Sends the new settings off |
---|
1627 | # to the back end. |
---|
1628 | # ---------------------------------------------------------------------- |
---|
1629 | itcl::body Rappture::NanovisViewer::_fixSettings {what {value ""}} { |
---|
1630 | set inner [$itk_component(controls).panel component inner] |
---|
1631 | switch -- $what { |
---|
1632 | light { |
---|
1633 | if {[isconnected]} { |
---|
1634 | set val [$inner.scales.light get] |
---|
1635 | set sval [expr {0.1*$val}] |
---|
1636 | _send volume shading diffuse $sval |
---|
1637 | |
---|
1638 | set sval [expr {sqrt($val+1.0)}] |
---|
1639 | _send volume shading specular $sval |
---|
1640 | } |
---|
1641 | } |
---|
1642 | transp { |
---|
1643 | if {[isconnected]} { |
---|
1644 | set val [$inner.scales.transp get] |
---|
1645 | set sval [expr {0.2*$val+1}] |
---|
1646 | _send volume shading opacity $sval |
---|
1647 | } |
---|
1648 | } |
---|
1649 | opacity { |
---|
1650 | if {[isconnected]} { |
---|
1651 | set dataobj [lindex [get] 0] |
---|
1652 | if {$dataobj != 0} { |
---|
1653 | set val [$inner.scales.opacity get] |
---|
1654 | set sval [expr {0.01*double($val)}] |
---|
1655 | set _opacity($dataobj) $sval |
---|
1656 | update_transfer_function |
---|
1657 | } |
---|
1658 | } |
---|
1659 | } |
---|
1660 | thickness { |
---|
1661 | if {[isconnected]} { |
---|
1662 | set dataobj [lindex [get] 0] |
---|
1663 | if {$dataobj != 0} { |
---|
1664 | set val [$inner.scales.thickness get] |
---|
1665 | # Scale values between 0.00001 and 0.01000 |
---|
1666 | set sval [expr {0.00001*double($val)}] |
---|
1667 | puts stderr "thickness($dataobj) = $sval" |
---|
1668 | set _thickness($dataobj) $sval |
---|
1669 | update_transfer_function |
---|
1670 | } |
---|
1671 | } |
---|
1672 | } |
---|
1673 | isosurface { |
---|
1674 | if {[isconnected]} { |
---|
1675 | set val $Rappture::NanovisViewer::_isosurface($this) |
---|
1676 | set dataobj [lindex [get] 0] |
---|
1677 | _send "volume" "shading" "isosurface" $val |
---|
1678 | } |
---|
1679 | } |
---|
1680 | default { |
---|
1681 | error "don't know how to fix $what" |
---|
1682 | } |
---|
1683 | } |
---|
1684 | } |
---|
1685 | |
---|
1686 | # ---------------------------------------------------------------------- |
---|
1687 | # USAGE: _fixLegend |
---|
1688 | # |
---|
1689 | # Used internally to update the legend area whenever it changes size |
---|
1690 | # or when the field changes. Asks the server to send a new legend |
---|
1691 | # for the current field. |
---|
1692 | # ---------------------------------------------------------------------- |
---|
1693 | itcl::body Rappture::NanovisViewer::_fixLegend {} { |
---|
1694 | set lineht [font metrics $itk_option(-font) -linespace] |
---|
1695 | set w [expr {[winfo width $itk_component(legend)]-20}] |
---|
1696 | set h [expr {[winfo height $itk_component(legend)]-20-$lineht}] |
---|
1697 | set ivol "" |
---|
1698 | |
---|
1699 | set dataobj [lindex [get] 0] |
---|
1700 | if {"" != $dataobj} { |
---|
1701 | set comp [lindex [$dataobj components] 0] |
---|
1702 | if {[info exists _obj2id($dataobj-$comp)]} { |
---|
1703 | set ivol $_obj2id($dataobj-$comp) |
---|
1704 | } |
---|
1705 | } |
---|
1706 | if {$w > 0 && $h > 0 && "" != $ivol} { |
---|
1707 | _send legend $ivol $w $h |
---|
1708 | } else { |
---|
1709 | #$itk_component(legend) delete all |
---|
1710 | } |
---|
1711 | } |
---|
1712 | |
---|
1713 | # ---------------------------------------------------------------------- |
---|
1714 | # USAGE: _serverDown |
---|
1715 | # |
---|
1716 | # Used internally to let the user know when the connection to the |
---|
1717 | # visualization server has been lost. Puts up a tip encouraging the |
---|
1718 | # user to press any control to reconnect. |
---|
1719 | # ---------------------------------------------------------------------- |
---|
1720 | itcl::body Rappture::NanovisViewer::_serverDown {} { |
---|
1721 | set x [expr {[winfo rootx $itk_component(area)]+10}] |
---|
1722 | set y [expr {[winfo rooty $itk_component(area)]+10}] |
---|
1723 | Rappture::Tooltip::cue @$x,$y "Lost connection to visualization server. This happens sometimes when there are too many users and the system runs out of memory.\n\nTo reconnect, reset the view or press any other control. Your picture should come right back up." |
---|
1724 | } |
---|
1725 | |
---|
1726 | # ---------------------------------------------------------------------- |
---|
1727 | # USAGE: _genTransfuncData <dataobj> <comp> |
---|
1728 | # |
---|
1729 | # Used internally to compute the colormap and alpha map used to define |
---|
1730 | # a transfer function for the specified component in a data object. |
---|
1731 | # Returns: name {v r g b ...} {v w ...} |
---|
1732 | # ---------------------------------------------------------------------- |
---|
1733 | itcl::body Rappture::NanovisViewer::_genTransfuncData {dataobj comp} { |
---|
1734 | array set style { |
---|
1735 | -color rainbow |
---|
1736 | -levels 6 |
---|
1737 | -opacity 1.0 |
---|
1738 | } |
---|
1739 | array set style [lindex [$dataobj components -style $comp] 0] |
---|
1740 | set sname "$style(-color):$style(-levels):$style(-opacity)" |
---|
1741 | |
---|
1742 | if {$style(-color) == "rainbow"} { |
---|
1743 | set style(-color) "white:yellow:green:cyan:blue:magenta" |
---|
1744 | } |
---|
1745 | set clist [split $style(-color) :] |
---|
1746 | set cmap "0.0 [_color2rgb white] " |
---|
1747 | for {set i 0} {$i < [llength $clist]} {incr i} { |
---|
1748 | set x [expr {double($i+1)/([llength $clist]+1)}] |
---|
1749 | set color [lindex $clist $i] |
---|
1750 | append cmap "$x [_color2rgb $color] " |
---|
1751 | } |
---|
1752 | append cmap "1.0 [_color2rgb $color]" |
---|
1753 | |
---|
1754 | set max $style(-opacity) |
---|
1755 | if { [info exists _opacity($dataobj)] } { |
---|
1756 | set max $_opacity($dataobj) |
---|
1757 | } |
---|
1758 | set key $dataobj |
---|
1759 | set isovalues {} |
---|
1760 | foreach m $_isomarkers($key) { |
---|
1761 | lappend isovalues [$m get_relative_value] |
---|
1762 | } |
---|
1763 | |
---|
1764 | # Sort the isovalues |
---|
1765 | set isovalues [lsort -real $isovalues] |
---|
1766 | |
---|
1767 | set delta 0.01 |
---|
1768 | if { [info exists _thickness($dataobj)]} { |
---|
1769 | set delta $_thickness($dataobj) |
---|
1770 | } |
---|
1771 | puts stderr "delta=$delta thickness($dataobj)=$_thickness($dataobj)" |
---|
1772 | set first [lindex $isovalues 0] |
---|
1773 | set last [lindex $isovalues end] |
---|
1774 | set wmap "" |
---|
1775 | if { $first == "" || $first != 0.0 } { |
---|
1776 | lappend wmap 0.0 0.0 |
---|
1777 | } |
---|
1778 | foreach x $isovalues { |
---|
1779 | set x1 [expr {$x-$delta-0.00001}] |
---|
1780 | set x2 [expr {$x-$delta}] |
---|
1781 | set x3 [expr {$x+$delta}] |
---|
1782 | set x4 [expr {$x+$delta+0.00001}] |
---|
1783 | if { $x1 < 0.0 } { |
---|
1784 | set x1 0.0 |
---|
1785 | } |
---|
1786 | if { $x2 < 0.0 } { |
---|
1787 | set x2 0.0 |
---|
1788 | } |
---|
1789 | if { $x3 > 1.0 } { |
---|
1790 | set x3 1.0 |
---|
1791 | } |
---|
1792 | if { $x4 > 1.0 } { |
---|
1793 | set x4 1.0 |
---|
1794 | } |
---|
1795 | # add spikes in the middle |
---|
1796 | lappend wmap $x1 0.0 |
---|
1797 | lappend wmap $x2 $max |
---|
1798 | lappend wmap $x3 $max |
---|
1799 | lappend wmap $x4 0.0 |
---|
1800 | } |
---|
1801 | if { $last == "" || $last != 1.0 } { |
---|
1802 | lappend wmap 1.0 0.0 |
---|
1803 | } |
---|
1804 | return [list $sname $cmap $wmap] |
---|
1805 | } |
---|
1806 | |
---|
1807 | # ---------------------------------------------------------------------- |
---|
1808 | # USAGE: _color2rgb <color> |
---|
1809 | # |
---|
1810 | # Used internally to convert a color name to a set of {r g b} values |
---|
1811 | # needed for the engine. Each r/g/b component is scaled in the |
---|
1812 | # range 0-1. |
---|
1813 | # ---------------------------------------------------------------------- |
---|
1814 | itcl::body Rappture::NanovisViewer::_color2rgb {color} { |
---|
1815 | foreach {r g b} [winfo rgb $itk_component(hull) $color] break |
---|
1816 | set r [expr {$r/65535.0}] |
---|
1817 | set g [expr {$g/65535.0}] |
---|
1818 | set b [expr {$b/65535.0}] |
---|
1819 | return [list $r $g $b] |
---|
1820 | } |
---|
1821 | |
---|
1822 | # ---------------------------------------------------------------------- |
---|
1823 | # USAGE: _euler2xyz <theta> <phi> <psi> |
---|
1824 | # |
---|
1825 | # Used internally to convert euler angles for the camera placement |
---|
1826 | # the to angles of rotation about the x/y/z axes, used by the engine. |
---|
1827 | # Returns a list: {xangle, yangle, zangle}. |
---|
1828 | # ---------------------------------------------------------------------- |
---|
1829 | itcl::body Rappture::NanovisViewer::_euler2xyz {theta phi psi} { |
---|
1830 | set xangle [expr {$theta-90.0}] |
---|
1831 | set yangle [expr {180-$phi}] |
---|
1832 | set zangle $psi |
---|
1833 | return [list $xangle $yangle $zangle] |
---|
1834 | } |
---|
1835 | |
---|
1836 | # ---------------------------------------------------------------------- |
---|
1837 | # CONFIGURATION OPTION: -plotbackground |
---|
1838 | # ---------------------------------------------------------------------- |
---|
1839 | itcl::configbody Rappture::NanovisViewer::plotbackground { |
---|
1840 | foreach {r g b} [_color2rgb $itk_option(-plotbackground)] break |
---|
1841 | #fix this! |
---|
1842 | #_send color background $r $g $b |
---|
1843 | } |
---|
1844 | |
---|
1845 | # ---------------------------------------------------------------------- |
---|
1846 | # CONFIGURATION OPTION: -plotforeground |
---|
1847 | # ---------------------------------------------------------------------- |
---|
1848 | itcl::configbody Rappture::NanovisViewer::plotforeground { |
---|
1849 | foreach {r g b} [_color2rgb $itk_option(-plotforeground)] break |
---|
1850 | #fix this! |
---|
1851 | #_send color background $r $g $b |
---|
1852 | } |
---|
1853 | |
---|
1854 | # ---------------------------------------------------------------------- |
---|
1855 | # CONFIGURATION OPTION: -plotoutline |
---|
1856 | # ---------------------------------------------------------------------- |
---|
1857 | itcl::configbody Rappture::NanovisViewer::plotoutline { |
---|
1858 | if {[isconnected]} { |
---|
1859 | if {"" == $itk_option(-plotoutline)} { |
---|
1860 | _send volume outline state off |
---|
1861 | } else { |
---|
1862 | _send volume outline state on |
---|
1863 | _send volume outline color [_color2rgb $itk_option(-plotoutline)] |
---|
1864 | } |
---|
1865 | } |
---|
1866 | } |
---|
1867 | |
---|
1868 | itcl::body Rappture::NanovisViewer::_hideIsoMarkers {dataobj} { |
---|
1869 | if { [info exists _isomarkers($dataobj)] } { |
---|
1870 | foreach m $_isomarkers($dataobj) { |
---|
1871 | $m hide |
---|
1872 | } |
---|
1873 | } |
---|
1874 | } |
---|
1875 | |
---|
1876 | itcl::body Rappture::NanovisViewer::_showIsoMarkers {dataobj} { |
---|
1877 | foreach obj [array names _all_data_objs] { |
---|
1878 | _hideIsoMarkers $obj |
---|
1879 | } |
---|
1880 | if { ![info exists _isomarkers($dataobj)] } { |
---|
1881 | return |
---|
1882 | } |
---|
1883 | foreach m $_isomarkers($dataobj) { |
---|
1884 | $m show |
---|
1885 | } |
---|
1886 | } |
---|
1887 | |
---|
1888 | itcl::body Rappture::NanovisViewer::_initIsoMarkers {dataobj comp} { |
---|
1889 | array set style { |
---|
1890 | -levels 6x |
---|
1891 | } |
---|
1892 | array set style [lindex [$dataobj components -style $comp] 0] |
---|
1893 | set levels $style(-levels) |
---|
1894 | set c $itk_component(legend) |
---|
1895 | regsub -all "," $levels " " levels |
---|
1896 | foreach level $levels { |
---|
1897 | set n [scan $level "%g%s" value suffix] |
---|
1898 | if { $n == 2 && $suffix == "%" } { |
---|
1899 | # ${n}% : Set relative value. |
---|
1900 | set value [expr {$value * 0.01}] |
---|
1901 | set m [IsoMarker \#auto $c $this] |
---|
1902 | $m set_relative_value $value |
---|
1903 | lappend _isomarkers($dataobj) $m |
---|
1904 | } elseif { $n == 2 && $suffix == "x" } { |
---|
1905 | # ${n}x : Set equal number of levels |
---|
1906 | if { $value != round($value) } { |
---|
1907 | error "\# of levels \"$value\" must be an interger" |
---|
1908 | } |
---|
1909 | set nLevels [expr round($value)] |
---|
1910 | for {set i 1} {$i <= $nLevels} {incr i} { |
---|
1911 | set x [expr {double($i)/($nLevels+1)}] |
---|
1912 | set m [IsoMarker \#auto $c $this] |
---|
1913 | $m set_relative_value $x |
---|
1914 | lappend _isomarkers($dataobj) $m |
---|
1915 | } |
---|
1916 | } else { |
---|
1917 | # ${n} : Set absolute value. |
---|
1918 | set m [IsoMarker \#auto $c $this] |
---|
1919 | $m set_absolute_value $value |
---|
1920 | lappend _isomarkers($dataobj) $m |
---|
1921 | } |
---|
1922 | } |
---|
1923 | } |
---|
1924 | |
---|
1925 | # ---------------------------------------------------------------------- |
---|
1926 | # USAGE: _marker start <x> <y> |
---|
1927 | # USAGE: _marker update <x> <y> |
---|
1928 | # USAGE: _marker end <x> <y> |
---|
1929 | # |
---|
1930 | # Used internally to handle the various marker operations performed |
---|
1931 | # when the user clicks and drags on the legend area. The marker changes the |
---|
1932 | # transfer function to highlight the area being selected in the |
---|
1933 | # legend. |
---|
1934 | # ---------------------------------------------------------------------- |
---|
1935 | itcl::body Rappture::NanovisViewer::update_transfer_function {} { |
---|
1936 | set dataobj [lindex [get] 0] |
---|
1937 | if {"" == $dataobj} { |
---|
1938 | return |
---|
1939 | } |
---|
1940 | set comp [lindex [$dataobj components] 0] |
---|
1941 | set key $dataobj-$comp |
---|
1942 | if {![info exists _obj2style($key)]} { |
---|
1943 | return |
---|
1944 | } |
---|
1945 | # Compute a transfer function for the current data set. |
---|
1946 | foreach {sname cmap wmap} [_genTransfuncData $dataobj $comp] break |
---|
1947 | _send transfunc define $_obj2style($key) $cmap $wmap |
---|
1948 | _send volume shading transfunc $_obj2style($key) $_obj2id($key) |
---|
1949 | _fixLegend |
---|
1950 | } |
---|
1951 | |
---|
1952 | itcl::body Rappture::NanovisViewer::_addIsoMarker { x y } { |
---|
1953 | set dataobj [lindex [get] 0] |
---|
1954 | if {$dataobj == ""} { |
---|
1955 | return 0; # No data sets defined |
---|
1956 | } |
---|
1957 | set c $itk_component(legend) |
---|
1958 | set m [IsoMarker \#auto $c $this] |
---|
1959 | set w [winfo width $c] |
---|
1960 | $m set_relative_value [expr {double($x-10)/($w-20)}] |
---|
1961 | $m show |
---|
1962 | lappend _isomarkers($dataobj) $m |
---|
1963 | update_transfer_function |
---|
1964 | return 1 |
---|
1965 | } |
---|
1966 | |
---|
1967 | itcl::body Rappture::NanovisViewer::remove_duplicate_isomarker { marker x } { |
---|
1968 | set dataobj [lindex [get] 0] |
---|
1969 | if {"" == $dataobj} { |
---|
1970 | return 0 |
---|
1971 | } |
---|
1972 | set bool 0 |
---|
1973 | if { [info exists _isomarkers($dataobj)] } { |
---|
1974 | set list {} |
---|
1975 | set marker [namespace tail $marker] |
---|
1976 | foreach m $_isomarkers($dataobj) { |
---|
1977 | set sx [$m get_screen_position] |
---|
1978 | if { $m != $marker } { |
---|
1979 | if { $x >= ($sx-3) && $x <= ($sx+3) } { |
---|
1980 | $marker set_relative_value [$m get_relative_value] |
---|
1981 | itcl::delete object $m |
---|
1982 | bell |
---|
1983 | set bool 1 |
---|
1984 | continue |
---|
1985 | } |
---|
1986 | } |
---|
1987 | lappend list $m |
---|
1988 | } |
---|
1989 | set _isomarkers($dataobj) $list |
---|
1990 | update_transfer_function |
---|
1991 | } |
---|
1992 | return $bool |
---|
1993 | } |
---|
1994 | |
---|
1995 | itcl::body Rappture::NanovisViewer::over_isomarker { marker x } { |
---|
1996 | set dataobj [lindex [get] 0] |
---|
1997 | if {"" == $dataobj} { |
---|
1998 | return "" |
---|
1999 | } |
---|
2000 | if { [info exists _isomarkers($dataobj)] } { |
---|
2001 | set marker [namespace tail $marker] |
---|
2002 | foreach m $_isomarkers($dataobj) { |
---|
2003 | set sx [$m get_screen_position] |
---|
2004 | if { $m != $marker } { |
---|
2005 | set bool [expr { $x >= ($sx-3) && $x <= ($sx+3) }] |
---|
2006 | $m activate $bool |
---|
2007 | } |
---|
2008 | } |
---|
2009 | } |
---|
2010 | return "" |
---|
2011 | } |
---|