Changeset 7922:0357fa4b519b


Ignore:
Timestamp:
01/03/08 12:08:25 (5 years ago)
Author:
Robert Bradshaw <robertwb@…>
Branch:
default
Parents:
7921:bc8c4b756d60 (diff), 7919:feb90d6ac1e9 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

...

Location:
sage/plot/plot3d
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • sage/plot/plot3d/all.py

    r7919 r7922  
    33 
    44from shapes import Box, ColorCube, Cone, Cylinder, LineSegment, Arrow, Sphere, Torus, Text as Text3D 
    5  
    6 from parametric_surface import MobiusStrip 
    7  
    8  
     5from parametric_surface import ParametricSurface, MobiusStrip 
    96from plot3d import plot3d, axes as axes3d 
    107from platonic import Tetrahedron, Cube, Octahedron, Dodecahedron, IndexFaceSet, Icosahedron 
  • sage/plot/plot3d/all.py

    r7906 r7922  
     1from parametric_plot3d import parametric_plot3d 
     2from list_plot3d import list_plot3d 
     3 
    14from shapes import Box, ColorCube, Cone, Cylinder, LineSegment, Arrow, Sphere, Torus, Text as Text3D 
    25from parametric_surface import ParametricSurface, MobiusStrip 
    3 from parametric_plot3d import parametric_plot3d 
    46from plot3d import plot3d, axes as axes3d 
    57from platonic import Tetrahedron, Cube, Octahedron, Dodecahedron, IndexFaceSet, Icosahedron 
  • sage/plot/plot3d/base.pyx

    r7919 r7922  
    4747from math import atan2 
    4848from random import randint 
     49import zipfile 
     50from cStringIO import StringIO 
    4951 
    5052import sage.misc.misc 
     
    205207        render_params.output_file = filename 
    206208        render_params.force_reload = render_params.randomize_counter = force_reload 
    207         f = open(filename, 'w') 
     209        render_params.output_archive = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED, True) 
     210         
     211        f = StringIO() 
     212         
    208213        # Set the scene background color 
    209214        f.write('background [%s,%s,%s]\n'%tuple([int(a*255) for a in background])) 
     
    227232        # Put the rest of the object in 
    228233        f.write("\n".join(flatten_list([self.jmol_repr(render_params), ""]))) 
    229         f.close() 
     234         
     235        render_params.output_archive.writestr('SCRIPT', f.getvalue()) 
     236        render_params.output_archive.close() 
    230237 
    231238    def jmol_repr(self, render_params): 
     
    434441            #    fg = 2 
    435442            filename = '%s-size%s%s'%(base, fg*100, ext) 
     443            ext = "jmol" 
     444            archive_name = "%s.%s.zip" % (filename, ext) 
    436445 
    437446            T = self._prepare_for_jmol(frame, axes, frame_aspect_ratio, aspect_ratio, zoom) 
    438             T.export_jmol(filename + ".jmol", force_reload=EMBEDDED_MODE, **kwds) 
     447            T.export_jmol(archive_name, force_reload=EMBEDDED_MODE, **kwds) 
    439448            viewer_app = sage.misc.misc.SAGE_LOCAL + "/java/jmol/jmol" 
    440             ext = "jmol" 
     449 
     450            # We need a script to load the file 
     451            f = open(filename + '.jmol', 'w') 
     452            f.write('set defaultdirectory "%s"\n' % archive_name) 
     453            f.write('script SCRIPT\n') 
     454            f.close() 
    441455 
    442456        if ext is None: 
     
    675689        self.transform = None 
    676690        self.ds = 1 
     691        self.crease_threshold = .8 
    677692        self.__dict__.update(kwds) 
    678693         
  • sage/plot/plot3d/base.pyx

    r7909 r7922  
    7777            return other 
    7878        return Graphics3dGroup([self, other]) 
     79 
     80    def aspect_ratio(self, v=None): 
     81        if not v is None: 
     82            if not isinstance(v, (tuple, list)): 
     83                raise TypeError, "v must be a list or tuple of length 3" 
     84            self._aspect_ratio = [float(a) for a in v] 
     85        else: 
     86            if self._aspect_ratio is None: 
     87                self._aspect_ratio = [1.0,1.0,1.0] 
     88            return self._aspect_ratio 
     89 
     90    def frame_aspect_ratio(self, v=None): 
     91        if not v is None: 
     92            self._frame_aspect_ratio = v 
     93        else: 
     94            if self._frame_aspect_ratio is None: 
     95                self._frame_aspect_ratio = [1,1,1] 
     96            return self._frame_aspect_ratio 
    7997 
    8098    def bounding_box(self): 
     
    233251            return self.transform(T=T) 
    234252 
    235     def _rescale_for_aspect_ratio_and_zoom(self, b, aspect_ratio, zoom): 
    236         if aspect_ratio is None: 
     253    def _rescale_for_frame_aspect_ratio_and_zoom(self, b, frame_aspect_ratio, zoom): 
     254        if frame_aspect_ratio is None: 
    237255            return (b*zoom,b*zoom,b*zoom), (-b*zoom,-b*zoom,-b*zoom) 
    238         box = [b*w for w in aspect_ratio] 
     256        box = [b*w for w in frame_aspect_ratio] 
    239257        # Now take the maximum length in box and rescale to b. 
    240258        s = b / max(box) 
     
    243261        return box_min, box_max 
    244262 
    245     def _prepare_for_jmol(self, frame, axes, aspect_ratio, zoom): 
    246         box_min, box_max = self._rescale_for_aspect_ratio_and_zoom(6.0, aspect_ratio, zoom) 
    247         return self._transform_to_bounding_box(box_min, box_max, frame=frame, 
    248                                                axes=axes, thickness=1) 
    249  
    250     def _prepare_for_tachyon(self, frame, axes, aspect_ratio, zoom): 
    251         box_min, box_max = self._rescale_for_aspect_ratio_and_zoom(1.0, aspect_ratio, zoom) 
    252         A = self._transform_to_bounding_box(box_min, box_max, 
     263    def _prepare_for_jmol(self, frame, axes, frame_aspect_ratio, aspect_ratio, zoom): 
     264        box_min, box_max = self._rescale_for_frame_aspect_ratio_and_zoom(6.0, frame_aspect_ratio, zoom) 
     265        a_min, a_max = self._box_for_aspect_ratio(aspect_ratio, box_min, box_max) 
     266        return self._transform_to_bounding_box(box_min, box_max, a_min, a_max, frame=frame, 
     267                                            axes=axes, thickness=1) 
     268 
     269    def _prepare_for_tachyon(self, frame, axes, frame_aspect_ratio, aspect_ratio, zoom): 
     270        box_min, box_max = self._rescale_for_frame_aspect_ratio_and_zoom(1.0, frame_aspect_ratio, zoom) 
     271        a_min, a_max = self._box_for_aspect_ratio(aspect_ratio, box_min, box_max) 
     272        return self._transform_to_bounding_box(box_min, box_max, a_min, a_max, 
    253273                                            frame=frame, axes=axes, thickness=0.5) 
    254         return A 
    255  
    256     def _transform_to_bounding_box(self, xyz_min, xyz_max, frame, axes, thickness): 
     274 
     275    def _box_for_aspect_ratio(self, aspect_ratio, box_min, box_max): 
     276        # Lengths of new box 
     277        new_box = [box_max[i] - box_min[i] for i in range(3)] 
     278         
     279        # Find a box around self so that when self gets rescaled into the 
     280        # box defined by box_min, box_max, it has the right aspect ratio 
     281        if aspect_ratio == "automatic": 
     282            return self.bounding_box() 
    257283        a_min, a_max = self.bounding_box() 
    258284        a_min = list(a_min); a_max = list(a_max) 
     
    261287                a_min[i] = -1 
    262288                a_max[i] = 1 
     289                 
     290        # 1.  
     291        longest_side = 0; longest_length = 0 
     292        shortest_side = 0; shortest_length = a_max[0] - a_min[0] 
     293         
     294        for i in range(3): 
     295            s = a_max[i] - a_min[i] 
     296            if s > longest_length: 
     297                longest_length = s 
     298                longest_side = i 
     299            if s < shortest_length: 
     300                shortest_length = s 
     301                shortest_side = i 
     302 
     303        # 2. Rescale aspect_ratio so the shortest side is 1. 
     304        r = float(aspect_ratio[shortest_side]) 
     305        aspect_ratio = [a/r for a in aspect_ratio] 
     306 
     307        # 3. Extend the bounding box of self by rescaling so the sides 
     308        # have the same ratio as aspect_ratio, and without changing 
     309        # the longest side. 
     310        long_box_side = box_max[longest_side] - box_min[longest_side] 
     311        sc = [1.0,1.0,1.0] 
     312        for i in range(3): 
     313            if i != longest_side: 
     314                # compute the length we want: 
     315                new_length = longest_length / aspect_ratio[i] 
     316                # change the side length by a_min and a_max so 
     317                # that a_max[i] - a_min[i] = new_length 
     318 
     319                # We have to take into account the ratio of the sides after transforming 
     320                # to the bounding box. 
     321                z = long_box_side / (box_max[i] - box_min[i]) 
     322                w = new_length / ((a_max[i] - a_min[i]) * z) 
     323                sc[i] = w 
     324 
     325        w = min(sc) 
     326        sc = [z/w for z in sc] 
     327        for i in range(3): 
     328            a_min[i] *= sc[i] 
     329            a_max[i] *= sc[i]             
     330             
     331        return a_min, a_max 
     332 
     333    def _transform_to_bounding_box(self, xyz_min, xyz_max, a_min, a_max, frame, axes, thickness): 
    263334 
    264335        # Rescale in each direction 
     
    291362 
    292363    def show(self, viewer="jmol", filename=None, verbosity=0, figsize=5, 
    293              aspect_ratio = None, zoom=1,  
     364             aspect_ratio = "automatic", 
     365             frame_aspect_ratio = "automatic", 
     366             zoom=1,  
    294367             frame=True, axes = False, **kwds): 
    295368        """ 
     
    305378                       pixels in each direction is 100 times figsize[0]. 
    306379                       This is ignored for the jmol embedded renderer.  
    307             **kwds -- other options, which make sense for particular rendering engines            
     380            **kwds -- other options, which make sense for particular rendering engines 
     381 
     382        EXAMPLES: 
     383 
     384        We illustrate use of the aspect_ratio option: 
     385           sage: var('x,y') 
     386           sage: p = plot3d(2*sin(x*y), (x, -pi, pi), (y, -pi, pi)) 
     387           sage: p.show(aspect_ratio=[1,1,1]) 
     388 
     389        This looks flattened, but filled with the plot: 
     390           sage: p.show(frame_aspect_ratio=[1,1,1/16]) 
     391 
     392        This looks flattened, but the plot is square and smaller: 
     393           sage: p.show(aspect_ratio=[1,1,1], frame_aspect_ratio=[1,1,1/8]) 
     394            
    308395        """ 
     396        if frame_aspect_ratio == "automatic": 
     397            frame_aspect_ratio = self.frame_aspect_ratio() 
     398 
    309399        import sage.misc.misc 
    310400        if filename is None: 
     
    326416 
    327417        if DOCTEST_MODE or viewer=='tachyon' or (viewer=='java3d' and EMBEDDED_MODE): 
    328             T = self._prepare_for_tachyon(frame, axes, aspect_ratio, zoom) 
     418            T = self._prepare_for_tachyon(frame, axes, frame_aspect_ratio, aspect_ratio, zoom) 
    329419            tachyon_rt(T.tachyon(**kwds), filename+".png", verbosity, True, opts) 
    330420            ext = "png" 
     
    354444            archive_name = "%s.%s.zip" % (filename, ext) 
    355445 
    356             T = self._prepare_for_jmol(frame, axes, aspect_ratio, zoom) 
     446            T = self._prepare_for_jmol(frame, axes, frame_aspect_ratio, aspect_ratio, zoom) 
    357447            T.export_jmol(archive_name, force_reload=EMBEDDED_MODE, **kwds) 
    358448            viewer_app = sage.misc.misc.SAGE_LOCAL + "/java/jmol/jmol" 
     
    377467    def __init__(self, all=[]): 
    378468        self.all = all 
     469        self.frame_aspect_ratio(optimal_aspect_ratios([a.frame_aspect_ratio() for a in all])) 
     470        self.aspect_ratio(optimal_aspect_ratios([a.aspect_ratio() for a in all])) 
    379471 
    380472    def bounding_box(self): 
     
    429521        if T is not None:  
    430522            self.T = T 
     523        self.frame_aspect_ratio(optimal_aspect_ratios([a.frame_aspect_ratio() for a in all])) 
     524        self.aspect_ratio(optimal_aspect_ratios([a.aspect_ratio() for a in all])) 
    431525 
    432526    def bounding_box(self): 
     
    670764    """ 
    671765    return tuple([max([a[i] for a in v]) for i in range(3)]) 
     766 
     767 
     768def optimal_aspect_ratios(ratios): 
     769    # average the aspect ratios 
     770    n = len(ratios) 
     771    if n > 0: 
     772        return [max([z[i] for z in ratios]) for i in range(3)] 
     773    else: 
     774        return [1.0,1.0,1.0] 
     775         
  • sage/plot/plot3d/plot3d.py

    r7906 r7922  
    5959        return [a,b,c] 
    6060 
     61import parametric_plot3d 
     62def plot3d(f, urange, vrange, **kwds): 
     63    """ 
     64    EXAMPLES: 
     65    We plot a 3d function defined as a Python function: 
     66        sage: show(plot3d(lambda x, y: x^2 + y^2, (-2,2), (-2,2))) 
    6167 
    62 def plot3d(f,(xmin,xmax),(ymin,ymax),texture=None, opacity=1, grad_f=None, 
     68    We plot some 3d symbolic functions: 
     69        sage: var('x,y') 
     70        sage: show(plot3d(x^2 + y^2, (x,-2,2), (y,-2,2))) 
     71        sage: show(plot3d(sin(x*y), (x, -pi, pi), (y, -pi, pi))) 
     72 
     73    We draw two parametric surfaces and a transparent plane: 
     74        sage: L = plot3d(lambda x,y: 0, (-5,5), (-5,5), texture=Texture("lightblue", opacity=0.8)) 
     75        sage: P = plot3d(lambda x,y: 4 - x^3 - y^2, (-2,2), (-2,2), texture=Texture('green')) 
     76        sage: Q = plot3d(lambda x,y: x^3 + y^2 - 4, (-2,2), (-2,2), texture=Texture('orange')) 
     77        sage: show(L + P + Q)     
     78    """ 
     79    if len(urange) == 2: 
     80        w = (lambda u,v: u, lambda u,v: v, f) 
     81    else: 
     82        u = urange[0] 
     83        v = vrange[0] 
     84        w = (u, v, f) 
     85    P = parametric_plot3d.parametric_plot3d(w, urange, vrange, **kwds) 
     86    P.frame_aspect_ratio([1.0,1.0,0.5]) 
     87    return P 
     88 
     89# This sucks.  It looks like crap.  Simple grid sampling looks way better?! 
     90def plot3d_old(f,(xmin,xmax),(ymin,ymax),texture=None, opacity=1, grad_f=None, 
    6391           max_bend=.5, max_depth=5, initial_depth=4, num_colors=None): 
    6492    """ 
    6593    EXAMPLES: 
    66      
    67  
    6894    """ 
    6995    if initial_depth >= max_depth: 
  • sage/plot/plot3d/shapes.pyx

    r7897 r7922  
    184184            return ParametricSurface.tachyon_repr(self, render_params) 
    185185             
    186         if transform is None: 
    187             base = (0,0,0) 
    188             top = (0,0,self.height) 
    189             rad = self.radius 
    190         else: 
    191             base = transform.transform_point((0,0,0)) 
    192             top = transform.transform_point((0,0,self.height)) 
    193             radv = transform.transform_vector((self.radius,0,0)) 
    194             rad = sqrt(sum([x*x for x in radv])) 
     186        base, top = self.get_endpoints(transform) 
     187        rad = self.get_radius(transform) 
    195188        cyl = """FCylinder  
    196189   Base %s %s %s 
     
    207200        else: 
    208201            return cyl 
     202             
     203    def jmol_repr(self, render_params): 
     204        transform = render_params.transform 
     205        base, top = self.get_endpoints(transform) 
     206        rad = self.get_radius(transform) 
     207         
     208        cdef double ratio = sqrt(rad*rad / ((base[0]-top[0])**2 + (base[1]-top[1])**2 + (base[2]-top[2])**2)) 
     209 
     210        if ratio > .02: 
     211            if not (transform is None or transform.is_uniform_on([(1,0,0),(0,1,0)])) or ratio > .05: 
     212                # Jmol can't do sqashed 
     213                return ParametricSurface.jmol_repr(self, render_params) 
     214             
     215        name = render_params.unique_name('line') 
     216        return [""" 
     217draw %s width %s {%s %s %s} {%s %s %s}\n%s 
     218""" % (name,  
     219       rad, 
     220       base[0], base[1], base[2], 
     221       top [0], top [1], top [2], 
     222       self.texture.jmol_str("$" + name)) ] 
     223        
     224    def get_endpoints(self, transform=None): 
     225        if transform is None: 
     226            return (0,0,0), (0,0,self.height) 
     227        else: 
     228            return transform.transform_point((0,0,0)), transform.transform_point((0,0,self.height)) 
     229             
     230    def get_radius(self, transform=None): 
     231        if transform is None: 
     232            return self.radius 
     233        else: 
     234            radv = transform.transform_vector((self.radius,0,0)) 
     235            return sqrt(sum([x*x for x in radv])) 
     236     
    209237 
    210238    def get_grid(self, ds): 
  • sage/plot/plot3d/shapes.pyx

    r7911 r7922  
    207207         
    208208        cdef double ratio = sqrt(rad*rad / ((base[0]-top[0])**2 + (base[1]-top[1])**2 + (base[2]-top[2])**2)) 
    209         print ratio 
    210209 
    211210        if ratio > .02: 
Note: See TracChangeset for help on using the changeset viewer.