get the raw pointer from the vtkPoints

Hello,

I tried to get the raw pointer of vtkPoints and send it to other services. But it looks that the return value of GetVoidPointer is incorrect. This is the code I used for testing, although I could go through every point and copy values explicitly, I’m just curious if it is possible to get the raw pointer directly.

  std::vector<double> source;
  for (int i = 0; i < 12; i++) {
    source.push_back(0.1 * i);
  }

  auto pointarray = vtkSmartPointer<vtkPoints>::New();
  pointarray->SetNumberOfPoints(4);
  for (vtkIdType i = 0; i < 4; i++) {
    pointarray->SetPoint(i, &source[i * 3]);
  }

  double* ptr = (double*)(pointarray->GetVoidPointer(0));
  int datalen = pointarray->GetNumberOfPoints() * 3;

  // why there are errors here ?
  for (int i = 0; i < datalen; i++) {
    double v = *ptr;
    if (v != 0.1 * i) {
      throw std::runtime_error("failed for data value checking");
    }
    ptr++;
  }

I also tested the vtkDoubleArray by similar code, it can return expected value if i use the GetVoidPointer

Thanks a lot for your help!

1 Like

You need to check if the point positions are stored in a vtkFloatArray or vtkDoubleArray and interpret the buffer accordingly.

Note that it is not guaranteed that you will find coordinate values in a tightly-packed xyzxyz… memory layout at the void pointer. There are some fancy new C++ constructs in VTK that allow safe access with reasonably low overhead.

1 Like

