vtkChartMatrix.cxx 8.37 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkChartMatrix.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 "vtkChartMatrix.h"

#include "vtkChartXY.h"
19
#include "vtkNew.h"
20 21 22
#include "vtkSmartPointer.h"
#include "vtkContext2D.h"
#include "vtkContextScene.h"
23
#include "vtkAxis.h"
24 25 26 27 28 29 30
#include "vtkObjectFactory.h"

#include <vector>

class vtkChartMatrix::PIMPL
{
public:
31
  PIMPL() : Geometry(0, 0) {}
32 33
  ~PIMPL() {}

34
  // Container for the vtkChart objects that make up the matrix.
35
  std::vector< vtkSmartPointer<vtkChart> > Charts;
36 37
  // Spans of the charts in the matrix, default is 1x1.
  std::vector< vtkVector2i > Spans;
38 39 40 41 42
  vtkVector2i Geometry;
};

vtkStandardNewMacro(vtkChartMatrix)

43
vtkChartMatrix::vtkChartMatrix() : Size(0, 0), Gutter(15.0, 15.0)
44 45
{
  this->Private = new PIMPL;
46 47
  this->Borders[vtkAxis::LEFT] = 50;
  this->Borders[vtkAxis::BOTTOM] = 40;
48
  this->Borders[vtkAxis::RIGHT] = 50;
49
  this->Borders[vtkAxis::TOP] = 40;
50
  this->LayoutIsDirty = true;
51 52 53 54 55 56 57 58 59 60 61 62 63 64
}

vtkChartMatrix::~vtkChartMatrix()
{
  delete this->Private;
}

void vtkChartMatrix::Update()
{

}

bool vtkChartMatrix::Paint(vtkContext2D *painter)
{
65 66
  if (this->LayoutIsDirty ||
      this->GetScene()->GetSceneWidth() != this->Private->Geometry.X() ||
67 68 69 70 71
      this->GetScene()->GetSceneHeight() != this->Private->Geometry.Y())
    {
    // Update the chart element positions
    this->Private->Geometry.Set(this->GetScene()->GetSceneWidth(),
                                this->GetScene()->GetSceneHeight());
72
    if (this->Size.X() > 0 && this->Size.Y() > 0)
73
      {
74 75 76 77 78 79 80 81 82 83 84 85 86
      // Calculate the increments without the gutters/borders that must be left
      vtkVector2f increments;
      increments.SetX((this->Private->Geometry.X() - (this->Size.X() - 1) *
                       this->Gutter.X() - this->Borders[vtkAxis::LEFT] -
                       this->Borders[vtkAxis::RIGHT]) /
                      this->Size.X());
      increments.SetY((this->Private->Geometry.Y() - (this->Size.Y() - 1) *
                       this->Gutter.Y() - this->Borders[vtkAxis::TOP] -
                       this->Borders[vtkAxis::BOTTOM]) /
                      this->Size.Y());

      float x = this->Borders[vtkAxis::LEFT];
      float y = this->Borders[vtkAxis::BOTTOM];
87
      for (int i = 0; i < this->Size.X(); ++i)
88
        {
89 90 91 92
        if (i > 0)
          {
          x += increments.X() + this->Gutter.X();
          }
93
        for (int j = 0; j < this->Size.Y(); ++j)
94
          {
95 96 97 98 99 100 101 102
          if (j > 0)
            {
            y += increments.Y() + this->Gutter.Y();
            }
          else
            {
            y = this->Borders[vtkAxis::BOTTOM];
            }
103 104 105 106
          size_t index = j * this->Size.X() + i;
          if (this->Private->Charts[index])
            {
            vtkChart *chart = this->Private->Charts[index];
107
            vtkVector2i &span = this->Private->Spans[index];
108
            chart->SetSize(vtkRectf(x, y,
109 110 111 112
                                    increments.X() * span.X() +
                                    (span.X() - 1) * this->Gutter.X(),
                                    increments.Y() * span.Y() +
                                    (span.Y() - 1) * this->Gutter.Y()));
113
            }
114 115 116
          }
        }
      }
117
    this->LayoutIsDirty = false;
118 119 120 121 122 123 124 125 126
    }
  return Superclass::Paint(painter);
}

void vtkChartMatrix::SetSize(const vtkVector2i &size)
{
  if (this->Size.X() != size.X() || this->Size.Y() != size.Y())
    {
    this->Size = size;
127 128 129 130 131 132 133 134
    if (size.X() * size.Y() < static_cast<int>(this->Private->Charts.size()))
      {
      for (int i = static_cast<int>(this->Private->Charts.size() - 1);
           i >= size.X() * size.Y(); --i)
        {
        this->RemoveItem(this->Private->Charts[i]);
        }
      }
135
    this->Private->Charts.resize(size.X() * size.Y());
136
    this->Private->Spans.resize(size.X() * size.Y(), vtkVector2i(1, 1));
137
    this->LayoutIsDirty = true;
138 139 140
    }
}

