<commit_before>/**
 * @file examples/megasync.cpp
 * @brief sample daemon, which synchronizes local and remote folders
 *
 * (c) 2013 by Mega Limited, Wellsford, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "mega.h"

#ifdef _WIN32
#include <conio.h>
#endif

using namespace mega;

class SyncApp : public MegaApp
{
    string remote_folder;
    string local_folder;
    handle cwd;
    bool initial_fetch;

    void debug_log(const char*);
    void login_result(error e);

	void fetchnodes_result (error e);

    void request_error(error e);
	void syncupdate_state(Sync*, syncstate);

	void syncupdate_stuck(string*);
	void syncupdate_local_folder_addition(Sync*, const char*);
	void syncupdate_local_folder_deletion(Sync*, const char*);
	void syncupdate_local_file_addition(Sync*, const char*);
	void syncupdate_local_file_deletion(Sync*, const char*);
	void syncupdate_local_file_change(Sync*, const char*);
	void syncupdate_local_move(Sync*, const char*, const char*);
	void syncupdate_get(Sync*, const char*);
	void syncupdate_put(Sync*, const char*);
	void syncupdate_remote_file_addition(Node*);
	void syncupdate_remote_file_deletion(Node*);
	void syncupdate_remote_folder_addition(Node*);
	void syncupdate_remote_folder_deletion(Node*);
	void syncupdate_remote_copy(Sync*, const char*);
	void syncupdate_remote_move(string*, string*);

    Node* nodebypath(const char* ptr, string* user, string* namepart);
public:
    bool debug;
    SyncApp (string local_folder_, string remote_folder_);
};

// globals
MegaClient* client;
bool mega::debug = false;

// returns node pointer determined by path relative to cwd
// Path naming conventions:
// path is relative to cwd
// /path is relative to ROOT
// //in is in INBOX
// //bin is in RUBBISH
// X: is user X's INBOX
// X:SHARE is share SHARE from user X
// : and / filename components, as well as the \, must be escaped by \.
// (correct UTF-8 encoding is assumed)
// returns NULL if path malformed or not found
Node* SyncApp::nodebypath(const char* ptr, string* user = NULL, string* namepart = NULL)
{
	vector<string> c;
	string s;
	int l = 0;
	const char* bptr = ptr;
	int remote = 0;
	Node* n;
	Node* nn;

	// split path by / or :
	do {
		if (!l)
		{
			if (*ptr >= 0)
			{
				if (*ptr == '\\')
				{
					if (ptr > bptr) s.append(bptr,ptr-bptr);
					bptr = ++ptr;

					if (*bptr == 0)
					{
						c.push_back(s);
						break;
					}

					ptr++;
					continue;
				}

				if (*ptr == '/' || *ptr == ':' || !*ptr)
				{
					if (*ptr == ':')
					{
						if (c.size()) return NULL;
						remote = 1;
					}

					if (ptr > bptr) s.append(bptr,ptr-bptr);

					bptr = ptr+1;

					c.push_back(s);

					s.erase();
				}
			}
			else if ((*ptr & 0xf0) == 0xe0) l = 1;
			else if ((*ptr & 0xf8) == 0xf0) l = 2;
			else if ((*ptr & 0xfc) == 0xf8) l = 3;
			else if ((*ptr & 0xfe) == 0xfc) l = 4;
		}
		else l--;
	} while (*ptr++);

	if (l) return NULL;

	if (remote)
	{
		// target: user inbox - record username/email and return NULL
		if (c.size() == 2 && !c[1].size())
		{
			if (user) *user = c[0];
			return NULL;
		}

		User* u;

		if ((u = client->finduser(c[0].c_str())))
		{
			// locate matching share from this user
			handle_set::iterator sit;

			for (sit = u->sharing.begin(); sit != u->sharing.end(); sit++)
			{
				if ((n = client->nodebyhandle(*sit)))
				{
					if (!strcmp(c[1].c_str(),n->displayname()))
					{
						l = 2;
						break;
					}
				}

				if (l) break;
			}
		}

		if (!l) return NULL;
	}
	else
	{
		// path starting with /
		if (c.size() > 1 && !c[0].size())
		{
			// path starting with //
			if (c.size() > 2 && !c[1].size())
			{
				if (c[2] == "in") n = client->nodebyhandle(client->rootnodes[1]);
				else if (c[2] == "bin") n = client->nodebyhandle(client->rootnodes[2]);
				else if (c[2] == "mail") n = client->nodebyhandle(client->rootnodes[3]);
				else return NULL;

				l = 3;
			}
			else
			{
				n = client->nodebyhandle(client->rootnodes[0]);

				l = 1;
			}
		}
		else n = client->nodebyhandle(cwd);
	}

	// parse relative path
	while (n && l < (int)c.size())
	{
		if (c[l] != ".")
		{
			if (c[l] == "..")
			{
				if (n->parent) n = n->parent;
			}
			else
			{
				// locate child node (explicit ambiguity resolution: not implemented)
				if (c[l].size())
				{
					nn = client->childnodebyname(n,c[l].c_str());

					if (!nn)
					{
						// mv command target? return name part of not found
						if (namepart && l == (int)c.size()-1)
						{
							*namepart = c[l];
							return n;
						}

						return NULL;
					}

					n = nn;
				}
			}
		}

		l++;
	}

	return n;
}

SyncApp:: SyncApp (string local_folder_, string remote_folder_):
    local_folder (local_folder_), remote_folder (remote_folder_), cwd (UNDEF), initial_fetch (true)
{
}

// callback for displaying debug logs
void SyncApp::debug_log(const char* message)
{
    if (debug)
        cout << "DEBUG: " << message << endl;
}

// this callback function is called when we have login result (success or error)
// TODO: check for errors
void SyncApp::login_result(error e)
{
    if (e != API_OK) {
        cout << "FATAL: Failed to get login result, exiting" << endl;
        exit (1);
    }
    // get the list of nodes
    client->fetchnodes();
}

void SyncApp::fetchnodes_result (error e)
{
    if (e != API_OK) {
        cout << "FATAL: Failed to fetch remote nodes, exiting" << endl;
        exit (1);
    }

    cout << "fetchnodes_result" << endl;

    if (initial_fetch) {
        initial_fetch = false;
        if (ISUNDEF(cwd)) cwd = client->rootnodes[0];

        Node* n = nodebypath(remote_folder.c_str());
        if (client->checkaccess(n, FULL))
        {
            string localname;

            client->fsaccess->path2local(&local_folder, &localname);

            if (!n) {
                cout << remote_folder << ": Not found." << endl;
                exit (1);
            } else if (n->type == FILENODE) {
                cout << remote_folder << ": Remote sync root must be folder." << endl;
                exit (1);
            } else {
                error e = client->addsync(&localname,n,0);
                if (e) {
                    cout << "Sync could not be added! " << endl;
                    exit (1);
                }

                cout << "Sync started !" << endl;
            }
        } else {
            cout << remote_folder << ": Syncing requires full access to path." << endl;
            exit (1);
        }
    }
}

// this callback function is called when request-level error occurred
void SyncApp::request_error(error e)
{
    cout << "FATAL: Request failed, exiting" << endl;
    exit (1);
}

void SyncApp::syncupdate_state(Sync*, syncstate state)
{
    if (state == SYNC_CANCELED || state == SYNC_FAILED) {
        cout << "FATAL: Sync failed !" << endl;
        exit (1);
    } else if (state == SYNC_ACTIVE) {
		cout << "Sync is now active" << endl;
    }
}

void SyncApp::syncupdate_stuck(string* reason)
{
	if (reason) cout << "Sync halted: " << *reason << " temporarily in use" << endl;
	else cout << "Sync resumed" << endl;
}

// sync update callbacks are for informational purposes only and must not change or delete the sync itself
void SyncApp::syncupdate_local_folder_addition(Sync* sync, const char* path)
{
    if (debug)
	cout << "Sync - local folder addition detected: " << path << endl;
}

void SyncApp::syncupdate_local_folder_deletion(Sync* sync, const char* path)
{
    if (debug)
	cout << "Sync - local folder deletion detected: " << path << endl;
}

void SyncApp::syncupdate_local_file_addition(Sync* sync, const char* path)
{
    if (debug)
	cout << "Sync - local file addition detected: " << path << endl;
}

void SyncApp::syncupdate_local_file_deletion(Sync* sync, const char* path)
{
    if (debug)
	cout << "Sync - local file deletion detected: " << path << endl;
}

void SyncApp::syncupdate_local_file_change(Sync* sync, const char* path)
{
    if (debug)
	cout << "Sync - local file change detected: " << path << endl;
}

void SyncApp::syncupdate_local_move(Sync*, const char* from, const char* to)
{
    if (debug)
	cout << "Sync - local rename/move " << from << " -> " << to << endl;
}

void SyncApp::syncupdate_remote_move(string* from, string* to)
{
    if (debug)
	cout << "Sync - remote rename/move " << *from << " -> " << *to << endl;
}

void SyncApp::syncupdate_remote_folder_addition(Node* n)
{
    if (debug)
	cout << "Sync - remote folder addition detected " << n->displayname() << endl;
}

void SyncApp::syncupdate_remote_file_addition(Node* n)
{
    if (debug)
	cout << "Sync - remote file addition detected " << n->displayname() << endl;
}

void SyncApp::syncupdate_remote_folder_deletion(Node* n)
{
    if (debug)
	cout << "Sync - remote folder deletion detected " << n->displayname() << endl;
}

void SyncApp::syncupdate_remote_file_deletion(Node* n)
{
    if (debug)
	cout << "Sync - remote file deletion detected " << n->displayname() << endl;
}

void SyncApp::syncupdate_get(Sync*, const char* path)
{
    if (debug)
	cout << "Sync - requesting file " << path << endl;
}

void SyncApp::syncupdate_put(Sync*, const char* path)
{
    if (debug)
	cout << "Sync - sending file " << path << endl;
}

void SyncApp::syncupdate_remote_copy(Sync*, const char* name)
{
    if (debug)
	cout << "Sync - creating remote file " << name << " by copying existing remote file" << endl;
}

//
int main (int argc, char *argv[])
{
    static byte pwkey[SymmCipher::KEYLENGTH];
    bool is_active = true;
    SyncApp *app;

    if (argc < 3) {
        cout << "Usage: " << argv[0] << " [local folder] [remote folder]" << endl;
        return 1;
    }

    app = new SyncApp (argv[1], argv[2]);

    if (!getenv ("MEGA_EMAIL") || !getenv ("MEGA_PWD")) {
        cout << "Please set both MEGA_EMAIL and MEGA_PWD env variables!" << endl;
        return 1;
    }

    // if MEGA_DEBUG env variable is set
    if (getenv ("MEGA_DEBUG") {
        if !strcmp (getenv ("MEGA_DEBUG"), "1")) {
            app->debug = true;
        } else if !strcmp (getenv ("MEGA_DEBUG"), "2")) {
            app->debug = true;
            mega::debug = true;
        }
    } else
        mega::debug = false;

    // create MegaClient, providing our custom MegaApp and Waiter classes
    client = new MegaClient(app, new WAIT_CLASS, new HTTPIO_CLASS, new FSACCESS_CLASS,
#ifdef DBACCESS_CLASS
	new DBACCESS_CLASS,
#else
	NULL,
#endif
    "megasync");

    // get values from env
    client->pw_key (getenv ("MEGA_PWD"), pwkey);
    client->login (getenv ("MEGA_EMAIL"), pwkey);

    while (is_active) {
	    // pass the CPU to the engine (nonblocking)
		client->exec();
		client->wait();
    }

    return 0;
}
<commit_msg>fix compilation error<commit_after>/**
 * @file examples/megasync.cpp
 * @brief sample daemon, which synchronizes local and remote folders
 *
 * (c) 2013 by Mega Limited, Wellsford, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "mega.h"

#ifdef _WIN32
#include <conio.h>
#endif

using namespace mega;

class SyncApp : public MegaApp
{
    string remote_folder;
    string local_folder;
    handle cwd;
    bool initial_fetch;

    void debug_log(const char*);
    void login_result(error e);

	void fetchnodes_result (error e);

    void request_error(error e);
	void syncupdate_state(Sync*, syncstate);

	void syncupdate_stuck(string*);
	void syncupdate_local_folder_addition(Sync*, const char*);
	void syncupdate_local_folder_deletion(Sync*, const char*);
	void syncupdate_local_file_addition(Sync*, const char*);
	void syncupdate_local_file_deletion(Sync*, const char*);
	void syncupdate_local_file_change(Sync*, const char*);
	void syncupdate_local_move(Sync*, const char*, const char*);
	void syncupdate_get(Sync*, const char*);
	void syncupdate_put(Sync*, const char*);
	void syncupdate_remote_file_addition(Node*);
	void syncupdate_remote_file_deletion(Node*);
	void syncupdate_remote_folder_addition(Node*);
	void syncupdate_remote_folder_deletion(Node*);
	void syncupdate_remote_copy(Sync*, const char*);
	void syncupdate_remote_move(string*, string*);

    Node* nodebypath(const char* ptr, string* user, string* namepart);
public:
    bool debug;
    SyncApp (string local_folder_, string remote_folder_);
};

// globals
MegaClient* client;
bool mega::debug = false;

// returns node pointer determined by path relative to cwd
// Path naming conventions:
// path is relative to cwd
// /path is relative to ROOT
// //in is in INBOX
// //bin is in RUBBISH
// X: is user X's INBOX
// X:SHARE is share SHARE from user X
// : and / filename components, as well as the \, must be escaped by \.
// (correct UTF-8 encoding is assumed)
// returns NULL if path malformed or not found
Node* SyncApp::nodebypath(const char* ptr, string* user = NULL, string* namepart = NULL)
{
	vector<string> c;
	string s;
	int l = 0;
	const char* bptr = ptr;
	int remote = 0;
	Node* n;
	Node* nn;

	// split path by / or :
	do {
		if (!l)
		{
			if (*ptr >= 0)
			{
				if (*ptr == '\\')
				{
					if (ptr > bptr) s.append(bptr,ptr-bptr);
					bptr = ++ptr;

					if (*bptr == 0)
					{
						c.push_back(s);
						break;
					}

					ptr++;
					continue;
				}

				if (*ptr == '/' || *ptr == ':' || !*ptr)
				{
					if (*ptr == ':')
					{
						if (c.size()) return NULL;
						remote = 1;
					}

					if (ptr > bptr) s.append(bptr,ptr-bptr);

					bptr = ptr+1;

					c.push_back(s);

					s.erase();
				}
			}
			else if ((*ptr & 0xf0) == 0xe0) l = 1;
			else if ((*ptr & 0xf8) == 0xf0) l = 2;
			else if ((*ptr & 0xfc) == 0xf8) l = 3;
			else if ((*ptr & 0xfe) == 0xfc) l = 4;
		}
		else l--;
	} while (*ptr++);

	if (l) return NULL;

	if (remote)
	{
		// target: user inbox - record username/email and return NULL
		if (c.size() == 2 && !c[1].size())
		{
			if (user) *user = c[0];
			return NULL;
		}

		User* u;

		if ((u = client->finduser(c[0].c_str())))
		{
			// locate matching share from this user
			handle_set::iterator sit;

			for (sit = u->sharing.begin(); sit != u->sharing.end(); sit++)
			{
				if ((n = client->nodebyhandle(*sit)))
				{
					if (!strcmp(c[1].c_str(),n->displayname()))
					{
						l = 2;
						break;
					}
				}

				if (l) break;
			}
		}

		if (!l) return NULL;
	}
	else
	{
		// path starting with /
		if (c.size() > 1 && !c[0].size())
		{
			// path starting with //
			if (c.size() > 2 && !c[1].size())
			{
				if (c[2] == "in") n = client->nodebyhandle(client->rootnodes[1]);
				else if (c[2] == "bin") n = client->nodebyhandle(client->rootnodes[2]);
				else if (c[2] == "mail") n = client->nodebyhandle(client->rootnodes[3]);
				else return NULL;

				l = 3;
			}
			else
			{
				n = client->nodebyhandle(client->rootnodes[0]);

				l = 1;
			}
		}
		else n = client->nodebyhandle(cwd);
	}

	// parse relative path
	while (n && l < (int)c.size())
	{
		if (c[l] != ".")
		{
			if (c[l] == "..")
			{
				if (n->parent) n = n->parent;
			}
			else
			{
				// locate child node (explicit ambiguity resolution: not implemented)
				if (c[l].size())
				{
					nn = client->childnodebyname(n,c[l].c_str());

					if (!nn)
					{
						// mv command target? return name part of not found
						if (namepart && l == (int)c.size()-1)
						{
							*namepart = c[l];
							return n;
						}

						return NULL;
					}

					n = nn;
				}
			}
		}

		l++;
	}

	return n;
}

SyncApp:: SyncApp (string local_folder_, string remote_folder_):
    local_folder (local_folder_), remote_folder (remote_folder_), cwd (UNDEF), initial_fetch (true)
{
}

// callback for displaying debug logs
void SyncApp::debug_log(const char* message)
{
    if (debug)
        cout << "DEBUG: " << message << endl;
}

// this callback function is called when we have login result (success or error)
// TODO: check for errors
void SyncApp::login_result(error e)
{
    if (e != API_OK) {
        cout << "FATAL: Failed to get login result, exiting" << endl;
        exit (1);
    }
    // get the list of nodes
    client->fetchnodes();
}

void SyncApp::fetchnodes_result (error e)
{
    if (e != API_OK) {
        cout << "FATAL: Failed to fetch remote nodes, exiting" << endl;
        exit (1);
    }

    cout << "fetchnodes_result" << endl;

    if (initial_fetch) {
        initial_fetch = false;
        if (ISUNDEF(cwd)) cwd = client->rootnodes[0];

        Node* n = nodebypath(remote_folder.c_str());
        if (client->checkaccess(n, FULL))
        {
            string localname;

            client->fsaccess->path2local(&local_folder, &localname);

            if (!n) {
                cout << remote_folder << ": Not found." << endl;
                exit (1);
            } else if (n->type == FILENODE) {
                cout << remote_folder << ": Remote sync root must be folder." << endl;
                exit (1);
            } else {
                error e = client->addsync(&localname,n,0);
                if (e) {
                    cout << "Sync could not be added! " << endl;
                    exit (1);
                }

                cout << "Sync started !" << endl;
            }
        } else {
            cout << remote_folder << ": Syncing requires full access to path." << endl;
            exit (1);
        }
    }
}

// this callback function is called when request-level error occurred
void SyncApp::request_error(error e)
{
    cout << "FATAL: Request failed, exiting" << endl;
    exit (1);
}

void SyncApp::syncupdate_state(Sync*, syncstate state)
{
    if (state == SYNC_CANCELED || state == SYNC_FAILED) {
        cout << "FATAL: Sync failed !" << endl;
        exit (1);
    } else if (state == SYNC_ACTIVE) {
		cout << "Sync is now active" << endl;
    }
}

void SyncApp::syncupdate_stuck(string* reason)
{
	if (reason) cout << "Sync halted: " << *reason << " temporarily in use" << endl;
	else cout << "Sync resumed" << endl;
}

// sync update callbacks are for informational purposes only and must not change or delete the sync itself
void SyncApp::syncupdate_local_folder_addition(Sync* sync, const char* path)
{
    if (debug)
	cout << "Sync - local folder addition detected: " << path << endl;
}

void SyncApp::syncupdate_local_folder_deletion(Sync* sync, const char* path)
{
    if (debug)
	cout << "Sync - local folder deletion detected: " << path << endl;
}

void SyncApp::syncupdate_local_file_addition(Sync* sync, const char* path)
{
    if (debug)
	cout << "Sync - local file addition detected: " << path << endl;
}

void SyncApp::syncupdate_local_file_deletion(Sync* sync, const char* path)
{
    if (debug)
	cout << "Sync - local file deletion detected: " << path << endl;
}

void SyncApp::syncupdate_local_file_change(Sync* sync, const char* path)
{
    if (debug)
	cout << "Sync - local file change detected: " << path << endl;
}

void SyncApp::syncupdate_local_move(Sync*, const char* from, const char* to)
{
    if (debug)
	cout << "Sync - local rename/move " << from << " -> " << to << endl;
}

void SyncApp::syncupdate_remote_move(string* from, string* to)
{
    if (debug)
	cout << "Sync - remote rename/move " << *from << " -> " << *to << endl;
}

void SyncApp::syncupdate_remote_folder_addition(Node* n)
{
    if (debug)
	cout << "Sync - remote folder addition detected " << n->displayname() << endl;
}

void SyncApp::syncupdate_remote_file_addition(Node* n)
{
    if (debug)
	cout << "Sync - remote file addition detected " << n->displayname() << endl;
}

void SyncApp::syncupdate_remote_folder_deletion(Node* n)
{
    if (debug)
	cout << "Sync - remote folder deletion detected " << n->displayname() << endl;
}

void SyncApp::syncupdate_remote_file_deletion(Node* n)
{
    if (debug)
	cout << "Sync - remote file deletion detected " << n->displayname() << endl;
}

void SyncApp::syncupdate_get(Sync*, const char* path)
{
    if (debug)
	cout << "Sync - requesting file " << path << endl;
}

void SyncApp::syncupdate_put(Sync*, const char* path)
{
    if (debug)
	cout << "Sync - sending file " << path << endl;
}

void SyncApp::syncupdate_remote_copy(Sync*, const char* name)
{
    if (debug)
	cout << "Sync - creating remote file " << name << " by copying existing remote file" << endl;
}

//
int main (int argc, char *argv[])
{
    static byte pwkey[SymmCipher::KEYLENGTH];
    bool is_active = true;
    SyncApp *app;

    if (argc < 3) {
        cout << "Usage: " << argv[0] << " [local folder] [remote folder]" << endl;
        return 1;
    }

    app = new SyncApp (argv[1], argv[2]);

    if (!getenv ("MEGA_EMAIL") || !getenv ("MEGA_PWD")) {
        cout << "Please set both MEGA_EMAIL and MEGA_PWD env variables!" << endl;
        return 1;
    }

    // if MEGA_DEBUG env variable is set
    if (getenv ("MEGA_DEBUG")) {
        if (!strcmp (getenv ("MEGA_DEBUG"), "1")) {
            app->debug = true;
        } else if (!strcmp (getenv ("MEGA_DEBUG"), "2")) {
            app->debug = true;
            mega::debug = true;
        }
    } else
        mega::debug = false;

    // create MegaClient, providing our custom MegaApp and Waiter classes
    client = new MegaClient(app, new WAIT_CLASS, new HTTPIO_CLASS, new FSACCESS_CLASS,
#ifdef DBACCESS_CLASS
	new DBACCESS_CLASS,
#else
	NULL,
#endif
    "megasync");

    // get values from env
    client->pw_key (getenv ("MEGA_PWD"), pwkey);
    client->login (getenv ("MEGA_EMAIL"), pwkey);

    while (is_active) {
	    // pass the CPU to the engine (nonblocking)
		client->exec();
		client->wait();
    }

    return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include "qtype.hpp"

/***********************************************************************************************************************
* 消息频道定义
***********************************************************************************************************************/
#define QWSC_ORGNIZIATION "jilong"

