[vtkusers] Dragging an object in the x-y plane

Dov Grobgeld dov.grobgeld at gmail.com
Fri Apr 11 08:40:35 EDT 2014


Hi David,

There is still something fishy going on.

While looking at my scene straight from above (the initial view) I
calculated the display Z as you said by doing:

Z = (surface - near)/(far - near)

and for worldSurface=0, I get the value approx displayZ=0.43. For an
arbitrary x,y I then call the display to world transformation in your
previous email, and I get e.g.:

Display: (303, 298, 0.434) →  World: (0.007, -0.005, 0.272 1.0)

but the worldZ is different from worldSurface=0! Why? I expected a round
trip.

If I now zoom in with the mousewheel (thus I'm still looking from the
negative z-direction) and press the mouse button and make another
calculation I get:

Display: (300 297 0.426) → World: (0.000 -0.000 0.639 1.0)

I then get a different value for worldZ. I still expected to get
worldSurface=0.

Is this a bug, or am I doing something wrong?

Here the functions (methods):

def DisplayToWorld(self, XYZ):
  """Translate a display XYZ coordinate to a world XYZ coordinate"""
  self.renderer.SetDisplayPoint(*XYZ)
  self.renderer.DisplayToWorld()
  worldPt = self.renderer.GetWorldPoint()
  print 'DisplayToWorld:',XYZ,'->',worldPt
  return worldPt[0]/worldPt[3], worldPt[1]/worldPt[3], worldPt[2]/worldPt[3]
def WorldZToDisplayZ(self, displayXY, worldZ=0):
  """Given a display coordinate displayXY and a worldZ coordinate,
return the corresponding displayZ coordinate"""
  wzNear = self.DisplayToWorld(list(displayXY) + [0])[2]
  wzFar = self.DisplayToWorld(list(displayXY) + [1])[2]
  return (worldZ-wzNear)/(wzFar-wzNear)

Thanks!
Dov


On Fri, Apr 11, 2014 at 1:08 AM, David Gobbi <david.gobbi at gmail.com> wrote:

