#include <limits> #include "quadtree.h" static const float BRUSHING_MAX_DIST = 20.0f; QuadTree::QuadTree(const RectF &bounds) : m_bounds(bounds) , m_value(-1) { } bool QuadTree::subdivide() { float halfWidth = m_bounds.width() / 2; float halfHeight = m_bounds.height() / 2; m_nw.reset(new QuadTree(RectF(m_bounds.x(), m_bounds.y(), halfWidth, halfHeight))); m_ne.reset(new QuadTree(RectF(m_bounds.x() + halfWidth, m_bounds.y(), halfWidth, halfHeight))); m_sw.reset(new QuadTree(RectF(m_bounds.x(), m_bounds.y() + halfHeight, halfWidth, halfHeight))); m_se.reset(new QuadTree(RectF(m_bounds.x() + halfWidth, m_bounds.y() + halfHeight, halfWidth, halfHeight))); int value = m_value; m_value = -1; return m_nw->insert(m_x, m_y, value) || m_ne->insert(m_x, m_y, value) || m_sw->insert(m_x, m_y, value) || m_se->insert(m_x, m_y, value); } bool QuadTree::insert(float x, float y, int value) { if (!m_bounds.contains(x, y)) { return false; } if (m_nw) { return m_nw->insert(x, y, value) || m_ne->insert(x, y, value) || m_sw->insert(x, y, value) || m_se->insert(x, y, value); } if (m_value >= 0) { subdivide(); return insert(x, y, value); } m_x = x; m_y = y; m_value = value; return true; } int QuadTree::nearestTo(float x, float y) const { if (!m_bounds.contains(x, y)) { return -1; } int q; if (m_nw) { q = m_nw->nearestTo(x, y); if (q >= 0) return q; q = m_ne->nearestTo(x, y); if (q >= 0) return q; q = m_sw->nearestTo(x, y); if (q >= 0) return q; q = m_se->nearestTo(x, y); if (q >= 0) return q; } float dist = std::numeric_limits<float>::infinity(); nearestTo(x, y, q, dist); if (dist < BRUSHING_MAX_DIST * BRUSHING_MAX_DIST) return q; return -1; } void QuadTree::nearestTo(float x, float y, int &nearest, float &dist) const { if (m_nw) { m_nw->nearestTo(x, y, nearest, dist); m_ne->nearestTo(x, y, nearest, dist); m_sw->nearestTo(x, y, nearest, dist); m_se->nearestTo(x, y, nearest, dist); } else if (m_value >= 0) { float d = (m_x - x)*(m_x - x) + (m_y - y)*(m_y - y); if (d < dist) { nearest = m_value; dist = d; } } } int QuadTree::query(float x, float y) const { if (!m_bounds.contains(x, y)) { // There is no way we could find the point return -1; } if (m_nw) { int q = -1; q = m_nw->query(x, y); if (q >= 0) return q; q = m_ne->query(x, y); if (q >= 0) return q; q = m_sw->query(x, y); if (q >= 0) return q; q = m_se->query(x, y); return q; } return m_value; } void QuadTree::query(const RectF &rect, std::vector<int> &result) const { if (!m_bounds.intersects(rect)) { return; } if (m_nw) { m_nw->query(rect, result); m_ne->query(rect, result); m_sw->query(rect, result); m_se->query(rect, result); } else if (rect.contains(m_x, m_y) && m_value != -1) { result.push_back(m_value); } }