Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion example_scenes/basic.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python


from manim import *
from manim.mobject.three_d.implicit_surface import ImplicitSurface

# To watch one of these scenes, run the following:
# python --quality m manim -p example_scenes.py SquareToCircle
Expand Down Expand Up @@ -176,4 +176,16 @@ def construct(self):
self.add(grp)


class ExampleImplicitSurface(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=70 * DEGREES, theta=45 * DEGREES)
surface = ImplicitSurface(
lambda x, y, z: x**2 + y**2 + z**2 - 1,
resolution=30,
color=BLUE,
)
self.add(surface)
self.wait()


# See many more examples at https://docs.manim.community/en/stable/examples.html
69 changes: 69 additions & 0 deletions manim/mobject/three_d/implicit_surface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from __future__ import annotations

import numpy as np
from skimage import measure

from manim import *

Check notice

Code scanning / CodeQL

'import *' may pollute namespace Note

Import pollutes the enclosing namespace, as the imported module
manim
does not define '__all__'.


class ImplicitSurface(ThreeDVMobject):
"""Renderiza uma isosuperfície implícita usando Marching Cubes.

Parameters
----------
func : Callable[[float, float, float], float]
Função implícita f(x,y,z). A superfície é definida onde f(x,y,z) = isolevel.
resolution : int, default=25
Número de divisões por eixo.
isolevel : float, default=0.0
Nível da isosuperfície.
x_range, y_range, z_range : list[float], default=[-2, 2]
Intervalos de amostragem.
color : Color, default=BLUE
Cor da superfície.
**kwargs
Argumentos adicionais para ThreeDVMobject.
"""

def __init__(
self,
func,
resolution=25,
isolevel=0.0,
x_range=[-2, 2],
y_range=[-2, 2],
z_range=[-2, 2],
color=BLUE,
**kwargs,
):
super().__init__(**kwargs)

# Gera a grade 3D:
x = np.linspace(x_range[0], x_range[1], resolution)
y = np.linspace(y_range[0], y_range[1], resolution)
z = np.linspace(z_range[0], z_range[1], resolution)
X, Y, Z = np.meshgrid(x, y, z, indexing="ij")
values = func(X, Y, Z)

# Extrai a malha:
verts, faces, _, _ = measure.marching_cubes(values, level=isolevel)

# Normaliza para o domínio real:
scale_x = (x_range[1] - x_range[0]) / resolution
scale_y = (y_range[1] - y_range[0]) / resolution
scale_z = (z_range[1] - z_range[0]) / resolution
verts = np.array(
[
[
x_range[0] + v[0] * scale_x,
y_range[0] + v[1] * scale_y,
z_range[0] + v[2] * scale_z,
]
for v in verts
]
)

# Constrói os polígonos:
for face in faces:
tri = [verts[i] for i in face]
self.add(Polygon(*tri, color=color, fill_opacity=1))
12 changes: 12 additions & 0 deletions tests/test_implicit_surface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from manim import *
from manim.mobject.three_d.implicit_surface import ImplicitSurface


class TestSurfaceScene(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=70 * DEGREES, theta=45 * DEGREES)
surface = ImplicitSurface(
lambda x, y, z, r=0.7: x**2 + y**2 - r**2, resolution=20, color=WHITE
)
self.add(surface)
self.wait()
16 changes: 16 additions & 0 deletions tests/test_implicit_surface360.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from manim import *
from manim.mobject.three_d.implicit_surface import ImplicitSurface


class TestSurface360(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=70 * DEGREES, theta=0)

surface = ImplicitSurface(
lambda x, y, z: x**2 + y**2 + z**2 - 1, resolution=20, color=BLUE
)
self.add(surface)

self.begin_ambient_camera_rotation(rate=PI / 4)
self.wait(8)
self.stop_ambient_camera_rotation()
Loading