Get single contour from vtkPolyData

Hi!
I have vtkPolyData containing contour data for multiple slices created using vtkPolyData::SetPoints() and vtkPolyData::SetLines():

Is there a convenient way to extract a single of these contour lines (possibly without creating a copy of the data) for rendering? Best would be also as vtkPolyData.

If there is not: I know there is vtkPolyData::GetLines() and vtkCellArray::GetCellAtId(). Unfortunately, the latter only gets me vtkIdList *. How would I get vtkCellArray needed for vtkPolyData::SetLines()?

Any help is appreciated!

I want to try again / give more information / elaborate.

Currently, I am using vtkImageViewer2 to both draw an image as well as contour data:

image

What I want is to render a single contour line in accordance with the currently displayed image slice.
I also played around with AutoAdjustCameraClippingRange of the InteractorStyleImage but that didn’t work.

Is there any functionality in VTK that I could use for this purpose? Thanks

You can add clipping planes to the mapper with the AddClippingPlane() method. Two clipping planes are needed, one on each side of the contour you want to show. Once the clipping planes are added to the mapper, you can adjust the two vtkPlane objects to select different contours.

If you want to adjust the clipping planes for interactive viewing, a good way to do this is by adding an observer method (a callback) for the StartEvent of the renderer. This method would have to figure out what contour should be displayed and then set the clipping planes. By observing the StartEvent, it’s guaranteed that the clipping planes can be set before the mapper actually renders the data.

Using observers like this is an advanced topic, but there are some general observer examples on the VTK examples site (though probably none with StartEvent or clipping planes).

Thank you for your ongoing help! I understood and followed your suggestion.

I subclassed vtkCallbackCommand. Inside its overridden Execute()-function I got this far:

void HPvtkRenderCallback::Execute(
    vtkObject* caller, unsigned long eventId, void* callData
)
{
	std::cout << "Render callback" << std::endl;
	std::cout << "Event: " << vtkCommand::GetStringFromEventId(eventId) << '\n';
	auto* renderer = static_cast<vtkRenderer*>(caller);
	double d1 = renderer->GetClippingRangeExpansion();
	double d2 = renderer->GetClippingRangeExpansionMinValue();
	double d3 = renderer->GetClippingRangeExpansionMaxValue();
	vtkActorCollection* propCollection = renderer->GetActors();
	propCollection->InitTraversal();
	for (vtkIdType i = 0; i < propCollection->GetNumberOfItems(); ++i)
	{
		vtkActor* actor = propCollection->GetNextActor();
	}
}

The calIback generally works. However, now I’m having problems getting the correct actor.
With this actor, I planned on:

  1. getting the actors mapper
  2. getting both mappers clipping planes (front and back as you said)
  3. calling vtkPlane::Push(double distance) with either d1, d2 or d3 (not figured out yet)

I am using VTK-9.0, so SetObjectName()/GetObjectName() is not an option.

How do I distinguish the correct actor from others?

So you’re introspecting the renderer to find the actors? I’d recommend a more direct approach: in your callback class, you can have a list of the mappers that you want to clip (more specifically, you can use an std::vector<vtkSmartPointer<vtkMapper>>).

For setting the planes, I don’t recommend Push(). Use SetOrigin() instead.

The GetClippingRangeExpansion() method isn’t going to give you anything useful for setting the mapper clipping planes. What you need is to get a point (any point) on the image plane, in world coordinates. The “origin” points of your clipping planes will be offset from that image plane point (offset in different directions along the plane normal).

That makes more sense - especially once I render more than a single contour, I agree!

I got the origin point using vtkImageData::GetPoint(), i.e., via:

std::array<double, 3> pointPos;
m_pImageData->GetPoint(0, pointPos.data());

I set the normal of both clipping planes to (0.0, 0.0, 1.0) (z-direction)

I offset the clipping planes via:

vtkNew<vtkTransform> transform;
transform->Translate(0, 0, offsetClippingPlanes);

with offsetClippingPlanes equal to +5 and -5.

Still no clipping :slightly_frowning_face: Is the order of adding a clipping plane to the mapper and configuring the plane (origin, normal, offset) relevant?

In general, I am quite groping in the dark with debugging in VTK. Is there a way I could show the image plane and clipping planes for debug purposes?

The clipping planes need to have opposite normals, i.e. one (0, 0, -1) and the other (0, 0, +1).

For debugging, I recommend trying just one thing at a time. Start with just one clipping plane. Manually set the Origin and Normal (without using a transform). Play around with both the Normal and Origin. Once you see it clipping in a way that makes sense, you can build up the rest of the code to properly automate the clipping.

Let’s assume I have a clipping plane c at coordinates (x_c,y_c,z_c), clipping in positive z-direction, i.e., its normal is set to (0,0,1). Will primitive p, with z-coordinate z_p = z_c get clipped or not?

Maybe yes and maybe not, it depends on roundoff error. The vtkPlane’s normal and origin are converted into a glClipPlane so that the GPU can do the clipping, which is a different formulation and uses different numerical precision (single-precision float rather than double-precision float).

In any case, most floating-point math is inexact, and questions like “is the point exactly on the plane” cannot, in general, be answered with floating-point math.

Thank you! Is the entire primitive getting clipped or only parts of it? More specifically, if I have a polyline, will it get clipped entirely, once a single point is on the plane or only parts of it?

A vertex will be clipped away completely.
A line will be cut at the position where it intersects the clip plane, with part of the line remaining.