<commit_before>
#include <libclientserver.h>

/**
 * Sleep
 * @param[in] Timeout The total length of time to sleep for
 */
void Time::Sleep(const struct timespec *Timeout)
{
	struct timespec ts;
	struct timespec rem;
	memcpy(&ts, Timeout, sizeof(ts));

restart:
	int ret = nanosleep(&ts, &rem);
	if (ret < 0)
	{
		switch(errno)
		{
			case EINTR:
				memcpy(&ts, &rem, sizeof(ts));
				goto restart;
				break;
			default:
				abort();
				break;
		}
	}
}

/**
 * Sleep
 * @param[in] Timeout The total length of time to sleep for
 */
void Time::Sleep(const struct timeval *Timeout)
{
	struct timespec ts;
	TimeValtoTimeSpec(Timeout, &ts);
	Sleep(Timeout);
}

/**
 * TimeSpecToTimeVal
 * @param[in] ts Source Value
 * @param[out] tv Output Value
 *
 * Convert the input timespec to a timeval structure.
 */
void Time::TimeSpecToTimeVal(const struct timespec *ts, struct timeval *tv)
{
	tv->tv_sec = ts->tv_sec;
	tv->tv_usec = ts->tv_nsec / 1000;
}

/**
 * TimeValtoTimeSpec
 * @param[in] tv Source Value
 * @param[out] ts Output Value
 *
 * Convert the input timeval to a timespec structure.
 */
void Time::TimeValtoTimeSpec(const struct timeval *tv, struct timespec *ts)
{
	ts->tv_sec = tv->tv_sec;
	ts->tv_nsec = tv->tv_usec * 1000;
}

/**
 * Add
 * @param[in] ts1 First Input Value
 * @param[in] ts2 Second Input Value
 * @param[out] res Output Value
 *
 * Add two timespec struct together to form the output.
 * It is safe to have the output specificed as the same address as either of the two input structures.
 */
void Time::Add(const struct timespec *ts1, const struct timespec *ts2, struct timespec *res)
{
	res->tv_sec = ts1->tv_sec + ts2->tv_sec;
	res->tv_nsec = ts1->tv_nsec + ts2->tv_nsec;
	if (res->tv_nsec > 999999999)
	{
		res->tv_sec++;
		res->tv_nsec -= 1000000000;
	}
}

/**
 * Add
 * @param[in] tv1 First Input Value
 * @param[in] tv2 Second Input Value
 * @param[out] res Output Value
 *
 * Add two timeval struct together to form the output.
 * It is safe to have the output specificed as the same address as either of the two input structures.
 */
void Time::Add(const struct timeval *tv1, const struct timeval *tv2, struct timeval *res)
{
	res->tv_sec = tv1->tv_sec + tv2->tv_sec;
	res->tv_usec = tv1->tv_usec + tv2->tv_usec;
	if (res->tv_usec > 999999)
	{
		res->tv_sec++;
		res->tv_usec -= 1000000;
	}
}

/**
 * Sub
 * @param[in] ts1 First Input Value
 * @param[in] ts2 Second Input Value
 * @param[out] res Output Value
 *
 * Subtrace two timespec struct together to form the output.
 * It is safe to have the output specificed as the same address as either of the two input structures.
 */
void Time::Sub(const struct timespec *ts1, const struct timespec *ts2, struct timespec *res)
{
	res->tv_sec = ts1->tv_sec - ts2->tv_sec;
	res->tv_nsec = ts1->tv_nsec - ts2->tv_nsec;
	if (res->tv_nsec < 0)
	{
		res->tv_sec--;
		res->tv_nsec += 1000000000;
	}
}

/**
 * Sub
 * @param[in] tv1 First Input Value
 * @param[in] tv2 Second Input Value
 * @param[out] res Output Value
 *
 * Subtract two timeval struct together to form the output.
 * It is safe to have the output specificed as the same address as either of the two input structures.
 */
void Time::Sub(const struct timeval *tv1, const struct timeval *tv2, struct timeval *res)
{
	res->tv_sec = tv1->tv_sec - tv2->tv_sec;
	res->tv_usec = tv1->tv_usec - tv2->tv_usec;
	if (res->tv_usec < 0)
	{
		res->tv_sec--;
		res->tv_usec += 1000000;
	}
}

/**
 * Diff
 * @param[in] ts1 Input One
 * @param[in] ts2 Input Two
 * @param[out] res Output the difference
 *
 * This will calculate the difference between two times. The value outputted will always be a positive value regardless of the order of ts1 and ts2
 */
void Time::Diff(const struct timespec *ts1, const struct timespec *ts2, struct timespec *res)
{
	if (IsGreater(ts1, ts2))
	{
		Sub(ts2, ts1, res);
	}
	else
	{
		Sub(ts2, ts1, res);
	}
}

/**
 * Diff
 * @param[in] tv1 Input One
 * @param[in] tv2 Input Two
 * @param[out] res Output the difference
 *
 * This will calculate the difference between two times. The value outputted will always be a positive value regardless of the order of ts1 and ts2
 */
void Time::Diff(const struct timeval *tv1, const struct timeval *tv2, struct timeval *res)
{
	if (IsGreater(tv1, tv2))
	{
		Sub(tv2, tv1, res);
	}
	else
	{
		Sub(tv2, tv1, res);
	}
}

/**
 * IsLess
 * @param[in] ts1
 * @param[in] ts2
 * @return True if ts1 is less than ts2
 *
 * Returns true if the values in ts1 is less than the value in ts2
 */
bool Time::IsLess(const struct timespec *ts1, const struct timespec *ts2)
{
	if (ts1->tv_sec < ts2->tv_sec)
		return true;
	if (ts1->tv_sec == ts2->tv_sec && ts1->tv_nsec < ts2->tv_nsec)
		return true;
	return false;
}

/**
 * IsLess
 * @param[in] tv1
 * @param[in] tv2
 * @return True if tv1 is less than tv2
 *
 * Returns true if the values in tv1 is less than the value in tv2
 */
bool Time::IsLess(const struct timeval *tv1, const struct timeval *tv2)
{
	if (tv1->tv_sec < tv2->tv_sec)
		return true;
	if (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec < tv2->tv_usec)
		return true;
	return false;
}

/**
 * IsGreater
 * @param[in] ts1
 * @param[in] ts2
 * @return True if ts1 is greater than ts2
 *
 * Returns true if the values in ts1 is greater than the value in ts2
 */
bool Time::IsGreater(const struct timespec *ts1, const struct timespec *ts2)
{
	if (ts1->tv_sec > ts2->tv_sec)
		return true;
	if (ts1->tv_sec == ts2->tv_sec && ts1->tv_nsec > ts2->tv_nsec)
		return true;
	return false;
}

/**
 * IsGreater
 * @param[in] tv1
 * @param[in] tv2
 * @return True if tv1 is greater than tv2
 *
 * Returns true if the values in tv1 is greater than the value in tv2
 */
bool Time::IsGreater(const struct timeval *tv1, const struct timeval *tv2)
{
	if (tv1->tv_sec > tv2->tv_sec)
		return true;
	if (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec > tv2->tv_usec)
		return true;
	return false;

}

<commit_msg>Fixed Recursive problem with Time::Sleep<commit_after>
#include <libclientserver.h>

/**
 * Sleep
 * @param[in] Timeout The total length of time to sleep for
 */
void Time::Sleep(const struct timespec *Timeout)
{
	struct timespec ts;
	struct timespec rem;
	memcpy(&ts, Timeout, sizeof(ts));

restart:
	int ret = nanosleep(&ts, &rem);
	if (ret < 0)
	{
		switch(errno)
		{
			case EINTR:
				memcpy(&ts, &rem, sizeof(ts));
				goto restart;
				break;
			default:
				abort();
				break;
		}
	}
}

/**
 * Sleep
 * @param[in] Timeout The total length of time to sleep for
 */
void Time::Sleep(const struct timeval *Timeout)
{
	struct timespec ts;
	TimeValtoTimeSpec(Timeout, &ts);
	Sleep(&ts);
}

/**
 * TimeSpecToTimeVal
 * @param[in] ts Source Value
 * @param[out] tv Output Value
 *
 * Convert the input timespec to a timeval structure.
 */
void Time::TimeSpecToTimeVal(const struct timespec *ts, struct timeval *tv)
{
	tv->tv_sec = ts->tv_sec;
	tv->tv_usec = ts->tv_nsec / 1000;
}

/**
 * TimeValtoTimeSpec
 * @param[in] tv Source Value
 * @param[out] ts Output Value
 *
 * Convert the input timeval to a timespec structure.
 */
void Time::TimeValtoTimeSpec(const struct timeval *tv, struct timespec *ts)
{
	ts->tv_sec = tv->tv_sec;
	ts->tv_nsec = tv->tv_usec * 1000;
}

/**
 * Add
 * @param[in] ts1 First Input Value
 * @param[in] ts2 Second Input Value
 * @param[out] res Output Value
 *
 * Add two timespec struct together to form the output.
 * It is safe to have the output specificed as the same address as either of the two input structures.
 */
void Time::Add(const struct timespec *ts1, const struct timespec *ts2, struct timespec *res)
{
	res->tv_sec = ts1->tv_sec + ts2->tv_sec;
	res->tv_nsec = ts1->tv_nsec + ts2->tv_nsec;
	if (res->tv_nsec > 999999999)
	{
		res->tv_sec++;
		res->tv_nsec -= 1000000000;
	}
}

/**
 * Add
 * @param[in] tv1 First Input Value
 * @param[in] tv2 Second Input Value
 * @param[out] res Output Value
 *
 * Add two timeval struct together to form the output.
 * It is safe to have the output specificed as the same address as either of the two input structures.
 */
void Time::Add(const struct timeval *tv1, const struct timeval *tv2, struct timeval *res)
{
	res->tv_sec = tv1->tv_sec + tv2->tv_sec;
	res->tv_usec = tv1->tv_usec + tv2->tv_usec;
	if (res->tv_usec > 999999)
	{
		res->tv_sec++;
		res->tv_usec -= 1000000;
	}
}

/**
 * Sub
 * @param[in] ts1 First Input Value
 * @param[in] ts2 Second Input Value
 * @param[out] res Output Value
 *
 * Subtrace two timespec struct together to form the output.
 * It is safe to have the output specificed as the same address as either of the two input structures.
 */
void Time::Sub(const struct timespec *ts1, const struct timespec *ts2, struct timespec *res)
{
	res->tv_sec = ts1->tv_sec - ts2->tv_sec;
	res->tv_nsec = ts1->tv_nsec - ts2->tv_nsec;
	if (res->tv_nsec < 0)
	{
		res->tv_sec--;
		res->tv_nsec += 1000000000;
	}
}

/**
 * Sub
 * @param[in] tv1 First Input Value
 * @param[in] tv2 Second Input Value
 * @param[out] res Output Value
 *
 * Subtract two timeval struct together to form the output.
 * It is safe to have the output specificed as the same address as either of the two input structures.
 */
void Time::Sub(const struct timeval *tv1, const struct timeval *tv2, struct timeval *res)
{
	res->tv_sec = tv1->tv_sec - tv2->tv_sec;
	res->tv_usec = tv1->tv_usec - tv2->tv_usec;
	if (res->tv_usec < 0)
	{
		res->tv_sec--;
		res->tv_usec += 1000000;
	}
}

/**
 * Diff
 * @param[in] ts1 Input One
 * @param[in] ts2 Input Two
 * @param[out] res Output the difference
 *
 * This will calculate the difference between two times. The value outputted will always be a positive value regardless of the order of ts1 and ts2
 */
void Time::Diff(const struct timespec *ts1, const struct timespec *ts2, struct timespec *res)
{
	if (IsGreater(ts1, ts2))
	{
		Sub(ts2, ts1, res);
	}
	else
	{
		Sub(ts2, ts1, res);
	}
}

/**
 * Diff
 * @param[in] tv1 Input One
 * @param[in] tv2 Input Two
 * @param[out] res Output the difference
 *
 * This will calculate the difference between two times. The value outputted will always be a positive value regardless of the order of ts1 and ts2
 */
void Time::Diff(const struct timeval *tv1, const struct timeval *tv2, struct timeval *res)
{
	if (IsGreater(tv1, tv2))
	{
		Sub(tv2, tv1, res);
	}
	else
	{
		Sub(tv2, tv1, res);
	}
}

/**
 * IsLess
 * @param[in] ts1
 * @param[in] ts2
 * @return True if ts1 is less than ts2
 *
 * Returns true if the values in ts1 is less than the value in ts2
 */
bool Time::IsLess(const struct timespec *ts1, const struct timespec *ts2)
{
	if (ts1->tv_sec < ts2->tv_sec)
		return true;
	if (ts1->tv_sec == ts2->tv_sec && ts1->tv_nsec < ts2->tv_nsec)
		return true;
	return false;
}

