Revert RedFox's changes to Spatial subdivisions in the simplest possible way (hopefully won't cause OOS, but at least we'll get reports). Fixes #2573, Refs #2430 . There probably are opportunities to remove more things.

This was SVN commit r15617.
This commit is contained in:
wraitii 2014-08-06 09:21:00 +00:00
parent c0e7208130
commit e865dc797d
4 changed files with 22 additions and 61 deletions

View File

@ -547,9 +547,9 @@ bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, enti
CFixedVector2D posMin (std::min(x0, x1) - r, std::min(z0, z1) - r);
CFixedVector2D posMax (std::max(x0, x1) + r, std::max(z0, z1) + r);
SpatialQueryArray unitShapes;
std::vector<entity_id_t> unitShapes;
m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax);
for (int i = 0; i < unitShapes.size(); ++i)
for (size_t i = 0; i < unitShapes.size(); ++i)
{
std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]);
ENSURE(it != m_UnitShapes.end());
@ -563,9 +563,9 @@ bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, enti
return true;
}
SpatialQueryArray staticShapes;
std::vector<entity_id_t> staticShapes;
m_StaticSubdivision.GetInRange(staticShapes, posMin, posMax);
for (int i = 0; i < staticShapes.size(); ++i)
for (size_t i = 0; i < staticShapes.size(); ++i)
{
std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]);
ENSURE(it != m_StaticShapes.end());
@ -885,9 +885,9 @@ void CCmpObstructionManager::GetObstructionsInRange(const IObstructionTestFilter
ENSURE(x0 <= x1 && z0 <= z1);
SpatialQueryArray unitShapes;
std::vector<entity_id_t> unitShapes;
m_UnitSubdivision.GetInRange(unitShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
for (int i = 0; i < unitShapes.size(); ++i)
for (size_t i = 0; i < unitShapes.size(); ++i)
{
std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]);
ENSURE(it != m_UnitShapes.end());
@ -907,9 +907,9 @@ void CCmpObstructionManager::GetObstructionsInRange(const IObstructionTestFilter
squares.push_back(s);
}
SpatialQueryArray staticShapes;
std::vector<entity_id_t> staticShapes;
m_StaticSubdivision.GetInRange(staticShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));
for (int i = 0; i < staticShapes.size(); ++i)
for (size_t i = 0; i < staticShapes.size(); ++i)
{
std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]);
ENSURE(it != m_StaticShapes.end());

View File

@ -981,10 +981,10 @@ public:
CFixedVector3D pos3d = cmpSourcePosition->GetPosition()+
CFixedVector3D(entity_pos_t::Zero(), q.elevationBonus, entity_pos_t::Zero()) ;
// Get a quick list of entities that are potentially in range, with a cutoff of 2*maxRange
SpatialQueryArray ents;
std::vector<entity_id_t> ents;
m_Subdivision.GetNear(ents, pos, q.maxRange*2);
for (int i = 0; i < ents.size(); ++i)
for (size_t i = 0; i < ents.size(); ++i)
{
EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);
ENSURE(it != m_EntityData.end());
@ -1018,10 +1018,10 @@ public:
else
{
// Get a quick list of entities that are potentially in range
SpatialQueryArray ents;
std::vector<entity_id_t> ents;
m_Subdivision.GetNear(ents, pos, q.maxRange);
for (int i = 0; i < ents.size(); ++i)
for (size_t i = 0; i < ents.size(); ++i)
{
EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);
ENSURE(it != m_EntityData.end());

View File

@ -49,12 +49,12 @@ std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simu
CFixedVector2D pos(fixed::FromFloat(pos3d.X), fixed::FromFloat(pos3d.Z));
// Get a rough group of entities using our approximated origin.
SpatialQueryArray ents;
std::vector<entity_id_t> ents;
cmpRangeManager->GetSubdivision()->GetNear(ents, pos, entity_pos_t::FromInt(range));
// Filter for relevent entities and calculate precise distances.
std::vector<std::pair<float, entity_id_t> > hits; // (dist^2, entity) pairs
for (int i = 0; i < ents.size(); ++i)
for (size_t i = 0; i < ents.size(); ++i)
{
CmpPtr<ICmpSelectable> cmpSelectable(simulation, ents[i]);
if (!cmpSelectable)

View File

@ -20,36 +20,10 @@
#include "simulation2/system/Component.h"
#include "simulation2/serialization/SerializeTemplates.h"
#include "ps/CLogger.h"
/**
* A simple fixed-size array that works similar to an std::vector
* but is obviously limited in its max items
*/
struct SpatialQueryArray
{
enum { MAX_COUNT = 2048 };
int count;
uint32_t items[MAX_COUNT];
inline SpatialQueryArray() : count(0) {}
inline const uint32_t& operator[](int index) const { return items[index]; }
inline uint32_t& operator[](int index) { return items[index]; }
inline int size() const { return count; }
inline void clear() { count = 0; }
void make_unique() // removes any duplicate entries
{
if (count)
{
std::sort(items, items + count); // we need a sorted list for std::unique to work
count = int(std::unique(items, items + count) - items);
}
}
};
/**
* A very basic subdivision scheme for finding items in ranges.
* Items are stored in lists in fixed-size divisions.
* Items are stored in lists in dynamic-sized divisions.
* Items have a size (min/max values of their axis-aligned bounding box)
* and are stored in all divisions overlapping that area.
*
@ -80,23 +54,9 @@ class SpatialSubdivision
items.pop_back();
}
void copy_items(SpatialQueryArray& out)
void copy_items_at_end(std::vector<uint32_t>& out)
{
if (items.empty())
return; // nothing to copy
int dsti = out.count; // the index in [out] where to start copying
int count = (int)items.size();
if ((dsti + count) > SpatialQueryArray::MAX_COUNT)
{
LOGWARNING(L"SpatialSubdivision Query too large. Results truncated.");
count = SpatialQueryArray::MAX_COUNT - dsti; // don't copy overflowing items
}
uint32_t* dst = &out.items[dsti];
uint32_t* src = &items[0];
for (int i = 0; i < count; ++i) // copy all items
dst[i] = src[i];
out.count += count;
out.insert(out.end(), items.begin(), items.end());
}
};
@ -288,7 +248,7 @@ public:
* Returns a sorted list of unique items that includes all items
* within the given axis-aligned square range.
*/
void GetInRange(SpatialQueryArray& out, CFixedVector2D posMin, CFixedVector2D posMax)
void GetInRange(std::vector<uint32_t>& out, CFixedVector2D posMin, CFixedVector2D posMax)
{
out.clear();
ENSURE(posMin.X <= posMax.X && posMin.Y <= posMax.Y);
@ -301,18 +261,19 @@ public:
{
for (u32 i = i0; i <= i1; ++i)
{
m_Divisions[i + j*m_DivisionsW].copy_items(out);
m_Divisions[i + j*m_DivisionsW].copy_items_at_end(out);
}
}
// some buildings span several tiles, so we need to make it unique
out.make_unique();
std::sort(out.begin(), out.end());
out.erase(std::unique(out.begin(), out.end()), out.end());
}
/**
* Returns a sorted list of unique items that includes all items
* within the given circular distance of the given point.
*/
void GetNear(SpatialQueryArray& out, CFixedVector2D pos, entity_pos_t range)
void GetNear(std::vector<uint32_t>& out, CFixedVector2D pos, entity_pos_t range)
{
// TODO: be cleverer and return a circular pattern of divisions,
// not this square over-approximation