Discussion:
[vtkusers] vtkPoints.SetPoints bug?
Fahlgren, Eric
2018-11-25 14:39:42 UTC
Permalink
I've just been testing with my build of VTK 8.1.2 built with VS 2017 using Python 3.7.1 on Windows 10 and came across this bad behavior when resetting the values of a vtkPoints object.

tl;dr Using SetPoint fails to update the bounds on the vtkPoints object and anything that subsequently uses the points object (a vtkPolyData in my case) draws incorrectly. This worked in 8.0...

Here's a small script that shows the problem. Is anyone else seeing this, or maybe it's my build???

#!/bin/env python

import vtk

nPts = 5
points = vtk.vtkPoints()
points.SetNumberOfPoints(nPts * 2)

for i in range(nPts):
id = i*2
points.SetPoint(id+0, 0, 0, 0)
points.SetPoint(id+1, 0, 0, 0)
print('Initial values:\n', points)

for i in range(nPts):
id = i*2
x = y = z = float(i)
points.SetPoint(id+0, x, y, z)
points.SetPoint(id+1, x+1, y+2, z+3)
print('After setting them to non-zero, bad bounds:\n', points)

print('Point data:')
for i in range(nPts):
id = i*2
print(id, points.GetPoint(id), points.GetPoint(id+1))

print('Bounds:\n', points.GetBounds())

points.ComputeBounds()
print('Bounds after re-computing:\n', points.GetBounds())

points.SetNumberOfPoints(0)
for i in range(nPts):
x = y = z = float(i)
points.InsertNextPoint(x, y, z)
points.InsertNextPoint(x+1, y+2, z+3)
print('After reallocation, now they are fine:\n', points)


Which gives this output:

Initial values:
vtkPoints (000001FE00289E00)
Debug: Off
Modified Time: 80
Reference Count: 1
RenderDepth: 0
Registered Events: (none)
Data: 000001FE7FD059E0
Data Array Name: Points
Number Of Points: 10
Bounds:
Xmin,Xmax: (0, 0)
Ymin,Ymax: (0, 0)
Zmin,Zmax: (0, 0)


After setting them to non-zero, bad bounds:
vtkPoints (000001FE00289E00)
Debug: Off
Modified Time: 80
Reference Count: 1
RenderDepth: 0
Registered Events: (none)
Data: 000001FE7FD059E0
Data Array Name: Points
Number Of Points: 10
Bounds:
Xmin,Xmax: (0, 0)
Ymin,Ymax: (0, 0)
Zmin,Zmax: (0, 0)


Point data:
0 (0.0, 0.0, 0.0) (1.0, 2.0, 3.0)
2 (1.0, 1.0, 1.0) (2.0, 3.0, 4.0)
4 (2.0, 2.0, 2.0) (3.0, 4.0, 5.0)
6 (3.0, 3.0, 3.0) (4.0, 5.0, 6.0)
8 (4.0, 4.0, 4.0) (5.0, 6.0, 7.0)

Bounds:
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

Bounds after re-computing:
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

After reallocation, now they are fine:
vtkPoints (000001FE00289E00)
Debug: Off
Modified Time: 87
Reference Count: 1
RenderDepth: 0
Registered Events: (none)
Data: 000001FE7FD059E0
Data Array Name: Points
Number Of Points: 10
Bounds:
Xmin,Xmax: (0, 5)
Ymin,Ymax: (0, 6)
Zmin,Zmax: (0, 7)
David Gobbi
2018-11-25 16:25:28 UTC
Permalink
Hi Eric,

It's necessary to call Modified() after calling SetPoint() in order for
ComputeBounds() to re-compute the bounds. This is because ComputeBounds()
checks the timestamp and does nothing if the timestamp shows that the
previous bounds are still good.

As far as I understand, vtkPoints has behaved this way for many years.
Recently, however, there have been many changes to the VTK rendering
pipeline that increase the reliance on timestamps. Perhaps in VTK 8.0
something was triggering a Modified() call or was otherwise forcing a
re-computation of the bounds.

David
Fahlgren, Eric
2018-11-25 18:00:38 UTC
Permalink
Thanks, David, that fixes it. I’m pretty surprised at this since the code was actually written back in the 5.2 days and hasn’t been touched since


Eric

From: David Gobbi [mailto:***@gmail.com]
Sent: Sunday, November 25, 2018 8:25 AM
To: Fahlgren, Eric
Cc: ***@public.kitware.com
Subject: Re: [vtkusers] vtkPoints.SetPoints bug?