/**
 * IsLess
 * @param[in] tv1
 * @param[in] tv2
 * @return True if tv1 is less than tv2
 *
 * Returns true if the values in tv1 is less than the value in tv2
 */
bool Time::IsLess(const struct timeval *tv1, const struct timeval *tv2)
{
	if (tv1->tv_sec < tv2->tv_sec)
		return true;
	if (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec < tv2->tv_usec)
		return true;
	return false;
}

/**
 * IsGreater
 * @param[in] ts1
 * @param[in] ts2
 * @return True if ts1 is greater than ts2
 *
 * Returns true if the values in ts1 is greater than the value in ts2
 */
bool Time::IsGreater(const struct timespec *ts1, const struct timespec *ts2)
{
	if (ts1->tv_sec > ts2->tv_sec)
		return true;
	if (ts1->tv_sec == ts2->tv_sec && ts1->tv_nsec > ts2->tv_nsec)
		return true;
	return false;
}

/**
 * IsGreater
 * @param[in] tv1
 * @param[in] tv2
 * @return True if tv1 is greater than tv2
 *
 * Returns true if the values in tv1 is greater than the value in tv2
 */
bool Time::IsGreater(const struct timeval *tv1, const struct timeval *tv2)
{
	if (tv1->tv_sec > tv2->tv_sec)
		return true;
	if (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec > tv2->tv_usec)
		return true;
	return false;

}

<|endoftext|>


<commit_before>#include "Util.h"
#include "Introspection.h"
#include "Debug.h"
#include "Error.h"
#include <sstream>
#include <map>

#ifdef __linux__
#include <unistd.h>
#include <linux/limits.h>
#endif

namespace Halide {
namespace Internal {

using std::string;
using std::vector;
using std::ostringstream;
using std::map;

std::string get_env_variable(char const *env_var_name, size_t &read) {
    if (!env_var_name)
        return "";
    read = 0;

    #ifdef _MSC_VER
    char lvl[32];
    getenv_s(&read, lvl, env_var_name);
    #else
    char *lvl = getenv(env_var_name);
    read = (lvl)?1:0;
    #endif

    if (read) {
        return std::string(lvl);
    }
    else
        return "";
}

string running_program_name() {
    // linux specific currently.
    #ifndef __linux__
    return "";
    #else
    string program_name;
    char path[PATH_MAX];
    ssize_t len = ::readlink("/proc/self/exe", path, sizeof(path)-1);
    if (len != -1) {
        path[len] = '\0';
        string tmp = std::string(path);
        program_name = tmp.substr(tmp.find_last_of("/")+1);
    }
    else
        return "";
    return program_name;
    #endif
}

string unique_name(char prefix) {
    // arrays with static storage duration should be initialized to zero automatically
    static int instances[256];
    ostringstream str;
    str << prefix << instances[(unsigned char)prefix]++;
    return str.str();
}

bool starts_with(const string &str, const string &prefix) {
    if (str.size() < prefix.size()) return false;
    for (size_t i = 0; i < prefix.size(); i++) {
        if (str[i] != prefix[i]) return false;
    }
    return true;
}

bool ends_with(const string &str, const string &suffix) {
    if (str.size() < suffix.size()) return false;
    size_t off = str.size() - suffix.size();
    for (size_t i = 0; i < suffix.size(); i++) {
        if (str[off+i] != suffix[i]) return false;
    }
    return true;
}

string replace_all(string &str, const string &find, const string &replace) {
    size_t pos = 0;
    while ((pos = str.find(find, pos)) != string::npos) {
        str.replace(pos, find.length(), replace);
        pos += replace.length();
    }
    return str;
}

string unique_name(const string &name, bool user) {
    static map<string, int> known_names;

    // An empty string really does not make sense, but use 'z' as prefix.
    if (name.length() == 0) {
        return unique_name('z');
    }

    // Check the '$' character doesn't appear in the prefix. This lets
    // us separate the name from the number using '$' as a delimiter,
    // which guarantees uniqueness of the generated name, without
    // having to track all names generated so far.
    if (user) {
        for (size_t i = 0; i < name.length(); i++) {
            user_assert(name[i] != '$')
                << "Name \"" << name << "\" is invalid. "
                << "Halide names may not contain the character '$'\n";
        }
    }

    int &count = known_names[name];
    count++;
    if (count == 1) {
        // The very first unique name is the original function name itself.
        return name;
    } else {
        // Use the programmer-specified name but append a number to make it unique.
        ostringstream oss;
        oss << name << '$' << count;
        return oss.str();
    }
}

string base_name(const string &name, char delim) {
    size_t off = name.rfind(delim);
    if (off == string::npos) {
        return name;
    }
    return name.substr(off+1);
}

string make_entity_name(void *stack_ptr, const string &type, char prefix) {
    string name = Introspection::get_variable_name(stack_ptr, type);

    if (name.empty()) {
        return unique_name(prefix);
    } else {
        // Halide names may not contain '.'
        for (size_t i = 0; i < name.size(); i++) {
            if (name[i] == '.') {
                name[i] = ':';
            }
        }
        return unique_name(name);
    }
}

std::vector<std::string> split_string(const std::string &source, const std::string &delim) {
    std::vector<std::string> elements;
    size_t start = 0;
    size_t found = 0;
    while ((found = source.find(delim, start)) != std::string::npos) {
        elements.push_back(source.substr(start, found - start));
        start = found + delim.size();
    }

    // If start is exactly source.size(), the last thing in source is a
    // delimiter, in which case we want to add an empty string to elements.
    if (start <= source.size()) {
        elements.push_back(source.substr(start, std::string::npos));
    }
    return elements;
}

}
}
<commit_msg>Added braces.<commit_after>#include "Util.h"
#include "Introspection.h"
#include "Debug.h"
#include "Error.h"
#include <sstream>
#include <map>

#ifdef __linux__
#include <unistd.h>
#include <linux/limits.h>
#endif

namespace Halide {
namespace Internal {

using std::string;
using std::vector;
using std::ostringstream;
using std::map;

std::string get_env_variable(char const *env_var_name, size_t &read) {
    if (!env_var_name) {
        return "";
    }
    read = 0;

    #ifdef _MSC_VER
    char lvl[32];
    getenv_s(&read, lvl, env_var_name);
    #else
    char *lvl = getenv(env_var_name);
    read = (lvl)?1:0;
    #endif

    if (read) {
        return std::string(lvl);
    }
    else {
        return "";
    }
}

string running_program_name() {
    // linux specific currently.
    #ifndef __linux__
    return "";
    #else
    string program_name;
    char path[PATH_MAX];
    ssize_t len = ::readlink("/proc/self/exe", path, sizeof(path)-1);
    if (len != -1) {
        path[len] = '\0';
        string tmp = std::string(path);
        program_name = tmp.substr(tmp.find_last_of("/")+1);
    }
    else {
        return "";
    }
    return program_name;
    #endif
}

string unique_name(char prefix) {
    // arrays with static storage duration should be initialized to zero automatically
    static int instances[256];
    ostringstream str;
    str << prefix << instances[(unsigned char)prefix]++;
    return str.str();
}

bool starts_with(const string &str, const string &prefix) {
    if (str.size() < prefix.size()) return false;
    for (size_t i = 0; i < prefix.size(); i++) {
        if (str[i] != prefix[i]) return false;
    }
    return true;
}

bool ends_with(const string &str, const string &suffix) {
    if (str.size() < suffix.size()) return false;
    size_t off = str.size() - suffix.size();
    for (size_t i = 0; i < suffix.size(); i++) {
        if (str[off+i] != suffix[i]) return false;
    }
    return true;
}

string replace_all(string &str, const string &find, const string &replace) {
    size_t pos = 0;
    while ((pos = str.find(find, pos)) != string::npos) {
        str.replace(pos, find.length(), replace);
        pos += replace.length();
    }
    return str;
}

string unique_name(const string &name, bool user) {
    static map<string, int> known_names;

    // An empty string really does not make sense, but use 'z' as prefix.
    if (name.length() == 0) {
        return unique_name('z');
    }

    // Check the '$' character doesn't appear in the prefix. This lets
    // us separate the name from the number using '$' as a delimiter,
    // which guarantees uniqueness of the generated name, without
    // having to track all names generated so far.
    if (user) {
        for (size_t i = 0; i < name.length(); i++) {
            user_assert(name[i] != '$')
                << "Name \"" << name << "\" is invalid. "
                << "Halide names may not contain the character '$'\n";
        }
    }

    int &count = known_names[name];
    count++;
    if (count == 1) {
        // The very first unique name is the original function name itself.
        return name;
    } else {
        // Use the programmer-specified name but append a number to make it unique.
        ostringstream oss;
        oss << name << '$' << count;
        return oss.str();
    }
}

string base_name(const string &name, char delim) {
    size_t off = name.rfind(delim);
    if (off == string::npos) {
        return name;
    }
    return name.substr(off+1);
}

string make_entity_name(void *stack_ptr, const string &type, char prefix) {
    string name = Introspection::get_variable_name(stack_ptr, type);

    if (name.empty()) {
        return unique_name(prefix);
    } else {
        // Halide names may not contain '.'
        for (size_t i = 0; i < name.size(); i++) {
            if (name[i] == '.') {
                name[i] = ':';
            }
        }
        return unique_name(name);
    }
}

std::vector<std::string> split_string(const std::string &source, const std::string &delim) {
    std::vector<std::string> elements;
    size_t start = 0;
    size_t found = 0;
    while ((found = source.find(delim, start)) != std::string::npos) {
        elements.push_back(source.substr(start, found - start));
        start = found + delim.size();
    }

    // If start is exactly source.size(), the last thing in source is a
    // delimiter, in which case we want to add an empty string to elements.
    if (start <= source.size()) {
        elements.push_back(source.substr(start, std::string::npos));
    }
    return elements;
}

}
}
<|endoftext|>


<commit_before>#include "Utils.h"

#include <string>

#include "Types.h"

using namespace std;

const vector<tagged_word> lemursHaveTails() {
  vector<tagged_word> fact;
  fact.push_back(LEMUR);
  fact.push_back(HAVE);
  fact.push_back(TAIL);
  return fact;
}

const vector<tagged_word> animalsHaveTails() {
  vector<tagged_word> animals;
  animals.push_back(ANIMAL);
  animals.push_back(HAVE);
  animals.push_back(TAIL);
  return animals;
}

const vector<tagged_word> catsHaveTails() {
  vector<tagged_word> cats;
  cats.push_back(CAT);
  cats.push_back(HAVE);
  cats.push_back(TAIL);
  return cats;
}

const vector<tagged_word> someDogsChaseCats() {
  vector<tagged_word> cats;
  cats.push_back(SOME);
  cats.push_back(DOG);
  cats.push_back(CHASE);
  cats.push_back(CAT);
  return cats;
}

string toString(const Graph& graph, const tagged_word* fact, const uint8_t factLength) {
  string gloss = "";
  for (int i = 0; i < factLength; ++i) {
    monotonicity m = fact[i].monotonicity;
    string marker = "";
    if (m == MONOTONE_DOWN) { marker = "[v]"; }
    if (m == MONOTONE_UP) { marker = "[^]"; }
    string sense = to_string((uint64_t) fact[i].sense);
    gloss = gloss + (gloss == "" ? "" : " ") + marker + graph.gloss(fact[i]) + "_" + sense;
  }
  return gloss;
}

string toString(const Graph& graph, SearchType& searchType, const Path* path) {
  if (path == NULL) {
    return "<start>";
  } else {
    return toString(graph, path->fact, path->factLength) +
           "; from\n  " +
           toString(graph, searchType, path->parent);
  }
}

