I’m implementing a brush tool for my VTK-based application, which has three 2D views: axial, sagittal, and coronal.
The brush works as follows: while the left mouse button is held and the mouse moves, I create a circular brush and add it to a vtkAppendPolyData. The relevant code looks like this:
auto transform = vtkSmartPointer<vtkTransform>::New();
transform->Translate(worldCoords[0], worldCoords[1], worldCoords[2]);
if (context->getDisplayType() == DisplayType::DISPLAY_2D) {
VTKDisplay2D* display2D = dynamic_cast<VTKDisplay2D*>(context);
switch (display2D->getCurrentAxis()) {
case CORONAL:
transform->RotateX(90.0);
break;
case SAGITTAL:
transform->RotateY(90.0);
break;
case AXIAL:
break;
}
}
UpdateBrushPosition(context);
auto transformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
transformFilter->SetInputConnection(brushPolyData->GetOutputPort());
transformFilter->SetTransform(transform);
transformFilter->Update();
appendPolyData->AddInputData(transformFilter->GetOutput());
This part works fine — when I print the final polygon bounds, they make sense and the geometry looks correct.
When I release the left mouse button, I use the accumulated polygons to paint the corresponding voxels in a segmentation image:
if (appendPolyData->GetNumberOfInputConnections(0) > 0) {
appendPolyData->Update();
polyDataToImageStencil->Update();
vtkImageStencilData* stencilData = polyDataToImageStencil->GetOutput();
int* extent = stencilData->GetExtent();
for (int z = extent[4]; z <= extent[5]; z++) {
for (int y = extent[2]; y <= extent[3]; y++) {
int x1, x2;
for (int iter = 0; stencilData->GetNextExtent(x1, x2, extent[0], extent[1], y, z, iter); iter++) {
for (int x = x1; x <= x2; x++) {
segmentationImage->SetScalarComponentFromDouble(x, y, z, 0, 1);
}
}
}
}
segmentationImage->Modified();
context->getWorkspaceContext()->getActiveSegmentation()->setSegmentation(segmentationImage);
context->getInteractor()->GetRenderWindow()->Render();
}
appendPolyData->RemoveAllInputs();
The problem:
The painting only works in the sagittal view. In that view, the voxels are updated correctly and the other two views also display the updated segmentation (since they share the same vtkImageData).
However, when I try painting from the axial or coronal views, the inner loop (for (int x = x1; x <= x2; x++)) never executes — meaning that GetNextExtent() returns no valid extents. You can see the behavior in this video:
I’ve read in the vtkPolyDataToImageStencil documentation that:
Warning:
If contours are provided, they must be aligned with the Z planes. Other contour orientations are not supported.
I’m wondering if this might be the issue — but it seems odd, because the axial view (which corresponds to constant Z) is actually the one where it doesn’t work.
Has anyone encountered this issue or can confirm whether the vtkPolyDataToImageStencil really requires the input polygons to be aligned with the Z plane?
Any advice or workaround would be greatly appreciated.