VTK/2DAPI: Difference between revisions
(Updated names) |
mNo edit summary |
||
(One intermediate revision by the same user not shown) | |||
Line 34: | Line 34: | ||
] | ] | ||
vtkContextDevice2D -> | vtkContextDevice2D -> vtkOpenGLContextDevice2D | ||
vtkContextDevice2D -> vtkQtContextDevice2D | vtkContextDevice2D -> vtkQtContextDevice2D? | ||
// "owns the lifetime of" | // "owns the lifetime of" | ||
Line 54: | Line 53: | ||
</graphviz> | </graphviz> | ||
The class relationship diagram is shown above. This a [http://en.wikipedia.org/wiki/Bridge_pattern bridge design pattern] where <em>Abstraction</em> is <tt>vtkContext2D</tt>, <em>Implementor</em> is <tt>vtkContextDevice2D</tt> and <em>ConcreteImplementors</em> are <tt> | The class relationship diagram is shown above. This a [http://en.wikipedia.org/wiki/Bridge_pattern bridge design pattern] where <em>Abstraction</em> is <tt>vtkContext2D</tt>, <em>Implementor</em> is <tt>vtkContextDevice2D</tt> and <em>ConcreteImplementors</em> are <tt>vtkOpenGLContextDevice2D</tt> and <tt>vtkQtContextDevice2D</tt>. There is no <em>RefinedAbstraction</em>. | ||
The headers for the two classes look as follows. | The headers for the two classes look as follows. |
Latest revision as of 19:58, 17 May 2010
The 2D API is currently composed of two levels, a concreate class called vtkContext2D that is called by the paint functions of components operating within the 2D API, and a vtkContextDevice2D which is called by the vtkContext2D to actually draw to a context. The vtkContext2D contains a pointer to the derived class of the vtkContextDevice2D to do low level painting. This is the class that must be implemented for a new backend to be supported. The vtkContext2D builds up more complex 2D constructs on top of the basic constructs implemented in the device.
Currently we only have an OpenGL context device, but this could change in the future.
The class relationship diagram is shown above. This a bridge design pattern where Abstraction is vtkContext2D, Implementor is vtkContextDevice2D and ConcreteImplementors are vtkOpenGLContextDevice2D and vtkQtContextDevice2D. There is no RefinedAbstraction.
The headers for the two classes look as follows.
vtkContext2D
<source lang="cpp"> class VTK_CHARTS_EXPORT vtkContext2D : public vtkObject { public:
vtkTypeRevisionMacro(vtkContext2D, vtkObject); virtual void PrintSelf(ostream &os, vtkIndent indent); static vtkContext2D *New(); // Begin painting, a valid context device is required bool Begin(vtkContextDevice2D *device);
// Perform any cleanup that might be necessary bool End();
// Line drawing functions void DrawLine(float x1, float y1, float x2, float y2); void DrawLine(vtkPoints2D *points); void DrawPoly(float *x, float *y, int n); void DrawPoly(vtkPoints2D *points); void DrawRectangle(float x, float y, float width, float height); void DrawRectangle(float *p); void DrawRectangle(vtkPoints2D *points);
// Point drawing functions void DrawPoint(float x, float y); void DrawPoints(float *x, float *y, int n); void DrawPoints(vtkPoints2D *points);
// Manage the state of the painter void SetColor(int r, int g, int b, int a); void SetPointSize(float size); void SetLineWidth(float width);
protected:
vtkContext2D(); ~vtkContext2D();
}; </source>
vtkContextDevice2D (Abstract)
While the vtkContextDevice2D class is an abstract class. The header for the equivalent functionality is,
<source lang="cpp"> class VTK_CHARTS_EXPORT vtkContextDevice2D : public vtkObject { public:
vtkTypeRevisionMacro(vtkContextDevice2D, vtkObject); virtual void PrintSelf(ostream &os, vtkIndent indent); static vtkContextDevice2D *New(); // Set up the paint device context virtual void Begin(vtkRenderer* renderer) { } // Clean anything up once rendering has been completed virtual void End() { }
// Line drawing functions virtual void DrawPoly(vtkPoints2D *points) = 0;
// Point drawing functions virtual void DrawPoints(vtkPoints2D *points) = 0;
// Manage the state of the paint device virtual void SetColor(int r, int g, int b, int a) = 0; virtual void SetPointSize(float size) = 0; virtual void SetLineWidth(float width) = 0;
protected:
vtkContextDevice2D(); ~vtkContextDevice2D();
}; </source>
Drawing Marks
The Views and Charts page contains details of a higher level API for drawing marks. Modifying this slightly to sit above the vtkContext2D API would allow a backend agnostic programmable glyph renderer.
<source lang="cpp"> class vtkPointMark { public:
virtual int GetNumberOfParameters();
virtual const char* GetParameterName( int param ); virtual int GetParameterHandle( const char* paramName ); virtual vtkInformation* GetParameterInformation( int param ); virtual vtkInformation* GetParameterInformation( const char* name );
virtual void ResetParameters();
virtual void BindParameter( int param, vtkVariant& value ); virtual void BindParameter( const char* paramName, vtkVariant& value );
virtual void BindParameter( int param, vtkAbstractArray* values, int component ); virtual void BindParameter( const char* paramName, vtkAbstractArray* values, int component );
virtual int GetParameterBinding( int param, vtkVariant& constVal, vtkAbstractArray*& arrayVal, int& component ); virtual int GetParameterBinding( const char* paramName, vtkVariant& constVal, vtkAbstractArray*& arrayVal, int& component );
virtual void DrawMarks( vtkContext2D* context, vtkDataArray* xCoords, int xComponent, vtkDataArray* yCoords, int yComponent, vtkIdType start, vtkIdType end, vtkIdType stride );
protected:
void GetParameterValuesForTuple( vtkIdType pt, vtkVariantArray* pvals ); virtual void SetupParameters() = 0;
}; </source>
Performance Considerations
One of the goals of this project is to create charts that scale well to large data sets. I have been examining several techniques to accomplish this goal, mainly centered around passing arrays to drawing functions to draw multiple 2D primitives using only one function call. If we use a virtual base class for the context device then it is important to be able to draw large numbers of points without multiple function calls. Even without virtual function calls, the function call overhead can become the bottleneck, i.e. OpenGL glVertex3fv versus glVertexPointer.
Most rendering backends expect coordinates to be packed in memory in certain ways. One of the most common is as a 1D array with of length tuple * number of points. The vtkPoints2D and vtkPoints (3D) classes achieve this packing in their underlying data structure. Using this data structure will lead to the best performance, otherwise the context must repack the arrays (such as data coming from multiple columns in a table).
This is the motivation for using functions with signatures that take multiple points. In my initial testing this has worked well with millions of points and maps well to OpenGL's API. I will work on adding some benchmarking to properly quantify how well this scales. It would be an interesting way to summarize the performance of various architectures.
<source lang="cpp">void DrawPoints(vtkPoints2D *points);</source>