string toString(const edge_type& edge) {
  switch (edge) {
    case WORDNET_UP                   : return "WORDNET_UP";
    case WORDNET_DOWN                 : return "WORDNET_DOWN";
    case WORDNET_NOUN_ANTONYM         : return "WORDNET_NOUN_ANTONYM";
    case WORDNET_NOUN_SYNONYM         : return "WORDNET_NOUN_SYNONYM";
    case WORDNET_VERB_ANTONYM         : return "WORDNET_VERB_ANTONYM";
    case WORDNET_ADJECTIVE_ANTONYM    : return "WORDNET_ADJECTIVE_ANTONYM";
    case WORDNET_ADVERB_ANTONYM       : return "WORDNET_ADVERB_ANTONYM";
    case WORDNET_ADJECTIVE_PERTAINYM  : return "WORDNET_ADJECTIVE_PERTAINYM";
    case WORDNET_ADVERB_PERTAINYM     : return "WORDNET_ADVERB_PERTAINYM";
    case WORDNET_ADJECTIVE_RELATED    : return "WORDNET_ADJECTIVE_RELATED";
    case ANGLE_NN                     : return "ANGLE_NN";
    case FREEBASE_UP                  : return "FREEBASE_UP";
    case FREEBASE_DOWN                : return "FREEBASE_DOWN";
    case MORPH_FUDGE_NUMBER           : return "MORPH_FUDGE_NUMBER";
    case SENSE_REMOVE                 : return "SENSE_REMOVE";
    case SENSE_ADD                    : return "SENSE_ADD";
    case ADD_NOUN                     : return "ADD_NOUN";
    case ADD_VERB                     : return "ADD_VERB";
    case ADD_ADJ                      : return "ADD_ADJ";
    case ADD_NEGATION                 : return "ADD_NEGATION";
    case ADD_EXISTENTIAL              : return "ADD_EXISTENTIAL";
    case ADD_QUANTIFIER_OTHER         : return "ADD_QUANTIFIER_OTHER";
    case ADD_UNIVERSAL                : return "ADD_UNIVERSAL";
    case ADD_OTHER                    : return "ADD_?";
    case DEL_NOUN                     : return "DEL_NOUN";
    case DEL_VERB                     : return "DEL_VERB";
    case DEL_ADJ                      : return "DEL_ADJ";
    case DEL_NEGATION                 : return "DEL_NEGATION";
    case DEL_EXISTENTIAL              : return "DEL_EXISTENTIAL";
    case DEL_QUANTIFIER_OTHER         : return "DEL_QUANTIFIER_OTHER";
    case DEL_UNIVERSAL                : return "DEL_UNIVERSAL";
    case DEL_OTHER                    : return "DEL_?";
    case QUANTIFIER_UP                : return "QUANTIFIER_UP";
    case QUANTIFIER_DOWN              : return "QUANTIFIER_DOWN";
    case QUANTIFIER_NEGATE            : return "QUANTIFIER_NEGATE";
    case QUANTIFIER_REWORD            : return "QUANTIFIER_REWORD";
    default: return "UNK_EDGE_TYPE";
  }
}

inference_function edge2function(const edge_type& type) {
  inference_function function;
  switch (type) {
    case WORDNET_UP:
    case FREEBASE_UP:
    case QUANTIFIER_UP:
    case DEL_NOUN:
    case DEL_VERB:
    case DEL_ADJ:
    case DEL_OTHER:
      function = FUNCTION_FORWARD_ENTAILMENT;
      break;
    case WORDNET_DOWN:
    case FREEBASE_DOWN:
    case QUANTIFIER_DOWN:
    case ADD_NOUN:
    case ADD_VERB:
    case ADD_ADJ:
    case ADD_OTHER:
      function = FUNCTION_REVERSE_ENTAILMENT;
      break;
    case WORDNET_NOUN_ANTONYM:
    case WORDNET_VERB_ANTONYM:
    case WORDNET_ADJECTIVE_ANTONYM:
    case WORDNET_ADVERB_ANTONYM:
      function = FUNCTION_ALTERNATION;
      break;
    case WORDNET_NOUN_SYNONYM:
    case WORDNET_ADJECTIVE_RELATED:
    case QUANTIFIER_REWORD:
    case ANGLE_NN:
    case MORPH_FUDGE_NUMBER:
    case SENSE_REMOVE:
    case SENSE_ADD:
      function = FUNCTION_EQUIVALENT;
      break;
    case WORDNET_ADJECTIVE_PERTAINYM:
    case WORDNET_ADVERB_PERTAINYM:
      function = FUNCTION_EQUIVALENT;
      break;
    case ADD_NEGATION:
    case DEL_NEGATION:
      function = FUNCTION_INDEPENDENCE;
      break;
    case QUANTIFIER_NEGATE:
      function = FUNCTION_NEGATION;
      break;
    // The weird cases...
    case ADD_EXISTENTIAL:
    case ADD_UNIVERSAL:
    case ADD_QUANTIFIER_OTHER:
    case DEL_EXISTENTIAL:
    case DEL_UNIVERSAL:
    case DEL_QUANTIFIER_OTHER:
    case NULL_EDGE_TYPE:
      function = FUNCTION_EQUIVALENT;
      break;
    default:
      printf("Unknown edge type: %u", type);
      std::exit(1);
      break;
  }
  return function;
}

/**
 * Print a demangled stack backtrace of the caller function to FILE* out.
 *
 * FROM:
 *
 * stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
 * published under the WTFPL v2.0
 */
void print_stacktrace(FILE *out, unsigned int max_frames)
{
    fprintf(out, "stack trace:\n");

    // storage array for stack trace address data
    void* addrlist[max_frames+1];

    // retrieve current stack addresses
    int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));

    if (addrlen == 0) {
	fprintf(out, "  <empty, possibly corrupt>\n");
	return;
    }

    // resolve addresses into strings containing "filename(function+address)",
    // this array must be free()-ed
    char** symbollist = backtrace_symbols(addrlist, addrlen);

    // allocate string which will be filled with the demangled function name
    size_t funcnamesize = 256;
    char* funcname = (char*)malloc(funcnamesize);

    // iterate over the returned symbol lines. skip the first, it is the
    // address of this function.
    for (int i = 1; i < addrlen; i++)
    {
	char *begin_name = 0, *begin_offset = 0, *end_offset = 0;

	// find parentheses and +address offset surrounding the mangled name:
	// ./module(function+0x15c) [0x8048a6d]
	for (char *p = symbollist[i]; *p; ++p)
	{
	    if (*p == '(')
		begin_name = p;
	    else if (*p == '+')
		begin_offset = p;
	    else if (*p == ')' && begin_offset) {
		end_offset = p;
		break;
	    }
	}

	if (begin_name && begin_offset && end_offset
	    && begin_name < begin_offset)
	{
	    *begin_name++ = '\0';
	    *begin_offset++ = '\0';
	    *end_offset = '\0';

	    // mangled name is now in [begin_name, begin_offset) and caller
	    // offset in [begin_offset, end_offset). now apply
	    // __cxa_demangle():

	    int status;
	    char* ret = abi::__cxa_demangle(begin_name,
					    funcname, &funcnamesize, &status);
	    if (status == 0) {
		funcname = ret; // use possibly realloc()-ed string
		fprintf(out, "  %s : %s+%s\n",
			symbollist[i], funcname, begin_offset);
	    }
	    else {
		// demangling failed. Output function name as a C function with
		// no arguments.
		fprintf(out, "  %s : %s()+%s\n",
			symbollist[i], begin_name, begin_offset);
	    }
	}
	else
	{
	    // couldn't parse the line? print the whole line.
	    fprintf(out, "  %s\n", symbollist[i]);
	}
    }

    free(funcname);
    free(symbollist);
}
<commit_msg>another try<commit_after>#include "Utils.h"

#include <string>

#include "Types.h"

using namespace std;

const vector<tagged_word> lemursHaveTails() {
  vector<tagged_word> fact;
  fact.push_back(LEMUR);
  fact.push_back(HAVE);
  fact.push_back(TAIL);
  return fact;
}

const vector<tagged_word> animalsHaveTails() {
  vector<tagged_word> animals;
  animals.push_back(ANIMAL);
  animals.push_back(HAVE);
  animals.push_back(TAIL);
  return animals;
}

const vector<tagged_word> catsHaveTails() {
  vector<tagged_word> cats;
  cats.push_back(CAT);
  cats.push_back(HAVE);
  cats.push_back(TAIL);
  return cats;
}

const vector<tagged_word> someDogsChaseCats() {
  vector<tagged_word> cats;
  cats.push_back(SOME);
  cats.push_back(DOG);
  cats.push_back(CHASE);
  cats.push_back(CAT);
  return cats;
}

string toString(const Graph& graph, const tagged_word* fact, const uint8_t factLength) {
  string gloss = "";
  for (int i = 0; i < factLength; ++i) {
    monotonicity m = fact[i].monotonicity;
    string marker = "";
    if (m == MONOTONE_DOWN) { marker = "[v]"; }
    if (m == MONOTONE_UP) { marker = "[^]"; }
    string sense = to_string((long long int) fact[i].sense);
    gloss = gloss + (gloss == "" ? "" : " ") + marker + graph.gloss(fact[i]) + "_" + sense;
  }
  return gloss;
}

string toString(const Graph& graph, SearchType& searchType, const Path* path) {
  if (path == NULL) {
    return "<start>";
  } else {
    return toString(graph, path->fact, path->factLength) +
           "; from\n  " +
           toString(graph, searchType, path->parent);
  }
}

string toString(const edge_type& edge) {
  switch (edge) {
    case WORDNET_UP                   : return "WORDNET_UP";
    case WORDNET_DOWN                 : return "WORDNET_DOWN";
    case WORDNET_NOUN_ANTONYM         : return "WORDNET_NOUN_ANTONYM";
    case WORDNET_NOUN_SYNONYM         : return "WORDNET_NOUN_SYNONYM";
    case WORDNET_VERB_ANTONYM         : return "WORDNET_VERB_ANTONYM";
    case WORDNET_ADJECTIVE_ANTONYM    : return "WORDNET_ADJECTIVE_ANTONYM";
    case WORDNET_ADVERB_ANTONYM       : return "WORDNET_ADVERB_ANTONYM";
    case WORDNET_ADJECTIVE_PERTAINYM  : return "WORDNET_ADJECTIVE_PERTAINYM";
    case WORDNET_ADVERB_PERTAINYM     : return "WORDNET_ADVERB_PERTAINYM";
    case WORDNET_ADJECTIVE_RELATED    : return "WORDNET_ADJECTIVE_RELATED";
    case ANGLE_NN                     : return "ANGLE_NN";
    case FREEBASE_UP                  : return "FREEBASE_UP";
    case FREEBASE_DOWN                : return "FREEBASE_DOWN";
    case MORPH_FUDGE_NUMBER           : return "MORPH_FUDGE_NUMBER";
    case SENSE_REMOVE                 : return "SENSE_REMOVE";
    case SENSE_ADD                    : return "SENSE_ADD";
    case ADD_NOUN                     : return "ADD_NOUN";
    case ADD_VERB                     : return "ADD_VERB";
    case ADD_ADJ                      : return "ADD_ADJ";
    case ADD_NEGATION                 : return "ADD_NEGATION";
    case ADD_EXISTENTIAL              : return "ADD_EXISTENTIAL";
    case ADD_QUANTIFIER_OTHER         : return "ADD_QUANTIFIER_OTHER";
    case ADD_UNIVERSAL                : return "ADD_UNIVERSAL";
    case ADD_OTHER                    : return "ADD_?";
    case DEL_NOUN                     : return "DEL_NOUN";
    case DEL_VERB                     : return "DEL_VERB";
    case DEL_ADJ                      : return "DEL_ADJ";
    case DEL_NEGATION                 : return "DEL_NEGATION";
    case DEL_EXISTENTIAL              : return "DEL_EXISTENTIAL";
    case DEL_QUANTIFIER_OTHER         : return "DEL_QUANTIFIER_OTHER";
    case DEL_UNIVERSAL                : return "DEL_UNIVERSAL";
    case DEL_OTHER                    : return "DEL_?";
    case QUANTIFIER_UP                : return "QUANTIFIER_UP";
    case QUANTIFIER_DOWN              : return "QUANTIFIER_DOWN";
    case QUANTIFIER_NEGATE            : return "QUANTIFIER_NEGATE";
    case QUANTIFIER_REWORD            : return "QUANTIFIER_REWORD";
    default: return "UNK_EDGE_TYPE";
  }
}

inference_function edge2function(const edge_type& type) {
  inference_function function;
  switch (type) {
    case WORDNET_UP:
    case FREEBASE_UP:
    case QUANTIFIER_UP:
    case DEL_NOUN:
    case DEL_VERB:
    case DEL_ADJ:
    case DEL_OTHER:
      function = FUNCTION_FORWARD_ENTAILMENT;
      break;
    case WORDNET_DOWN:
    case FREEBASE_DOWN:
    case QUANTIFIER_DOWN:
    case ADD_NOUN:
    case ADD_VERB:
    case ADD_ADJ:
    case ADD_OTHER:
      function = FUNCTION_REVERSE_ENTAILMENT;
      break;
    case WORDNET_NOUN_ANTONYM:
    case WORDNET_VERB_ANTONYM:
    case WORDNET_ADJECTIVE_ANTONYM:
    case WORDNET_ADVERB_ANTONYM:
      function = FUNCTION_ALTERNATION;
      break;
    case WORDNET_NOUN_SYNONYM:
    case WORDNET_ADJECTIVE_RELATED:
    case QUANTIFIER_REWORD:
    case ANGLE_NN:
    case MORPH_FUDGE_NUMBER:
    case SENSE_REMOVE:
    case SENSE_ADD:
      function = FUNCTION_EQUIVALENT;
      break;
    case WORDNET_ADJECTIVE_PERTAINYM:
    case WORDNET_ADVERB_PERTAINYM:
      function = FUNCTION_EQUIVALENT;
      break;
    case ADD_NEGATION:
    case DEL_NEGATION:
      function = FUNCTION_INDEPENDENCE;
      break;
    case QUANTIFIER_NEGATE:
      function = FUNCTION_NEGATION;
      break;
    // The weird cases...
    case ADD_EXISTENTIAL:
    case ADD_UNIVERSAL:
    case ADD_QUANTIFIER_OTHER:
    case DEL_EXISTENTIAL:
    case DEL_UNIVERSAL:
    case DEL_QUANTIFIER_OTHER:
    case NULL_EDGE_TYPE:
      function = FUNCTION_EQUIVALENT;
      break;
    default:
      printf("Unknown edge type: %u", type);
      std::exit(1);
      break;
  }
  return function;
}

