/* * © Copyright 2014 – Urheberrechtshinweis * Alle Rechte vorbehalten / All Rights Reserved * * Programmcode ist urheberrechtlich geschuetzt. * Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner. * Keine Verwendung ohne explizite Genehmigung. * (vgl. § 106 ff UrhG / § 97 UrhG) */ #ifndef WIFIMODELPERFLOOR_H #define WIFIMODELPERFLOOR_H #include "../AccessPoint.h" #include "../../../geo/Point3.h" #include #include "WiFiModelFactory.h" /** * FOR TESTING * * this model allows using a different sub-models for each floor to reduce the error */ class WiFiModelPerFloor : public WiFiModel { static constexpr const char* name = "WiFiModelFlo"; public: struct ModelForFloor { float fromZ; float toZ; WiFiModel* mdl; /** ctor */ ModelForFloor(const float fromZ, const float toZ, WiFiModel* mdl) : fromZ(fromZ), toZ(toZ), mdl(mdl) {;} /** does this entry apply to the given z-position? */ bool matches(const float z) const { return (fromZ <= z && z < toZ); } }; private: Floorplan::IndoorMap* map; /** all contained models [one per floor] */ std::vector models; public: WiFiModelPerFloor(Floorplan::IndoorMap* map) : map(map) { ; } /** dtor */ virtual ~WiFiModelPerFloor() { } /** get a list of all models for the distinct floors */ std::vector& getFloorModels() { return models; } /** get a list of all APs known to the model */ std::vector getAllAPs() const override { // combine all submodels std::vector res; for (const ModelForFloor& sub : models) { for (const AccessPoint& ap : sub.mdl->getAllAPs()) { if (std::find(res.begin(), res.end(), ap) == res.end()) { // TODO use map instead? res.push_back(ap); } } } return res; } void add(WiFiModel* mdl, const Floorplan::Floor* floor) { ModelForFloor mff(floor->atHeight, floor->atHeight+floor->height, mdl); models.push_back(mff); } float getRSSI(const MACAddress& accessPoint, const Point3 position_m) const override { #if (1==0) float res = -120; // find the best matching one for (const ModelForFloor& mff : models) { if (mff.matches(position_m.z)) { const float rssi = mff.mdl->getRSSI(accessPoint, position_m); if (rssi > res) {res = rssi;} } } return res; #elif (1==0) // nearest matching model float nearest = 9999; float res = -120; for (const ModelForFloor& mff : models) { const float distToFloor = std::abs(position_m.z - mff.fromZ); if (distToFloor < nearest) { const float rssi = mff.mdl->getRSSI(accessPoint, position_m); if (rssi == rssi) { res = rssi; nearest = distToFloor; } } } Assert::isNotNaN(res, "detected NaN"); return res; #elif (1==1) // average of all matching models float sum = 0; int cnt = 0; // find the best matching one for (const ModelForFloor& mff : models) { if (mff.matches(position_m.z)) { const float rssi = mff.mdl->getRSSI(accessPoint, position_m); if (rssi == rssi) { sum += rssi; ++cnt; } } } Assert::isNotNaN(sum, "detected NaN"); return (cnt > 0) ? (sum/cnt) : (-120); #endif // for (const ModelForFloor& mff : models) { // if (mff.matches(position_m.z)) {return mff.mdl->getRSSI(accessPoint, position_m);} // } // return -120; } void readFromXML(XMLDoc* doc, XMLElem* src) override { // check type if (std::string("WiFiModelPerFloor") != src->Attribute("type")) {throw Exception("invalid model type");} models.clear(); // model factory [create models based on XMl content] WiFiModelFactory fac(map); // parse all contained models [one per floor] XML_FOREACH_ELEM_NAMED("floor", xfloor, src) { // floor params const float z1 = xfloor->FloatAttribute("z1"); const float z2 = xfloor->FloatAttribute("z2"); // node for the model XMLElem* xmodel = xfloor->FirstChildElement("model"); // let the factory instantiate the model WiFiModel* mdl = fac.readFromXML(doc, xmodel); // add models.push_back(ModelForFloor(z1, z2, mdl)); } Log::add(name, "loaded " + std::to_string(models.size()) + " floor models"); } void writeToXML(XMLDoc* doc, XMLElem* dst) override { // set my type dst->SetAttribute("type", "WiFiModelPerFloor"); for (const ModelForFloor& mff : models) { XMLElem* xfloor = doc->NewElement("floor"); { xfloor->SetAttribute("z1", mff.fromZ); xfloor->SetAttribute("z2", mff.toZ); XMLElem* xmodel = doc->NewElement("model"); { mff.mdl->writeToXML(doc, xmodel); }; xfloor->InsertEndChild(xmodel); }; dst->InsertEndChild(xfloor); } } }; #endif // WIFIMODELPERFLOOR_H