Commit 216094cf authored by Julien Finet's avatar Julien Finet
Browse files

Support transfer functions with a range wider than [0, 1]

Change-Id: Iaf5dabad85bd7cdfb2c2a7021c751cf7298855cc
parent d09e905c
......@@ -38,9 +38,9 @@ int TestColorTransferFunction(int , char * [])
vtkSmartPointer<vtkColorTransferFunction> colorTransferFunction =
vtkSmartPointer<vtkColorTransferFunction>::New();
colorTransferFunction->AddHSVSegment(0.,0.,1.,1.,0.3333,0.3333,1.,1.);
colorTransferFunction->AddHSVSegment(0.3333,0.3333,1.,1.,0.6666,0.6666,1.,1.);
colorTransferFunction->AddHSVSegment(0.6666,0.6666,1.,1.,1.,0.,1.,1.);
colorTransferFunction->AddHSVSegment(50.,0.,1.,1.,85.,0.3333,1.,1.);
colorTransferFunction->AddHSVSegment(85.,0.3333,1.,1.,170.,0.6666,1.,1.);
colorTransferFunction->AddHSVSegment(170.,0.6666,1.,1.,200.,0.,1.,1.);
colorTransferFunction->Build();
......@@ -52,6 +52,7 @@ int TestColorTransferFunction(int , char * [])
vtkSmartPointer<vtkColorTransferControlPointsItem> controlPointsItem =
vtkSmartPointer<vtkColorTransferControlPointsItem>::New();
controlPointsItem->SetColorTransferFunction(colorTransferFunction);
controlPointsItem->SetUserBounds(0., 255., 0., 1.);
chart->AddPlot(controlPointsItem);
//Finally render the scene and compare the image to a reference image
......
......@@ -85,6 +85,7 @@ void vtkColorTransferControlPointsItem::SetColorTransferFunction(vtkColorTransfe
{
this->ColorTransferFunction->AddObserver(vtkCommand::ModifiedEvent, this->Callback);
}
this->ResetBounds();
this->ComputePoints();
}
......
......@@ -88,6 +88,7 @@ void vtkCompositeControlPointsItem::SetOpacityFunction(vtkPiecewiseFunction* fun
{
this->OpacityFunction->AddObserver(vtkCommand::ModifiedEvent, this->Callback);
}
this->ResetBounds();
this->ComputePoints();
}
......
......@@ -44,6 +44,12 @@ vtkControlPointsItem::vtkControlPointsItem()
this->Callback->SetClientData(this);
this->Callback->SetCallback(
vtkControlPointsItem::CallComputePoints);
this->Bounds[0] = this->Bounds[2] = 0.;
this->Bounds[1] = this->Bounds[3] = -1.;
this->UserBounds[0] = this->UserBounds[2] = 0.;
this->UserBounds[1] = this->UserBounds[3] = -1.;
this->ScreenPointRadius = 6.f;
this->Transform = vtkTransform2D::New();
......@@ -81,20 +87,19 @@ void vtkControlPointsItem::PrintSelf(ostream &os, vtkIndent indent)
//-----------------------------------------------------------------------------
void vtkControlPointsItem::GetBounds(double bounds[4])
{
if (this->BoundsMTime.GetMTime() < this->GetControlPointsMTime())
if (this->UserBounds[0] <= this->UserBounds[1] &&
this->UserBounds[2] <= this->UserBounds[3])
{
this->Bounds[0] = this->Bounds[2] = VTK_DOUBLE_MAX;
this->Bounds[1] = this->Bounds[3] = -VTK_DOUBLE_MAX;
for (vtkIdType i=0; i < this->GetNumberOfPoints(); ++i)
{
double point[4];
this->GetControlPoint(i, point);
this->Bounds[0] = std::min(this->Bounds[0], point[0]);
this->Bounds[1] = std::max(this->Bounds[1], point[0]);
this->Bounds[2] = std::min(this->Bounds[2], point[1]);
this->Bounds[3] = std::max(this->Bounds[3], point[1]);
}
this->BoundsMTime.Modified();
bounds[0] = this->UserBounds[0];
bounds[1] = this->UserBounds[1];
bounds[2] = this->UserBounds[2];
bounds[3] = this->UserBounds[3];
return;
}
if (this->Bounds[0] > this->Bounds[1] ||
this->Bounds[2] > this->Bounds[3])
{
this->ComputeBounds();
}
bounds[0] = this->Bounds[0];
bounds[1] = this->Bounds[1];
......@@ -102,6 +107,32 @@ void vtkControlPointsItem::GetBounds(double bounds[4])
bounds[3] = this->Bounds[3];
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::ResetBounds()
{
this->Bounds[0] = 0.;
this->Bounds[1] = -1.;
this->Bounds[2] = 0.;
this->Bounds[3] = -1.;
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::ComputeBounds()
{
this->Bounds[0] = this->Bounds[2] = VTK_DOUBLE_MAX;
this->Bounds[1] = this->Bounds[3] = -VTK_DOUBLE_MAX;
for (vtkIdType i=0; i < this->GetNumberOfPoints(); ++i)
{
double point[4];
this->GetControlPoint(i, point);
this->Bounds[0] = std::min(this->Bounds[0], point[0]);
this->Bounds[1] = std::max(this->Bounds[1], point[0]);
this->Bounds[2] = std::min(this->Bounds[2], point[1]);
this->Bounds[3] = std::max(this->Bounds[3], point[1]);
this->Modified();
}
}
//-----------------------------------------------------------------------------
bool vtkControlPointsItem::Paint(vtkContext2D* painter)
{
......@@ -191,8 +222,53 @@ void vtkControlPointsItem::ComputePoints()
//-----------------------------------------------------------------------------
bool vtkControlPointsItem::Hit(const vtkContextMouseEvent &mouse)
{
return mouse.Pos[0] <= 1. && mouse.Pos[0] >= 0. &&
mouse.Pos[1] <= 1. && mouse.Pos[1] >= 0.;
double pos[2];
pos[0] = mouse.Pos[0];
pos[1] = mouse.Pos[1];
bool clamped = this->ClampPos(pos);
if (!clamped)
{
return true;
}
// maybe the cursor is over the first or last point (which could be outside
// the bounds because of the screen point size).
pos[0] = mouse.Pos[0];
pos[1] = mouse.Pos[1];
if (this->IsOverPoint(pos, 0) ||
this->IsOverPoint(pos, this->GetNumberOfPoints() - 1))
{
return true;
}
return false;
}
//-----------------------------------------------------------------------------
bool vtkControlPointsItem::ClampPos(double pos[2])
{
double bounds[4];
this->GetBounds(bounds);
bool clamped = false;
if (pos[0] < bounds[0])
{
pos[0] = bounds[0];
clamped = true;
}
if (pos[0] > bounds[1])
{
pos[0] = bounds[1];
clamped = true;
}
if (pos[1] < 0.)
{
pos[1] = 0.;
clamped = true;
}
if (pos[1] > 1.)
{
pos[1] = 1.;
clamped = true;
}
return clamped;
}
//-----------------------------------------------------------------------------
......@@ -421,11 +497,37 @@ vtkIdType vtkControlPointsItem::FindPoint(double* pos, double tolerance)
}
*/
//-----------------------------------------------------------------------------
bool vtkControlPointsItem::IsOverPoint(double* pos, vtkIdType pointId)
{
if (pointId < 0 || pointId >= this->GetNumberOfPoints())
{
return false;
}
double screenPos[2];
this->Transform->TransformPoints(pos, screenPos, 1);
double point[4];
this->GetControlPoint(pointId, point);
double screenPoint[2];
this->Transform->TransformPoints(point, screenPoint, 1);
double distance2 =
(screenPoint[0] - screenPos[0]) * (screenPoint[0] - screenPos[0]) +
(screenPoint[1] - screenPos[1]) * (screenPoint[1] - screenPos[1]);
double tolerance = 1.3;
double radius2 = this->ScreenPointRadius * this->ScreenPointRadius
* tolerance * tolerance;
return distance2 <= radius2;
}
//-----------------------------------------------------------------------------
vtkIdType vtkControlPointsItem::FindPoint(double* pos)
{
double tolerance = 1.3;
double radius = this->ScreenPointRadius * this->ScreenPointRadius * tolerance * tolerance;
double radius2 = this->ScreenPointRadius * this->ScreenPointRadius
* tolerance * tolerance;
double screenPos[2];
this->Transform->TransformPoints(pos, screenPos, 1);
vtkIdType pointId = -1;
......@@ -437,19 +539,19 @@ vtkIdType vtkControlPointsItem::FindPoint(double* pos)
this->GetControlPoint(i, point);
double screenPoint[2];
this->Transform->TransformPoints(point, screenPoint, 1);
double distance =
double distance2 =
(screenPoint[0] - screenPos[0]) * (screenPoint[0] - screenPos[0]) +
(screenPoint[1] - screenPos[1]) * (screenPoint[1] - screenPos[1]);
if (distance <= radius)
if (distance2 <= radius2)
{
if (distance == 0.)
if (distance2 == 0.)
{// we found the best match ever
return i;
}
else if (distance < minDist)
else if (distance2 < minDist)
{// we found something not too bad, maybe we can find closer
pointId = i;
minDist = distance;
minDist = distance2;
}
}
// don't search any further if the x is already too large
......@@ -584,8 +686,7 @@ bool vtkControlPointsItem::MouseButtonPressEvent(const vtkContextMouseEvent &mou
&& this->Selection->GetNumberOfTuples() <= 1
&& !this->StrokeMode)
{
pos[0] = std::min(std::max(pos[0], 0.), 1.);
pos[1] = std::min(std::max(pos[1], 0.), 1.);
this->ClampPos(pos);
vtkIdType addedPoint = this->AddPoint(pos);
this->SetCurrentPoint(addedPoint);
return true;
......@@ -723,8 +824,9 @@ vtkIdType vtkControlPointsItem::MovePoint(vtkIdType point, const vtkVector2f& ne
// Make sure the new point is inside the boundaries of the function
double boundedPos[2];
boundedPos[0] = std::min(std::max(newPos[0], 0.f), 1.f);
boundedPos[1] = std::min(std::max(newPos[1], 0.f), 1.f);
boundedPos[0] = newPos[0];
boundedPos[1] = newPos[1];
this->ClampPos(boundedPos);
if (!this->SwitchPointsMode)
{
......@@ -827,8 +929,9 @@ void vtkControlPointsItem::MovePoints(float tX, float tY)
void vtkControlPointsItem::Stroke(const vtkVector2f& newPos)
{
double pos[2];
pos[0] = std::min(std::max(newPos[0], 0.f), 1.f);
pos[1] = std::min(std::max(newPos[1], 0.f), 1.f);
pos[0] = newPos[0];
pos[1] = newPos[1];
this->ClampPos(pos);
// last point
if (this->CurrentPoint != -1)
......
......@@ -46,8 +46,16 @@ public:
// Description:
// Bounds of the item, typically the bound of all the control points
// except if custom bounds have been set \sa SetUserBounds.
virtual void GetBounds(double bounds[4]);
// Description:
// Set custom bounds, except if bounds are invalid, bounds will be
// automatically computed based on the range of the control points
// Invalid bounds by default.
vtkSetVector4Macro(UserBounds, double);
vtkGetVector4Macro(UserBounds, double)
// Description:
// Paint the points with a fixed size (cosmetic) which doesn't depend
// on the scene zoom factor. Selected and unselected points are drawn
......@@ -102,6 +110,12 @@ public:
// based on the screen point size.
vtkIdType FindPoint(double* pos);
// Description:
// Returns true if pos is above the pointId point, false otherwise.
// It uses the size of the drawn point. To search what point is under the pos,
// use the more efficient \sa FindPoint() instead.
bool IsOverPoint(double* pos, vtkIdType pointId);
// Description:
// Returns the id of the control point exactly matching pos, -1 if not found.
vtkIdType GetControlPointId(double* pos);
......@@ -152,6 +166,12 @@ public:
// Description:
// Sets the current point selected.
void SetCurrentPoint(vtkIdType index);
// Description:
// Recompute the bounds next time they are requested.
// You shouldn't have to call it but it is provided for rare cases.
void ResetBounds();
protected:
vtkControlPointsItem();
virtual ~vtkControlPointsItem();
......@@ -168,6 +188,11 @@ protected:
// Returns true if the supplied x, y coordinate is on a control point.
virtual bool Hit(const vtkContextMouseEvent &mouse);
// Description:
// Clamp the given 2D pos into the bounds of the function.
// Return true if the pos has been clamped, false otherwise.
bool ClampPos(double pos[2]);
// Description:
// Internal function that paints a collection of points and optionally
// excludes some.
......@@ -197,7 +222,8 @@ protected:
vtkIdType CurrentPoint;
double Bounds[4];
vtkTimeStamp BoundsMTime; // Time at which bounds computed
double UserBounds[4];
vtkTransform2D* Transform;
float ScreenPointRadius;
float ItemPointRadius2;
......@@ -215,6 +241,7 @@ private:
void operator=(const vtkControlPointsItem &); // Not implemented.
vtkIdType RemovePointId(vtkIdType pointId);
void ComputeBounds();
};
#endif
......@@ -84,6 +84,7 @@ void vtkPiecewiseControlPointsItem::SetPiecewiseFunction(vtkPiecewiseFunction* t
{
this->PiecewiseFunction->AddObserver(vtkCommand::ModifiedEvent, this->Callback);
}
this->ResetBounds();
this->ComputePoints();
}
......
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