/**
 * Print a demangled stack backtrace of the caller function to FILE* out.
 *
 * FROM:
 *
 * stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
 * published under the WTFPL v2.0
 */
void print_stacktrace(FILE *out, unsigned int max_frames)
{
    fprintf(out, "stack trace:\n");

    // storage array for stack trace address data
    void* addrlist[max_frames+1];

    // retrieve current stack addresses
    int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));

    if (addrlen == 0) {
	fprintf(out, "  <empty, possibly corrupt>\n");
	return;
    }

    // resolve addresses into strings containing "filename(function+address)",
    // this array must be free()-ed
    char** symbollist = backtrace_symbols(addrlist, addrlen);

    // allocate string which will be filled with the demangled function name
    size_t funcnamesize = 256;
    char* funcname = (char*)malloc(funcnamesize);

    // iterate over the returned symbol lines. skip the first, it is the
    // address of this function.
    for (int i = 1; i < addrlen; i++)
    {
	char *begin_name = 0, *begin_offset = 0, *end_offset = 0;

	// find parentheses and +address offset surrounding the mangled name:
	// ./module(function+0x15c) [0x8048a6d]
	for (char *p = symbollist[i]; *p; ++p)
	{
	    if (*p == '(')
		begin_name = p;
	    else if (*p == '+')
		begin_offset = p;
	    else if (*p == ')' && begin_offset) {
		end_offset = p;
		break;
	    }
	}

	if (begin_name && begin_offset && end_offset
	    && begin_name < begin_offset)
	{
	    *begin_name++ = '\0';
	    *begin_offset++ = '\0';
	    *end_offset = '\0';

	    // mangled name is now in [begin_name, begin_offset) and caller
	    // offset in [begin_offset, end_offset). now apply
	    // __cxa_demangle():

	    int status;
	    char* ret = abi::__cxa_demangle(begin_name,
					    funcname, &funcnamesize, &status);
	    if (status == 0) {
		funcname = ret; // use possibly realloc()-ed string
		fprintf(out, "  %s : %s+%s\n",
			symbollist[i], funcname, begin_offset);
	    }
	    else {
		// demangling failed. Output function name as a C function with
		// no arguments.
		fprintf(out, "  %s : %s()+%s\n",
			symbollist[i], begin_name, begin_offset);
	    }
	}
	else
	{
	    // couldn't parse the line? print the whole line.
	    fprintf(out, "  %s\n", symbollist[i]);
	}
    }

    free(funcname);
    free(symbollist);
}
<|endoftext|>


<commit_before>#ifndef ansi
#define ansi

// various ANSI escape codes

const std::string ANSI_RESET = "\u001B[0m";
const std::string ANSI_BLACK = "\u001B[1;30m";
const std::string ANSI_RED = "\u001B[1;31m";
const std::string ANSI_GREEN = "\u001B[1;32m";
const std::string ANSI_YELLOW = "\u001B[1;33m";
const std::string ANSI_BLUE = "\u001B[1;34m";
const std::string ANSI_PURPLE = "\u001B[1;35m";
const std::string ANSI_CYAN = "\u001B[1;36m";
const std::string ANSI_WHITE = "\u001B[1;37m";

const std::string ANSI_LEFT = "\u001B[1C";
const std::string ANSI_RIGHT = "\u001B[1D";
const std::string ANSI_CLEAR_LINE = "\u001B[K";

#endif
<commit_msg>removed unused ANSI escape codes<commit_after>#ifndef ansi
#define ansi

// various ANSI escape codes

const std::string ANSI_RESET = "\u001B[0m";
const std::string ANSI_BLACK = "\u001B[1;30m";
const std::string ANSI_RED = "\u001B[1;31m";
const std::string ANSI_GREEN = "\u001B[1;32m";
const std::string ANSI_YELLOW = "\u001B[1;33m";
const std::string ANSI_BLUE = "\u001B[1;34m";
const std::string ANSI_PURPLE = "\u001B[1;35m";
const std::string ANSI_CYAN = "\u001B[1;36m";
const std::string ANSI_WHITE = "\u001B[1;37m";

#endif
<|endoftext|>


<commit_before>#include "base.h"
#include "opencv2/core/core.hpp"
#include <boost/filesystem.hpp>

namespace fs=boost::filesystem;

/** \brief Class constructor. Reads node parameters and initialize some properties.
  * @return
  * \param nh public node handler
  * \param nhp private node handler
  */
slam::SlamBase::SlamBase(
  ros::NodeHandle nh, ros::NodeHandle nhp) : nh_(nh), nh_private_(nhp)
{
  // Read the node parameters
  readParameters();

  // Initialize the stereo slam
  init();
}

/** \brief Finalize stereo slam node
  * @return
  */
void slam::SlamBase::finalize()
{
  ROS_INFO("[StereoSlam:] Finalizing...");
  lc_.finalize();
  ROS_INFO("[StereoSlam:] Done!");
}

/** \brief Messages callback. This function is called when synchronized odometry and image
  * message are received.
  * @return
  * \param odom_msg ros odometry message of type nav_msgs::Odometry
  * \param l_img left stereo image message of type sensor_msgs::Image
  * \param r_img right stereo image message of type sensor_msgs::Image
  * \param l_info left stereo info message of type sensor_msgs::CameraInfo
  * \param r_info right stereo info message of type sensor_msgs::CameraInfo
  * \param cloud_msg ros pointcloud message of type sensor_msgs::PointCloud2
  */
void slam::SlamBase::msgsCallback(const nav_msgs::Odometry::ConstPtr& odom_msg,
                                  const sensor_msgs::ImageConstPtr& l_img_msg,
                                  const sensor_msgs::ImageConstPtr& r_img_msg,
                                  const sensor_msgs::CameraInfoConstPtr& l_info_msg,
                                  const sensor_msgs::CameraInfoConstPtr& r_info_msg,
                                  const sensor_msgs::PointCloud2ConstPtr& cloud_msg)
{
  // Get the cloud
  PointCloud::Ptr pcl_cloud(new PointCloud);
  pcl::fromROSMsg(*cloud_msg, *pcl_cloud);
  pcl::copyPointCloud(*pcl_cloud, pcl_cloud_);

  // Call the general slam callback
  msgsCallback(odom_msg, l_img_msg, r_img_msg, l_info_msg, r_info_msg);
}

/** \brief Messages callback. This function is called when synchronized odometry and image
  * message are received.
  * @return
  * \param odom_msg ros odometry message of type nav_msgs::Odometry
  * \param l_img left stereo image message of type sensor_msgs::Image
  * \param r_img right stereo image message of type sensor_msgs::Image
  * \param l_info left stereo info message of type sensor_msgs::CameraInfo
  * \param r_info right stereo info message of type sensor_msgs::CameraInfo
  */
void slam::SlamBase::msgsCallback(const nav_msgs::Odometry::ConstPtr& odom_msg,
                                  const sensor_msgs::ImageConstPtr& l_img_msg,
                                  const sensor_msgs::ImageConstPtr& r_img_msg,
                                  const sensor_msgs::CameraInfoConstPtr& l_info_msg,
                                  const sensor_msgs::CameraInfoConstPtr& r_info_msg)
{
  // Get the messages
  Mat l_img, r_img;
  Tools::imgMsgToMat(*l_img_msg, *r_img_msg, l_img, r_img);
  double timestamp = odom_msg->header.stamp.toSec();
  tf::Transform current_odom = Tools::odomTotf(*odom_msg);

  // Initialization
  if (first_iter_)
  {
    // Set the camera model (only once)
    Mat camera_matrix;
    image_geometry::StereoCameraModel stereo_camera_model;
    Tools::getCameraModel(*l_info_msg, *r_info_msg, stereo_camera_model, camera_matrix);
    lc_.setCameraModel(stereo_camera_model, camera_matrix);

    // Save the first node
    int cur_id = graph_.addVertice(current_odom, current_odom, timestamp);
    string lc_ref = boost::lexical_cast<string>(cur_id);
    lc_.setNode(l_img, r_img, lc_ref);

    // Publish and exit
    pose_.publish(*odom_msg, current_odom, true);
    first_iter_ = false;
    return;
  }

  // Correct the current odometry with the graph information
  tf::Transform last_graph_pose, last_graph_odom;
  graph_.getLastPoses(current_odom, last_graph_pose, last_graph_odom);
  tf::Transform corrected_odom = pose_.correctOdom(current_odom, last_graph_pose, last_graph_odom);

   // Check if difference between poses is larger than minimum displacement
  double pose_diff = Tools::poseDiff(last_graph_odom, current_odom);
  if (pose_diff <= params_.min_displacement)
  {
    pose_.publish(*odom_msg, corrected_odom, false);
    return;
  }

  // Insert this new node into the graph
  int cur_id = graph_.addVertice(current_odom, corrected_odom, timestamp);
  string lc_ref = boost::lexical_cast<string>(cur_id);
  lc_.setNode(l_img, r_img, lc_ref);
  ROS_INFO_STREAM("[StereoSlam:] Node " << cur_id << " inserted.");

  // Save the pointcloud for this new node
  if (params_.save_clouds && pcl_cloud_.size() > 0)
  {
    // The file name will be the timestamp
    stringstream s;
    s << fixed << setprecision(9) << timestamp;
    string filename = s.str();
    filename.erase(std::remove(filename.begin(), filename.end(), '.'), filename.end());
    pcl::io::savePCDFileBinary(params_.clouds_dir + filename + ".pcd", pcl_cloud_);
  }

  // Detect loop closures between nodes by distance
  bool any_loop_closure = false;
  vector<int> neighbors;
  graph_.findClosestNodes(params_.min_neighbour, 2, neighbors);
  for (uint i=0; i<neighbors.size(); i++)
  {
    tf::Transform edge;
    string lc_id = boost::lexical_cast<string>(neighbors[i]);
    bool valid_lc = lc_.getLoopClosureById(lc_ref, lc_id, edge);
    if (valid_lc)
    {
      ROS_INFO_STREAM("[StereoSlam:] Node with id " << cur_id << " closes loop with " << lc_id);
      graph_.addEdge(boost::lexical_cast<int>(lc_id), cur_id, edge);
      any_loop_closure = true;
    }
  }

  // TODO: do not repeat loop closures in libhaloc!

  // Detect loop closures between nodes using hashes
  int lc_id_num = -1;
  string lc_id_name = "";
  tf::Transform edge;
  bool valid_lc = lc_.getLoopClosure(lc_id_num, lc_id_name, edge);
  if (valid_lc)
  {
    ROS_INFO_STREAM("[StereoSlam:] Node with id " << cur_id << " closes loop with " << lc_id_name);
    graph_.addEdge(boost::lexical_cast<int>(lc_id_name), cur_id, edge);
    any_loop_closure = true;
  }

  // Update the graph if any loop closing
  if (any_loop_closure) graph_.update();

  // Publish the corrected pose
  graph_.getLastPoses(current_odom, last_graph_pose, last_graph_odom);
  corrected_odom = pose_.correctOdom(current_odom, last_graph_pose, last_graph_odom);
  pose_.publish(*odom_msg, corrected_odom, true);

  // Save graph to file
  graph_.saveGraphToFile();

  return;
}

/** \brief Reads the stereo slam node parameters
  * @return
  */
