vtkChartMatrix.cxx 10.3 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
  ~PIMPL() = default;
33

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

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

void vtkChartMatrix::SetSize(const vtkVector2i &size)
{
130
  if (this->Size.GetX() != size.GetX() || this->Size.GetY() != size.GetY())
131
  {
132
    this->Size = size;
133
    if (size.GetX() * size.GetY() < static_cast<int>(this->Private->Charts.size()))
134
    {
135
      for (int i = static_cast<int>(this->Private->Charts.size() - 1);
136
           i >= size.GetX() * size.GetY(); --i)
137
      {
138 139
        this->RemoveItem(this->Private->Charts[i]);
      }
140
    }
141 142
    this->Private->Charts.resize(size.GetX() * size.GetY());
    this->Private->Spans.resize(size.GetX() * size.GetY(), vtkVector2i(1, 1));
143
    this->LayoutIsDirty = true;
144
  }
145 146
}

147 148 149 150 151 152 153 154 155
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;
}

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
void vtkChartMatrix::SetBorderLeft(int value)
{
  this->Borders[vtkAxis::LEFT] = value;
  this->LayoutIsDirty = true;
}

void vtkChartMatrix::SetBorderBottom(int value)
{
  this->Borders[vtkAxis::BOTTOM] = value;
  this->LayoutIsDirty = true;
}

void vtkChartMatrix::SetBorderRight(int value)
{
  this->Borders[vtkAxis::RIGHT] = value;
  this->LayoutIsDirty = true;
}

void vtkChartMatrix::SetBorderTop(int value)
{
  this->Borders[vtkAxis::TOP] = value;
  this->LayoutIsDirty = true;
}


181 182 183
void vtkChartMatrix::SetGutter(const vtkVector2f &gutter)
{
  this->Gutter = gutter;
184
  this->LayoutIsDirty = true;
185 186
}

187 188 189 190 191 192 193 194 195 196 197 198
void vtkChartMatrix::SetGutterX(float value)
{
  this->Gutter.SetX (value);
  this->LayoutIsDirty = true;
}

void vtkChartMatrix::SetGutterY(float value)
{
  this->Gutter.SetY (value);
  this->LayoutIsDirty = true;
}

199 200
void vtkChartMatrix::SetSpecificResize(const vtkVector2i& index, const vtkVector2f& resize)
{
201 202
  if (this->SpecificResize.find(index) == this->SpecificResize.end() ||
    this->SpecificResize[index] != resize)
203 204 205 206
    {
    this->SpecificResize[index] = resize;
    this->LayoutIsDirty = true;
    }
207 208 209 210
}

void vtkChartMatrix::ClearSpecificResizes()
{
211
  if (!this->SpecificResize.empty())
212 213 214 215
    {
    this->SpecificResize.clear();
    this->LayoutIsDirty = true;
    }
216 217
}

218 219 220 221 222 223 224
void vtkChartMatrix::Allocate()
{
  // Force allocation of all objects as vtkChartXY.
}

bool vtkChartMatrix::SetChart(const vtkVector2i &position, vtkChart *chart)
{
225
  if (position.GetX() < this->Size.GetX() && position.GetY() < this->Size.GetY())
226
  {
227
    size_t index = position.GetY() * this->Size.GetX() + position.GetX();
228
    if (this->Private->Charts[index])
229
    {
230
      this->RemoveItem(this->Private->Charts[index]);
231
    }
232 233
    this->Private->Charts[index] = chart;
    this->AddItem(chart);
234
    chart->SetLayoutStrategy(vtkChart::AXES_TO_RECT);
235
    return true;
236
  }
237
  else
238
  {
239
    return false;
240
  }
241 242 243 244
}

vtkChart* vtkChartMatrix::GetChart(const vtkVector2i &position)
{
245
  if (position.GetX() < this->Size.GetX() && position.GetY() < this->Size.GetY())
246
  {
247
    size_t index = position.GetY() * this->Size.GetX() + position.GetX();
248
    if (this->Private->Charts[index] == nullptr)
249
    {
250
      vtkNew<vtkChartXY> chart;
251 252
      this->Private->Charts[index] = chart;
      this->AddItem(chart);
253
      chart->SetLayoutStrategy(vtkChart::AXES_TO_RECT);
254
    }
255 256
    return this->Private->Charts[index];
  }
257
  else
258
  {
259
    return nullptr;
260
  }
261 262
}