#define QWSC_MODULE_APP "app"
#define QWSC_MODULE_SRV "srv"

#define QWSC_CHANNEL_GUI QWSC_ORGNIZIATION##"/"##QWSC_MODULE_APP##"/"##"gui"
#define QWSC_CHANNEL_FUSION QWSC_ORGNIZIATION##"/"##QWSC_MODULE_SRV##"/"##"fusion"

/***********************************************************************************************************************
* 消息类型定义
***********************************************************************************************************************/
#define MSG_START_FUSION         "MSG_START_FUSION"
#define MSG_STOP_FUSION          "MSG_STOP_FUSION"
#define MSG_START_HEAT           "MSG_START_HEAT"
#define MSG_STOP_HEAT            "MSG_STOP_HEAT"
#define MSG_MOVE_MOTOR           "MSG_MOVE_MOTOR"
#define MSG_STOP_MOTOR           "MSG_STOP_MOTOR"
#define MSG_MOVE_CAMERA          "MSG_MOVE_CAMERA"
#define MSG_START_TEST1          "MSG_START_TEST1"
#define MSG_SET_DISPLAY_MODE     "MSG_SET_DISPLAY_MODE"

/***********************************************************************************************************************
* 加热模块数据定义
***********************************************************************************************************************/

/* 光纤材料类型 */
typedef enum tagMaterialType
{
        MATERIAL_STANDARD = 0,                           /* Standard */
        MATERIAL_MICRO_250 = 1,                          /* Micro_250 */
        MATERIAL_MICRO_400 = 2,                          /* Micro_400 */
        MATERIAL_MICRO_900 = 3,                          /* Micro_900 */

        MATERIAL_NULL
}MATERIAL_TYPE;

