mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 21:31:53 +00:00
222 lines
5.7 KiB
C++
222 lines
5.7 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/scummsys.h"
|
|
#include "common/textconsole.h"
|
|
|
|
#include "math/rect2d.h"
|
|
|
|
namespace Math {
|
|
|
|
Rect2d::Rect2d() {
|
|
}
|
|
|
|
Rect2d::Rect2d(const Vector2d &topLeft, const Vector2d &bottomRight) {
|
|
float left = (topLeft.getX() <= bottomRight.getX() ? topLeft.getX() : bottomRight.getX());
|
|
float right = (topLeft.getX() <= bottomRight.getX() ? bottomRight.getX() : topLeft.getX());
|
|
float top = (topLeft.getY() <= bottomRight.getY() ? topLeft.getY() : bottomRight.getY());
|
|
float bottom = (topLeft.getY() <= bottomRight.getY() ? bottomRight.getY() : topLeft.getY());
|
|
|
|
_topLeft = Vector2d(left, top);
|
|
_topRight = Vector2d(right, top);
|
|
_bottomLeft = Vector2d(left, bottom);
|
|
_bottomRight = Vector2d(right, bottom);
|
|
}
|
|
|
|
Rect2d::Rect2d(const Vector2d &topLeft, const Vector2d &topRight,
|
|
const Vector2d &bottomLeft, const Vector2d &bottomRight) :
|
|
_topLeft(topLeft), _topRight(topRight),
|
|
_bottomLeft(bottomLeft), _bottomRight(bottomRight) {
|
|
|
|
}
|
|
|
|
void Rect2d::rotateAround(const Vector2d &point, const Angle &angle) {
|
|
_topLeft.rotateAround(point, angle);
|
|
_topRight.rotateAround(point, angle);
|
|
_bottomLeft.rotateAround(point, angle);
|
|
_bottomRight.rotateAround(point, angle);
|
|
}
|
|
|
|
void Rect2d::rotateAroundCenter(const Angle &angle) {
|
|
Vector2d center = getCenter();
|
|
rotateAround(center, angle);
|
|
}
|
|
|
|
void Rect2d::moveCenterTo(const Vector2d &pos) {
|
|
Vector2d vec(pos - getCenter());
|
|
translate(vec);
|
|
}
|
|
|
|
void Rect2d::scale(float amount) {
|
|
Vector2d c = getCenter();
|
|
moveCenterTo(Vector2d(0, 0));
|
|
|
|
_topLeft *= amount;
|
|
_topRight *= amount;
|
|
_bottomLeft *= amount;
|
|
_bottomRight *= amount;
|
|
|
|
moveCenterTo(c);
|
|
}
|
|
|
|
void Rect2d::translate(const Vector2d &vec) {
|
|
_topLeft += vec;
|
|
_topRight += vec;
|
|
_bottomLeft += vec;
|
|
_bottomRight += vec;
|
|
}
|
|
|
|
bool Rect2d::intersectsRect(const Rect2d &rect) const {
|
|
// TODO: implement this;
|
|
error("Rect2d::intersectsRect not implemented");
|
|
return false;
|
|
}
|
|
|
|
bool Rect2d::intersectsCircle(const Vector2d ¢er, float radius) const {
|
|
Vector2d c = getCenter();
|
|
float w = getWidth();
|
|
float h = getHeight();
|
|
|
|
Math::Angle angle = (_topRight - _topLeft).getAngle();
|
|
|
|
if (angle == 0) {
|
|
Vector2d circleDistance(fabs(center.getX() - c.getX()), fabs(center.getY() - c.getY()));
|
|
|
|
if (circleDistance.getX() > (w / 2.f + radius)) {
|
|
return false;
|
|
}
|
|
if (circleDistance.getY() > (h / 2.f + radius)) {
|
|
return false;
|
|
}
|
|
|
|
if (circleDistance.getX() <= (w / 2.f)) {
|
|
return true;
|
|
}
|
|
if (circleDistance.getY() <= (h / 2.f)) {
|
|
return true;
|
|
}
|
|
|
|
float cornerDistance_sq = pow(circleDistance.getX() - w / 2.f, 2.f) +
|
|
pow(circleDistance.getY() - h / 2.f, 2.f);
|
|
|
|
return (cornerDistance_sq <= radius * radius);
|
|
} else { //The rectangle was rotated
|
|
Rect2d r(_topLeft, _topRight, _bottomLeft, _bottomRight);
|
|
r.rotateAroundCenter(-angle);
|
|
Vector2d circle(center);
|
|
circle.rotateAround(r.getCenter(), -angle);
|
|
return r.intersectsCircle(circle, radius);
|
|
}
|
|
}
|
|
|
|
inline bool le(float a, float b) {
|
|
return (a < b || (fabsf(a - b) < 0.0001f));
|
|
}
|
|
|
|
inline bool ge(float a, float b) {
|
|
return (a > b || (fabsf(a - b) < 0.0001f));
|
|
}
|
|
|
|
bool Rect2d::containsPoint(const Vector2d &point) const {
|
|
return ge(point.getX(), _topLeft.getX()) && le(point.getX(), _bottomRight.getX()) &&
|
|
ge(point.getY(), _topLeft.getY()) && le(point.getY(), _bottomRight.getY());
|
|
}
|
|
|
|
Vector2d Rect2d::getCenter() const {
|
|
Vector2d sum = _topLeft + _topRight + _bottomLeft + _bottomRight;
|
|
sum /= 4;
|
|
|
|
return sum;
|
|
}
|
|
|
|
Vector2d Rect2d::getTopLeft() const {
|
|
return _topLeft;
|
|
}
|
|
|
|
Vector2d Rect2d::getTopRight() const {
|
|
return _topRight;
|
|
}
|
|
|
|
Vector2d Rect2d::getBottomLeft() const {
|
|
return _bottomLeft;
|
|
}
|
|
|
|
Vector2d Rect2d::getBottomRight() const {
|
|
return _bottomRight;
|
|
}
|
|
|
|
float Rect2d::getWidth() const {
|
|
float x = _topRight.getX() - _topLeft.getX();
|
|
float y = _topRight.getY() - _topLeft.getY();
|
|
|
|
return sqrt(x * x + y * y);
|
|
}
|
|
|
|
float Rect2d::getHeight() const {
|
|
float x = _bottomLeft.getX() - _topLeft.getX();
|
|
float y = _bottomLeft.getY() - _topLeft.getY();
|
|
|
|
return sqrt(x * x + y * y);
|
|
}
|
|
|
|
Vector2d Rect2d::getIntersection(const Vector2d &start, const Vector2d &dir, Segment2d *edge) const {
|
|
float w = getWidth();
|
|
float h = getHeight();
|
|
float d = sqrt(w * w + h * h);
|
|
|
|
Segment2d line(start, start + dir.getNormalized() * 2*d);
|
|
Vector2d intersection;
|
|
|
|
Segment2d l(_topLeft, _topRight);
|
|
if (line.intersectsSegment(l, &intersection)) {
|
|
if (edge) {
|
|
*edge = l;
|
|
}
|
|
return intersection;
|
|
}
|
|
l = Segment2d(_topRight, _bottomRight);
|
|
if (line.intersectsSegment(l, &intersection)) {
|
|
if (edge) {
|
|
*edge = l;
|
|
}
|
|
return intersection;
|
|
}
|
|
l = Segment2d(_bottomRight, _bottomLeft);
|
|
if (line.intersectsSegment(l, &intersection)) {
|
|
if (edge) {
|
|
*edge = l;
|
|
}
|
|
return intersection;
|
|
}
|
|
l = Segment2d(_bottomLeft, _topLeft);
|
|
if (line.intersectsSegment(l, &intersection)) {
|
|
if (edge) {
|
|
*edge = l;
|
|
}
|
|
return intersection;
|
|
}
|
|
|
|
return intersection;
|
|
|
|
}
|
|
|
|
}
|