Commit 16185208 authored by Andras Lasso's avatar Andras Lasso
Browse files

Fix vtkChartXY axis updates

API improvement:

vtkAxis did not have an API to change minimum and maximum value
with one vtkChart::UpdateRange event.
This lead to inability to precisely shift an axis without temporarily
changing its range width (distance between minimum and maximum value),
and complexity and inefficiency when synchronizing axes
between multiple charts.

SetRange and SetUnscaledRange methods now invoke only one
vtkChart::UpdateRange event (after both minimum and maximum values
are updated).

Fixing minor issues:

1. Added a missing vtkCommand::InteractionEvent invocation
when vtkChartXY axes range are adjusted using ZoomAxis action
(this event indicates that the user adjusted axes and so the
application can propagate this change to other charts).

2. Fixed vtkChartXY transform computation logic

vtkChartXY unnecessarily recomputed transforms when axes
were modified after the chart's last modified timestamp.
ALso, vtkChartXY never recomputed transforms when chart
properties changed after axes changed, even when
recomputation would have been necessary.
parent 6a6e24e2
......@@ -719,8 +719,30 @@ void vtkAxis::SetUnscaledMaximumLimit(double highest)
//-----------------------------------------------------------------------------
void vtkAxis::SetRange(double minimum, double maximum)
{
this->SetMinimum(minimum);
this->SetMaximum(maximum);
bool rangeModified = false;
minimum = std::max(minimum, this->MinimumLimit);
if (this->Minimum != minimum)
{
this->Minimum = minimum;
this->UnscaledMinimum = this->LogScaleActive ? pow(10., this->Minimum) : this->Minimum;
rangeModified = true;
}
maximum = std::min(maximum, this->MaximumLimit);
if (this->Maximum != maximum)
{
this->Maximum = maximum;
this->UnscaledMaximum = this->LogScaleActive ? pow(10., this->Maximum) : this->Maximum;
rangeModified = true;
}
if (rangeModified)
{
this->UsingNiceMinMax = false;
this->TickMarksDirty = true;
this->Modified();
this->InvokeEvent(vtkChart::UpdateRange);
}
}
//-----------------------------------------------------------------------------
......@@ -728,16 +750,38 @@ void vtkAxis::SetRange(double *range)
{
if (range)
{
this->SetMinimum(range[0]);
this->SetMaximum(range[1]);
this->SetRange(range[0], range[1]);
}
}
//-----------------------------------------------------------------------------
void vtkAxis::SetUnscaledRange(double minimum, double maximum)
{
this->SetUnscaledMinimum(minimum);
this->SetUnscaledMaximum(maximum);
bool rangeModified = false;
minimum = std::max(minimum, this->UnscaledMinimumLimit);
if (this->UnscaledMinimum != minimum)
{
this->UnscaledMinimum = minimum;
this->UpdateLogScaleActive(true);
rangeModified = true;
}
maximum = std::min(maximum, this->UnscaledMaximumLimit);
if (this->UnscaledMaximum != maximum)
{
this->UnscaledMaximum = maximum;
this->UpdateLogScaleActive(true);
rangeModified = true;
}
if (rangeModified)
{
this->UsingNiceMinMax = false;
this->TickMarksDirty = true;
this->Modified();
this->InvokeEvent(vtkChart::UpdateRange);
}
}
//-----------------------------------------------------------------------------
......@@ -745,8 +789,7 @@ void vtkAxis::SetUnscaledRange(double *range)
{
if (range)
{
this->SetUnscaledMinimum(range[0]);
this->SetUnscaledMaximum(range[1]);
this->SetUnscaledRange(range[0], range[1]);
}
}
......@@ -1086,6 +1129,19 @@ void vtkAxis::UpdateLogScaleActive(bool alwaysUpdateMinMaxFromUnscaled)
// The limit is on the other side of 0 relative to the data...
// move it to the same side as the data.
// Specifically, allow scrolling equal to the width of the plot.
// Note: There may be something wrong with this logic,
// as calling UpdateLogScaleActive(true) first will set
// this->NonLogUnscaledMinLimit = this->UnscaledMinimumLimit
// but when it is called again, it will set
// this->NonLogUnscaledMinLimit = 0.
// If this->NonLogUnscaledMinLimit should be set to 0 then
// it should be set immediately (on the first call).
// If the original this->UnscaledMinimumLimit needs to be preserved
// then the current behavior is broken, as the value is not preserved
// after calling this method multiple times (the method is usually
// called twice: first for the minimum, then for the maximum value).
this->MinimumLimit = -vtkMath::Inf();
this->NonLogUnscaledMinLimit = this->UnscaledMinimumLimit;
this->UnscaledMinimumLimit = 0.;
......
......@@ -104,6 +104,7 @@ public:
vtkSmartPointer<vtkColorSeries> Colors; // Colors in the chart
vtkSmartPointer<vtkContextClip> Clip; // Colors in the chart
int Borders[4];
vtkTimeStamp TransformCalculatedTime;
};
//-----------------------------------------------------------------------------
......@@ -376,10 +377,10 @@ bool vtkChartXY::Paint(vtkContext2D* painter)
this->UpdateLayout(painter);
// Axes may have changed during updateLayout
if (this->MTime < this->ChartPrivate->axes[0]->GetMTime() ||
this->MTime < this->ChartPrivate->axes[1]->GetMTime() ||
this->MTime < this->ChartPrivate->axes[2]->GetMTime() ||
this->MTime < this->ChartPrivate->axes[3]->GetMTime())
if (this->ChartPrivate->TransformCalculatedTime < this->ChartPrivate->axes[0]->GetMTime() ||
this->ChartPrivate->TransformCalculatedTime < this->ChartPrivate->axes[1]->GetMTime() ||
this->ChartPrivate->TransformCalculatedTime < this->ChartPrivate->axes[2]->GetMTime() ||
this->ChartPrivate->TransformCalculatedTime < this->ChartPrivate->axes[3]->GetMTime())
{
// Cause the plot transform to be recalculated if necessary
recalculateTransform = true;
......@@ -587,6 +588,7 @@ void vtkChartXY::RecalculatePlotTransforms()
}
}
this->PlotTransformValid = true;
this->ChartPrivate->TransformCalculatedTime.Modified();
}
//-----------------------------------------------------------------------------
......@@ -1494,10 +1496,8 @@ bool vtkChartXY::MouseMoveEvent(const vtkContextMouseEvent& mouse)
: std::max(delta[0], xAxis->GetMinimumLimit() - xAxis->GetMinimum());
delta[1] = delta[1] > 0 ? std::min(delta[1], yAxis->GetMaximumLimit() - yAxis->GetMaximum())
: std::max(delta[1], yAxis->GetMinimumLimit() - yAxis->GetMinimum());
xAxis->SetMinimum(xAxis->GetMinimum() + delta[0]);
xAxis->SetMaximum(xAxis->GetMaximum() + delta[0]);
yAxis->SetMinimum(yAxis->GetMinimum() + delta[1]);
yAxis->SetMaximum(yAxis->GetMaximum() + delta[1]);
xAxis->SetRange(xAxis->GetMinimum() + delta[0], xAxis->GetMaximum() + delta[0]);
yAxis->SetRange(yAxis->GetMinimum() + delta[1], yAxis->GetMaximum() + delta[1]);
if (this->ChartPrivate->PlotCorners.size() == 2)
{
......@@ -1518,8 +1518,7 @@ bool vtkChartXY::MouseMoveEvent(const vtkContextMouseEvent& mouse)
// Now move the axes and recalculate the transform
delta[1] = delta[1] > 0 ? std::min(delta[1], yAxis->GetMaximumLimit() - yAxis->GetMaximum())
: std::max(delta[1], yAxis->GetMinimumLimit() - yAxis->GetMinimum());
yAxis->SetMinimum(yAxis->GetMinimum() + delta[1]);
yAxis->SetMaximum(yAxis->GetMaximum() + delta[1]);
yAxis->SetRange(yAxis->GetMinimum() + delta[1], yAxis->GetMaximum() + delta[1]);
}
else if (this->ChartPrivate->PlotCorners.size() > 2)
{
......@@ -1543,10 +1542,8 @@ bool vtkChartXY::MouseMoveEvent(const vtkContextMouseEvent& mouse)
: std::max(delta[0], xAxis->GetMinimumLimit() - xAxis->GetMinimum());
delta[1] = delta[1] > 0 ? std::min(delta[1], yAxis->GetMaximumLimit() - yAxis->GetMaximum())
: std::max(delta[1], yAxis->GetMinimumLimit() - yAxis->GetMinimum());
xAxis->SetMinimum(xAxis->GetMinimum() + delta[0]);
xAxis->SetMaximum(xAxis->GetMaximum() + delta[0]);
yAxis->SetMinimum(yAxis->GetMinimum() + delta[1]);
yAxis->SetMaximum(yAxis->GetMaximum() + delta[1]);
xAxis->SetRange(xAxis->GetMinimum() + delta[0], xAxis->GetMaximum() + delta[0]);
yAxis->SetRange(yAxis->GetMinimum() + delta[1], yAxis->GetMaximum() + delta[1]);
}
this->RecalculatePlotTransforms();
......@@ -1606,8 +1603,7 @@ bool vtkChartXY::MouseMoveEvent(const vtkContextMouseEvent& mouse)
min -= delta * frac;
max += delta * frac;
}
axis->SetMinimum(min);
axis->SetMaximum(max);
axis->SetRange(min, max);
axis->RecalculateTickSpacing();
}
......@@ -1615,6 +1611,8 @@ bool vtkChartXY::MouseMoveEvent(const vtkContextMouseEvent& mouse)
// Mark the scene as dirty
this->Scene->SetDirty(true);
this->InvokeEvent(vtkCommand::InteractionEvent);
}
else if (mouse.GetButton() == this->Actions.SelectPolygon())
{
......@@ -2178,23 +2176,23 @@ void vtkChartXY::ZoomInAxes(vtkAxis* x, vtkAxis* y, float* originf, float* maxf)
// Ensure we preserve the directionality of the axes
if (x->GetMaximum() > x->GetMinimum())
{
x->SetMaximum(torigin[0] > tmax[0] ? torigin[0] : tmax[0]);
x->SetMinimum(torigin[0] < tmax[0] ? torigin[0] : tmax[0]);
x->SetRange(torigin[0] < tmax[0] ? torigin[0] : tmax[0],
torigin[0] > tmax[0] ? torigin[0] : tmax[0]);
}
else
{
x->SetMaximum(torigin[0] < tmax[0] ? torigin[0] : tmax[0]);
x->SetMinimum(torigin[0] > tmax[0] ? torigin[0] : tmax[0]);
x->SetRange(torigin[0] > tmax[0] ? torigin[0] : tmax[0],
torigin[0] < tmax[0] ? torigin[0] : tmax[0]);
}
if (y->GetMaximum() > y->GetMinimum())
{
y->SetMaximum(torigin[1] > tmax[1] ? torigin[1] : tmax[1]);
y->SetMinimum(torigin[1] < tmax[1] ? torigin[1] : tmax[1]);
y->SetRange(torigin[1] < tmax[1] ? torigin[1] : tmax[1],
torigin[1] > tmax[1] ? torigin[1] : tmax[1]);
}
else
{
y->SetMaximum(torigin[1] < tmax[1] ? torigin[1] : tmax[1]);
y->SetMinimum(torigin[1] > tmax[1] ? torigin[1] : tmax[1]);
y->SetRange(torigin[1] > tmax[1] ? torigin[1] : tmax[1],
torigin[1] < tmax[1] ? torigin[1] : tmax[1]);
}
x->RecalculateTickSpacing();
y->RecalculateTickSpacing();
......@@ -2229,8 +2227,7 @@ bool vtkChartXY::MouseWheelEvent(const vtkContextMouseEvent&, int delta)
min -= delta * frac;
max += delta * frac;
}
axis->SetMinimum(min);
axis->SetMaximum(max);
axis->SetRange(min, max);
axis->RecalculateTickSpacing();
}
......
Supports Markdown
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