void slam::SlamBase::readParameters()
{
  Params params;
  slam::Pose::Params pose_params;
  slam::Graph::Params graph_params;
  haloc::LoopClosure::Params lc_params;
  lc_params.num_proj = 2;
  lc_params.validate = false;
  lc_params.verbose = true;

  // Operational directories
  string work_dir;
  nh_private_.param("work_dir", work_dir, string(""));
  if (work_dir[work_dir.length()-1] != '/')
    work_dir += "/";
  lc_params.work_dir = work_dir;
  params.clouds_dir = work_dir + "clouds/";
  if (fs::is_directory(params.clouds_dir))
    fs::remove_all(params.clouds_dir);
  fs::path dir(params.clouds_dir);
  if (!fs::create_directory(dir))
    ROS_ERROR("[StereoSlam:] ERROR -> Impossible to create the clouds directory.");

  // Topic parameters
  string odom_topic, left_topic, right_topic, left_info_topic, right_info_topic, cloud_topic;
  nh_private_.param("pose_frame_id",        pose_params.pose_frame_id,        string("/map"));
  nh_private_.param("pose_child_frame_id",  pose_params.pose_child_frame_id,  string("/robot"));
  nh_private_.param("odom_topic",           odom_topic,                       string("/odometry"));
  nh_private_.param("left_topic",           left_topic,                       string("/left/image_rect_color"));
  nh_private_.param("right_topic",          right_topic,                      string("/right/image_rect_color"));
  nh_private_.param("left_info_topic",      left_info_topic,                  string("/left/camera_info"));
  nh_private_.param("right_info_topic",     right_info_topic,                 string("/right/camera_info"));
  nh_private_.param("cloud_topic",          cloud_topic,                      string("/points2"));

  // Motion parameters
  nh_private_.param("save_clouds",  params.save_clouds, false);
  nh_private_.getParam("min_displacement",  params.min_displacement);

  // Loop closure parameters
  nh_private_.param("desc_type",            lc_params.desc_type,              string("SIFT"));
  nh_private_.param("desc_matching_type",   lc_params.desc_matching_type,     string("CROSSCHECK"));
  nh_private_.getParam("desc_thresh_ratio", lc_params.desc_thresh_ratio);
  nh_private_.getParam("min_neighbour",     lc_params.min_neighbour);
  nh_private_.getParam("n_candidates",      lc_params.n_candidates);
  nh_private_.getParam("min_matches",       lc_params.min_matches);
  nh_private_.getParam("min_inliers",       lc_params.min_inliers);

  // G2O parameters
  nh_private_.getParam("g2o_algorithm",     graph_params.g2o_algorithm);
  nh_private_.getParam("g2o_opt_max_iter",  graph_params.go2_opt_max_iter);
  graph_params.save_dir = lc_params.work_dir;
  graph_params.pose_frame_id = pose_params.pose_frame_id;
  graph_params.pose_child_frame_id = pose_params.pose_child_frame_id;

  // Set the class parameters
  params.min_neighbour = lc_params.min_neighbour;
  setParams(params);
  pose_.setParams(pose_params);
  graph_.setParams(graph_params);
  lc_.setParams(lc_params);

  // Topics subscriptions
  image_transport::ImageTransport it(nh_);
  odom_sub_       .subscribe(nh_, odom_topic,       1);
  left_sub_       .subscribe(it,  left_topic,       1);
  right_sub_      .subscribe(it,  right_topic,      1);
  left_info_sub_  .subscribe(nh_, left_info_topic,  1);
  right_info_sub_ .subscribe(nh_, right_info_topic, 1);

  if (params_.save_clouds)
    cloud_sub_    .subscribe(nh_, cloud_topic,      1);
}

/** \brief Initializes the stereo slam node
  * @return true if init OK
  */
void slam::SlamBase::init()
{
  first_iter_ = true;

  // Init Haloc
  lc_.init();

  // Advertise the pose message
  pose_.advertisePoseMsg(nh_private_);

  // Callback synchronization
  if (params_.save_clouds)
  {
    exact_sync_cloud_.reset(new ExactSyncCloud(ExactPolicyCloud(1),
                                    odom_sub_,
                                    left_sub_,
                                    right_sub_,
                                    left_info_sub_,
                                    right_info_sub_,
                                    cloud_sub_) );
    exact_sync_cloud_->registerCallback(boost::bind(
        &slam::SlamBase::msgsCallback,
        this, _1, _2, _3, _4, _5, _6));
  }
  else
  {
    exact_sync_no_cloud_.reset(new ExactSyncNoCloud(ExactPolicyNoCloud(1),
                                    odom_sub_,
                                    left_sub_,
                                    right_sub_,
                                    left_info_sub_,
                                    right_info_sub_) );
    exact_sync_no_cloud_->registerCallback(boost::bind(
        &slam::SlamBase::msgsCallback,
        this, _1, _2, _3, _4, _5));
  }

}<commit_msg>Fix incompatibility with libhaloc<commit_after>#include "base.h"
#include "opencv2/core/core.hpp"
#include <boost/filesystem.hpp>

namespace fs=boost::filesystem;

/** \brief Class constructor. Reads node parameters and initialize some properties.
  * @return
  * \param nh public node handler
  * \param nhp private node handler
  */
slam::SlamBase::SlamBase(
  ros::NodeHandle nh, ros::NodeHandle nhp) : nh_(nh), nh_private_(nhp)
{
  // Read the node parameters
  readParameters();

  // Initialize the stereo slam
  init();
}

/** \brief Finalize stereo slam node
  * @return
  */
void slam::SlamBase::finalize()
{
  ROS_INFO("[StereoSlam:] Finalizing...");
  lc_.finalize();
  ROS_INFO("[StereoSlam:] Done!");
}

/** \brief Messages callback. This function is called when synchronized odometry and image
  * message are received.
  * @return
  * \param odom_msg ros odometry message of type nav_msgs::Odometry
  * \param l_img left stereo image message of type sensor_msgs::Image
  * \param r_img right stereo image message of type sensor_msgs::Image
  * \param l_info left stereo info message of type sensor_msgs::CameraInfo
  * \param r_info right stereo info message of type sensor_msgs::CameraInfo
  * \param cloud_msg ros pointcloud message of type sensor_msgs::PointCloud2
  */
void slam::SlamBase::msgsCallback(const nav_msgs::Odometry::ConstPtr& odom_msg,
                                  const sensor_msgs::ImageConstPtr& l_img_msg,
                                  const sensor_msgs::ImageConstPtr& r_img_msg,
                                  const sensor_msgs::CameraInfoConstPtr& l_info_msg,
                                  const sensor_msgs::CameraInfoConstPtr& r_info_msg,
                                  const sensor_msgs::PointCloud2ConstPtr& cloud_msg)
{
  // Get the cloud
  PointCloud::Ptr pcl_cloud(new PointCloud);
  pcl::fromROSMsg(*cloud_msg, *pcl_cloud);
  pcl::copyPointCloud(*pcl_cloud, pcl_cloud_);

  // Call the general slam callback
  msgsCallback(odom_msg, l_img_msg, r_img_msg, l_info_msg, r_info_msg);
}

/** \brief Messages callback. This function is called when synchronized odometry and image
  * message are received.
  * @return
  * \param odom_msg ros odometry message of type nav_msgs::Odometry
  * \param l_img left stereo image message of type sensor_msgs::Image
  * \param r_img right stereo image message of type sensor_msgs::Image
  * \param l_info left stereo info message of type sensor_msgs::CameraInfo
  * \param r_info right stereo info message of type sensor_msgs::CameraInfo
  */
void slam::SlamBase::msgsCallback(const nav_msgs::Odometry::ConstPtr& odom_msg,
                                  const sensor_msgs::ImageConstPtr& l_img_msg,
                                  const sensor_msgs::ImageConstPtr& r_img_msg,
                                  const sensor_msgs::CameraInfoConstPtr& l_info_msg,
                                  const sensor_msgs::CameraInfoConstPtr& r_info_msg)
{
  // Get the messages
  Mat l_img, r_img;
  Tools::imgMsgToMat(*l_img_msg, *r_img_msg, l_img, r_img);
  double timestamp = odom_msg->header.stamp.toSec();
  tf::Transform current_odom = Tools::odomTotf(*odom_msg);

  // Initialization
  if (first_iter_)
  {
    // Set the camera model (only once)
    Mat camera_matrix;
    image_geometry::StereoCameraModel stereo_camera_model;
    Tools::getCameraModel(*l_info_msg, *r_info_msg, stereo_camera_model, camera_matrix);
    lc_.setCameraModel(stereo_camera_model, camera_matrix);

    // Save the first node
    int cur_id = graph_.addVertice(current_odom, current_odom, timestamp);
    string lc_ref = boost::lexical_cast<string>(cur_id);
    lc_.setNode(l_img, r_img, lc_ref);

    // Publish and exit
    pose_.publish(*odom_msg, current_odom, true);
    first_iter_ = false;
    return;
  }

  // Correct the current odometry with the graph information
  tf::Transform last_graph_pose, last_graph_odom;
  graph_.getLastPoses(current_odom, last_graph_pose, last_graph_odom);
  tf::Transform corrected_odom = pose_.correctOdom(current_odom, last_graph_pose, last_graph_odom);

   // Check if difference between poses is larger than minimum displacement
  double pose_diff = Tools::poseDiff(last_graph_odom, current_odom);
  if (pose_diff <= params_.min_displacement)
  {
    pose_.publish(*odom_msg, corrected_odom, false);
    return;
  }

  // Insert this new node into the graph
  int cur_id = graph_.addVertice(current_odom, corrected_odom, timestamp);
  string lc_ref = boost::lexical_cast<string>(cur_id);
  lc_.setNode(l_img, r_img, lc_ref);
  ROS_INFO_STREAM("[StereoSlam:] Node " << cur_id << " inserted.");

  // Save the pointcloud for this new node
  if (params_.save_clouds && pcl_cloud_.size() > 0)
  {
    // The file name will be the timestamp
    stringstream s;
    s << fixed << setprecision(9) << timestamp;
    string filename = s.str();
    filename.erase(std::remove(filename.begin(), filename.end(), '.'), filename.end());
    pcl::io::savePCDFileBinary(params_.clouds_dir + filename + ".pcd", pcl_cloud_);
  }

  // Detect loop closures between nodes by distance
  bool any_loop_closure = false;
  vector<int> neighbors;
  graph_.findClosestNodes(params_.min_neighbour, 2, neighbors);
  for (uint i=0; i<neighbors.size(); i++)
  {
    tf::Transform edge;
    string lc_id = boost::lexical_cast<string>(neighbors[i]);
    bool valid_lc = lc_.getLoopClosureById(lc_ref, lc_id, edge);
    if (valid_lc)
    {
      ROS_INFO_STREAM("[StereoSlam:] Node with id " << cur_id << " closes loop with " << lc_id);
      graph_.addEdge(boost::lexical_cast<int>(lc_id), cur_id, edge);
      any_loop_closure = true;
    }
  }

  // TODO: do not repeat loop closures in libhaloc!

  // Detect loop closures between nodes using hashes
  int lc_id_num = -1;
  string lc_id_name = "";
  tf::Transform edge;
  bool valid_lc = lc_.getLoopClosure(lc_id_num, lc_id_name, edge);
  if (valid_lc)
  {
    ROS_INFO_STREAM("[StereoSlam:] Node with id " << cur_id << " closes loop with " << lc_id_name);
    graph_.addEdge(boost::lexical_cast<int>(lc_id_name), cur_id, edge);
    any_loop_closure = true;
  }

  // Update the graph if any loop closing
  if (any_loop_closure) graph_.update();

  // Publish the corrected pose
  graph_.getLastPoses(current_odom, last_graph_pose, last_graph_odom);
  corrected_odom = pose_.correctOdom(current_odom, last_graph_pose, last_graph_odom);
  pose_.publish(*odom_msg, corrected_odom, true);

  // Save graph to file
  graph_.saveGraphToFile();

  return;
}

/** \brief Reads the stereo slam node parameters
  * @return
  */
