#include <iostream> #include <cmath> #include <cfloat> #include "Box.hpp" namespace nbody { using namespace std; Box::Box() { for (int i = 0; i < 3; i++) { this->min[i] = FLT_MAX; this->max[i] = -FLT_MAX; } } Box::~Box() { } //min/max getter/setters double Box::getMin(int index) { return this->min[index]; } double Box::getMax(int index) { return this->max[index]; } void Box::setMin(int index, double value) { this->min[index] = value; } void Box::setMax(int index, double value) { this->max[index] = value; } void Box::extendForBodies(vector<Body> bodies) { if (bodies.empty()) { return; } for (vector<Body>::iterator it = bodies.begin(); it != bodies.end(); it++) { for (int i = 0; i < 3; i++) { if (it->position[i] < this->min[i]) { this->min[i] = it->position[i]; } if (it->position[i] > this->max[i]) { this->max[i] = it->position[i]; } } } } void Box::extendToCube() { int longestSide = -1; double sidelength = 0.0; for (int i = 0; i < 3; i++) { if (this->max[i] - this->min[i] >= sidelength) { longestSide = i; sidelength = this->max[i] - this->min[i]; } } if (longestSide == -1) { return; } for (int i = 0; i < 3; i++) { if (i != longestSide) { double extend = (sidelength - (this->max[i] - this->min[i])) / 2.0; this->min[i] -= extend; this->max[i] += extend; } } } vector<Body> Box::copyBodies(vector<Body> bodies) { vector<Body> result; for (vector<Body>::iterator it = bodies.begin(); it != bodies.end(); it++) { if (it->position[0] >= this->min[0] && it->position[0] <= this->max[0] && it->position[1] >= this->min[1] && it->position[1] <= this->max[1] && it->position[2] >= this->min[2] && it->position[2] <= this->max[2]) { result.push_back(*it); } } return result; } vector<Body> Box::extractBodies(vector<Body>& bodies) { vector<Body> result; vector<Body>::iterator it = bodies.begin(); while (it != bodies.end()) { if (it->position[0] >= this->min[0] && it->position[0] <= this->max[0] && it->position[1] >= this->min[1] && it->position[1] <= this->max[1] && it->position[2] >= this->min[2] && it->position[2] <= this->max[2]) { result.push_back(*it); it = bodies.erase(it); } else { it++; } } return result; } bool Box::isContained(Body body) { for (int i = 0; i < 3; i++) { if (body.position[i] < this->min[i] || body.position[i] > this->max[i]) { return false; } } return true; } //TODO: check semantics bool Box::isContained(Box box) { for (int i = 0; i < 3; i++) { if (box.min[i] < this->min[i] || box.max[i] > this->max[i]) { return false; } } return true; } double Box::volume() { if (!this->isValid()) { return -1.0; } double result = 1.0; for (int i = 0; i < 3; i++) { result *= this->max[i] - this->min[i]; } return result; } bool Box::overlapsSphere(double* sphereCenter, double sphereRadius) { double dmin = 0.0; if (!this->isValid()) { return false; } for (int i = 0; i < 3; i++) { if (sphereCenter[i] < this->min[i]) { double dist = sphereCenter[i] - this->min[i]; dmin += dist * dist; } else if (sphereCenter[i] > this->max[i]) { double dist = sphereCenter[i] - this->max[i]; dmin += dist * dist; } } return dmin <= sphereRadius * sphereRadius; } double Box::maxSidelength() { double max = 0.0; if (!this->isValid()) { return -1.0; } for (int i = 0; i < 3; i++) { if (this->max[i] - this->min[i] > max) { max = this->max[i] - this->min[i]; } } return max; } double Box::distanceToPosition(double* position) { int inside = 0; double nextPosition[3] = {position[0], position[1], position[2]}; if (!this->isValid()) { return DBL_MAX; } for (int i = 0; i < 3; i++) { if (nextPosition[i] < this->min[i]) { nextPosition[i] = this->min[i]; } else if (nextPosition[i] > this->max[i]) { nextPosition[i] = this->max[i]; } else { inside++; } } if (inside == 3) { return 0.0; } else { double dist = 0.0; for (int i = 0; i < 3; i++) { dist += (nextPosition[i] - position[i]) * (nextPosition[i] - position[i]); } return sqrt(dist); } } double Box::distanceToBox(Box box) { double length = 0.0; if (!this->isValid()) { return DBL_MAX; } for (int i = 0; i < 3; i++) { double elem; if (box.min[i] < this->min[i] && box.max[i] < this->min[i]) { elem = this->min[i] - box.max[i]; } else if (box.min[i] > this->max[i] && box.max[i] > this->max[i]) { elem = box.min[i] - this->max[i]; } else { elem = 0.0; } length += elem * elem; } return sqrt(length); } vector<Box> Box::octreeSplit() { vector<Box> result; if (!this->isValid()) { return result; } for (unsigned int i = 0; i < 8; i++) { Box current = *this; for (unsigned int j = 0; j < 3; j++) { double middle = current.getMin(j) + (current.getMax(j) - current.getMin(j)) / 2.0; if (i & (1 << j)) { current.setMin(j, middle); } else { current.setMax(j, middle); } } result.push_back(current); } return result; } vector<Box> Box::splitLongestSide() { vector<Box> result; int longestIndex = -1; double longestSide = -1.0; if (!this->isValid()) { return result; } for (int i = 0; i < 3; i++) { if (this->max[i] - this->min[i] > longestSide) { longestSide = this->max[i] - this->min[i]; longestIndex = i; } } double middle = this->min[longestIndex] + (this->max[longestIndex] - this->min[longestIndex]) / 2.0; result.push_back(*this); result.back().max[longestIndex] = middle; result.push_back(*this); result.back().min[longestIndex] = middle; return result; } bool Box::isCorrect() { for (int i = 0; i < 3; i++) { if (this->max[i] < this->min[i]) { cout << "inverted bb" << endl; return false; } } return true; } bool Box::isValid() { for (int i = 0; i < 3; i++) { if (this->max[i] < this->min[i]) { return false; } } return true; } void Box::print() { cout << " min "; for (int i = 0; i < 3; i++) { cout << this->min[i] << " "; } cout << " max "; for (int i = 0; i < 3; i++) { cout << this->max[i] << " "; } cout << endl; } bool Box::contained(double* position) { if (!this->isValid()) { return false; } for (int i = 0; i < 3; i++) { if (position[i] < this->min[i] || position[i] > this->max[i]) { return false; } } return true; } void Box::extend(Box extender) { if (!extender.isValid()) { return; } for (int i = 0; i < 3; i++) { if (this->min[i] > extender.min[i]) { this->min[i] = extender.min[i]; } if (this->max[i] < extender.max[i]) { this->max[i] = extender.max[i]; } } } void Box::extend(Body extender) { for (int i = 0; i < 3; i++) { if (this->min[i] > extender.position[i]) { this->min[i] = extender.position[i]; } if (this->max[i] < extender.position[i]) { this->max[i] = extender.position[i]; } } } }