263 264 265
bool vtkChartMatrix::SetChartSpan(const vtkVector2i& position,
                                  const vtkVector2i& span)
{
266 267
  if (this->Size.GetX() - position.GetX() - span.GetX() < 0 ||
      this->Size.GetY() - position.GetY() - span.GetY() < 0)
268
  {
269
    return false;
270
  }
271
  else
272
  {
273
    this->Private->Spans[position.GetY() * this->Size.GetX() + position.GetX()] = span;
274
    this->LayoutIsDirty = true;
275
    return true;
276
  }
277 278 279 280
}

vtkVector2i vtkChartMatrix::GetChartSpan(const vtkVector2i& position)
{
281 282
  size_t index = position.GetY() * this->Size.GetX() + position.GetX();
  if (position.GetX() < this->Size.GetX() && position.GetY() < this->Size.GetY())
283
  {
284
    return this->Private->Spans[index];
285
  }
286
  else
287
  {
288
    return vtkVector2i(0, 0);
289
  }
290 291
}

292 293
vtkVector2i vtkChartMatrix::GetChartIndex(const vtkVector2f &position)
{
294
  if (this->Size.GetX() > 0 && this->Size.GetY() > 0)
295
  {
296 297
    // Calculate the increments without the gutters/borders that must be left.
    vtkVector2f increments;
298 299
    increments.SetX((this->Private->Geometry.GetX() - (this->Size.GetX() - 1) *
                     this->Gutter.GetX() - this->Borders[vtkAxis::LEFT] -
300
                     this->Borders[vtkAxis::RIGHT]) /
301 302 303
                     this->Size.GetX());
    increments.SetY((this->Private->Geometry.GetY() - (this->Size.GetY() - 1) *
                     this->Gutter.GetY() - this->Borders[vtkAxis::TOP] -
304
                     this->Borders[vtkAxis::BOTTOM]) /
305
                     this->Size.GetY());
306 307 308

    float x = this->Borders[vtkAxis::LEFT];
    float y = this->Borders[vtkAxis::BOTTOM];
309
    for (int i = 0; i < this->Size.GetX(); ++i)
310
    {
311
      if (i > 0)
312
      {
313
        x += increments.GetX() + this->Gutter.GetX();
314
      }
315
      for (int j = 0; j < this->Size.GetY(); ++j)
316
      {
317
        if (j > 0)
318
        {
319
          y += increments.GetY() + this->Gutter.GetY();
320
        }
321
        else
322
        {
323
          y = this->Borders[vtkAxis::BOTTOM];
324
        }
325 326 327
        vtkVector2f resize(0., 0.);
        vtkVector2i key(i, j);
        if (this->SpecificResize.find(key) != this->SpecificResize.end())
328
        {
329
          resize = this->SpecificResize[key];
330
        }
331
        size_t index = j * this->Size.GetX() + i;
332
        if (this->Private->Charts[index])
333
        {
334 335
          vtkVector2i &span = this->Private->Spans[index];
          // Check if the supplied location is within this charts area.
336 337 338 339
          float x2 = x + resize.GetX();
          float y2 = y + resize.GetY();
          if (position.GetX() > x2 &&
              position.GetX() < (x2 + increments.GetX() * span.GetX() - resize.GetY()
340
                              + (span.GetX() - 1) * this->Gutter.GetX()) &&
341 342
              position.GetY() > y2 &&
              position.GetY() < (y2 + increments.GetY() * span.GetY() - resize.GetY()
343
                              + (span.GetY() - 1) * this->Gutter.GetY()))
344 345 346 347
            return vtkVector2i(i, j);
        }
      }
    }
348
  }
349 350 351
  return vtkVector2i(-1, -1);
}

352 353 354 355
void vtkChartMatrix::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}