[vtk-developers] Class design for spline visualizations

David Thompson david.thompson at kitware.com
Wed Jun 10 14:39:33 EDT 2015


Hi Lin,

> I have made it support 3D ellipse with function ...

Great!

> As you can see in the python test, I call this function 4 times for each quadrant to generate the entire ellipse. Since we need to support multiple patches, I think it's better to define a new dataset class for bezier patches as you mentioned before about  creating a new vtkControlPoints class that inherits from vtkPoints and allows for an extra coordinate.

Rather than create new dataset types, I would like to use existing datatypes to store the data and make an adaptor to iterate over them. That way existing pipelines could modify scalar values defined on control points (and perhaps even patches). For instance, B-splines could be represented as a vtkStructuredGrid whose FieldData contains a special knot array (special in the sense that the array must be of the proper size and with a fixed name like "_vtkKnotVector").

The adaptor would take a vtkDataObject as input and provide iterator-style access to each patch defined by the dataset. Specific subclasses of the adaptor would be B-splines (which expect the vtkDataObject to be a vtkStructuredGrid) or T-splines (which might expect a vtkUniformGridAMR) or even point-based splines (PB-splines as defined in Sederberg's T-spline paper, which could expect any dataset derived vtkPointSet).

class vtkBezierPatchAdaptor : public vtkObject
{
public:
  virtual void SetControlPointData(vtkDataObject* controlPointData);
  vtkGetObjectMacro(vtkDataObject,ControlPointData);

  // Methods to iterate over patches:
  virtual void Begin() = 0;
  virtual bool IsAtEnd() = 0;
  virtual bool GoToPatch(vtkIdType patchId) = 0; // random access iteration
  virtual bool Next() = 0;

  // Methods to access the current patch:
  virtual int GetPatchDimension() const = 0;
  virtual void GetPatchShape() const = 0;
    // returns VTK_TRIANGLE/VTK_QUAD when PatchDimension==2,
    // returns VTK_HEXAHEDRON/VTK_TETRA when PatchDimension==3
  virtual void GetPatchDegree(int* degreeOut) const = 0;
  virtual void GetPatchParameterRange(double* paramsOut) const = 0;
  virtual void GetPatchPoints(vtkPoints* pointsOut) const = 0;

  // Some helper methods that would make Python wrappings usable:
  int GetPatchDegree(int dim) const
    {
    std::vector<int> degree(this->GetPatchDimension());
    this->GetPatchDegree(&degree[0]);
    return degree[dim];
    }
  void GetPatchParameterRange(int dim, double paramRange[2])
    {
    std::vector<double> range(2 * this->GetPatchDimension());
    this->GetPatchDegree(&range[0]);
    paramRange[0] = [2 * dim];
    paramRange[1] = [2 * dim + 1];
    }

protected:
  vtkDataObject* ControlPointData;
};

The B-spline subclass could then iterate over patches by keeping a current "cell ID," which would be incremented by calling Next(). When asked for the *patch* points (not the input points), the adaptor would create a vtkMappedDataArray (see http://www.vtk.org/Wiki/VTK/InSituDataStructure for more information) that did not copy control point coordinates from its ControlPointData->GetPoints() but instead used the implicit connectivity to provide access to underlying B-spline points.

For example, consider the simple case of a rectangular B-spline with degree 1 (bi-linear). We might be given a 5x6 grid of control points as input and asked to iterate over all the patches. Each patch is simply a quadrilateral, and there are (5-1)*(6-1) = 20 of them.

  adaptor->Begin(); // would initialize an internal "cell ID" to 0
  adaptor->IsAtEnd(); // would return false for "cell ID" values in [0,19] and true otherwise.
  adaptor->GetPatchDimension(); // would return 2
  adaptor->GetPatchShape(); // would return VTK_QUAD
  adaptor->GetPatchDegree(degreeOut); // would populate degreeOut with [1,1]
  adaptor->GetPatchPoints(pointsOut); // would populate pointsOut with a vtkMappedDataArray.

The vtkMappedDataArray would report having 4 tuples (one for each corner of the quad... when the degree is higher, is would report the product of (degreeOut[i]+1) for all i in GetPatchDimension()). The actual points reported would depend on the "cell ID" in the adaptor.

I have not figured out yet how the "w" homogeneous coordinate would work with vtkPoints. A different adaptor API might work better (keeping the "w" coordinate separate from the other points).

> Another question is that currently the domain of parameter coordinate is [0, 1] for each patch. Do you think it's better to make the domain continuously, namely [0, 0.25] for the first quadrant, [0.25, 0.75] for the second quadrant, etc?

If we focus on the B-spline adaptor above, we get that for free since the returned knot vector could be normalized to the range [0,1].

	David


More information about the vtk-developers mailing list