> I should add a bit more explanation to my last email...
>
> When you move a 3D object with the mouse, you usually want
> the exact point on the surface of the object that you pick to be
> the point that moves with the mouse.  This means that the
> "constraint plane" that you want to use for the motion is the plane
> that:
> 1) contains all the vectors that describe allowed directions of motion, and
> 2) contains the point on the object that you want to move with the mouse
>
> In order for the interaction to be intuitive, it is not good enough to use
> just any point within the object.  It is necessary to use the point on
> the closest surface of the object.
>
>    David
>
>
> On Thu, Apr 10, 2014 at 3:45 PM, David Gobbi <david.gobbi at gmail.com>
> wrote:
> > Hi Dov,
> >
> > The DisplayToWorld transformation definitely takes the zoom factor
> > into account.  The WorldToDisplay and DisplayToWorld methods are used
> > throughout VTK: in the picking, in the interaction, and in the
> > rendering.  If they didn't work, then neither would VTK.
> >
> > The only thing in your code that looks questionable to me is that you
> > always assume that you world coordinate has Z=0.  Your objects are
> > not two dimensional, so obviously when you click on them the "pick"
> > position (in world coordinates) will not have Z=0, since the surface
> > of the object lies above Z=0.  I believe that the problems that you
> > are seeing are due to parallax: the motion at the Z=0 plane is dx,
> > but the motion at the surface of your object is in fact slightly higher
> > due to perspective.
> >
> > Instead of using Z=0, you should use the actual Z of the surface of
> > the object under the cursor.
> >
> >   David
> >
> > On Thu, Apr 10, 2014 at 1:29 AM, Dov Grobgeld <dov.grobgeld at gmail.com>
> wrote:
> >> Hi David,
> >>
> >> Though I suspected that the errors are negligible, I changed the code to
> >> remember the coordinate at the point of the picking and then translate
> >> relative to it. As I expected there was no noticeable difference. The
> >> problem at high zooms remain. It appears like the current zoom factor
> is not
> >> taken properly into account the DisplayToWorld transformation. Do you
> have
> >> any idea of what is wrong?
> >>
> >> Thanks,
> >> Dov
> >>
> >>
> >>
> >>
> >> On Thu, Apr 10, 2014 at 12:34 AM, David Gobbi <david.gobbi at gmail.com>
> wrote:
> >>>
> >>> Hi Dov,
> >>>
> >>> I took a quick look at your code, and I notice that on every MouseMove
> >>> you compute the dx,dy since the last MouseMove.  I advise that you do
> >>> not do this, because it leads to the accumulation of errors.  Instead,
> >>> on the ButtonDown, you should save the Display and World coordinates
> >>> (i.e. the coordinates at which the drag action started).  Then, in
> >>> MouseMove, you should do all your offset calculations relative to this
> >>> start position, _not_ relative to the previous MouseMove.  I.e. always
> >>> compute dx,dy relative to the position at the start of the drag.
> >>>
> >>>   David
> >>>
> >>> On Wed, Apr 9, 2014 at 2:28 PM, Dov Grobgeld <dov.grobgeld at gmail.com>
> >>> wrote:
> >>> > Thanks David. With your help I almost solved the interaction
> problem. My
> >>> > resulting example creates a board with three pieces on it that may be
> >>> > moved
> >>> > around with the right mouse button. The example may be found here:
> >>> >
> >>> > https://gist.github.com/dov/10310484
> >>> >
> >>> > It gives a very intuitive feeling for moving the pieces around on the
> >>> > board
> >>> > no matter how the board is rotated. But there is still a dragging
> >>> > problem at
> >>> > high zoom ins. Then the pieces don't follow the mouse anymore. I'm
> still
> >>> > at
> >>> > lost why his happens.
> >>> >
> >>> > Feel free to add this example to the vtk example programs.
> >>> >
> >>> > Regards,
> >>> > Dov
> >>> >
> >>> >
> >>> >
> >>> > On Wed, Apr 9, 2014 at 12:36 AM, David Gobbi <david.gobbi at gmail.com>
> >>> > wrote:
> >>> >>
> >>> >> Hi Dov,
> >>> >>
> >>> >> When you do the Display-to-World, what are you using as the input
> "Z"
> >>> >> display coordinate? Really, I don't think I understand your
> situation.
> >>> >>
> >>> >> Generally, if you know that your objects are constrained to move
> >>> >> within a certain plane, you should do the following:
> >>> >>
> >>> >> Let X,Y be the "display" coordinates, in pixel units.
> >>> >> Let Z be the display "depth", with a range of [0,1].
> >>> >>
> >>> >> Convert display coordinate (X, Y, 0.0) to world coordinate (x_near,
> >>> >> y_near, z_near)
> >>> >> Convert display coordinate (X, Y, 1.0) to world coordinate (x_far,
> >>> >> y_far,
> >>> >> z_far)
> >>> >>
> >>> >> Now "far" and "near" define the two ends of a line segment in world
> >>> >> coordinates.  These are where the view ray intersects the near and
> far
> >>> >> clipping planes for the vtkCamera.
> >>> >>
> >>> >> At some point along the segment between "near" and "far", the
> segment
> >>> >> will intersect your constraint plane.  Obviously it does not have to
> >>> >> be a plane, it can be whatever kind of constraint surface you want.
> >>> >> Let's call this intersection point "surface" because it lies on the
> >>> >> constraint surface.
> >>> >>
> >>> >> So now you have three points in world coordinates: near, surface,
> and
> >>> >> far.  Use Pythagoras to compute:
> >>> >>
> >>> >> Z = (surface - near)/(far - near)
> >>> >>
> >>> >> Now Z is the depth at which the view ray at (X,Y) intersects your
> >>> >> constraint surface.  Of course, maybe you don't need to compute "Z"
> at
> >>> >> all, maybe you can just leave the surface intersection point in
> world
> >>> >> coordinates.
> >>> >>
> >>> >> I don't know if VTK has any special functions to do this, but even
> if
> >>> >> it did, I probably wouldn't use them.  I always write my interaction
> >>> >> code by thinking about how the view ray intersects my world space,
> and
> >>> >> then by applying a constraint to achieve the desired 2D-to-3D
> >>> >> coordinate conversion (or vice-versa).
> >>> >>
> >>> >>   David
> >>> >>
> >>> >>
> >>> >>
> >>> >>
> >>> >>
> >>> >>
> >>> >> On Tue, Apr 8, 2014 at 2:48 PM, Dov Grobgeld <
> dov.grobgeld at gmail.com>
> >>> >> wrote:
> >>> >> > Thanks David,
> >>> >> >
> >>> >> > I got it to work perfectly as long as I'm looking at the scene
> from
> >>> >> > the
> >>> >> > top.
> >>> >> > But when i rotate the scene, e.g. tilt it forward around the
> x-axis,
> >>> >> > then
> >>> >> > the dragging of the pieces lags behind the mouse. Geometrically I
> >>> >> > somehow
> >>> >> > understand why, as I'm constraining to only move the piece in the
> x-y
> >>> >> > plane
> >>> >> > and the Display2World transformation is also returning a
> z-component
> >>> >> > that
> >>> >> > I'm ignoring. Is there a shortcut in vtk to do the necessary z to
> x,y
> >>> >> > projections, or should i just figure it out on my own? Again, my
> >>> >> > requirement
> >>> >> > is that the mouse should stay around the same position on the
> piece,
> >>> >> > as
> >>> >> > I'm
> >>> >> > moving it around.
> >>> >> >
> >>> >> > Regards,
> >>> >> > Dov
> >>> >> >
> >>> >> >
> >>> >> >
> >>> >> > On Tue, Apr 8, 2014 at 11:19 PM, David Gobbi <
> david.gobbi at gmail.com>
> >>> >> > wrote:
> >>> >> >>
> >>> >> >> Hi Dov,
> >>> >> >>
> >>> >> >> I use a function like this:
> >>> >> >>
> >>> >> >> void DisplayToWorld(vtkRenderer *renderer,
> >>> >> >>   double x, double y, double z, // window coordinates (the input)
> >>> >> >>   double world[3]) // world coordinates (the output)
> >>> >> >> {
> >>> >> >>   // Use the vtkViewport interterface for conversions.
> >>> >> >>   renderer->SetDisplayPoint(x, y, z);
> >>> >> >>   renderer->DisplayToWorld();
> >>> >> >>   double hcoord[4];
> >>> >> >>   renderer->GetWorldPoint(hcoord);
> >>> >> >>   world[0] = hcoord[0]/hcoord[3];
> >>> >> >>   world[1] = hcoord[1]/hcoord[3];
> >>> >> >>   world[2] = hcoord[2]/hcoord[3];
> >>> >> >> }
> >>> >> >>
> >>> >> >> It is not enough to have just the xy window coordinates.  You
> also
> >>> >> >> need a z window coordinate, which is a depth value in the range
> >>> >> >> [0,1].
> >>> >> >> Usually you get the depth from the pick.
> >>> >> >>
> >>> >> >>   David
> >>> >> >>
> >>> >> >>
> >>> >> >> On Tue, Apr 8, 2014 at 2:03 PM, Dov Grobgeld
> >>> >> >> <dov.grobgeld at gmail.com>
> >>> >> >> wrote:
> >>> >> >> > I'm trying to create a toy x-y board which has pieces,
> realized as
> >>> >> >> > Actors,
> >>> >> >> > that I can drag around in the x-y plane. Through the
> vtkPicker() I
> >>> >> >> > have
> >>> >> >> > figured out how to choose a piece, and I can get the render
> window
> >>> >> >> > coordinates through GetInteractor().GetEventPosition().
> Further,
> >>> >> >> > if I
> >>> >> >> > now
> >>> >> >> > move the mouse I can calculate a Dx,Dy shift in the window
> >>> >> >> > coordinate.
> >>> >> >> > But I
> >>> >> >> > would now like to translate the Window Dx,Dy to an Actor Dx,Dy
> >>> >> >> > shift.
> >>> >> >> > I.e. I
> >>> >> >> > would like to take a two pairs of xy coordinates in window
> >>> >> >> > coordinates
> >>> >> >> > and
> >>> >> >> > calculate their respective positions in actor coordinates,
> >>> >> >> > according
> >>> >> >> > to
> >>> >> >> > the
> >>> >> >> > current actor to dispay matrix. How can I do that?
> >>> >> >> >
> >>> >> >> > Thanks in advance!
> >>> >> >> > Dov
> >>> >> >
> >>> >> >
> >>> >
> >>> >
> >>
> >>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.vtk.org/pipermail/vtkusers/attachments/20140411/6adbc912/attachment.html>


More information about the vtkusers mailing list