Graphics 3D object for representing and triangulating isosurfaces.¶
AUTHORS:
- Robert Hanson (2007): initial Java version, in Jmol.
- Carl Witty (2009-01): first Cython version.
- Bill Cauchois (2009): improvements for inclusion into Sage.
-
class
sage.plot.plot3d.implicit_surface.
ImplicitSurface
¶ Bases:
sage.plot.plot3d.index_face_set.IndexFaceSet
TESTS:
sage: from sage.plot.plot3d.implicit_surface import ImplicitSurface sage: var('x,y,z') (x, y, z) sage: G = ImplicitSurface(x^2 + y^2 + z^2, (x,-2, 2), (y,-2, 2), (z,-2, 2), contour=4) sage: show(G)
A colored case:
sage: t = (1-sin(2*x*y+3*z)**2).function(x,y,z) sage: cm = colormaps.autumn sage: G = ImplicitSurface(x^2 + y^2 + z^2, (x,-2, 2), (y,-2, 2), (z,-2, 2), contour=4, color=(t,cm)) sage: G.show(viewer='tachyon')
-
bounding_box
()¶ Return a bounding box for the
ImplicitSurface
, as a tuple of two 3-dimensional points.EXAMPLES:
Note that the bounding box corresponds exactly to the x-, y-, and z- range:
sage: from sage.plot.plot3d.implicit_surface import ImplicitSurface sage: G = ImplicitSurface(0, (0, 1), (0, 1), (0, 1)) sage: G.bounding_box() ((0.0, 0.0, 0.0), (1.0, 1.0, 1.0))
-
color_function
¶
-
colormap
¶
-
contours
¶
-
f
¶
-
gradient
¶
-
jmol_repr
(render_params)¶ Return a representation of this object suitable for use with the Jmol renderer.
TESTS:
sage: from sage.plot.plot3d.implicit_surface import ImplicitSurface sage: var('x,y,z') (x, y, z) sage: G = ImplicitSurface(x + y + z, (x,-1, 1), (y,-1, 1), (z,-1, 1)) sage: show(G, viewer='jmol') # indirect doctest
-
json_repr
(render_params)¶ Return a representation of this object in JavaScript Object Notation (JSON).
TESTS:
sage: from sage.plot.plot3d.implicit_surface import ImplicitSurface sage: var('x,y,z') (x, y, z) sage: G = ImplicitSurface(x + y + z, (x,-1, 1), (y,-1, 1), (z,-1, 1)) sage: G.json_repr(G.default_render_params())[0].startswith('{vertices:') True
-
obj_repr
(render_params)¶ Return a representation of this object in the .obj format.
TESTS:
We graph a simple plane:
sage: from sage.plot.plot3d.implicit_surface import ImplicitSurface sage: var('x,y,z') (x, y, z) sage: G = ImplicitSurface(x + y + z, (x,-1, 1), (y,-1, 1), (z,-1, 1)) sage: obj = G.obj_repr(G.default_render_params()) sage: vertices = obj[2]
The number of vertices in the OBJ representation should equal the number of vertices in the face set:
sage: len(vertices) == len(G.vertex_list()) True
The vertices in the OBJ representation should also be approximately equal to the vertices in the face set – the small error is due to rounding which occurs during output (we test only the first 20 points for the sake of speed):
sage: def points_equal(a, b, epsilon=(1e-5)): ....: return all(abs(x0-x1) < epsilon for x0, x1 in zip(a, b)) sage: checklist = [] sage: assert len(vertices) >= 20 # I should hope so, we're rendering at the default resolution! sage: for vertex, surf_vertex in list(zip(vertices, G.vertex_list()))[0:20]: ....: checklist.append(points_equal(map(float, vertex.split(' ')[1:]), surf_vertex)) sage: all(checklist) True
-
plot_points
¶
-
region
¶
-
smooth
¶
-
tachyon_repr
(render_params)¶ Return a representation of this object suitable for use with the Tachyon renderer.
TESTS:
sage: from sage.plot.plot3d.implicit_surface import ImplicitSurface sage: var('x,y,z') (x, y, z) sage: G = ImplicitSurface(x + y + z, (x,-1, 1), (y,-1, 1), (z,-1, 1)) sage: G.tachyon_repr(G.default_render_params())[0].startswith('TRI') True
-
triangulate
(force=False)¶ The IndexFaceSet will be empty until you call this method, which generates the faces and vertices according to the parameters specified in the constructor for ImplicitSurface.
Note that if you call this method more than once, subsequent invocations will have no effect (this is an optimization to avoid repeated work) unless you specify
force=True
in the keywords.EXAMPLES:
sage: from sage.plot.plot3d.implicit_surface import ImplicitSurface sage: var('x,y,z') (x, y, z) sage: G = ImplicitSurface(x + y + z, (x,-1, 1), (y,-1, 1), (z,-1, 1)) sage: len(G.vertex_list()), len(G.face_list()) (0, 0) sage: G.triangulate() sage: len(G.vertex_list()) > 0, len(G.face_list()) > 0 (True, True) sage: G.show() # This should be fast, since the mesh is already triangulated.
-
vars
¶
-
xrange
¶
-
yrange
¶
-
zrange
¶
-
-
class
sage.plot.plot3d.implicit_surface.
MarchingCubes
¶ Bases:
object
Handles marching cube rendering.
Protocol:
- Create the class.
- Call
process_slice
once for each X slice, from self.nx > x >= 0. - Call
finish()
, which returns a list of strings.
Note
Actually, only 4 slices ever exist; the caller will re-use old storage.
-
color_function
¶
-
colormap
¶
-
contour
¶
-
finish
()¶ Return the results of the marching cubes algorithm as a list.
The format is specific to the subclass implementing this method.
TESTS:
By default, it returns an empty list:
sage: from sage.plot.plot3d.implicit_surface import MarchingCubes sage: cube_marcher = MarchingCubes((0, 1), (0, 1), (0, 1), 1, (10, 10, 10), None) sage: cube_marcher.finish() []
-
gradient
¶
-
nx
¶
-
ny
¶
-
nz
¶
-
region
¶
-
results
¶
-
smooth
¶
-
transform
¶
-
xrange
¶
-
yrange
¶
-
zrange
¶
-
class
sage.plot.plot3d.implicit_surface.
MarchingCubesTriangles
¶ Bases:
sage.plot.plot3d.implicit_surface.MarchingCubes
A subclass of MarchingCubes that returns its results as a list of triangles, including their vertices and normals (if
smooth=True
).And also their vertex colors if a vertex coloring function is given.
-
add_triangle
(v1, v2, v3)¶ Called when a new triangle is generated by the marching cubes algorithm to update the results array.
TESTS:
sage: from sage.plot.plot3d.implicit_surface import MarchingCubesTriangles, VertexInfo sage: cube_marcher = MarchingCubesTriangles((0, 1), (0, 1), (0, 1), 0, (10,)*3, smooth=False) sage: cube_marcher.add_triangle(VertexInfo(), VertexInfo(), VertexInfo()) sage: cube_marcher.finish() [({'x': 0.0, 'y': 0.0, 'z': 0.0}, {'x': 0.0, 'y': 0.0, 'z': 0.0}, {'x': 0.0, 'y': 0.0, 'z': 0.0})]
-
process_cubes
(_left, _right)¶ TESTS:
sage: from sage.plot.plot3d.implicit_surface import MarchingCubesTriangles sage: import numpy as np sage: cube_marcher = MarchingCubesTriangles((0, 1), (0, 1), (0, 1), 0, (3, 2, 2), smooth=False) sage: slices = [np.ones((2, 2), dtype=np.double) for i in range(3)] sage: slices[0][1, 1] = -1 sage: cube_marcher._update_yz_vertices(0, None, slices[0], slices[1]) sage: cube_marcher._update_x_vertices(0, None, slices[0], slices[1], slices[2]) sage: cube_marcher.process_cubes(slices[0], slices[1]) sage: cube_marcher.finish() [({'x': 0.0, 'y': 1.0, 'z': 0.5}, {'x': 0.25, 'y': 1.0, 'z': 1.0}, {'x': 0.0, 'y': 0.5, 'z': 1.0})]
-
process_slice
(x, slice)¶ Process a single slice of function evaluations at the specified \(x\) coordinate.
EXAMPLES:
sage: from sage.plot.plot3d.implicit_surface import MarchingCubesTriangles sage: import numpy as np sage: cube_marcher = MarchingCubesTriangles((-2, 2), (-2, 2), (-2, 2), 4, (10,)*3, smooth=False) sage: f = lambda x, y, z: x^2 + y^2 + z^2 sage: slices = np.zeros((10, 10, 10), dtype=np.double) sage: for x in reversed(range(0, 10)): ....: for y in range(0, 10): ....: for z in range(0, 10): ....: slices[x, y, z] = f(*[a * (4 / 9) -2 for a in (x, y, z)]) ....: cube_marcher.process_slice(x, slices[x, :, :]) sage: faces = cube_marcher.finish() sage: faces[0][0] {'x': 1.555555555555..., 'y': -1.111111111111..., 'z': -0.555555555555...}
We render the isosurface using IndexFaceSet:
sage: from sage.plot.plot3d.index_face_set import IndexFaceSet sage: IndexFaceSet([tuple((p['x'], p['y'], p['z']) for p in face) for face in faces]) Graphics3d Object
-
slices
¶
-
x_vertices
¶
-
y_vertices
¶
-
y_vertices_swapped
¶
-
z_vertices
¶
-
z_vertices_swapped
¶
-
-
class
sage.plot.plot3d.implicit_surface.
VertexInfo
¶ Bases:
object
-
sage.plot.plot3d.implicit_surface.
render_implicit
(f, xrange, yrange, zrange, plot_points, cube_marchers)¶ INPUT:
f
- a (fast!) callable functionxrange
- a 2-tuple (x_min, x_max)yrange
- a 2-tuple (y_min, y_may)zrange
- a 2-tuple (z_min, z_maz)plot_points
- a triple of integers indicating the number of function evaluations in each direction.cube_marchers
- a list of cube marchers, one for each contour.
OUTPUT:
A representation of the isosurface, in the format specified by the individual cube marchers.
TESTS:
sage: from sage.plot.plot3d.implicit_surface import render_implicit, MarchingCubesTriangles sage: plot_points, f = (40,)*3, lambda x, y, z: x + y + z sage: cube_marcher = MarchingCubesTriangles((0, 1), (0, 1), (0, 1), 1, (10,)*3) sage: results = render_implicit(lambda x, y, z: x + y + z, ....: (0, 1), (0, 1), (0, 1), (10,)*3, [cube_marcher]) sage: results[0][0] {'x': 1.0, 'y': 0.0, 'z': 0.0}