current state

This commit is contained in:
2017-04-24 16:12:15 +02:00
parent 67a9f02d6d
commit 755f5662ae
15 changed files with 1211 additions and 329 deletions

View File

@@ -31,12 +31,21 @@ class PlotErrFunc {
K::GnuplotPlot gplot;
//std::vector<std::string> colors = {"#000000", "#ff0000", "#00bb00", "#0000ff"};
std::vector<std::string> colors = {"#000000", "#ff0000", "#00ff00", "#0000ff", "#00aaaa"};
std::vector<std::string> colors = {"#000000", "#ff0000", "#00ff00", "#0000ff", "#00aaaa", "#aa00aa"};
bool markers = false;
struct Markers {
bool median = false;
bool quantil75 = false;
} markers;
std::string codeFile;
struct Range {
int fromPercent = 0;
int toPercent = 0;
int increment = 0;
} range;
public:
@@ -44,8 +53,17 @@ public:
PlotErrFunc(const std::string& xLabel, const std::string& yLabel) {
gplot.getAxisX().setLabel(xLabel);
gplot.getAxisY().setLabel(yLabel);
gplot.getAxisX().setRange(K::GnuplotAxis::Range(0, K::GnuplotAxis::Range::AUTO));
gplot.getAxisY().setRange(K::GnuplotAxis::Range(0, K::GnuplotAxis::Range::AUTO));
setYRange(0, 90, 5);
//gplot.getAxisX().setRange(K::GnuplotAxis::Range(0, K::GnuplotAxis::Range::AUTO));
gplot.getAxisX().setRange(K::GnuplotAxis::Range(K::GnuplotAxis::Range::AUTO, K::GnuplotAxis::Range::AUTO));
}
/** set the percentage range to show */
void setYRange(const int fromPercent, const int toPercent, const int increment = 5) {
this->range.fromPercent = fromPercent;
this->range.toPercent = toPercent;
this->range.increment = increment;
gplot.getAxisY().setRange(K::GnuplotAxis::Range(this->range.fromPercent, K::GnuplotAxis::Range::AUTO));
}
/** add one curve. Statistics<T> are allowed to be altered outside afterwards! */
@@ -75,14 +93,18 @@ public:
return gplot;
}
void writeCodeTo(const std::string& file) {
this->codeFile = file;
/** write the gnuplot commands to file for later re-use */
void writePlotToFile(const std::string& file) {
this->gp.writePlotToFile(file);
}
void showMarkers(const bool show) {
this->markers = show;
/** whether to show additional markers */
void showMarkers(const bool median, const bool quantil75) {
this->markers.median = median;
this->markers.quantil75 = quantil75;
}
/** plot all curves */
void plot() {
@@ -100,42 +122,35 @@ public:
const float range = e.stats->getQuantile(0.85) - minX;
const float space = range * 0.07;
// 0 - 80%
for (int j = 0; j <= 85; j+= 5) {
// [from:stepsSize:to]
//for (int j = this->range.fromPercent; j <= this->range.toPercent; j += this->range.increment) {
for (int j = 0; j <= 100; j += this->range.increment) {
const float y = j / 100.0f;
const float x = e.stats->getQuantile(y);
K::GnuplotPoint2 gp2(x, y*100);
e.line->add(gp2);
if (markers) {
int id = (i+1) * 100;
if (j == 50) {
gp << "set object " << id+1 << " circle at " << x << "," << j << " size screen 0.02,0.02\n";
gp << "set label " << id+2 << " at " << x+space << "," << j << " '" << x << "'\n";
gp << "set arrow " << id+3 << " from " << x << "," << 0 << " to " << x << "," << j << " nohead\n";
gp << "set arrow " << id+4 << " from " << 0 << "," << j << " to " << x << "," << j << " nohead\n";
} else if (j == 75) {
gp << "set object " << id+5 << " circle at " << x << "," << j << " size screen 0.02,0.02\n";
gp << "set label " << id+6 << " at " << x+space << "," << j << " '" << x << "'\n";
gp << "set arrow " << id+7 << " from " << x << "," << 0 << " to " << x << "," << j << " nohead\n";
gp << "set arrow " << id+8 << " from " << 0 << "," << j << " to " << x << "," << j << " nohead\n";
}
// show additional markers?
int id = (i+1) * 100;
if (j == 50 && markers.median) {
gp << "set object " << id+1 << " circle at " << x << "," << j << " size screen 0.02,0.02\n";
gp << "set label " << id+2 << " at " << x+space << "," << j << " '" << x << "'\n";
gp << "set arrow " << id+3 << " from " << x << "," << 0 << " to " << x << "," << j << " nohead\n";
gp << "set arrow " << id+4 << " from " << 0 << "," << j << " to " << x << "," << j << " nohead\n";
} else if (j == 75 && markers.quantil75) {
gp << "set object " << id+5 << " circle at " << x << "," << j << " size screen 0.02,0.02\n";
gp << "set label " << id+6 << " at " << x+space << "," << j << " '" << x << "'\n";
gp << "set arrow " << id+7 << " from " << x << "," << 0 << " to " << x << "," << j << " nohead\n";
gp << "set arrow " << id+8 << " from " << 0 << "," << j << " to " << x << "," << j << " nohead\n";
}
}
}
// render
gp.draw(gplot);
if (codeFile != "") {
std::ofstream out(codeFile);
out << gp.getBuffer();
out.close();
}
gp.flush();
}

View File

@@ -39,7 +39,7 @@ private:
struct Entry {
Point3 pos;
K::GnuplotObjectPolygon* poly;
float max = 0;
float max = -1;
float sum = 0;
int cnt = 0;
};
@@ -51,19 +51,28 @@ private:
public:
/** ctor */
PlotWiFiGroundProb(const Floorplan::IndoorMap* map) : map(map), plot(map) {
buildEvalPoints();
PlotWiFiGroundProb(const Floorplan::IndoorMap* map, Plotty::Settings settings = Plotty::Settings()) : map(map), plot(map) {
plot.settings.outline = false;
plot.settings = settings;
buildEvalPoints();
plot.buildFloorplan();
}
Plotty& getPlot() {
return plot;
}
/** plot the ground-probability for the given measurement */
void show(const WiFiObserverFree& prob, const WiFiMeasurements& _mes) {
VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
const WiFiMeasurements mes = vap.group(_mes);
// determine min/max probability
double min = +99999;
double max = -99999;
for (Entry& e : pos) {
@@ -71,9 +80,9 @@ public:
if (p < min) {min = p;}
if (p > max) {max = p;}
}
double diff = max-min;
const double diff = max-min;
// render
for (Entry& e : pos) {
const double p = prob.getProbability(e.pos, mes.entries.front().getTimestamp(), mes);
const double f = (p-min) / diff * 255;
@@ -85,11 +94,51 @@ public:
e.poly->getFill().setColor(c);
e.max = f;
//}
if (f < 0.1) {
e.poly->setEnabled(false);
}
//plot.cpoints.add(K::GnuplotPoint3(pt.x, pt.y, pt.z), p);
}
}
void showStrongest(const WiFiObserverFree& prob, const WiFiMeasurements& mes, const float hue) {
// determine min/max probability
double min = +99999;
double max = -99999;
for (Entry& e : pos) {
const double p = prob.getProbability(e.pos, mes.entries.front().getTimestamp(), mes);
if (p < min) {min = p;}
if (p > max) {max = p;}
}
const double diff = max-min;
// render
for (Entry& e : pos) {
// get probability within [0:255]
const double p = prob.getProbability(e.pos, mes.entries.front().getTimestamp(), mes);
const double f = (p-min) / diff * 255;
if (p != p) {
throw Exception("nan");
}
// overwrite weak entries
if (f > e.max) {
const K::GnuplotColor c = K::GnuplotColor::fromHSV(hue, f, 245);
e.poly->getFill().setColor(c);
e.max = f;
// disable unlikely onces to save performance and disk-space
e.poly->setEnabled(f > 32);
}
}
}
@@ -143,6 +192,7 @@ private:
e.poly->close();
e.poly->getFill().setStyle(K::GnuplotFillStyle::SOLID);
e.poly->setStroke(K::GnuplotStroke::NONE());
e.poly->setZIndex(f->atHeight - 0.001); // between outline and obstacles
e.pos = Point3(x, y, f->atHeight);

View File

@@ -10,6 +10,9 @@
#include <KLib/misc/gnuplot/GnuplotSplotElementPoints.h>
#include <KLib/misc/gnuplot/GnuplotSplotElementColorPoints.h>
#include <KLib/misc/gnuplot/GnuplotSplotElementLines.h>
#include <KLib/misc/gnuplot/GnuplotSplotElementPM3D.h>
#include <KLib/misc/gnuplot/GnuplotSplotElementEmpty.h>
#include <KLib/misc/gnuplot/GnuplotPlot.h>
#include <KLib/misc/gnuplot/GnuplotPlotElementHistogram.h>
#include <KLib/misc/gnuplot/objects/GnuplotObjects.h>
@@ -103,6 +106,11 @@ public:
K::GnuplotSplotElementLines mapOutlineConcrete;
K::GnuplotSplotElementLines mapBBoxes;
K::GnuplotSplotElementEmpty emptyElem;
K::GnuplotSplotElementPM3D pm3doutline;
std::string codeFile;
struct Settings {
@@ -134,6 +142,9 @@ public:
mapOutlineDrywall.getStroke().getColor().setHexStr("#888888");
mapOutlineGlass.getStroke().getColor().setHexStr("#888888"); mapOutlineGlass.getStroke().setType(K::GnuplotDashtype::DASHED);
mapBBoxes.getStroke().setWidth(2);
splot.add(&emptyElem);
splot.add(&mapOutlineConcrete);
splot.add(&mapOutlineDrywall);
splot.add(&mapOutlineGlass);
@@ -144,6 +155,8 @@ public:
splot.add(&pathReal); pathReal.getStroke().setWidth(2); pathReal.getStroke().getColor().setHexStr("#000000");
splot.add(&pathEst); pathEst.getStroke().setWidth(2); pathEst.getStroke().getColor().setHexStr("#0000ff");
splot.add(&pm3doutline);
splot.add(&points);
points.setPointType(7);
points.setPointSize(0.5);
@@ -239,7 +252,8 @@ public:
}
void addLabel(const std::string& txt, const Point3 pos) {
gp << "set label '" << txt << "' at " << pos.x << "," << pos.y << "," << pos.z << "\n";
//gp << "set label '" << txt << "' at " << pos.x << "," << pos.y << "," << pos.z << "\n";
splot.getCustom() << "set label '" << txt << "' at " << pos.x << "," << pos.y << "," << pos.z << " front\n";
}
void addRectangle(const Point3 p1, const Point3 p2, const Color c, bool front = false, bool fill = true) {
@@ -271,11 +285,11 @@ public:
splot.getObjects().add(poly);
}
void addPolygon(const std::vector<Point3>& points, const std::string& color, bool front = false, bool fill = true, const float alpha = 1) {
K::GnuplotObjectPolygon* addPolygon(const std::vector<Point3>& points, const std::string& color, bool front = false, bool fill = true, const float alpha = 1) {
for (const Point3 p : points) {
if (p.z < settings.minZ) {return;}
if (p.z > settings.maxZ) {return;}
if (p.z < settings.minZ) {return nullptr;}
if (p.z > settings.maxZ) {return nullptr;}
}
const K::GnuplotFill pfill = (fill) ? (K::GnuplotFill(K::GnuplotFillStyle::SOLID, K::GnuplotColor::fromHexStr(color))) : (K::GnuplotFill::NONE());
@@ -303,6 +317,8 @@ public:
// gp << " fc rgb " << "'" << color << "'";
// gp << "\n";
return poly;
}
void setZRange(const float min, const float max) {
@@ -310,7 +326,7 @@ public:
}
void addFloorRect(const Point3 pos_m, const float size, Color c, float ratio = 1.0) {
K::GnuplotObjectPolygon* addFloorRect(const Point3 pos_m, const float size, Color c, float ratio = 1.0) {
const Point3 p1 = pos_m + Point3(-size, -size/ratio, 0);
const Point3 p2 = pos_m + Point3(+size, -size/ratio, 0);
@@ -319,7 +335,7 @@ public:
std::vector<Point3> points = {p1,p2,p3,p4,p1};
addPolygon(points, c.toHEX(), false, true);
return addPolygon(points, c.toHEX(), false, true);
// gp << "set object polygon from ";
// for (size_t i = 0; i < points.size(); ++i) {
@@ -397,6 +413,8 @@ public:
std::vector<Floorplan::Floor*> floors;
BBox3 bbox = FloorplanHelper::getBBox(map);
// only some floors??
if (settings.floors.empty()) {
floors = map->floors;
@@ -406,33 +424,31 @@ public:
}
}
// mapOutlineDrywall.addSegment(
// K::GnuplotPoint3(bbox.getMin().x, bbox.getMin().y, bbox.getMin().z),
// K::GnuplotPoint3(bbox.getMax().x, bbox.getMax().y, bbox.getMax().z)
// );
splot.getAxisX().setRange(K::GnuplotAxis::Range(bbox.getMin().x, bbox.getMax().x));
splot.getAxisY().setRange(K::GnuplotAxis::Range(bbox.getMin().y, bbox.getMax().y));
splot.getAxisZ().setRange(K::GnuplotAxis::Range(0, 11));
// process each selected floor
for (Floorplan::Floor* floor : floors) {
// plot obstacles?
if (settings.obstacles) {
for (Floorplan::FloorObstacle* obs : floor->obstacles) {
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obs);
if (line) {
const K::GnuplotPoint3 p1(line->from.x, line->from.y, floor->atHeight);
const K::GnuplotPoint3 p2(line->to.x, line->to.y, floor->atHeight);
switch(line->material) {
case Floorplan::Material::CONCRETE: mapOutlineConcrete.addSegment(p1, p2); break;
case Floorplan::Material::GLASS: mapOutlineGlass.addSegment(p1, p2); break;
case Floorplan::Material::UNKNOWN:
case Floorplan::Material::DRYWALL: mapOutlineDrywall.addSegment(p1, p2); break;
}
}
}
}
const float vo = floor->atHeight * 4.5;
// plot the floor's outline
if (settings.outline) {
for (Floorplan::FloorOutlinePolygon* poly : floor->outline) {
K::GnuplotColor color = K::GnuplotColor::fromRGB(210,210,210);
if (poly->outdoor) {color = K::GnuplotColor::fromRGB(200, 240, 200);}
if (floor->atHeight < settings.minZ) {continue;}
if (floor->atHeight > settings.maxZ) {continue;}
const float v = 180 + vo;
K::GnuplotColor color = K::GnuplotColor::fromRGB(v,v,v);
if (poly->outdoor) {color = K::GnuplotColor::fromRGB(180, 240, 180);}
//if (poly->method == Floorplan::OutlineMethod::REMOVE) {color = K::GnuplotColor::fromRGB(245,245,245);}
K::GnuplotFill filler(K::GnuplotFillStyle::SOLID, color);
K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(filler, K::GnuplotStroke::NONE());
@@ -441,7 +457,56 @@ public:
gpol->add(coord);
}
gpol->close();
gpol->setZIndex(floor->atHeight-0.1); // below the lines
//gpol->setFront(true);
splot.getObjects().add(gpol);
}
}
// plot obstacles?
if (settings.obstacles) {
for (Floorplan::FloorObstacle* obs : floor->obstacles) {
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obs);
if (line) {
if (floor->atHeight < settings.minZ) {continue;}
if (floor->atHeight > settings.maxZ) {continue;}
// const K::GnuplotPoint3 p1(line->from.x, line->from.y, floor->atHeight);
// const K::GnuplotPoint3 p2(line->to.x, line->to.y, floor->atHeight);
// switch(line->material) {
// case Floorplan::Material::CONCRETE: mapOutlineConcrete.addSegment(p1, p2); break;
// case Floorplan::Material::GLASS: mapOutlineGlass.addSegment(p1, p2); break;
// case Floorplan::Material::UNKNOWN:
// case Floorplan::Material::DRYWALL: mapOutlineDrywall.addSegment(p1, p2); break;
// }
// K::GnuplotObjectArrow* arrow = new K::GnuplotObjectArrow(
// K::GnuplotCoordinate3(line->from.x, line->from.y, floor->atHeight, K::GnuplotCoordinateSystem::FIRST),
// K::GnuplotCoordinate3(line->to.x, line->to.y, floor->atHeight, K::GnuplotCoordinateSystem::FIRST)
// );
// arrow->setHead(K::GnuplotObjectArrow::Head::NONE);
// splot.getObjects().add(arrow);
const float v = 140 + vo;
// drawing outlines as polygon is a hack for correct depth-order in gnuplot
K::GnuplotColor color = K::GnuplotColor::fromRGB(v,v,v);
K::GnuplotFill filler = K::GnuplotFill(K::GnuplotFillStyle::EMPTY_BORDER, color);
K::GnuplotStroke stroke(K::GnuplotDashtype::NONE, 1, color);
//K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(K::GnuplotFill::NONE(), stroke);
K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(filler, stroke);
//K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(K::GnuplotFill::NONE(), K::GnuplotStroke::NONE());
gpol->add(K::GnuplotCoordinate3(line->from.x, line->from.y, floor->atHeight, K::GnuplotCoordinateSystem::FIRST));
gpol->add(K::GnuplotCoordinate3(line->to.x, line->to.y, floor->atHeight, K::GnuplotCoordinateSystem::FIRST));
gpol->close();
gpol->setZIndex(floor->atHeight); // above the ground polygon
//gpol->setFront(true);
splot.getObjects().add(gpol);
}
}
}
@@ -450,7 +515,32 @@ public:
for (Floorplan::Stair* s : floor->stairs) {
std::vector<Floorplan::Quad3> quads = Floorplan::getQuads(s->getParts(), floor);
for (const Floorplan::Quad3& q : quads) {
addPolygon({q.p1, q.p2, q.p3, q.p4, q.p1}, "#c0c0c0");
// K::GnuplotObjectPolygon* poly = addPolygon({q.p1, q.p2, q.p3, q.p4, q.p1}, "#c0c0c0");
// if (poly) {
// poly->setZIndex(floor->atHeight+1.5); // above the floor
// }
const float v1 = 180 + q.p1.z * 4.5;
const float v2 = 140 + q.p1.z * 4.5;
const float z = (q.p1.z + q.p2.z + q.p3.z + q.p4.z) / 4.0f;
if (z < settings.minZ) {continue;}
if (z > settings.maxZ) {continue;}
K::GnuplotColor color = K::GnuplotColor::fromRGB(v1,v1,v1);
K::GnuplotColor color2 = K::GnuplotColor::fromRGB(v2,v2,v2);
K::GnuplotFill filler(K::GnuplotFillStyle::SOLID, color);
K::GnuplotStroke stroke(K::GnuplotDashtype::SOLID, 1, color2);
K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(filler, stroke);
gpol->add(K::GnuplotCoordinate3(q.p1.x, q.p1.y, q.p1.z, K::GnuplotCoordinateSystem::FIRST));
gpol->add(K::GnuplotCoordinate3(q.p2.x, q.p2.y, q.p2.z, K::GnuplotCoordinateSystem::FIRST));
gpol->add(K::GnuplotCoordinate3(q.p3.x, q.p3.y, q.p3.z, K::GnuplotCoordinateSystem::FIRST));
gpol->add(K::GnuplotCoordinate3(q.p4.x, q.p4.y, q.p4.z, K::GnuplotCoordinateSystem::FIRST));
gpol->close();
gpol->setZIndex(z); // above the ground
splot.getObjects().add(gpol);
}
}
}