/*光纤长度类型*/
typedef enum tagFibreLenType
{
        FIBRE_LEN_40MM = 0,                              /* 40mm */
        FIBRE_LEN_60MM = 1,                              /* 60mm */

        FIBRE_LEN_NULL
}FIBRE_LEN_TYPE;

/***********************************************************************************************************************
* 熔接模块数据定义
***********************************************************************************************************************/

/* 熔接模式 */
typedef enum tagWeldPattern
{
        WELD_PATTERN_AUTO,
        WELD_PATTERN_CALIBRATE,
        WELD_PATTERN_NORMAL,
        WELD_PATTERN_SPECIAL,
        WELD_PATERN_BLANK
}WELD_PATTERN_E;

/* 光纤类型 */
typedef enum tagFibreType
{
        FIBRE_TYPE_SM,
        FIBRE_TYPE_DS,
        FIBRE_TYPE_NZ,
        FIBRE_TYPE_NM,
        FIBRE_TYPE_LF_LF,
        FIBRE_TYPE_RS_RS,
        FIBRE_TYPE_RCH_RCH,
        FIBRE_TYPE_HI_HI,
        FIBRE_TYPE_FX_FX,
        FIBRE_TYPE_SM080,
        FIBRE_TYPE_SM80125,
        FIBRE_TYPE_TR_TR,
        FIBRE_TYPE_TRU_TRU,
        FIBRE_TYPE_FR_FR,
        FIBRE_TYPE_MT_MT,
        FIBRE_TYPE_ULA,
        FIBRE_TYPE_LA_LA,
        FIBRE_TYPE_SS_SS,

        FIBRE_TYPE_END
}FIBRE_TYPE_E;

/* 光纤对齐方式 */
typedef enum tagFibreAlignment
{
        FIBRE_ALIGN_FINE_CORE,                          /* 精细对芯 */
        FIBRE_ALIGN_CLADDING,                           /* 包层 */
        FIBRE_ALIGN_CORE,                               /* 纤芯 */
        FIBRE_ALIGN_MANUAL                              /* 手动 */
}FIBRE_ALIGNMENT_E;

typedef enum tagFibreShiftCompensantion
{
        FIBRE_SHIFT_COMPENSANTION_AUTOMATIC            /* 纤芯偏移补偿功能:自动 */
}FIBRE_SHIFT_COMPENSANTION_E;

/* 光纤算好估计方式 */
typedef enum tagFibreLossEstimation
{
        FIBRE_LOSS_ESTIMATION_DELICATE,                 /* 精细估算 */
        FIBRE_LOSS_ESTIMATION_CLADDING,                 /* 包层估算 */
        FIBRE_LOSS_ESTIMATION_CORE,                     /* 纤芯估算 */
        FIBRE_LOSS_ESTIMATION_OFF                       /* 关闭 */
}FIBRE_LOSS_ESTIMATION_E;

/* 图像坐标显示方式 */
typedef enum tagCoordinate
{
        COOR_X,                                         /* X */
        COOR_Y,                                         /* Y */
        COOR_X1Y,                                       /* X/Y */
        COOR_X2Y,                                       /* X|Y */
        COOR_X3Y,                                       /* X=>Y */
        COOR_X4Y                                        /* Y=>X */
}COORDINATE_E;

/**
 * \brief service state
 */
enum class svc_state_t{
    fs_reset,
    fs_idle,
    fs_clring,
    ///
    heat_idle
};

/**
 * \brief motor id
 */
enum motorId_t {
    LZ = 0,	// left z
    RZ,	// right z
    X,	// x
    Y,	// y
    NUM	// total number
};

typedef enum
{
    DISPLAY_MODE_X  = 0x0,	/// only x
    DISPLAY_MODE_Y  = 0x1,	/// only y
    DISPLAY_MODE_TB = 0x2,	/// top <-> bottom
    DISPLAY_MODE_LR = 0x3,	/// left <-> right
    DISPLAY_MODE_N  = 0x4	/// no
} DISPLAY_MODE_E;

/* 加热参数 */
typedef struct tagHeatPara                                 /* 加热参数 */
{
    MATERIAL_TYPE eMaterialType;                       /* 材料类型 */
    FIBRE_LEN_TYPE eFibreLenType;                      /* 长度类型 */
    BOOL bHeatControl;                                 /* 是否使用加热控制 */
    ULONG ulHeatMinute;                                /* 加热时间 */
    ULONG ulHeatTemperature;                           /* 加热温度 */
    ULONG ulHeatFinishTemperature;                     /* 结束温度 */
}HEAT_PARA_S;

