[vtkusers] Difficulty keeping volume within vtkBoxWidget
Zamir Khan
zkhan at modusmed.com
Fri Dec 11 09:50:51 EST 2009
Hi Jérôme,
Although this class might help with part of the problem, the most
significant source of difficulty for me was that manipulation of the box
widget did not keep the volume within the box (I wanted the volume to be
anchored to the center of the box, which I have now achieved). The
actual cropping once I had achieved this, was less of an issue. I may be
able to incorporate your class to clean up my code a bit - I'll let you
know if I succeed with that.
Thanks!
Zamir
Jérôme wrote:
> Hi,
> there is a thread that deals with this problem: look for "Creating an
> ImageData from the bounds of a PolyData".
>
> I posted a class that outputs a volume cropped from an input volume
> and the bounding box of the polydata. Maybe you can use the box widget
> to produce the cube polydata and use it as bounds. This process will
> then appears as a simple VTK pipeline in your code.
>
> HTH
> Jerome
>
>
> 2009/12/10 Zamir Khan <zkhan at modusmed.com <mailto:zkhan at modusmed.com>>
>
> I think I have found a solution to my problem and, although it
> does not feel elegant (it's actually rather ugly), I am posting
> back to the mailing list for archival purposes, in case someone
> else is trying to accomplish a similar goal.
>
> To recap: I have a volume, which I want to allow the user to
> interactively crop. So I used a vtkBoxWidget to bound the volume
> and was intending to use the bounds of the box as the cropping
> planes. The simplistic approach in my first post did not work, in
> retrospect because I was operating on a false assumption: that
> when I associated the volume actor and box widget with each other,
> they would be anchored about the center of the box widget. The
> reason I assumed this was that when I rotated the box, I saw that
> the volume rotated with it, seemingly about the center of the box.
> However, further investigation showed me that my objects were
> actually anchored to another position and that, when certain
> actions happened to the box (scaling, translation induced by
> scaling of the individual box faces), if I wanted to see my
> desired behaviour, I needed to re-position the volume to maintain
> a constant positioning between the center of the box and the volume.
>
> I have attached the callback code I used to accomplish this with
> some comments. This is the callback that gets invoked on the
> boxWidget's InteractionEvt. The objects and helper methods are
> hopefully named reasonably enough to figure out what they are/do
> (e.g. I call my vtkBoxWidget a croppingBox). It's not a pretty
> solution and I'm half-expecting a response with a much easier and
> more elegant way to do this. If so, I would love to be enlightened
> and, regardless, it's been a good learning experience =)
>
> Zamir Khan wrote:
>
> I should add: even purely scaling the box to a smaller size,
> with the
> right mouse button, will cause the volume to leave the box. It
> seems
> that they are not centered on the same point. I have verified
> that the
> volume remains in place - both position and origin remain at
> (0,0,0) -
> is it possible that the box's scaling is not centered on
> (0,0,0), even
> though it was bounded to the volume through SetProp3D()?
>
> Zamir Khan wrote:
> > Thanks for the response. I would like to continue to allow
> rotation,
> > could I perhaps apply an inverse of the box transform to its
> bounds and
> > then use that for cropping? Also, the reason that
> translation fails, I
> > believe, is that when you grow or shrink one of the faces of
> the box,
> > this appears to be a scaling & translation operation and,
> perhaps
> > because I am always negating the scaling operation in my
> transform on
> > the volume, by moving the faces of the box back and forth, I
> can get the
> > volume to leave the bounds of the box.
> >
> > I will keep trying some different solutions (unfortunately
> disabling
> > rotation is not an acceptable one for my application), but
> if anyone has
> > accomplished this task before (with or without a
> vtkBoxWidget!) -
> > example code would be much appreciated.
> >
> > Thanks,
> > Zamir
> >
> > Karthik Krishnan wrote:
> > > On Mon, Dec 7, 2009 at 5:26 PM, Zamir Khan
> <zkhan at modusmed.com <mailto:zkhan at modusmed.com>>
> <mailto:zkhan at modusmed.com <mailto:zkhan at modusmed.com>%3E>
> > <mailto:zkhan at modusmed.com <mailto:zkhan at modusmed.com>%3E>
> <mailto:zkhan at modusmed.com <mailto:zkhan at modusmed.com>%3E%3E>
> > > <mailto:zkhan at modusmed.com <mailto:zkhan at modusmed.com>%3E>
> <mailto:zkhan at modusmed.com <mailto:zkhan at modusmed.com>%3E%3E>
> <mailto:zkhan at modusmed.com <mailto:zkhan at modusmed.com>%3E%3E>
> <mailto:zkhan at modusmed.com
> <mailto:zkhan at modusmed.com>%3E%3E%3E> wrote:
> > > > Hi all,
> > > >
> > > > I have been attempting to use a vtkBoxWidget for what
> appears to be
> > > a fairly
> > > > common task: bounding and cropping a volume. My end goal
> is to have
> > > the all
> > > > user actions (translation, rotation) on the box be
> passed onto the
> > > volume
> > > > within, except for scaling. When the box is scaled, I
> need the
> > > volume within
> > > > to remain the same size, but be cropped by the planes of
> the box.
> > > >
> > > > I have been attempting to accomplish this with the
> following code (C#
> > > > snippets, using Activiz.NET personal edition):
> > > >
> > > > // this callback gets called on the vtkBoxWidget's
> (outlineBox)
> > > > InteractionEvt
> > > > private void transformCallback( vtkObject sender,
> > > vtkObjectEventArgs e
> > > > )
> > > > {
> > > > vtkTransform boxTransform = vtkTransform.New();
> > > > outlineBox.GetTransform( boxTransform );
> > > >
> > > > // remove the scaling from the transform before passing
> it on
> > > > double[] scale = boxTransform.GetScale();
> > > > boxTransform.Scale( 1.0 / scale[ 0 ], 1.0 / scale[ 1 ],
> 1.0 /
> > > > scale[ 2 ] );
> > > > volume.SetUserTransform( ( vtkLinearTransform )
> > > boxTransform );
> > > >
> > > > // crop the volume
> > > > vtkPlanes planes = vtkPlanes.New();
> > > > outlineBox.GetPlanes(planes);
> > > > double[] bounds = planes.GetPoints().GetBounds();
> > > > volumeMapper.SetCroppingRegionPlanes( bounds[ 0 ],
> bounds[ 1 ],
> > > bounds[ 2 ],
> > > > bounds[ 3 ], bounds[ 4 ], bounds[ 5 ] ); }
> > > >
> > > > Now, a few things go wrong with this (probably
> over-simplified)
> > > > implementation.
> > > >
> > > > 1) The volume does not stay within the box for all
> manipulations.
> > I have
> > > > tried various approaches to remedy this, including not
> allowing
> > > translation
> > > > on the box (which is not critical to my application),
> but even so, I
> > > have
> > > > not been able to come up with a solution that guarantees
> that the
> > volume
> > > > stays inside the box.
> > >
> > > See answer to (2) below..
> > >
> > >
> > > >
> > > > 2) The cropping does not always occur on the expected
> plane. When I
> > > take a
> > > > particular plane on the box and shrink the box w.r.t.
> that plane,
> > > especially
> > > > after having rotated the box, the volume will be
> cropped, but on it's
> > > > corresponding plane. It appears that the "bounds"
> coordinates of
> > the box
> > > > that I am passing to the mapper are not in agreement
> with the volume
> > > - am I
> > > > missing a transformation?
> > >
> > > The bounds specified via
> > > volumeMapper.SetCroppingRegionPlanes()
> > >
> > > specify an axis-aligned aligned bounding box. You mention
> below that
> > > they are out of sync after rotating the box, which is
> natural, since
> > > the box widget no longer remains axis-aligned. Disable
> rotation on it.
> > >
> > > Translation should have worked just fine.. Perhaps a bug
> in your code..
> > >
> ------------------------------------------------------------------------
> >
> > _______________________________________________
> > Powered by www.kitware.com <http://www.kitware.com>
> >
> > Visit other Kitware open-source projects at
> > http://www.kitware.com/opensource/opensource.html
> >
> > Please keep messages on-topic and check the VTK FAQ at:
> > http://www.vtk.org/Wiki/VTK_FAQ
> >
> > Follow this link to subscribe/unsubscribe:
> > http://www.vtk.org/mailman/listinfo/vtkusers
> >
> ------------------------------------------------------------------------
>
> _______________________________________________
> Powered by www.kitware.com <http://www.kitware.com>
>
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
>
> Please keep messages on-topic and check the VTK FAQ at:
> http://www.vtk.org/Wiki/VTK_FAQ
>
> Follow this link to subscribe/unsubscribe:
> http://www.vtk.org/mailman/listinfo/vtkusers
> ------------------------------------------------------------------------
>
>
>
> private void transformCallback( vtkObject sender,
> vtkObjectEventArgs e )
> {
> if( pipelineExists )
> {
> // Get the transform currently being applied to the
> cropping box
> vtkTransform boxTransform = vtkTransform.New();
> croppingBox.GetTransform( boxTransform );
>
> // Get the planes that define the faces of the
> cropping box
> vtkPlanes planes = vtkPlanes.New();
> croppingBox.GetPlanes( planes );
>
> // Apply the inverse transform to the planes, so we
> have axis-aligned planes
> vtkPoints transformedPoints = vtkPoints.New();
> boxTransform.GetInverse().TransformPoints(
> planes.GetPoints(), transformedPoints );
>
> // Remember the cropping box center before scaling
> occurred, in order to keep all other scene
> // objects anchored to the cropping box center
> double[] preScalingBoxCenter = GetBoundsCenter(
> transformedPoints.GetBounds() );
>
> // Now get the scaled the bounds of the cropping
> box, this moves the center of the box since
> // scaling is anchored to the origin, not the center
> vtkTransform scalingTransform = vtkTransform.New();
>
> double[] scale = boxTransform.GetScale();
> scalingTransform.Scale( scale[ 0 ], scale[ 1 ],
> scale[ 2 ] );
>
> vtkPoints scaledPoints = vtkPoints.New();
> scalingTransform.TransformPoints(
> transformedPoints, scaledPoints );
>
> double[] bounds = scaledPoints.GetBounds();
>
> // calculate the post-scaling center of the
> cropping box
> double[] postScalingBoxCenter = GetBoundsCenter(
> bounds );
>
> // on the first invocation only, store the vector
> relating the position of the volume
> // to the center of the cropping box. We want to
> maintain this relation at all times.
> if( null == vectorFromBoxCenter )
> {
> vectorFromBoxCenter = new double[ 3 ];
> vectorFromBoxCenter[ 0 ] =
> volume.GetPosition()[ 0 ] - postScalingBoxCenter[ 0 ];
> vectorFromBoxCenter[ 1 ] =
> volume.GetPosition()[ 1 ] - postScalingBoxCenter[ 1 ];
> vectorFromBoxCenter[ 2 ] =
> volume.GetPosition()[ 2 ] - postScalingBoxCenter[ 2 ];
> }
>
> // This transform will be passed on to the other
> scene objects, but scaling should be removed
> // since only the cropping box should be allowed to
> change size.
> boxTransform.Scale( 1.0 / scale[ 0 ], 1.0 / scale[
> 1 ], 1.0 / scale[ 2 ] );
>
> // Re-position the other scene objects relative to
> the new cropping box center
> SetScenePosition( postScalingBoxCenter[ 0 ] +
> vectorFromBoxCenter[ 0 ], postScalingBoxCenter[ 1 ] +
> vectorFromBoxCenter[ 1 ], postScalingBoxCenter[ 2 ] +
> vectorFromBoxCenter[ 2 ] );
> SetSceneOrigin( postScalingBoxCenter[ 0 ] +
> vectorFromBoxCenter[ 0 ], postScalingBoxCenter[ 1 ] +
> vectorFromBoxCenter[ 1 ], postScalingBoxCenter[ 2 ] +
> vectorFromBoxCenter[ 2 ] );
>
> // Adjust the cropping box bounds relative to the
> current cropping box center
> bounds[ 0 ] += ( preScalingBoxCenter[ 0 ] -
> postScalingBoxCenter[ 0 ] );
> bounds[ 1 ] += ( preScalingBoxCenter[ 0 ] -
> postScalingBoxCenter[ 0 ] );
> bounds[ 2 ] += ( preScalingBoxCenter[ 1 ] -
> postScalingBoxCenter[ 1 ] );
> bounds[ 3 ] += ( preScalingBoxCenter[ 1 ] -
> postScalingBoxCenter[ 1 ] );
> bounds[ 4 ] += ( preScalingBoxCenter[ 2 ] -
> postScalingBoxCenter[ 2 ] );
> bounds[ 5 ] += ( preScalingBoxCenter[ 2 ] -
> postScalingBoxCenter[ 2 ] );
>
> // Set the new cropping planes based on the
> adjusted bounds
> volumeMapper.SetCroppingRegionPlanes( bounds[ 0 ],
> bounds[ 1 ], bounds[ 2 ], bounds[ 3 ], bounds[ 4 ], bounds[ 5 ] );
>
> // Apply the cropping box transform (that has had
> scaling removed) to the other scene members
> TransformScene( boxTransform );
> }
> }
> _______________________________________________
> Powered by www.kitware.com <http://www.kitware.com>
>
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
>
> Please keep messages on-topic and check the VTK FAQ at:
> http://www.vtk.org/Wiki/VTK_FAQ
>
> Follow this link to subscribe/unsubscribe:
> http://www.vtk.org/mailman/listinfo/vtkusers
>
>
> ------------------------------------------------------------------------
More information about the vtkusers
mailing list