I wrote a Python script using matplotlib, to visualize and rotate polycubes together with planes or axes that reveal symmetry in the polycube. Up to a certain point I succeeded as you can see from the illustrations below. There you see one of seventy-seven possible 3D polycubes of six cubes. My script uses matplotlib and it seems to do a nice job: matplotlib allows me to rotate the polycube and view it at any wanted angle. There is a big problem with most polycubes, which is illustrated in the second image below. A little after I start rotating the polycube, matplotlib shows planes that are partly behind other planes and are therefore partly invisble and not to be drawn or only partly drawn.
I have been searching a lot on forums and with Google, but to no avail. There were hits suggesting that I should use mayavi instead of matplotlib. So I studied extensively on mayavi. I spent literally weeks trying to figure out how to get mayavi going. The hits on docs.enthought seemed promising at first, but although mayavi is clearly suited to the purpose and superb in visualizing objects, I cannot find understandable documentation. I could use a real programmers guide on vtk or tvtk. There is a lot of documentation, but mostly for designers, not programmers. If not available (?) I would also be happy with an example of a script with hexahedrons or irregular grids, that works in canopy's (1.6.2) implementation of python.
I've modified an example from the vtk documentation (http://www.vtk.org/gitweb?p=VTK.git;a=blob_plain;f=Examples/DataManipulation/Python/BuildUGrid.py)
This example can be turned into a function which can create the geometry from a point coordinate array and an element array.
I haven't used any guides for vtk, I usually refer to the python examples found here: http://www.vtk.org/Wiki/VTK/Examples/Python
import vtk
# Initialize the vtkPoints variable and set the number of points
points = vtk.vtkPoints()
points.SetNumberOfPoints(8)
# Add points to the variable, with the point number first, then the x, y, z coordinates.
# For demonstration purposes, I started numbering the ponts at 10 (normally they would start at 0).
points.InsertPoint(0, 0, 0, 0)
points.InsertPoint(1, 1, 0, 0)
points.InsertPoint(2, 1, 1, 0)
points.InsertPoint(3, 0, 1, 0)
points.InsertPoint(4, 0, 0, 1)
points.InsertPoint(5, 1, 0, 1)
points.InsertPoint(6, 1, 1, 1)
points.InsertPoint(7, 0, 1, 1)
points.InsertPoint(8, 0, 0, 1.1)
points.InsertPoint(9, 1, 0, 1.1)
points.InsertPoint(10, 1, 1, 1.1)
points.InsertPoint(11, 0, 1, 1.1)
points.InsertPoint(12, 0, 0, 2)
points.InsertPoint(13, 1, 0, 2)
points.InsertPoint(14, 1, 1, 2)
points.InsertPoint(15, 0, 1, 2.5)
# Define the hexahedron, then set the point Ids of the hexahedron cell/element.
# From the documentation: points (0,1,2,3) is the base of the hexahedron which, using the right hand rule, forms a
# quadrilaterial whose normal points in the direction of the opposite face (4,5,6,7)
aHexahedron1 = vtk.vtkHexahedron()
aHexahedron1.GetPointIds().SetId(0, 0) # Cell point 0 corresponds to point 0 which was defined above
aHexahedron1.GetPointIds().SetId(1, 1)
aHexahedron1.GetPointIds().SetId(2, 2)
aHexahedron1.GetPointIds().SetId(3, 3)
aHexahedron1.GetPointIds().SetId(4, 4)
aHexahedron1.GetPointIds().SetId(5, 5)
aHexahedron1.GetPointIds().SetId(6, 6)
aHexahedron1.GetPointIds().SetId(7, 7)
# Define a second hexahedron
aHexahedron2 = vtk.vtkHexahedron()
aHexahedron2.GetPointIds().SetId(0, 8) # Cell point 0 corresponds to point 8 which was defined above
aHexahedron2.GetPointIds().SetId(1, 9)
aHexahedron2.GetPointIds().SetId(2, 10)
aHexahedron2.GetPointIds().SetId(3, 11)
aHexahedron2.GetPointIds().SetId(4, 12)
aHexahedron2.GetPointIds().SetId(5, 13)
aHexahedron2.GetPointIds().SetId(6, 14)
aHexahedron2.GetPointIds().SetId(7, 15)
# Define an unstructured grid.
aHexahedronGrid = vtk.vtkUnstructuredGrid()
# Add the hexahedron to the unstructured grid
# Note: this operation defines the point ids, and not the actual point coordinates
aHexahedronGrid.InsertNextCell(aHexahedron1.GetCellType(), aHexahedron1.GetPointIds())
aHexahedronGrid.InsertNextCell(aHexahedron2.GetCellType(), aHexahedron2.GetPointIds())
# Set the points which includes the coordinates. The point ids defined in the line above correspond to the point ids
# that were defined earlier (i.e. points.InsertPoint(10, 0, 0, 0))
aHexahedronGrid.SetPoints(points)
# Now we have defined one hexahedron, and added it an unstructured grid.
# We could create more hexahedrons, and add them to the same unstructured grid.
# To view the unstructured grid, we need to define a mapper and set the unstructured grid as the input
aHexahedronMapper = vtk.vtkDataSetMapper()
aHexahedronMapper.SetInputData(aHexahedronGrid)
# Define an actor, and set the mapper as the input
aHexahedronActor = vtk.vtkActor()
aHexahedronActor.SetMapper(aHexahedronMapper)
# Create the usual rendering stuff.
ren = vtk.vtkRenderer()
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(ren)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
iren.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera()) # Change the rotation type from the default to 'trackball'
ren.SetBackground(.1, .2, .4)
# Add the actor to the renderer to actually view the geometry
ren.AddActor(aHexahedronActor)
# Render the scene and start interaction.
iren.Initialize()
renWin.Render()
iren.Start()
Related
I'm doing some stuff with 2D opengl rendering.
Is there a way to render a vertex array object but have the data be passed through multiple shaders? For example, a shader that applies a normal map to the texture, and then a shader that blurs the image. It would be very difficult and unclean to combine the two shaders into one let alone potentially combining more than 2 shaders. This is my current code for creating the vertex array object:
# TEX_COORDS = [0, 1, 1, 1,
# 0, 0, 1, 0]
# TEX_INDICES = [0, 1, 2,
# 1, 2, 3]
# self.vertices looks something like this: [-1, -1, 1, -1, -1, 1, 1, 1], but with different coordinates
self.vbo = self.ctx.buffer(struct.pack("8f", *self.vertices))
self.uv_map = self.ctx.buffer(struct.pack("8f", *TEX_COORDS))
self.ibo = self.ctx.buffer(struct.pack("6I", *TEX_INDICES))
self.vao_content = [(self.vbo, "2f", "vertexPos"), (self.uv_map, "2f", "vertexTexCoord")]
self.vao = self.ctx.vertex_array(self.program, self.vao_content, self.ibo) # self.program is the shader program object
And I'm doing texture.use() (texture being a moderngl texture object) and then self.vao.render() to render it onto the screen.
A single rendering call will only ever use a single set of vertex, fragment, and other shaders. You cannot chain together shaders for a particular stage via the API; you must manufacture a single such shader that does those multiple things.
How you go about that process is up to you. You can have one shader that has all possible operations, with a bunch of uniform variables that define which operations will be applied. Or you can dynamically build shaders to fit particular needs.
I have a mesh file generate by Gmsh(*.vtu), the mesh is a cube area and consist of tetrahedrons. Then I have a point (given by coordinate) in the cube, I want to find which tetrahedron contains the point, how did I do?
with pygmsh.occ.Geometry() as geom:
geom.add_box([0, 0, 0],
[1, 1, 1], mesh_size=0.1)
mesh = geom.generate_mesh()
mesh.write('original_gmsh.vtu')
uGridReader = vtkXMLUnstructuredGridReader()
uGridReader.SetFileName('original_gmsh.vtu')
uGridReader.Update()
uGrid: vtkUnstructuredGrid = uGridReader.GetOutput()
givenPoint = [0.5, 0.5, 0.5]
You should be able to use the FindAndGetCell() method that vtkUnstructuredGrid inherits from vtkDataSet. The python documentation for this can be found using help(vtkUnstructuredGrid.FindAndGetCell) within your python shell (assuming you have imported vtkUnstructuredGrid, if not prepend with vtk. as usual.
As a recommendation, consider check out the PyVista package, its far easier to use in my experience and uses VTK as its backend as well.
I created a simple unstructured square in VTK:
x = [0,10,0,10]
y = [0, 0, 10, 10]
z = [0,0,0,0]
data = np.asarray([x,y,z]).T
for i in range(0, len(x)):
points.InsertPoint(i, data[i])
quad = [2,3,1,0]
ugrid.InsertNextCell(vtk.VTK_QUAD, 4, quad)
ugrid.SetPoints(points)
Say I wanted to create a colormap of the temperature across the square. I know the temperature at the corners:
temp = [0,20,40,60]
How can I color the entire square knowing these values?
VTK provides one example to create a colormap in their tutorials (the ColoredElevationMap tutorial), however, I don't completely understand it and I believe there is another simpler way to create a colormap in VTK that I don't know of.
You should add your data array and set it as the scalars (= default array to use in VTK, particularly for coloring)
temperature = vtk.vtkIntArray()
temperature.SetName("Temp")
temp = [00,20,40,60]
for t in temp:
temperature.InsertNextValue(t)
ugrid.GetPointData().SetScalars(temperature)
Then in the rendering part, this array will be used by default for coloration. You still have to update the color range:
mapper.SetScalarRange(ugrid.GetScalarRange())
You can take a look to this example (edit: update link thanks to #paulo-carvalho)
Adding to Nico Vuaille's answer. The color of the map can be changed using a lookup table such as:
lut = vtk.vtkLookupTable()
lut.SetHueRange(0, 0)
lut.SetSaturationRange(0, 0)
lut.SetValueRange(0.2, 1.0)
lut.Build()
and
Mapper.SetLookupTable(lut)
I have 6 corner points coordinate of 3d surface like Figure 1. I want to generate and plot 3d surface like Figure 2. I need to find the distance of midpoint of each meshed area from the origin.
Figure 1
Figure 2
Please suggest me, which module will be better for meshing and also for plotting?
PyVista and vtkplotter are very similar and both are built on top of VTK but have pretty different APIs/design choices. For your use, either would be great! Here is the equivalent with PyVista for completeness.
Typically with simple geometries like this, Matplotlib, PyVista, or vtkplotter would all do well. If you start to create more sophisticated meshes and 3D scenes, then that's where PyVista and vtkplotter will excel as they are built for 3D while MPL is really awesome at 2D.
PyVista will especially excel at data management if you start making complex meshes.... shameless plug ;)
import pyvista as pv
import numpy as np
# Define the nodes
pts = np.array([(-5.795555, -4, 1.55291), (-4.829629, -2, 1.294095),
(-5.795555, 1, 1.552914), (-5.536736, -4, 2.51884),
(-4.57081, -2, 2.260021), (-5.536736, 1, 2.51884)])
# Define the quads
faces = np.array([(4,0,3,4,1), (4,1,4,5,2)])
# Instantiate a mesh
mesh = pv.PolyData(pts, faces)
# Create a plotting window and display!
p = pv.Plotter()
# Add the mesh and some labels
p.add_mesh(mesh, show_edges=True)
p.add_point_labels(mesh.points, ["%d"%i for i in range(mesh.n_points)])
# A pretty view position
p.camera_position = [(-11.352247399703748, -3.421477319390501, 9.827830270231935),
(-5.1831825, -1.5, 1.9064675),
(-0.48313206526616853, 0.8593146723923926, -0.16781448484204659)]
# Render it!
p.show()
You can use vedo:
from vedo import *
pts = [(-5.795555, -4, 1.55291), (-4.829629, -2, 1.294095),
(-5.795555, 1, 1.552914), (-5.536736, -4, 2.51884),
(-4.57081, -2, 2.260021), (-5.536736, 1, 2.51884)]
faces = [(0,3,4,1), (1,4,5,2)]
mesh = Mesh([pts, faces]).color('red').alpha(0.3).lineWidth(2)
labels = [Text(i, pos=pts[i], s=.2, c='k') for i in range(len(pts))]
show(mesh, labels)
I don't know what your data looks like, but matplotlib is capable of plotting 3D surfaces based on points with x, y and z coordinates.
See: https://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html
Using Python and VTK I am trying to render 10k cylinders to visualize gradient directions. I have reviewed multiple examples on the internet but none of them shows how you can, at the same time, change the position, orientation, color and height of each rendered cylinder independently.
I know it is possible to create an actor per cylinder but with 10k cylinders that would be very slow.
The following example code is my work in progress on this problem. I first define some data for 2 cylinders and next I try to visualize them with VTK.
What works is the position, orientation and color of the cylinders.
What does not work is the height of each cylinder.
Possible solutions might be to use different cylinder sources to get the heights right. Yet I don't know how to apply those.
Perhaps a more experienced VTK programmer can enlighten me?
from vtk import *
# input data, every row is for a different item
positions = [[0, 0, 0],
[1.5, 0, 0]]
orientations = [[1.0, 0.0, 0.0],
[0.0, 1.0, 1.0]]
colors = [[255, 0, 0],
[0, 255, 255]]
heights = [1,
2]
# rendering of those two defined cylinders
points = vtkPoints()
points.InsertNextPoint(*positions[0])
points.InsertNextPoint(*positions[1])
polydata = vtkPolyData()
polydata.SetPoints(points)
color_def = vtkUnsignedCharArray()
color_def.SetNumberOfComponents(3)
color_def.SetNumberOfTuples(polydata.GetNumberOfPoints())
color_def.InsertTuple3(0, *colors[0])
color_def.InsertTuple3(1, *colors[1])
polydata.GetPointData().SetScalars(color_def)
pointNormalsArray = vtkDoubleArray()
pointNormalsArray.SetNumberOfComponents(3)
pointNormalsArray.SetNumberOfTuples(polydata.GetNumberOfPoints())
pointNormalsArray.SetTuple(0, orientations[0])
pointNormalsArray.SetTuple(1, orientations[1])
polydata.GetPointData().SetNormals(pointNormalsArray)
cyl_source = vtkCylinderSource()
cyl_source.SetResolution(10)
cyl_source.SetHeight(0.8)
cyl_source.SetRadius(0.1)
cyl_source.Update()
glyph = vtkGlyph3D()
glyph.SetInputData(polydata)
glyph.SetSourceConnection(cyl_source.GetOutputPort())
glyph.SetColorModeToColorByScalar()
glyph.SetVectorModeToUseNormal()
glyph.ScalingOff()
mapper = vtkPolyDataMapper()
mapper.SetInputConnection(glyph.GetOutputPort())
actor = vtkActor()
actor.SetMapper(mapper)
ren = vtkRenderer()
ren.AddActor(actor)
renwin = vtk.vtkRenderWindow()
renwin.AddRenderer(ren)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renwin)
renwin.Render()
iren.Initialize()
iren.Start()
It seems that http://www.vtk.org/Wiki/VTK/Examples/Python/Visualization/ClampGlyphSizes has something similar to what you need (I haven't tried):
# Tell glyph which attribute arrays to use for what
glyph.SetInputArrayToProcess(0,0,0,0,'Elevation') # scalars
glyph.SetInputArrayToProcess(1,0,0,0,'RTDataGradient') # vectors
# glyph.SetInputArrayToProcess(2,0,0,0,'nothing') # normals
glyph.SetInputArrayToProcess(3,0,0,0,'RTData') # colors
From the documentation http://www.vtk.org/doc/nightly/html/classvtkGlyph3D.html#details :
You can set what arrays to use for the scalars, vectors, normals, and
color scalars by using the SetInputArrayToProcess methods in
vtkAlgorithm. The first array is scalars, the next vectors, the next
normals and finally color scalars.
vtkGlyphMapper and vtkGlyph3DMapper allow you to set a 3-dimensional ScaleArray, which you can then add to the point data:
glyph.SetScaleArray("CylinderScales")
scaleArray = vtkDoubleArray()
scaleArray.SetName("CylinderScales")
scaleArray.SetNumberOfComponents(3)
scaleArray.SetNumberOfTuples(polydata.GetNumberOfPoints())
scaleArray.SetTuple(0, (1, 1, 1))
scaleArray.SetTuple(1, (1, 1, 2))
polydata.GetPointData().AddArray(scaleArray)
The second cylinder should be twice as tall as the first, unless I got my axes wrong.