I’m currently working on creating meshings for a surface using Delaunay2D for triangulation, but I’ve encountered an issue while reading the xyz points from my file. These are georeferenced points, so they actually represent East, North, and Height. The points look like this:
Now, here’s the problem — if I use these points without any modification, when plotting them, they appear “grouped” along the X and Y axes in the VTK window. (I’ve attached all the images so you can better understand what I mean visually.)
After several tests, I came up with the idea of translating my points to the centroid of the file and making that centroid the new (0,0) of the image. That significantly improved the issue. This improvement is clearly visible in the lines when generating the meshing.
I’m still not sure whether this is a problem related to the magnitude of the values, the fact that they are georeferenced, or if I simply need to adjust something when creating the vtkPoints and later adding them to the vtkPolyData.
If anyone has any idea why this happens, I’d really appreciate it, even if it’s not a full solution.
By default, VTK uses 32-bit floats for points, and 32-bit floats cannot precisely represent your data values because your data has too many significant digits. For example (using numpy):
import numpy as np
# 2867996.4 cannot be exactly represented with float32
x = np.float32(2867996.4)
print(x)
2867996.5
# print a list of available float32 values
x = np.float32(2867996.000)
for i in range(4):
x = np.nextafter(x, np.inf, dtype=np.float32)
print(f"{x:.3f}")
2867996.250
2867996.500
2867996.750
2867997.000
In other words, the “grouping” occurs because your data points are being rounded to the closest 32-bit float. A good rule-of-thumb is to only use 32-bit floats for data that has fewer than 7 significant digits.
By subtracting the centroid, you are essentially reducing the number of significant digits used by your data.
There are ways to create data sets with double-precision in VTK, e.g. vtkPoints::SetDataTypeToDouble(), but you would still run into this precision issue on the GPU itself, since GPUs use 32-bit floats for rendering.
Subtracting the centroid is a very reasonable solution to this problem, I don’t know of any “quick fix” provided by VTK itself, since this is a numerical precision issue.
You can get automated shifting and scaling within the vtkPolyDataMapper itself by calling SetVBOShiftScaleMethod() and setting it to one of the ShiftScaleMethodType enum values. AUTO_SHIFT is perhaps what you would want to use here to effectively subtract the centroid under the hood without needing to transform your data.
Other shift/scale options are:
DISABLE_SHIFT_SCALE: Do not shift/scale point coordinates. Ever!
AUTO_SHIFT_SCALE: The default, automatic computation.
ALWAYS_AUTO_SHIFT_SCALE: Always shift scale using auto computed values.
MANUAL_SHIFT_SCALE: Manual shift/scale (for use with AppendVBO)
NEAR_PLANE_SHIFT_SCALE: Shift scale based on camera settings.
FOCAL_POINT_SHIFT_SCALE: Shift scale based on camera settings.
Thank you very much for taking the time to explain everything to me. The problem is now perfectly clear, and I’ll test in the code what Cory mentioned.
open file stream with filename
while there are lines in the file:
read the next line
parse the line into x, y, z values
if parsing succeeds:
add {x, y, z} to tempPoints
// Calculate the centroid (average position)
initialize origin as {0.0, 0.0, 0.0}
for each point in tempPoints:
add point.x to origin.x
add point.y to origin.y
add point.z to origin.z
if tempPoints is not empty:
divide origin.x by number of points in tempPoints
divide origin.y by number of points in tempPoints
divide origin.z by number of points in tempPoints
for each point in tempPoints:
compute shifted as {point.x - origin.x, point.y - origin.y, point.z - origin.z}
insert the original point (point.x, point.y, point.z) into vtkpoints
insert point.z into z_values for coloring
What i basically want is to avoid the 3 loops my code. This are the difference at the VTK Window.
I just tested with the function you mentioned, and it works correctly without applying the VBO method. I’m not sure if it might cause any issues in the future, but for now it’s perfect.