// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Mathematics module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #define F(a) static_cast(a) namespace Nz { template Rect::Rect(T Width, T Height) { Set(Width, Height); } template Rect::Rect(T X, T Y, T Width, T Height) { Set(X, Y, Width, Height); } template Rect::Rect(const T vec[4]) { Set(vec); } template Rect::Rect(const Vector2& lengths) { Set(lengths); } template Rect::Rect(const Vector2& vec1, const Vector2& vec2) { Set(vec1, vec2); } template template Rect::Rect(const Rect& rect) { Set(rect); } template bool Rect::Contains(T X, T Y) const { return X >= x && X <= x+width && Y >= y && Y <= y+height; } template bool Rect::Contains(const Vector2& point) const { return Contains(point.x, point.y); } template bool Rect::Contains(const Rect& rect) const { return Contains(rect.x, rect.y) && Contains(rect.x + rect.width, rect.y + rect.height); } template Rect& Rect::ExtendTo(T X, T Y) { width = std::max(x + width, X); height = std::max(y + height, Y); x = std::min(x, X); y = std::min(y, Y); width -= x; height -= y; return *this; } template Rect& Rect::ExtendTo(const Vector2& point) { return ExtendTo(point.x, point.y); } template Rect& Rect::ExtendTo(const Rect& rect) { width = std::max(x + width, rect.x + rect.width); height = std::max(y + height, rect.y + rect.height); x = std::min(x, rect.x); y = std::min(y, rect.y); width -= x; height -= y; return *this; } template Vector2 Rect::GetCenter() const { return GetPosition() + GetLengths() / F(2.0); } template Vector2 Rect::GetCorner(RectCorner corner) const { switch (corner) { case RectCorner_LeftBottom: return Vector2(x, y + height); case RectCorner_LeftTop: return Vector2(x, y); case RectCorner_RightBottom: return Vector2(x + width, y + height); case RectCorner_RightTop: return Vector2(x + width, y); } NazaraError("Corner not handled (0x" + String::Number(corner, 16) + ')'); return Vector2(); } template Vector2 Rect::GetLengths() const { return Vector2(width, height); } template Vector2 Rect::GetMaximum() const { return GetPosition() + GetLengths(); } template Vector2 Rect::GetMinimum() const { ///DOC: Alias de GetPosition() return GetPosition(); } template Vector2 Rect::GetNegativeVertex(const Vector2& normal) const { Vector2 neg(GetPosition()); if (normal.x < F(0.0)) neg.x += width; if (normal.y < F(0.0)) neg.y += height; return neg; } template Vector2 Rect::GetPosition() const { return Vector2(x, y); } template Vector2 Rect::GetPositiveVertex(const Vector2& normal) const { Vector2 pos(GetPosition()); if (normal.x > F(0.0)) pos.x += width; if (normal.y > F(0.0)) pos.y += height; return pos; } template bool Rect::Intersect(const Rect& rect, Rect* intersection) const { T left = std::max(x, rect.x); T right = std::min(x + width, rect.x + rect.width); if (left >= right) return false; T top = std::max(y, rect.y); T bottom = std::min(y + height, rect.y + rect.height); if (top >= bottom) return false; if (intersection) { intersection->x = left; intersection->y = top; intersection->width = right - left; intersection->height = bottom - top; } return true; } template bool Rect::IsValid() const { return width > F(0.0) && height > F(0.0); } template Rect& Rect::MakeZero() { x = F(0.0); y = F(0.0); width = F(0.0); height = F(0.0); return *this; } template Rect& Rect::Set(T Width, T Height) { x = F(0.0); y = F(0.0); width = Width; height = Height; return *this; } template Rect& Rect::Set(T X, T Y, T Width, T Height) { x = X; y = Y; width = Width; height = Height; return *this; } template Rect& Rect::Set(const T rect[4]) { x = rect[0]; y = rect[1]; width = rect[2]; height = rect[3]; return *this; } template Rect& Rect::Set(const Rect& rect) { std::memcpy(this, &rect, sizeof(Rect)); return *this; } template Rect& Rect::Set(const Vector2& lengths) { return Set(lengths.x, lengths.y); } template Rect& Rect::Set(const Vector2& vec1, const Vector2& vec2) { x = std::min(vec1.x, vec2.x); y = std::min(vec1.y, vec2.y); width = (vec2.x > vec1.x) ? vec2.x-vec1.x : vec1.x-vec2.x; height = (vec2.y > vec1.y) ? vec2.y-vec1.y : vec1.y-vec2.y; return *this; } template template Rect& Rect::Set(const Rect& rect) { x = F(rect.x); y = F(rect.y); width = F(rect.width); height = F(rect.height); return *this; } template String Rect::ToString() const { StringStream ss; return ss << "Rect(" << x << ", " << y << ", " << width << ", " << height << ')'; } template Rect& Rect::Translate(const Vector2& translation) { x += translation.x; y += translation.y; return *this; } template T& Rect::operator[](unsigned int i) { #if NAZARA_MATH_SAFE if (i >= 4) { StringStream ss; ss << "Index out of range: (" << i << " >= 4)"; NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif return *(&x+i); } template T Rect::operator[](unsigned int i) const { #if NAZARA_MATH_SAFE if (i >= 4) { StringStream ss; ss << "Index out of range: (" << i << " >= 4)"; NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif return *(&x+i); } template Rect Rect::operator*(T scalar) const { return Rect(x, y, width*scalar, height*scalar); } template Rect Rect::operator*(const Vector2& vec) const { return Rect(x, y, width*vec.x, height*vec.y); } template Rect Rect::operator/(T scalar) const { return Rect(x, y, width/scalar, height/scalar); } template Rect Rect::operator/(const Vector2& vec) const { return Rect(x, y, width/vec.x, height/vec.y); } template Rect& Rect::operator*=(T scalar) { width *= scalar; height *= scalar; return *this; } template Rect& Rect::operator*=(const Vector2& vec) { width *= vec.x; height *= vec.y; return *this; } template Rect& Rect::operator/=(T scalar) { width /= scalar; height /= scalar; return *this; } template Rect& Rect::operator/=(const Vector2& vec) { width /= vec.x; height /= vec.y; return *this; } template bool Rect::operator==(const Rect& rect) const { return NumberEquals(x, rect.x) && NumberEquals(y, rect.y) && NumberEquals(width, rect.width) && NumberEquals(height, rect.height); } template bool Rect::operator!=(const Rect& rect) const { return !operator==(rect); } template Rect Rect::Lerp(const Rect& from, const Rect& to, T interpolation) { #ifdef NAZARA_DEBUG if (interpolation < F(0.0) || interpolation > F(1.0)) { NazaraError("Interpolation must be in range [0..1] (Got " + String::Number(interpolation) + ')'); return Zero(); } #endif Rect rect; rect.x = Lerp(from.x, to.x, interpolation); rect.y = Lerp(from.y, to.y, interpolation); rect.width = Lerp(from.width, to.width, interpolation); rect.height = Lerp(from.height, to.height, interpolation); return rect; } template Rect Rect::Zero() { Rect rect; rect.MakeZero(); return rect; } } template std::ostream& operator<<(std::ostream& out, const Nz::Rect& rect) { return out << rect.ToString(); } #undef F #include