[vtkusers] Dragging an object in the x-y plane
David Gobbi
david.gobbi at gmail.com
Fri Apr 11 09:30:20 EDT 2014
Hi Dov,
Yes, that looks fishy, but I don't think that I can help you here. You will
have to do bunch of mini-experiments until you identify the location of
the problem.
For example, if display (303, 298, 0.434) gives you world z=0.272,
did you also try e.g. display (0, 0, 0.434) to verify that it also gives
the same world z? Just keep doing checks like this to verify that
each little piece of the code is behaving the way that you expect.
David
On Fri, Apr 11, 2014 at 6:40 AM, Dov Grobgeld <dov.grobgeld at gmail.com> wrote:
> 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
>> >>> >> >
>> >>> >> >
>> >>> >
>> >>> >
>> >>
>> >>
>
>
More information about the vtkusers
mailing list