vtkChartParallelCoordinates.cxx 23.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkChartParallelCoordinates.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkChartParallelCoordinates.h"

#include "vtkContext2D.h"
#include "vtkBrush.h"
#include "vtkPen.h"
#include "vtkContextScene.h"
22
#include "vtkContextMouseEvent.h"
23 24 25 26 27 28 29 30 31 32
#include "vtkTextProperty.h"
#include "vtkAxis.h"
#include "vtkPlotParallelCoordinates.h"
#include "vtkContextMapper2D.h"
#include "vtkSmartPointer.h"
#include "vtkTable.h"
#include "vtkDataArray.h"
#include "vtkIdTypeArray.h"
#include "vtkTransform2D.h"
#include "vtkObjectFactory.h"
33 34 35 36
#include "vtkCommand.h"
#include "vtkAnnotationLink.h"
#include "vtkSelection.h"
#include "vtkSelectionNode.h"
37
#include "vtkStringArray.h"
38

39 40
#include <vector>
#include <algorithm>
41 42 43 44 45 46

// Minimal storage class for STL containers etc.
class vtkChartParallelCoordinates::Private
{
public:
  Private()
47
  {
48 49 50
    this->Plot = vtkSmartPointer<vtkPlotParallelCoordinates>::New();
    this->Transform = vtkSmartPointer<vtkTransform2D>::New();
    this->CurrentAxis = -1;
51
    this->AxisResize = -1;
52
  }
53
  ~Private()
54
  {
55
    for (std::vector<vtkAxis *>::iterator it = this->Axes.begin();
56
         it != this->Axes.end(); ++it)
57
    {
58 59
      (*it)->Delete();
    }
60
  }
61 62
  vtkSmartPointer<vtkPlotParallelCoordinates> Plot;
  vtkSmartPointer<vtkTransform2D> Transform;
63 64
  std::vector<vtkAxis *> Axes;
  std::vector<vtkVector<float, 2> > AxesSelections;
65
  int CurrentAxis;
66
  int AxisResize;
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
};

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkChartParallelCoordinates);

//-----------------------------------------------------------------------------
vtkChartParallelCoordinates::vtkChartParallelCoordinates()
{
  this->Storage = new vtkChartParallelCoordinates::Private;
  this->Storage->Plot->SetParent(this);
  this->GeometryValid = false;
  this->Selection = vtkIdTypeArray::New();
  this->Storage->Plot->SetSelection(this->Selection);
82
  this->VisibleColumns = vtkStringArray::New();
83 84 85 86

  // Set up default mouse button assignments for parallel coordinates.
  this->SetActionToButton(vtkChart::PAN, vtkContextMouseEvent::RIGHT_BUTTON);
  this->SetActionToButton(vtkChart::SELECT, vtkContextMouseEvent::LEFT_BUTTON);
87 88 89 90 91 92 93 94
}

//-----------------------------------------------------------------------------
vtkChartParallelCoordinates::~vtkChartParallelCoordinates()
{
  this->Storage->Plot->SetSelection(NULL);
  delete this->Storage;
  this->Selection->Delete();
95
  this->VisibleColumns->Delete();
96 97 98 99 100 101 102
}