/* 熔接参数 */
typedef struct tagWeldPara
{
    WELD_PATTERN_E eWeldPattern;                    /* 熔接模式 */
    FIBRE_TYPE_E eFibreType;                        /* 光纤类型 */
    FIBRE_ALIGNMENT_E eFibreAlignment;              /* 光纤对准选择 */
    BOOL bXImageFocus;                              /* x图像聚焦 */
    BOOL bYImageFocus;                              /* y图像聚焦 */
    FIBRE_SHIFT_COMPENSANTION_E eFibreShift;        /* 纤芯偏移补偿功能 */
    BOOL bDischargeStrengthAdjustment;              /* 放电强度自动调整 */
    BOOL bTensionSet;                               /* 拉力测试 */
    FLOAT fCutAngleLimit;                           /* 切割角限定 */
    FLOAT fLossLimit;                               /* 损耗限定 */
    FLOAT fFibreAngleLimit;                         /* 纤芯角限定 */
    ULONG ulCleanDischargeTime;                     /* 清洁放电时间 */
    ULONG ulFibreIntervalSetup;                     /* 光纤间隙设定 */
    LONG  lWeldPosSetup;                            /* 熔接位置设定 */
    ULONG ulFibrePreWeldingStrength;                /* 光纤预熔强度 */
    ULONG ulFibrePreWeldingTime;                    /* 光纤预熔时间 */
    ULONG ulFibreOverlapSetup;                      /* 熔接重叠量设定 */
    ULONG ulDischarge1Strength;                     /* 放电1强度 */
    ULONG ulDischarge1Time;                         /* 放电1时间 */
    ULONG ulDischarge2Strength;                     /* 放电2强度 */
    ULONG ulDischarge2LastTime;                     /* 放电2持续时间 */
    ULONG ulDischarge2StartTime;                    /* 放电2接通时间 */
    ULONG ulDischarge2StopTime;                     /* 放电2关闭时间 */
    ULONG ulExtraManualDischargeTime;               /* 手动补充放电定时 */
    BOOL bConeWelding;                              /* 锥形熔接 */
    ULONG ulConeWeldingWaitTime;                    /* 锥形熔接等待时间 */
    ULONG ulConeWeldingSpeed;                       /* 锥形熔接速度 bit */
    ULONG ulConeWeldingStretchLength;               /* 锥形熔接拉伸长度 um */
    FIBRE_LOSS_ESTIMATION_E eLossEstimationMode;    /* 算好估算方式 */
    FLOAT fLeftFibreMFD;                            /* 左纤模场直径(MFD)设定 */
    FLOAT fRightFibreMFD;                           /* 右纤模场直径(MFD)设定 */
    FLOAT fLeastLoss;                               /* 最小损耗 dB */
    FLOAT fRateOfSyntropyBending;                   /* 纤芯同向弯曲系数 */
    FLOAT fRateOfReverseBending;                    /* 纤芯反向弯曲系数 */
    FLOAT fRateOfMFDDeviation;                      /* 模场直径(MFD)失配系数 */

/* 熔接操作选项 */
    /* 操作选项 */
    BOOL bAutoStart;                                /* 自动开始:打开或关闭 */
    BOOL bStop1;                                    /* 停止1 */
    BOOL bStop2;                                    /* 停止1 */

    /* 数据显示 */
    BOOL bCutAngle;                                 /* 切割角度显示 */
    BOOL bOffsetData;                               /* 偏移数据显示 */

    /* 忽略选项 */
    BOOL bCut;                                      /* 切割 */
    BOOL bLoss;                                     /* 损耗 */
    BOOL bFibreCoreAngle;                           /* 纤芯角 */
    BOOL bBubble;                                   /* 气泡 */
    BOOL bThick;                                    /* 粗 */
    BOOL bThin;                                     /* 细 */

    /* 放电补偿 */
    BOOL bAirPressure;                              /* 气压 */
    BOOL bTemperature;                              /* 温度 */

    /* 光纤图像显示 */
    COORDINATE_E eGap;                              /* 间隙设定 */
    COORDINATE_E eStop1;                            /* 暂停1 */
    COORDINATE_E eAlign;                            /* 对准 */
    COORDINATE_E eStop2;                            /* 暂停2 */
    COORDINATE_E eDischarge;                        /* 放电 */
    COORDINATE_E eLossEstimation;                   /* 损耗估算 */

    /* 其他 */
    BOOL bFibreAutoFeed;                            /* 光纤自动推进 */
    BOOL bBadCutSurface;                            /* 切割端面不良 */
    BOOL bAutoAlignAfterStop;                       /* 暂停后自动对齐 */
    ULONG bManualDischargeTimes;                    /* 手动补充放电次数限定 */

}WELD_PARA_S;

//camera window info
typedef struct tagCameraPara
{
    bool is_pos_x;
    int row;
    int column;
}CAMERA_PARA_S;

typedef struct tagMotorPara
{
    int motorId;
    bool direction;
}MotorPara_S;
<commit_msg>modify qmsg<commit_after>#pragma once

#include "qtype.hpp"

/***********************************************************************************************************************
* 消息频道定义
***********************************************************************************************************************/
#define QWSC_ORGNIZIATION "jilong"

#define QWSC_MODULE_APP "app"
#define QWSC_MODULE_SRV "srv"

#define QWSC_CHANNEL_GUI QWSC_ORGNIZIATION##QWSC_MODULE_APP##gui"
#define QWSC_CHANNEL_FUSION QWSC_ORGNIZIATION##QWSC_MODULE_SRV##"fusion"

/***********************************************************************************************************************
* 消息类型定义
***********************************************************************************************************************/
#define MSG_START_FUSION         "MSG_START_FUSION"
#define MSG_STOP_FUSION          "MSG_STOP_FUSION"
#define MSG_START_HEAT           "MSG_START_HEAT"
#define MSG_STOP_HEAT            "MSG_STOP_HEAT"
#define MSG_MOVE_MOTOR           "MSG_MOVE_MOTOR"
#define MSG_STOP_MOTOR           "MSG_STOP_MOTOR"
#define MSG_MOVE_CAMERA          "MSG_MOVE_CAMERA"
#define MSG_START_TEST1          "MSG_START_TEST1"
#define MSG_SET_DISPLAY_MODE     "MSG_SET_DISPLAY_MODE"

/***********************************************************************************************************************
* 加热模块数据定义
***********************************************************************************************************************/

/* 光纤材料类型 */
typedef enum tagMaterialType
{
        MATERIAL_STANDARD = 0,                           /* Standard */
        MATERIAL_MICRO_250 = 1,                          /* Micro_250 */
        MATERIAL_MICRO_400 = 2,                          /* Micro_400 */
        MATERIAL_MICRO_900 = 3,                          /* Micro_900 */

        MATERIAL_NULL
}MATERIAL_TYPE;

/*光纤长度类型*/
typedef enum tagFibreLenType
{
        FIBRE_LEN_40MM = 0,                              /* 40mm */
        FIBRE_LEN_60MM = 1,                              /* 60mm */

        FIBRE_LEN_NULL
}FIBRE_LEN_TYPE;

/***********************************************************************************************************************
* 熔接模块数据定义
***********************************************************************************************************************/

/* 熔接模式 */
typedef enum tagWeldPattern
{
        WELD_PATTERN_AUTO,
        WELD_PATTERN_CALIBRATE,
        WELD_PATTERN_NORMAL,
        WELD_PATTERN_SPECIAL,
        WELD_PATERN_BLANK
}WELD_PATTERN_E;

/* 光纤类型 */
typedef enum tagFibreType
{
        FIBRE_TYPE_SM,
        FIBRE_TYPE_DS,
        FIBRE_TYPE_NZ,
        FIBRE_TYPE_NM,
        FIBRE_TYPE_LF_LF,
        FIBRE_TYPE_RS_RS,
        FIBRE_TYPE_RCH_RCH,
        FIBRE_TYPE_HI_HI,
        FIBRE_TYPE_FX_FX,
        FIBRE_TYPE_SM080,
        FIBRE_TYPE_SM80125,
        FIBRE_TYPE_TR_TR,
        FIBRE_TYPE_TRU_TRU,
        FIBRE_TYPE_FR_FR,
        FIBRE_TYPE_MT_MT,
        FIBRE_TYPE_ULA,
        FIBRE_TYPE_LA_LA,
        FIBRE_TYPE_SS_SS,

        FIBRE_TYPE_END
}FIBRE_TYPE_E;

/* 光纤对齐方式 */
typedef enum tagFibreAlignment
{
        FIBRE_ALIGN_FINE_CORE,                          /* 精细对芯 */
        FIBRE_ALIGN_CLADDING,                           /* 包层 */
        FIBRE_ALIGN_CORE,                               /* 纤芯 */
        FIBRE_ALIGN_MANUAL                              /* 手动 */
}FIBRE_ALIGNMENT_E;

typedef enum tagFibreShiftCompensantion
{
        FIBRE_SHIFT_COMPENSANTION_AUTOMATIC            /* 纤芯偏移补偿功能:自动 */
}FIBRE_SHIFT_COMPENSANTION_E;

/* 光纤算好估计方式 */
typedef enum tagFibreLossEstimation
{
        FIBRE_LOSS_ESTIMATION_DELICATE,                 /* 精细估算 */
        FIBRE_LOSS_ESTIMATION_CLADDING,                 /* 包层估算 */
        FIBRE_LOSS_ESTIMATION_CORE,                     /* 纤芯估算 */
        FIBRE_LOSS_ESTIMATION_OFF                       /* 关闭 */
}FIBRE_LOSS_ESTIMATION_E;

/* 图像坐标显示方式 */
typedef enum tagCoordinate
{
        COOR_X,                                         /* X */
        COOR_Y,                                         /* Y */
        COOR_X1Y,                                       /* X/Y */
        COOR_X2Y,                                       /* X|Y */
        COOR_X3Y,                                       /* X=>Y */
        COOR_X4Y                                        /* Y=>X */
}COORDINATE_E;

/**
 * \brief service state
 */
enum class svc_state_t{
    fs_reset,
    fs_idle,
    fs_clring,
    ///
    heat_idle
};

/**
 * \brief motor id
 */
enum motorId_t {
    LZ = 0,	// left z
    RZ,	// right z
    X,	// x
    Y,	// y
    NUM	// total number
};

