I am attempting to create a world file that accompanies each screenshot I produce so that I can easily reference the files in CAD in the correct location, orientation, and scale as my original input data.
The issue is that I need to obtain the coordinates of the upper left corner of the exported image to use as the base point in the worldfile.
If we use the simple code below you will see the the top left corner of the rendered polydata is (0, 1)
. However I need the actual coordinates of the corner of the image.
I had assumed that the plotter.bounds()
would return the polydata bounds and the renderer.bounds()
would return the image bounds. However they both return the polydata bounds. Any ideas?
import pyvista as pv
points = [[0, 0, 0],
[1, 0, 0],
[0.5, 1.0, 0]]
mesh = pv.PolyData(points)
pl = pv.Plotter()
pl.add_mesh(mesh)
pl.show_bounds(location='all', all_edges=True, grid=True)
pl.camera.tight(padding=0.1)
pl.parallel_projection = True #redunant but set he to remove perspective questions
pl.screenshot('with_padding')
pl.show()
pl.bounds
(0.0, 1.0, 0.0, 1.0, 0.0, 0.0)
pl.renderer.bounds
(0.0, 1.0, 0.0, 1.0, 0.0, 0.0)
Does anyone know of a method that returns the image corner coordinates?
Although I noted in a comment that the question can only be answered if we restrict ourselves the an xy
view (because in that case the z
coordinate is arbitrary but you only seem to be looking for x
and y
coordinates), it seems that VTK readily has machinery that can do these coordinate transformations via vtkCoordinate()
.
You can create a vtkCoordinate
instance, set its coordinate system to be normalized viewport, use the corresponding normalized coordinates ((0, 0)
is bottom left corner, (1, 1)
is upper right), then query the corresponding world points using the plotter's renderer:
import pyvista as pv
from vtkmodules.vtkRenderingCore import vtkCoordinate
# example data
points = [
[0, 0, 0],
[1, 0, 0],
[0.5, 1.0, 0],
]
mesh = pv.PolyData(points)
# example plot
pl = pv.Plotter()
pl.add_mesh(mesh)
pl.show_bounds(location='all', all_edges=True, grid=True)
pl.camera.tight(padding=0.1)
pl.parallel_projection = True
# get world coordinates of upper left corner of viewport
coordinate = vtkCoordinate()
coordinate.SetCoordinateSystemToNormalizedViewport()
coordinate.SetValue(0, 1) # (0, 0) is lower left, (1, 1) is upper right
coords = coordinate.GetComputedWorldValue(pl.renderer)
print(coords)
# (-0.050000000000000044, 1.05, 0.06472500000000003)
I slightly edited your example data, and the last code block prints the world coordinates of the upper left corner. Notice you have a nonzero z
coordinate; you'll have to make sure to discard this, or check how this behaves with a real, thick mesh. If you have older vtk
and you get an import error, you can use from vtk import vtkCoordinate
instead of the vtkmodules
import, but this will be a lot slower (pyvista uses vtkCoordinate
internally, so the above version of the import is free).
Looking at your original figure, (-0.05, 1.05)
looks correct to me. Unfortunately I couldn't visually prove that this is the correct position, because adding a new mesh even with reset_camera=False
messes with the resulting view, even if I restore pl.camera_position
from before the second mesh is added. I suspect this has to do with something related to pl.camera.tight()
. Anyway, you should be able to confirm the values with your real mesh.