Thanks a lot for the information, do you mean this vtkArrayDispatch? (https://vtk.org/doc/nightly/html/VTK-7-1-ArrayDispatch.html)

1 Like

Yes, that’s it.

1 Like

Just for curious, why the vtkPointSet only allow the user to access the inner vtkPoint by the point id? I mean why it does not provide a function that can get the underlying point data array directly. Are there some design considerations about this? Thanks!

VTK can use various memory layouts for storing an array. VTK developers would want to discourage you from accessing the raw memory array directly because then your code would only work with a specific memory layout.

1 Like

There is a follow up question, I noticed that it is ok to get the raw memory of the points of vtkPolyData based on GetPoints function (https://vtk.org/Wiki/VTK/Examples/Cxx/PolyData/PolyDataGetPoint). But I can not find the definition of the GetPoints function in the source code, it is not defined both in https://github.com/Kitware/VTK/blob/master/Common/DataModel/vtkPolyData.h or https://github.com/Kitware/VTK/blob/master/Common/DataModel/vtkPointSet.h. I’m a little bit curious about this. Thanks for your help!

As I’ve heard it said, inheritance is the “goto” of object oriented systems. Meaning, the GetPoints() method is defined in a superclass of vtkPolyData - that is vtkPointSet::GetPoints(). https://vtk.org/doc/nightly/html/classvtkPointSet.html

And this does not return the “raw” data, it returns a vtkPoints class. In turn, you can retrieve a vtkDataArray with vtkPoints::GetData() (which ultimately is the container that holds the data). Then if you want raw data, you have to wrap your head around vtkDataArrays and array dispatch. Some introductory resources are:
https://vtk.org/Wiki/VTK/Tutorials/DataArrays
https://blog.kitware.com/c11-for-range-support-in-vtk/

vtkDataArrays have undergone massive evolution over the last years, largely due to the work of Allison Vacanti. There are a lot of reasons for this, partially for performance, partially to bring VTK closer to modern C++ practices, and also to support data arrays with different memory layouts (e.g., AOS vs SOA). Also, there was a lot of ugly code for dispatching to templated methods using vtkTemplateMacro (and similar) – the ArrayDispatch mechanism is brilliant and really cleans all this up.

The moral of the story is: if you really want raw data it’s quite sophisticated and complex, and the API has evolved so that there are different access patterns depending on what you want to do. My advice for beginners is to use the virtualized API SetPoint()/GetPoint() (for points) or InsertTuple() etc for data arrays. Also, there are hundreds of examples if you dig into the various filters and see how things are implemented.

2 Likes

Thanks so much for the informative reply!

The interesting thing is that, for the online document here (https://vtk.org/doc/nightly/html/classvtkPointSet.html), there is a virtual function to get the vtkPoints by GetPoints, but when I try to check the source code to get more details (https://github.com/Kitware/VTK/blob/master/Common/DataModel/vtkPointSet.h), I could not find that function, that is a little bit annoying. Could you point out this function’s definition at the source code repo?

Some background: one part of our project need to transfer the vtkPolyData to other processes by RPC, and we use the MarshalDataObject function to do it firstly, then we realize that maybe it is faster to transfer different subcomponents (such as points, cell, etc.) separately. Then we think it might be faster if we could transfer the sub-components by shallow copy instead of iterating all points and copy value by GetPoint.

Although there is a new ArrayDispatch mechanism (we still need some time to understand it fully), it may be mainly designed to access the raw data for the efficiency of the filter algorithm (if I understand it correctly). If we want to transfer the raw data of sub-components, the original GetVoidPointer may be more convenient in this case (if we know the value type in advance)?

You need to learn about the magic of vtk macros: look for vtkGetObjectMacro(Points, vtkPoints); in vtkPointSet.h

1 Like

Thanks a lot for the information!

Hello, Dr. Schroeder:

I try to go through the examples about different solutions to range the vtkdataArray, and run them step by step based on this blog from kitware:

There are two small questions:

For the section Type-Explicit-Subclass APIs, is there a way to create the vectors and magnitudes with the type of vtkGenericDataArrayTemplate?, it looks the latest code uses the vtkGenericDataArray, but how to create the array to call this function? For the sample code at this line:

I got this error message:

cannot convert 'vtkSmartPointer<vtkDoubleArray>' to 'vtkGenericDataArray<double, double>*'

Another question is about this line:

I got this error message:

error: no type named 'ComponentType' in 'struct vtk::detail::ValueRange<vtkDataArray, 1>'
  145 |     using MagType = typename decltype(magRange)::ComponentType;

Could you provide some hints for solving these two issues?
Thanks!

I got this error message:

I don’t think you should use a vtkGenericDataArray here. If you want to directly template on types like double, you could use vtkAOSDataArrayTemplate<double> in mag3Explicit. Even better, you could directly template on the type of the array. The signature of your function would look like:

template <typename ArrayT1, typename ArrayT2>
void mag3Explicit(ArrayT1* vectors, ArrayT2* magnitudes)
{
  using VecType = typename ArrayT1::ValueType;
  using MagType = typename ArrayT2::ValueType;
  // Do stuff ...
}

I got this error message:

The correct type inside DataArrayValueRange is ValueType. Note that there is also a ReferenceType defined, which can be used to write in the array, which is not the case when you get a ValueType.

Hello, Bearzi:

Thanks for the information! Could you point out a sample code that uses DataArrayValueRange?, I try to follow the example here https://vtk.org/doc/nightly/html/classvtkArrayDispatch.html by using auto magRange = vtk::DataArrayValueRange(mags);, but I got this error message:

forloops.cpp:146:11: error: no type named 'ComponentType' in 'struct vtk::detail::ValueRange<vtkDataArray, 0>'
  146 |     using MagType = typename decltype(magRange)::ComponentType;

Thanks!

You have three choices:

  • using MagType = typename decltype(magRange)::ValueType
  • using MagType = typename decltype(magRange)::ReferenceType
  • using MagType = typename decltype(magRange)::ConstReferenceType

ValueType will be a double in your case. The reference types are “magic types” which lets you access elements of the array through references. In your case, you would want to use a ReferenceType.

You can access elements in your range using operator[] like an stl indexed container. You could rewrite your method:

struct Mag3Worker2 {
  template <typename VecArray, typename MagArray>
  void operator()(VecArray *vecs, MagArray *mags) {
    // Create range objects:
    const auto vecRange = vtk::DataArrayTupleRange<3>(vecs);
    auto magRange = vtk::DataArrayValueRange<1>(mags);

    using VecConstTupleRef = typename decltype(vecRange)::ConstTupleReferenceType;
    using VecConstCompRef = typename decltype(vecRange)::ConstComponentReferenceType
    using MagRef = typename decltype(magRange)::ReferenceType;
    using MagType = typename decltype(magRange)::ValueType;

    for (vtkIdType id = 0; id < vecRange.size(); ++id)
    {
       MagRef magRef = magRange[id] = 0;
       VecConstTupleRef vecTuple = vecRange[id];
       for (VecConstCompRef comp : vecTuple)
       {
         magRef += static_cast<MagType>(comp * comp);
       }
       magRef = std::sqrt(magRef);
      }
    }
  }
};

Hello, Bearzi:

Thanks so much for your help, and this is workable code (5MCST/forloops.cpp at master · wangzhezhe/5MCST · GitHub) for all examples mentioned in this blog (C++11 for-range support in VTK - Kitware Blog)

I Just put it here in case other people may occur similar issues.

Yohann, Andrew I’m wondering if we should transform this code into a test and/or Example… it might be useful.

@will.schroeder @Yohann_Bearzi here is a MR for vtk-examples: ForLoop. Comments and improvements are welcome. The markdown description should probably have more comments. Also note that the code also tests for the expected output so this could be dropped into VTK as a test also.

1 Like

Andrew I trust you saw my response. Yes, I agree making this a test would be useful.

I certainly did, thanks for the feedback. That’s a good idea. Also Yohann has gone through the code and added lots of excellent constructive comments.

I really appreciate the help.

Andrew Maclean