void slam::SlamBase::readParameters()
{
  Params params;
  slam::Pose::Params pose_params;
  slam::Graph::Params graph_params;
  haloc::LoopClosure::Params lc_params;
  lc_params.verbose = true;

  // Operational directories
  string work_dir;
  nh_private_.param("work_dir", work_dir, string(""));
  if (work_dir[work_dir.length()-1] != '/')
    work_dir += "/";
  lc_params.work_dir = work_dir;
  params.clouds_dir = work_dir + "clouds/";
  if (fs::is_directory(params.clouds_dir))
    fs::remove_all(params.clouds_dir);
  fs::path dir(params.clouds_dir);
  if (!fs::create_directory(dir))
    ROS_ERROR("[StereoSlam:] ERROR -> Impossible to create the clouds directory.");

  // Topic parameters
  string odom_topic, left_topic, right_topic, left_info_topic, right_info_topic, cloud_topic;
  nh_private_.param("pose_frame_id",        pose_params.pose_frame_id,        string("/map"));
  nh_private_.param("pose_child_frame_id",  pose_params.pose_child_frame_id,  string("/robot"));
  nh_private_.param("odom_topic",           odom_topic,                       string("/odometry"));
  nh_private_.param("left_topic",           left_topic,                       string("/left/image_rect_color"));
  nh_private_.param("right_topic",          right_topic,                      string("/right/image_rect_color"));
  nh_private_.param("left_info_topic",      left_info_topic,                  string("/left/camera_info"));
  nh_private_.param("right_info_topic",     right_info_topic,                 string("/right/camera_info"));
  nh_private_.param("cloud_topic",          cloud_topic,                      string("/points2"));

  // Motion parameters
  nh_private_.param("save_clouds",  params.save_clouds, false);
  nh_private_.getParam("min_displacement",  params.min_displacement);

  // Loop closure parameters
  nh_private_.param("desc_type",            lc_params.desc_type,              string("SIFT"));
  nh_private_.param("desc_matching_type",   lc_params.desc_matching_type,     string("CROSSCHECK"));
  nh_private_.getParam("desc_thresh_ratio", lc_params.desc_thresh_ratio);
  nh_private_.getParam("min_neighbour",     lc_params.min_neighbour);
  nh_private_.getParam("n_candidates",      lc_params.n_candidates);
  nh_private_.getParam("min_matches",       lc_params.min_matches);
  nh_private_.getParam("min_inliers",       lc_params.min_inliers);

  // G2O parameters
  nh_private_.getParam("g2o_algorithm",     graph_params.g2o_algorithm);
  nh_private_.getParam("g2o_opt_max_iter",  graph_params.go2_opt_max_iter);
  graph_params.save_dir = lc_params.work_dir;
  graph_params.pose_frame_id = pose_params.pose_frame_id;
  graph_params.pose_child_frame_id = pose_params.pose_child_frame_id;

  // Set the class parameters
  params.min_neighbour = lc_params.min_neighbour;
  setParams(params);
  pose_.setParams(pose_params);
  graph_.setParams(graph_params);
  lc_.setParams(lc_params);

  // Topics subscriptions
  image_transport::ImageTransport it(nh_);
  odom_sub_       .subscribe(nh_, odom_topic,       1);
  left_sub_       .subscribe(it,  left_topic,       1);
  right_sub_      .subscribe(it,  right_topic,      1);
  left_info_sub_  .subscribe(nh_, left_info_topic,  1);
  right_info_sub_ .subscribe(nh_, right_info_topic, 1);

  if (params_.save_clouds)
    cloud_sub_    .subscribe(nh_, cloud_topic,      1);
}

/** \brief Initializes the stereo slam node
  * @return true if init OK
  */
void slam::SlamBase::init()
{
  first_iter_ = true;

  // Init Haloc
  lc_.init();

  // Advertise the pose message
  pose_.advertisePoseMsg(nh_private_);

  // Callback synchronization
  if (params_.save_clouds)
  {
    exact_sync_cloud_.reset(new ExactSyncCloud(ExactPolicyCloud(1),
                                    odom_sub_,
                                    left_sub_,
                                    right_sub_,
                                    left_info_sub_,
                                    right_info_sub_,
                                    cloud_sub_) );
    exact_sync_cloud_->registerCallback(boost::bind(
        &slam::SlamBase::msgsCallback,
        this, _1, _2, _3, _4, _5, _6));
  }
  else
  {
    exact_sync_no_cloud_.reset(new ExactSyncNoCloud(ExactPolicyNoCloud(1),
                                    odom_sub_,
                                    left_sub_,
                                    right_sub_,
                                    left_info_sub_,
                                    right_info_sub_) );
    exact_sync_no_cloud_->registerCallback(boost::bind(
        &slam::SlamBase::msgsCallback,
        this, _1, _2, _3, _4, _5));
  }

}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Lech Kulina
 *
 * This file is part of the Realms Of Steel.
 * For conditions of distribution and use, see copyright details in the LICENSE file.
 */
#include <cstdlib>
#include <boost/property_tree/info_parser.hpp>
#include <Application/Logger.h>
#include <Application/Application.h>

int main() {
    int exitCode = EXIT_FAILURE;

    ros::PropertyTree config;
    boost::property_tree::read_info("Config.info", config);

    if (!ros::Logger::initInstance(config.get_child("Logger")) ||
        !ros::Application::initInstance(config.get_child("application"))) {
        return exitCode;
    }

    exitCode = ros::Application::getInstance()->run();
    ros::Application::getInstance()->uninit();

    return exitCode;
}
<commit_msg>Prepare Shaders and Programs managers before starting main loop<commit_after>/*
 * Copyright (c) 2016 Lech Kulina
 *
 * This file is part of the Realms Of Steel.
 * For conditions of distribution and use, see copyright details in the LICENSE file.
 */
#include <cstdlib>
#include <boost/property_tree/info_parser.hpp>
#include <application/Logger.h>
#include <application/Application.h>
#include <graphics/ShadersManager.h>
#include <graphics/ProgramsManager.h>

int main() {
    int exitCode = EXIT_FAILURE;

    ros::PropertyTree config;
    boost::property_tree::read_info("Config.info", config);

    if (!ros::Logger::initInstance(config.get_child("Logger")) ||
        !ros::Application::initInstance(config.get_child("application"))) {
        return exitCode;
    }

    ros::PropertyTree::const_assoc_iterator iter = config.find("models");
    if (iter != config.not_found()) {
        ros::PropertyTree::const_iterator cast = config.to_iterator(iter);
        if (!ros::ShadersManager::getInstance()->prepare(cast->second) ||
            !ros::ProgramsManager::getInstance()->prepare(cast->second)) {
            return exitCode;
        }
    }

    exitCode = ros::Application::getInstance()->run();
    ros::Application::getInstance()->uninit();

    return exitCode;
}
<|endoftext|>


<commit_before>#include <catch.hpp>
#include <rapidcheck-catch.h>

#include "rapidcheck/shrinkable/Transform.h"
#include "rapidcheck/shrinkable/Create.h"
#include "rapidcheck/shrinkable/Operations.h"

#include "util/Generators.h"
#include "util/CopyGuard.h"

using namespace rc;
using namespace rc::test;

int doubleIt(int x) { return x * 2; }

TEST_CASE("shrinkable::map") {
    prop("maps value()",
         [](int x) {
             const auto shrinkable = shrinkable::map(
                 doubleIt, shrinkable::just(x));
             RC_ASSERT(shrinkable.value() == doubleIt(x));
         });

    prop("maps shrinks()",
         [](Shrinkable<int> from) {
             const auto shrinkable = shrinkable::map(doubleIt, from);
             const auto expected = seq::map([](Shrinkable<int> &&shrink) {
                 return shrinkable::map(doubleIt, shrink);
             }, from.shrinks());

             RC_ASSERT(shrinkable.shrinks() == expected);
         });

    prop("does not copy shrinkable on construction",
         [](Shrinkable<CopyGuard> from) {
             const auto shrinkable = shrinkable::map(
                 [](CopyGuard &&x) { return std::move(x); },
                 std::move(from));
         });
}

TEST_CASE("shrinkable::mapShrinks") {
    prop("maps shrinks with the given mapping callable",
         [](Shrinkable<int> shrinkable) {
             const auto mapper = [](Seq<Shrinkable<int>> &&shrinkable) {
                 return seq::map([](const Shrinkable<int> &shrink) {
                     return shrinkable::just(shrink.value());
                 }, std::move(shrinkable));
             };

             const auto mapped = shrinkable::mapShrinks(mapper, shrinkable);
             RC_ASSERT(mapped.shrinks() == mapper(shrinkable.shrinks()));
         });

    prop("leaves value unaffected",
         [](int x) {
             const auto shrinkable = shrinkable::mapShrinks(
                 fn::constant(Seq<Shrinkable<int>>()),
                 shrinkable::just(x));
             RC_ASSERT(shrinkable.value() == x);
         });

    prop("does not copy shrinkable on construction",
         [](Shrinkable<CopyGuard> from) {
             const auto shrinkable = shrinkable::mapShrinks(
                 fn::constant(Seq<Shrinkable<CopyGuard>>()),
                 std::move(from));
         });
}

