Convert from plotter coordinates to world coordinates in PyVista - python

I am new to PyVista and vtk. I am implementing a mesh editing tool (Python=3.10, pyvista=0.37,vtk=9.1 ) When a user clicks all points within a given radius of the mouse cursor's world coordinates (e.g. projected point on the surface) should be selected. I have implemented this much through callbacks to mouse clicks using the pyvista plotters track_click_position method.
My problem is that I also want for a user to be able to preview the selection (highlight the vertices that will be selected) before they click. For this it is necessary to track the mouse location in world coordinates and to attach a callback function to the movement of the mouse that will highlight the relevant nodes.
The pyvista plotter's 'track_mouse_position' method doesn't support attaching callbacks but I figured out a work around for that. In the minimal example below I have managed to track changes to the mouse cursor location in pixels in the plotter's coordinate system. I am stuck now as to how to convert these into world coordinates. When the mouse hovers over the sphere these 'world coordinates' this should be the projected location on the sphere. When the mouse hovers off the sphere then it should return nothing or inf or some other useless value.
import pyvista as pv
def myCallback(src,evt):
C = src.GetEventPosition() # appears to be in pixels of the viewer
print(C)
# how to convert C into world coordinates on the sphere
sp = pv.Sphere()
p = pv.Plotter()
p.add_mesh(sp)
p.iren.add_observer("MouseMoveEvent",myCallback)
p.show()
Thank you very much for your help.
Harry

I figured this one out. They key was to use 'pick_mouse_position' after calling 'track_mouse_position'.
import pyvista as pv
def myCallback(src,evt):
out = p.pick_mouse_position()
print(out)
sp = pv.Sphere()
p = pv.Plotter()
p.add_mesh(sp)
p.track_mouse_position()
p.iren.add_observer("MouseMoveEvent",myCallback)
p.show()

Related

How to generate a ripple shape pattern using python

I am looking to create a repetitive pattern from a single shape (in the example below, the starting shape would be the smallest centre star) using Python. The pattern would look something like this:
To give context, I am working on a project that uses a camera to detect a shape on a rectangle of sand. The idea is that the ripple pattern is drawn out around the object using a pen plotter-type mechanism in the sand to create a zen garden-type feature.
Currently, I am running the Canny edge detection algorithm to create a png (in this example it would be the smallest star). I am able to convert this into an SVG using potrace, but am not sure how to create the ripple pattern (and at what stage, i.e. before converting to an SVG, or after).
Any help would be appreciated!
Here's how I did it:
In the end, I ran a vertex detection algorithm to calculate the shape's vertices.
Then, I sorted them in a clockwise order around the centroid coordinate. Using the svgwrite library, I recreated the shapes using lines.
I 'drew' a circle with a set radius around each vertex and calculated the intersection between the circle and a straight line from the centroid through the vertex.
This gave me two potential solutions (a +ve and a -ve). I chose the point furthest away from the centroid, iterated this method for each vertex and joined the points to create an outline of the shape.
Assing you are using turtle (very beginner friendly) you can use this:
import turtle, math
turtle.title("Stars!")
t = turtle.Turtle()
t.speed(900) # make it go fast
t.hideturtle() # hide turtle
t.width(1.5) # make lines nice & thick
def drawstar(size):
t.up() # make turtle not draw while repositioning
t.goto(0, size * math.sin(144)) # center star at 0, 0
t.setheading(216); # make star flat
t.down() # make turtle draw
for i in range(5): # draw 5 spikes
t.forward(size)
t.right(144)
t.forward(size)
t.right(288)
drawstar(250)
drawstar(200)
drawstar(150)
drawstar(100)
input() # stop turtle from exiting
which creates this:

Python OpenGL glRotatef - looking for the correct multiplier