141 142 143 144 145 146 147 148 149
void vtkChartMatrix::SetBorders(int left, int bottom, int right, int top)
{
  this->Borders[vtkAxis::LEFT] = left;
  this->Borders[vtkAxis::BOTTOM] = bottom;
  this->Borders[vtkAxis::RIGHT] = right;
  this->Borders[vtkAxis::TOP] = top;
  this->LayoutIsDirty = true;
}

150 151 152
void vtkChartMatrix::SetGutter(const vtkVector2f &gutter)
{
  this->Gutter = gutter;
153
  this->LayoutIsDirty = true;
154 155
}

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
void vtkChartMatrix::Allocate()
{
  // Force allocation of all objects as vtkChartXY.
}

bool vtkChartMatrix::SetChart(const vtkVector2i &position, vtkChart *chart)
{
  if (position.X() < this->Size.X() && position.Y() < this->Size.Y())
    {
    size_t index = position.Y() * this->Size.X() + position.X();
    if (this->Private->Charts[index])
      {
      this->RemoveItem(this->Private->Charts[index]);
      }
    this->Private->Charts[index] = chart;
    this->AddItem(chart);
172
    chart->SetLayoutStrategy(vtkChart::AXES_TO_RECT);
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
    return true;
    }
  else
    {
    return false;
    }
}

vtkChart* vtkChartMatrix::GetChart(const vtkVector2i &position)
{
  if (position.X() < this->Size.X() && position.Y() < this->Size.Y())
    {
    size_t index = position.Y() * this->Size.X() + position.X();
    if (this->Private->Charts[index] == NULL)
      {
188 189 190
      vtkNew<vtkChartXY> chart;
      this->Private->Charts[index] = chart.GetPointer();
      this->AddItem(chart.GetPointer());
191
      chart->SetLayoutStrategy(vtkChart::AXES_TO_RECT);
192 193 194 195 196 197 198 199 200
      }
    return this->Private->Charts[index];
    }
  else
    {
    return NULL;
    }
}

201 202 203 204 205 206 207 208 209 210 211
bool vtkChartMatrix::SetChartSpan(const vtkVector2i& position,
                                  const vtkVector2i& span)
{
  if (this->Size.X() - position.X() - span.X() < 0 ||
      this->Size.Y() - position.Y() - span.Y() < 0)
    {
    return false;
    }
  else
    {
    this->Private->Spans[position.Y() * this->Size.X() + position.X()] = span;
212
    this->LayoutIsDirty = true;
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
    return true;
    }
}

vtkVector2i vtkChartMatrix::GetChartSpan(const vtkVector2i& position)
{
  size_t index = position.Y() * this->Size.X() + position.X();
  if (position.X() < this->Size.X() && position.Y() < this->Size.Y())
    {
    return this->Private->Spans[index];
    }
  else
    {
    return vtkVector2i(0, 0);
    }
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
vtkVector2i vtkChartMatrix::GetChartIndex(const vtkVector2f &position)
{
  if (this->Size.X() > 0 && this->Size.Y() > 0)
    {
    // Calculate the increments without the gutters/borders that must be left.
    vtkVector2f increments;
    increments.SetX((this->Private->Geometry.X() - (this->Size.X() - 1) *
                     this->Gutter.X() - this->Borders[vtkAxis::LEFT] -
                     this->Borders[vtkAxis::RIGHT]) /
                     this->Size.X());
    increments.SetY((this->Private->Geometry.Y() - (this->Size.Y() - 1) *
                     this->Gutter.Y() - this->Borders[vtkAxis::TOP] -
                     this->Borders[vtkAxis::BOTTOM]) /
                     this->Size.Y());

    float x = this->Borders[vtkAxis::LEFT];
    float y = this->Borders[vtkAxis::BOTTOM];
    for (int i = 0; i < this->Size.X(); ++i)
      {
      if (i > 0)
        {
        x += increments.X() + this->Gutter.X();
        }
      for (int j = 0; j < this->Size.Y(); ++j)
        {
        if (j > 0)
          {
          y += increments.Y() + this->Gutter.Y();
          }
        else
          {
          y = this->Borders[vtkAxis::BOTTOM];
          }
        size_t index = j * this->Size.X() + i;
        if (this->Private->Charts[index])
          {
          vtkVector2i &span = this->Private->Spans[index];
          // Check if the supplied location is within this charts area.
          if (position.X() > x &&
              position.X() < (x + increments.X() * span.X()
                              + (span.X() - 1) * this->Gutter.X()) &&
              position.Y() > y &&
              position.Y() < (y + increments.Y() * span.Y()
                              + (span.Y() - 1) * this->Gutter.Y()))
            return vtkVector2i(i, j);
          }
        }
      }
    }
  return vtkVector2i(-1, -1);
}

282 283 284 285
void vtkChartMatrix::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}