Hi Eric,

It's necessary to call Modified() after calling SetPoint() in order for ComputeBounds() to re-compute the bounds. This is because ComputeBounds() checks the timestamp and does nothing if the timestamp shows that the previous bounds are still good.

As far as I understand, vtkPoints has behaved this way for many years. Recently, however, there have been many changes to the VTK rendering pipeline that increase the reliance on timestamps. Perhaps in VTK 8.0 something was triggering a Modified() call or was otherwise forcing a re-computation of the bounds.

David
Fahlgren, Eric
2018-11-25 20:09:11 UTC
Permalink
Using InsertPoint alone instead of SetPoint+Modified also pings the modified time, which brings us to an interesting side point.

We apparently had avoided InsertPoint due to performance issues in the past, so I benchmarked them and InsertPoint is now about 10% faster than SetPoint (which seems odd, since you’d think InsertPoint would be doing some extra mallocs that are clearly ☺ more expensive than simple indexing). Maybe the extra data marshalling for the id parameter is the difference?

from tools.timethis import timethis
import vtk

nPts = 5
points = vtk.vtkPoints()

for iteration in range(21):
print(f'{iteration:3d} {nPts:9_d}')

with timethis('Insert'):
points.SetNumberOfPoints(0)
for i in range(nPts):
x = y = z = float(i)
points.InsertNextPoint(x, y, z)
points.InsertNextPoint(x+1, y+2, z+3)

with timethis('Set'):
points.SetNumberOfPoints(nPts * 2)
for i in range(nPts):
id = i*2
x = y = z = float(i)
points.SetPoint(id+0, x, y, z)
points.SetPoint(id+1, x+1, y+2, z+3)
points.Modified()

nPts *= 2


0 5
1 10
2 20
...
18 1_310_720
19 2_621_440
20 5_242_880
Insert : 0.367240s : N= 21 : stddev=0.89898
Set : 0.417269s : N= 21 : stddev=1.01908


From: vtkusers [mailto:vtkusers-***@public.kitware.com] On Behalf Of Fahlgren, Eric
Sent: Sunday, November 25, 2018 10:01 AM
To: David Gobbi
Cc: ***@public.kitware.com
Subject: Re: [vtkusers] vtkPoints.SetPoints bug?

Thanks, David, that fixes it. I’m pretty surprised at this since the code was actually written back in the 5.2 days and hasn’t been touched since


Eric

From: David Gobbi [mailto:***@gmail.com]
Sent: Sunday, November 25, 2018 8:25 AM
To: Fahlgren, Eric
Cc: ***@public.kitware.com
Subject: Re: [vtkusers] vtkPoints.SetPoints bug?

Hi Eric,

It's necessary to call Modified() after calling SetPoint() in order for ComputeBounds() to re-compute the bounds. This is because ComputeBounds() checks the timestamp and does nothing if the timestamp shows that the previous bounds are still good.

As far as I understand, vtkPoints has behaved this way for many years. Recently, however, there have been many changes to the VTK rendering pipeline that increase the reliance on timestamps. Perhaps in VTK 8.0 something was triggering a Modified() call or was otherwise forcing a re-computation of the bounds.

David
David Gobbi
2018-11-25 20:47:46 UTC
Permalink
Hi Eric,

In your benchmarks, most of the time is going to the Python overhead. So I
agree with your hypothesis: in Python, InsertPoint() will be faster than
SetPoint() simply because the InsertPoint() only has 3 parameters while
SetPoint() has 4. It's all about the time that Python takes to build the
args tuple (function calls in Python are not cheap).

David

On Sun, Nov 25, 2018 at 1:09 PM Fahlgren, Eric <
Post by Fahlgren, Eric
Using InsertPoint alone instead of SetPoint+Modified also pings the
modified time, which brings us to an interesting side point.
We apparently had avoided InsertPoint due to performance issues in the
past, so I benchmarked them and InsertPoint is now about 10% faster than
SetPoint (which seems odd, since you’d think InsertPoint would be doing
some extra mallocs that are clearly J more expensive than simple
indexing). Maybe the extra data marshalling for the id parameter is the
difference?
from tools.timethis import timethis
import vtk
nPts = 5
points = vtk.vtkPoints()
print(f'{iteration:3d} {nPts:9_d}')
points.SetNumberOfPoints(0)
x = y = z = float(i)
points.InsertNextPoint(x, y, z)
points.InsertNextPoint(x+1, y+2, z+3)
points.SetNumberOfPoints(nPts * 2)
id = i*2
x = y = z = float(i)
points.SetPoint(id+0, x, y, z)
points.SetPoint(id+1, x+1, y+2, z+3)
points.Modified()
nPts *= 2
0 5
1 10
2 20
...
18 1_310_720
19 2_621_440
20 5_242_880
Insert : 0.367240s : N= 21 : stddev=0.89898
Set : 0.417269s : N= 21 : stddev=1.01908
Of *Fahlgren, Eric
*Sent:* Sunday, November 25, 2018 10:01 AM
*To:* David Gobbi
*Subject:* Re: [vtkusers] vtkPoints.SetPoints bug?
Thanks, David, that fixes it. I’m pretty surprised at this since the code
was actually written back in the 5.2 days and hasn’t been touched since

