# Re: [pyqtgraph] Picking a point in 3D

```Thank you so much for posting this. i was struggling with this for a while
and your solution really helped me! I hope this gets implemented into some
version of pyqtgraph - it works quite well!```
```
m.e.

On Thursday, 19 May 2016 12:05:14 UTC+2, B. Oytun Peksel wrote:
>
> Well I realize now even posting a question makes your understanding
> boost.I solved the problem couple of hours later. It works very good so far
>
> def mPosition(self):
>         #This function is called by a mouse event
>         ## Get mouse coordinates saved when the mouse is clicked( incase
> dragging)
>         mx = self._downpos.x()
>         my = self._downpos.y()
>         self.Candidates = [] #Initiate a list for storing indices of
> picked points
>         #Get height and width of 2D Viewport space
>         view_w = self.width()
>         view_h = self.height()
>         #Convert pixel values to normalized coordinates
>         x = 2.0 * mx / view_w - 1.0
>         y = 1.0 - (2.0 * my / view_h)
>         # Convert projection and view matrix to numpy types and inverse
> them
>         PMi = self.projectionMatrix().inverted()[0]
>         # PMi = numpy.matrix([PMi[0:4],
>         #                    PMi[4:8],
>         #                    PMi[8:12],
>         #                    PMi[12:16]])
>         VMi = self.viewMatrix().inverted()[0]
>         # VMi = numpy.matrix([VMi[0:4],
>         #                    VMi[4:8],
>         #                    VMi[8:12],
>         #                    VMi[12:16]])
>         #Move to clip coordinates by chosing z= -1 and w 1 (Dont
> understand this part)
>         # Q1: Why are we picking arbitrary -1 for z?
>         ray_clip = QtGui.QVector4D(x, y, -1.0, 1.0) # get transpose for
> matrix multiplication
>         # Q2 = Clip space should clip some of the scene depending on the
> zoom. How is it done? Is it implicit
>         # in the transformation matrices?
>         # Convert to eye space by view matrix
>         ray_eye = PMi * ray_clip
>         ray_eye.setZ(-1)
>         ray_eye.setW(0)
>         #Convert to world coordinates
>         ray_world = VMi * ray_eye
>         ray_world = QtGui.QVector3D(ray_world.x(), ray_world.y(),
> ray_world.z()) # get transpose for matrix multiplication
>         ray_world.normalize()
>         #ray_world = ray_world / numpy.linalg.norm(ray_world) # normalize
> to get the ray
>         # Q3: Since we normalize this vector, does it mean the values are
> a b c values of a ray definition in
>         # linear algebra such as z = ax+by+c
>         # Now I 'll use the ray intersection with spheres. I assume every
> point is a sphere with a radius
> scroll down to spehere intersection
>         O = numpy.matrix(self.cameraPosition())  # camera position should
> be starting point of the ray
>         ray_world = numpy.matrix([ray_world.x(), ray_world.y(),
> ray_world.z()])
>         # Q4: Is this approach correct? Is starting point really the
> camera coordinates obtained like this?
>         print O, ray_world
>         for i, C in enumerate(self.Poss): # Iterate over all points
>             OC = O - C
>             b = numpy.inner(ray_world, OC)
>             b = b.item(0)
>             c = numpy.inner(OC, OC)
>             #Q5: When the plot function is called with pxMode = False the
> sizes should reflect the size of point
>             #dots in world coordinates. So I assumed they were the
> diameter of the spheres. Is this correct? Otherwise how do I reach the
>             #diameter of spheres in terms of world coordinates?
>             c = c.item(0) - (self.Sizes[i]/2)**2
> #numpy.square((self.Sizes[i]))
>             bsqr = numpy.square(b)
>             if (bsqr - c) >= 0: # means intersection
>                 self.Candidates.append(self.GlobalInds[i])
>
>         print self.Candidates
>
>
>
> On Thursday, May 19, 2016 at 9:00:29 AM UTC+2, B. Oytun Peksel wrote:
>>
>> First of all I would like to thank Bi Ge for his/her help. I could not
>> make it work so I tried to find a different approach to the problem. I
>> think it is important we have alternatives cause this will be a important
>> function for pyqtgraph development.
>>
>> So instead of projecting all points to the 2D viewport space I took the
>> http://antongerdelan.net/opengl/raycasting.html
>>
>> My questions are embedded in the comments in the code as Q1..Q5 in the
>> method call mPosition. Please scroll down to see it. it is the last method.
>>
>>
>> from PySide import QtCore, QtGui
>> import pyqtgraph.opengl as gl
>> import numpy
>>
>>
>> class PlotObject(gl.GLViewWidget):
>>     """ Override GLViewWidget with enhanced behavior
>>
>>     """
>>     #: Fired in update() method to synchronize listeners.
>>     #sigUpdate = QtCore.Signal(float, float)
>>     App = None
>>
>>     def __init__(self, app=None):
>>
>>         if self.App is None:
>>             if app is not None:
>>                 self.App = app
>>             else:
>>                 self.App = QtGui.QApplication([])
>>         super(PlotObject,self).__init__()
>>         self.Gridxy = gl.GLGridItem()
>>         self.Gridyz = gl.GLGridItem()
>>         self.Gridxz = gl.GLGridItem()
>>         self.Axes = gl.GLAxisItem()
>>         self.Gridxy.setSize(6000,2000,3)
>>         self.Gridxy.setSpacing(200,200,0)
>>         self.Gridxy.translate(3000, 0, 0)
>>
>>         self.Gridyz.setSize(1800,2000,3)
>>         self.Gridyz.setSpacing(200,200,0)
>>         self.Gridyz.translate(900, 0, 0)
>>         self.Gridyz.rotate(-90, 0, 1, 0)
>>
>>
>>         self.Gridxz.setSize(6000,2000,3)
>>         self.Gridxz.setSpacing(200,200,0)
>>         self.Gridxz.translate(3000, -1000, 0)
>>         self.Gridxz.rotate(-90, 1, 0, 0)
>>         self.Poss = []
>>
>>         self.Plot = gl.GLScatterPlotItem()
>>
>>         self._downpos = []
>>
>>         #self.sigUpdate.connect(self.rayCast)
>>         self.setWindowTitle('Center of Gravity of Parts')
>>
>>     def mousePressEvent(self, ev):
>>         """ Store the position of the mouse press for later use.
>>
>>         """
>>         super(PlotObject, self).mousePressEvent(ev)
>>         self._downpos = self.mousePos
>>
>>     def mouseReleaseEvent(self, ev):
>>         """ Allow for single click to move and right click for context
>>
>>         Also emits a sigUpdate to refresh listeners.
>>         """
>>         super(PlotObject, self).mouseReleaseEvent(ev)
>>         if self._downpos == ev.pos():
>>             x = ev.pos().x()
>>             y = ev.pos().y()
>>             if ev.button() == 2 :
>>                 self.mPosition()
>>             elif ev.button() == 1:
>>                 x = x - self.width() / 2
>>                 y = y - self.height() / 2
>>                 #self.pan(-x, -y, 0, relative=True)
>>                 print self.opts['center']
>>                 print x,y
>>         self._prev_zoom_pos = None
>>         self._prev_pan_pos = None
>>
>>
>>     def mouseMoveEvent(self, ev):
>>         """ Allow Shift to Move and Ctrl to Pan.
>>
>>         """
>>         shift = ev.modifiers() & QtCore.Qt.ShiftModifier
>>         ctrl = ev.modifiers() & QtCore.Qt.ControlModifier
>>         if shift:
>>             y = ev.pos().y()
>>             if not hasattr(self, '_prev_zoom_pos') or not
>> self._prev_zoom_pos:
>>                 self._prev_zoom_pos = y
>>                 return
>>             dy = y - self._prev_zoom_pos
>>             def delta():
>>                 return -dy * 5
>>             ev.delta = delta
>>             self._prev_zoom_pos = y
>>             self.wheelEvent(ev)
>>         elif ctrl:
>>             pos = ev.pos().x(), ev.pos().y()
>>             if not hasattr(self, '_prev_pan_pos') or not
>> self._prev_pan_pos:
>>                 self._prev_pan_pos = pos
>>                 return
>>             dx = pos[0] - self._prev_pan_pos[0]
>>             dy = pos[1] - self._prev_pan_pos[1]
>>             self.pan(dx, dy, 0, relative=True)
>>             self._prev_pan_pos = pos
>>         else:
>>             super(PlotObject, self).mouseMoveEvent(ev)
>>     def plotGLPlot(self, objs):
>>         poss = numpy.array([0, 0, 0])
>>         self.Poss = []
>>         self.GlobalInds = []
>>         weights = numpy.array(0, dtype=float)
>>         def pswc (x) : return 10 * x**0.25 #pseudoweight calculation with
>> exponential scaling
>>         for obj in objs:
>>             for i,cogs in enumerate(obj.CoG):
>>                 for cog in cogs:
>>                     #cog[1] = 0
>>                     if obj.PieceWeight[i]:
>>                         poss = numpy.vstack([poss,numpy.asarray(cog.T)])
>>                         self.Poss.append(numpy.matrix(cog.T)) # for
>> picking stuff
>>                         self.GlobalInds.append(obj.Index[i])
>>                         pw = pswc(obj.PieceWeight[i])
>>                         weights = numpy.append(weights, pw)
>>
>>
>>
>>         maxw = max(weights)
>>         threshold = numpy.mean(weights)
>>         self.Colors = numpy.empty([len(weights),4])
>>         for i, pw in enumerate(weights):
>>             if pw <= threshold:
>>                 c = pw / maxw
>>                 self.Colors[i] = numpy.array([c,1,0,0.7])
>>             else:
>>                 c = 1 - pw / maxw
>>                 self.Colors[i] = numpy.array([1,c,0,0.7])
>>
>>         self.removeItem(self.Plot)
>>         self.Plot = gl.GLScatterPlotItem()
>>         self.Plot.setData(pos=poss, size=weights, color=self.Colors,
>> pxMode=False)
>>         self.Sizes = weights
>>         self.show()
>>
>>     def mPosition(self):
>>         #This function is called by a mouse event
>>         ## Get mouse coordinates saved when the mouse is clicked( incase
>> dragging)
>>         mx = self._downpos.x()
>>         my = self._downpos.y()
>>         self.Candidates = [] #Initiate a list for storing indices of
>> picked points
>>         #Get height and width of 2D Viewport space
>>         view_w = self.width()
>>         view_h = self.height()
>>         #Convert pixel values to normalized coordinates
>>         x = 2.0 * mx / view_w - 1.0
>>         y = 1.0 - (2.0 * my / view_h)
>>         # Convert projection and view matrix to numpy types and inverse
>> them
>>         PM = numpy.matrix([self.projectionMatrix().data()[0:4],
>>                            self.projectionMatrix().data()[4:8],
>>                            self.projectionMatrix().data()[8:12],
>>                            self.projectionMatrix().data()[12:16]])
>>         PMi = numpy.linalg.inv(PM)
>>         VM = numpy.matrix([self.viewMatrix().data()[0:4],
>>                            self.viewMatrix().data()[4:8],
>>                            self.viewMatrix().data()[8:12],
>>                            self.viewMatrix().data()[12:16]])
>>         VMi = numpy.linalg.inv(VM)
>>         #Move to clip coordinates by chosing z= -1 and w 1 (Dont
>> understand this part)
>>         # Q1: Why are we picking arbitrary -1 for z?
>>         ray_clip = numpy.matrix([x, y, -1.0, 1.0]).T # get transpose for
>> matrix multiplication
>>         # Q2 = Clip space should clip some of the scene depending on the
>> zoom. How is it done? Is it implicit
>>         # in the transformation matrices?
>>         # Convert to eye space by view matrix
>>         ray_eye = PMi * ray_clip
>>         ray_eye[2] = -1
>>         ray_eye[3] = 0
>>         #Convert to world coordinates
>>         ray_world = VMi * ray_eye
>>         ray_world = ray_world[0:3].T # get transpose for matrix
>> multiplication
>>         ray_world = ray_world / numpy.linalg.norm(ray_world) # normalize
>> to get the ray
>>         # Q3: Since we normalize this vector, does it mean the values
>> are a b c values of a ray definition in
>>         # linear algebra such as z = ax+by+c
>>         # Now I 'll use the ray intersection with spheres. I assume every
>> point is a sphere with a radius
>> scroll down to spehere intersection
>>         O = numpy.matrix(self.cameraPosition())  # camera position should
>> be starting point of the ray
>>         # Q4: Is this approach correct? Is starting point really the
>> camera coordinates obtained like this?
>>         print O, ray_world
>>         for i, C in enumerate(self.Poss): # Iterate over all points
>>             OC = O - C
>>             b = numpy.inner(ray_world, OC)
>>             b = b.item(0)
>>             c = numpy.inner(OC, OC)
>>             #Q5: When the plot function is called with pxMode = False
>> the sizes should reflect the size of point
>>             #dots in world coordinates. So I assumed they were the
>> diameter of the spheres. Is this correct? Otherwise how do I reach the
>>             #diameter of spheres in terms of world coordinates?
>>             c = c.item(0) - numpy.square((self.Sizes[i] / 2 ))
>>             bsqr = numpy.square(b)
>>             if (bsqr - c) >= 0: # means intersection
>>                 self.Candidates.append(self.GlobalInds[i])
>>
>>         print self.Candidates
>>
>>
>>
>>
>>
>>
>>
>> On Monday, May 16, 2016 at 11:51:22 PM UTC+2, Bi Ge wrote:
>>>
>>> Oops, WorldView is an extended class of opelgl.GLViewWidget, the
>>> definition is put below at the end of this thread.
>>>
>>> " It always gives me the same indice wherever I click. " What exactly
>>> do you mean the same indice? The projection matrix and view matrix simply
>>> reflects the current position/view of your view point, it has nothing to do
>>> with where you click. Yes the projected_array shouldn't contain any value
>>> greater than 1.
>>>
>>> Note I don't own any rights to the WorldView code:
>>>
>>> class WorldView(gl.GLViewWidget):
>>>     def __init__(self, parent=None):
>>>         global ShareWidget
>>>
>>>         if ShareWidget is None:
>>>             # create a dummy widget to allow sharing objects
>>>             # (textures, shaders, etc) between views
>>>             ShareWidget = QtOpenGL.QGLWidget()
>>>
>>>         QtOpenGL.QGLWidget.__init__(self, parent, ShareWidget)
>>>
>>>         self.setFocusPolicy(QtCore.Qt.ClickFocus)
>>>
>>>         self.opts = {
>>>             # will always appear at the center of the widget
>>>             'center': Vector(0, 0, 0),
>>>             # distance of camera from center
>>>             'distance': 10.0,
>>>             # horizontal field of view in degrees
>>>             'fov':  60,
>>>             # camera's angle of elevation in degrees
>>>             'elevation':  30,
>>>             # camera's azimuthal angle in degrees
>>>             # (rotation around z-axis 0 points along x-axis)
>>>             'azimuth': 45,
>>>             # glViewport params; None == whole widget
>>>             'viewport': None,
>>>         }
>>>         self.setBackgroundColor('k')
>>>         self.items = []
>>>         self.noRepeatKeys = [QtCore.Qt.Key_Right, QtCore.Qt.Key_Left,
>>>                              QtCore.Qt.Key_Up, QtCore.Qt.Key_Down,
>>>                              QtCore.Qt.Key_PageUp,
>>> QtCore.Qt.Key_PageDown]
>>>         self.keysPressed = {}
>>>         self.keyTimer = QtCore.QTimer()
>>>         self.keyTimer.timeout.connect(self.evalKeyState)
>>>
>>>         self.makeCurrent()
>>>
>>>         self.ray = QtGui.QVector3D(0, 0, 0)
>>>         self.select = False
>>>
>>>     def mousePressEvent(self, event):
>>>         print ("Pressed button", event.button(), "at", event.pos())
>>>
>>>         self.mousePos = event.pos()
>>>         if event.button() == 2:
>>>             self.select = True
>>>         else:
>>>             self.select = False
>>>         print (self.itemsAt((self.mousePos.x(), self.mousePos.y(), 3,
>>> 3)))
>>>
>>>
>>> On Mon, May 16, 2016 at 7:42 AM, B. Oytun Peksel <oytun....@gmail.com>
>>> wrote:
>>>
>>>> Ok! I understand what you have done now. Apart from one thing.
>>>>
>>>> w = WorldView()
>>>>
>>>> Don't know what this is and could not find anything googling. When I
>>>> get projectionMatrix() and ViewMatrix from pyqtgraph.opengl.
>>>> GLViewWidget
>>>> I get the wrong result. It always gives me the same indice wherever I
>>>> click. projected_array contains values greater than 1 which I assume
>>>> should
>>>> not happen.
>>>>
>>>> So the key question is what is WorldView?
>>>>
>>>> On Monday, May 16, 2016 at 11:25:06 AM UTC+2, Bi Ge wrote:
>>>>>
>>>>> b contains the coordinates (positions) of the points you want to
>>>>> render, i.e. when you call:
>>>>> w = WorldView()
>>>>> sp1 = gl.GLScatterPlotItem(pos=b, size=1)
>>>>>
>>>>> Inside the for loop I just iterate through every point in b, calculate
>>>>> their corresponding positions on the screen (stored in projected_array)
>>>>> using the projection matrix and choose the "selected point" based on
>>>>> finding the smallest distance between projected point on the screen and
>>>>> the
>>>>> pixel clicked by the mouse, thus:
>>>>>         # find distance between mouse and points on screen
>>>>>         projected_array[:, 0] = (projected_array[:, 0] -
>>>>>                                  (mouse_x/view_w))
>>>>>         projected_array[:, 1] = (projected_array[:, 1] -
>>>>>                                  (mouse_y/view_h))
>>>>>         distance_array = np.power(np.power(projected_array[:, 0], 2) +
>>>>>                                   np.power(projected_array[:, 1], 2),
>>>>> 0.5)
>>>>>
>>>>>         min_index = np.nanargmin(distance_array)
>>>>>
>>>>> On Mon, May 16, 2016 at 3:51 AM, B. Oytun Peksel <oytun....@gmail.com>
>>>>> wrote:
>>>>>
>>>>>> Thanks for the response! I have one question. I don't understand what
>>>>>> b is. What do you mean by raw coordinates? Can you explain what you are
>>>>>> doing inside the for loop?
>>>>>>
>>>>>>
>>>>>> On Thursday, May 12, 2016 at 4:41:47 PM UTC+2, Bi Ge wrote:
>>>>>>
>>>>>>> "
>>>>>>> `
>>>>>>>        # w = WorldView()
>>>>>>>         __WIDTH = 512
>>>>>>>         __HEIGHT = 424
>>>>>>>         m = w.projectionMatrix() * w.viewMatrix()
>>>>>>>         projected_array = np.zeros((__WIDTH * __HEIGHT, 2))
>>>>>>>         view_w = w.width()
>>>>>>>         view_h = w.height()
>>>>>>>         mouse_x = w.mousePos.x()
>>>>>>>         mouse_y = w.mousePos.y()
>>>>>>>         # b array contains the raw coordinates of all the points on
>>>>>>> screen
>>>>>>>         for i in xrange(0, __WIDTH, step):
>>>>>>>             for j in xrange(0, __HEIGHT, step):
>>>>>>>                 pt = m.map(QtGui.QVector3D(b[j*__WIDTH+i, 0],
>>>>>>>                                            b[j*__WIDTH+i, 1],
>>>>>>>                                            b[j*__WIDTH+i, 2]))
>>>>>>>                 # origin range [-1, 1]
>>>>>>>                 projected_array[j*__WIDTH+i, 0] = (pt.x() + 1)/2
>>>>>>>                 projected_array[j*__WIDTH+i, 1] = (- pt.y() + 1)/2
>>>>>>>
>>>>>>>
>>>>>>>         projected_array[:, 0] = (projected_array[:, 0] -
>>>>>>>                                  (mouse_x/view_w))
>>>>>>>         projected_array[:, 1] = (projected_array[:, 1] -
>>>>>>>                                  (mouse_y/view_h))
>>>>>>>         distance_array = np.power(np.power(projected_array[:, 0], 2)
>>>>>>> +
>>>>>>>                                   np.power(projected_array[:, 1],
>>>>>>> 2), 0.5)
>>>>>>>
>>>>>>>         min_index = np.nanargmin(distance_array)
>>>>>>>         # mark the selected point on screen with a big sphere
>>>>>>>         sp2.setData(pos=b[min_index, :], size=100)
>>>>>>> `
>>>>>>> "
>>>>>>> Should be self-explanatory, we are basically projecting every point
>>>>>>> onto the screen to see which one is the closest to the mouse (slow;
>>>>>>> pretty
>>>>>>> sure OpenGL has built-in way of doing this) let me know if you have any
>>>>>>> questions.
>>>>>>>
>>>>>>> Bi
>>>>>>>
>>>>>>> On Thu, May 12, 2016 at 6:14 AM, B. Oytun Peksel <
>>>>>>> oytun....@gmail.com> wrote:
>>>>>>>
>>>>>>>> BiGe, can you please post your solution? I am struggling with the
>>>>>>>> same thing!
>>>>>>>>
>>>>>>>>
>>>>>>>> On Sunday, June 21, 2015 at 7:12:45 AM UTC+2, Bi Ge wrote:
>>>>>>>>>
>>>>>>>>> Found out why my selected point is jumping all around the screen.
>>>>>>>>>
>>>>>>>>> When applying
>>>>>>>>> pt = m.map(QtGui.QVector3D(x,y,z))
>>>>>>>>> as Luke pointed out the range for x and y is [-1, 1] but unlike
>>>>>>>>> the mouse position returned by GLViewWidget, (-1, -1) is actually the
>>>>>>>>> right
>>>>>>>>> top corner.
>>>>>>>>>
>>>>>>>>> Thanks for all the help.
>>>>>>>>>
>>>>>>>>> Bi
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Saturday, June 20, 2015 at 10:23:16 PM UTC-4, Bi Ge wrote:
>>>>>>>>>>
>>>>>>>>>> I am trying to select a point already in the plot. It is true
>>>>>>>>>> that I only have the relative x and y axes but from my minimal
>>>>>>>>>> computer
>>>>>>>>>> graphics experience I assume I can either a) construct a ray based
>>>>>>>>>> on the
>>>>>>>>>> view and camera position and do a poor-man's collision detection to
>>>>>>>>>> find
>>>>>>>>>> out which point is closest to that ray. b) convert all points in the
>>>>>>>>>> scene
>>>>>>>>>> to 2D based on view and camera position and select the point closed
>>>>>>>>>> to the
>>>>>>>>>> mouse.
>>>>>>>>>>
>>>>>>>>>> Of course we will run into situations where two points in 3D
>>>>>>>>>> overlay in 2D but we are always going to select the point closer to
>>>>>>>>>> the
>>>>>>>>>> camera.
>>>>>>>>>>
>>>>>>>>>> Hopefully this cleared my question a bit.
>>>>>>>>>>
>>>>>>>>>> Bi
>>>>>>>>>>
>>>>>>>>>> On Saturday, June 20, 2015 at 9:30:31 PM UTC-4, Mathew Schwartz
>>>>>>>>>> wrote:
>>>>>>>>>>>
>>>>>>>>>>> Can you explain a bit more of what you want? If you dont want to
>>>>>>>>>>> select a point already in the plot, how do you pick a 3d point on a
>>>>>>>>>>> 2d
>>>>>>>>>>> screen, there is a third axis that you need to define how deep you
>>>>>>>>>>> want to
>>>>>>>>>>> select.
>>>>>>>>>>>
>>>>>>>>>>> On Fri, Jun 19, 2015 at 10:02 AM, Bi Ge <sean...@gmail.com>
>>>>>>>>>>> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> I've tried itemsAt but it only returns the GLScatterPlotItem
>>>>>>>>>>>> object instead of a point.
>>>>>>>>>>>>
>>>>>>>>>>>> Bi
>>>>>>>>>>>>
>>>>>>>>>>>> On Thursday, June 18, 2015 at 8:57:37 PM UTC-4, Mathew Schwartz
>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Im not exactly sure on your questions so I wont try to answer
>>>>>>>>>>>>> them, but if you are trying to pick a point, there is a method
>>>>>>>>>>>>> available
>>>>>>>>>>>>> http://www.pyqtgraph.org/documentation/3dgraphics/glviewwidget.html
>>>>>>>>>>>>>
>>>>>>>>>>>>> In that case, you dont need the 3d vector (its most likely a
>>>>>>>>>>>>> vector because it needs to point into the screen) just the 2d xy
>>>>>>>>>>>>> coordinates
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Fri, Jun 19, 2015 at 6:35 AM, Bi Ge <sean...@gmail.com>
>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi folks,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I would like to pick a point in a 3D scatter plot. I read
>>>>>>>>>>>>>> from Luke's post here:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> "
>>>>>>>>>>>>>> This version also has methods for determining the projection
>>>>>>>>>>>>>> and view matrices, which allows you to determine the
>>>>>>>>>>>>>> relationship between
>>>>>>>>>>>>>> 3D and 2D manually:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> m = glView.projectionMatrix() * glView.viewMatrix()
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> # Map 3D location to normalized device coordaintes: (-1,-1)
>>>>>>>>>>>>>> and (1,1) are opposite corners of the view
>>>>>>>>>>>>>> pt = m.map(QtGui.QVector3D(x,y,z))
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> # Inverse mapping:
>>>>>>>>>>>>>> pt = m.inverted()[0].map(QtGui.QVector3D(x,y,z))
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> "
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> My questions are:
>>>>>>>>>>>>>> 1. Does inverse mapping meaning from 2D to 3D? If so, why
>>>>>>>>>>>>>> does the map take a 3D vector when the point on screen is only
>>>>>>>>>>>>>> 2D:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> 2. After apply inverse mapping on a point on the screen, we
>>>>>>>>>>>>>> get a point(vector) in 3D and from here I just need to cast a
>>>>>>>>>>>>>> ray and find
>>>>>>>>>>>>>> where it hits the point I want to find correct?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Bi
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> --
>>>>>>>>>>>>>> You received this message because you are subscribed to the
>>>>>>>>>>>>>> To unsubscribe from this group and stop receiving emails from
>>>>>>>>>>>>>> it, send an email to pyqtgraph+...@googlegroups.com.
>>>>>>>>>>>>>> To view this discussion on the web visit
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> .
>>>>>>>>>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> --
>>>>>>>>>>>> You received this message because you are subscribed to the
>>>>>>>>>>>> To unsubscribe from this group and stop receiving emails from
>>>>>>>>>>>> it, send an email to pyqtgraph+...@googlegroups.com.
>>>>>>>>>>>> To view this discussion on the web visit
>>>>>>>>>>>>
>>>>>>>>>>>> .
>>>>>>>>>>>>
>>>>>>>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> --
>>>>>>>> You received this message because you are subscribed to a topic in
>>>>>>>> the Google Groups "pyqtgraph" group.
>>>>>>>> To unsubscribe from this topic, visit
>>>>>>>> .
>>>>>>>> To unsubscribe from this group and all its topics, send an email to
>>>>>>>> To view this discussion on the web visit
>>>>>>>>
>>>>>>>> .
>>>>>>>>
>>>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>> You received this message because you are subscribed to a topic in
>>>>>> the Google Groups "pyqtgraph" group.
>>>>>> To unsubscribe from this topic, visit
>>>>>> To unsubscribe from this group and all its topics, send an email to
>>>>>> To view this discussion on the web visit
>>>>>>
>>>>>> .
>>>>>>
>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>
>>>>>
>>>>> --
>>>> You received this message because you are subscribed to a topic in the
>>>> To unsubscribe from this topic, visit
>>>> To unsubscribe from this group and all its topics, send an email to
>>>> To view this discussion on the web visit
>>>>
>>>> .
>>>>
>>>> For more options, visit https://groups.google.com/d/optout.
>>>>
>>>
>>>

--
You received this message because you are subscribed to the Google Groups
"pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email