You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
9.0 KiB
C++
356 lines
9.0 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkVector.h
|
|
|
|
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.
|
|
|
|
=========================================================================*/
|
|
|
|
/**
|
|
* @class vtkRect
|
|
* @brief templated base type for storage of 2D rectangles.
|
|
*
|
|
*
|
|
* This class is a templated data type for storing and manipulating rectangles.
|
|
* The memory layout is a contiguous array of the specified type, such that a
|
|
* float[4] can be cast to a vtkRectf and manipulated. Also a float[12] could
|
|
* be cast and used as a vtkRectf[3].
|
|
*/
|
|
|
|
#ifndef vtkRect_h
|
|
#define vtkRect_h
|
|
|
|
#include "vtkVector.h"
|
|
|
|
#include "vtkMath.h" // for Min, Max
|
|
|
|
template <typename T>
|
|
class vtkRect : public vtkVector<T, 4>
|
|
{
|
|
public:
|
|
vtkRect() {}
|
|
|
|
vtkRect(const T& x, const T& y, const T& width, const T& height)
|
|
{
|
|
this->Data[0] = x;
|
|
this->Data[1] = y;
|
|
this->Data[2] = width;
|
|
this->Data[3] = height;
|
|
}
|
|
|
|
explicit vtkRect(const T* init)
|
|
: vtkVector<T, 4>(init)
|
|
{
|
|
}
|
|
|
|
//@{
|
|
/**
|
|
* Set the x, y components of the rectangle, and the width/height.
|
|
*/
|
|
void Set(const T& x, const T& y, const T& width, const T& height)
|
|
{
|
|
this->Data[0] = x;
|
|
this->Data[1] = y;
|
|
this->Data[2] = width;
|
|
this->Data[3] = height;
|
|
}
|
|
//@}
|
|
|
|
/**
|
|
* Set the x component of the rectangle bottom corner, i.e. element 0.
|
|
*/
|
|
void SetX(const T& x) { this->Data[0] = x; }
|
|
|
|
/**
|
|
* Get the x component of the rectangle bottom corner, i.e. element 0.
|
|
*/
|
|
const T& GetX() const { return this->Data[0]; }
|
|
|
|
/**
|
|
* Set the y component of the rectangle bottom corner, i.e. element 1.
|
|
*/
|
|
void SetY(const T& y) { this->Data[1] = y; }
|
|
|
|
/**
|
|
* Get the y component of the rectangle bottom corner, i.e. element 1.
|
|
*/
|
|
const T& GetY() const { return this->Data[1]; }
|
|
|
|
/**
|
|
* Set the width of the rectanle, i.e. element 2.
|
|
*/
|
|
void SetWidth(const T& width) { this->Data[2] = width; }
|
|
|
|
/**
|
|
* Get the width of the rectangle, i.e. element 2.
|
|
*/
|
|
const T& GetWidth() const { return this->Data[2]; }
|
|
|
|
/**
|
|
* Set the height of the rectangle, i.e. element 3.
|
|
*/
|
|
void SetHeight(const T& height) { this->Data[3] = height; }
|
|
|
|
/**
|
|
* Get the height of the rectangle, i.e. element 3.
|
|
*/
|
|
const T& GetHeight() const { return this->Data[3]; }
|
|
|
|
/**
|
|
* Get the left boundary of the rectangle along the X direction.
|
|
*/
|
|
const T& GetLeft() const { return this->Data[0]; }
|
|
|
|
/**
|
|
* Get the right boundary of the rectangle along the X direction.
|
|
*/
|
|
T GetRight() const { return this->Data[0] + this->Data[2]; }
|
|
|
|
/**
|
|
* Get the top boundary of the rectangle along the Y direction.
|
|
*/
|
|
T GetTop() const { return this->Data[1] + this->Data[3]; }
|
|
|
|
/**
|
|
* Get the bottom boundary of the rectangle along the Y direction.
|
|
*/
|
|
const T& GetBottom() const { return this->Data[1]; }
|
|
|
|
/**
|
|
* Get the bottom left corner of the rect as a vtkVector.
|
|
*/
|
|
vtkVector2<T> GetBottomLeft() const { return vtkVector2<T>(this->GetLeft(), this->GetBottom()); }
|
|
|
|
/**
|
|
* Get the top left corner of the rect as a vtkVector.
|
|
*/
|
|
vtkVector<T, 2> GetTopLeft() const { return vtkVector2<T>(this->GetLeft(), this->GetTop()); }
|
|
|
|
/**
|
|
* Get the bottom right corner of the rect as a vtkVector.
|
|
*/
|
|
vtkVector<T, 2> GetBottomRight() const
|
|
{
|
|
return vtkVector2<T>(this->GetRight(), this->GetBottom());
|
|
}
|
|
|
|
/**
|
|
* Get the bottom left corner of the rect as a vtkVector.
|
|
*/
|
|
vtkVector<T, 2> GetTopRight() const { return vtkVector2<T>(this->GetRight(), this->GetTop()); }
|
|
|
|
//@{
|
|
/**
|
|
* Expand this rect to contain the point passed in.
|
|
*/
|
|
void AddPoint(const T point[2])
|
|
{
|
|
// This code is written like this to ensure that adding a point gives
|
|
// exactly the same result as AddRect(vtkRect(x,y,0,0)
|
|
if (point[0] < this->GetX())
|
|
{
|
|
T dx = this->GetX() - point[0];
|
|
this->SetX(point[0]);
|
|
this->SetWidth(dx + this->GetWidth());
|
|
}
|
|
else if (point[0] > this->GetX())
|
|
{
|
|
// this->GetX() is already correct
|
|
T dx = point[0] - this->GetX();
|
|
this->SetWidth(vtkMath::Max(dx, this->GetWidth()));
|
|
}
|
|
//@}
|
|
|
|
if (point[1] < this->GetY())
|
|
{
|
|
T dy = this->GetY() - point[1];
|
|
this->SetY(point[1]);
|
|
this->SetHeight(dy + this->GetHeight());
|
|
}
|
|
else if (point[1] > this->GetY())
|
|
{
|
|
// this->GetY() is already correct
|
|
T dy = point[1] - this->GetY();
|
|
this->SetHeight(vtkMath::Max(dy, this->GetHeight()));
|
|
}
|
|
}
|
|
|
|
//@{
|
|
/**
|
|
* Expand this rect to contain the point passed in.
|
|
*/
|
|
void AddPoint(T x, T y)
|
|
{
|
|
T point[2] = { x, y };
|
|
this->AddPoint(point);
|
|
}
|
|
//@}
|
|
|
|
//@{
|
|
/**
|
|
* Expand this rect to contain the rect passed in.
|
|
*/
|
|
void AddRect(const vtkRect<T>& rect)
|
|
{
|
|
if (rect.GetX() < this->GetX())
|
|
{
|
|
T dx = this->GetX() - rect.GetX();
|
|
this->SetX(rect.GetX());
|
|
this->SetWidth(vtkMath::Max(dx + this->GetWidth(), rect.GetWidth()));
|
|
}
|
|
else if (rect.GetX() > this->GetX())
|
|
{
|
|
T dx = rect.GetX() - this->GetX();
|
|
// this->GetX() is already correct
|
|
this->SetWidth(vtkMath::Max(dx + rect.GetWidth(), this->GetWidth()));
|
|
}
|
|
else
|
|
{
|
|
// this->GetX() is already correct
|
|
this->SetWidth(vtkMath::Max(rect.GetWidth(), this->GetWidth()));
|
|
}
|
|
//@}
|
|
|
|
if (rect.GetY() < this->GetY())
|
|
{
|
|
T dy = this->GetY() - rect.GetY();
|
|
this->SetY(rect.GetY());
|
|
this->SetHeight(vtkMath::Max(dy + this->GetHeight(), rect.GetHeight()));
|
|
}
|
|
else if (rect.GetY() > this->GetY())
|
|
{
|
|
T dy = rect.GetY() - this->GetY();
|
|
// this->GetY() is already correct
|
|
this->SetHeight(vtkMath::Max(dy + rect.GetHeight(), this->GetHeight()));
|
|
}
|
|
else
|
|
{
|
|
// this->GetY() is already correct
|
|
this->SetHeight(vtkMath::Max(rect.GetHeight(), this->GetHeight()));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true if the rect argument overlaps this rect.
|
|
* If the upper bound of one rect is equal to the lower bound of
|
|
* the other rect, then this will return false (in that case, the
|
|
* rects would be considered to be adjacent but not overlapping).
|
|
*/
|
|
bool IntersectsWith(const vtkRect<T>& rect) const
|
|
{
|
|
bool intersects = true;
|
|
|
|
if (rect.GetX() < this->GetX())
|
|
{
|
|
T dx = this->GetX() - rect.GetX();
|
|
intersects &= (dx < rect.GetWidth());
|
|
}
|
|
else if (rect.GetX() > this->GetX())
|
|
{
|
|
T dx = rect.GetX() - this->GetX();
|
|
intersects &= (dx < this->GetWidth());
|
|
}
|
|
|
|
if (rect.GetY() < this->GetY())
|
|
{
|
|
T dy = this->GetY() - rect.GetY();
|
|
intersects &= (dy < rect.GetHeight());
|
|
}
|
|
else if (rect.GetY() > this->GetY())
|
|
{
|
|
T dy = rect.GetY() - this->GetY();
|
|
intersects &= (dy < this->GetHeight());
|
|
}
|
|
|
|
return intersects;
|
|
}
|
|
|
|
/**
|
|
* Move the rectangle, moving the bottom-left corner
|
|
* to the given position. The rectangles size remains unchanged.
|
|
*/
|
|
void MoveTo(T x, T y)
|
|
{
|
|
this->Data[0] = x;
|
|
this->Data[1] = y;
|
|
}
|
|
|
|
/**
|
|
* Intersect with `other` rectangle. If `this->IntersectsWith(other)` is true,
|
|
* this method will update this rect to the intersection of `this` and
|
|
* `other` and return true. If `this->IntersectsWith(other)` returns false,
|
|
* then this method will return false leaving this rect unchanged.
|
|
*
|
|
* Returns true if the intersection was performed otherwise false.
|
|
*/
|
|
bool Intersect(const vtkRect<T>& other)
|
|
{
|
|
if (this->IntersectsWith(other))
|
|
{
|
|
const T left = vtkMath::Max(this->GetLeft(), other.GetLeft());
|
|
const T bottom = vtkMath::Max(this->GetBottom(), other.GetBottom());
|
|
const T right = vtkMath::Min(this->GetRight(), other.GetRight());
|
|
const T top = vtkMath::Min(this->GetTop(), other.GetTop());
|
|
|
|
this->Data[0] = left;
|
|
this->Data[1] = bottom;
|
|
this->Data[2] = (right - left);
|
|
this->Data[3] = (top - bottom);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
class vtkRecti : public vtkRect<int>
|
|
{
|
|
public:
|
|
vtkRecti() {}
|
|
vtkRecti(int x, int y, int width, int height)
|
|
: vtkRect<int>(x, y, width, height)
|
|
{
|
|
}
|
|
explicit vtkRecti(const int* init)
|
|
: vtkRect<int>(init)
|
|
{
|
|
}
|
|
};
|
|
|
|
class vtkRectf : public vtkRect<float>
|
|
{
|
|
public:
|
|
vtkRectf() {}
|
|
vtkRectf(float x, float y, float width, float height)
|
|
: vtkRect<float>(x, y, width, height)
|
|
{
|
|
}
|
|
explicit vtkRectf(const float* init)
|
|
: vtkRect<float>(init)
|
|
{
|
|
}
|
|
};
|
|
|
|
class vtkRectd : public vtkRect<double>
|
|
{
|
|
public:
|
|
vtkRectd() {}
|
|
vtkRectd(double x, double y, double width, double height)
|
|
: vtkRect<double>(x, y, width, height)
|
|
{
|
|
}
|
|
explicit vtkRectd(const double* init)
|
|
: vtkRect<double>(init)
|
|
{
|
|
}
|
|
};
|
|
|
|
#endif // vtkRect_h
|
|
// VTK-HeaderTest-Exclude: vtkRect.h
|