#ifndef WIFIOPTIMIZERPERFLOOR_H #define WIFIOPTIMIZERPERFLOOR_H #include "WiFiOptimizerLogDistCeiling.h" #include "../model/WiFiModelPerFloor.h" #include "../../../floorplan/v2/FloorplanHelper.h" #include #define WITH_DEBUG_PLOT #ifdef WITH_DEBUG_PLOT #include #include #include #include #include #endif /** * uses the log-distance model, but one per floor. * the model is optimized using all fingerprints that belong to this floor */ class WiFiOptimizerPerFloor { WiFiModelPerFloor* mdl = nullptr; WiFiFingerprints fps; Floorplan::IndoorMap* map; std::mutex mtx; #ifdef WITH_DEBUG_PLOT K::Gnuplot gp; K::GnuplotSplot splot; K::GnuplotSplotElementColorPoints pts; K::GnuplotSplotElementLines lines; #endif public: WiFiOptimizerPerFloor(Floorplan::IndoorMap* map) : map(map) { // the overall model (contains one sub-model per floor) mdl = new WiFiModelPerFloor(map); #ifdef WITH_DEBUG_PLOT splot.add(&pts); pts.setPointSize(1); pts.setPointType(7); splot.add(&lines); BBox3 bb = FloorplanHelper::getBBox(map); splot.getAxisX().setRange(bb.getMin().x, bb.getMax().x); splot.getAxisY().setRange(bb.getMin().y, bb.getMax().y); splot.getAxisZ().setRange(bb.getMin().z, bb.getMax().z); #endif } /** make the given fingerprint known to the optimizer */ void addFingerprint(const WiFiFingerprint& fp) { fps.add(fp); } WiFiModelPerFloor* optimizeAll() { const VAPGrouper vg = VAPGrouper(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::MAXIMUM, VAPGrouper::TimeAggregation::AVERAGE, 1); // optimize each floor on its own //for (WiFiModelPerFloor::ModelForFloor& mdlForFloor : mdl->getFloorModels()) { for (size_t i = 0; i < map->floors.size(); ++i) { const Floorplan::Floor* floor = map->floors[i]; // 1) create a new optimizer for the current floor WiFiOptimizer::LogDistCeiling opt(map, vg); // 2) create the model for this floor mtx.lock(); WiFiModelLogDistCeiling* mdlForFloor = new WiFiModelLogDistCeiling(map); mdl->add(mdlForFloor, floor); mtx.unlock(); // 3) get the floor's bbox and adjust the z-region (needed for museum in Rothenburg) BBox3 bb = FloorplanHelper::getBBox(floor); bb.setMinZ(floor->atHeight+0.25); bb.setMaxZ(floor->atHeight+2); // 4) find all fingerprints that belong to the floor/model and add them to the optimizer for (const WiFiFingerprint& fp : fps.getFingerprints()) { //if (mdlForFloor.matches(fp.pos_m.z)) { // std::cout << fp.pos_m.z << std::endl; // opt.addFingerprint(fp); //} if (bb.contains(fp.pos_m)) { //if (fp.pos_m.z >= floor->atHeight && fp.pos_m.z < floor->atHeight+floor->height) { std::cout << fp.pos_m.z << std::endl; opt.addFingerprint(fp); #ifdef WITH_DEBUG_PLOT pts.add(K::GnuplotPoint3(fp.pos_m.x, fp.pos_m.y, fp.pos_m.z), i); #endif } } #ifdef WITH_DEBUG_PLOT for (Floorplan::FloorOutlinePolygon* poly : floor->outline) { for (const Point2 pt : poly->poly.points) { lines.add(K::GnuplotPoint3(pt.x, pt.y, floor->atHeight)); } lines.splitFace(); lines.splitFace(); for (const Point2 pt : poly->poly.points) { lines.add(K::GnuplotPoint3(pt.x, pt.y, floor->atHeight+floor->height)); } lines.splitFace(); lines.splitFace(); } gp.draw(splot); gp.flush(); pts.clear(); lines.clear(); sleep(1); #endif // 5) run the optimizer const WiFiOptimizer::LogDistCeiling::APParamsList res = opt.optimizeAll(opt.MIN_2_FPS); // 6) add all optimized APs to the floor's model for (const WiFiOptimizer::LogDistCeiling::APParamsMAC& ap : res.get()) { // model is per-floor. so model cant optimize waf.. set to VERY HIGH manually const WiFiModelLogDistCeiling::APEntry entry(ap.params.getPos(), ap.params.txp, ap.params.exp, ap.params.waf); mdlForFloor->addAP(ap.mac, entry); } } return mdl; } }; #endif // WIFIOPTIMIZERPERFLOOR_H