worked on grid creation

fixed some issues with stairs
fixed/added LINT
This commit is contained in:
k-a-z-u
2017-07-27 18:40:56 +02:00
parent 3a92199777
commit c21925e86f
5 changed files with 114 additions and 38 deletions

View File

@@ -60,7 +60,7 @@ namespace Floorplan {
if (i.type == Type::ERROR) {++err;} if (i.type == Type::ERROR) {++err;}
} }
if (err > 0) { if (err > 0) {
throw Exception("detected floorplan errors"); // throw Exception("detected floorplan errors");
} }
} }
@@ -94,7 +94,7 @@ namespace Floorplan {
// check stairs // check stairs
for (const Stair* s : floor->stairs) { for (const Stair* s : floor->stairs) {
checkStair(res, floor, s); checkStair(res, map, floor, s);
} }
// check elevators // check elevators
@@ -169,7 +169,14 @@ namespace Floorplan {
} }
static void checkStair(Issues& res, const Floor* floor, const Stair* stair) { static void checkStair(Issues& res, const IndoorMap* map, const Floor* floor, const Stair* stair) {
// list of all heights where there is a floor;
std::vector<int> floorAtHeight_cm;
for (const Floor* f : map->floors) {
const int floorZ_cm = std::round(f->atHeight * 100);
floorAtHeight_cm.push_back(floorZ_cm); // integer height in cm
}
if (stair->getParts().empty()) { if (stair->getParts().empty()) {
res.push_back(Issue(Type::ERROR, floor, "stair does not contain any parts! [empty stair]")); res.push_back(Issue(Type::ERROR, floor, "stair does not contain any parts! [empty stair]"));
@@ -182,13 +189,20 @@ namespace Floorplan {
const Floorplan::Quad3& quadS = quads.front(); const Floorplan::Quad3& quadS = quads.front();
const Floorplan::Quad3& quadE = quads.back(); const Floorplan::Quad3& quadE = quads.back();
// disconnected start? // start == end?
if (quadS.p1.z == quadE.p3.z) {
res.push_back(Issue(Type::ERROR, floor, "stair start and end must not belong to the same floor!"));
}
// disconnected start? (MUST belong to the floor the stair is attached to)
if (quadS.p1.z != floor->getStartingZ()) { if (quadS.p1.z != floor->getStartingZ()) {
res.push_back(Issue(Type::ERROR, floor, "stair is not connected to the starting floor's ground! [open stair start]")); res.push_back(Issue(Type::ERROR, floor, "stair is not connected to the starting floor's ground! [open stair start]"));
} }
// disconnected end? // disconnected end? (must be long to ANY other floor within the map)
if (quadE.p3.z != floor->getEndingZ()) { //if (quadE.p3.z != floor->getEndingZ()) {
const int stairEndingZ_cm = std::round( quadE.p3.z * 100 );
if(std::find(floorAtHeight_cm.begin(), floorAtHeight_cm.end(), stairEndingZ_cm) == floorAtHeight_cm.end()) {
res.push_back(Issue(Type::ERROR, floor, "stair is not connected to the ending floor's ground! [open stair end]")); res.push_back(Issue(Type::ERROR, floor, "stair is not connected to the ending floor's ground! [open stair end]"));
} }

View File

@@ -268,7 +268,7 @@ public:
} }
/** remove the connection from n1 to n2 (not the other way round!) */ /** remove the connection from n1 to n2 (not the other way round!) */
void disconnectUniDir(T& n1, T& n2) { void disconnectUniDir(T& n1, const T& n2) {
for (int n = 0; n < n1._numNeighbors; ++n) { for (int n = 0; n < n1._numNeighbors; ++n) {
if (n1._neighbors[n] == n2._idx) { if (n1._neighbors[n] == n2._idx) {
arrayRemove(n1._neighbors, n, n1._numNeighbors); arrayRemove(n1._neighbors, n, n1._numNeighbors);
@@ -301,12 +301,16 @@ public:
void remove(T& node) { void remove(T& node) {
// disconnect from all neighbors // disconnect from all neighbors
int cnt = 0;
while (node._numNeighbors) { while (node._numNeighbors) {
// by removing one neighbor, all others are shifted to close the gap within the array // by removing one neighbor, all others are shifted to close the gap within the array
// its therefor ok to always delete array index [0] // its therefor ok to always delete array index [0]
disconnectBiDir(node._idx, node._neighbors[0]); disconnectBiDir(node._idx, node._neighbors[0]);
if (++cnt > node.MAX_NEIGHBORS) {
Log::add(name, "WARNING! found unsolveable neighboring! " + node.asString(), true);
break;
}
} }
// remove from hash-list // remove from hash-list

View File

@@ -89,7 +89,7 @@ public:
if (listener) {listener->onGridBuildUpdateMajor("adding stairs");} if (listener) {listener->onGridBuildUpdateMajor("adding stairs");}
if (_buildStairs) { if (_buildStairs) {
for (Floorplan::Floor* f : map->floors) { for (Floorplan::Floor* f : map->floors) {
buildStairs(f, listener); buildStairs(map, f, listener);
if (listener) {listener->onGridBuildUpdateMajor(total, ++cur);} if (listener) {listener->onGridBuildUpdateMajor(total, ++cur);}
} }
} }
@@ -215,7 +215,7 @@ public:
GridNodeBBox bbox(GridPoint(x_cm, y_cm, z_cm), helper.gridSize()); GridNodeBBox bbox(GridPoint(x_cm, y_cm, z_cm), helper.gridSize());
// slightly grow the bbox to ensure even obstacles that are directly aligned to the bbox are hit // slightly grow the bbox to ensure even obstacles that are directly aligned to the bbox are hit
bbox.grow(0.42345); bbox.grow(0.1337);
if (intersects(bbox, floor)) {continue;} if (intersects(bbox, floor)) {continue;}
// add to the grid [once] // add to the grid [once]
@@ -246,7 +246,7 @@ public:
} }
void buildStairs(const Floorplan::Floor* floor, GridFactoryListener* listener = nullptr) { void buildStairs(const Floorplan::IndoorMap* map, const Floorplan::Floor* floor, GridFactoryListener* listener = nullptr) {
const int total = floor->stairs.size(); const int total = floor->stairs.size();
int cur = 0; int cur = 0;
@@ -254,7 +254,7 @@ public:
// process each stair within the floor // process each stair within the floor
for (const Floorplan::Stair* stair : floor->stairs) { for (const Floorplan::Stair* stair : floor->stairs) {
if (listener) {listener->onGridBuildUpdateMinor("adding " + floor->name + " stair " + std::to_string(cur+1));} if (listener) {listener->onGridBuildUpdateMinor("adding " + floor->name + " stair " + std::to_string(cur+1));}
stairs.build(floor, stair); stairs.build(map, floor, stair);
if (listener) {listener->onGridBuildUpdateMinor(total, ++cur);} if (listener) {listener->onGridBuildUpdateMinor(total, ++cur);}
} }
@@ -419,6 +419,9 @@ public:
void removeIsolatedNodes() { void removeIsolatedNodes() {
//std::cout << "todo: remove" << std::endl;
//return;
// try to start at the first stair // try to start at the first stair
for (T& n : grid) { for (T& n : grid) {
if (n.getType() == GridNode::TYPE_STAIR) {removeIsolatedNodes(n); return;} if (n.getType() == GridNode::TYPE_STAIR) {removeIsolatedNodes(n); return;}
@@ -439,6 +442,9 @@ public:
getConnected(n1, set); getConnected(n1, set);
Log::tock(); Log::tock();
//const int numToRemove = grid.getNumNodes() - set.size();
//int numRemoved = 0;
// remove all other // remove all other
Log::add(name, "removing all nodes NOT connected to " + (std::string) n1, false); Log::add(name, "removing all nodes NOT connected to " + (std::string) n1, false);
Log::tick(); Log::tick();
@@ -455,6 +461,9 @@ public:
// proceed ;) // proceed ;)
grid.remove(n2); grid.remove(n2);
//++numRemoved;
//std::cout << numRemoved << ":" << numToRemove << std::endl;
} }
} }
Log::tock(); Log::tock();

View File

@@ -254,13 +254,13 @@ public:
} }
static bool bary(Point2 p, Point2 a, Point2 b, Point2 c, float &u, float &v, float &w) { static bool bary(Point2 p, Point2 a, Point2 b, Point2 c, float &u, float &v, float &w) {
Point2 v0 = b - a, v1 = c - a, v2 = p - a; const Point2 v0 = b - a, v1 = c - a, v2 = p - a;
float d00 = dot(v0, v0); double d00 = dot(v0, v0);
float d01 = dot(v0, v1); double d01 = dot(v0, v1);
float d11 = dot(v1, v1); double d11 = dot(v1, v1);
float d20 = dot(v2, v0); double d20 = dot(v2, v0);
float d21 = dot(v2, v1); double d21 = dot(v2, v1);
float denom = d00 * d11 - d01 * d01; double denom = d00 * d11 - d01 * d01;
v = (d11 * d20 - d01 * d21) / denom; v = (d11 * d20 - d01 * d21) / denom;
w = (d00 * d21 - d01 * d20) / denom; w = (d00 * d21 - d01 * d20) / denom;
u = 1.0f - v - w; u = 1.0f - v - w;

View File

@@ -31,19 +31,23 @@ private:
// keep a list of all vertices below stairwells and remove them hereafter // keep a list of all vertices below stairwells and remove them hereafter
std::vector<T*> toDelete; std::vector<T*> toDelete;
bool tryImproveStairConnections = true;
private: private:
/** helper struct */ /** helper struct */
struct StairNode { struct StairNode {
const int x_cm; int x_cm;
const int y_cm; int y_cm;
const int belongsToQuadIdx; int belongsToQuadIdx;
float z_cm; // interpolated float z_cm; // interpolated
int gridIdx = -1; int gridIdx = -1;
StairNode(const int x_cm, const int y_cm, const int quadIdx) : x_cm(x_cm), y_cm(y_cm), belongsToQuadIdx(quadIdx) {;} StairNode(const int x_cm, const int y_cm, const int quadIdx) : x_cm(x_cm), y_cm(y_cm), belongsToQuadIdx(quadIdx) {;}
}; };
@@ -62,7 +66,15 @@ public:
void build(const Floorplan::Floor* floor, const Floorplan::Stair* stair) { void build(const Floorplan::IndoorMap* map, const Floorplan::Floor* floor, const Floorplan::Stair* stair) {
// starting-height of all available floors (in cm)
// needed to ensure that stairs start and end at floors
std::vector<int> floorsAtHeight_cm;
for (const Floorplan::Floor* f : map->floors) {
const int floorAtHeight_cm = std::round(f->atHeight*100);
floorsAtHeight_cm.push_back(floorAtHeight_cm);
}
const int gs_cm = grid.getGridSize_cm(); const int gs_cm = grid.getGridSize_cm();
@@ -123,20 +135,56 @@ public:
} }
const float stairAbsStart_m = floor->atHeight + stair->getParts().front().start.z;
const float stairAbsEnd_m = floor->atHeight + stair->getParts().back().end.z;
//const float stairHeight_m = stairAbsEnd_m - stairAbsStart_m;
const float stairAbsStart_cm = std::round(stairAbsStart_m*100);
const float stairAbsEnd_cm = std::round(stairAbsEnd_m*100);
const float stairHeight_cm = stairAbsEnd_cm - stairAbsStart_cm;
// this might lead to stairs the start slightly above the starting-floor // this might lead to stairs the start slightly above the starting-floor
// or ending slightly below the ending floor. this would lead to DISCONNECTION! // or ending slightly below the ending floor. this would lead to DISCONNECTION!
// therefore re-scale the z-values to ensure they start at floor1 and end at floor 2 // therefore re-scale the z-values to ensure they start at floor1 and end at floor 2
float minZ = +9999999; {
float maxZ = -9999999;
for (const StairNode& sn : stairNodes) { float minZ = +9999999;
if (sn.z_cm < minZ) {minZ = sn.z_cm;} float maxZ = -9999999;
if (sn.z_cm > maxZ) {maxZ = sn.z_cm;} for (const StairNode& sn : stairNodes) {
} if (sn.z_cm < minZ) {minZ = sn.z_cm;}
for (StairNode& sn : stairNodes) { if (sn.z_cm > maxZ) {maxZ = sn.z_cm;}
const float zPercent = (sn.z_cm - minZ) / (maxZ - minZ); // current percentage from minZ to maxZ }
sn.z_cm = floor->getStartingZ()*100 + zPercent * floor->height*100; // apply percentage to floorStartZ <-> floorEndZ
for (StairNode& sn : stairNodes) {
const float zPercent = (sn.z_cm - minZ) / (maxZ - minZ); // current percentage from minZ to maxZ
//sn.z_cm = floor->getStartingZ()*100 + zPercent * floor->height*100; // apply percentage to floorStartZ <-> floorEndZ
sn.z_cm = std::round(stairAbsStart_cm + zPercent * stairHeight_cm); // apply percentage to floorStartZ <-> floorEndZ
}
// snap stair-nodes to nearby grid nodes, if possible
if (tryImproveStairConnections) {
for (StairNode& sn : stairNodes) {
if (std::abs(sn.z_cm-stairAbsStart_cm) < gs_cm*0.75 && grid.hasNodeFor(GridPoint(sn.x_cm, sn.y_cm, stairAbsStart_cm)) ) {sn.z_cm = stairAbsStart_cm;}
if (std::abs(sn.z_cm-stairAbsEnd_cm) < gs_cm*0.75 && grid.hasNodeFor(GridPoint(sn.x_cm, sn.y_cm, stairAbsEnd_cm))) {sn.z_cm = stairAbsEnd_cm;}
}
}
// stort all stair-nodes by z (ascending)
const auto comp = [] (const StairNode& sn1, const StairNode& sn2) {return sn1.z_cm < sn2.z_cm;};
std::sort(stairNodes.begin(), stairNodes.end(), comp);
// get first and last stair note
const bool end1OK = std::find(floorsAtHeight_cm.begin(), floorsAtHeight_cm.end(), stairNodes.front().z_cm) != floorsAtHeight_cm.end();
const bool end2OK = std::find(floorsAtHeight_cm.begin(), floorsAtHeight_cm.end(), stairNodes.back().z_cm) != floorsAtHeight_cm.end();
// be sure both are connected to a floor
if (!end1OK || !end2OK) {
throw Exception("stair's start or end is not directly connectable to a floor");
}
} }
// track z-positions of already-existing grid nodes we connected the stair to // track z-positions of already-existing grid nodes we connected the stair to
// if this list contains 2 distinctive values, the stair is successfully connected to starting and ending floor! // if this list contains 2 distinctive values, the stair is successfully connected to starting and ending floor!
std::unordered_set<float> connectedWithHeights; std::unordered_set<float> connectedWithHeights;
@@ -167,15 +215,16 @@ public:
// check if there is a nearby floor-node to delete // check if there is a nearby floor-node to delete
// -> remove nodes directly above/below the stair // -> remove nodes directly above/below the stair
const int deleteDist_cm = 100; const int deleteDist_cm = 100;
const float distToBelow = gp.z_cm - floor->getStartingZ()*100; const float distToBelow = gp.z_cm - stairAbsStart_cm;//floor->getStartingZ()*100;
const float distToAbove = floor->getEndingZ()*100 - gp.z_cm; const float distToAbove = stairAbsEnd_cm - gp.z_cm;//floor->getEndingZ()*100 - gp.z_cm;
//if (distToBelow > gs_cm && distToBelow < deleteDist_cm) { //if (distToBelow > gs_cm && distToBelow < deleteDist_cm) {
if (distToBelow > 0 && distToBelow < deleteDist_cm) { if (distToBelow > 0 && distToBelow < deleteDist_cm) {
T* n = (T*) grid.getNodePtrFor(GridPoint(gp.x_cm, gp.y_cm, floor->getStartingZ()*100)); T* n = (T*) grid.getNodePtrFor(GridPoint(gp.x_cm, gp.y_cm, stairAbsStart_cm));//floor->getStartingZ()*100));
if (n) {toDelete.push_back(n);} if (n) {toDelete.push_back(n);}
//} else if (distToAbove > gs_cm && distToAbove < deleteDist_cm) { //} else if (distToAbove > gs_cm && distToAbove < deleteDist_cm) {
} else if (distToAbove > 0 && distToAbove < deleteDist_cm) { }
T* n = (T*) grid.getNodePtrFor(GridPoint(gp.x_cm, gp.y_cm, floor->getEndingZ()*100)); if (distToAbove > 0 && distToAbove < deleteDist_cm) {
T* n = (T*) grid.getNodePtrFor(GridPoint(gp.x_cm, gp.y_cm, stairAbsEnd_cm));//floor->getEndingZ()*100));
if (n) {toDelete.push_back(n);} if (n) {toDelete.push_back(n);}
} }
@@ -191,7 +240,7 @@ public:
// one for the starting floor // one for the starting floor
// one for the ending floor // one for the ending floor
// this mainly fails, when there is a REMOVING outline-area that removes to many nodes and the stair can not be connected // this mainly fails, when there is a REMOVING outline-area that removes to many nodes and the stair can not be connected
Assert::isTrue(connectedWithHeights.size() == 2, "stair is not correctly connected to starting and ending floor!"); Assert::isTrue(connectedWithHeights.size() == 2, "stair is not correctly connected to starting and ending floor!");
// now connect all new nodes with their neighbors // now connect all new nodes with their neighbors
// do not perform normal grid-connection but examine the nodes within the generated vector // do not perform normal grid-connection but examine the nodes within the generated vector