Commit 6e058168 authored by Sören Schwertfeger's avatar Sören Schwertfeger
Browse files

ok not bad so far...

parent a04d4f76
......@@ -20,6 +20,9 @@
//Qt
#include <QtGui>
#include <QFileDialog>
#include "sttl.h"
......@@ -55,9 +58,25 @@ void qTransformsPlugin::getActions(QActionGroup& group)
m_action->setIcon(getIcon());
//connect appropriate signal
connect(m_action, SIGNAL(triggered()), this, SLOT(doAction()));
m_actionLoadTransform = new QAction("Load Transforms...",this);
m_actionLoadTransform->setToolTip("Load transforms from a JSON file and apply to the visible point clouds.");
m_actionLoadTransform->setIcon(getIcon());
//connect appropriate signal
connect(m_actionLoadTransform, SIGNAL(triggered()), this, SLOT(loadTransforms()));
m_actionSaveTransform = new QAction("Save Transforms...",this);
m_actionSaveTransform->setToolTip("Save transforms to a JSON file.");
m_actionSaveTransform->setIcon(getIcon());
//connect appropriate signal
connect(m_actionSaveTransform, SIGNAL(triggered()), this, SLOT(saveTransforms()));
}
group.addAction(m_action);
group.addAction(m_actionLoadTransform);
group.addAction(m_actionSaveTransform);
}
......@@ -85,12 +104,12 @@ void qTransformsPlugin::recTravTree(ccHObject * obj, QString spaces){
}
void qTransformsPlugin::recTravTree(ccHObject * obj, sttl::Frame * parent){
sttl::Frame * current = parent;
void qTransformsPlugin::recTravTree(ccHObject * obj, sttl::Transform * parent){
sttl::Transform * current = parent;
if(obj->getClassID() == CC_TYPES::POINT_CLOUD){
// this is a point cloud - will be a new parent...
sttl::Frame frame;
frame.name = obj->getName().toStdString();
sttl::Transform transform;
transform.frameName = obj->getName().toStdString();
const ccGLMatrix& transf = obj->getGLTransformationHistory();
Eigen::Transform<double,3,Eigen::Affine> globalT;
for(int i = 0; i<16; ++i){
......@@ -98,14 +117,13 @@ void qTransformsPlugin::recTravTree(ccHObject * obj, sttl::Frame * parent){
}
// ToDo: properly compute the transform of this frame wrt the parent... - I think this is correct...
Eigen::Transform<double,3,Eigen::Affine> result = globalT * parent->transform.inverse();
frame.transform = result;
transform.transform = result;
frame.referenceFrameName = parent->name;
frame.referenceFrame = parent;
m_frames.push_back(frame);
current = &m_frames.back();
transform.referenceFrameName = parent->frameName;
transform.generateId();
m_transforms.push_back(transform);
current = &m_transforms.back();
}
// recursively call the children...
......@@ -115,6 +133,44 @@ void qTransformsPlugin::recTravTree(ccHObject * obj, sttl::Frame * parent){
}
void qTransformsPlugin::loadTransforms(){
ccHObject * root = getMainAppInterface()->dbRootObject();
QString file = QFileDialog::getOpenFileName(0, "SaveTransforms", "", "*.stt", 0 , 0);
m_transforms.clear();
if(!file.isEmpty()){
sttl::loadList(m_transforms, file.toStdString());
}
std::cerr<<"We now have "<<m_transforms.size()<<" transforms! "<<std::endl;
}
void qTransformsPlugin::saveTransforms(){
ccHObject * root = getMainAppInterface()->dbRootObject();
recTravTree(root, QString(""));
m_transforms.clear();
sttl::Transform rootFrame;
rootFrame.frameName = "root";
rootFrame.transform = Eigen::Transform<double,3,Eigen::Affine>::Identity();
rootFrame.referenceFrameName = "";
rootFrame.byUser = "Schwerti";
m_transforms.push_back(rootFrame);
recTravTree(root, &m_transforms.front());
QString file = QFileDialog::getSaveFileName(0, "SaveTransforms", "", "*.stt", 0 , 0);
if(!file.isEmpty()){
sttl::saveList(m_transforms, file.toStdString());
}
}
//This is an example of an action's slot called when the corresponding action
//is triggered (i.e. the corresponding icon or menu entry is clicked in CC's
//main interface). You can access to most of CC components (database,
......@@ -138,16 +194,16 @@ void qTransformsPlugin::doAction()
ccHObject * root = getMainAppInterface()->dbRootObject();
recTravTree(root, QString(""));
m_frames.clear();
sttl::Frame rootFrame;
rootFrame.name = "root";
m_transforms.clear();
sttl::Transform rootFrame;
rootFrame.frameName = "root";
rootFrame.transform = Eigen::Transform<double,3,Eigen::Affine>::Identity();
rootFrame.referenceFrameName = "";
rootFrame.byUser = "Schwerti";
m_frames.push_back(rootFrame);
recTravTree(root, &m_frames.front());
sttl::saveList(m_frames);
m_transforms.push_back(rootFrame);
recTravTree(root, &m_transforms.front());
}
......
......@@ -63,6 +63,8 @@ protected slots:
/*** ADD YOUR CUSTOM ACTIONS' SLOTS HERE ***/
void doAction();
void loadTransforms();
void saveTransforms();
protected:
......@@ -73,11 +75,13 @@ protected:
**/
void recTravTree(ccHObject * obj, QString spaces);
void recTravTree(ccHObject * obj, sttl::Frame * parent);
void recTravTree(ccHObject * obj, sttl::Transform * parent);
std::list<sttl::Frame> m_frames;
std::list<sttl::Transform> m_transforms;
QAction* m_action;
QAction* m_actionLoadTransform;
QAction* m_actionSaveTransform;
};
#endif
#include "sttl.h"
#include <iostream>
#include <fstream>
#include <json/json.h>
#include <json/value.h>
using namespace std;
void testSTTL(){
cout<<"Hello STTL"<<endl;
}
#include <chrono>
#include <functional>
#include <cstdlib>
using namespace std;
Eigen::MatrixXd ReadJsonMatrix(Json::Value Array){
int rows = Array.size();
int cols = Array[0].size();
Eigen::MatrixXd Matrix(rows,cols) ;
for(int i = 0 ; i<rows ; i++){
for(int j=0 ; j<cols ; j++){
Matrix(i,j) = Array[i][j].asDouble() ;
}
}
return Matrix;
std::string sttl::Transform::Id::toString() const{
std::stringstream str;
str.fill('0');
str.width(16);
str<<std::hex<<id[0];
str.fill('0');
str.width(16);
str<<std::hex<<id[1];
return str.str();
}
//// Read Json Array and return as Eigen Vector
Eigen::VectorXd ReadJsonVector(Json::Value Array){
int size = Array.size();
Eigen::VectorXd Vector(size);
for(int i = 0 ; i < size ; i++){
Vector(i) = Array[i].asDouble();
}
return Vector;
bool sttl::Transform::Id::fromString(const std::string& string){
for(int i=0; i<2; ++i){
std::stringstream str(string.substr(i*16,16));
str>>std::hex>>id[i];
}
return true;
}
bool fillJson(const sttl::Frame & frame, Json::Value & node){
node["name"] = frame.name;
bool readJson(sttl::Transform & transform, Json::Value & node){
transform.frameName = node["name"].asString();
transform.referenceFrameName = node["referenceFrame"].asString();
transform.id.fromString(node["id"].asString());
if(node["transform"].size()!=4){
std::cerr<<"transform does not have 4 elements!"<<std::endl;
return false;
}
if(node["transform"][0].size()!=4){
std::cerr<<"transform does not have 4x4 elements!"<<std::endl;
return false;
}
for(int i=0; i<4; ++i){
for(int j=0; j<4; ++j){
transform.transform(i, j) = node["transform"][i][j].asDouble();
}
}
transform.hasCovariance = false;
if(node.isMember("covariance")){
transform.hasCovariance = true;
if(node["covariance"].size()!=7){
std::cerr<<"covariance does not have 7 elements!"<<std::endl;
return false;
}
if(node["covariance"][0].size()!=7){
std::cerr<<"covariance does not have 7x7 elements!"<<std::endl;
return false;
}
for(int i=0; i<7; ++i){
for(int j=0; j<7; ++j){
transform.covariance(i, j) = node["covariance"][i][j].asDouble();
}
}
}
return true;
}
bool fillJson(const sttl::Transform & transform, Json::Value & node){
node["name"] = transform.frameName;
Json::Value trans(Json::arrayValue);
trans.resize(4);
for(int i=0; i<4; ++i){
trans[i]=Json::Value(Json::arrayValue);
trans[i].resize(4);
for(int k=0; k<4; ++k){
trans[i][k] = frame.transform(i, k);
trans[i][k] = transform.transform(i, k);
}
}
node["transform"] = trans;
if(frame.hasCovariance){
if(transform.hasCovariance){
Json::Value cov(Json::arrayValue);
cov.resize(7);
for(int i=0; i<7; ++i){
cov[i]=Json::Value(Json::arrayValue);
cov[i].resize(7);
for(int k=0; k<7; ++k){
cov[i][k] = frame.covariance(i, k);
cov[i][k] = transform.covariance(i, k);
}
}
node["covariance"] = cov;
node["covariance"] = cov;
}
node["referenceFrame"] = frame.referenceFrameName;
node["referenceFrame"] = transform.referenceFrameName;
node["id"] = transform.id.toString();
//std::cout<<node;
return true;
}
bool sttl::saveList(const std::list<sttl::Frame> & frames){
uint64_t hash_combine(uint64_t& seed, const uint64_t &hash) {
seed ^= hash + 0x9e3773e79b4319b9 + (seed<<6) + (seed>>2);
return seed;
}
// inline void hash_combine(std::size_t& seed, const std::size_t &hash) {
// seed ^= hash + 0x9e3779b9 + (seed<<6) + (seed>>2);
// }
bool sttl::Transform::generateId(){
if(!(id==Id())){
std::cerr<<"Id was not empty when calling generateId()!"<<std::endl;
return false;
}
uint64_t id_time = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
uint64_t hashNames = 0;
hash_combine(hashNames, std::hash<std::string>()(frameName));
hash_combine(hashNames, std::hash<std::string>()(referenceFrameName));
hash_combine(hashNames, std::hash<std::string>()(byUser));
hash_combine(hashNames, std::hash<std::string>()(method));
hash_combine(hashNames, std::hash<std::string>()(program));
uint64_t hashTransf = 0;
for(int i=0; i<4; ++i) for(int k=0; k<4; ++k){
hash_combine(hashTransf, std::hash<double>()(transform(i, k)));
}
static bool srandCalled = false;
if(!srandCalled){
srandCalled = true;
std::srand(id_time);
}
uint64_t random = std::rand();
hash_combine(random, std::rand());
hash_combine(random, std::rand());
hash_combine(random, std::rand());
hash_combine(random, std::rand());
id = Id(hash_combine(random, id_time), hash_combine(hashNames, hashTransf));
return true;
}
bool sttl::saveList(const std::list<sttl::Transform> & transfs, const std::string &file ){
Json::Value root(Json::arrayValue);
for(std::list<sttl::Frame>::const_iterator itr = frames.begin(); itr != frames.end(); ++itr){
for(std::list<sttl::Transform>::const_iterator itr = transfs.begin(); itr != transfs.end(); ++itr){
Json::Value frame;
fillJson(*itr, frame);
root.append(frame);
}
std::fstream fs;
fs.open (file, std::fstream::out);
if (fs.is_open()){
std::cout<<root;
fs<<root;
fs.close();
}else{
cerr<<"Unable to open file "<<file<<" for writing..."<<std::endl;
return false;
}
return true;
}
bool sttl::loadList(std::list<sttl::Transform> & transfs, const std::string &file ){
if(!transfs.empty()){
std::cerr<<"Load list - list provided not empty!"<<std::endl;
return false;
}
std::fstream fs;
fs.open (file, std::fstream::in);
if (!fs.is_open()){
std::cerr<<"Error opening file "<<file<<std::endl;
return false;
}
Json::Value root;
fs >> root;
for(int i = 0 ; i < root.size() ; ++i){
sttl::Transform trans;
bool ret = readJson(trans, root[i]);
if(!ret){
std::cerr<<"Error reading transform # "<<i<<std::endl;
return false;
}
transfs.push_back(trans);
}
return true;
}
......@@ -2,35 +2,83 @@
#define STTL
// #include <stdlib.h>
// #include <stdio.h>
#include <Eigen/Geometry>
#include <iomanip>
#include <iostream>
#include <string>
#include <list>
namespace sttl{
class Frame{
/*
* A Transform between two frames
* There might be multiple transforms for every frame - maybe even with the same reference frame.
* Those are not specially handeled here - just more than one Transform will exist.
*/
class Transform{
public:
std::string name;
Eigen::Transform<double,3,Eigen::Affine> transform;
Eigen::Matrix<double, 7, 7> covariance; //< the 7x7 covariance matrix of translation and rotation as quaternion
bool hasCovariance; //< only true ifthe covariance matrix has proper values
Frame * referenceFrame;
struct Id{
uint64_t id[2];
Id(){
id[0] = 0;
id[1] = 0;
// id[2] = 0;
// id[3] = 0;
}
Id(uint64_t id0, uint64_t id1){
id[0] = id0;
id[1] = id1;
// id[2] = id2;
// id[3] = id3;
}
bool operator==(const Id& other) const{
return id[0] == other.id[0] && id[1] == other.id[1];
}
std::string toString() const;
bool fromString(const std::string& string);
};
std::string frameName; //< the name of the frame we are describing
std::string referenceFrameName; //< in case the reference Frame cannot be found
Frame():hasCovariance(false), referenceFrame(0){}
Eigen::Transform<double,3,Eigen::Affine> transform; //< the transfrom of this frame wrt the reference frame
bool hasCovariance; //< only true if the covariance matrix below has proper values
Eigen::Matrix<double, 7, 7> covariance; //< the 7x7 covariance matrix of translation and rotation as quaternion
std::string byUser; //< The user responsible for generating this transform
std::string time; //< the time this transform was generated
std::string method; //< Name of the method used to generate this transform - use the constants below if possible
std::string program; //< Name of the program used to generate this transform (e.g. "cloudcompare")
std::string details; //< Any additional data that this method/ program wants to save
Id id; //< special 256bit (hopefully) unique id generated once by generateId()
std::string byUser;
std::string time;
std::list<std::string> files;
std::list<Id> history; //< list of other transforms between these frames that influenced this result.
Transform():hasCovariance(false){}
bool generateId();
};
bool saveList(const std::list<sttl::Frame> & frames);
static const std::string METHOD_MANUAL = "Manual";
static const std::string METHOD_ICP = "ICP";
static const std::string METHOD_G2O = "g2o";
void testSTTL();
bool saveList(const std::list<sttl::Transform> & frames, const std::string &file);
bool loadList(std::list<sttl::Transform> & frames, const std::string &file);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment