[vtk-developers] Class design for spline visualizations

Lin M majcjc at gmail.com
Thu Jun 18 21:08:35 EDT 2015


Hi Dr. Thompson,

I have added one commit which contains a vtkMappedDataArray subclass but
I'm not sure I totally get the idea about the in-situ data structures. Can
you take a look at it please? (
https://gitlab.kitware.com/splines/vtk/merge_requests/4)

Best,
Lin

On Thu, Jun 18, 2015 at 10:47 AM, David Thompson <david.thompson at kitware.com
> wrote:

> Hi Lin,
>
> > From some examples I saw, usually we put some points in vtkPoints, store
> the connectivity in cellArray and add them to a dataset (vtkPolyData,
> vtkStructuredGrid or vtkUnstructureGrid). So is that we store the control
> point of multiple patches in the vtkPoints where we replace the
> vtkDataArray with vtkMappedDataArray now? And in a vtkMappedDataArray, we
> store all the points for all patches together but we overwrite how to
> iterate the array.
>
> That is nearly correct. We will accept
>
>     vtkDataObject* ControlPointData;
>
> from the user. For the case we will implement first, ControlPointData's
> actual type will be the vtkStructuredGrid subclass of vtkDataObject. The
> vtkStructuredGrid instance can hold many user-supplied vtkDataArray
> instances:
>
>     vtkStructuredGrid* structuredControlPoints =
>       vtkStructuredGrid::SafeDownCast(ControlPointData);
>
>     // Control points to map from parameter-space to world coordinates:
>     vtkDataArray* geometricControlPoints =
>       structuredControlPoints->GetPoints()->GetData();
>
>     // Control points to map from paramter-space to scalar fields:
>     vtkDataSetAttributes* scalarFields =
> structuredControlPoints->GetPointData();
>     vtkIdType numScalarFields = scalarFields->GetNumberOfArrays();
>     for (vtkIdType i = 0; i < numScalarFields; ++i)
>       { // scalarFieldControlPoints will hold things like temperature,
> pressure, etc.:
>       vtkDataArray* scalarFieldControlPoints = scalarFields->GetArray(i);
>       }
>
> Because the user supplies these arrays, we cannot force them to be
> vtkMappedDataArray. Instead, we can make a vtkMappedDataArray subclass that
> owns a reference to one of the arrays above and only returns one patch's
> values from the user-supplied array (which holds the values for all patches
> in the spline).
>
> The BezierPatchAdaptor below would return instances of our
> vtkMappedDataArray when its GetPatchPoints method is called. Now that I've
> written some more out, it looks like the API should be changed a little bit
> so that users can ask for a particular array (geometricControlPoints or
> scalarFieldControlPoints):
>
> class vtkBezierPatchAdaptor : public vtkObject
> {
> public:
>   virtual void SetControlPointData(vtkDataObject* controlPointData);
>   vtkGetObjectMacro(vtkDataObject,ControlPointData);
>
>   // Methods to iterate over patches:
>   // ... same as below ...
>
>   // Methods to access the current patch:
>   // ...
>   virtual vtkSmartPointer<vtkMappedArray> GetPatchPoints(int scalarField)
> const = 0;
>   // ...
> };
>
> This way, GetPatchPoints() could return the vtkMappedDataArray for
> geometricControlPoints when the "int scalarField" argument is negative
> value and a vtkMappedDataArray for one of the scalarFieldControlPoints
> arrays when scalarField is positive.
>
> Having GetPatchPoints() return a smart pointer to a vtkMappedDataArray
> subclass would also get around the issue that vtkPoints expects its
> vtkDataArray to have 3 components per tuple (where ours will have 4 for
> geometricControlPoints or an arbitrary number for scalarFieldControlPoints).
>
> The vtkMappedDataArray instances would own a weak reference back the
> vtkBezierPatchAdaptor which created them and a weak reference to the
> geometricControlPoints or scalarFieldControlPoints array it draws values
> from. When vtkBezierPatchAdaptor::Next() or
> vtkBezierPatchAdaptor::GoToPatch() is called, the adaptor would iterate
> over all of the vtkMappedDataArray instances it owns and change an internal
> variable so they would return values for the proper patch. That way the
> vtkMappedDataArray instances only have to be created once for each spline
> dataset, not once per patch.
>
> Is that clear enough, or should I sketch out a header file for our
> vtkMappedDataArray subclass?
>
>         David
>
> > On Wed, Jun 17, 2015 at 10:22 PM, David Thompson <
> david.thompson at kitware.com> wrote:
> > Hi Lin,
> >
> >> Sorry for late reply. Since the midterm is coming, I'll definitely
> speed up the development from now on.
> >
> > We both need to do a little more work. I have been looking at how to
> read data from PetIGA so we can show some actual simulation data and have
> some 3-D volumetric examples.
> >
> > It would be nice to have a patch ready to merge into VTK's master branch
> at the midterm that provides spline interpolation and tests it for all 3
> parametric dimensions (curves, surfaces, and volumes). The means producing
> triangles and tetrahedra, not just polylines.
> >
> >> I have a question about the class design in your last email. To my
> understanding, control points for one patch is stored in a vtkDataArray.
> >
> > Close. I think that we should use the vtkMappedDataArray class to hold
> control points for multiple patches but program it to appear as if points
> for each individual patch are stored in patch-order.
> >
> >> Do you mean store multiple vtkDataArray regarding to multiple patches
> in the vtkDataObject?
> >
> > There would be one data array to hold point coordinates, but other
> arrays would hold simulation variables like temperature, pressure,
> velocity, and so on.
> >
> >> If so, what class do I need to use for vtkDataObject?
> >
> > The class outline below is an abstract class. A concrete implementation
> for NURBs would require   the base class's ControlPointData to be an
> instance of vtkStructuredGrid. A T-spline implementation might expect
> ControlPointData to be a vtkUnstructuredGrid. I think all we should do this
> summer is the NURBs case.
> >
> >     David
> >
> >>
> >> On Wed, Jun 10, 2015 at 2:39 PM, David Thompson <
> david.thompson at kitware.com> wrote:
> >> 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
> >>
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/vtk-developers/attachments/20150618/34c45d1b/attachment.html>


More information about the vtk-developers mailing list