//-----------------------------------------------------------------------------
void vtkChartParallelCoordinates::Update()
{
  vtkTable* table = this->Storage->Plot->GetData()->GetInput();
  if (!table)
103
  {
104
    return;
105
  }
106

107 108
  if (table->GetMTime() < this->BuildTime && this->MTime < this->BuildTime &&
      this->GetScene()->GetMTime() < this->BuildTime)
109
  {
110
    return;
111
  }
112 113

  // Now we have a table, set up the axes accordingly, clear and build.
114 115
  if (static_cast<int>(this->Storage->Axes.size()) !=
      this->VisibleColumns->GetNumberOfTuples())
116
  {
117
    for (std::vector<vtkAxis *>::iterator it = this->Storage->Axes.begin();
118
         it != this->Storage->Axes.end(); ++it)
119
    {
120
      this->RemoveItem(*it);
121
      (*it)->Delete();
122
    }
123
    this->Storage->Axes.clear();
124
    this->Storage->AxesSelections.clear();
125

126
    for (int i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
127
    {
128 129
      vtkAxis* axis = vtkAxis::New();
      axis->SetPosition(vtkAxis::PARALLEL);
130
      this->AddItem(axis);
131
      this->Storage->Axes.push_back(axis);
132
    }
133 134
    this->Storage->AxesSelections.resize(this->Storage->Axes.size(),
                                         vtkVector2f(0, 0));
135
  }
136 137

  // Now set up their ranges and locations
138
  for (int i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
139
  {
140
    double range[2];
141
    vtkDataArray* array =
142 143
        vtkArrayDownCast<vtkDataArray>(table->GetColumnByName(
                                         this->VisibleColumns->GetValue(i)));
144
    if (array)
145
    {
146
      array->GetRange(range);
147
    }
148
    vtkAxis* axis = this->Storage->Axes[i];
149
    if (axis->GetBehavior() == 0)
150
    {
151 152
      axis->SetMinimum(range[0]);
      axis->SetMaximum(range[1]);
153
    }
154 155
    axis->SetTitle(this->VisibleColumns->GetValue(i));
  }
156

157 158
  this->GeometryValid = false;
  this->BuildTime.Modified();
159 160 161 162 163 164 165
}

//-----------------------------------------------------------------------------
bool vtkChartParallelCoordinates::Paint(vtkContext2D *painter)
{
  if (this->GetScene()->GetViewWidth() == 0 ||
      this->GetScene()->GetViewHeight() == 0 ||
166 167
      !this->Visible || !this->Storage->Plot->GetVisible() ||
      this->VisibleColumns->GetNumberOfTuples() < 2)
168
  {
169 170
    // The geometry of the chart must be valid before anything can be drawn
    return false;
171
  }
172 173 174 175

  this->Update();
  this->UpdateGeometry();

176 177 178
  // Handle selections
  vtkIdTypeArray *idArray = 0;
  if (this->AnnotationLink)
179
  {
180
    vtkSelection *selection = this->AnnotationLink->GetCurrentSelection();
181
    if (this->AnnotationLink->GetMTime() > this->Storage->Plot->GetMTime())
182
    {
183 184
      vtkSelectionNode *node = selection->GetNumberOfNodes() > 0?
        selection->GetNode(0) : NULL;
185 186
      idArray = node? vtkArrayDownCast<vtkIdTypeArray>(node->GetSelectionList())
                    : NULL;
187 188
      this->Storage->Plot->SetSelection(idArray);
    }
189
  }
190
  else
191
  {
192
    vtkDebugMacro("No annotation link set.");
193
  }
194

195
  painter->PushMatrix();
196
  painter->AppendTransform(this->Storage->Transform);
197 198 199 200
  this->Storage->Plot->Paint(painter);
  painter->PopMatrix();

  // Now we have a table, set up the axes accordingly, clear and build.
201
  for (std::vector<vtkAxis *>::iterator it = this->Storage->Axes.begin();
202
       it != this->Storage->Axes.end(); ++it)
203
  {
204
    (*it)->Paint(painter);
205
  }
206 207 208

  // If there is a selected axis, draw the highlight
  if (this->Storage->CurrentAxis >= 0)
209
  {
210 211 212 213
    painter->GetBrush()->SetColor(200, 200, 200, 200);
    vtkAxis* axis = this->Storage->Axes[this->Storage->CurrentAxis];
    painter->DrawRect(axis->GetPoint1()[0]-10, this->Point1[1],
                      20, this->Point2[1]-this->Point1[1]);
214
  }
215 216 217

  // Now draw our active selections
  for (size_t i = 0; i < this->Storage->AxesSelections.size(); ++i)
218
  {
219 220
    vtkVector<float, 2> &range = this->Storage->AxesSelections[i];
    if (range[0] != range[1])
221
    {
222
      painter->GetBrush()->SetColor(200, 20, 20, 220);
223 224 225 226 227 228 229 230
      float x = this->Storage->Axes[i]->GetPoint1()[0] - 5;
      float y = range[0];
      y *= this->Storage->Transform->GetMatrix()->GetElement(1, 1);
      y += this->Storage->Transform->GetMatrix()->GetElement(1, 2);
      float height = range[1] - range[0];
      height *= this->Storage->Transform->GetMatrix()->GetElement(1, 1);

      painter->DrawRect(x, y, 10, height);
231
    }
232
  }
233 234 235 236

  return true;
}

237
//-----------------------------------------------------------------------------
238
void vtkChartParallelCoordinates::SetColumnVisibility(const vtkStdString& name,
239 240 241
                                                      bool visible)
{
  if (visible)
242
  {
243
    for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
244
    {
245
      if (this->VisibleColumns->GetValue(i) == name)
246
      {
247 248 249
        // Already there, nothing more needs to be done
        return;
      }
250
    }
251 252 253 254
    // Add the column to the end of the list
    this->VisibleColumns->InsertNextValue(name);
    this->Modified();
    this->Update();
255
  }
256
  else
257
  {
258 259
    // Remove the value if present
    for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
260
    {
261
      if (this->VisibleColumns->GetValue(i) == name)
262
      {
263 264
        // Move all the later elements down by one, and reduce the size
        while (i < this->VisibleColumns->GetNumberOfTuples()-1)
265
        {
266 267
          this->VisibleColumns->SetValue(i, this->VisibleColumns->GetValue(i+1));
          ++i;
268
        }
269 270
        this->VisibleColumns->SetNumberOfTuples(
            this->VisibleColumns->GetNumberOfTuples()-1);
271
        if (this->Storage->CurrentAxis >= this->VisibleColumns->GetNumberOfTuples())
272
        {
273
          this->Storage->CurrentAxis = -1;
274
        }
275 276 277 278 279
        this->Modified();
        this->Update();
        return;
      }
    }
280
  }
281 282
}

283 284 285
//-----------------------------------------------------------------------------
void vtkChartParallelCoordinates::SetColumnVisibilityAll(bool visible)
{
286 287 288
  // We always need to clear the current visible columns.
  this->VisibleColumns->SetNumberOfTuples(0);
  this->Storage->CurrentAxis = -1;
289
  if (visible)
290
  {
291 292
    vtkTable *table = this->GetPlot(0)->GetInput();
    for (vtkIdType i = 0; i < table->GetNumberOfColumns(); ++i)
293
    {
294
      this->SetColumnVisibility(table->GetColumnName(i), visible);
295
    }
296
  }
297 298
}

299
//-----------------------------------------------------------------------------
300
bool vtkChartParallelCoordinates::GetColumnVisibility(const vtkStdString& name)
301 302
{
  for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
303
  {
304
    if (this->VisibleColumns->GetValue(i) == name)
305
    {
306 307
      return true;
    }
308
  }
309 310 311
  return false;
}

312 313 314 315 316 317 318
//-----------------------------------------------------------------------------
void vtkChartParallelCoordinates::SetPlot(vtkPlotParallelCoordinates *plot)
{
  this->Storage->Plot = plot;
  this->Storage->Plot->SetParent(this);
}

319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
//-----------------------------------------------------------------------------
vtkPlot* vtkChartParallelCoordinates::GetPlot(vtkIdType)
{
  return this->Storage->Plot;
}

//-----------------------------------------------------------------------------
vtkIdType vtkChartParallelCoordinates::GetNumberOfPlots()
{
  return 1;
}

//-----------------------------------------------------------------------------
vtkAxis* vtkChartParallelCoordinates::GetAxis(int index)
{
  if (index < this->GetNumberOfAxes())
335
  {
336
    return this->Storage->Axes[index];
337
  }
338
  else
339
  {
340
    return NULL;
341
  }
342 343 344 345 346 347 348 349 350 351 352
}

//-----------------------------------------------------------------------------
vtkIdType vtkChartParallelCoordinates::GetNumberOfAxes()
{
  return this->Storage->Axes.size();
}

//-----------------------------------------------------------------------------
void vtkChartParallelCoordinates::UpdateGeometry()
{
353 354
  vtkVector2i geometry(this->GetScene()->GetViewWidth(),
                       this->GetScene()->GetViewHeight());
355

356
  if (geometry.GetX() != this->Geometry[0] || geometry.GetY() != this->Geometry[1] ||
357
      !this->GeometryValid)
358
  {
359
    // Take up the entire window right now, this could be made configurable
360
    this->SetGeometry(geometry.GetData());
361 362 363 364

    vtkVector2i tileScale = this->Scene->GetLogicalTileScale();
    this->SetBorders(60 * tileScale.GetX(), 50 * tileScale.GetY(),
                     60 * tileScale.GetX(), 20 * tileScale.GetY());
365 366 367

    // Iterate through the axes and set them up to span the chart area.
    int xStep = (this->Point2[0] - this->Point1[0]) /
368
                (static_cast<int>(this->Storage->Axes.size())-1);
369 370 371
    int x =  this->Point1[0];

    for (size_t i = 0; i < this->Storage->Axes.size(); ++i)
372
    {
373 374 375
      vtkAxis* axis = this->Storage->Axes[i];
      axis->SetPoint1(x, this->Point1[1]);
      axis->SetPoint2(x, this->Point2[1]);
376
      if (axis->GetBehavior() == 0)
377
      {
378
        axis->AutoScale();
379
      }
380 381
      axis->Update();
      x += xStep;
382
    }
383 384 385 386

    this->GeometryValid = true;
    // Cause the plot transform to be recalculated if necessary
    this->CalculatePlotTransform();
387
    this->Storage->Plot->Update();
388
  }
389 390 391 392 393 394 395 396 397
}

//-----------------------------------------------------------------------------
void vtkChartParallelCoordinates::CalculatePlotTransform()
{
  // In the case of parallel coordinates everything is plotted in a normalized
  // system, where the range is from 0.0 to 1.0 in the y axis, and in screen
  // coordinates along the x axis.
  if (!this->Storage->Axes.size())
398
  {
399
    return;
400
  }
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421

  vtkAxis* axis = this->Storage->Axes[0];
  float *min = axis->GetPoint1();
  float *max = axis->GetPoint2();
  float yScale = 1.0f / (max[1] - min[1]);

  this->Storage->Transform->Identity();
  this->Storage->Transform->Translate(0, axis->GetPoint1()[1]);
  // Get the scale for the plot area from the x and y axes
  this->Storage->Transform->Scale(1.0, 1.0 / yScale);
}

//-----------------------------------------------------------------------------
void vtkChartParallelCoordinates::RecalculateBounds()
{
  return;
}

//-----------------------------------------------------------------------------
bool vtkChartParallelCoordinates::Hit(const vtkContextMouseEvent &mouse)
{
422 423 424 425 426
  vtkVector2i pos(mouse.GetScreenPos());
  if (pos[0] > this->Point1[0] - 10 &&
      pos[0] < this->Point2[0] + 10 &&
      pos[1] > this->Point1[1] &&
      pos[1] < this->Point2[1])
427
  {
428
    return true;
429
  }
430
  else
431
  {
432
    return false;
433
  }
434 435 436 437 438 439 440 441 442 443 444
}

//-----------------------------------------------------------------------------
bool vtkChartParallelCoordinates::MouseEnterEvent(const vtkContextMouseEvent &)
{
  return true;
}

//-----------------------------------------------------------------------------
bool vtkChartParallelCoordinates::MouseMoveEvent(const vtkContextMouseEvent &mouse)
{
445
  if (mouse.GetButton() == this->Actions.Select())
446
  {
447 448
    // If an axis is selected, then lets try to narrow down a selection...
    if (this->Storage->CurrentAxis >= 0)
449
    {
450 451 452 453
      vtkVector<float, 2> &range =
          this->Storage->AxesSelections[this->Storage->CurrentAxis];

      // Normalize the coordinates
454
      float current = mouse.GetScenePos().GetY();
455 456 457 458
      current -= this->Storage->Transform->GetMatrix()->GetElement(1, 2);
      current /= this->Storage->Transform->GetMatrix()->GetElement(1, 1);

      if (current > 1.0f)
459
      {
460
        range[1] = 1.0f;
461
      }
462
      else if (current < 0.0f)
463
      {
464
        range[1] = 0.0f;
465
      }
466
      else
467
      {
468
        range[1] = current;
469 470
      }
    }
471 472
    this->Scene->SetDirty(true);
  }
473
  else if (mouse.GetButton() == this->Actions.Pan())
474
  {
475
    vtkAxis* axis = this->Storage->Axes[this->Storage->CurrentAxis];
476
    if (this->Storage->AxisResize == 0)
477
    {
478
      // Move the axis in x
479
      float deltaX = mouse.GetScenePos().GetX() - mouse.GetLastScenePos().GetX();
480

481 482
      axis->SetPoint1(axis->GetPoint1()[0]+deltaX, axis->GetPoint1()[1]);
      axis->SetPoint2(axis->GetPoint2()[0]+deltaX, axis->GetPoint2()[1]);
483 484 485 486 487

      vtkAxis* leftAxis = this->Storage->CurrentAxis > 0 ?
        this->Storage->Axes[this->Storage->CurrentAxis-1] :
        NULL;

488 489 490
      vtkAxis* rightAxis =
          this->Storage->CurrentAxis < static_cast<int>(this->Storage->Axes.size())-1 ?
          this->Storage->Axes[this->Storage->CurrentAxis+1] : NULL;
491 492

      if (leftAxis && axis->GetPoint1()[0] < leftAxis->GetPoint1()[0])
493
      {
494 495
        this->SwapAxes(this->Storage->CurrentAxis,this->Storage->CurrentAxis-1);
        this->Storage->CurrentAxis--;
496
      }
497
      else if (rightAxis && axis->GetPoint1()[0] > rightAxis->GetPoint1()[0])
498
      {
499 500
        this->SwapAxes(this->Storage->CurrentAxis,this->Storage->CurrentAxis+1);
        this->Storage->CurrentAxis++;
501
      }
502
    }
503
    else if (this->Storage->AxisResize == 1)
504
    {
505
      // Modify the bottom axis range...
506
      float deltaY = mouse.GetScenePos().GetY() - mouse.GetLastScenePos().GetY();
507 508 509 510 511 512 513
      float scale = (axis->GetPoint2()[1]-axis->GetPoint1()[1]) /
                    (axis->GetMaximum() - axis->GetMinimum());
      axis->SetMinimum(axis->GetMinimum() - deltaY/scale);
      // If there is an active selection on the axis, remove it
      vtkVector<float, 2>& range =
          this->Storage->AxesSelections[this->Storage->CurrentAxis];
      if (range[0] != range[1])
514
      {
515 516
        range[0] = range[1] = 0.0f;
        this->ResetSelection();
517
      }
518 519 520 521 522

      // Now update everything that needs to be
      axis->Update();
      axis->RecalculateTickSpacing();
      this->Storage->Plot->Update();
523
    }
524
    else if (this->Storage->AxisResize == 2)
525
    {
526
      // Modify the bottom axis range...
527
      float deltaY = mouse.GetScenePos().GetY() - mouse.GetLastScenePos().GetY();
528 529 530 531 532 533 534
      float scale = (axis->GetPoint2()[1]-axis->GetPoint1()[1]) /
                    (axis->GetMaximum() - axis->GetMinimum());
      axis->SetMaximum(axis->GetMaximum() - deltaY/scale);
      // If there is an active selection on the axis, remove it
      vtkVector<float, 2>& range =
          this->Storage->AxesSelections[this->Storage->CurrentAxis];
      if (range[0] != range[1])
535
      {
536 537
        range[0] = range[1] = 0.0f;
        this->ResetSelection();
538
      }
539 540 541 542

      axis->Update();
      axis->RecalculateTickSpacing();
      this->Storage->Plot->Update();
543
    }
544 545
    this->Scene->SetDirty(true);
  }
546 547 548 549 550 551 552 553 554 555 556

  return true;
}

//-----------------------------------------------------------------------------
bool vtkChartParallelCoordinates::MouseLeaveEvent(const vtkContextMouseEvent &)
{
  return true;
}

//-----------------------------------------------------------------------------
557 558
bool vtkChartParallelCoordinates::MouseButtonPressEvent(
    const vtkContextMouseEvent& mouse)
559
{
560
  if (mouse.GetButton() == this->Actions.Select())
561
  {
562
    // Select an axis if we are within range
563 564
    if (mouse.GetScenePos()[1] > this->Point1[1] &&
        mouse.GetScenePos()[1] < this->Point2[1])
565
    {
566 567
      // Iterate over the axes, see if we are within 10 pixels of an axis
      for (size_t i = 0; i < this->Storage->Axes.size(); ++i)
568
      {
569
        vtkAxis* axis = this->Storage->Axes[i];
570 571
        if (axis->GetPoint1()[0]-10 < mouse.GetScenePos()[0] &&
            axis->GetPoint1()[0]+10 > mouse.GetScenePos()[0])
572
        {
573
          this->Storage->CurrentAxis = static_cast<int>(i);
574 575
          vtkVector<float, 2>& range = this->Storage->AxesSelections[i];
          if (range[0] != range[1])
576
          {
577 578
            range[0] = range[1] = 0.0f;
            this->ResetSelection();
579
          }
580 581

          // Transform into normalized coordinates
582
          float low = mouse.GetScenePos()[1];
583 584
          low -= this->Storage->Transform->GetMatrix()->GetElement(1, 2);
          low /= this->Storage->Transform->GetMatrix()->GetElement(1, 1);
585 586 587
          range[0] = range[1] = low;

          this->Scene->SetDirty(true);
588 589 590
          return true;
        }
      }
591
    }
592 593
    this->Storage->CurrentAxis = -1;
    this->Scene->SetDirty(true);
594
    return true;
595
  }
596
  else if (mouse.GetButton() == this->Actions.Pan())
597
  {
598 599 600
    // Middle mouse button - move and zoom the axes
    // Iterate over the axes, see if we are within 10 pixels of an axis
    for (size_t i = 0; i < this->Storage->Axes.size(); ++i)
601
    {
602
      vtkAxis* axis = this->Storage->Axes[i];
603 604
      if (axis->GetPoint1()[0]-10 < mouse.GetScenePos()[0] &&
          axis->GetPoint1()[0]+10 > mouse.GetScenePos()[0])
605
      {
606
        this->Storage->CurrentAxis = static_cast<int>(i);
607 608
        if (mouse.GetScenePos().GetY() > axis->GetPoint1()[1] &&
            mouse.GetScenePos().GetY() < axis->GetPoint1()[1] + 20)
609
        {
610 611
          // Resize the bottom of the axis
          this->Storage->AxisResize = 1;
612
        }
613 614
        else if (mouse.GetScenePos().GetY() < axis->GetPoint2()[1] &&
                 mouse.GetScenePos().GetY() > axis->GetPoint2()[1] - 20)
615
        {
616 617
          // Resize the top of the axis
          this->Storage->AxisResize = 2;
618
        }
619
        else
620
        {
621 622
          // Move the axis
          this->Storage->AxisResize = 0;
623 624
        }
      }
625
    }
626 627
    return true;
  }
628
  else
629
  {
630
    return false;
631
  }
632 633 634
}

//-----------------------------------------------------------------------------
635 636
bool vtkChartParallelCoordinates::MouseButtonReleaseEvent(
    const vtkContextMouseEvent& mouse)
637
{
638
  if (mouse.GetButton() == this->Actions.Select())
639
  {
640
    if (this->Storage->CurrentAxis >= 0)
641
    {
642 643 644
      vtkVector<float, 2> &range =
          this->Storage->AxesSelections[this->Storage->CurrentAxis];

645
      float final = mouse.GetScenePos()[1];
646 647
      final -= this->Storage->Transform->GetMatrix()->GetElement(1, 2);
      final /= this->Storage->Transform->GetMatrix()->GetElement(1, 1);
648 649

      // Set the final mouse position
650
      if (final > 1.0)
651
      {
652
        range[1] = 1.0;
653
      }
654
      else if (final < 0.0)
655
      {
656
        range[1] = 0.0;
657
      }
658
      else
659
      {
660
        range[1] = final;
661
      }
662

663
      if (range[0] == range[1])
664
      {
665
        this->ResetSelection();
666
      }
667
      else
668
      {
669 670
        // Add a new selection
        if (range[0] < range[1])
671
        {
672 673
          this->Storage->Plot->SetSelectionRange(this->Storage->CurrentAxis,
                                                 range[0], range[1]);
674
        }
675
        else
676
        {
677 678
          this->Storage->Plot->SetSelectionRange(this->Storage->CurrentAxis,
                                                 range[1], range[0]);
679
        }
680
      }
681

682
      if (this->AnnotationLink)
683
      {
684 685 686
        vtkSelection* selection = vtkSelection::New();
        vtkSelectionNode* node = vtkSelectionNode::New();
        selection->AddNode(node);
687 688 689
        node->SetContentType(vtkSelectionNode::INDICES);
        node->SetFieldType(vtkSelectionNode::POINT);

690 691 692 693
        node->SetSelectionList(this->Storage->Plot->GetSelection());
        this->AnnotationLink->SetCurrentSelection(selection);
        selection->Delete();
        node->Delete();
694
      }
695
      this->InvokeEvent(vtkCommand::SelectionChangedEvent);
696
      this->Scene->SetDirty(true);
697
    }
698 699
    return true;
  }
700
  else if (mouse.GetButton() == this->Actions.Pan())
701
  {
702
    this->Storage->CurrentAxis = -1;
703
    this->Storage->AxisResize = -1;
704
    return true;
705
  }
706 707 708 709 710 711 712 713 714 715
  return false;
}

//-----------------------------------------------------------------------------
bool vtkChartParallelCoordinates::MouseWheelEvent(const vtkContextMouseEvent &,
                                                  int)
{
  return true;
}

716 717 718 719 720 721 722 723 724
//-----------------------------------------------------------------------------
void vtkChartParallelCoordinates::ResetSelection()
{
  // This function takes care of resetting the selection of the chart
  // Reset the axes.
  this->Storage->Plot->ResetSelectionRange();

  // Now set the remaining selections that were kept
  for (size_t i = 0; i < this->Storage->AxesSelections.size(); ++i)
725
  {
726 727
    vtkVector<float, 2> &range = this->Storage->AxesSelections[i];
    if (range[0] != range[1])
728
    {
729 730
      // Process the selected range and display this
      if (range[0] < range[1])
731
      {
732 733
        this->Storage->Plot->SetSelectionRange(static_cast<int>(i),
                                               range[0], range[1]);
734
      }
735
      else
736
      {
737 738 739 740
        this->Storage->Plot->SetSelectionRange(static_cast<int>(i),
                                               range[1], range[0]);
      }
    }
741
  }
742 743
}

744 745 746 747 748
//-----------------------------------------------------------------------------
void vtkChartParallelCoordinates::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770

//-----------------------------------------------------------------------------
void vtkChartParallelCoordinates::SwapAxes(int a1, int a2)
{
  // only neighboring axes
  if (abs(a1-a2) != 1)
    return;

  vtkAxis* axisTmp = this->Storage->Axes[a1];
  this->Storage->Axes[a1] = this->Storage->Axes[a2];
  this->Storage->Axes[a2] = axisTmp;

  vtkVector<float, 2> selTmp = this->Storage->AxesSelections[a1];
  this->Storage->AxesSelections[a1] = this->Storage->AxesSelections[a2];
  this->Storage->AxesSelections[a2] = selTmp;

  vtkStdString colTmp = this->VisibleColumns->GetValue(a1);
  this->VisibleColumns->SetValue(a1,this->VisibleColumns->GetValue(a2));
  this->VisibleColumns->SetValue(a2,colTmp);

  this->Storage->Plot->Update();
}