/* * Copyright (c) 2007 INRIA * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Mathieu Lacage */ #include "rectangle.h" #include "ns3/assert.h" #include "ns3/fatal-error.h" #include "ns3/vector.h" #include #include #include #include namespace ns3 { Rectangle::Rectangle(double _xMin, double _xMax, double _yMin, double _yMax) : xMin(_xMin), xMax(_xMax), yMin(_yMin), yMax(_yMax) { } Rectangle::Rectangle() : xMin(0.0), xMax(0.0), yMin(0.0), yMax(0.0) { } bool Rectangle::IsInside(const Vector& position) const { return position.x <= this->xMax && position.x >= this->xMin && position.y <= this->yMax && position.y >= this->yMin; } bool Rectangle::IsOnTheBorder(const Vector& position) const { return position.x == this->xMax || position.x == this->xMin || position.y == this->yMax || position.y == this->yMin; } Rectangle::Side Rectangle::GetClosestSide(const Vector& position) const { std::array distanceFromBorders{ std::abs(position.x - this->xMin), // left border std::abs(this->xMax - position.x), // right border std::abs(position.y - this->yMin), // bottom border std::abs(this->yMax - position.y), // top border }; uint8_t flags = 0; double minDist = std::numeric_limits::max(); for (int i = 0; i < 4; i++) { if (distanceFromBorders[i] > minDist) { continue; } // In case we find a border closer to the position, // we replace it and mark the flag if (distanceFromBorders[i] < minDist) { minDist = distanceFromBorders[i]; flags = 0; } flags |= (0b1000 >> i); } NS_ASSERT(minDist != std::numeric_limits::max()); Rectangle::Side side; switch (flags) { // LRBT case 0b1111: // Every side is equally distant, so choose any side = TOPSIDE; break; case 0b0011: // Opposing sides are equally distant, so we need to check the other two // We also need to check if we're inside or outside. side = TOPSIDE; if (!IsInside(position)) { side = (distanceFromBorders[0] > distanceFromBorders[1]) ? RIGHTSIDE : LEFTSIDE; } break; case 0b1100: // Opposing sides are equally distant, so we need to check the other two // We also need to check if we're inside or outside. side = RIGHTSIDE; if (!IsInside(position)) { side = (distanceFromBorders[2] > distanceFromBorders[3]) ? TOPSIDE : BOTTOMSIDE; } break; case 0b0001: case 0b1101: side = TOPSIDE; break; case 0b0010: case 0b1110: side = BOTTOMSIDE; break; case 0b0100: case 0b0111: side = RIGHTSIDE; break; case 0b0101: side = TOPRIGHTCORNER; break; case 0b0110: side = BOTTOMRIGHTCORNER; break; case 0b1000: case 0b1011: side = LEFTSIDE; break; case 0b1001: side = TOPLEFTCORNER; break; case 0b1010: side = BOTTOMLEFTCORNER; break; default: NS_FATAL_ERROR("Impossible case"); break; } return side; } Vector Rectangle::CalculateIntersection(const Vector& current, const Vector& speed) const { NS_ASSERT(IsInside(current)); double xMaxY = current.y + (this->xMax - current.x) / speed.x * speed.y; double xMinY = current.y + (this->xMin - current.x) / speed.x * speed.y; double yMaxX = current.x + (this->yMax - current.y) / speed.y * speed.x; double yMinX = current.x + (this->yMin - current.y) / speed.y * speed.x; bool xMaxYOk = (xMaxY <= this->yMax && xMaxY >= this->yMin); bool xMinYOk = (xMinY <= this->yMax && xMinY >= this->yMin); bool yMaxXOk = (yMaxX <= this->xMax && yMaxX >= this->xMin); bool yMinXOk = (yMinX <= this->xMax && yMinX >= this->xMin); if (xMaxYOk && speed.x >= 0) { return Vector(this->xMax, xMaxY, 0.0); } else if (xMinYOk && speed.x <= 0) { return Vector(this->xMin, xMinY, 0.0); } else if (yMaxXOk && speed.y >= 0) { return Vector(yMaxX, this->yMax, 0.0); } else if (yMinXOk && speed.y <= 0) { return Vector(yMinX, this->yMin, 0.0); } else { NS_ASSERT(false); // quiet compiler return Vector(0.0, 0.0, 0.0); } } ATTRIBUTE_HELPER_CPP(Rectangle); /** * \brief Stream insertion operator. * * \param os the stream * \param rectangle the rectangle * \returns a reference to the stream */ std::ostream& operator<<(std::ostream& os, const Rectangle& rectangle) { os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|" << rectangle.yMax; return os; } /** * \brief Stream extraction operator. * * \param is the stream * \param rectangle the rectangle * \returns a reference to the stream */ std::istream& operator>>(std::istream& is, Rectangle& rectangle) { char c1; char c2; char c3; is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 >> rectangle.yMax; if (c1 != '|' || c2 != '|' || c3 != '|') { is.setstate(std::ios_base::failbit); } return is; } /** * \brief Stream insertion operator. * * \param os the stream * \param side the rectangle side * \returns a reference to the stream */ std::ostream& operator<<(std::ostream& os, const Rectangle::Side& side) { switch (side) { case Rectangle::RIGHTSIDE: os << "RIGHTSIDE"; break; case Rectangle::LEFTSIDE: os << "LEFTSIDE"; break; case Rectangle::TOPSIDE: os << "TOPSIDE"; break; case Rectangle::BOTTOMSIDE: os << "BOTTOMSIDE"; break; case Rectangle::TOPRIGHTCORNER: os << "TOPRIGHTCORNER"; break; case Rectangle::TOPLEFTCORNER: os << "TOPLEFTCORNER"; break; case Rectangle::BOTTOMRIGHTCORNER: os << "BOTTOMRIGHTCORNER"; break; case Rectangle::BOTTOMLEFTCORNER: os << "BOTTOMLEFTCORNER"; break; } return os; } } // namespace ns3