Commit e054a56d authored by Allison Vacanti's avatar Allison Vacanti

Improve support for log scaling in color opacity widgets.

parent c68bae18
......@@ -814,12 +814,12 @@ void vtkChartXY::RecalculatePlotBounds()
}
if (this->ForceAxesToBounds)
{
axis->SetUnscaledMinimumLimit(range[0]);
axis->SetUnscaledMaximumLimit(range[1]);
axis->SetMinimumLimit(range[0]);
axis->SetMaximumLimit(range[1]);
}
if (axis->GetBehavior() == vtkAxis::AUTO && initialized[i])
{
axis->SetUnscaledRange(range[0], range[1]);
axis->SetRange(range[0], range[1]);
axis->AutoScale();
}
}
......
......@@ -239,11 +239,12 @@ void vtkColorTransferControlPointsItem::ComputeBounds(double* bounds)
{
if (this->ColorTransferFunction)
{
const double* range = this->ColorTransferFunction->GetRange();
bounds[0] = range[0];
bounds[1] = range[1];
this->ColorTransferFunction->GetRange(bounds);
bounds[2] = 0.5;
bounds[3] = 0.5;
this->TransformDataToScreen(bounds[0], bounds[2], bounds[0], bounds[2]);
this->TransformDataToScreen(bounds[1], bounds[3], bounds[1], bounds[3]);
}
else
{
......
......@@ -70,9 +70,10 @@ void vtkColorTransferFunctionItem::ComputeBounds(double* bounds)
this->Superclass::ComputeBounds(bounds);
if (this->ColorTransferFunction)
{
double unused;
double* range = this->ColorTransferFunction->GetRange();
bounds[0] = range[0];
bounds[1] = range[1];
this->TransformDataToScreen(range[0], 1, bounds[0], unused);
this->TransformDataToScreen(range[1], 1, bounds[1], unused);
}
}
......@@ -98,9 +99,9 @@ void vtkColorTransferFunctionItem::SetColorTransferFunction(vtkColorTransferFunc
//-----------------------------------------------------------------------------
void vtkColorTransferFunctionItem::ComputeTexture()
{
double bounds[4];
this->GetBounds(bounds);
if (bounds[0] == bounds[1]
double screenBounds[4];
this->GetBounds(screenBounds);
if (screenBounds[0] == screenBounds[1]
|| !this->ColorTransferFunction)
{
return;
......@@ -110,6 +111,12 @@ void vtkColorTransferFunctionItem::ComputeTexture()
this->Texture = vtkImageData::New();
}
double dataBounds[4];
this->TransformScreenToData(screenBounds[0], screenBounds[2],
dataBounds[0], dataBounds[2]);
this->TransformScreenToData(screenBounds[1], screenBounds[3],
dataBounds[1], dataBounds[3]);
// Could depend of the screen resolution
const int dimension = this->GetTextureWidth();
double* values = new double[dimension];
......@@ -118,22 +125,9 @@ void vtkColorTransferFunctionItem::ComputeTexture()
0, 0,
0, 0);
this->Texture->AllocateScalars(VTK_UNSIGNED_CHAR, 4);
bool isLogTable = this->GetXAxis()->GetLogScaleActive();
double logBoundsMin = bounds[0] > 0.0 ? log10(bounds[0]) : 0.0;
double logBoundsDelta = (bounds[0] > 0.0 && bounds[1] > 0.0)?
(log10(bounds[1])-log10(bounds[0])) : 0.0;
for (int i = 0; i < dimension; ++i)
{
if (isLogTable)
{
double normVal = i/(dimension-1.0);
double lval = logBoundsMin + normVal*logBoundsDelta;
values[i] = pow(10.0, lval);
}
else
{
values[i] = bounds[0] + i * (bounds[1] - bounds[0]) / (dimension - 1);
}
values[i] = dataBounds[0] + i * (dataBounds[1] - dataBounds[0]) / (dimension - 1);
}
unsigned char* ptr =
reinterpret_cast<unsigned char*>(this->Texture->GetScalarPointer(0,0,0));
......
......@@ -72,9 +72,11 @@ void vtkCompositeTransferFunctionItem::ComputeBounds(double* bounds)
this->Superclass::ComputeBounds(bounds);
if (this->OpacityFunction)
{
double* opacityRange = this->OpacityFunction->GetRange();
bounds[0] = std::min(bounds[0], opacityRange[0]);
bounds[1] = std::max(bounds[1], opacityRange[1]);
double unused;
double opacityRange[2];
this->OpacityFunction->GetRange(opacityRange);
this->TransformDataToScreen(opacityRange[0], 1, bounds[0], unused);
this->TransformDataToScreen(opacityRange[1], 1, bounds[1], unused);
}
}
......@@ -101,9 +103,9 @@ void vtkCompositeTransferFunctionItem::SetOpacityFunction(vtkPiecewiseFunction*
void vtkCompositeTransferFunctionItem::ComputeTexture()
{
this->Superclass::ComputeTexture();
double bounds[4];
this->GetBounds(bounds);
if (bounds[0] == bounds[1]
double screenBounds[4];
this->GetBounds(screenBounds);
if (screenBounds[0] == screenBounds[1]
|| !this->OpacityFunction)
{
return;
......@@ -113,12 +115,19 @@ void vtkCompositeTransferFunctionItem::ComputeTexture()
this->Texture = vtkImageData::New();
}
double dataBounds[4];
this->TransformScreenToData(screenBounds[0], screenBounds[2],
dataBounds[0], dataBounds[2]);
this->TransformScreenToData(screenBounds[1], screenBounds[3],
dataBounds[1], dataBounds[3]);
const bool logX = this->GetXAxis()->GetLogScaleActive();
const bool logY = this->GetYAxis()->GetLogScaleActive();
const int dimension = this->GetTextureWidth();
double* values = new double[dimension];
this->OpacityFunction->GetTable(bounds[0], bounds[1], dimension, values, 1,
this->OpacityFunction->GetTable(dataBounds[0], dataBounds[1],
dimension, values, 1,
logX ? 1 : 0);
unsigned char* ptr =
reinterpret_cast<unsigned char*>(this->Texture->GetScalarPointer(0,0,0));
......@@ -127,13 +136,7 @@ void vtkCompositeTransferFunctionItem::ComputeTexture()
if (this->MaskAboveCurve || this->PolyLinePen->GetLineType() != vtkPen::SOLID_LINE)
{
this->Shape->SetNumberOfPoints(dimension);
if (logX)
{
bounds[0] = std::log10(bounds[0]);
bounds[1] = std::log10(bounds[1]);
}
const double step = (bounds[1] - bounds[0]) / dimension;
const double step = (screenBounds[1] - screenBounds[0]) / dimension;
for (int i = 0; i < dimension; ++i)
{
......@@ -144,7 +147,7 @@ void vtkCompositeTransferFunctionItem::ComputeTexture()
}
ptr[3] = static_cast<unsigned char>(values[i] * this->Opacity * 255);
double xValue = bounds[0] + step * i;
double xValue = screenBounds[0] + step * i;
double yValue = values[i];
if (logY)
{
......
......@@ -196,6 +196,9 @@ void vtkControlPointsItem::ComputeBounds( double* bounds)
bounds[2] = std::min(bounds[2], point[1]);
bounds[3] = std::max(bounds[3], point[1]);
}
this->TransformDataToScreen(bounds[0], bounds[2], bounds[0], bounds[2]);
this->TransformDataToScreen(bounds[1], bounds[3], bounds[1], bounds[3]);
}
//-----------------------------------------------------------------------------
......@@ -358,54 +361,77 @@ void vtkControlPointsItem::ComputePoints()
//-----------------------------------------------------------------------------
void vtkControlPointsItem::TransformScreenToData(const vtkVector2f& in, vtkVector2f& out)
{
out = in;
double tmp[2] = { in.GetX(), in.GetY() };
this->TransformScreenToData(tmp[0], tmp[1], tmp[0], tmp[1]);
out.Set(static_cast<float>(tmp[0]), static_cast<float>(tmp[1]));
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::TransformDataToScreen(const vtkVector2f& in, vtkVector2f& out)
{
double tmp[2] = { in.GetX(), in.GetY() };
this->TransformDataToScreen(tmp[0], tmp[1], tmp[0], tmp[1]);
out.Set(static_cast<float>(tmp[0]), static_cast<float>(tmp[1]));
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::TransformScreenToData(
const double inX, const double inY, double &outX, double &outY)
{
outX = inX;
outY = inY;
// inverse shift/scale from screen space.
const vtkRectd& ss = this->ShiftScale;
out.SetX(static_cast<float>((out.GetX() / ss[2]) - ss[0]));
out.SetY(static_cast<float>((out.GetY() / ss[3]) - ss[1]));
outX = (outX / ss[2]) - ss[0];
outY = (outY / ss[3]) - ss[1];
const bool logX = this->GetXAxis() && this->GetXAxis()->GetLogScaleActive();
const bool logY = this->GetYAxis() && this->GetYAxis()->GetLogScaleActive();
if (logX)
{
out.SetX(std::pow(10., out.GetX()));
outX = std::pow(10., outX);
}
if (logY)
{
out.SetY(std::pow(10., out.GetY()));
outY = std::pow(10., outY);
}
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::TransformDataToScreen(const vtkVector2f& in, vtkVector2f& out)
void vtkControlPointsItem::TransformDataToScreen(
const double inX, const double inY, double &outX, double &outY)
{
out = in;
outX = inX;
outY = inY;
const bool logX = this->GetXAxis() && this->GetXAxis()->GetLogScaleActive();
const bool logY = this->GetYAxis() && this->GetYAxis()->GetLogScaleActive();
if (logX)
{
out.SetX(std::log10(out.GetX()));
outX = std::log10(outX);
}
if (logY)
{
out.SetY(std::log10(out.GetY()));
outY = std::log10(outY);
}
// now, shift/scale to screen space.
const vtkRectd& ss = this->ShiftScale;
out.SetX(static_cast<float>((out.GetX() + ss[0]) * ss[2]));
out.SetY(static_cast<float>((out.GetY() + ss[1]) * ss[3]));
outX = (outX + ss[0]) * ss[2];
outY = (outY + ss[1]) * ss[3];
}
//-----------------------------------------------------------------------------
bool vtkControlPointsItem::Hit(const vtkContextMouseEvent &mouse)
{
vtkVector2f vpos = mouse.GetPos();
this->TransformScreenToData(vpos, vpos);
double pos[2];
pos[0] = vpos.GetX();
pos[1] = vpos.GetY();
......@@ -463,7 +489,16 @@ bool vtkControlPointsItem::ClampPos(double pos[2], double bounds[4])
}
//-----------------------------------------------------------------------------
bool vtkControlPointsItem::ClampValidPos(double pos[2])
bool vtkControlPointsItem::ClampValidDataPos(double pos[2])
{
this->TransformDataToScreen(pos[0], pos[1], pos[0], pos[1]);
bool res = this->ClampValidScreenPos(pos);
this->TransformScreenToData(pos[0], pos[1], pos[0], pos[1]);
return res;
}
//-----------------------------------------------------------------------------
bool vtkControlPointsItem::ClampValidScreenPos(double pos[2])
{
double validBounds[4];
this->GetValidBounds(validBounds);
......@@ -511,10 +546,7 @@ void vtkControlPointsItem::DrawPoint(vtkContext2D* painter, vtkIdType index)
double point[4];
this->GetControlPoint(index, point);
vtkVector2f vpoint(point[0], point[1]);
this->TransformDataToScreen(vpoint, vpoint);
point[0] = vpoint.GetX();
point[1] = vpoint.GetY();
this->TransformDataToScreen(point[0], point[1], point[0], point[1]);
double pointInScene[2];
vtkTransform2D* sceneTransform = painter->GetTransform();
......@@ -837,18 +869,16 @@ bool vtkControlPointsItem::IsOverPoint(double* pos, vtkIdType pointId)
}
//-----------------------------------------------------------------------------
vtkIdType vtkControlPointsItem::FindPoint(double* _pos)
vtkIdType vtkControlPointsItem::FindPoint(double* posData)
{
vtkVector2f vpos(_pos[0], _pos[1]);
this->TransformDataToScreen(vpos, vpos);
double pos[2] = {vpos.GetX(), vpos.GetY()};
double pos[2];
this->TransformDataToScreen(posData[0], posData[1], pos[0], pos[1]);
double tolerance = 1.3;
double radius2 = this->ScreenPointRadius * this->ScreenPointRadius
* tolerance * tolerance;
double screenPos[2];
this->Transform->TransformPoints(pos, screenPos, 1);
this->Transform->TransformPoints(pos, pos, 1);
vtkIdType pointId = -1;
double minDist = VTK_DOUBLE_MAX;
const int numberOfPoints = this->GetNumberOfPoints();
......@@ -856,16 +886,11 @@ vtkIdType vtkControlPointsItem::FindPoint(double* _pos)
{
double point[4];
this->GetControlPoint(i, point);
vtkVector2f vpos1(point[0], point[1]);
this->TransformDataToScreen(vpos1, vpos1);
point[0] = vpos1.GetX();
point[1] = vpos1.GetY();
double screenPoint[2];
this->Transform->TransformPoints(point, screenPoint, 1);
this->TransformDataToScreen(point[0], point[1], point[0], point[1]);
this->Transform->TransformPoints(point, point, 1);
double distance2 =
(screenPoint[0] - screenPos[0]) * (screenPoint[0] - screenPos[0]) +
(screenPoint[1] - screenPos[1]) * (screenPoint[1] - screenPos[1]);
(point[0] - pos[0]) * (point[0] - pos[0]) +
(point[1] - pos[1]) * (point[1] - pos[1]);
if (distance2 <= radius2)
{
if (distance2 == 0.)
......@@ -879,7 +904,7 @@ vtkIdType vtkControlPointsItem::FindPoint(double* _pos)
}
}
// don't search any further if the x is already too large
if (screenPoint[0] > (screenPos[0] + this->ScreenPointRadius * tolerance))
if (point[0] > (pos[0] + this->ScreenPointRadius * tolerance))
{
break;
}
......@@ -1009,11 +1034,14 @@ bool vtkControlPointsItem::MouseButtonPressEvent(const vtkContextMouseEvent &mou
this->PointToToggle = -1;
this->PointToDelete = -1;
vtkVector2f vpos = mouse.GetPos();
this->TransformScreenToData(vpos, vpos);
double pos[2];
pos[0] = vpos.GetX();
pos[1] = vpos.GetY();
{
vtkVector2f vpos = mouse.GetPos();
pos[0] = vpos.GetX();
pos[1] = vpos.GetY();
}
this->TransformScreenToData(pos[0], pos[1], pos[0], pos[1]);
vtkIdType pointUnderMouse = this->FindPoint(pos);
if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON)
......@@ -1027,7 +1055,7 @@ bool vtkControlPointsItem::MouseButtonPressEvent(const vtkContextMouseEvent &mou
&& this->GetNumberOfSelectedPoints() <= 1
&& !this->StrokeMode)
{
this->ClampValidPos(pos);
this->ClampValidDataPos(pos);
vtkIdType addedPoint = this->AddPoint(pos);
this->SetCurrentPoint(addedPoint);
return true;
......@@ -1227,7 +1255,7 @@ vtkIdType vtkControlPointsItem::SetPointPos(vtkIdType point, const vtkVector2f&
double boundedPos[2];
boundedPos[0] = newPos[0];
boundedPos[1] = newPos[1];
this->ClampValidPos(boundedPos);
this->ClampValidDataPos(boundedPos);
if (!this->SwitchPointsMode)
{
......@@ -1484,7 +1512,7 @@ void vtkControlPointsItem::Stroke(const vtkVector2f& newPos)
double pos[2];
pos[0] = newPos[0];
pos[1] = newPos[1];
this->ClampValidPos(pos);
this->ClampValidDataPos(pos);
// last point
if (this->CurrentPoint != -1)
......
......@@ -398,10 +398,14 @@ protected:
//@{
/**
* Transform the mouse event in the control-points space. This is needed when
* ColorTransferFunction is using log-scale.
* ColorTransferFunction is using log-scale or shifted/scaled.
*/
virtual void TransformScreenToData(const vtkVector2f& in, vtkVector2f& out);
virtual void TransformDataToScreen(const vtkVector2f& in, vtkVector2f& out);
virtual void TransformScreenToData(const double inX, const double inY,
double &outX, double &outY);
virtual void TransformDataToScreen(const double inX, const double inY,
double &outX, double &outY);
//@}
//@{
......@@ -410,7 +414,8 @@ protected:
* Return true if the pos has been clamped, false otherwise.
*/
virtual bool ClampPos(double pos[2], double bounds[4]);
bool ClampValidPos(double pos[2]);
bool ClampValidDataPos(double pos[2]);
bool ClampValidScreenPos(double pos[2]);
//@}
//@{
......
......@@ -81,6 +81,44 @@ vtkScalarsToColorsItem::~vtkScalarsToColorsItem()
}
}
//-----------------------------------------------------------------------------
void vtkScalarsToColorsItem::TransformDataToScreen(
const double dataX, const double dataY, double &screenX, double &screenY)
{
const bool logX = this->GetXAxis() && this->GetXAxis()->GetLogScaleActive();
const bool logY = this->GetYAxis() && this->GetYAxis()->GetLogScaleActive();
screenX = logX ? log10(dataX) : dataX;
screenY = logY ? log10(dataY) : dataY;
// now, shift/scale to screen space.
const vtkRectd& ss = this->ShiftScale;
screenX = (screenX + ss[0]) * ss[2];
screenY = (screenY + ss[1]) * ss[3];
}
//-----------------------------------------------------------------------------
void vtkScalarsToColorsItem::TransformScreenToData(
const double screenX, const double screenY, double &dataX, double &dataY)
{
// inverse shift/scale from screen space.
const vtkRectd& ss = this->ShiftScale;
dataX = (screenX / ss[2]) - ss[0];
dataY = (screenY / ss[3]) - ss[1];
const bool logX = this->GetXAxis() && this->GetXAxis()->GetLogScaleActive();
const bool logY = this->GetYAxis() && this->GetYAxis()->GetLogScaleActive();
if (logX)
{
dataX = pow(10., dataX);
}
if (logY)
{
dataY = pow(10., dataY);
}
}
//-----------------------------------------------------------------------------
void vtkScalarsToColorsItem::PrintSelf(ostream &os, vtkIndent indent)
{
......@@ -128,7 +166,7 @@ bool vtkScalarsToColorsItem::Paint(vtkContext2D* painter)
vtkSmartPointer<vtkPen> transparentPen = vtkSmartPointer<vtkPen>::New();
transparentPen->SetLineType(vtkPen::NO_PEN);
painter->ApplyPen(transparentPen);
painter->GetBrush()->SetColorF(0., 0.,0.,1.);
painter->GetBrush()->SetColorF(0., 0., 0., 1.);
painter->GetBrush()->SetColorF(1., 1., 1., 1.);
painter->GetBrush()->SetTexture(this->Texture);
painter->GetBrush()->SetTextureProperties(
......@@ -139,32 +177,10 @@ bool vtkScalarsToColorsItem::Paint(vtkContext2D* painter)
{
double dbounds[4];
this->GetBounds(dbounds);
const bool logX = this->GetXAxis()->GetLogScaleActive();
const bool logY = this->GetYAxis()->GetLogScaleActive();
if (logX)
{
dbounds[0] = std::log10(dbounds[0]);
dbounds[1] = std::log10(dbounds[1]);
}
if (logY)
{
dbounds[2] = std::log10(dbounds[2]);
dbounds[3] = std::log10(dbounds[3]);
}
// shift/scale to scale from data space to rendering space.
const vtkRectd& ss = this->ShiftScale;
float fbounds[4];
fbounds[0] = static_cast<float>((dbounds[0] + ss[0]) * ss[2]);
fbounds[1] = static_cast<float>((dbounds[1] + ss[0]) * ss[2]);
fbounds[2] = static_cast<float>((dbounds[2] + ss[1]) * ss[3]);
fbounds[3] = static_cast<float>((dbounds[3] + ss[1]) * ss[3]);
painter->DrawQuad(fbounds[0], fbounds[2],
fbounds[0], fbounds[3],
fbounds[1], fbounds[3],
fbounds[1], fbounds[2]);
painter->DrawQuad(dbounds[0], dbounds[2],
dbounds[0], dbounds[3],
dbounds[1], dbounds[3],
dbounds[1], dbounds[2]);
}
else
{
......
......@@ -107,6 +107,11 @@ protected:
vtkGetMacro(TextureWidth, int);
void TransformDataToScreen(const double dataX, const double dataY,
double &screenX, double &screenY);
void TransformScreenToData(const double screenX, const double screenY,
double &dataX, double &dataY);
//@{
/**
* Called whenever the ScalarsToColors function(s) is modified. It internally
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment