Ticket #1707: spatial_optimization.patch

File spatial_optimization.patch, 2.7 KB (added by mrf, 11 years ago)
  • source/simulation2/helpers/Spatial.h

     
    210210     */
    211211    std::vector<T> GetNear(CFixedVector2D pos, entity_pos_t range)
    212212    {
    213         // TODO: be cleverer and return a circular pattern of divisions,
    214         // not this square over-approximation
     213        std::vector<T> ret;
    215214
    216         return GetInRange(pos - CFixedVector2D(range, range), pos + CFixedVector2D(range, range));
     215        ENSURE(range >= entity_pos_t::FromInt(0));
     216
     217        u32 i0 = GetI0(pos.X - range);
     218        u32 j0 = GetJ0(pos.Y - range);
     219        u32 i1 = GetI1(pos.X + range);
     220        u32 j1 = GetJ1(pos.Y + range);
     221        for (u32 j = j0; j <= j1; ++j)
     222        {
     223            for (u32 i = i0; i <= i1; ++i)
     224            {
     225                std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW);
     226                if (!div.empty())
     227                {
     228                    if (OverlapBoxCircle(GetPos0(i,j), GetPos1(i,j), pos, range))
     229                    {
     230                        ret.insert(ret.end(), div.begin(), div.end());
     231                    }
     232                }
     233            }
     234        }
     235
     236        // Remove duplicates
     237        std::sort(ret.begin(), ret.end());
     238        ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
     239
     240        return ret;
    217241    }
    218242
    219243private:
     
    251275        return GetI1(pos.X) + GetJ1(pos.Y)*m_DivisionsW;
    252276    }
    253277
     278    // Helper functions for translating division indexes into the coordinates
     279    // of the corresponding division rectangle.
     280    CFixedVector2D GetPos0(u32 i, u32 j)
     281    {
     282        return CFixedVector2D(m_DivisionSize * (int)i, m_DivisionSize * (int)j);
     283    }
     284   
     285    CFixedVector2D GetPos1(u32 i, u32 j)
     286    {
     287        return CFixedVector2D(m_DivisionSize * (int)(i+1), m_DivisionSize * (int)(j+1));
     288    }
     289
     290    // Helper function to determine whether (the area of) an axis aligned box specified
     291    // by posMin and posMax overlaps with (the area of) a circle defined by center and radius.
     292    bool OverlapBoxCircle(CFixedVector2D posMin, CFixedVector2D posMax, CFixedVector2D c, entity_pos_t r)
     293    {
     294        // distance of c from X/Y slab corresponding to the box (negative if inside)
     295        entity_pos_t distX = std::max(posMin.X - c.X, c.X - posMax.X);
     296        entity_pos_t distY = std::max(posMin.Y - c.Y, c.Y - posMax.Y);
     297
     298        if (distX <= entity_pos_t::Zero())
     299        {
     300            // within X slab; overlap if not too far from Y-boundary of box
     301            return distY <= r;
     302        }
     303        else if (distY <= entity_pos_t::Zero())
     304        {
     305            // within Y slab; overlap if not too far from X-boundary of box
     306            return distX <= r;
     307        }
     308        else
     309        {
     310            // neither within X or Y slab; overlap if not too far from corner point
     311            return CFixedVector2D(distX, distY).CompareLength(r) <= 0;
     312        }
     313    }
     314
    254315    entity_pos_t m_DivisionSize;
    255316    std::vector<std::vector<T> > m_Divisions;
    256317    u32 m_DivisionsW;