Eric
*Sent:* Sunday, November 25, 2018 8:25 AM
*To:* Fahlgren, Eric
*Subject:* Re: [vtkusers] vtkPoints.SetPoints bug?
Hi Eric,
It's necessary to call Modified() after calling SetPoint() in order for
ComputeBounds() to re-compute the bounds. This is because ComputeBounds()
checks the timestamp and does nothing if the timestamp shows that the
previous bounds are still good.
As far as I understand, vtkPoints has behaved this way for many years.
Recently, however, there have been many changes to the VTK rendering
pipeline that increase the reliance on timestamps. Perhaps in VTK 8.0
something was triggering a Modified() call or was otherwise forcing a
re-computation of the bounds.
David
David Gobbi
2018-11-25 21:18:58 UTC
Permalink
Post by David Gobbi
Hi Eric,
In your benchmarks, most of the time is going to the Python overhead. So
I agree with your hypothesis: in Python, InsertPoint() will be faster than
SetPoint() simply because the InsertPoint() only has 3 parameters while
SetPoint() has 4. It's all about the time that Python takes to build the
args tuple (function calls in Python are not cheap).
Actually it's probably not just the Python function call overhead. The
benchmark loop for SetPoint() also contains more operations and creates an
additional variable.

David


On Sun, Nov 25, 2018 at 1:09 PM Fahlgren, Eric <
Post by David Gobbi
Post by Fahlgren, Eric
Using InsertPoint alone instead of SetPoint+Modified also pings the
modified time, which brings us to an interesting side point.
We apparently had avoided InsertPoint due to performance issues in the
past, so I benchmarked them and InsertPoint is now about 10% faster than
SetPoint (which seems odd, since you’d think InsertPoint would be doing
some extra mallocs that are clearly J more expensive than simple
indexing). Maybe the extra data marshalling for the id parameter is the
difference?
from tools.timethis import timethis
import vtk
nPts = 5
points = vtk.vtkPoints()
print(f'{iteration:3d} {nPts:9_d}')
points.SetNumberOfPoints(0)
x = y = z = float(i)
points.InsertNextPoint(x, y, z)
points.InsertNextPoint(x+1, y+2, z+3)
points.SetNumberOfPoints(nPts * 2)
id = i*2
x = y = z = float(i)
points.SetPoint(id+0, x, y, z)
points.SetPoint(id+1, x+1, y+2, z+3)
points.Modified()
nPts *= 2
0 5
1 10
2 20
...
18 1_310_720
19 2_621_440
20 5_242_880
Insert : 0.367240s : N= 21 : stddev=0.89898
Set : 0.417269s : N= 21 : stddev=1.01908
Of *Fahlgren, Eric
*Sent:* Sunday, November 25, 2018 10:01 AM
*To:* David Gobbi
*Subject:* Re: [vtkusers] vtkPoints.SetPoints bug?
Thanks, David, that fixes it. I’m pretty surprised at this since the
code was actually written back in the 5.2 days and hasn’t been touched
since

Eric
*Sent:* Sunday, November 25, 2018 8:25 AM
*To:* Fahlgren, Eric
*Subject:* Re: [vtkusers] vtkPoints.SetPoints bug?
Hi Eric,
It's necessary to call Modified() after calling SetPoint() in order for
ComputeBounds() to re-compute the bounds. This is because ComputeBounds()
checks the timestamp and does nothing if the timestamp shows that the
previous bounds are still good.
As far as I understand, vtkPoints has behaved this way for many years.
Recently, however, there have been many changes to the VTK rendering
pipeline that increase the reliance on timestamps. Perhaps in VTK 8.0
something was triggering a Modified() call or was otherwise forcing a
re-computation of the bounds.
David
Loading...