1
2
3
4
5 """Viewer.py graphics driver for producing a output file
6 for the Raster3D ray tracer.
7 """
8 import subprocess
9 import copy
10 import random
11 import math
12
13 try:
14 import numpy
15 try:
16 from numpy.oldnumeric import linear_algebra as linalg
17 except ImportError:
18 from numpy.linalg import old as linalg
19 except ImportError:
20 import NumericCompat as numpy
21 from NumericCompat import linalg
22
23 import ConsoleOutput
24 import Constants
25 import Gaussian
26 import AtomMath
27
28
29 MARGIN = 1.15
30 BASE_LINE_WIDTH = 0.05
31
32
34
35
37 """M is a 4x4 rotation-translation matrix, x is a 3x1 vector. Returns
38 the 3x1 vector of x transformed by M.
39 """
40 return numpy.array((M[0,0]*x[0] + M[0,1]*x[1] + M[0,2]*x[2] + M[0,3],
41 M[1,0]*x[0] + M[1,1]*x[1] + M[1,2]*x[2] + M[1,3],
42 M[2,0]*x[0] + M[2,1]*x[1] + M[2,2]*x[2] + M[2,3]), float)
43
48 for fil in self.fils:
49 fil.write(buff)
51 for fil in self.fils:
52 fil.close()
53
55 """Viewer.py graphics driver for producing a output file
56 for the Raster3D ray tracer.
57 """
64
66 self.render_program_path = render_path
67
69 self.render_stdin = stdin
70
72 self.render_png_path = path
73
75 """Re-initalizes driver state variables.
76 """
77 self.object_list = []
78
79 self.matrix = numpy.identity(4, float)
80 self.matrix_stack = []
81
82 self.line_width = 1.0 * BASE_LINE_WIDTH
83
84 self.normal = None
85 self.normalize = False
86
87 self.light_two_sides = False
88
89 self.width = 400
90 self.height = 400
91 self.bg_color_rgbf = (0.0, 0.0, 0.0)
92 self.ambient_light = 0.2
93 self.specular_light = 1.0
94
95 self.material_color_r = 1.0
96 self.material_color_g = 1.0
97 self.material_color_b = 1.0
98 self.material_alpha = 1.0
99
101 """Returns True if draw compiling is supported by the driver.
102 """
103 return False
104
105 - def glr_render_begin(
106 self,
107 width = 200,
108 height = 100,
109 zoom = 50,
110 near = 0,
111 far = 0,
112 bg_color_rgbf = (0.0, 0.0, 0.0),
113 ambient_light = 0.2,
114 diffuse_light = 1.0,
115 specular_light = 1.0,
116 **args):
117 """Sets up lighting and OpenGL options before scene rendering.
118 """
119 self.glr_init_state()
120
121 self.width = width
122 self.height = height
123 self.zoom = zoom
124
125 self.front_clip = near
126 self.back_clip = far
127
128
129 r, g, b = bg_color_rgbf
130 r = r*r
131 g = g*g
132 b = b*b
133 self.bg_color_rgbf = (r,g,b)
134
135
136
137 total_light = ambient_light + diffuse_light + specular_light
138
139 self.ambient = ambient_light / total_light
140 self.specular = specular_light / total_light
141 self.phong = 3
142
143
144 self.object_list.append((8, 0.0, 0, self.front_clip, self.back_clip))
145
147 """Creates the header for the render program.
148 """
149 tsz_width = 16
150 tsz_height = 16
151
152 xtiles = int(round(self.width / float(tsz_width)))
153 ytiles = int(round(self.height / float(tsz_height)))
154
155 pixel_width = xtiles * tsz_width
156 pixel_height = ytiles * tsz_height
157
158
159
160
161 if pixel_width > pixel_height:
162 r = float(pixel_height) / float(pixel_width)
163 z = self.zoom * r
164 else:
165 z = self.zoom
166
167 self.header_list = [
168 "mmLib Generated Raster3D Output",
169 "%d %d tiles in x,y" % (xtiles, ytiles),
170 "%d %d pixels (x,y) per tile" % (tsz_width, tsz_height),
171 "4 anti-aliasing level 4; 3x3->2x2",
172 "%4.2f %4.2f %4.2f background(rgb)" % self.bg_color_rgbf,
173 "F no shadows cast",
174 "%2d Phong power" % (self.phong),
175 "0.20 secondary light contribution",
176 "%4.2f ambient light contribution" % (self.ambient),
177 "%4.2f specular reflection component" % (self.specular),
178 "0.0 eye position(no perspective)",
179 "1 1 1 main light source position",
180 "1 0 0 0 4x4 view matrix",
181 "0 1 0 0",
182 "0 0 1 0",
183 "0 0 0 %f" % (z),
184 "3 mixed objects",
185 "* (free format triangle and plane descriptors)",
186 "* (free format sphere descriptors",
187 "* (free format cylinder descriptors)",
188 "16",
189 "FRONTCLIP %8.3f" % (self.front_clip),
190 "16",
191 "BACKCLIP %8.3f" % (self.back_clip),
192 ]
193
195 """Write out the input file for the render program.
196 """
197
198 pobj = None
199
200 if self.render_stdin is not None:
201 stdin = self.render_stdin
202 else:
203 cmdlist = [self.render_program_path, "-png", self.render_png_path, "-gamma", "1.5"]
204 try:
205 pobj = subprocess.Popen(cmdlist,
206 stdin = subprocess.PIPE,
207 stdout = subprocess.PIPE,
208 stderr = subprocess.STDOUT,
209 close_fds = True,
210 bufsize = 32768)
211 except OSError:
212 ConsoleOutput.warning("the render program failed to execute from path: %s" % (
213 self.render_program_path))
214 return
215
216 stdin = pobj.stdin
217
218
219
220
221
222
223 self.glr_construct_header()
224
225 try:
226 stdin.write("\n".join(self.header_list))
227 stdin.write("\n")
228 self.glr_write_objects(stdin)
229 except IOError, err:
230 ConsoleOutput.warning("IOError while executing %s" % (self.render_program_path))
231 ConsoleOutput.warning(str(err))
232 return
233
234 if self.render_stdin is not None:
235 self.render_stdin = None
236
237 if pobj is not None:
238 pobj.stdin.close()
239 pobj.wait()
240
242 """Write the graphic objects to the stdin file.
243 """
244
245 for gob in self.object_list:
246 gob_type = gob[0]
247
248
249 if gob_type==1:
250 stdin.write(
251 "1\n"\
252 "%8.3f %8.3f %8.3f "\
253 "%8.3f %8.3f %8.3f "\
254 "%8.3f %8.3f %8.3f "\
255 "%4.2f %4.2f %4.2f\n" % (
256 gob[1][0], gob[1][1], gob[1][2],
257 gob[2][0], gob[2][1], gob[2][2],
258 gob[3][0], gob[3][1], gob[3][2],
259 gob[4], gob[5], gob[6]))
260
261
262 elif gob_type==2:
263 stdin.write(
264 "2\n"\
265 "%8.3f %8.3f %8.3f %8.3f %4.2f %4.2f %4.2f\n" % (
266 gob[1][0], gob[1][1], gob[1][2],
267 gob[2],
268 gob[3], gob[4], gob[5]))
269
270
271 elif gob_type==3:
272 stdin.write(
273 "3\n"\
274 "%8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f 0 "\
275 "%4.2f %4.2f %4.2f\n" % (
276 gob[1][0], gob[1][1], gob[1][2],
277 gob[3],
278 gob[2][0], gob[2][1], gob[2][2],
279 gob[4], gob[5], gob[6]))
280
281
282 elif gob_type==5:
283 stdin.write(
284 "5\n"\
285 "%8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f 0 "\
286 "%4.2f %4.2f %4.2f\n" % (
287 gob[1][0], gob[1][1], gob[1][2],
288 gob[3],
289 gob[2][0], gob[2][1], gob[2][2],
290 gob[4], gob[5], gob[6]))
291
292
293 elif gob_type==7:
294 stdin.write(
295 "7\n"\
296 "%8.3f %8.3f %8.3f "\
297 "%8.3f %8.3f %8.3f "\
298 "%8.3f %8.3f %8.3f\n" % (
299 gob[1][0], gob[1][1], gob[1][2],
300 gob[2][0], gob[2][1], gob[2][2],
301 gob[3][0], gob[3][1], gob[3][2] ))
302
303
304 elif gob_type==8:
305
306 stdin.write(
307 "%d\n"\
308 "-1 -1 -1 -1 -1 %4.2f %1d 0 0 2\n"\
309 "FRONTCLIP %8.3f\n"\
310 "BACKCLIP %8.2f\n" % gob)
311
312
313 elif gob_type==14:
314 q = gob[6]
315
316 stdin.write(
317 "14\n"\
318 "%8.3f %8.3f %8.3f "\
319 "%8.3f "\
320 "%4.2f %4.2f %4.2f "\
321 "%8.3f %8.3f %8.3f %8.3f %8.3f %8.3f 0 0 0 %8.3f\n" % (
322 gob[1][0], gob[1][1], gob[1][2],
323 gob[2],
324 gob[3], gob[4], gob[5],
325 q[0,0], q[1,1], q[2,2], q[0,1], q[1,2], q[0,2],
326 gob[7]))
327
329 """
330 """
331 assert len(self.matrix_stack)<=25
332 self.matrix_stack.append(self.matrix.copy())
333
335 """
336 """
337 self.matrix = self.matrix_stack[-1]
338 self.matrix_stack = self.matrix_stack[:-1]
339
341 """Translates the scene by vector t.
342 """
343 M = numpy.array( [[ 1.0, 0.0, 0.0, t[0]],
344 [ 0.0, 1.0, 0.0, t[1]],
345 [ 0.0, 0.0, 1.0, t[2]],
346 [ 0.0, 0.0, 0.0, 1.0]], float)
347
348 self.matrix = numpy.dot(self.matrix, M)
349
351 """
352 """
353 M = numpy.array( [[ 1.0, 0.0, 0.0, x],
354 [ 0.0, 1.0, 0.0, y],
355 [ 0.0, 0.0, 1.0, z],
356 [ 0.0, 0.0, 0.0, 1.0]], float)
357
358 self.matrix = numpy.dot(self.matrix, M)
359
361 """Return the current matrix as a 3x3 rotation matrix R and 3x1
362 translation vector t.
363 """
364 M = numpy.array( [[R[0,0], R[0,1], R[0,2], t[0]],
365 [R[1,0], R[1,1], R[1,2], t[1]],
366 [R[2,0], R[2,1], R[2,2], t[2]],
367 [ 0.0, 0.0, 0.0, 1.0]], float)
368
369 self.matrix = numpy.dot(self.matrix, M)
370
372 """Multiplies the current matrix by rotation matrix R and translates
373 by t
374 """
375 M = numpy.array( [[R[0,0], R[0,1], R[0,2], 0.0],
376 [R[1,0], R[1,1], R[1,2], 0.0],
377 [R[2,0], R[2,1], R[2,2], 0.0],
378 [ 0.0, 0.0, 0.0, 1.0]], float)
379
380 self.matrix = numpy.dot(self.matrix, M)
381
387
392
397
402
404 """Creates a stock rendering material colored according to the given
405 RGB values.
406 """
407 self.material_color_r = r*r
408 self.material_color_g = g*g
409 self.material_color_b = b*b
410
411 if self.material_alpha<1.0:
412 self.material_alpha = 1.0
413
414 if self.light_two_sides==True:
415 self.object_list.append(
416 (8, 0.0, 2,
417 self.front_clip, self.back_clip))
418 else:
419 self.object_list.append(
420 (8, 0.0, 0,
421 self.front_clip, self.back_clip))
422
424 """Creates a stock rendering material colored according to the given
425 RGB values.
426 """
427 self.material_color_r = r*r
428 self.material_color_g = g*g
429 self.material_color_b = b*b
430
431 if self.material_alpha!=a:
432 self.material_alpha = a
433
434 if self.light_two_sides==True:
435 self.object_list.append(
436 (8, 1.0 - self.material_alpha, 2,
437 self.front_clip, self.back_clip))
438 else:
439 self.object_list.append(
440 (8, 1.0 - self.material_alpha, 0,
441 self.front_clip, self.back_clip))
442
444 """
445 """
446 self.glr_vertex_func(vertex)
447
449 """
450 """
451 self.glr_vertex_func((x,y,z))
452
457
462
464 self.glr_vertex_func = self.glr_vertex_quads_1
465 self.glr_end = self.glr_end_quads
466 self.vertex_1 = None
467 self.normal_1 = None
468 self.vertex_2 = None
469 self.normal_2 = None
470 self.vertex_3 = None
471 self.normal_3 = None
472
474 del self.glr_vertex_func
475 del self.glr_end
476 del self.vertex_1
477 del self.normal_1
478 del self.vertex_2
479 del self.normal_2
480 del self.vertex_3
481 del self.normal_3
482
484 self.glr_vertex_func = self.glr_vertex_quads_2
485 self.normal_1 = self.normal
486 self.vertex_1 = dot43(self.matrix, vertex)
487
489 self.glr_vertex_func = self.glr_vertex_quads_3
490 self.normal_2 = self.normal
491 self.vertex_2 = dot43(self.matrix, vertex)
492
494 self.glr_vertex_func = self.glr_vertex_quads_4
495 self.normal_3 = self.normal
496 self.vertex_3 = dot43(self.matrix, vertex)
497
499 self.glr_vertex_func = self.glr_vertex_quads_1
500
501 normal_4 = self.normal
502 vertex_4 = dot43(self.matrix, vertex)
503
504 self.object_list.append(
505 (1,
506 self.vertex_1,
507 self.vertex_2,
508 self.vertex_3,
509 self.material_color_r,
510 self.material_color_g,
511 self.material_color_b))
512
513 self.object_list.append(
514 (7,
515 self.normal_1,
516 self.normal_2,
517 self.normal_3))
518
519 self.object_list.append(
520 (1,
521 self.vertex_1,
522 self.vertex_3,
523 vertex_4,
524 self.material_color_r,
525 self.material_color_g,
526 self.material_color_b))
527
528 self.object_list.append(
529 (7,
530 self.normal_1,
531 self.normal_3,
532 normal_4))
533
543
545 """
546 """
547 del self.glr_vertex_func
548 del self.glr_end
549 del self.vertex_1
550 del self.vertex_2
551 del self.normal_1
552 del self.normal_2
553
555 """Get (first) common fan vertex.
556 """
557 self.glr_vertex_func = self.glr_vertex_triangle_fan_2
558
559 self.vertex_1 = dot43(self.matrix, vertex)
560 self.normal_1 = self.normal
561
563 """Get second vertex.
564 """
565 self.glr_vertex_func = self.glr_vertex_triangle_fan_3
566
567 self.vertex_2 = dot43(self.matrix, vertex)
568 self.normal_2 = self.normal
569
571 """Get third vertex and beyond: construct triangles.
572 """
573 vertex_3 = dot43(self.matrix, vertex)
574 normal_3 = self.normal
575
576 self.object_list.append(
577 (1,
578 self.vertex_1,
579 self.vertex_2,
580 vertex_3,
581 self.material_color_r,
582 self.material_color_g,
583 self.material_color_b) )
584
585 self.object_list.append(
586 (7,
587 self.normal_1,
588 self.normal_2,
589 normal_3) )
590
591 self.vertex_2 = vertex_3
592 self.normal_2 = normal_3
593
598
603
605 """
606 """
607
608 R = self.matrix[:3,:3]
609 nr = numpy.dot(R, n)
610
611 if self.normalize==True:
612 self.normal = AtomMath.normalize(nr)
613 else:
614 self.normal = nr
615
617 """
618 """
619
620 R = self.matrix[:3,:3]
621 n = numpy.array([x, y, z], float)
622 nr = numpy.dot(R, n)
623
624 if self.normalize==True:
625 self.normal = AtomMath.normalize(nr)
626 else:
627 self.normal = nr
628
630 """
631 """
632 self.light_two_sides = True
633 self.object_list.append(
634 (8, 1.0 - self.material_alpha, 2,
635 self.front_clip, self.back_clip))
636
638 """
639 """
640 self.light_two_sides = False
641 self.object_list.append(
642 (8, 1.0 - self.material_alpha, 0,
643 self.front_clip, self.back_clip))
644
645 - def glr_line(self, position1, position2):
646 """Draws a single line.
647 """
648 self.object_list.append(
649 (3,
650 dot43(self.matrix, position1),
651 dot43(self.matrix, position2),
652 self.line_width,
653 self.material_color_r,
654 self.material_color_g,
655 self.material_color_b))
656
657 - def glr_text(self, text, scale):
658 """Renders a text string.
659 """
660 pass
661
662 - def glr_axis(self, position, axis, radius):
663 """Draw a vector axis using the current set material at position
664 with the given radius.
665 """
666
667 if numpy.allclose(AtomMath.length(axis), 0.0):
668 return
669
670 self.object_list.append(
671 (5,
672 dot43(self.matrix, position),
673 dot43(self.matrix, position + axis),
674 radius,
675 self.material_color_r,
676 self.material_color_g,
677 self.material_color_b))
678
679 - def glr_tube(self, position1, position2, radius):
680 """Draws a hollow tube beginning at pos1, and ending at pos2.
681 """
682 self.object_list.append(
683 (5,
684 dot43(self.matrix, position1),
685 dot43(self.matrix, position2),
686 radius,
687 self.material_color_r,
688 self.material_color_g,
689 self.material_color_b))
690
692 """Draw a atom as a CPK sphere.
693 """
694 self.object_list.append(
695 (2,
696 dot43(self.matrix, position),
697 radius,
698 self.material_color_r,
699 self.material_color_g,
700 self.material_color_b))
701
702 - def glr_cross(self, position, color, line_width):
703 """Draws atom with a cross of lines.
704 """
705 pass
706
707 - def glr_Uaxes(self, position, U, prob, color, line_width):
708 """Draw the anisotropic axies of the atom at the given probability.
709 """
710
711 R = self.matrix[:3,:3]
712 Ur = numpy.dot(numpy.dot(R, U), numpy.transpose(R))
713
714 evals, evecs = linalg.eigenvectors(Ur)
715
717 """Renders the ellipsoid enclosing the given fractional probability
718 given the gaussian variance-covariance matrix U at the given position.
719 C=1.8724 = 68%
720 """
721
722 R = self.matrix[:3,:3]
723 Ur = numpy.dot(numpy.dot(R, U), numpy.transpose(R))
724
725 Umax = max(linalg.eigenvalues(Ur))
726 try:
727 limit_radius = Gaussian.GAUSS3C[prob] * MARGIN * math.sqrt(Umax)
728 except ValueError:
729 limit_radius = 2.0
730
731 try:
732 Q = linalg.inverse(Ur)
733 except linalg.LinAlgError:
734 return
735
736 self.object_list.append(
737 (14,
738 dot43(self.matrix, position),
739 limit_radius,
740 self.material_color_r,
741 self.material_color_g,
742 self.material_color_b,
743 Q,
744 -Gaussian.GAUSS3C[prob]**2))
745
747 """Renders the root mean square (one standard deviation) surface of
748 the
749 gaussian variance-covariance matrix U at the given position. This
750 is a peanut-shaped surface. (Note: reference the peanut paper!)
751 """
752 pass
753