Ticket #9855: trac_9855_tachyon.patch
File trac_9855_tachyon.patch, 17.5 KB (added by , 10 years ago) 


sage/plot/plot3d/tachyon.py
# HG changeset patch # User Marshall Hampton <hamptonio@gmail.com> # Date 1284238603 18000 # Node ID 29d76f1e05dc8be7029720ee5d9640087671f162 # Parent c58f82863c75b2e53662e08cd550bb398653174c trac_9855: fix support for project options in tachyon diff r c58f82863c75 r 29d76f1e05dc sage/plot/plot3d/tachyon.py
a b 15 15 16 16 One can also directly control Tachyon, which gives a huge amount of 17 17 flexibility. For example, here we directly use Tachyon to draw 3 18 spheres on the coordinate axes. Notice that the result is 19 gorgeous:: 18 spheres on the coordinate axes:: 20 19 21 20 sage: t = Tachyon(xres=500,yres=500, camera_center=(2,0,0)) 22 21 sage: t.light((4,3,2), 0.2, (1,1,1)) … … 28 27 sage: t.sphere((0,0,0.5), 0.2, 't4') 29 28 sage: t.show() 30 29 30 For scenes with many reflections it is helpful to increase the raydepth option, and turn on antialiasing. The following scene is an extreme case with many reflections between four cotangent spheres:: 31 32 sage: t = Tachyon(camera_center=(0,4,1), xres = 800, yres = 600, raydepth = 12, aspectratio=.75, antialiasing = 4) 33 sage: t.light((0.02,0.012,0.001), 0.01, (1,0,0)) 34 sage: t.light((0,0,10), 0.01, (0,0,1)) 35 sage: t.texture('s', color = (.8,1,1), opacity = .9, specular = .95, diffuse = .3, ambient = 0.05) 36 sage: t.texture('p', color = (0,0,1), opacity = 1, specular = .2) 37 sage: t.sphere((1,.57735,0.7071),1,'s') 38 sage: t.sphere((1,.57735,0.7071),1,'s') 39 sage: t.sphere((0,1.15465,0.7071),1,'s') 40 sage: t.sphere((0,0,0.9259),1,'s') 41 sage: t.plane((0,0,1.9259),(0,0,1),'p') 42 sage: t.show() # long time 43 44 Different projection options are available. The following examples all use a sphere and cube:: 45 46 sage: cedges = [[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], \ 47 [1, 1, 1]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]], \ 48 [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], \ 49 [1, 1, 1]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]],\ 50 [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]]] 51 52 The default projection is 'perspective':: 53 54 sage: t = Tachyon(xres = 800, yres = 600, camera_center = (1.5,0.0,0.0), zoom = .2) 55 sage: t.texture('t1',color=(0,0,1)) 56 sage: for ed in cedges: 57 ... t.fcylinder(ed[0],ed[1],.05,'t1') 58 sage: t.light((4,4,4),.1,(1,1,1)) 59 sage: t.show() 60 61 Another option is projection='fisheye', which requires frustrum information. The frustrum data is [bottom angle, top angle, left angle, right angle]:: 62 63 sage: t = Tachyon(xres = 800, yres = 600, camera_center = (1.5,0.0,0.0), \ 64 projection='fisheye', frustum=(1.2, 1.2, 1.2, 1.2)) 65 sage: t.texture('t1',color=(0,0,1)) 66 sage: for ed in cedges: 67 ... t.fcylinder(ed[0],ed[1],.05,'t1') 68 sage: t.light((4,4,4),.1,(1,1,1)) 69 sage: t.show() 70 71 Finally there is the projection=perspective_dof option. This may not be implemented correctly; sometimes the setting seems to be ignored:: 72 73 sage: T = Tachyon(xres=800,antialiasing=4, raydepth=10, projection = 'perspective_dof', focallength = '1.0', aperture = '.0025') 74 sage: T.light((0,5,7),1.0,(1,1,1)) 75 sage: T.texture('t1', opacity=1, specular = .3) 76 sage: T.texture('t2', opacity=1, specular = .3, color = (0,0,1)) 77 sage: T.texture('t3', opacity = 1, specular = 1, color = (1,.8,1), diffuse=0.2) 78 sage: T.plane((0,0,1),(0,0,1),'t3') 79 sage: ttlist = ['t1','t2'] 80 sage: tt = 't1' 81 sage: T.cylinder((0,0,.1),(1,1/3,0),.05,'t3') 82 sage: for q in srange(3,100,.15): 83 ... if tt == 't1': 84 ... tt = 't2' 85 ... else: 86 ... tt = 't1' 87 ... T.sphere((q,q/3+.3*sin(3*q),.1+.3*cos(3*q)), .1, tt) 88 sage: T.show() 89 90 Image files in the ppm format can be used to tile planes or cover cylinders or spheres. In this example an image is created and then used to tile the plane:: 91 92 sage: from sage.misc.misc import tmp_filename 93 sage: T = Tachyon(xres = 800, yres = 600, camera_center = (2.0,.1,.3), projection='fisheye', frustum=(1.0, 1.0, 1.0, 1.0)) 94 sage: T.texture('t1',color=(0,0,1)) 95 sage: for ed in cedges: 96 ... T.fcylinder(ed[0],ed[1],.05,'t1') 97 sage: T.light((4,4,4),.1,(1,1,1)) 98 99 sage: fname = tmp_filename() 100 sage: T.save(fname+'.png') 101 sage: r2 = os.system('convert '+fname+'.png '+DATA+'t1.ppm') # optional 102 sage: T = Tachyon(xres = 800, yres = 600, camera_center = (2.0,.1,.3), projection='fisheye', frustum=(1.0, 1.0, 1.0, 1.0)) # optional 103 sage: T.texture('t1',color=(1,0,0), specular=.9) # optional 104 sage: T.texture('p1',color=(1,1,1),opacity = .1, imagefile=DATA+'t1.ppm', texfunc=9) # optional 105 sage: T.sphere((0,0,0),.5,'t1') # optional 106 sage: T.plane((0,0,1),(0,0,1),'p1') # optional 107 sage: T.light((4,4,4),.1,(1,1,1)) # optional 108 sage: T.show() # optional 109 sage: os.unlink(fname+'.png') # optional 110 111 31 112 AUTHOR: 32 113 33 114  John E. Stone (johns@megapixel.com): wrote tachyon ray tracer … … 40 121 41 122  Leif Hille: key idea for bugfix for texfunc issue (trac #799) 42 123 43  Marshall Hampton: improved doctests, rings, axisaligned boxes .124  Marshall Hampton: improved doctests, rings, axisaligned boxes, documentation. 44 125 45 126 TODO: 46 127 … … 72 153  ``xres``  (default 350) 73 154  ``yres``  (default 350) 74 155  ``zoom``  (default 1.0) 75  ``antialiasing``  (default False) 156  ``antialiasing``  (default False) Values larger than 1 157 oversample, improves quality at the cost of speed. 76 158  ``aspectratio``  (default 1.0) 77 159  ``raydepth``  (default 5) 78 160  ``camera_center``  (default (3, 0, 0)) 79 161  ``updir``  (default (0, 0, 1)) 80 162  ``look_at``  (default (0,0,0)) 81  ``viewdir``  (default None) 82  ``projection``  (default 'PERSPECTIVE') 163  ``viewdir``  (default None), otherwise list of three numbers 164  ``frustum``  (default ''), otherwise list of four numbers. Only 165 used with projection='fisheye'. 166  ``focallength``  (default ''), otherwise a number. Only used 167 with projection='perspective_dof'. 168  ``aperture``  (default ''), otherwise a number. Only used 169 with projection='perspective_dof'. 170  ``projection``  (default 'PERSPECTIVE'), otherwise 171 'perspective_dof' or 'fisheye'. 83 172 84 173 OUTPUT: A Tachyon 3d scene. 85 174 … … 199 288 sage: t.texture('white', color=(1,1,1), opacity=1, specular=1, diffuse=1) 200 289 sage: t.plane((0,0,100), (0,0,100), 'white') 201 290 sage: t.show() 291 292 Use of a fisheye lens perspective. 293 294 :: 295 296 sage: T = Tachyon(xres = 800, yres = 600, camera_center = (1.5,1.5,.3), projection='fisheye', frustum=(1.0, 1.0, 1.0, 1.0)) 297 sage: T.texture('t1',color=(0,0,1)) 298 sage: cedges = [[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]],\ 299 [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], \ 300 [1, 1, 1]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]],\ 301 [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], \ 302 [1, 1, 1]], [[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]]] 303 sage: for ed in cedges: 304 ... T.fcylinder(ed[0],ed[1],.05,'t1') 305 sage: T.light((4,4,4),.1,(1,1,1)) 306 sage: T.show() 307 308 Use of the projection=perspective_dof option. This may not be implemented correctly. 309 310 :: 311 312 sage: T = Tachyon(xres=800,antialiasing=4, raydepth=10, projection = 'perspective_dof', focallength = '1.0', aperture = '.0025') 313 sage: T.light((0,5,7),1.0,(1,1,1)) 314 sage: T.texture('t1', opacity=1, specular = .3) 315 sage: T.texture('t2', opacity=1, specular = .3, color = (0,0,1)) 316 sage: T.texture('t3', opacity = 1, specular = 1, color = (1,.8,1), diffuse=0.2) 317 sage: T.plane((0,0,1),(0,0,1),'t3') 318 sage: ttlist = ['t1','t2'] 319 sage: tt = 't1' 320 sage: T.cylinder((0,0,.1),(1,1/3,0),.05,'t3') 321 sage: for q in srange(3,100,.15): 322 ... if tt == 't1': 323 ... tt = 't2' 324 ... else: 325 ... tt = 't1' 326 ... T.sphere((q,q/3+.3*sin(3*q),.1+.3*cos(3*q)), .1, tt) 327 sage: T.show() 328 202 329 """ 203 330 def __init__(self, 204 331 xres=350, yres=350, … … 210 337 updir = (0, 0, 1), 211 338 look_at = (0,0,0), 212 339 viewdir = None, 213 projection = 'PERSPECTIVE'): 340 projection = 'PERSPECTIVE', focallength = '', 341 aperture = '', 342 frustum = ''): 214 343 r""" 215 344 Creates an instance of the Tachyon class. 216 345 … … 229 358 self._camera_center = camera_center 230 359 self._updir = updir 231 360 self._projection = projection 361 self._focallength = focallength 362 self._aperture = aperture 363 self._frustum = frustum 232 364 self._objects = [] 233 365 if viewdir is None: 234 366 self._viewdir = [look_at[i]  camera_center[i] for i in range(3)] … … 346 478 347 479 sage: t = Tachyon(raydepth = 16, zoom = 2, antialiasing = True) 348 480 sage: t._camera().split()[3:10] 349 [' aspectratio', '1.0', 'antialiasing', '1', 'raydepth', '16', 'center']481 ['zoom', '2.0', 'aspectratio', '1.0', 'antialiasing', '1', 'raydepth'] 350 482 """ 351 returnr"""483 camera_out = r""" 352 484 camera 485 projection %s"""%(tostr(self._projection)) 486 if self._focallength != '': 487 camera_out = camera_out + r""" 488 focallength %s"""%(float(self._focallength)) 489 if self._aperture != '': 490 camera_out = camera_out + r""" 491 aperture %s"""%(float(self._aperture)) 492 camera_out = camera_out + r""" 353 493 zoom %s 354 494 aspectratio %s 355 495 antialiasing %s 356 496 raydepth %s 357 497 center %s 358 498 viewdir %s 359 updir %s 360 end_camera 361 """%(float(self._zoom), float(self._aspectratio), 499 updir %s"""%(float(self._zoom), 500 float(self._aspectratio), 362 501 int(self._antialiasing), 363 502 int(self._raydepth), 364 503 tostr(self._camera_center), 365 504 tostr(self._viewdir), 366 505 tostr(self._updir)) 506 if self._frustum != '': 507 camera_out = camera_out + r""" 508 frustum %s"""%(tostr(self._frustum)) 509 camera_out = camera_out + r""" 510 end_camera""" 511 return camera_out 367 512 368 513 def str(self): 369 514 r""" … … 380 525 sage: t.sphere((0.5,0,0), 0.2, 't3') 381 526 sage: t.sphere((0,0,0.5), 0.2, 't4') 382 527 sage: t.str().find('PLASTIC') 383 5 67528 595 384 529 """ 385 530 return r""" 386 531 begin_scene … … 397 542 r""" 398 543 Creates a light source of the given center, radius, and color. 399 544 400 EXAMPLES::545 TESTS:: 401 546 402 547 sage: q = Tachyon() 403 548 sage: q.light((1,1,1),1.0,(.2,0,.8)) 404 sage: q.str().split('\n')[17] 405 ' light center 1.0 1.0 1.0 ' 549 sage: lightindex = q.str().index('light') 550 sage: q.str()[lightindex:].split('\n')[0] 551 'light center 1.0 1.0 1.0 ' 406 552 """ 407 553 self._objects.append(Light(center, radius, color)) 408 554 409 def texfunc(self, t ype=0, center=(0,0,0), rotate=(0,0,0), scale=(1,1,1)):555 def texfunc(self, ttype=0, center=(0,0,0), rotate=(0,0,0), scale=(1,1,1), imagefile = ''): 410 556 r""" 411 557 INPUT: 412 558 … … 420 566 5. 3D gradient noise function (can't remember what it looks 421 567 like) 422 568 6. Don't remember 423 7. Cylindrical Image Map, requires ppm filename (don't know 424 how to specify name in sage?!) 425 8. Spherical Image Map, requires ppm filename (don't know 426 how to specify name in sage?!) 427 9. Planar Image Map, requires ppm filename (don't know how 428 to specify name in sage?!) 569 7. Cylindrical Image Map, requires ppm filename (with path) 570 8. Spherical Image Map, requires ppm filename (with path) 571 9. Planar Image Map, requires ppm filename (with path) 429 572 430 573  ``center``  (default: (0,0,0)) 431 574  ``rotate``  (default: (0,0,0)) … … 439 582 sage: t.plane((0,0,0),(0,0,1),'black') 440 583 sage: t.show() 441 584 """ 442 t ype = int(type)443 if t ype < 0 ortype > 9:585 ttype = int(ttype) 586 if ttype < 0 or ttype > 9: 444 587 raise ValueError, "type must be an integer between 0 and 9" 445 return Texfunc(t ype,center,rotate,scale).str()588 return Texfunc(ttype,center,rotate,scale,imagefile=imagefile).str() 446 589 447 590 def texture(self, name, ambient=0.2, diffuse=0.8, 448 591 specular=0.0, opacity=1.0, 449 color=(1.0,0.0, 0.5), texfunc=0, phong=0, phongsize=.5, phongtype="PLASTIC" ):592 color=(1.0,0.0, 0.5), texfunc=0, phong=0, phongsize=.5, phongtype="PLASTIC", imagefile = ''): 450 593 r""" 451 594 INPUT: 452 595 … … 490 633 sage: show(t) 491 634 """ 492 635 if texfunc and not isinstance(texfunc, Texfunc): 493 texfunc = self.texfunc(int(texfunc) )636 texfunc = self.texfunc(int(texfunc), imagefile=imagefile) 494 637 self._objects.append(Texture(name, ambient, diffuse, 495 638 specular, opacity, color, texfunc, 496 phong,phongsize,phongtype ))639 phong,phongsize,phongtype,imagefile=imagefile)) 497 640 498 641 def texture_recolor(self, name, colors): 499 642 r""" … … 570 713 r""" 571 714 Creates an infinite plane with the given center and normal. 572 715 573 EXAMPLES::716 TESTS:: 574 717 575 718 sage: t = Tachyon() 576 719 sage: t.plane((0,0,0),(1,1,1),'s') 577 sage: t.str()[338:380] 720 sage: plane_pos = t.str().index('plane') 721 sage: t.str()[plane_pos:plane_pos+42] 578 722 'plane center 0.0 0.0 0.0 normal 1.0 1.0' 579 723 """ 580 724 self._objects.append(Plane(center, normal, texture)) … … 606 750 sage: t = Tachyon() 607 751 sage: t.fcylinder((1,1,1),(1,2,3),.01,'s') 608 752 sage: len(t.str()) 609 4 23753 451 610 754 """ 611 755 self._objects.append(FCylinder(base, apex, radius, texture)) 612 756 … … 804 948 tostr(self._color)) 805 949 806 950 class Texfunc: 807 def __init__(self, t ype=0,center=(0,0,0), rotate=(0,0,0), scale=(1,1,1)):951 def __init__(self, ttype=0,center=(0,0,0), rotate=(0,0,0), scale=(1,1,1), imagefile = ''): 808 952 r""" 809 953 Creates a texture function. 810 954 … … 812 956 813 957 sage: from sage.plot.plot3d.tachyon import Texfunc 814 958 sage: t = Texfunc() 815 sage: t._t ype959 sage: t._ttype 816 960 0 817 961 """ 818 self._t ype =type962 self._ttype = ttype 819 963 self._center = center 820 964 self._rotate = rotate 821 965 self._scale = scale 966 self._imagefile = imagefile 822 967 823 968 def str(self): 824 969 r""" … … 829 974 sage: from sage.plot.plot3d.tachyon import Texfunc 830 975 sage: t = Texfunc() 831 976 sage: t.str() 832 '0 center 0.0 0.0 0.0 rotate 0.0 0.0 0.0 scale 1.0 1.0 1.0'977 '0' 833 978 """ 834 if type == 0:979 if self._ttype == 0: 835 980 return "0" 836 return r"""%d center %s rotate %s scale %s"""%(self._type, 981 elif self._ttype < 7 and self._ttype > 0: 982 return r"""%d center %s rotate %s scale %s"""%(self._ttype, 837 983 tostr(self._center), 838 984 tostr(self._rotate), 839 985 tostr(self._scale)) 986 elif self._ttype < 9: 987 return r"""%d %s center %s rotate %s scale %s"""%(self._ttype, self._imagefile,tostr(self._center),tostr(self._rotate),tostr(self._scale)) 988 elif self._ttype == 9: 989 return r"""%d %s center %s rotate %s scale %s 990 uaxis 1.0 0.0 0.0 991 vaxis 0.0 1.0 0.0"""%(self._ttype, 992 self._imagefile, 993 tostr(self._center), 994 tostr(self._rotate), 995 tostr(self._scale)) 996 else: 997 raise ValueError 998 840 999 841 1000 class Texture: 842 1001 def __init__(self, name, ambient=0.2, diffuse=0.8, 843 1002 specular=0.0, opacity=1.0, 844 color=(1.0,0.0, 0.5), texfunc=0, phong=0, phongsize=0, phongtype="PLASTIC" ):1003 color=(1.0,0.0, 0.5), texfunc=0, phong=0, phongsize=0, phongtype="PLASTIC", imagefile = ''): 845 1004 r""" 846 1005 Stores texture information. 847 1006 … … 862 1021 self._phong = phong 863 1022 self._phongsize = phongsize 864 1023 self._phongtype = phongtype 1024 self._imagefile = imagefile 865 1025 866 1026 def recolor(self, name, color): 867 1027 r""" … … 878 1038 'color 0.1 0.2 0.3 ' 879 1039 """ 880 1040 return Texture(name, self._ambient, self._diffuse, self._specular, self._opacity, 881 color, self._texfunc, self._phong, self._phongsize, self._phongtype )1041 color, self._texfunc, self._phong, self._phongsize, self._phongtype, self._imagefile) 882 1042 883 1043 def str(self): 884 1044 r"""