typedef enum
{
    DISPLAY_MODE_X  = 0x0,	/// only x
    DISPLAY_MODE_Y  = 0x1,	/// only y
    DISPLAY_MODE_TB = 0x2,	/// top <-> bottom
    DISPLAY_MODE_LR = 0x3,	/// left <-> right
    DISPLAY_MODE_N  = 0x4	/// no
} DISPLAY_MODE_E;

/* 加热参数 */
typedef struct tagHeatPara                                 /* 加热参数 */
{
    MATERIAL_TYPE eMaterialType;                       /* 材料类型 */
    FIBRE_LEN_TYPE eFibreLenType;                      /* 长度类型 */
    BOOL bHeatControl;                                 /* 是否使用加热控制 */
    ULONG ulHeatMinute;                                /* 加热时间 */
    ULONG ulHeatTemperature;                           /* 加热温度 */
    ULONG ulHeatFinishTemperature;                     /* 结束温度 */
}HEAT_PARA_S;

/* 熔接参数 */
typedef struct tagWeldPara
{
    WELD_PATTERN_E eWeldPattern;                    /* 熔接模式 */
    FIBRE_TYPE_E eFibreType;                        /* 光纤类型 */
    FIBRE_ALIGNMENT_E eFibreAlignment;              /* 光纤对准选择 */
    BOOL bXImageFocus;                              /* x图像聚焦 */
    BOOL bYImageFocus;                              /* y图像聚焦 */
    FIBRE_SHIFT_COMPENSANTION_E eFibreShift;        /* 纤芯偏移补偿功能 */
    BOOL bDischargeStrengthAdjustment;              /* 放电强度自动调整 */
    BOOL bTensionSet;                               /* 拉力测试 */
    FLOAT fCutAngleLimit;                           /* 切割角限定 */
    FLOAT fLossLimit;                               /* 损耗限定 */
    FLOAT fFibreAngleLimit;                         /* 纤芯角限定 */
    ULONG ulCleanDischargeTime;                     /* 清洁放电时间 */
    ULONG ulFibreIntervalSetup;                     /* 光纤间隙设定 */
    LONG  lWeldPosSetup;                            /* 熔接位置设定 */
    ULONG ulFibrePreWeldingStrength;                /* 光纤预熔强度 */
    ULONG ulFibrePreWeldingTime;                    /* 光纤预熔时间 */
    ULONG ulFibreOverlapSetup;                      /* 熔接重叠量设定 */
    ULONG ulDischarge1Strength;                     /* 放电1强度 */
    ULONG ulDischarge1Time;                         /* 放电1时间 */
    ULONG ulDischarge2Strength;                     /* 放电2强度 */
    ULONG ulDischarge2LastTime;                     /* 放电2持续时间 */
    ULONG ulDischarge2StartTime;                    /* 放电2接通时间 */
    ULONG ulDischarge2StopTime;                     /* 放电2关闭时间 */
    ULONG ulExtraManualDischargeTime;               /* 手动补充放电定时 */
    BOOL bConeWelding;                              /* 锥形熔接 */
    ULONG ulConeWeldingWaitTime;                    /* 锥形熔接等待时间 */
    ULONG ulConeWeldingSpeed;                       /* 锥形熔接速度 bit */
    ULONG ulConeWeldingStretchLength;               /* 锥形熔接拉伸长度 um */
    FIBRE_LOSS_ESTIMATION_E eLossEstimationMode;    /* 算好估算方式 */
    FLOAT fLeftFibreMFD;                            /* 左纤模场直径(MFD)设定 */
    FLOAT fRightFibreMFD;                           /* 右纤模场直径(MFD)设定 */
    FLOAT fLeastLoss;                               /* 最小损耗 dB */
    FLOAT fRateOfSyntropyBending;                   /* 纤芯同向弯曲系数 */
    FLOAT fRateOfReverseBending;                    /* 纤芯反向弯曲系数 */
    FLOAT fRateOfMFDDeviation;                      /* 模场直径(MFD)失配系数 */

/* 熔接操作选项 */
    /* 操作选项 */
    BOOL bAutoStart;                                /* 自动开始:打开或关闭 */
    BOOL bStop1;                                    /* 停止1 */
    BOOL bStop2;                                    /* 停止1 */

    /* 数据显示 */
    BOOL bCutAngle;                                 /* 切割角度显示 */
    BOOL bOffsetData;                               /* 偏移数据显示 */

    /* 忽略选项 */
    BOOL bCut;                                      /* 切割 */
    BOOL bLoss;                                     /* 损耗 */
    BOOL bFibreCoreAngle;                           /* 纤芯角 */
    BOOL bBubble;                                   /* 气泡 */
    BOOL bThick;                                    /* 粗 */
    BOOL bThin;                                     /* 细 */

    /* 放电补偿 */
    BOOL bAirPressure;                              /* 气压 */
    BOOL bTemperature;                              /* 温度 */

    /* 光纤图像显示 */
    COORDINATE_E eGap;                              /* 间隙设定 */
    COORDINATE_E eStop1;                            /* 暂停1 */
    COORDINATE_E eAlign;                            /* 对准 */
    COORDINATE_E eStop2;                            /* 暂停2 */
    COORDINATE_E eDischarge;                        /* 放电 */
    COORDINATE_E eLossEstimation;                   /* 损耗估算 */

    /* 其他 */
    BOOL bFibreAutoFeed;                            /* 光纤自动推进 */
    BOOL bBadCutSurface;                            /* 切割端面不良 */
    BOOL bAutoAlignAfterStop;                       /* 暂停后自动对齐 */
    ULONG bManualDischargeTimes;                    /* 手动补充放电次数限定 */

}WELD_PARA_S;

//camera window info
typedef struct tagCameraPara
{
    bool is_pos_x;
    int row;
    int column;
}CAMERA_PARA_S;

typedef struct tagMotorPara
{
    int motorId;
    bool direction;
}MotorPara_S;
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2010, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: project_inliers.cpp 35810 2011-02-08 00:03:46Z rusu $
 *
 */

#include "pcl/impl/instantiate.hpp"
#include "pcl/point_types.h"
#include "pcl/filters/project_inliers.h"
#include "pcl/filters/impl/project_inliers.hpp"

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::ProjectInliers<sensor_msgs::PointCloud2>::applyFilter (PointCloud2 &output)
{
  if (indices_->empty ())
  {
    ROS_WARN ("[pcl::%s::applyFilter] No indices given or empty indices!", getClassName ().c_str ());
    output.width = output.height = 0;
    output.data.clear ();
    return;
  }

  //Eigen::Map<Eigen::VectorXf, Eigen::Aligned> model_coefficients (&model_->values[0], model_->values.size ());
  // More expensive than a map but safer (32bit architectures seem to complain)
  Eigen::VectorXf model_coefficients (model_->values.size ());
  for (size_t i = 0; i < model_->values.size (); ++i)
    model_coefficients[i] = model_->values[i];

  // Construct the model and project
  if (!initSACModel (model_type_))
  {
    ROS_ERROR ("[pcl::%s::segment] Error initializing the SAC model!", getClassName ().c_str ());
    output.width = output.height = 0;
    output.data.clear ();
    return;
  }
  pcl::PointCloud<pcl::PointXYZ> cloud_out;

  if (!copy_all_fields_)
    sacmodel_->projectPoints (*indices_, model_coefficients, cloud_out, false);
  else
    sacmodel_->projectPoints (*indices_, model_coefficients, cloud_out, true);

  if (copy_all_data_)
  {
    output.height       = input_->height;
    output.width        = input_->width;
    output.is_bigendian = input_->is_bigendian;
    output.point_step   = input_->point_step;
    output.row_step     = input_->row_step;
    output.data         = input_->data;
    output.is_dense     = input_->is_dense;

    // Get the distance field index
    int x_idx, y_idx, z_idx;
    for (size_t d = 0; d < output.fields.size (); ++d)
    {
      if (output.fields[d].name == "x") x_idx = d;
      if (output.fields[d].name == "y") y_idx = d;
      if (output.fields[d].name == "z") z_idx = d;
    }

    // Copy the projected points
    for (size_t i = 0; i < indices_->size (); ++i)
    {
      memcpy (&output.data[(*indices_)[i] * output.point_step + output.fields[x_idx].offset], &cloud_out.points[(*indices_)[i]].x, sizeof (float));
      memcpy (&output.data[(*indices_)[i] * output.point_step + output.fields[y_idx].offset], &cloud_out.points[(*indices_)[i]].y, sizeof (float));
      memcpy (&output.data[(*indices_)[i] * output.point_step + output.fields[z_idx].offset], &cloud_out.points[(*indices_)[i]].z, sizeof (float));
    }
  }
  else
  {
    if (!copy_all_fields_)
    {
      pcl::toROSMsg<pcl::PointXYZ> (cloud_out, output);
    }
    else
    {
      // Copy everything
      output.height       = 1;
      output.width        = indices_->size ();
      output.point_step   = input_->point_step;
      output.data.resize (output.width * output.point_step);
      output.is_bigendian = input_->is_bigendian;
      output.row_step     = output.point_step * output.width;
      // All projections should return valid data, so is_dense = true
      output.is_dense     = true;

      // Get the distance field index
      int x_idx, y_idx, z_idx;
      for (size_t d = 0; d < output.fields.size (); ++d)
      {
        if (output.fields[d].name == "x") x_idx = d;
        if (output.fields[d].name == "y") y_idx = d;
        if (output.fields[d].name == "z") z_idx = d;
      }
      // Copy the projected points
      for (size_t i = 0; i < indices_->size (); ++i)
      {
        memcpy (&output.data[i * output.point_step], &input_->data[(*indices_)[i] * input_->point_step], output.point_step);
        memcpy (&output.data[i * output.point_step + output.fields[x_idx].offset], &cloud_out.points[(*indices_)[i]].x, sizeof (float));
        memcpy (&output.data[i * output.point_step + output.fields[y_idx].offset], &cloud_out.points[(*indices_)[i]].y, sizeof (float));
        memcpy (&output.data[i * output.point_step + output.fields[z_idx].offset], &cloud_out.points[(*indices_)[i]].z, sizeof (float));
      }
    }
  }
}

