diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 693c4e27d31..e17c8a95fed 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -52,7 +52,14 @@ include "point_c.pxi" from sage.interfaces.tachyon import tachyon_rt -from renderers.jmol import JMOLRenderer + +import renderers.jmol +import renderers.json +import renderers.canvas3d +import renderers.x3d +import renderers.obj +import renderers.tachyon +import renderers.wavefront # import the double infinity constant cdef extern from "math.h": @@ -69,6 +76,7 @@ cdef class Graphics3d(SageObject): .. automethod:: __add__ .. automethod:: _rich_repr_ """ + render_method = "render_graphics3d" def __cinit__(self): """ The Cython constructor @@ -135,7 +143,7 @@ cdef class Graphics3d(SageObject): if viewer == 'jmol' and not can_view_jmol: viewer = 'tachyon' ### Second, return the corresponding graphics file if viewer == 'jmol': - rrr = JMOLRenderer() + rrr = renderers.jmol.JMOLRenderer() return rrr.rich_repr_graphics3d(self, **opts) elif viewer == 'tachyon': preferred = ( @@ -1346,7 +1354,7 @@ end_scene""" % (render_params.antialiasing, render = self._rich_repr_tachyon(OutputImagePng, **opts) render.png.save_as(filename) elif viewer == 'jmol': - rrr = JMOLRenderer() + rrr = renderers.jmol.JMOLRenderer() scene = rrr.rich_repr_graphics3d(self, **opts) scene.preview_png.save_as(filename) else: @@ -1457,6 +1465,7 @@ class Graphics3dGroup(Graphics3d): This class represents a collection of 3d objects. Usually they are formed implicitly by summing. """ + render_method = "render_graphics3d_group" def __init__(self, all=(), rot=None, trans=None, scale=None, T=None): """ EXAMPLES:: @@ -1570,7 +1579,8 @@ class Graphics3dGroup(Graphics3d): sage: G.json_repr(G.default_render_params()) [[["{vertices:..."]], [["{vertices:..."]]] """ - return [g.json_repr(render_params) for g in self.all] + rrr = renderers.json.JsonRenderer() + return rrr.render_graphics3d_group(self, render_params) def tachyon_repr(self, render_params): """ @@ -1584,25 +1594,13 @@ class Graphics3dGroup(Graphics3d): [['Sphere center 0.0 0.0 0.0 Rad 1.0 texture...'], ['Sphere center 1.0 2.0 3.0 Rad 1.0 texture...']] """ - return [g.tachyon_repr(render_params) for g in self.all] + rrr = renderers.tachyon.TachyonRenderer() + return rrr.render_graphics3d_group(self, render_params) def x3d_str(self): - """ - The x3d representation of a group is simply the concatenation of - the representation of its objects. + rrr = renderers.x3d.X3dRenderer() + return rrr.render_graphics3d_group(self, render_params=None) - EXAMPLES:: - - sage: G = sphere() + sphere((1,2,3)) - sage: print G.x3d_str() - - - - - - - """ - return "\n".join([g.x3d_str() for g in self.all]) def obj_repr(self, render_params): """ @@ -1630,7 +1628,8 @@ class Graphics3dGroup(Graphics3d): ['f 5 6 7', 'f 6 8 7', 'f 5 7 8', 'f 5 8 6'], []]]] """ - return [g.obj_repr(render_params) for g in self.all] + rrr = renderers.obj.ObjRenderer() + return rrr.render_graphics3d_group(self, render_params) def jmol_repr(self, render_params): r""" @@ -1644,7 +1643,8 @@ class Graphics3dGroup(Graphics3d): [[['isosurface sphere_1 center {0.0 0.0 0.0} sphere 1.0\ncolor isosurface [102,102,255]']], [['isosurface sphere_2 center {1.0 2.0 3.0} sphere 1.0\ncolor isosurface [102,102,255]']]] """ - return [g.jmol_repr(render_params) for g in self.all] + rrr = renderers.jmol.JMOLRenderer() + return rrr.render_graphics3d_group(self, render_params) def texture_set(self): """ @@ -1701,6 +1701,7 @@ class TransformGroup(Graphics3dGroup): This class is a container for a group of objects with a common transformation. """ + render_method = "render_transform_group" def __init__(self, all=[], rot=None, trans=None, scale=None, T=None): """ EXAMPLES:: @@ -1952,6 +1953,7 @@ cdef class PrimitiveObject(Graphics3d): """ This is the base class for the non-container 3d objects. """ + render_method = "render_primitive_object" def __init__(self, **kwds): if 'texture' in kwds: self.texture = kwds['texture'] diff --git a/src/sage/plot/plot3d/implicit_surface.pyx b/src/sage/plot/plot3d/implicit_surface.pyx index be288cde294..d3026d58021 100644 --- a/src/sage/plot/plot3d/implicit_surface.pyx +++ b/src/sage/plot/plot3d/implicit_surface.pyx @@ -1132,7 +1132,7 @@ cdef class ImplicitSurface(IndexFaceSet): sage: show(G, viewer='jmol') # indirect doctest """ rrr = renderers.jmol.JMOLRenderer() - return rrr.render_implicit_surface(self, render_params) + return [rrr.render_implicit_surface(self, render_params)] def json_repr(self, render_params): """ diff --git a/src/sage/plot/plot3d/index_face_set.pyx b/src/sage/plot/plot3d/index_face_set.pyx index 42210344a64..9fad161e5c0 100644 --- a/src/sage/plot/plot3d/index_face_set.pyx +++ b/src/sage/plot/plot3d/index_face_set.pyx @@ -68,7 +68,14 @@ from sage.plot.plot3d.base import Graphics3dGroup from transform cimport Transformation -import renderers +import renderers.jmol +import renderers.json +import renderers.canvas3d +import renderers.x3d +import renderers.obj +import renderers.tachyon +import renderers.wavefront + @@ -76,64 +83,6 @@ import renderers # Fast routines for generating string representations of the polygons. # -------------------------------------------------------------------- -cdef inline format_tachyon_texture(color_c rgb): - cdef char rs[200] - cdef Py_ssize_t cr = sprintf_3d(rs, - "TEXTURE\n AMBIENT 0.3 DIFFUSE 0.7 SPECULAR 0 OPACITY 1.0\n COLOR %g %g %g \n TEXFUNC 0", - rgb.r, rgb.g, rgb.b) - return PyString_FromStringAndSize(rs, cr) - - -cdef inline format_tachyon_triangle(point_c P, point_c Q, point_c R): - cdef char ss[250] - # PyString_FromFormat doesn't do floats? - cdef Py_ssize_t r = sprintf_9d(ss, - "TRI V0 %g %g %g V1 %g %g %g V2 %g %g %g", - P.x, P.y, P.z, - Q.x, Q.y, Q.z, - R.x, R.y, R.z ) - return PyString_FromStringAndSize(ss, r) - - -cdef inline format_json_vertex(point_c P): - cdef char ss[100] - cdef Py_ssize_t r = sprintf_3d(ss, "{x:%g,y:%g,z:%g}", P.x, P.y, P.z) - return PyString_FromStringAndSize(ss, r) - -cdef inline format_json_face(face_c face): - return "[{}]".format(",".join([str(face.vertices[i]) - for i from 0 <= i < face.n])) - -cdef inline format_obj_vertex(point_c P): - cdef char ss[100] - # PyString_FromFormat doesn't do floats? - cdef Py_ssize_t r = sprintf_3d(ss, "v %g %g %g", P.x, P.y, P.z) - return PyString_FromStringAndSize(ss, r) - -cdef inline format_obj_face(face_c face, int off): - cdef char ss[100] - cdef Py_ssize_t r, i - if face.n == 3: - r = sprintf_3i(ss, "f %d %d %d", face.vertices[0] + off, face.vertices[1] + off, face.vertices[2] + off) - elif face.n == 4: - r = sprintf_4i(ss, "f %d %d %d %d", face.vertices[0] + off, face.vertices[1] + off, face.vertices[2] + off, face.vertices[3] + off) - else: - return "f " + " ".join([str(face.vertices[i] + off) for i from 0 <= i < face.n]) - # PyString_FromFormat is almost twice as slow - return PyString_FromStringAndSize(ss, r) - -cdef inline format_obj_face_back(face_c face, int off): - cdef char ss[100] - cdef Py_ssize_t r, i - if face.n == 3: - r = sprintf_3i(ss, "f %d %d %d", face.vertices[2] + off, face.vertices[1] + off, face.vertices[0] + off) - elif face.n == 4: - r = sprintf_4i(ss, "f %d %d %d %d", face.vertices[3] + off, face.vertices[2] + off, face.vertices[1] + off, face.vertices[0] + off) - else: - return "f " + " ".join([str(face.vertices[i] + off) for i from face.n > i >= 0]) - return PyString_FromStringAndSize(ss, r) - - cdef class IndexFaceSet(PrimitiveObject): """ @@ -699,160 +648,16 @@ cdef class IndexFaceSet(PrimitiveObject): return all def tachyon_repr(self, render_params): - """ - Return a tachyon object for ``self``. - - EXAMPLES: - - A basic test with a triangle:: - - sage: G = polygon([(0,0,1), (1,1,1), (2,0,1)]) - sage: s = G.tachyon_repr(G.default_render_params()); s - ['TRI V0 0 0 1 V1 1 1 1 V2 2 0 1', ...] - - A simple colored one:: - - sage: from sage.plot.plot3d.index_face_set import IndexFaceSet - sage: from sage.plot.plot3d.texture import Texture - sage: point_list = [(2,0,0),(0,2,0),(0,0,2),(0,1,1),(1,0,1),(1,1,0)] - sage: face_list = [[0,4,5],[3,4,5],[2,3,4],[1,3,5]] - sage: col = rainbow(10, 'rgbtuple') - sage: t_list=[Texture(col[i]) for i in range(10)] - sage: S = IndexFaceSet(face_list, point_list, texture_list=t_list) - sage: S.tachyon_repr(S.default_render_params()) - ['TRI V0 2 0 0 V1 1 0 1 V2 1 1 0', - 'TEXTURE... AMBIENT 0.3 DIFFUSE 0.7 SPECULAR 0 OPACITY 1.0... COLOR 1 0 0 ... TEXFUNC 0',...] - """ - cdef Transformation transform = render_params.transform - lines = [] - cdef point_c P, Q, R - cdef face_c face - cdef Py_ssize_t i, k - sig_on() - for i from 0 <= i < self.fcount: - face = self._faces[i] - if transform is not None: - transform.transform_point_c(&P, self.vs[face.vertices[0]]) - transform.transform_point_c(&Q, self.vs[face.vertices[1]]) - transform.transform_point_c(&R, self.vs[face.vertices[2]]) - else: - P = self.vs[face.vertices[0]] - Q = self.vs[face.vertices[1]] - R = self.vs[face.vertices[2]] - PyList_Append(lines, format_tachyon_triangle(P, Q, R)) - if self.global_texture: - PyList_Append(lines, self.texture.id) - else: - PyList_Append(lines, format_tachyon_texture(face.color)) - if face.n > 3: - for k from 3 <= k < face.n: - Q = R - if transform is not None: - transform.transform_point_c(&R, self.vs[face.vertices[k]]) - else: - R = self.vs[face.vertices[k]] - PyList_Append(lines, format_tachyon_triangle(P, Q, R)) - if self.global_texture: - PyList_Append(lines, self.texture.id) - else: - PyList_Append(lines, format_tachyon_texture(face.color)) - sig_off() - - return lines + rrr = renderers.tachyon.TachyonRenderer() + return rrr.render_index_face_set(self, render_params) def json_repr(self, render_params): - """ - Return a json representation for ``self``. - - TESTS: - - A basic test with a triangle:: - - sage: G = polygon([(0,0,1), (1,1,1), (2,0,1)]) - sage: G.json_repr(G.default_render_params()) - ["{vertices:[{x:0,y:0,z:1},{x:1,y:1,z:1},{x:2,y:0,z:1}],faces:[[0,1,2]],color:'#0000ff'}"] - - A simple colored one:: - - sage: from sage.plot.plot3d.index_face_set import IndexFaceSet - sage: from sage.plot.plot3d.texture import Texture - sage: point_list = [(2,0,0),(0,2,0),(0,0,2),(0,1,1),(1,0,1),(1,1,0)] - sage: face_list = [[0,4,5],[3,4,5],[2,3,4],[1,3,5]] - sage: col = rainbow(10, 'rgbtuple') - sage: t_list=[Texture(col[i]) for i in range(10)] - sage: S = IndexFaceSet(face_list, point_list, texture_list=t_list) - sage: S.json_repr(S.default_render_params()) - ["{vertices:[{x:2,y:0,z:0},{x:0,y:2,z:0},{x:0,y:0,z:2},{x:0,y:1,z:1},{x:1,y:0,z:1},{x:1,y:1,z:0}],faces:[[0,4,5],[3,4,5],[2,3,4],[1,3,5]],face_colors:['#ff0000','#ff9900','#cbff00','#33ff00']}"] - """ - cdef Transformation transform = render_params.transform - cdef point_c res - - if transform is None: - vertices_str = "[{}]".format( - ",".join([format_json_vertex(self.vs[i]) - for i from 0 <= i < self.vcount])) - else: - vertices_str = "[" - for i from 0 <= i < self.vcount: - transform.transform_point_c(&res, self.vs[i]) - if i > 0: - vertices_str += "," - vertices_str += format_json_vertex(res) - vertices_str += "]" - - faces_str = "[{}]".format(",".join([format_json_face(self._faces[i]) - for i from 0 <= i < self.fcount])) - if self.global_texture: - color_str = "'#{}'".format(self.texture.hex_rgb()) - return ["{vertices:%s,faces:%s,color:%s}" % - (vertices_str, faces_str, color_str)] - else: - color_str = "[{}]".format(",".join(["'{}'".format( - Color(self._faces[i].color.r, - self._faces[i].color.g, - self._faces[i].color.b).html_color()) - for i from 0 <= i < self.fcount])) - return ["{vertices:%s,faces:%s,face_colors:%s}" % - (vertices_str, faces_str, color_str)] + rrr = renderers.json.JsonRenderer() + return [rrr.render_index_face_set(self, render_params)] def obj_repr(self, render_params): - """ - Return an obj representation for ``self``. - - TESTS:: - - sage: from sage.plot.plot3d.shapes import * - sage: S = Cylinder(1,1) - sage: s = S.obj_repr(S.default_render_params()) - """ - cdef Transformation transform = render_params.transform - cdef int off = render_params.obj_vertex_offset - cdef Py_ssize_t i - cdef point_c res - - sig_on() - if transform is None: - points = [format_obj_vertex(self.vs[i]) for i from 0 <= i < self.vcount] - else: - points = [] - for i from 0 <= i < self.vcount: - transform.transform_point_c(&res, self.vs[i]) - PyList_Append(points, format_obj_vertex(res)) - - faces = [format_obj_face(self._faces[i], off) for i from 0 <= i < self.fcount] - if not self.enclosed: - back_faces = [format_obj_face_back(self._faces[i], off) for i from 0 <= i < self.fcount] - else: - back_faces = [] - - render_params.obj_vertex_offset += self.vcount - sig_off() - - return ["g " + render_params.unique_name('obj'), - "usemtl " + self.texture.id, - points, - faces, - back_faces] + rrr = renderers.obj.ObjRenderer() + return rrr.render_index_face_set(self, render_params) def jmol_repr(self, render_params): rrr = renderers.jmol.JMOLRenderer() diff --git a/src/sage/plot/plot3d/parametric_surface.pyx b/src/sage/plot/plot3d/parametric_surface.pyx index e0d803741c2..689c4e88747 100644 --- a/src/sage/plot/plot3d/parametric_surface.pyx +++ b/src/sage/plot/plot3d/parametric_surface.pyx @@ -272,7 +272,7 @@ cdef class ParametricSurface(IndexFaceSet): ['pmesh obj_1 "obj_1.pmesh"\ncolor pmesh [102,102,255]'] """ rrr = renderers.jmol.JMOLRenderer() - return rrr.render_implicit_surface(self, render_params) + return [rrr.render_implicit_surface(self, render_params)] def json_repr(self, render_params): """ diff --git a/src/sage/plot/plot3d/renderers/api.py b/src/sage/plot/plot3d/renderers/api.py index 589f3fe511b..6a0ae02c691 100644 --- a/src/sage/plot/plot3d/renderers/api.py +++ b/src/sage/plot/plot3d/renderers/api.py @@ -16,7 +16,7 @@ def render_graphics3d(self, obj, render_params): return '' def render_graphics3d_group(self, obj, render_params): - return self.render_graphics3d(obj, render_params) + return [g.render(render_params, renderer=self) for g in obj.all] def render_transform_group(self, obj, render_params): return self.render_graphics3d_group(obj, render_params) diff --git a/src/sage/plot/plot3d/renderers/canvas3d.py b/src/sage/plot/plot3d/renderers/canvas3d.py index c1e400cede2..176ba16c106 100644 --- a/src/sage/plot/plot3d/renderers/canvas3d.py +++ b/src/sage/plot/plot3d/renderers/canvas3d.py @@ -4,7 +4,7 @@ from . import register, Graphics3dRenderer -class Canvas3dRenderer(object): +class Canvas3dRenderer(Graphics3dRenderer): def render_graphics3d(self, obj, render_params): """ @@ -13,8 +13,8 @@ def render_graphics3d(self, obj, render_params): """ return '' - def render_graphics3d_group(self, obj, render_params): - return self.render_graphics3d(obj, render_params) + # def render_graphics3d_group(self, obj, render_params): + # return self.render_graphics3d(obj, render_params) def render_transform_group(self, obj, render_params): return self.render_graphics3d_group(obj, render_params) diff --git a/src/sage/plot/plot3d/renderers/jmol.py b/src/sage/plot/plot3d/renderers/jmol.py index ac98d5dd1f7..82d11d82939 100644 --- a/src/sage/plot/plot3d/renderers/jmol.py +++ b/src/sage/plot/plot3d/renderers/jmol.py @@ -62,6 +62,21 @@ def render_graphics3d_image(self,obj): scene = obj._rich_repr_jmol(**opts) scene.preview_png.save_as(filename) + def render_graphics3d(self, obj, render_params): + return '' + + def render_graphics3d_group(self, obj, render_params): + return [g.render(render_params, renderer=self) for g in obj.all] + def render_transform_group(self, obj, render_params): + return self.render_graphics3d_group(obj, render_params) + + def render_primitive_object(self, obj, render_params): + return self.render_graphics3d(obj, render_params) + def render_line(self, obj, render_params): + return self.render_primitive_objectd(obj, render_params) + def render_point(self, obj, render_params): + return self.render_primitive_object(obj, render_params) + def render_index_face_set(self, obj, render_params): """ Return a jmol representation for ``obj``. @@ -79,7 +94,7 @@ def render_index_face_set(self, obj, render_params): obj._seperate_creases(render_params.crease_threshold) if transform is None: - points = ["%g %g %g"%v for v in vertices] + points = ["%g %g %g"%tuple(v) for v in vertices] else: points = ["%g %g %g"%transform.transform_point(v) for v in vertices] @@ -142,25 +157,6 @@ def render_index_face_set(self, obj, render_params): s += '\npmesh %s dots\n' % name return s - - - def render_graphics3d(self, obj, render_params): - return '' - - def render_graphics3d_group(self, obj, render_params): - return [g.render(render_params, renderer=self) for g in obj.all] - def render_transform_group(self, obj, render_params): - return self.render_graphics3d_group(obj, render_params) - - def render_primitive_object(self, obj, render_params): - return self.render_graphics3d(obj, render_params) - def render_line(self, obj, render_params): - return self.render_primitive_objectd(obj, render_params) - def render_point(self, obj, render_params): - return self.render_primitive_object(obj, render_params) - - def render_index_face_set(self, obj, render_params): - return self.render_graphics3d(obj, render_params) def render_box(self, obj, render_params): return self.render_index_face_set(obj, render_params) @@ -208,7 +204,7 @@ def render_sphere(self, obj, render_params): res = "resolution %s" % min(int(7/rad), 100) else: res = "" - return ["isosurface %s %s center {%s %s %s} sphere %s\n%s" % (name, res, cen[0], cen[1], cen[2], rad, obj.texture.jmol_str("isosurface"))] + return "isosurface %s %s center {%s %s %s} sphere %s\n%s" % (name, res, cen[0], cen[1], cen[2], rad, obj.texture.jmol_str("isosurface")) def render_cylinder(self, obj, render_params): diff --git a/src/sage/plot/plot3d/renderers/json.py b/src/sage/plot/plot3d/renderers/json.py index af298ef6fae..0d3b7fab2f6 100644 --- a/src/sage/plot/plot3d/renderers/json.py +++ b/src/sage/plot/plot3d/renderers/json.py @@ -4,7 +4,7 @@ from . import register, Graphics3dRenderer -class JsonRenderer(object): +class JsonRenderer(Graphics3dRenderer): def render_graphics3d(self, obj, render_params): """ @@ -13,8 +13,8 @@ def render_graphics3d(self, obj, render_params): """ return '' - def render_graphics3d_group(self, obj, render_params): - return self.render_graphics3d(obj, render_params) + # def render_graphics3d_group(self, obj, render_params): + # return self.render_graphics3d(obj, render_params) def render_transform_group(self, obj, render_params): return self.render_graphics3d_group(obj, render_params) @@ -26,7 +26,58 @@ def render_point(self, obj, render_params): return self.render_primitive_object(obj, render_params) def render_index_face_set(self, obj, render_params): - return self.render_graphics3d(obj, render_params) + """ + Return a json representation for ``self``. + + TESTS: + + A basic test with a triangle:: + + sage: G = polygon([(0,0,1), (1,1,1), (2,0,1)]) + sage: G.json_repr(G.default_render_params()) + ["{vertices:[{x:0,y:0,z:1},{x:1,y:1,z:1},{x:2,y:0,z:1}],faces:[[0,1,2]],color:'#0000ff'}"] + + A simple colored one:: + + sage: from sage.plot.plot3d.index_face_set import IndexFaceSet + sage: from sage.plot.plot3d.texture import Texture + sage: point_list = [(2,0,0),(0,2,0),(0,0,2),(0,1,1),(1,0,1),(1,1,0)] + sage: face_list = [[0,4,5],[3,4,5],[2,3,4],[1,3,5]] + sage: col = rainbow(10, 'rgbtuple') + sage: t_list=[Texture(col[i]) for i in range(10)] + sage: S = IndexFaceSet(face_list, point_list, texture_list=t_list) + sage: S.json_repr(S.default_render_params()) + ["{vertices:[{x:2,y:0,z:0},{x:0,y:2,z:0},{x:0,y:0,z:2},{x:0,y:1,z:1},{x:1,y:0,z:1},{x:1,y:1,z:0}],faces:[[0,4,5],[3,4,5],[2,3,4],[1,3,5]],face_colors:['#ff0000','#ff9900','#cbff00','#33ff00']}"] + """ + transform = render_params.transform + vertices = obj.vertices() + faces = obj.faces() + + if transform is None: + vertices_str = "[{}]".format(",".join(["{x:%g,y:%g,z:%g}"%tuple(v) for v in vertices])) + else: + vertices_str = "[{}]".format(",".join( + ["{x:%g,y:%g,z:%g}"%transform.transform_point(v) for v in vertices] + )) + + faces_str = "[{}]".format(",".join( + ["[{}]".format(",".join( + [str(v) for v in face.iter_index()] + )) for face in faces] + )) + + if True:#obj.global_texture: + color_str = "'#{}'".format(obj.texture.hex_rgb()) + return "{vertices:%s,faces:%s,color:%s}"%(vertices_str, faces_str, color_str) + # else: + # color_str = "[{}]".format(",".join(["'{}'".format( + # Color(obj._faces[i].color.r, + # obj._faces[i].color.g, + # obj._faces[i].color.b).html_color()) + # for i from 0 <= i < obj.fcount])) + # return "{vertices:%s,faces:%s,face_colors:%s}"%(vertices_str, faces_str, color_str) + + def render_box(self, obj, render_params): return self.render_index_face_set(obj, render_params) @@ -50,3 +101,13 @@ def render_implicit_surface(self, obj, render_params): register(JsonRenderer) + +# cdef inline format_json_vertex(point_c P): +# cdef char ss[100] +# cdef Py_ssize_t r = sprintf_3d(ss, "{x:%g,y:%g,z:%g}", P.x, P.y, P.z) +# return PyString_FromStringAndSize(ss, r) + +# cdef inline format_json_face(face_c face): +# return "[{}]".format(",".join([str(face.vertices[i]) +# for i from 0 <= i < face.n])) + diff --git a/src/sage/plot/plot3d/renderers/obj.py b/src/sage/plot/plot3d/renderers/obj.py index e2bc82765d6..b7979cb5fd3 100644 --- a/src/sage/plot/plot3d/renderers/obj.py +++ b/src/sage/plot/plot3d/renderers/obj.py @@ -4,49 +4,87 @@ from . import register, Graphics3dRenderer -class ObjRenderer(object): +class ObjRenderer(Graphics3dRenderer): - def render_graphics3d(self, obj, render_params): + # grob = (gr)aphics (ob)ject + def render_graphics3d(self, grob, render_params): """ Unless otherwise changed, all rendering methods fall back to this one. """ return '' - def render_graphics3d_group(self, obj, render_params): - return self.render_graphics3d(obj, render_params) - def render_transform_group(self, obj, render_params): - return self.render_graphics3d_group(obj, render_params) - - def render_primitive_object(self, obj, render_params): - return self.render_graphics3d(obj, render_params) - def render_line(self, obj, render_params): - return self.render_primitive_objectd(obj, render_params) - def render_point(self, obj, render_params): - return self.render_primitive_object(obj, render_params) - - def render_index_face_set(self, obj, render_params): - return self.render_graphics3d(obj, render_params) - def render_box(self, obj, render_params): - return self.render_index_face_set(obj, render_params) - - def render_parametric_surface(self, obj, render_params): - obj.triangulate() - return self.render_index_face_set(obj, render_params) - def render_sphere(self, obj, render_params): - return self.render_parametric_surface(obj, render_params) - def render_cylinder(self, obj, render_params): - return self.render_parametric_surface(obj, render_params) - def render_torus(self, obj, render_params): - return self.render_parametric_surface(obj, render_params) - def render_cone(self, obj, render_params): - return self.render_parametric_surface(obj, render_params) - def render_mobius_strip(self, obj, render_params): - return self.render_parametric_surface(obj, render_params) - - def render_implicit_surface(self, obj, render_params): - obj.triangulate() - return self.render_index_face_set(obj, render_params) + # def render_graphics3d_group(self, grob, render_params): + # return self.render_graphics3d(grob, render_params) + def render_transform_group(self, grob, render_params): + return self.render_graphics3d_group(grob, render_params) + + def render_primitive_grobect(self, grob, render_params): + return self.render_graphics3d(grob, render_params) + def render_line(self, grob, render_params): + return self.render_primitive_grobectd(grob, render_params) + def render_point(self, grob, render_params): + return self.render_primitive_grobect(grob, render_params) + + def render_index_face_set(self, grob, render_params): + """ + Return an obj representation for ``grob``. + + TESTS:: + + sage: from sage.plot.plot3d.shapes import * + sage: S = Cylinder(1,1) + sage: s = S.obj_repr(S.default_render_params()) + """ + transform = render_params.transform + if transform is None: + transform_point = tuple + else: + transform_point = transform.transform_point + + off = render_params.obj_vertex_offset + + grob_faces = grob.faces() + + points = ["v %g %g %g"%(transform_point(v)) for v in grob.vertices()] + + faces = [format_obj_face(indexed_face, off) for indexed_face in grob.index_faces()] + if not grob.is_enclosed(): + back_faces = [format_obj_face(indexed_face, off, order=-1) for indexed_face in grob.index_faces()] + else: + back_faces = [] + + render_params.obj_vertex_offset += len(grob.vertices()) + + + return ["g " + render_params.unique_name('obj'), + "usemtl " + grob.texture.id, + points, + faces, + back_faces] + + def render_box(self, grob, render_params): + return self.render_index_face_set(grob, render_params) + + def render_parametric_surface(self, grob, render_params): + grob.triangulate() + return self.render_index_face_set(grob, render_params) + def render_sphere(self, grob, render_params): + return self.render_parametric_surface(grob, render_params) + def render_cylinder(self, grob, render_params): + return self.render_parametric_surface(grob, render_params) + def render_torus(self, grob, render_params): + return self.render_parametric_surface(grob, render_params) + def render_cone(self, grob, render_params): + return self.render_parametric_surface(grob, render_params) + def render_mobius_strip(self, grob, render_params): + return self.render_parametric_surface(grob, render_params) + + def render_implicit_surface(self, grob, render_params): + grob.triangulate() + return self.render_index_face_set(grob, render_params) register(ObjRenderer) +def format_obj_face(indexed_face, off, order=1): + return "f "+" ".join("%d"%(j+off) for j in indexed_face[::order]) diff --git a/src/sage/plot/plot3d/renderers/wavefront.py b/src/sage/plot/plot3d/renderers/wavefront.py index d954bc6e3f8..650cdc8a663 100644 --- a/src/sage/plot/plot3d/renderers/wavefront.py +++ b/src/sage/plot/plot3d/renderers/wavefront.py @@ -4,7 +4,7 @@ from . import register, Graphics3dRenderer -class WavefrontRenderer(object): +class WavefrontRenderer(Graphics3dRenderer): def render_graphics3d(self, obj, render_params): """ @@ -13,8 +13,8 @@ def render_graphics3d(self, obj, render_params): """ return '' - def render_graphics3d_group(self, obj, render_params): - return self.render_graphics3d(obj, render_params) + # def render_graphics3d_group(self, obj, render_params): + # return self.render_graphics3d(obj, render_params) def render_transform_group(self, obj, render_params): return self.render_graphics3d_group(obj, render_params) diff --git a/src/sage/plot/plot3d/renderers/x3d.py b/src/sage/plot/plot3d/renderers/x3d.py index 936be026a55..4efcc60f546 100644 --- a/src/sage/plot/plot3d/renderers/x3d.py +++ b/src/sage/plot/plot3d/renderers/x3d.py @@ -4,7 +4,7 @@ from . import register, Graphics3dRenderer -class X3dRenderer(object): +class X3dRenderer(Graphics3dRenderer): def render_graphics3d(self, obj, render_params): """ @@ -14,7 +14,23 @@ def render_graphics3d(self, obj, render_params): return '' def render_graphics3d_group(self, obj, render_params): - return self.render_graphics3d(obj, render_params) + """ + The x3d representation of a group is simply the concatenation of + the representation of its objects. + + EXAMPLES:: + + sage: G = sphere() + sphere((1,2,3)) + sage: print G.x3d_str() + + + + + + + """ + return "\n".join([g.x3d_str() for g in obj.all]) + def render_transform_group(self, obj, render_params): return self.render_graphics3d_group(obj, render_params) diff --git a/src/sage/plot/plot3d/shapes.pyx b/src/sage/plot/plot3d/shapes.pyx index 48b25d76d5e..bd7952e6c6a 100644 --- a/src/sage/plot/plot3d/shapes.pyx +++ b/src/sage/plot/plot3d/shapes.pyx @@ -740,7 +740,7 @@ cdef class Sphere(ParametricSurface): def jmol_repr(self, render_params): rrr = renderers.jmol.JMOLRenderer() - return rrr.render_sphere(self, render_params) + return [rrr.render_sphere(self, render_params)] def get_grid(self, double ds): """ Return the range of variables to be evaluated on to render as a