Since moving to 6.2.0, Plot On Sorted Lines crashes on our slice output. It happens whenever the input segments aren’t listed in the order they connect. The script below crashes on 6.2.0 and prints 1 block(s), 5 points on 6.1.1:
from paraview.simple import PlotOnSortedLines, ProgrammableSource, servermanager
SEGMENTS = """
from vtkmodules.vtkCommonCore import vtkPoints
from vtkmodules.vtkCommonDataModel import vtkCellArray
points = vtkPoints()
for i in range(5):
points.InsertNextPoint(float(i), 0.0, 0.0)
lines = vtkCellArray()
for a, b in [(2, 3), (0, 1), (3, 4), (1, 2)]:
lines.InsertNextCell(2, [a, b])
output = self.GetPolyDataOutput()
output.SetPoints(points)
output.SetLines(lines)
"""
source = ProgrammableSource(OutputDataSetType="vtkPolyData", Script=SEGMENTS)
sorted_lines = PlotOnSortedLines(Input=source)
sorted_lines.UpdatePipeline()
result = servermanager.Fetch(sorted_lines)
points = 0
for i in range(result.GetNumberOfBlocks()):
points += result.GetBlock(i).GetNumberOfPoints()
print(f"{result.GetNumberOfBlocks()} block(s), {points} points")
With the segments in order, (0,1), (1,2), (2,3), (3,4), it doesn’t crash.
The crash is in the first pass of vtkPlotEdges::ConnectSegmentsWithNodes, which does ++nodeIt; nodes->RemoveItem(node); while iterating with vtk::Range. vtkCollection became a std::vector in VTK 2a47085bc3, so the erase shifts the later nodes down. The iterator then skips one, and it can run past end(). The second pass had the same problem and was fixed in d3461dbc4c. The first pass is still like this on master.
Iterating by index fixes it for us:
--- a/VTKExtensions/FiltersGeneral/vtkPlotEdges.cxx
+++ b/VTKExtensions/FiltersGeneral/vtkPlotEdges.cxx
@@ -916,28 +916,28 @@
void vtkPlotEdges::ConnectSegmentsWithNodes(vtkCollection* segments, vtkCollection* nodes)
{
Node* node = nullptr;
- auto range = vtk::Range(nodes);
- auto nodeIt = range.begin();
// do a first pass with straightforward nodes(2 branches)
- while (nodeIt != range.end())
+ int i = 0;
+ while (i < nodes->GetNumberOfItems())
{
- node = Node::SafeDownCast(*nodeIt);
+ node = Node::SafeDownCast(nodes->GetItemAsObject(i));
if (node->GetSegments()->GetNumberOfItems() == 2)
{
Segment* segmentA = Segment::SafeDownCast(node->GetSegments()->GetItemAsObject(0));
Segment* segmentB = Segment::SafeDownCast(node->GetSegments()->GetItemAsObject(1));
vtkPlotEdges::MergeSegments(segments, nodes, node, segmentA, segmentB);
- ++nodeIt;
- nodes->RemoveItem(node);
+ nodes->RemoveItem(i);
}
else
{
- ++nodeIt;
+ ++i;
}
}
// do a second pass with the other nodes
- nodeIt = range.begin();
+ auto range = vtk::Range(nodes);
+ auto nodeIt = range.begin();
while (nodeIt != range.end())
With this applied to 6.2.0, the script above works. I have a branch off master with the fix, a regression test and a release note. I’m happy to open a merge request, a backport to 6.2 would help us too.