/////////////////////////////////////////////////////////////////////////////////////////////
bool
pcl::ProjectInliers<sensor_msgs::PointCloud2>::initSACModel (int model_type)
{
  // Convert the input data
  PointCloud<PointXYZ> cloud;
  fromROSMsg (*input_, cloud);
  PointCloud<PointXYZ>::Ptr cloud_ptr = cloud.makeShared ();

  // Build the model
  switch (model_type)
  {
    case SACMODEL_PLANE:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_PLANE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelPlane<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_LINE:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_LINE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelLine<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_CIRCLE2D:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_CIRCLE2D", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelCircle2D<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_SPHERE:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_SPHERE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelSphere<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_PARALLEL_LINE:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_PARALLEL_LINE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelParallelLine<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_PERPENDICULAR_PLANE:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_PERPENDICULAR_PLANE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelPerpendicularPlane<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_CYLINDER:
    {
      //ROS_DEBUG ("[pcl::%s::segment] Using a model of type: SACMODEL_CYLINDER", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelCylinder<pcl::PointXYZ, Normal> (cloud_ptr));
      break;
    }
    case SACMODEL_NORMAL_PLANE:
    {
      //ROS_DEBUG ("[pcl::%s::segment] Using a model of type: SACMODEL_NORMAL_PLANE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelNormalPlane<pcl::PointXYZ, Normal> (cloud_ptr));
      break;
    }
    case SACMODEL_NORMAL_PARALLEL_PLANE:
    {
      //ROS_DEBUG ("[pcl::%s::segment] Using a model of type: SACMODEL_NORMAL_PARALLEL_PLANE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelNormalParallelPlane<pcl::PointXYZ, Normal> (cloud_ptr));
      break;
    }
    case SACMODEL_PARALLEL_PLANE:
    {
      //ROS_DEBUG ("[pcl::%s::segment] Using a model of type: SACMODEL_PARALLEL_PLANE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelParallelPlane<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    default:
    {
      ROS_ERROR ("[pcl::%s::initSACModel] No valid model given!", getClassName ().c_str ());
      return (false);
    }
  }
  return (true);
}

// Instantiations of specific point types
PCL_INSTANTIATE(ProjectInliers, PCL_XYZ_POINT_TYPES);

<commit_msg>added default values for x/y/z plus extra checks<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2010, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: project_inliers.cpp 35810 2011-02-08 00:03:46Z rusu $
 *
 */

#include "pcl/impl/instantiate.hpp"
#include "pcl/point_types.h"
#include "pcl/filters/project_inliers.h"
#include "pcl/filters/impl/project_inliers.hpp"

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::ProjectInliers<sensor_msgs::PointCloud2>::applyFilter (PointCloud2 &output)
{
  if (indices_->empty ())
  {
    ROS_WARN ("[pcl::%s::applyFilter] No indices given or empty indices!", getClassName ().c_str ());
    output.width = output.height = 0;
    output.data.clear ();
    return;
  }

  //Eigen::Map<Eigen::VectorXf, Eigen::Aligned> model_coefficients (&model_->values[0], model_->values.size ());
  // More expensive than a map but safer (32bit architectures seem to complain)
  Eigen::VectorXf model_coefficients (model_->values.size ());
  for (size_t i = 0; i < model_->values.size (); ++i)
    model_coefficients[i] = model_->values[i];

  // Construct the model and project
  if (!initSACModel (model_type_))
  {
    ROS_ERROR ("[pcl::%s::segment] Error initializing the SAC model!", getClassName ().c_str ());
    output.width = output.height = 0;
    output.data.clear ();
    return;
  }
  pcl::PointCloud<pcl::PointXYZ> cloud_out;

  if (!copy_all_fields_)
    sacmodel_->projectPoints (*indices_, model_coefficients, cloud_out, false);
  else
    sacmodel_->projectPoints (*indices_, model_coefficients, cloud_out, true);

  if (copy_all_data_)
  {
    output.height       = input_->height;
    output.width        = input_->width;
    output.is_bigendian = input_->is_bigendian;
    output.point_step   = input_->point_step;
    output.row_step     = input_->row_step;
    output.data         = input_->data;
    output.is_dense     = input_->is_dense;

    // Get the distance field index
    int x_idx = -1, y_idx = -1, z_idx = -1;
    for (size_t d = 0; d < output.fields.size (); ++d)
    {
      if (output.fields[d].name == "x") x_idx = d;
      if (output.fields[d].name == "y") y_idx = d;
      if (output.fields[d].name == "z") z_idx = d;
    }
    if (x_idx == -1 || y_idx == -1 || z_idx == -1)
    {
      ROS_ERROR ("[pcl::%s::segment] X (%d) Y (%d) Z (%d) field dimensions not found!", getClassName ().c_str (), x_idx, y_idx, z_idx);
      output.width = output.height = 0;
      output.data.clear ();
      return;
    }

    // Copy the projected points
    for (size_t i = 0; i < indices_->size (); ++i)
    {
      memcpy (&output.data[(*indices_)[i] * output.point_step + output.fields[x_idx].offset], &cloud_out.points[(*indices_)[i]].x, sizeof (float));
      memcpy (&output.data[(*indices_)[i] * output.point_step + output.fields[y_idx].offset], &cloud_out.points[(*indices_)[i]].y, sizeof (float));
      memcpy (&output.data[(*indices_)[i] * output.point_step + output.fields[z_idx].offset], &cloud_out.points[(*indices_)[i]].z, sizeof (float));
    }
  }
  else
  {
    if (!copy_all_fields_)
    {
      pcl::toROSMsg<pcl::PointXYZ> (cloud_out, output);
    }
    else
    {
      // Copy everything
      output.height       = 1;
      output.width        = indices_->size ();
      output.point_step   = input_->point_step;
      output.data.resize (output.width * output.point_step);
      output.is_bigendian = input_->is_bigendian;
      output.row_step     = output.point_step * output.width;
      // All projections should return valid data, so is_dense = true
      output.is_dense     = true;

      // Get the distance field index
      int x_idx = -1, y_idx = -1, z_idx = -1;
      for (size_t d = 0; d < output.fields.size (); ++d)
      {
        if (output.fields[d].name == "x") x_idx = d;
        if (output.fields[d].name == "y") y_idx = d;
        if (output.fields[d].name == "z") z_idx = d;
      }

      if (x_idx == -1 || y_idx == -1 || z_idx == -1)
      {
        ROS_ERROR ("[pcl::%s::segment] X (%d) Y (%d) Z (%d) field dimensions not found!", getClassName ().c_str (), x_idx, y_idx, z_idx);
        output.width = output.height = 0;
        output.data.clear ();
        return;
      }

      // Copy the projected points
      for (size_t i = 0; i < indices_->size (); ++i)
      {
        memcpy (&output.data[i * output.point_step], &input_->data[(*indices_)[i] * input_->point_step], output.point_step);
        memcpy (&output.data[i * output.point_step + output.fields[x_idx].offset], &cloud_out.points[(*indices_)[i]].x, sizeof (float));
        memcpy (&output.data[i * output.point_step + output.fields[y_idx].offset], &cloud_out.points[(*indices_)[i]].y, sizeof (float));
        memcpy (&output.data[i * output.point_step + output.fields[z_idx].offset], &cloud_out.points[(*indices_)[i]].z, sizeof (float));
      }
    }
  }
}

/////////////////////////////////////////////////////////////////////////////////////////////
bool
pcl::ProjectInliers<sensor_msgs::PointCloud2>::initSACModel (int model_type)
{
  // Convert the input data
  PointCloud<PointXYZ> cloud;
  fromROSMsg (*input_, cloud);
  PointCloud<PointXYZ>::Ptr cloud_ptr = cloud.makeShared ();

  // Build the model
  switch (model_type)
  {
    case SACMODEL_PLANE:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_PLANE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelPlane<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_LINE:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_LINE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelLine<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_CIRCLE2D:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_CIRCLE2D", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelCircle2D<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_SPHERE:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_SPHERE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelSphere<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_PARALLEL_LINE:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_PARALLEL_LINE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelParallelLine<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_PERPENDICULAR_PLANE:
    {
      //ROS_DEBUG ("[pcl::%s::initSACModel] Using a model of type: SACMODEL_PERPENDICULAR_PLANE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelPerpendicularPlane<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    case SACMODEL_CYLINDER:
    {
      //ROS_DEBUG ("[pcl::%s::segment] Using a model of type: SACMODEL_CYLINDER", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelCylinder<pcl::PointXYZ, Normal> (cloud_ptr));
      break;
    }
    case SACMODEL_NORMAL_PLANE:
    {
      //ROS_DEBUG ("[pcl::%s::segment] Using a model of type: SACMODEL_NORMAL_PLANE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelNormalPlane<pcl::PointXYZ, Normal> (cloud_ptr));
      break;
    }
    case SACMODEL_NORMAL_PARALLEL_PLANE:
    {
      //ROS_DEBUG ("[pcl::%s::segment] Using a model of type: SACMODEL_NORMAL_PARALLEL_PLANE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelNormalParallelPlane<pcl::PointXYZ, Normal> (cloud_ptr));
      break;
    }
    case SACMODEL_PARALLEL_PLANE:
    {
      //ROS_DEBUG ("[pcl::%s::segment] Using a model of type: SACMODEL_PARALLEL_PLANE", getClassName ().c_str ());
      sacmodel_.reset (new SampleConsensusModelParallelPlane<pcl::PointXYZ> (cloud_ptr));
      break;
    }
    default:
    {
      ROS_ERROR ("[pcl::%s::initSACModel] No valid model given!", getClassName ().c_str ());
      return (false);
    }
  }
  return (true);
}

// Instantiations of specific point types
PCL_INSTANTIATE(ProjectInliers, PCL_XYZ_POINT_TYPES);

<|endoftext|>


<commit_before>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
*/

#pragma once

#include <cstdint>
#include <map>
#include <memory>
#include <mutex>
#include <typeindex>
#include <vector>
#include "raz/memory.hpp"

namespace raz
{
	class EventDispatcher
	{
	public:
		template<class Event, class Cookie = void>
		using EventRouteCondition = bool(*)(const Event&, Cookie*);

		EventDispatcher(IMemoryPool* memory = nullptr) :
			m_memory(memory),
			m_recursion(0)
		{
		}

		template<class Event, class Cookie = void, class EventReceiver = void>
		void addEventRoute(EventReceiver* receiver, EventRouteCondition<Event, Cookie> condition = nullptr, int route_id = 0)
		{
			std::lock_guard<decltype(m_mutex)> guard(m_mutex);
			RecursionGuard rguard(m_recursion);

			getRouteTable<Event>()->add(receiver, condition, route_id);
		}

		template<class Event>
		void removeEventRoute(int route_id)
		{
			std::lock_guard<decltype(m_mutex)> guard(m_mutex);
			RecursionGuard rguard(m_recursion);

			getRouteTable<Event>()->remove(route_id);
		}

		template<class Event, class Cookie = void>
		void dispatch(const Event& e, Cookie* cookie = nullptr) const
		{
			std::lock_guard<decltype(m_mutex)> guard(m_mutex);
			RecursionGuard rguard(m_recursion);

			const auto* table = getRouteTable<Event>();
			if (table)
			{
				table->handle(e, cookie);
			}
		}

		void unbindReceiver(void* receiver)
		{
			std::lock_guard<decltype(m_mutex)> guard(m_mutex);
			RecursionGuard rguard(m_recursion);

			for (auto& it : m_route_tables)
			{
				it.second->remove(receiver);
			}
		}

		struct RecursionDetected : public std::exception
		{
		};

		struct CookieTypeMismatch : public std::exception
		{
		};

	private:
		template<class Event>
		class EventRoute
		{
		public:
			template<class EventReceiver, class Cookie>
			EventRoute(EventReceiver* receiver, EventRouteCondition<Event, Cookie> condition = nullptr, int route_id = 0) :
				m_route_id(route_id),
				m_receiver(receiver),
				m_handler(&__handler<EventReceiver>),
				m_condition(reinterpret_cast<EventRouteCondition<Event>>(condition)),
				m_cookie_type(typeid(Cookie))
			{
			}

			int getID() const
			{
				return m_route_id;
			}

			void* getvoid()
			{
				return m_receiver;
			}

			template<class Cookie>
			void operator()(const Event& e, Cookie* cookie) const
			{
				if (m_cookie_type != typeid(Cookie))
				{
					throw CookieTypeMismatch();
				}

				if (!m_condition || (m_condition && m_condition(e, cookie)))
				{
					m_handler(m_receiver, e);
				}
			}

		private:
			typedef void(*EventHandler)(void*, const Event&);

			template<class EventReceiver>
			static void __handler(void* receiver, const Event& e)
			{
				static_cast<EventReceiver*>(receiver)->operator()(e);
			}

			int m_route_id;
			void* m_receiver;
			EventHandler m_handler;
			EventRouteCondition<Event> m_condition;
			std::type_index m_cookie_type;
		};

		class IEventRouteTable
		{
		public:
			virtual ~IEventRouteTable() = default;
			virtual void remove(void* receiver) = 0;
		};

		template<class Event>
		class EventRouteTable : public IEventRouteTable
		{
		public:
			EventRouteTable(IMemoryPool* memory = nullptr) :
				m_routes(memory)
			{
			}

			template<class EventReceiver, class Cookie>
			void add(EventReceiver* receiver, EventRouteCondition<Event, Cookie> condition = nullptr, int route_id = 0)
			{
				m_routes.emplace_back(receiver, condition, route_id);
			}

			void remove(int route_id)
			{
				for (auto it = m_routes.begin(); it != m_routes.end(); )
				{
					if (it->getID() == route_id)
						it = m_routes.erase(it);
					else
						++it;
				}
			}

			virtual void remove(void* receiver)
			{
				for (auto it = m_routes.begin(); it != m_routes.end(); )
				{
					if (it->getvoid() == receiver)
						it = m_routes.erase(it);
					else
						++it;
				}
			}

			template<class Cookie>
			void handle(const Event& e, Cookie* cookie) const
			{
				for (auto& route : m_routes)
				{
					route(e, cookie);
				}
			}

		private:
			std::vector<EventRoute<Event>, raz::Allocator<EventRoute<Event>>> m_routes;
		};

		class CustomRouteDeleter
		{
		public:
			CustomRouteDeleter(IMemoryPool* memory) :
				m_memory(memory)
			{
			}

			void operator()(IEventRouteTable* ptr)
			{
				if (m_memory)
					m_memory->destroy(ptr);
				else
					delete ptr;
			}

		private:
			IMemoryPool* m_memory;
		};

		class RecursionGuard
		{
		public:
			RecursionGuard(int& recursion) : m_recursion(recursion)
			{
				if (m_recursion > 0)
					throw RecursionDetected();

				++m_recursion;
			}

			~RecursionGuard()
			{
				--m_recursion;
			}

		private:
			int& m_recursion;
		};

		mutable std::recursive_mutex m_mutex;
		mutable int m_recursion;
		IMemoryPool* m_memory;
		std::map<std::type_index, std::unique_ptr<IEventRouteTable, CustomRouteDeleter>> m_route_tables;

		template<class Event>
		EventRouteTable<Event>* getRouteTable()
		{
			auto it = m_route_tables.find(typeid(Event));
			if (it == m_route_tables.end())
			{
				decltype(m_route_tables)::mapped_type ptr(m_memory ? m_memory->create<EventRouteTable<Event>>() : new EventRouteTable<Event>(), m_memory);
				it = m_route_tables.emplace(typeid(Event), std::move(ptr)).first;
			}

			return static_cast<EventRouteTable<Event>*>(it->second.get());
		}

		template<class Event>
		const EventRouteTable<Event>* getRouteTable() const
		{
			auto it = m_route_tables.find(typeid(Event));
			if (it == m_route_tables.end())
				return nullptr;

			return static_cast<const EventRouteTable<Event>*>(it->second.get());
		}
	};
}
<commit_msg>Passing memory pool pointer to EventRouteTable constructor<commit_after>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
*/

#pragma once

#include <cstdint>
#include <map>
#include <memory>
#include <mutex>
#include <typeindex>
#include <vector>
#include "raz/memory.hpp"

namespace raz
{
	class EventDispatcher
	{
	public:
		template<class Event, class Cookie = void>
		using EventRouteCondition = bool(*)(const Event&, Cookie*);

		EventDispatcher(IMemoryPool* memory = nullptr) :
			m_memory(memory),
			m_recursion(0)
		{
		}

		template<class Event, class Cookie = void, class EventReceiver = void>
		void addEventRoute(EventReceiver* receiver, EventRouteCondition<Event, Cookie> condition = nullptr, int route_id = 0)
		{
			std::lock_guard<decltype(m_mutex)> guard(m_mutex);
			RecursionGuard rguard(m_recursion);

			getRouteTable<Event>()->add(receiver, condition, route_id);
		}

		template<class Event>
		void removeEventRoute(int route_id)
		{
			std::lock_guard<decltype(m_mutex)> guard(m_mutex);
			RecursionGuard rguard(m_recursion);

			getRouteTable<Event>()->remove(route_id);
		}

		template<class Event, class Cookie = void>
		void dispatch(const Event& e, Cookie* cookie = nullptr) const
		{
			std::lock_guard<decltype(m_mutex)> guard(m_mutex);
			RecursionGuard rguard(m_recursion);

			const auto* table = getRouteTable<Event>();
			if (table)
			{
				table->handle(e, cookie);
			}
		}

		void unbindReceiver(void* receiver)
		{
			std::lock_guard<decltype(m_mutex)> guard(m_mutex);
			RecursionGuard rguard(m_recursion);

			for (auto& it : m_route_tables)
			{
				it.second->remove(receiver);
			}
		}

		struct RecursionDetected : public std::exception
		{
		};

		struct CookieTypeMismatch : public std::exception
		{
		};

	private:
		template<class Event>
		class EventRoute
		{
		public:
			template<class EventReceiver, class Cookie>
			EventRoute(EventReceiver* receiver, EventRouteCondition<Event, Cookie> condition = nullptr, int route_id = 0) :
				m_route_id(route_id),
				m_receiver(receiver),
				m_handler(&__handler<EventReceiver>),
				m_condition(reinterpret_cast<EventRouteCondition<Event>>(condition)),
				m_cookie_type(typeid(Cookie))
			{
			}

			int getID() const
			{
				return m_route_id;
			}

			void* getvoid()
			{
				return m_receiver;
			}

			template<class Cookie>
			void operator()(const Event& e, Cookie* cookie) const
			{
				if (m_cookie_type != typeid(Cookie))
				{
					throw CookieTypeMismatch();
				}

				if (!m_condition || (m_condition && m_condition(e, cookie)))
				{
					m_handler(m_receiver, e);
				}
			}

		private:
			typedef void(*EventHandler)(void*, const Event&);

			template<class EventReceiver>
			static void __handler(void* receiver, const Event& e)
			{
				static_cast<EventReceiver*>(receiver)->operator()(e);
			}

			int m_route_id;
			void* m_receiver;
			EventHandler m_handler;
			EventRouteCondition<Event> m_condition;
			std::type_index m_cookie_type;
		};

		class IEventRouteTable
		{
		public:
			virtual ~IEventRouteTable() = default;
			virtual void remove(void* receiver) = 0;
		};

		template<class Event>
		class EventRouteTable : public IEventRouteTable
		{
		public:
			EventRouteTable(IMemoryPool* memory = nullptr) :
				m_routes(memory)
			{
			}

			template<class EventReceiver, class Cookie>
			void add(EventReceiver* receiver, EventRouteCondition<Event, Cookie> condition = nullptr, int route_id = 0)
			{
				m_routes.emplace_back(receiver, condition, route_id);
			}

			void remove(int route_id)
			{
				for (auto it = m_routes.begin(); it != m_routes.end(); )
				{
					if (it->getID() == route_id)
						it = m_routes.erase(it);
					else
						++it;
				}
			}

			virtual void remove(void* receiver)
			{
				for (auto it = m_routes.begin(); it != m_routes.end(); )
				{
					if (it->getvoid() == receiver)
						it = m_routes.erase(it);
					else
						++it;
				}
			}

			template<class Cookie>
			void handle(const Event& e, Cookie* cookie) const
			{
				for (auto& route : m_routes)
				{
					route(e, cookie);
				}
			}

		private:
			std::vector<EventRoute<Event>, raz::Allocator<EventRoute<Event>>> m_routes;
		};

		class CustomRouteDeleter
		{
		public:
			CustomRouteDeleter(IMemoryPool* memory) :
				m_memory(memory)
			{
			}

			void operator()(IEventRouteTable* ptr)
			{
				if (m_memory)
					m_memory->destroy(ptr);
				else
					delete ptr;
			}

		private:
			IMemoryPool* m_memory;
		};

		class RecursionGuard
		{
		public:
			RecursionGuard(int& recursion) : m_recursion(recursion)
			{
				if (m_recursion > 0)
					throw RecursionDetected();

				++m_recursion;
			}

			~RecursionGuard()
			{
				--m_recursion;
			}

		private:
			int& m_recursion;
		};

		mutable std::recursive_mutex m_mutex;
		mutable int m_recursion;
		IMemoryPool* m_memory;
		std::map<std::type_index, std::unique_ptr<IEventRouteTable, CustomRouteDeleter>> m_route_tables;

		template<class Event>
		EventRouteTable<Event>* getRouteTable()
		{
			auto it = m_route_tables.find(typeid(Event));
			if (it == m_route_tables.end())
			{
				decltype(m_route_tables)::mapped_type ptr(
					m_memory ? m_memory->create<EventRouteTable<Event>>(m_memory) : new EventRouteTable<Event>(),
					m_memory);
				it = m_route_tables.emplace(typeid(Event), std::move(ptr)).first;
			}

			return static_cast<EventRouteTable<Event>*>(it->second.get());
		}

		template<class Event>
		const EventRouteTable<Event>* getRouteTable() const
		{
			auto it = m_route_tables.find(typeid(Event));
			if (it == m_route_tables.end())
				return nullptr;

			return static_cast<const EventRouteTable<Event>*>(it->second.get());
		}
	};
}
<|endoftext|>


<commit_before>// Copyright (2015) Gustav

#include "finans/core/commandline.h"

#include "gtest/gtest.h"
#include "gmock/gmock.h"

using namespace testing;

struct CommandlineTest : public Test {
  std::ostringstream output;
  std::ostringstream error;
};

#define GTEST(x) TEST_F(CommandlineTest, x)

/*
void main(int argc, char* argv[])
{
  enum MyEnum
  {
    MyVal, MyVal2
  };

  std::string compiler;
  int i;
  int op = 2;
  std::vector<std::string> strings;
  //MyEnum v;
  bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("compiler", compiler)
    ("int", i)
    ("-op", op)
    .add<std::vector<std::string>, std::string>("-strings", strings, argparse::Extra().count(argparse::Count::MoreThanOne).metavar("string"), argparse::PushBackVector<std::string>) // todo: is this beautifiable?
    //("-enum", &v, Convert<MyEnum>("MyVal", MyEnum::MyVal)("MyVal2", MyEnum::MyVal2) )
    .parseArgs(argc, argv);
  if (ok == false) return;
  std::cout << compiler << " " << i << " " << op << std::endl;
  BOOST_FOREACH(const std::string& s, strings)
  {
    std::cout << s << " " << std::endl;
  }
}
*/

GTEST(TestEmpty) {
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    .ParseArgs(argparse::Arguments("app.exe", {}), output, error);
  EXPECT_EQ(true, ok);
}

GTEST(TestError) {
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    .ParseArgs(argparse::Arguments("app.exe", { "hello", "world" }), output, error);
  EXPECT_EQ(false, ok);
}

GTEST(TestOptionalDefault) {
  int op = 2;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("-op", op)
    .ParseArgs(argparse::Arguments("app.exe", {}), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_EQ(2, op);
}

GTEST(TestOptionalValue) {
  int op = 2;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("-op", op)
    .ParseArgs(argparse::Arguments("app.exe", {"-op", "42"}), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_EQ(42, op);
}

GTEST(TestPositionalValue) {
  int op = 2;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("op", op)
    .ParseArgs(argparse::Arguments("app.exe", { "42" }), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_EQ(42, op);
}

GTEST(TestPositionalValueErr) {
  int op = 42;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("op", op)
    .ParseArgs(argparse::Arguments("app.exe", {}), output, error);
  EXPECT_EQ(false, ok);
  EXPECT_EQ(42, op); // not touched
}

GTEST(TestStdVector) {
  std::vector<std::string> strings;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    .AddGreedy("-strings", strings, "string")
    .ParseArgs(argparse::Arguments("app.exe", {"-strings", "cat", "dog", "fish"}), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_THAT(strings, ElementsAre("cat", "dog", "fish"));
}

GTEST(TestStdVectorInts) {
  std::vector<int> ints;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    .AddGreedy("-ints", ints, "string")
    .ParseArgs(argparse::Arguments("app.exe", { "-ints", "2", "3", "-5", "4" }), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_THAT(ints, ElementsAre(2, 3, -5, 4));
}

GTEST(TestNonGreedyVector) {
  std::vector<std::string> strings;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("-s", strings)
    .ParseArgs(argparse::Arguments("app.exe", { "-s", "cat", "-s", "dog", "-s", "fish" }), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_THAT(strings, ElementsAre("cat", "dog", "fish"));
}
<commit_msg>testing enum parsing<commit_after>// Copyright (2015) Gustav

#include "finans/core/commandline.h"

#include "gtest/gtest.h"
#include "gmock/gmock.h"

using namespace testing;

struct CommandlineTest : public Test {
  std::ostringstream output;
  std::ostringstream error;
};

#define GTEST(x) TEST_F(CommandlineTest, x)

/*
void main(int argc, char* argv[])
{
  enum MyEnum
  {
    MyVal, MyVal2
  };

  std::string compiler;
  int i;
  int op = 2;
  std::vector<std::string> strings;
  //MyEnum v;
  bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("compiler", compiler)
    ("int", i)
    ("-op", op)
    .add<std::vector<std::string>, std::string>("-strings", strings, argparse::Extra().count(argparse::Count::MoreThanOne).metavar("string"), argparse::PushBackVector<std::string>) // todo: is this beautifiable?
    //("-enum", &v, Convert<MyEnum>("MyVal", MyEnum::MyVal)("MyVal2", MyEnum::MyVal2) )
    .parseArgs(argc, argv);
  if (ok == false) return;
  std::cout << compiler << " " << i << " " << op << std::endl;
  BOOST_FOREACH(const std::string& s, strings)
  {
    std::cout << s << " " << std::endl;
  }
}
*/

GTEST(TestEmpty) {
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    .ParseArgs(argparse::Arguments("app.exe", {}), output, error);
  EXPECT_EQ(true, ok);
}

GTEST(TestError) {
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    .ParseArgs(argparse::Arguments("app.exe", { "hello", "world" }), output, error);
  EXPECT_EQ(false, ok);
}

GTEST(TestOptionalDefault) {
  int op = 2;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("-op", op)
    .ParseArgs(argparse::Arguments("app.exe", {}), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_EQ(2, op);
}

GTEST(TestOptionalValue) {
  int op = 2;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("-op", op)
    .ParseArgs(argparse::Arguments("app.exe", {"-op", "42"}), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_EQ(42, op);
}

GTEST(TestPositionalValue) {
  int op = 2;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("op", op)
    .ParseArgs(argparse::Arguments("app.exe", { "42" }), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_EQ(42, op);
}

GTEST(TestPositionalValueErr) {
  int op = 42;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("op", op)
    .ParseArgs(argparse::Arguments("app.exe", {}), output, error);
  EXPECT_EQ(false, ok);
  EXPECT_EQ(42, op); // not touched
}

GTEST(TestStdVector) {
  std::vector<std::string> strings;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    .AddGreedy("-strings", strings, "string")
    .ParseArgs(argparse::Arguments("app.exe", {"-strings", "cat", "dog", "fish"}), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_THAT(strings, ElementsAre("cat", "dog", "fish"));
}

GTEST(TestStdVectorInts) {
  std::vector<int> ints;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    .AddGreedy("-ints", ints, "string")
    .ParseArgs(argparse::Arguments("app.exe", { "-ints", "2", "3", "-5", "4" }), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_THAT(ints, ElementsAre(2, 3, -5, 4));
}

GTEST(TestNonGreedyVector) {
  std::vector<std::string> strings;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("-s", strings)
    .ParseArgs(argparse::Arguments("app.exe", { "-s", "cat", "-s", "dog", "-s", "fish" }), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_THAT(strings, ElementsAre("cat", "dog", "fish"));
}

enum class Day
{
  TODAY, YESTERDAY, TOMORROW
};

template<>
Day argparse::StandardConverter(const std::string& type)
{
  static const auto values = StringConverter<Day>{ "day" }("Today", Day::TODAY)("Tomorrow", Day::TOMORROW)("Yesterday", Day::YESTERDAY);
  return values.Convert(type);
}

GTEST(TestEnum) {
  Day op = Day::TOMORROW;
  const bool ok = argparse::Parser::ParseComplete ==
    argparse::Parser("description")
    ("op", op)
    .ParseArgs(argparse::Arguments("app.exe", { "tod" }), output, error);
  EXPECT_EQ(true, ok);
  EXPECT_EQ(Day::TODAY, op);
}
<|endoftext|>