I am using gluLookAt with a camera whose coordinates are xCam, yCam and zCam. The coordinates of the object the camera is looking at are xPos, yPos, and zPos. There are variables named mouseturnX and mouseturnY, which measure the deviation of the mouse from the middle of the screen in the x-axis and the y-axis. The variable camdist describes the distance between camera and the object it looks at.
The code of the cameraposition is this:
xCam = sin(mouseturnX)*camdist+xPos
yCam = mouseturnY+yPos
zCam = cos(mouseturnX)*camdist+zPos
I now made a polygon object, which I rotate with:
glRotatef(mouseturnX,0,1,0)
Usually it should only show me the backside of the object, it does not matter which position the camera has. But now it does not turn correctly. I tried it with other rotation-axises, there it works fine, but with the y-axis it just does not want to work. I tried changing the camdist from positive to negative, the mouseturnX in the glRotatef function from positive to negative and back to positive again. It just does not work. I used glPushMatrix before the rotation command and glPopMatrix after it. One line before the rotation command I used the translate function to set a fixpoint for the polygon.
Edit: The polygon actually spins, but not in the right amount. It seems like I have to multiply the rotation of the polygon with something.
I found the multiplicator by trying. It is 56.5. It is not perfect, but it works.

Can I select multiple random points from .obj file by Python and Open3D

What should I do if I want to pick up some random point from .obj file by Open3D.
I test that I can read file by
import open3d as o3d
print("Testing IO for textured meshes ...")
textured_mesh = o3d.io.read_triangle_mesh("../pikaqiu.obj")
print(textured_mesh)
mesh = o3d.geometry.TriangleMesh()
but how can I choose a point from the file?
First, you can visualize the mech byopen3d.visualization.draw_geometries_with_editing().
Then, after the window appears, you can select points by Shift+Left Mouse Click. If you want to deselect, then Shift+Right Mouse Click. After you are done selecting the points, press Q or Esc to close the window. get_picked_points() will return you indices of multiple points you selected.
import open3d as o3d
textured_mesh = o3d.io.read_triangle_mesh("../pikaqiu.obj")
vis = o3d.visualization.draw_geometries_with_editing()
vis.create_window()
vis.add_geometry(textured_mesh)
vis.run() # user picks points
vis.destroy_window()
vis.get_picked_points()
You can get the points from the array of the mesh
mesh_array = np.asarray(pcd.points)
points = mesh_array[vis.get_picked_points()]

Using PsychoPy changing origin coordinate

I am trying to make a program that gets Pen coordinate from wacom tablet which I manage to figure out using this:
data = display.Display().screen().root.query_pointer()._data
X = data["root_x"]-cfg['winpos'][0]-(cfg['width']/2)
Y = cfg['height']-(data["root_y"]-cfg['winpos'][1])-(cfg['height']/2)
print "Pen Position is: ", X, Y
but problem is that Psychopy has origin coordinate for screen at the centre please refer to pic:
and i am using a wacom INTUOS PTZ1230 12" 12" tablet which i want (0, 0) to start from regular monitor origin from top refer to second pic.
very long to read but all i need is to change my coordinate system in python using psychopy. thanks any bit helps
Experimenters generally present their stimuli symetrically around the center of the screen so, although top left and bottom left are (both) more conventional for the origin, the center of the screen makes most sense for scientists.
The window does have atributes viewScale and viewPos though. Although they aren't designed quite for this purpose I think you could use viewPos to shift the origin.
Jon

Python Matplotlib MouseEvent xy vs. xydata

I am working on a project to make a mouse click interactive pixel map (created with pyplot) using Python 3.4 and Matplotlib 1.4.3. I am using the matplotlib.backend_bases.MouseEvent class to make my figure interactive. I'm just getting started, and so far I have:
# Define an on_click() function that will print event data upon mouseclick
def on_click(event):
"""Print event data on mouseclick"""
print(event)
When I click on the figure, here's the kind of output I get:
MPL MouseEvent: xy=(289,265) xydata=(24.5956632653,21.9489795918) button=1 dblclick=False inaxes=Axes(0.141923,0.1;0.603077x0.8)
Can anyone tell me what the xy part means? It's a 50x50 pixel map, so the xydata is the pixel position of the mouse click.
It is the position from left and bottom of canvas, respectively.
Here is the documentation:
the following attributes
x- x position - pixels from left of canvas
y- y position - pixels from bottom of canvas
canvas- the FigureCanvas instance generating the event

Categories

Resources