Как создать параболоидную поверхность и заставить ее реагировать на события - PullRequest
1 голос
/ 12 апреля 2020

Я новичок в vispy и компьютерной графике. Я должен создать параболоид согласно определенному уравнению, центр и параметры которого меняются в зависимости от ввода пользователя. Я просмотрел документацию и примеры по Vispy и получил некоторое представление о пакете.

Параболоид, который мне нужно создать, должен иметь симметрию вращения, как показано на рисунке ниже:

enter image description here

Принимая во внимание, что я получил здесь

enter image description here

Мой код указан ниже. Я изменил пример isosurface.py в примерах vispy.

import sys
import numpy as np

from vispy import app, scene

from matplotlib import pyplot as plt

# Create a canvas with a 3D viewport
canvas = scene.SceneCanvas(keys='interactive')
view = canvas.central_widget.add_view()


## Define a scalar field from which we will generate an isosurface
def psi3(i, j, k, offset=(25, 25, 25)):
    x = i-offset[0]
    y = j-offset[1]
    z = k-offset[2]
    r = (0.2*x**2 + 0.2*y**2 - 4*z)
    return r

# Create isosurface visual
data = np.fromfunction(psi3, (50, 50, 50))

surface = scene.visuals.Isosurface(data, level=data.max() / 4., color=(0.5, 0.6, 1, 1), shading='smooth', parent=view.scene)
surface.transform = scene.transforms.STTransform(translate=(-25, -25, -25))

# Add a 3D axis to keep us oriented
axis = scene.visuals.XYZAxis(parent=view.scene)

# Use a 3D camera
# Manual bounds; Mesh visual does not provide bounds yet
# Note how you can set bounds before assigning the camera to the viewbox
cam = scene.TurntableCamera(elevation=30, azimuth=30)
cam.set_range((-10, 10), (-10, 10), (-10, 10))
view.camera = cam

if __name__ == '__main__':
    canvas.show()
    if sys.flags.interactive == 0:
        app.run()

Мои запросы следующие:

  1. Как сделать параболоид похожим на первом изображении ( без обрезания краев)
  2. Есть ли лучший способ рисовать параболоид, кроме использования изоповерхностей. Коэффициенты параболоида должны изменяться пользователем.
  3. Как заставить параболоид реагировать на события мыши: hover, drag-drop et c. Из документации я понимаю, что должен связать ее с классом Node. Я не могу понять точный способ сделать это, так как я новичок ie.

Редактировать:

Вот соответствующий код, используя matplotlib для генерации необходимого параболоида. Также я могу создать параболоидную полосу в matplotlib.

import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np



# Create the surface
radius = 5
hole_radius = 4

# Generate the grid in cylindrical coordinates
r  = np.linspace(0, radius, 100)
theta = np.linspace(0, 2 * np.pi, 100)
R, THETA = np.meshgrid(r, theta)

X, Y = R * np.cos(THETA), R * np.sin(THETA)
a=0.6;b=0.6;c=0.6
Z1 = (X/a)**2+(Y/b)**2 # Elliptic paraboloid

# Do not plot the inner region
x = np.where(X**2+Y**2<=hole_radius**2,np.NAN,X)
y = np.where(X**2+Y**2<=hole_radius**2,np.NAN,Y)

# Plot the surface
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(x, y, Z1, cmap=cm.coolwarm, linewidth=0, antialiased=True, cstride=2, rstride=2)

ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")

plt.show()

Это приводит к следующему: enter image description here

Разница между поверхностным участком вязкости и matplotlib состоит в том, что последний работает, принимая двумерные массивы для x и y, тогда как SurfacePlot () vispy принимает только одномерные векторы как в x, так и в y.

Поскольку сетка имеет цилиндрические координаты и преобразует их в декартовы координаты для При построении графика сетка не может быть сгенерирована путем репликации векторов 1D x и y.

Обновление: Как указывает @djhoesem, isosurface не является правильным методом для этого.

1 Ответ

1 голос
/ 13 апреля 2020

Я поддерживаю vispy, но у меня очень мало опыта работы с изоповерхностью. Давайте посмотрим, что я могу ответить:

  1. Самое простое, что я видел, чтобы сделать это, это сделать levels еще меньше (я сделал его нулевым для тестирования). Я не уверен, как это влияет на производительность или результат, но функция isosurface упоминает бумагу, на которой она основана. Может быть, это может сказать вам больше.
    See Paul Bourke, "Polygonising a Scalar Field"  
    (http://paulbourke.net/geometry/polygonise/)

Чтобы сделать параметры контролируемыми пользователем, вы можете создать подкласс существующего класса Isosurface и добавить свойства для управления ими. Тем не менее, это, вероятно, будет работать плохо, если вы хотите немедленной обратной связи, так как вам придется перегенерировать массив numpy и перезапустить все другие вычисления на ЦП. Класс IsosurfaceVisual ожидает данные объема c и затем преобразует их в изоповерхность. Он генерирует меня sh, которое понимает MeshVisual (IsosurfaceVisual является подклассом MeshVisual). Если вы хотите что-то лучше, вам, вероятно, придется написать собственный код шейдера, чтобы сделать это. Зависит от ваших точных требований (вы должны принять любую формулу с контролируемыми коэффициентами?).

scene.visuals Визуальные классы уже являются подклассами Node класс, так что вам не нужно делать там ничего лишнего. Другие примеры на основе SceneCanvas должны дать вам некоторые идеи о том, как вы можете обрабатывать события мыши. Тем не менее, вы упомянули «перетаскивание», я не уверен, что это будет чем-то, что вы будете обрабатывать на земле VisPy, но, скорее всего, на земле PyQt5 (если вы используете бэкэнд).

...