Commit 94f5564b authored by David C. Lonie's avatar David C. Lonie

Add DrawMarkers to Context2D.

This patch moves the point marker rendering from vtkPlotPoints to
the vtkContext2D classes, allowing GL2PS export to properly handle
the plotted points.

Change-Id: Iaf17bc73f90f7cb330a319e0944e6bf4badc86a6
parent 78fe9609
......@@ -108,12 +108,43 @@ bool ContextTest::Paint(vtkContext2D *painter)
painter->DrawPoint(10, 590);
painter->DrawPoint(790, 590);
// Test the markers
float markerPoints[10*2];
unsigned char markerColors[10*4];
for (int i = 0; i < 10; ++i)
{
markerPoints[2 * i] = 500.0 + i * 30.0;
markerPoints[2 * i + 1] = 20 * sin(markerPoints[2 * i]) + 375.0;
markerColors[4 * i] = static_cast<unsigned char>(255 * i / 10.0);
markerColors[4 * i + 1] =
static_cast<unsigned char>(255 * (1.0 - i / 10.0));
markerColors[4 * i + 2] = static_cast<unsigned char>(255 * (0.3));
markerColors[4 * i + 3] =
static_cast<unsigned char>(255 * (1.0 - ((i / 10.0) * 0.25)));
}
for (int style = VTK_MARKER_NONE + 1; style < VTK_MARKER_UNKNOWN; ++style)
{
// Increment the y values:
for (int i = 1; i < 20; i += 2)
{
markerPoints[i] += 35.0;
}
painter->GetPen()->SetWidth(style * 5 + 5);
// Not highlighted:
painter->DrawMarkers(style, false, markerPoints, 10, markerColors, 4);
// Highlight the middle 4 points
painter->GetPen()->SetColorF(0.9, 0.8, 0.1, 0.5);
painter->DrawMarkers(style, true, markerPoints + 3*2, 4);
}
// Draw some individual lines of different thicknesses.
for (int i = 0; i < 10; ++i)
{
painter->GetPen()->SetColor(0,
static_cast<unsigned char>(float(i)*25.0),
255);
255, 255);
painter->GetPen()->SetWidth(1.0 + float(i));
painter->DrawPoint(75, 50 + float(i)*10);
}
......
......@@ -71,8 +71,6 @@ vtkPlotPoints::vtkPlotPoints()
this->MarkerSize = -1.0;
this->LogX = false;
this->LogY = false;
this->Marker = NULL;
this->HighlightMarker = NULL;
this->LookupTable = 0;
this->Colors = 0;
......@@ -93,14 +91,6 @@ vtkPlotPoints::~vtkPlotPoints()
this->BadPoints->Delete();
this->BadPoints = NULL;
}
if (this->Marker)
{
this->Marker->Delete();
}
if (this->HighlightMarker)
{
this->HighlightMarker->Delete();
}
if (this->LookupTable)
{
this->LookupTable->UnRegister(this);
......@@ -166,24 +156,20 @@ bool vtkPlotPoints::Paint(vtkContext2D *painter)
}
}
float *f = vtkFloatArray::SafeDownCast(this->Points->GetData())->GetPointer(0);
int n = static_cast<int>(this->Points->GetData()->GetNumberOfTuples());
// If there is a marker style, then draw the marker for each point too
if (this->MarkerStyle)
if (this->MarkerStyle != VTK_MARKER_NONE)
{
this->GeneraterMarker(vtkContext2D::FloatToInt(width));
painter->ApplyPen(this->Pen);
painter->ApplyBrush(this->Brush);
painter->GetPen()->SetWidth(width);
if (this->ScalarVisibility && this->Colors)
{
painter->DrawPointSprites(this->Marker, this->Points, this->Colors);
painter->DrawMarkers(this->MarkerStyle, false,
this->Points, this->Colors);
}
else
{
painter->DrawPointSprites(this->Marker, f, n);
painter->DrawMarkers(this->MarkerStyle, false, this->Points);
}
}
......@@ -193,6 +179,8 @@ bool vtkPlotPoints::Paint(vtkContext2D *painter)
if (this->Selection->GetMTime() > this->SelectedPoints->GetMTime() ||
this->GetMTime() > this->SelectedPoints->GetMTime())
{
float *f = vtkFloatArray::SafeDownCast(
this->Points->GetData())->GetPointer(0);
int nSelected(static_cast<int>(this->Selection->GetNumberOfTuples()));
this->SelectedPoints->SetNumberOfComponents(2);
this->SelectedPoints->SetNumberOfTuples(nSelected);
......@@ -204,13 +192,23 @@ bool vtkPlotPoints::Paint(vtkContext2D *painter)
}
}
vtkDebugMacro(<<"Selection set " << this->Selection->GetNumberOfTuples());
this->GeneraterMarker(vtkContext2D::FloatToInt(width + 2.7), true);
painter->GetPen()->SetColor(255, 50, 0, 150);
painter->GetPen()->SetWidth(width + 2.7);
painter->DrawPointSprites(this->HighlightMarker,
static_cast<float *>(this->SelectedPoints->GetVoidPointer(0)),
this->SelectedPoints->GetNumberOfTuples());
if (this->MarkerStyle == VTK_MARKER_NONE)
{
painter->DrawMarkers(VTK_MARKER_PLUS, false,
static_cast<float *>(
this->SelectedPoints->GetVoidPointer(0)),
this->SelectedPoints->GetNumberOfTuples());
}
else
{
painter->DrawMarkers(this->MarkerStyle, true,
static_cast<float *>(
this->SelectedPoints->GetVoidPointer(0)),
this->SelectedPoints->GetNumberOfTuples());
}
}
return true;
......@@ -227,200 +225,16 @@ bool vtkPlotPoints::PaintLegend(vtkContext2D *painter, const vtkRectf& rect,
{
width = 8.0;
}
this->GeneraterMarker(vtkContext2D::FloatToInt(width));
painter->ApplyPen(this->Pen);
painter->ApplyBrush(this->Brush);
painter->GetPen()->SetWidth(width);
float point[] = { rect[0]+ 0.5f * rect[2], rect[1] + 0.5f * rect[3] };
painter->DrawPointSprites(this->Marker, point, 1);
painter->DrawMarkers(this->MarkerStyle, false, point, 1);
}
return true;
}
//-----------------------------------------------------------------------------
void vtkPlotPoints::GeneraterMarker(int width, bool highlight)
{
// Set up the image data, if highlight then the mark shape is different
vtkImageData *data = 0;
if (!highlight)
{
if (!this->Marker)
{
this->Marker = vtkImageData::New();
}
else
{
if (this->Marker->GetMTime() >= this->GetMTime() &&
this->Marker->GetMTime() >= this->Pen->GetMTime())
{
// Marker already generated, no need to do this again.
return;
}
}
data = this->Marker;
}
else
{
if (!this->HighlightMarker)
{
this->HighlightMarker = vtkImageData::New();
}
else
{
if (this->HighlightMarker->GetMTime() >= this->GetMTime() &&
this->HighlightMarker->GetMTime() >= this->Pen->GetMTime())
{
// Marker already generated, no need to do this again.
return;
}
}
data = this->HighlightMarker;
}
data->SetExtent(0, width-1, 0, width-1, 0, 0);
data->AllocateScalars(VTK_UNSIGNED_CHAR, 4);
unsigned char* image =
static_cast<unsigned char*>(data->GetScalarPointer());
// Generate the marker image at the required size
switch (this->MarkerStyle)
{
case vtkPlotPoints::CROSS:
{
for (int i = 0; i < width; ++i)
{
for (int j = 0; j < width; ++j)
{
unsigned char color = 0;
if (highlight)
{
if ((i >= j-1 && i <= j+1) || (i >= width-j-1 && i <= width-j+1))
{
color = 255;
}
}
else
{
if (i == j || i == width-j)
{
color = 255;
}
}
image[4*width*i + 4*j] = image[4*width*i + 4*j + 1] =
image[4*width*i + 4*j + 2] = color;
image[4*width*i + 4*j + 3] = color;
}
}
break;
}
case vtkPlotPoints::PLUS:
{
int x = width / 2;
int y = width / 2;
for (int i = 0; i < width; ++i)
{
for (int j = 0; j < width; ++j)
{
unsigned char color = 0;
if (i == x || j == y)
{
color = 255;
}
if (highlight)
{
if (i == x-1 || i == x+1 || j == y-1 || j == y+1)
{
color = 255;
}
}
image[4*width*i + 4*j] = image[4*width*i + 4*j + 1] =
image[4*width*i + 4*j + 2] = color;
image[4*width*i + 4*j + 3] = color;
}
}
break;
}
case vtkPlotPoints::SQUARE:
{
for (int i = 0; i < width; ++i)
{
for (int j = 0; j < width; ++j)
{
unsigned char color = 255;
image[4*width*i + 4*j] = image[4*width*i + 4*j + 1] =
image[4*width*i + 4*j + 2] = color;
image[4*width*i + 4*j + 3] = color;
}
}
break;
}
case vtkPlotPoints::CIRCLE:
{
double c = width/2.0;
for (int i = 0; i < width; ++i)
{
double dx2 = (i - c)*(i-c);
for (int j = 0; j < width; ++j)
{
double dy2 = (j - c)*(j - c);
unsigned char color = 0;
if (sqrt(dx2 + dy2) < c)
{
color = 255;
}
image[4*width*i + 4*j] = image[4*width*i + 4*j + 1] =
image[4*width*i + 4*j + 2] = color;
image[4*width*i + 4*j + 3] = color;
}
}
break;
}
case vtkPlotPoints::DIAMOND:
{
int c = width/2;
for (int i = 0; i < width; ++i)
{
int dx = i-c > 0 ? i-c : c-i;
for (int j = 0; j < width; ++j)
{
int dy = j-c > 0 ? j-c : c-j;
unsigned char color = 0;
if (c-dx >= dy)
{
color = 255;
}
image[4*width*i + 4*j] = image[4*width*i + 4*j + 1] =
image[4*width*i + 4*j + 2] = color;
image[4*width*i + 4*j + 3] = color;
}
}
break;
}
default:
{
int x = width / 2;
int y = width / 2;
for (int i = 0; i < width; ++i)
{
for (int j = 0; j < width; ++j)
{
unsigned char color = 0;
if (i == x || j == y)
{
color = 255;
}
image[4*width*i + 4*j] = image[4*width*i + 4*j + 1] =
image[4*width*i + 4*j + 2] = color;
image[4*width*i + 4*j + 3] = color;
}
}
}
}
}
//-----------------------------------------------------------------------------
void vtkPlotPoints::GetBounds(double bounds[4])
{
......
......@@ -121,12 +121,12 @@ public:
// Description:
// Enum containing various marker styles that can be used in a plot.
enum {
NONE = 0,
CROSS,
PLUS,
SQUARE,
CIRCLE,
DIAMOND
NONE = VTK_MARKER_NONE,
CROSS = VTK_MARKER_CROSS,
PLUS = VTK_MARKER_PLUS,
SQUARE = VTK_MARKER_SQUARE,
CIRCLE = VTK_MARKER_CIRCLE,
DIAMOND = VTK_MARKER_DIAMOND
};
//ETX
......@@ -147,10 +147,6 @@ protected:
vtkPlotPoints();
~vtkPlotPoints();
// Description:
// Generate the requested symbol for the plot
void GeneraterMarker(int width, bool highlight = false);
// Description:
// Update the table cache.
bool UpdateTableCache(vtkTable *table);
......@@ -197,8 +193,6 @@ protected:
// The marker style that should be used
int MarkerStyle;
float MarkerSize;
vtkImageData* Marker;
vtkImageData* HighlightMarker;
bool LogX, LogY;
......
......@@ -95,6 +95,15 @@
#define VTK_COLOR_MODE_DEFAULT 0
#define VTK_COLOR_MODE_MAP_SCALARS 1
// Marker shapes for plotting
#define VTK_MARKER_NONE 0
#define VTK_MARKER_CROSS 1
#define VTK_MARKER_PLUS 2
#define VTK_MARKER_SQUARE 3
#define VTK_MARKER_CIRCLE 4
#define VTK_MARKER_DIAMOND 5
#define VTK_MARKER_UNKNOWN 6 // Must be last
// Constants for InterpolationType
#define VTK_NEAREST_INTERPOLATION 0
#define VTK_LINEAR_INTERPOLATION 1
......
......@@ -134,12 +134,43 @@ bool ContextGL2PSTest::Paint(vtkContext2D *painter)
painter->DrawPoint(10, 590);
painter->DrawPoint(790, 590);
// Test the markers
float markerPoints[10*2];
unsigned char markerColors[10*4];
for (int i = 0; i < 10; ++i)
{
markerPoints[2 * i] = 500.0 + i * 30.0;
markerPoints[2 * i + 1] = 20 * sin(markerPoints[2 * i]) + 375.0;
markerColors[4 * i] = static_cast<unsigned char>(255 * i / 10.0);
markerColors[4 * i + 1] =
static_cast<unsigned char>(255 * (1.0 - i / 10.0));
markerColors[4 * i + 2] = static_cast<unsigned char>(255 * (0.3));
markerColors[4 * i + 3] =
static_cast<unsigned char>(255 * (1.0 - ((i / 10.0) * 0.25)));
}
for (int style = VTK_MARKER_NONE + 1; style < VTK_MARKER_UNKNOWN; ++style)
{
// Increment the y values:
for (int i = 1; i < 20; i += 2)
{
markerPoints[i] += 35.0;
}
painter->GetPen()->SetWidth(style * 5 + 5);
// Not highlighted:
painter->DrawMarkers(style, false, markerPoints, 10, markerColors, 4);
// Highlight the middle 4 points
painter->GetPen()->SetColorF(0.9, 0.8, 0.1, 0.5);
painter->DrawMarkers(style, true, markerPoints + 3*2, 4);
}
// Draw some individual lines of different thicknesses.
for (int i = 0; i < 10; ++i)
{
painter->GetPen()->SetColor(0,
static_cast<unsigned char>(float(i)*25.0),
255);
255, 255);
painter->GetPen()->SetWidth(1.0 + float(i));
painter->DrawPoint(75, 50 + float(i)*10);
}
......
......@@ -291,6 +291,50 @@ void vtkContext2D::DrawPointSprites(vtkImageData *sprite, float *points, int n)
this->Device->DrawPointSprites(sprite, points, n);
}
//-----------------------------------------------------------------------------
void vtkContext2D::DrawMarkers(int shape, bool highlight, float *points, int n,
unsigned char *colors, int nc_comps)
{
if (!this->Device)
{
vtkErrorMacro(<< "Attempted to paint with no active vtkContextDevice2D.");
return;
}
this->Device->DrawMarkers(shape, highlight, points, n, colors, nc_comps);
}
//-----------------------------------------------------------------------------
void vtkContext2D::DrawMarkers(int shape, bool highlight, float *points, int n)
{
this->DrawMarkers(shape, highlight, points, n, NULL, 0);
}
//-----------------------------------------------------------------------------
void vtkContext2D::DrawMarkers(int shape, bool highlight, vtkPoints2D *points)
{
// Construct an array with the correct coordinate packing for OpenGL.
int n = static_cast<int>(points->GetNumberOfPoints());
float *f = vtkFloatArray::SafeDownCast(points->GetData())->GetPointer(0);
this->DrawMarkers(shape, highlight, f, n);
}
//-----------------------------------------------------------------------------
void vtkContext2D::DrawMarkers(int shape, bool highlight, vtkPoints2D *points, vtkUnsignedCharArray *colors)
{
// Construct an array with the correct coordinate packing for OpenGL.
int n = static_cast<int>(points->GetNumberOfPoints());
int nc = static_cast<int>(colors->GetNumberOfTuples());
if (n != nc)
{
vtkErrorMacro(<< "Attempted to color points with array of wrong length");
return;
}
int nc_comps = static_cast<int>(colors->GetNumberOfComponents());
float *f = vtkFloatArray::SafeDownCast(points->GetData())->GetPointer(0);
unsigned char *c = colors->GetPointer(0);
this->DrawMarkers(shape, highlight, f, n, c, nc_comps);
}
//-----------------------------------------------------------------------------
void vtkContext2D::DrawRect(float x, float y, float width, float height)
{
......
......@@ -165,6 +165,24 @@ public:
// drawn and the size is set using SetPointSize.
void DrawPointSprites(vtkImageData *sprite, float *points, int n);
// Description:
// Draw a series of markers centered at the points supplied. The \a shape
// argument controls the marker shape, and can be one of
// - VTK_MARKER_CROSS
// - VTK_MARKER_PLUS
// - VTK_MARKER_SQUARE
// - VTK_MARKER_CIRCLE
// - VTK_MARKER_DIAMOND
// Marker size is determined by the current pen width.
// \param colors is an optional array of colors.
// \param nc_comps is the number of components for the color.
virtual void DrawMarkers(int shape, bool highlight, float *points, int n,
unsigned char *colors, int nc_comps);
virtual void DrawMarkers(int shape, bool highlight, float *points, int n);
virtual void DrawMarkers(int shape, bool highlight, vtkPoints2D *points);
virtual void DrawMarkers(int shape, bool highlight, vtkPoints2D *points,
vtkUnsignedCharArray *colors);
// Description:
// Draw a rectangle with origin at x, y and width w, height h
void DrawRect(float x, float y, float w, float h);
......
......@@ -107,3 +107,8 @@ void vtkContextDevice2D::PrintSelf(ostream &os, vtkIndent indent)
os << indent << "Text Property: ";
this->TextProp->PrintSelf(os, indent.GetNextIndent());
}
void vtkContextDevice2D::DrawMarkers(int, bool, float*, int, unsigned char*,
int)
{
}
......@@ -70,6 +70,19 @@ public:
virtual void DrawPointSprites(vtkImageData *sprite, float *points, int n,
unsigned char *colors = 0, int nc_comps = 0) = 0;
// Description:
// Draw a series of markers centered at the points supplied. The \a shape
// argument controls the marker shape, and can be one of
// - VTK_MARKER_CROSS
// - VTK_MARKER_PLUS
// - VTK_MARKER_SQUARE
// - VTK_MARKER_CIRCLE
// - VTK_MARKER_DIAMOND
// \param colors is an optional array of colors.
// \param nc_comps is the number of components for the color.
virtual void DrawMarkers(int shape, bool highlight, float *points, int n,
unsigned char *colors = 0, int nc_comps = 0);
// Description:
// Draw a quad using the specified number of points.
virtual void DrawQuad(float *, int) { ; }
......
......@@ -50,6 +50,8 @@
#include "vtkOpenGLContextDevice2DPrivate.h"
#include <algorithm>
//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkOpenGLContextDevice2D)
......@@ -61,11 +63,18 @@ vtkOpenGLContextDevice2D::vtkOpenGLContextDevice2D()
this->TextRenderer = vtkFreeTypeStringToImage::New();
this->Storage = new vtkOpenGLContextDevice2D::Private;
this->RenderWindow = NULL;
this->MarkerCacheSize = 20;
}
//-----------------------------------------------------------------------------
vtkOpenGLContextDevice2D::~vtkOpenGLContextDevice2D()
{
while (!this->MarkerCache.empty())
{
this->MarkerCache.back().Value->Delete();
this->MarkerCache.pop_back();
}
this->TextRenderer->Delete();
delete this->Storage;
}
......@@ -374,6 +383,17 @@ void vtkOpenGLContextDevice2D::DrawPointSprites(vtkImageData *sprite,
}
}
//-----------------------------------------------------------------------------
void vtkOpenGLContextDevice2D::DrawMarkers(int shape, bool highlight,
float *points, int n,
unsigned char *colors, int nc_comps)
{
// Get a point sprite for the shape
vtkImageData *sprite = this->GetMarker(shape, this->Pen->GetWidth(),
highlight);
this->DrawPointSprites(sprite, points, n, colors, nc_comps);
}
//-----------------------------------------------------------------------------
void vtkOpenGLContextDevice2D::DrawQuad(float *f, int n)
{
......@@ -1285,6 +1305,175 @@ bool vtkOpenGLContextDevice2D::LoadExtensions(vtkOpenGLExtensionManager *m)
return true;
}
//-----------------------------------------------------------------------------
vtkImageData *vtkOpenGLContextDevice2D::GetMarker(int shape, int size,
bool highlight)
{
// Generate the cache key for this marker
vtkTypeUInt64 key = highlight ? (1 << 31) : 0;
key |= static_cast<vtkTypeUInt16>(shape);
key <<= 32;
key |= static_cast<vtkTypeUInt32>(size);
// Try to find the marker in the cache
std::list<vtkMarkerCacheObject>::iterator match =
std::find(this->MarkerCache.begin(), this->MarkerCache.end(), key);
// Was it in the cache?
if (match != this->MarkerCache.end())
{
// Yep -- move it to the front and return the data.
if (match == this->MarkerCache.begin())
{
return match->Value;
}
else
{
vtkMarkerCacheObject result = *match;
this->MarkerCache.erase(match);
this->MarkerCache.push_front(result);
return result.Value;
}
}
// Nope -- we'll need to generate it. Create the image data:
vtkMarkerCacheObject result;
result.Key = key;
result.Value = this->GenerateMarker(shape, size, highlight);
// If there was an issue generating the marker, just return NULL.
if (!result.Value)
{
vtkErrorMacro(<<"Error generating marker: shape,size: "
<< shape << "," << size)
return NULL;
}
// Check the current cache size.
while (this->MarkerCache.size() > this->MarkerCacheSize - 1 &&
!this->MarkerCache.empty())
{
this->MarkerCache.back().Value->Delete();
this->MarkerCache.pop_back();
}
// Add to the cache
this->MarkerCache.push_front(result);
return result.Value;
}
//-----------------------------------------------------------------------------
vtkImageData *vtkOpenGLContextDevice2D::GenerateMarker(int shape, int width,
bool highlight)
{
// Set up the image data, if highlight then the mark shape is different
vtkImageData *result = vtkImageData::New();
result->SetExtent(0, width - 1, 0, width - 1, 0, 0);
result->AllocateScalars(VTK_UNSIGNED_CHAR, 4);
unsigned char* image =
static_cast<unsigned char*>(result->GetScalarPointer());
memset(image, 0, width * width * 4);
// Generate the marker image at the required size
switch (shape)
{
case VTK_MARKER_CROSS:
{
int center = (width + 1) / 2;
for (int i = 0; i < center; ++i)
{
int j = width - i - 1;
memset(image + (4 * (width * i + i)), 255, 4);
memset(image + (4 * (width * i + j)), 255, 4);
memset(image + (4 * (width * j + i)), 255, 4);
memset(image + (4 * (width * j + j)), 255, 4);
if (highlight)
{
memset(image + (4 * (width * (j-1) + (i))), 255, 4);
memset(image + (4 * (width * (i+1) + (i))), 255, 4);
memset(image + (4 * (width * (i) + (i+1))), 255, 4);
memset(image + (4 * (width * (i) + (j-1))), 255, 4);
memset(image + (4 * (width * (i+1) + (j))), 255, 4);
memset(image + (4 * (width * (j-1) + (j))), 255, 4);
memset(image + (4 * (width * (j) + (j-1))), 255, 4);
memset(image + (4 * (width * (j) + (i+1))), 255, 4);
}
}
break;
}
default: // Maintaining old behavior, which produces plus for unknown shape
vtkWarningMacro(<<"Invalid marker shape: " << shape);
case VTK_MARKER_PLUS:
{
int center = (width + 1) / 2;
for (int i = 0; i < center; ++i)
{