1

I am new to vispy and computer graphics. I have to generate a paraboloid according to a certain equation whose center and parameters vary according to the user input. I have gone through vispy documentation and examples and got some idea regarding the package.

The paraboloid that I need to generate should have rotational symmetry such as shown in the figure below:

enter image description here

Whereas what I got is here

enter image description here

My code is given below. I have modified the isosurface.py example in the vispy examples.

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()

My queries are the following:

  1. How do I make the paraboloid look like in the first image (without the edges getting clipped off)
  2. Is there a better way to draw the paraboloid other than using isosurfaces. The coefficients of the paraboloid should be varied by the user.
  3. How to make the paraboloid respond to mouse events: hover, drag-drop etc. I understand from the documentation that I have to couple it to the Node class. I am unable to figure out the exact way to do this as I am a newbie.

Edit:

Here is the corresponding code using matplotlib for generating the required paraboloid. Also I am able to create a paraboloidal strip in 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()

This results in the following: enter image description here

The difference between the surface plot of vispy and matplotlib is that the latter work by accepting 2D arrays for x and y, whereas vispy's SurfacePlot() accepts only 1D vectors in both x and y.

Since the grid in cylindrical coordinates and converting them to cartesian coordinates for plotting, the grid cannot be generated by replicating the 1D x and y vectors.

Update: As pointed by @djhoesem, isosurface is not the correct method to do this.

DVS
  • 43
  • 10

2 Answers2

1

I'm the maintainer of vispy, but have very little isosurface experience. Let's see what I can answer:

  1. The easiest thing I saw to do this is to make levels even smaller (I made it zero for testing). I'm not sure how this effects performance or the output exactly but the isosurface function mentions the paper it is based on. Maybe that can tell you more.
    See Paul Bourke, "Polygonising a Scalar Field"  
    (http://paulbourke.net/geometry/polygonise/)
  1. To make the parameters controllable by the user you could subclass the existing Isosurface class and add properties to control these. However, this will probably perform poorly if you want immediate feedback since you'd have to regenerate the numpy array and rerun all the other calculations on the CPU. The IsosurfaceVisual class expects volumetric data and then converts it to an isosurface. It generates a mesh that the MeshVisual understands (IsosurfaceVisual is a subclass of MeshVisual). If you want anything better you'd probably have to write your own shader code to do it. Depends what your exact requirements are (do you have to accept any formula with controllable coefficients?).

  2. The scene.visuals Visual classes are already subclasses of the Node class so you don't have to do anything extra there. The other SceneCanvas-based examples should give you some ideas of how you can handle mouse events. That said, you mentioned "drag-drop", I'm not sure that would be something you'd handle in VisPy land but more likely in PyQt5 land (if that's the backend you are using).

djhoese
  • 3,567
  • 1
  • 27
  • 45
  • Thanks for your reply. I had the similar concern to what you have explained regarding the performance when using isosurfaces. When I looked at the examples, I found that the isosurface helped me quickly create the surface I wanted. There is an example on the construction of a sphere using Mesh. I found it difficult to customise it for my equations. As you mentioned in #2, I have to create other surfaces too based on their equations. Paraboloid is only one of the surfaces. It would be good if you can suggest any resource/example the usage of meshes for this. – DVS Apr 14 '20 at 06:29
  • The existing examples are the best source for vispy-specific help. These concepts are specific to vispy so you might be able to find an OpenGL implementation of what you're trying to do and then adapt it to work with vispy. If you need additional help you might try a github issue for more back and forth (something SO isn't really good for). – djhoese Apr 14 '20 at 12:32
1

Added the feature via pull request: https://github.com/vispy/vispy/pull/1863#event-3344873987

Made a small modification to the code and resolved the issue.

The corresponding example can be found here: https://github.com/vispy/vispy/blob/master/examples/basics/visuals/axially_symmetric_surfaces.py

DVS
  • 43
  • 10