dollar/dollar/Gesture.cpp

211 lines
6.4 KiB
C++

/** @file
* @author Edouard DUPIN
* @copyright 2016, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
*/
#include <dollar/debug.h>
#include <dollar/Gesture.h>
#include <dollar/tools.h>
#include <etk/os/FSNode.h>
#include <ejson/ejson.h>
#include <esvg/esvg.h>
#include <etk/stdTools.h>
static std::vector<std::vector<vec2>> loadPointsJson(const ejson::Document& _doc) {
// extract lines:
std::vector<std::vector<vec2>> out;
const ejson::Array listOfLines = _doc["data"].toArray();
if (listOfLines.exist() == false) {
DOLLAR_WARNING("Reference element has no element named 'data' " << _doc["data"]);
return out;
}
for (auto itLines : listOfLines) {
ejson::Array listOfpoint = itLines.toArray();
std::vector<vec2> line;
for (auto itPoints : listOfpoint) {
ejson::Array pointsArray = itPoints.toArray();
line.push_back(vec2(pointsArray[0].toNumber().get(), pointsArray[1].toNumber().get()));
}
if (line.size() > 1) {
out.push_back(std::move(line));
}
}
return out;
}
std::vector<std::vector<vec2>> dollar::loadPoints(const std::string& _fileName, std::string* _label, std::string* _type) {
ejson::Document doc;
doc.load(_fileName);
if (_label != nullptr) {
*_label = doc["value"].toString().get();
}
if (_type != nullptr) {
*_type = doc["type"].toString().get();
}
// extract lines:
std::vector<std::vector<vec2>> out;
ejson::Array listOfLines = doc["data"].toArray();
for (auto itLines : listOfLines) {
ejson::Array listOfpoint = itLines.toObject()["list"].toArray();
std::vector<vec2> line;
for (auto itPoints : listOfpoint) {
ejson::Array pointsArray = itPoints.toArray();
line.push_back(vec2(pointsArray[0].toNumber().get(), pointsArray[1].toNumber().get()));
}
if (line.size() > 1) {
out.push_back(std::move(line));
}
}
return out;
}
dollar::Gesture::Gesture():
m_name(""),
m_subId(0),
m_path(){
}
bool dollar::Gesture::load(const std::string& _fileName) {
std::string tmpName = etk::tolower(_fileName);
if (etk::end_with(tmpName, ".json") == true) {
return loadJSON(_fileName);
} else if (etk::end_with(tmpName, ".svg") == true) {
return loadSVG(_fileName);
}
DOLLAR_ERROR("Un-sopported LOAD extention : " << _fileName);
DOLLAR_ERROR(" supported: [svg,json]");
return false;
}
bool dollar::Gesture::loadJSON(const std::string& _fileName) {
ejson::Document doc;
doc.load(_fileName);
if (doc["type"].toString().get() != "REFERENCE") {
DOLLAR_WARNING("can not LOAD file that is not a reference");
}
m_name = doc["value"].toString().get();
m_subId = doc["sub-id"].toNumber().getU64(),
m_path = loadPointsJson(doc);
m_path = dollar::scaleToOne(m_path);
DOLLAR_DEBUG("Load gesture : " << m_name << " id=" << m_subId << " nb_elem=" << m_path.size());
return true;
}
bool dollar::Gesture::loadSVG(const std::string& _fileName) {
esvg::Document doc;
doc.load(_fileName);
std::vector<std::string> plop = etk::split(_fileName, '.');
plop = etk::split(plop[plop.size() -2], '/');
plop = etk::split(plop[plop.size() -1], '_');
m_name = plop[0];
m_subId = etk::string_to_int32_t(plop[1]);
m_path = doc.getLines();
// SVG is written in the oposite mode ==> need to invert it ...
for (auto &it : m_path) {
for (auto &it2 : it) {
it2.setY(it2.y()*-1);
}
}
m_path = dollar::scaleToOne(m_path);
DOLLAR_DEBUG("Load gesture : " << m_name << " id=" << m_subId << " nb_elem=" << m_path.size());
return true;
}
bool dollar::Gesture::store(const std::string& _fileName) {
std::string tmpName = etk::tolower(_fileName);
if (etk::end_with(tmpName, ".json") == true) {
storeJSON(_fileName);
return true;
} else if (etk::end_with(tmpName, ".svg") == true) {
storeSVG(_fileName);
return true;
}
DOLLAR_ERROR("Un-sopported STORE extention : " << _fileName);
DOLLAR_ERROR(" supported: [svg,json]");
return false;
}
void dollar::Gesture::storeJSON(const std::string& _fileName) {
ejson::Document doc;
doc.add("type", ejson::String("REFERENCE"));
doc.add("value", ejson::String(m_name));
doc.add("sub-id", ejson::Number(m_subId));
ejson::Array data;
doc.add("data", data);
for (auto &it : m_path) {
ejson::Array path;
for (auto &pathIt : it) {
ejson::Array value;
value.add(ejson::Number(pathIt.x()));
value.add(ejson::Number(pathIt.y()));
path.add(value);
}
data.add(path);
}
doc.store(_fileName);
}
void dollar::Gesture::storeSVG(const std::string& _fileName, bool _storeDot) {
std::vector<std::vector<vec2>> strokes = dollar::scaleToOne(m_path);
std::string data("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
data += "<svg height=\"100\" width=\"100\">\n";
for (auto &itLines : strokes) {
data += " <polyline fill=\"none\" stroke=\"black\" stroke-opacity=\"1\" stroke-width=\"2\"\n";
data += " points=\"";
bool first = true;
for (auto& itPoints : itLines) {
if (first == false) {
data += " ";
}
first = false;
data += etk::to_string(itPoints.x()*100.0f) + "," + etk::to_string((1.0-itPoints.y())*100.0f);
}
data += "\"\n";
data += " />\n";
}
if (_storeDot == true) {
for (auto &it : m_enginePoints) {
data += " <circle fill=\"red\" cx=\"" + etk::to_string(it.x()*100.0f) + "\" cy=\"" + etk::to_string((1.0-it.y())*100.0f) + "\" r=\"0.6\"/>\n";
}
}
data += "</svg>\n";
etk::FSNodeWriteAllData(_fileName, data);
}
void dollar::Gesture::set(const std::string& _name, uint32_t _subId, std::vector<std::vector<vec2>> _path) {
m_name = _name;
m_subId = _subId;
m_path = _path;
m_enginePath.clear();
m_engineVector.clear();
m_engineStartV.clear();
m_enginePoints.clear();
}
void dollar::Gesture::configure(float _startAngleIndex, size_t _nbSample, bool _ignoreRotation, float _distance) {
m_enginePath.clear();
m_engineVector.clear();
m_engineStartV.clear();
m_enginePoints.clear();
// Generates dots:
m_enginePoints = dollar::normalizePathToPoints(m_path, _distance);
DOLLAR_VERBOSE("create " << m_enginePoints.size() << " points");
// for debug only
storeSVG("out_dollar/lib/gestures/" + m_name + "_" + etk::to_string(m_subId) + ".svg", true);
// Simplyfy paths
std::vector<std::vector<vec2>> uniPath = dollar::makeReferenceStrokes(m_path);
// normalize paths
for (auto &it : uniPath) {
std::vector<vec2> val = dollar::normalizePath(it, _nbSample, _ignoreRotation);
m_enginePath.push_back(val);
// calculate start vector:
vec2 startv = dollar::getStartVector(val, _startAngleIndex);
m_engineStartV.push_back(startv);
m_engineVector.push_back(dollar::normalyse(val));
}
}