|
|
|
|
@@ -10,7 +10,6 @@
|
|
|
|
|
//
|
|
|
|
|
#define CELL_LIMIT 0x7FFFFF
|
|
|
|
|
#define CELL_SCALE 10.0
|
|
|
|
|
#define CELL_INVALID 0
|
|
|
|
|
|
|
|
|
|
// Round a float and return as integer. Clamp result to the specified range.
|
|
|
|
|
static int round_and_clamp(double x, int lo, int hi) {
|
|
|
|
|
@@ -34,16 +33,16 @@ struct CellRange {
|
|
|
|
|
|
|
|
|
|
// Get the range of cells that includes everything in the rectangle.
|
|
|
|
|
//
|
|
|
|
|
// Gracefully handles the case that some or all of the rectangle is off
|
|
|
|
|
// the map: in that case, returns exactly the valid cells and not the
|
|
|
|
|
// invalid ones.
|
|
|
|
|
// Gracefully handles the case that some or all of the rectangle is
|
|
|
|
|
// beyond the maximum cell range. In that case, it clamps to the edge
|
|
|
|
|
// of the cell range.
|
|
|
|
|
//
|
|
|
|
|
static CellRange rect_cell_range(double x1, double y1, double x2, double y2) {
|
|
|
|
|
CellRange result;
|
|
|
|
|
result.xlo = round_and_clamp(x1 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT + 1);
|
|
|
|
|
result.ylo = round_and_clamp(y1 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT + 1);
|
|
|
|
|
result.xhi = round_and_clamp(x2 / CELL_SCALE, -CELL_LIMIT - 1, CELL_LIMIT);
|
|
|
|
|
result.yhi = round_and_clamp(y2 / CELL_SCALE, -CELL_LIMIT - 1, CELL_LIMIT);
|
|
|
|
|
result.xlo = round_and_clamp(x1 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
|
|
|
|
|
result.ylo = round_and_clamp(y1 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
|
|
|
|
|
result.xhi = round_and_clamp(x2 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
|
|
|
|
|
result.yhi = round_and_clamp(y2 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -53,23 +52,14 @@ static int64_t cell_id(int64_t cellx, int64_t celly) {
|
|
|
|
|
return 0x0001000000000000 | (icellx << 24) | (icelly << 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the cell ID of the specified point, or CELL_INVALID if the point is off the map.
|
|
|
|
|
// Get the cell ID of the specified point
|
|
|
|
|
static int64_t point_cell_id(double x, double y) {
|
|
|
|
|
double cellx = round(x / CELL_SCALE);
|
|
|
|
|
double celly = round(y / CELL_SCALE);
|
|
|
|
|
if ((cellx < -CELL_LIMIT) || (celly < -CELL_LIMIT) || (cellx > CELL_LIMIT) || (celly > CELL_LIMIT)) {
|
|
|
|
|
return CELL_INVALID;
|
|
|
|
|
}
|
|
|
|
|
double cellx = round_and_clamp(x / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
|
|
|
|
|
double celly = round_and_clamp(y / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
|
|
|
|
|
return cell_id(int64_t(cellx), int64_t(celly));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PlaneMap::remove(const std::string &plane, int64_t cellid, PlaneItem *client) {
|
|
|
|
|
if (cellid == CELL_INVALID) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ((plane == "") || (plane == "nowhere")) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto piter = planes_.find(plane);
|
|
|
|
|
if (piter == planes_.end()) {
|
|
|
|
|
return;
|
|
|
|
|
@@ -90,12 +80,6 @@ void PlaneMap::remove(const std::string &plane, int64_t cellid, PlaneItem *clien
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PlaneMap::insert(const std::string &plane, int64_t cellid, PlaneItem *client) {
|
|
|
|
|
if (cellid == CELL_INVALID) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ((plane == "") || (plane == "nowhere")) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Plane &p = planes_[plane];
|
|
|
|
|
EltVec &l = p[cellid];
|
|
|
|
|
l.push_back(client);
|
|
|
|
|
@@ -127,11 +111,11 @@ void PlaneItem::untrack() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PlaneMap::track(PlaneItem *item) {
|
|
|
|
|
if (item->pmap_ != this) {
|
|
|
|
|
item->untrack();
|
|
|
|
|
insert(item->plane(), point_cell_id(item->x(), item->y()), item);
|
|
|
|
|
item->pmap_ = this;
|
|
|
|
|
void PlaneItem::track(PlaneMap *pmap) {
|
|
|
|
|
if (pmap_ != pmap) {
|
|
|
|
|
untrack();
|
|
|
|
|
pmap->insert(plane_, point_cell_id(x_, y_), this);
|
|
|
|
|
pmap_ = pmap;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -224,13 +208,13 @@ LuaDefine(unittests_planemap, "c") {
|
|
|
|
|
LuaAssert(L, rect_cell_range((HI-7)*SC, (HI-5)*SC, (HI+3)*SC, (HI+6)*SC).equal(HI-7, HI-5, HI, HI));
|
|
|
|
|
|
|
|
|
|
// Rectangle that exceeds the high end of the range.
|
|
|
|
|
LuaAssert(L, rect_cell_range((HI+7)*SC, (HI+5)*SC, (HI+15)*SC, (HI+12)*SC).equal(HI+1, HI+1, HI, HI));
|
|
|
|
|
LuaAssert(L, rect_cell_range((HI+7)*SC, (HI+5)*SC, (HI+15)*SC, (HI+12)*SC).equal(HI, HI, HI, HI));
|
|
|
|
|
|
|
|
|
|
// Rectangle that crosses the low end of the range.
|
|
|
|
|
LuaAssert(L, rect_cell_range((LO-7)*SC, (LO-5)*SC, (LO+3)*SC, (LO+4)*SC).equal(LO, LO, LO+3, LO+4));
|
|
|
|
|
|
|
|
|
|
// Rectangle that exceeds the low end of the range.
|
|
|
|
|
LuaAssert(L, rect_cell_range((LO-15)*SC, (LO-17)*SC, (LO-7)*SC, (LO-5)*SC).equal(LO, LO, LO-1, LO-1));
|
|
|
|
|
LuaAssert(L, rect_cell_range((LO-15)*SC, (LO-17)*SC, (LO-7)*SC, (LO-5)*SC).equal(LO, LO, LO, LO));
|
|
|
|
|
|
|
|
|
|
// Simple test.
|
|
|
|
|
LuaAssert(L, point_cell_id(-7*SC, 15*SC) == cell_id(-7, 15));
|
|
|
|
|
@@ -245,10 +229,10 @@ LuaDefine(unittests_planemap, "c") {
|
|
|
|
|
LuaAssert(L, point_cell_id(LO*SC, LO*SC) == cell_id(LO, LO));
|
|
|
|
|
|
|
|
|
|
// Beyond various edges.
|
|
|
|
|
LuaAssert(L, point_cell_id((LO-1)*SC, 0) == CELL_INVALID);
|
|
|
|
|
LuaAssert(L, point_cell_id((HI+1)*SC, 0) == CELL_INVALID);
|
|
|
|
|
LuaAssert(L, point_cell_id(0, (LO-1)*SC) == CELL_INVALID);
|
|
|
|
|
LuaAssert(L, point_cell_id(0, (HI+1)*SC) == CELL_INVALID);
|
|
|
|
|
LuaAssert(L, point_cell_id((LO-1)*SC, 0) == point_cell_id(LO*SC, 0));
|
|
|
|
|
LuaAssert(L, point_cell_id((HI+1)*SC, 0) == point_cell_id(HI*SC, 0));
|
|
|
|
|
LuaAssert(L, point_cell_id(0, (LO-1)*SC) == point_cell_id(0, LO*SC));
|
|
|
|
|
LuaAssert(L, point_cell_id(0, (HI+1)*SC) == point_cell_id(0, HI*SC));
|
|
|
|
|
|
|
|
|
|
// Test using the insert function.
|
|
|
|
|
pm.clear();
|
|
|
|
|
@@ -270,20 +254,8 @@ LuaDefine(unittests_planemap, "c") {
|
|
|
|
|
LuaAssert(L, elts[0] == &pib);
|
|
|
|
|
pm.remove("foo", 12345, &pib);
|
|
|
|
|
LuaAssert(L, pm.total_cells() == 0);
|
|
|
|
|
|
|
|
|
|
// Test the insert function on the nowhere plane.
|
|
|
|
|
pm.clear();
|
|
|
|
|
pm.insert("nowhere", 12345, &pia);
|
|
|
|
|
pm.insert("nowhere", 12345, &pib);
|
|
|
|
|
LuaAssert(L, pm.total_cells() == 0);
|
|
|
|
|
|
|
|
|
|
// Test the insert function on an invalid cell.
|
|
|
|
|
pm.clear();
|
|
|
|
|
pm.insert("foo", CELL_INVALID, &pia);
|
|
|
|
|
pm.insert("foo", CELL_INVALID, &pib);
|
|
|
|
|
LuaAssert(L, pm.total_cells() == 0);
|
|
|
|
|
|
|
|
|
|
// Try moving a plane item around without it being connected to a grid.
|
|
|
|
|
// Try moving a plane item around without it being tracked to a grid.
|
|
|
|
|
pia.set_pos("foo", 3, 4, 5);
|
|
|
|
|
LuaAssert(L, pia.plane() == "foo");
|
|
|
|
|
LuaAssert(L, pia.x() == 3.0);
|
|
|
|
|
@@ -292,7 +264,7 @@ LuaDefine(unittests_planemap, "c") {
|
|
|
|
|
|
|
|
|
|
// Attach pia to the grid. This should record it.
|
|
|
|
|
pm.clear();
|
|
|
|
|
pm.track(&pia);
|
|
|
|
|
pia.track(&pm);
|
|
|
|
|
elts = pm.get_cell("foo", point_cell_id(3.0, 4.0));
|
|
|
|
|
LuaAssert(L, elts.size() == 1);
|
|
|
|
|
LuaAssert(L, elts[0] == &pia);
|
|
|
|
|
@@ -302,7 +274,7 @@ LuaDefine(unittests_planemap, "c") {
|
|
|
|
|
LuaAssert(L, pm.total_cells() == 0);
|
|
|
|
|
|
|
|
|
|
// Reattach pia to the grid, then move it.
|
|
|
|
|
pm.track(&pia);
|
|
|
|
|
pia.track(&pm);
|
|
|
|
|
LuaAssert(L, pm.total_cells() == 1);
|
|
|
|
|
pia.set_pos("bar", 1000.0, 1000.0, 0.0);
|
|
|
|
|
LuaAssert(L, pm.total_cells() == 1);
|
|
|
|
|
@@ -311,7 +283,7 @@ LuaDefine(unittests_planemap, "c") {
|
|
|
|
|
LuaAssert(L, elts[0] == &pia);
|
|
|
|
|
|
|
|
|
|
// Insert the four elements, then test the scan function.
|
|
|
|
|
pm.track(&pib);
|
|
|
|
|
pib.track(&pm);
|
|
|
|
|
pia.set_id(123);
|
|
|
|
|
pib.set_id(456);
|
|
|
|
|
pib.set_pos("bar", 1100.0, 1000.0, 0.0);
|
|
|
|
|
|