TEST_CASE("shrinkable::filter") {
    prop("returns Nothing if predicate returns false for value",
         [](int x) {
             const auto shrinkable = shrinkable::just(x);
             RC_ASSERT(!shrinkable::filter(fn::constant(false), shrinkable));
         });

    prop("returned shrinkable does not contain any value for which predicate"
         " returns false",
         [] {
             const auto pred = [](int x) { return (x % 2) == 0; };
             const auto shrinkable = *gen::suchThat<Shrinkable<int>>(
                 [&](const Shrinkable<int> &x) {
                     return pred(x.value());
                 });
             const auto filtered = *shrinkable::filter(pred, shrinkable);
             RC_ASSERT(shrinkable::all(filtered, [&](const Shrinkable<int> &s) {
                 return pred(s.value());
             }));
         });

TEST_CASE("shrinkable::pair") {
    prop("has no shrinks if the two Shrinkables have no shrinks",
         [](int a, int b) {
             REQUIRE(shrinkable::pair(shrinkable::just(a),
                                      shrinkable::just(b)) ==
                     shrinkable::just(std::make_pair(a, b)));
         });

    prop("shrinks first element and then the second one",
         [] {
             const auto a = *gen::ranged<int>(0, 3);
             const auto b = *gen::ranged<int>(0, 3);
             const auto makeShrinkable = [](int x) {
                 return shrinkable::shrinkRecur(x, [](int v) {
                     return seq::range(v - 1, -1);
                 });
             };
             const auto shrinkable = shrinkable::pair(
                 makeShrinkable(a),
                 makeShrinkable(b));
             const auto expected = shrinkable::shrinkRecur(
                 std::make_pair(a, b), [](const std::pair<int, int> &p) {
                     return seq::concat(
                         seq::map([=](int x) {
                             return std::make_pair(x, p.second);
                         }, seq::range(p.first - 1, -1)),
                         seq::map([=](int x) {
                             return std::make_pair(p.first, x);
                         }, seq::range(p.second - 1, -1)));
                 });

             RC_ASSERT(shrinkable == expected);
         });
}
<commit_msg>Add an extra test for shrinkable::filter<commit_after>#include <catch.hpp>
#include <rapidcheck-catch.h>

#include "rapidcheck/shrinkable/Transform.h"
#include "rapidcheck/shrinkable/Create.h"
#include "rapidcheck/shrinkable/Operations.h"

#include "util/Generators.h"
#include "util/CopyGuard.h"

using namespace rc;
using namespace rc::test;

int doubleIt(int x) { return x * 2; }

TEST_CASE("shrinkable::map") {
    prop("maps value()",
         [](int x) {
             const auto shrinkable = shrinkable::map(
                 doubleIt, shrinkable::just(x));
             RC_ASSERT(shrinkable.value() == doubleIt(x));
         });

    prop("maps shrinks()",
         [](Shrinkable<int> from) {
             const auto shrinkable = shrinkable::map(doubleIt, from);
             const auto expected = seq::map([](Shrinkable<int> &&shrink) {
                 return shrinkable::map(doubleIt, shrink);
             }, from.shrinks());

             RC_ASSERT(shrinkable.shrinks() == expected);
         });

    prop("does not copy shrinkable on construction",
         [](Shrinkable<CopyGuard> from) {
             const auto shrinkable = shrinkable::map(
                 [](CopyGuard &&x) { return std::move(x); },
                 std::move(from));
         });
}

TEST_CASE("shrinkable::mapShrinks") {
    prop("maps shrinks with the given mapping callable",
         [](Shrinkable<int> shrinkable) {
             const auto mapper = [](Seq<Shrinkable<int>> &&shrinkable) {
                 return seq::map([](const Shrinkable<int> &shrink) {
                     return shrinkable::just(shrink.value());
                 }, std::move(shrinkable));
             };

             const auto mapped = shrinkable::mapShrinks(mapper, shrinkable);
             RC_ASSERT(mapped.shrinks() == mapper(shrinkable.shrinks()));
         });

    prop("leaves value unaffected",
         [](int x) {
             const auto shrinkable = shrinkable::mapShrinks(
                 fn::constant(Seq<Shrinkable<int>>()),
                 shrinkable::just(x));
             RC_ASSERT(shrinkable.value() == x);
         });

    prop("does not copy shrinkable on construction",
         [](Shrinkable<CopyGuard> from) {
             const auto shrinkable = shrinkable::mapShrinks(
                 fn::constant(Seq<Shrinkable<CopyGuard>>()),
                 std::move(from));
         });
}

TEST_CASE("shrinkable::filter") {
    prop("returns Nothing if predicate returns false for value",
         [](int x) {
             const auto shrinkable = shrinkable::just(x);
             RC_ASSERT(!shrinkable::filter(fn::constant(false), shrinkable));
         });

    prop("returned shrinkable does not contain any value for which predicate"
         " returns false",
         [] {
             const auto pred = [](int x) { return (x % 2) == 0; };
             const auto shrinkable = *gen::suchThat<Shrinkable<int>>(
                 [&](const Shrinkable<int> &x) {
                     return pred(x.value());
                 });
             const auto filtered = *shrinkable::filter(pred, shrinkable);
             RC_ASSERT(shrinkable::all(filtered, [&](const Shrinkable<int> &s) {
                 return pred(s.value());
             }));
         });

    prop("if the filter returns true for every value, the returned shrinkable"
         " is equal to the original",
         [](Shrinkable<int> shrinkable) {
             RC_ASSERT(*shrinkable::filter(fn::constant(true), shrinkable) ==
                       shrinkable);
         });
}

TEST_CASE("shrinkable::pair") {
    prop("has no shrinks if the two Shrinkables have no shrinks",
         [](int a, int b) {
             REQUIRE(shrinkable::pair(shrinkable::just(a),
                                      shrinkable::just(b)) ==
                     shrinkable::just(std::make_pair(a, b)));
         });

    prop("shrinks first element and then the second one",
         [] {
             const auto a = *gen::ranged<int>(0, 3);
             const auto b = *gen::ranged<int>(0, 3);
             const auto makeShrinkable = [](int x) {
                 return shrinkable::shrinkRecur(x, [](int v) {
                     return seq::range(v - 1, -1);
                 });
             };
             const auto shrinkable = shrinkable::pair(
                 makeShrinkable(a),
                 makeShrinkable(b));
             const auto expected = shrinkable::shrinkRecur(
                 std::make_pair(a, b), [](const std::pair<int, int> &p) {
                     return seq::concat(
                         seq::map([=](int x) {
                             return std::make_pair(x, p.second);
                         }, seq::range(p.first - 1, -1)),
                         seq::map([=](int x) {
                             return std::make_pair(p.first, x);
                         }, seq::range(p.second - 1, -1)));
                 });

             RC_ASSERT(shrinkable == expected);
         });
}
<|endoftext|>


<commit_before>/*
 * bacteria-core, core for cellular automaton
 * Copyright (C) 2016 Pavel Dolgov
 *
 * See the LICENSE file for terms of use.
 */

#ifndef CONSTANTS_HPP_
#define CONSTANTS_HPP_

const int DEFAULT_MASS = 5;

#endif
<commit_msg>Add some new constants<commit_after>/*
 * bacteria-core, core for cellular automaton
 * Copyright (C) 2016 Pavel Dolgov
 *
 * See the LICENSE file for terms of use.
 */

#ifndef CONSTANTS_HPP_
#define CONSTANTS_HPP_

const int DEFAULT_MASS = 5;

const int MIN_WIDTH = 5;

const int MAX_WIDTH = 500;

const int MIN_HEIGHT = 5;

const int MAX_HEIGHT = 500;

#endif
<|endoftext|>


<commit_before>/***************************************
** Tsunagari Tile Engine              **
** area.cpp                           **
** Copyright 2011-2015 Michael Reiley **
** Copyright 2011-2018 Paul Merrill   **
***************************************/

// **********
// 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.
// **********

#include "core/area.h"

#include <math.h>

#include <algorithm>

#include "core/algorithm.h"
#include "core/client-conf.h"
#include "core/display-list.h"
#include "core/entity.h"
#include "core/formatter.h"
#include "core/log.h"
#include "core/images.h"
#include "core/music.h"
#include "core/npc.h"
#include "core/overlay.h"
#include "core/player.h"
#include "core/tile.h"
#include "core/viewport.h"
#include "core/window.h"
#include "core/world.h"
#include "util/assert.h"
#include "util/math2.h"

#include "data/data-world.h"

#define CHECK(x)  if (!(x)) { return false; }

/* NOTE: In the TMX map format used by Tiled, tileset tiles start counting
         their Y-positions from 0, while layer tiles start counting from 1. I
         can't imagine why the author did this, but we have to take it into
         account.
*/

Area::Area(Player* player,
           const std::string& descriptor)
    : dataArea(DataWorld::instance().area(descriptor)),
      player(player),
      colorOverlayARGB(0),
      beenFocused(false),
      redraw(true),
      descriptor(descriptor) {
    grid.dim = ivec3(0, 0, 0);
    grid.tileDim = ivec2(0, 0);
    grid.loopX = false;
    grid.loopY = false;
}

bool Area::init() {
    // Abstract method.
    return false;
}

void Area::focus() {
    if (!beenFocused) {
        beenFocused = true;
        if (dataArea) {
            dataArea->onLoad();
        }
    }

    if (musicPath) {
        Music::instance().play(*musicPath);
    }

    if (dataArea) {
        dataArea->onFocus();
    }
}

void Area::buttonDown(KeyboardKey key) {
    switch (key) {
    case KBLeftArrow:
        player->startMovement(ivec2(-1, 0));
        break;
    case KBRightArrow:
        player->startMovement(ivec2(1, 0));
        break;
    case KBUpArrow:
        player->startMovement(ivec2(0, -1));
        break;
    case KBDownArrow:
        player->startMovement(ivec2(0, 1));
        break;
    case KBSpace:
        player->useTile();
        break;
    default:
        break;
    }
}

void Area::buttonUp(KeyboardKey key) {
    switch (key) {
    case KBLeftArrow:
        player->stopMovement(ivec2(-1, 0));
        break;
    case KBRightArrow:
        player->stopMovement(ivec2(1, 0));
        break;
    case KBUpArrow:
        player->stopMovement(ivec2(0, -1));
        break;
    case KBDownArrow:
        player->stopMovement(ivec2(0, 1));
        break;
    default:
        break;
    }
}

void Area::draw(DisplayList* display) {
    icube tiles = visibleTiles();
    int maxZ = grid.dim.z;

    assert_(tiles.z1 == 0);
    assert_(tiles.z2 == maxZ);

    for (int z = 0; z < maxZ; z++) {
        drawTiles(display, tiles, z);
        drawEntities(display, tiles, z);
    }

    redraw = false;
}

bool Area::needsRedraw() const {
    if (redraw) {
        return true;
    }

    const icube tiles = visibleTiles();
    const icube pixels = {
        tiles.x1 * grid.tileDim.x,
        tiles.y1 * grid.tileDim.y,
        tiles.z1,
        tiles.x2 * grid.tileDim.x,
        tiles.y2 * grid.tileDim.y,
        tiles.z2,
    };

    if (player->needsRedraw(pixels)) {
        return true;
    }
    for (const auto& character : characters) {
        if (character->needsRedraw(pixels)) {
            return true;
        }
    }
    for (const auto& overlay : overlays) {
        if (overlay->needsRedraw(pixels)) {
            return true;
        }
    }

    // Do any on-screen tile types need to update their animations?
    BitRecord tileTypes(static_cast<size_t>(maxTileTypeId));

    for (int z = tiles.z1; z < tiles.z2; z++) {
        for (int y = tiles.y1; y < tiles.y2; y++) {
            for (int x = tiles.x1; x < tiles.x2; x++) {
                const Tile* tile = getTile(icoord(x, y, z));
                const TileType* type = tile->getType();
                if (!type) {
                    continue;
                }
                if (tileTypes[type->id]) {
                    continue;
                }
                tileTypes[type->id] = true;
                if (type->needsRedraw()) {
                    return true;
                }
            }
        }
    }
    return false;
}

void Area::requestRedraw() {
    redraw = true;
}

void Area::tick(time_t dt) {
    if (dataArea) {
        dataArea->tick(dt);
    }

    for (auto& overlay : overlays) {
        overlay->tick(dt);
    }
    erase_if(overlays, [] (const Rc<Overlay>& o) {
        bool dead = o->isDead();
        if (dead) {
            o->setArea(nullptr);
        }
        return dead;
    });

    if (conf.moveMode != TURN) {
        player->tick(dt);

        for (auto& character : characters) {
            character->tick(dt);
        }
        erase_if(characters, [] (const Rc<Character>& c) {
            bool dead = c->isDead();
            if (dead) {
                c->setArea(nullptr);
            }
            return dead;
        });
    }

    Viewport::instance().tick(dt);
}

void Area::turn() {
    if (dataArea) {
        dataArea->turn();
    }

    player->turn();

    for (auto& character : characters) {
        character->turn();
    }
    erase_if(characters, [] (const Rc<Character>& c) {
        bool dead = c->isDead();
        if (dead) {
            c->setArea(nullptr);
        }
        return dead;
    });

    Viewport::instance().turn();
}

uint32_t Area::getColorOverlay() {
    return colorOverlayARGB;
}

void Area::setColorOverlay(uint8_t a, uint8_t r, uint8_t g, uint8_t b) {
    colorOverlayARGB = (uint32_t)(a << 24) + (uint32_t)(r << 16) +
        (uint32_t)(g << 8) + (uint32_t)b;
    redraw = true;
}

const Tile* Area::getTile(icoord phys) const {
    return grid.getTile(phys);
}

const Tile* Area::getTile(vicoord virt) const {
    return grid.getTile(virt);
}

const Tile* Area::getTile(rcoord virt) const {
    return grid.getTile(virt);
}

Tile* Area::getTile(icoord phys) {
    return grid.getTile(phys);
}

Tile* Area::getTile(vicoord virt) {
    return grid.getTile(virt);
}

Tile* Area::getTile(rcoord virt) {
    return grid.getTile(virt);
}

TileSet* Area::getTileSet(const std::string& imagePath) {
    std::unordered_map<std::string, TileSet>::iterator it;
    it = tileSets.find(imagePath);
    if (it == tileSets.end()) {
        Log::err("Area", "tileset " + imagePath + " not found");
        return nullptr;
    }
    return &tileSets[imagePath];
}

ivec3 Area::getDimensions() const {
    return grid.dim;
}

ivec2 Area::getTileDimensions() const {
    return grid.tileDim;
}

icube Area::visibleTiles() const {
    Viewport& viewport = Viewport::instance();

    rvec2 screen = viewport.getVirtRes();
    rvec2 off = viewport.getMapOffset();

    int x1 = static_cast<int>(floor(off.x / grid.tileDim.x));
    int y1 = static_cast<int>(floor(off.y / grid.tileDim.y));
    int x2 = static_cast<int>(ceil((screen.x + off.x) / grid.tileDim.x));
    int y2 = static_cast<int>(ceil((screen.y + off.y) / grid.tileDim.y));

    if (!grid.loopX) {
        x1 = bound(x1, 0, grid.dim.x);
        x2 = bound(x2, 0, grid.dim.x);
    }
    if (!grid.loopY) {
        y1 = bound(y1, 0, grid.dim.y);
        y2 = bound(y2, 0, grid.dim.y);
    }

    return icube{x1, y1, 0, x2, y2, grid.dim.z};
}

bool Area::inBounds(icoord phys) const {
    return grid.inBounds(phys);
}

bool Area::inBounds(vicoord virt) const {
    return grid.inBounds(virt);
}

bool Area::inBounds(rcoord virt) const {
    return grid.inBounds(virt);
}

bool Area::inBounds(Entity* ent) const {
    return inBounds(ent->getPixelCoord());
}

bool Area::loopsInX() const {
    return grid.loopX;
}

bool Area::loopsInY() const {
    return grid.loopY;
}

const std::string Area::getDescriptor() const {
    return descriptor;
}

Rc<NPC> Area::spawnNPC(const std::string& descriptor,
                       vicoord coord,
                       const std::string& phase) {
    auto c = Rc<NPC>(new NPC);
    if (!c->init(descriptor, phase)) {
        // Error logged.
        return Rc<NPC>();
    }
    c->setArea(this);
    c->setTileCoords(coord);
    characters.insert(c);
    return c;
}

Rc<Overlay> Area::spawnOverlay(const std::string& descriptor,
                               vicoord coord,
                               const std::string& phase) {
    auto o = Rc<Overlay>(new Overlay);
    if (!o->init(descriptor, phase)) {
        // Error logged.
        return Rc<Overlay>();
    }
    o->setArea(this);
    o->teleport(coord);
    overlays.insert(o);
    return o;
}

vicoord Area::phys2virt_vi(icoord phys) const {
    return grid.phys2virt_vi(phys);
}

rcoord Area::phys2virt_r(icoord phys) const {
    return grid.phys2virt_r(phys);
}

icoord Area::virt2phys(vicoord virt) const {
    return grid.virt2phys(virt);
}

icoord Area::virt2phys(rcoord virt) const {
    return grid.virt2phys(virt);
}

rcoord Area::virt2virt(vicoord virt) const {
    return grid.virt2virt(virt);
}

vicoord Area::virt2virt(rcoord virt) const {
    return grid.virt2virt(virt);
}

DataArea* Area::getDataArea() {
    return dataArea;
}

static void drawTile(DisplayList* display, const TileType* type,
                     int x, int y, double depth, int tileDimY) {
    Image* img = type->anim.frame();
    if (img) {
        rvec2 drawPos(
                double(x * (int)img->width()),
                double(y * (int)img->height())
        );
        //drawPos.z = depth + drawPos.y / tileDimY * ISOMETRIC_ZOFF_PER_TILE;
        display->items.push_back(DisplayItem{img, drawPos});
    }
}

void Area::drawTiles(DisplayList* display, const icube& tiles, int z) {
    time_t now = World::instance().time();
    BitRecord tilesAnimated(static_cast<size_t>(maxTileTypeId));
    double depth = grid.idx2depth[(size_t)z];

    for (int y = tiles.y1; y < tiles.y2; y++) {
        for (int x = tiles.x1; x < tiles.x2; x++) {
            Tile* tile = getTile(icoord(x, y, z));
            // We are certain the Tile exists.
            TileType* type = tile->getType();
            if (!type) {
                continue;
            }
            if (!tilesAnimated[type->id]) {
                type->anim.frame(now);
            }
            drawTile(display, type, x, y, depth, grid.tileDim.y);
        }
    }
}

void Area::drawEntities(DisplayList* display, const icube& tiles, int z) {
    double depth = grid.idx2depth[(size_t)z];

    for (auto& character : characters) {
        if (character->getTileCoords_i().z == z) {
            character->draw(display);
        }
    }

    for (auto& overlay : overlays) {
        if (overlay->getPixelCoord().z == depth) {
            overlay->draw(display);
        }
    }

    if (player->getTileCoords_i().z == z) {
        player->draw(display);
    }
}
<commit_msg>Area: Remove header<commit_after>/***************************************
** Tsunagari Tile Engine              **
** area.cpp                           **
** Copyright 2011-2015 Michael Reiley **
** Copyright 2011-2018 Paul Merrill   **
***************************************/

// **********
// 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.
// **********

#include "core/area.h"

#include <math.h>

#include "core/algorithm.h"
#include "core/client-conf.h"
#include "core/display-list.h"
#include "core/entity.h"
#include "core/formatter.h"
#include "core/log.h"
#include "core/images.h"
#include "core/music.h"
#include "core/npc.h"
#include "core/overlay.h"
#include "core/player.h"
#include "core/tile.h"
#include "core/viewport.h"
#include "core/window.h"
#include "core/world.h"
#include "util/assert.h"
#include "util/math2.h"

#include "data/data-world.h"

#define CHECK(x)  if (!(x)) { return false; }

/* NOTE: In the TMX map format used by Tiled, tileset tiles start counting
         their Y-positions from 0, while layer tiles start counting from 1. I
         can't imagine why the author did this, but we have to take it into
         account.
*/

Area::Area(Player* player,
           const std::string& descriptor)
    : dataArea(DataWorld::instance().area(descriptor)),
      player(player),
      colorOverlayARGB(0),
      beenFocused(false),
      redraw(true),
      descriptor(descriptor) {
    grid.dim = ivec3(0, 0, 0);
    grid.tileDim = ivec2(0, 0);
    grid.loopX = false;
    grid.loopY = false;
}

bool Area::init() {
    // Abstract method.
    return false;
}

void Area::focus() {
    if (!beenFocused) {
        beenFocused = true;
        if (dataArea) {
            dataArea->onLoad();
        }
    }

    if (musicPath) {
        Music::instance().play(*musicPath);
    }

    if (dataArea) {
        dataArea->onFocus();
    }
}

void Area::buttonDown(KeyboardKey key) {
    switch (key) {
    case KBLeftArrow:
        player->startMovement(ivec2(-1, 0));
        break;
    case KBRightArrow:
        player->startMovement(ivec2(1, 0));
        break;
    case KBUpArrow:
        player->startMovement(ivec2(0, -1));
        break;
    case KBDownArrow:
        player->startMovement(ivec2(0, 1));
        break;
    case KBSpace:
        player->useTile();
        break;
    default:
        break;
    }
}

void Area::buttonUp(KeyboardKey key) {
    switch (key) {
    case KBLeftArrow:
        player->stopMovement(ivec2(-1, 0));
        break;
    case KBRightArrow:
        player->stopMovement(ivec2(1, 0));
        break;
    case KBUpArrow:
        player->stopMovement(ivec2(0, -1));
        break;
    case KBDownArrow:
        player->stopMovement(ivec2(0, 1));
        break;
    default:
        break;
    }
}

void Area::draw(DisplayList* display) {
    icube tiles = visibleTiles();
    int maxZ = grid.dim.z;

    assert_(tiles.z1 == 0);
    assert_(tiles.z2 == maxZ);

    for (int z = 0; z < maxZ; z++) {
        drawTiles(display, tiles, z);
        drawEntities(display, tiles, z);
    }

    redraw = false;
}

bool Area::needsRedraw() const {
    if (redraw) {
        return true;
    }

    const icube tiles = visibleTiles();
    const icube pixels = {
        tiles.x1 * grid.tileDim.x,
        tiles.y1 * grid.tileDim.y,
        tiles.z1,
        tiles.x2 * grid.tileDim.x,
        tiles.y2 * grid.tileDim.y,
        tiles.z2,
    };

    if (player->needsRedraw(pixels)) {
        return true;
    }
    for (const auto& character : characters) {
        if (character->needsRedraw(pixels)) {
            return true;
        }
    }
    for (const auto& overlay : overlays) {
        if (overlay->needsRedraw(pixels)) {
            return true;
        }
    }

    // Do any on-screen tile types need to update their animations?
    BitRecord tileTypes(static_cast<size_t>(maxTileTypeId));

    for (int z = tiles.z1; z < tiles.z2; z++) {
        for (int y = tiles.y1; y < tiles.y2; y++) {
            for (int x = tiles.x1; x < tiles.x2; x++) {
                const Tile* tile = getTile(icoord(x, y, z));
                const TileType* type = tile->getType();
                if (!type) {
                    continue;
                }
                if (tileTypes[type->id]) {
                    continue;
                }
                tileTypes[type->id] = true;
                if (type->needsRedraw()) {
                    return true;
                }
            }
        }
    }
    return false;
}

void Area::requestRedraw() {
    redraw = true;
}

void Area::tick(time_t dt) {
    if (dataArea) {
        dataArea->tick(dt);
    }

    for (auto& overlay : overlays) {
        overlay->tick(dt);
    }
    erase_if(overlays, [] (const Rc<Overlay>& o) {
        bool dead = o->isDead();
        if (dead) {
            o->setArea(nullptr);
        }
        return dead;
    });

    if (conf.moveMode != TURN) {
        player->tick(dt);

        for (auto& character : characters) {
            character->tick(dt);
        }
        erase_if(characters, [] (const Rc<Character>& c) {
            bool dead = c->isDead();
            if (dead) {
                c->setArea(nullptr);
            }
            return dead;
        });
    }

    Viewport::instance().tick(dt);
}

void Area::turn() {
    if (dataArea) {
        dataArea->turn();
    }

    player->turn();

    for (auto& character : characters) {
        character->turn();
    }
    erase_if(characters, [] (const Rc<Character>& c) {
        bool dead = c->isDead();
        if (dead) {
            c->setArea(nullptr);
        }
        return dead;
    });

    Viewport::instance().turn();
}

uint32_t Area::getColorOverlay() {
    return colorOverlayARGB;
}

void Area::setColorOverlay(uint8_t a, uint8_t r, uint8_t g, uint8_t b) {
    colorOverlayARGB = (uint32_t)(a << 24) + (uint32_t)(r << 16) +
        (uint32_t)(g << 8) + (uint32_t)b;
    redraw = true;
}

const Tile* Area::getTile(icoord phys) const {
    return grid.getTile(phys);
}

const Tile* Area::getTile(vicoord virt) const {
    return grid.getTile(virt);
}

const Tile* Area::getTile(rcoord virt) const {
    return grid.getTile(virt);
}

Tile* Area::getTile(icoord phys) {
    return grid.getTile(phys);
}

Tile* Area::getTile(vicoord virt) {
    return grid.getTile(virt);
}

Tile* Area::getTile(rcoord virt) {
    return grid.getTile(virt);
}

TileSet* Area::getTileSet(const std::string& imagePath) {
    std::unordered_map<std::string, TileSet>::iterator it;
    it = tileSets.find(imagePath);
    if (it == tileSets.end()) {
        Log::err("Area", "tileset " + imagePath + " not found");
        return nullptr;
    }
    return &tileSets[imagePath];
}

ivec3 Area::getDimensions() const {
    return grid.dim;
}

ivec2 Area::getTileDimensions() const {
    return grid.tileDim;
}

icube Area::visibleTiles() const {
    Viewport& viewport = Viewport::instance();

    rvec2 screen = viewport.getVirtRes();
    rvec2 off = viewport.getMapOffset();

    int x1 = static_cast<int>(floor(off.x / grid.tileDim.x));
    int y1 = static_cast<int>(floor(off.y / grid.tileDim.y));
    int x2 = static_cast<int>(ceil((screen.x + off.x) / grid.tileDim.x));
    int y2 = static_cast<int>(ceil((screen.y + off.y) / grid.tileDim.y));

    if (!grid.loopX) {
        x1 = bound(x1, 0, grid.dim.x);
        x2 = bound(x2, 0, grid.dim.x);
    }
    if (!grid.loopY) {
        y1 = bound(y1, 0, grid.dim.y);
        y2 = bound(y2, 0, grid.dim.y);
    }

    return icube{x1, y1, 0, x2, y2, grid.dim.z};
}

bool Area::inBounds(icoord phys) const {
    return grid.inBounds(phys);
}

bool Area::inBounds(vicoord virt) const {
    return grid.inBounds(virt);
}

bool Area::inBounds(rcoord virt) const {
    return grid.inBounds(virt);
}

bool Area::inBounds(Entity* ent) const {
    return inBounds(ent->getPixelCoord());
}

bool Area::loopsInX() const {
    return grid.loopX;
}

bool Area::loopsInY() const {
    return grid.loopY;
}

const std::string Area::getDescriptor() const {
    return descriptor;
}

Rc<NPC> Area::spawnNPC(const std::string& descriptor,
                       vicoord coord,
                       const std::string& phase) {
    auto c = Rc<NPC>(new NPC);
    if (!c->init(descriptor, phase)) {
        // Error logged.
        return Rc<NPC>();
    }
    c->setArea(this);
    c->setTileCoords(coord);
    characters.insert(c);
    return c;
}

Rc<Overlay> Area::spawnOverlay(const std::string& descriptor,
                               vicoord coord,
                               const std::string& phase) {
    auto o = Rc<Overlay>(new Overlay);
    if (!o->init(descriptor, phase)) {
        // Error logged.
        return Rc<Overlay>();
    }
    o->setArea(this);
    o->teleport(coord);
    overlays.insert(o);
    return o;
}

vicoord Area::phys2virt_vi(icoord phys) const {
    return grid.phys2virt_vi(phys);
}

rcoord Area::phys2virt_r(icoord phys) const {
    return grid.phys2virt_r(phys);
}

icoord Area::virt2phys(vicoord virt) const {
    return grid.virt2phys(virt);
}

icoord Area::virt2phys(rcoord virt) const {
    return grid.virt2phys(virt);
}

rcoord Area::virt2virt(vicoord virt) const {
    return grid.virt2virt(virt);
}

vicoord Area::virt2virt(rcoord virt) const {
    return grid.virt2virt(virt);
}

DataArea* Area::getDataArea() {
    return dataArea;
}

static void drawTile(DisplayList* display, const TileType* type,
                     int x, int y, double depth, int tileDimY) {
    Image* img = type->anim.frame();
    if (img) {
        rvec2 drawPos(
                double(x * (int)img->width()),
                double(y * (int)img->height())
        );
        //drawPos.z = depth + drawPos.y / tileDimY * ISOMETRIC_ZOFF_PER_TILE;
        display->items.push_back(DisplayItem{img, drawPos});
    }
}

void Area::drawTiles(DisplayList* display, const icube& tiles, int z) {
    time_t now = World::instance().time();
    BitRecord tilesAnimated(static_cast<size_t>(maxTileTypeId));
    double depth = grid.idx2depth[(size_t)z];

    for (int y = tiles.y1; y < tiles.y2; y++) {
        for (int x = tiles.x1; x < tiles.x2; x++) {
            Tile* tile = getTile(icoord(x, y, z));
            // We are certain the Tile exists.
            TileType* type = tile->getType();
            if (!type) {
                continue;
            }
            if (!tilesAnimated[type->id]) {
                type->anim.frame(now);
            }
            drawTile(display, type, x, y, depth, grid.tileDim.y);
        }
    }
}

void Area::drawEntities(DisplayList* display, const icube& tiles, int z) {
    double depth = grid.idx2depth[(size_t)z];

    for (auto& character : characters) {
        if (character->getTileCoords_i().z == z) {
            character->draw(display);
        }
    }

    for (auto& overlay : overlays) {
        if (overlay->getPixelCoord().z == depth) {
            overlay->draw(display);
        }
    }

    if (player->getTileCoords_i().z == z) {
        player->draw(display);
    }
}
<|endoftext|>