<commit_before>// Copyright (c) 2011-2017 The Bitcoin developers
// Copyright (c) 2015-2021 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "qt/rpcexecutor.h"

#include "rpc/client.h"

#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
#endif

#include <QUrlQuery>

#include <univalue.h>

QString RPCExecutor::categoryClass(int category)
{
    switch (category) {
    case CMD_REQUEST:
        return "cmd-request";
        break;
    case CMD_REPLY:
        return "cmd-reply";
        break;
    case CMD_ERROR:
        return "cmd-error";
        break;
    default:
        return "misc";
    }
}

void RPCExecutor::request(const QString& command)
{
    try
    {
        std::string result;
        std::string executableCommand = command.toStdString() + "\n";

        // Catch the console-only-help command before RPC call is executed and reply with help text as-if a RPC reply.
        if(executableCommand == "help-console\n")
        {
            Q_EMIT reply(CMD_REPLY, QString(("\n"
                "This console accepts RPC commands using the standard syntax.\n"
                "   example:    getblockhash 0\n\n"

                "This console can also accept RPC commands using parenthesized syntax.\n"
                "   example:    getblockhash(0)\n\n"

                "Commands may be nested when specified with the parenthesized syntax.\n"
                "   example:    getblock(getblockhash(0) true)\n\n"

                "A space or a comma can be used to delimit arguments for either syntax.\n"
                "   example:    getblockhash 0\n"
                "               getblockhash,0\n\n"

                "Named results can be queried with a non-quoted key string in brackets.\n"
                "   example:    getblock(getblockhash(0) true)[tx]\n\n"

                "Results without keys can be queried using an integer in brackets.\n"
                "   example:    getblock(getblockhash(0),true)[tx][0]\n\n")));
            return;
        }
        if(!ExecuteCommandLine(result, executableCommand))
        {
            Q_EMIT reply(CMD_ERROR, QString("Parse error: unbalanced ' or \""));
            return;
        }
        Q_EMIT reply(CMD_REPLY, QString::fromStdString(result));
    }
    catch (UniValue& objError)
    {
        try {
            // Nice formatting for standard-format error
            int code = find_value(objError, "code").get_int();
            std::string message = find_value(objError, "message").get_str();
            Q_EMIT reply(CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")");

        } catch (const std::runtime_error&) {
            // raised when converting to invalid type, i.e. missing code or message
            // Show raw JSON object
            Q_EMIT reply(CMD_ERROR, QString::fromStdString(objError.write()));
        }
    } catch (const std::exception& e) {
        Q_EMIT reply(CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
    }
}

/**
 * Split shell command line into a list of arguments and execute the command(s).
 * Aims to emulate \c bash and friends.
 *
 * - Command nesting is possible with brackets [example: validateaddress(getnewaddress())]
 * - Arguments are delimited with whitespace or comma
 * - Extra whitespace at the beginning and end and between arguments will be ignored
 * - Text can be "double" or 'single' quoted
 * - The backslash \c \ is used as escape character
 *   - Outside quotes, any character can be escaped
 *   - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
 *   - Within single quotes, no escaping is possible and no special interpretation takes place
 *
 * @param[out]   result      stringified Result from the executed command(chain)
 * @param[in]    strCommand  Command line to split
 */
bool RPCExecutor::ExecuteCommandLine(std::string& strResult, const std::string& strCommand)
{
    std::vector< std::vector<std::string> > stack;
    stack.push_back(std::vector<std::string>());

    enum CmdParseState
    {
        STATE_EATING_SPACES,
        STATE_ARGUMENT,
        STATE_SINGLEQUOTED,
        STATE_DOUBLEQUOTED,
        STATE_ESCAPE_OUTER,
        STATE_ESCAPE_DOUBLEQUOTED,
        STATE_COMMAND_EXECUTED,
        STATE_COMMAND_EXECUTED_INNER
    } state = STATE_EATING_SPACES;
    std::string curarg;
    UniValue lastResult;

    std::string strCommandTerminated = strCommand;
    if (strCommandTerminated.back() != '\n')
        strCommandTerminated += "\n";
    for(char ch: strCommandTerminated)
    {
        switch(state)
        {
            case STATE_COMMAND_EXECUTED_INNER:
            case STATE_COMMAND_EXECUTED:
            {
                bool breakParsing = true;
                switch(ch)
                {
                    case '[': curarg.clear(); state = STATE_COMMAND_EXECUTED_INNER; break;
                    default:
                        if (state == STATE_COMMAND_EXECUTED_INNER)
                        {
                            if (ch != ']')
                            {
                                // append char to the current argument (which is also used for the query command)
                                curarg += ch;
                                break;
                            }
                            if (curarg.size())
                            {
                                // if we have a value query, query arrays with index and objects with a string key
                                UniValue subelement;
                                if (lastResult.isArray())
                                {
                                    for(char argch: curarg)
                                        if (!std::isdigit(argch))
                                            throw std::runtime_error("Invalid result query");
                                    subelement = lastResult[atoi(curarg.c_str())];
                                }
                                else if (lastResult.isObject())
                                    subelement = find_value(lastResult, curarg);
                                else
                                    throw std::runtime_error("Invalid result query"); //no array or object: abort
                                lastResult = subelement;
                            }

                            state = STATE_COMMAND_EXECUTED;
                            break;
                        }
                        // don't break parsing when the char is required for the next argument
                        breakParsing = false;

                        // pop the stack and return the result to the current command arguments
                        stack.pop_back();

                        // don't stringify the json in case of a string to avoid doublequotes
                        if (lastResult.isStr())
                            curarg = lastResult.get_str();
                        else
                            curarg = lastResult.write(2);

                        // if we have a non empty result, use it as stack argument otherwise as general result
                        if (curarg.size())
                        {
                            if (stack.size())
                                stack.back().push_back(curarg);
                            else
                                strResult = curarg;
                        }
                        curarg.clear();
                        // assume eating space state
                        state = STATE_EATING_SPACES;
                }
                if (breakParsing)
                    break;
            }
            case STATE_ARGUMENT: // In or after argument
            case STATE_EATING_SPACES: // Handle runs of whitespace
                switch(ch)
            {
                case '"': state = STATE_DOUBLEQUOTED; break;
                case '\'': state = STATE_SINGLEQUOTED; break;
                case '\\': state = STATE_ESCAPE_OUTER; break;
                case '(': case ')': case '\n':
                    if (state == STATE_ARGUMENT)
                    {
                        if (ch == '(' && stack.size() && stack.back().size() > 0)
                            stack.push_back(std::vector<std::string>());
                        if (curarg.size())
                        {
                            // don't allow commands after executed commands on baselevel
                            if (!stack.size())
                                throw std::runtime_error("Invalid Syntax");
                            stack.back().push_back(curarg);
                        }
                        curarg.clear();
                        state = STATE_EATING_SPACES;
                    }
                    if ((ch == ')' || ch == '\n') && stack.size() > 0)
                    {
                        std::string strPrint;
                        // Convert argument list to JSON objects in method-dependent way,
                        // and pass it along with the method name to the dispatcher.
                        JSONRPCRequest req;
                        req.params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
                        req.strMethod = stack.back()[0];
#ifdef ENABLE_WALLET
                        // TODO: Move this logic to WalletModel
                        if (!vpwallets.empty()) {
                            // in Qt, use always the wallet with index 0 when running with multiple wallets
                            QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(vpwallets[0]->GetName()));
                            req.URI = "/wallet/"+std::string(encodedName.constData(), encodedName.length());
                        }
#endif
                        lastResult = tableRPC.execute(req);
                        state = STATE_COMMAND_EXECUTED;
                        curarg.clear();
                    }
                    break;
                case ' ': case ',': case '\t':
                    if(state == STATE_ARGUMENT) // Space ends argument
                    {
                        if (curarg.size())
                            stack.back().push_back(curarg);
                        curarg.clear();
                    }
                    state = STATE_EATING_SPACES;
                    break;
                default: curarg += ch; state = STATE_ARGUMENT;
            }
                break;
            case STATE_SINGLEQUOTED: // Single-quoted string
                switch(ch)
            {
                case '\'': state = STATE_ARGUMENT; break;
                default: curarg += ch;
            }
                break;
            case STATE_DOUBLEQUOTED: // Double-quoted string
                switch(ch)
            {
                case '"': state = STATE_ARGUMENT; break;
                case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
                default: curarg += ch;
            }
                break;
            case STATE_ESCAPE_OUTER: // '\' outside quotes
                curarg += ch; state = STATE_ARGUMENT;
                break;
            case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
                if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
                curarg += ch; state = STATE_DOUBLEQUOTED;
                break;
        }
    }
    switch (state) // final state
    {
        case STATE_COMMAND_EXECUTED:
            if (lastResult.isStr())
                strResult = lastResult.get_str();
            else
                strResult = lastResult.write(2);
        case STATE_ARGUMENT:
        case STATE_EATING_SPACES:
            return true;
        default: // ERROR to end in one of the other states
            return false;
    }
}
<commit_msg>[Qt] Console: allow empty arguments<commit_after>// Copyright (c) 2011-2017 The Bitcoin developers
// Copyright (c) 2015-2021 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "qt/rpcexecutor.h"

#include "rpc/client.h"

#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
#endif

#include <QUrlQuery>

#include <univalue.h>

QString RPCExecutor::categoryClass(int category)
{
    switch (category) {
    case CMD_REQUEST:
        return "cmd-request";
        break;
    case CMD_REPLY:
        return "cmd-reply";
        break;
    case CMD_ERROR:
        return "cmd-error";
        break;
    default:
        return "misc";
    }
}

void RPCExecutor::request(const QString& command)
{
    try
    {
        std::string result;
        std::string executableCommand = command.toStdString() + "\n";

        // Catch the console-only-help command before RPC call is executed and reply with help text as-if a RPC reply.
        if(executableCommand == "help-console\n")
        {
            Q_EMIT reply(CMD_REPLY, QString(("\n"
                "This console accepts RPC commands using the standard syntax.\n"
                "   example:    getblockhash 0\n\n"

                "This console can also accept RPC commands using parenthesized syntax.\n"
                "   example:    getblockhash(0)\n\n"

                "Commands may be nested when specified with the parenthesized syntax.\n"
                "   example:    getblock(getblockhash(0) true)\n\n"

                "A space or a comma can be used to delimit arguments for either syntax.\n"
                "   example:    getblockhash 0\n"
                "               getblockhash,0\n\n"

                "Named results can be queried with a non-quoted key string in brackets.\n"
                "   example:    getblock(getblockhash(0) true)[tx]\n\n"

                "Results without keys can be queried using an integer in brackets.\n"
                "   example:    getblock(getblockhash(0),true)[tx][0]\n\n")));
            return;
        }
        if(!ExecuteCommandLine(result, executableCommand))
        {
            Q_EMIT reply(CMD_ERROR, QString("Parse error: unbalanced ' or \""));
            return;
        }
        Q_EMIT reply(CMD_REPLY, QString::fromStdString(result));
    }
    catch (UniValue& objError)
    {
        try {
            // Nice formatting for standard-format error
            int code = find_value(objError, "code").get_int();
            std::string message = find_value(objError, "message").get_str();
            Q_EMIT reply(CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")");

        } catch (const std::runtime_error&) {
            // raised when converting to invalid type, i.e. missing code or message
            // Show raw JSON object
            Q_EMIT reply(CMD_ERROR, QString::fromStdString(objError.write()));
        }
    } catch (const std::exception& e) {
        Q_EMIT reply(CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
    }
}

/**
 * Split shell command line into a list of arguments and execute the command(s).
 * Aims to emulate \c bash and friends.
 *
 * - Command nesting is possible with brackets [example: validateaddress(getnewaddress())]
 * - Arguments are delimited with whitespace or comma
 * - Extra whitespace at the beginning and end and between arguments will be ignored
 * - Text can be "double" or 'single' quoted
 * - The backslash \c \ is used as escape character
 *   - Outside quotes, any character can be escaped
 *   - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
 *   - Within single quotes, no escaping is possible and no special interpretation takes place
 *
 * @param[out]   result      stringified Result from the executed command(chain)
 * @param[in]    strCommand  Command line to split
 */
bool RPCExecutor::ExecuteCommandLine(std::string& strResult, const std::string& strCommand)
{
    std::vector< std::vector<std::string> > stack;
    stack.push_back(std::vector<std::string>());

    enum CmdParseState
    {
        STATE_EATING_SPACES,
        STATE_EATING_SPACES_IN_ARG,
        STATE_ARGUMENT,
        STATE_SINGLEQUOTED,
        STATE_DOUBLEQUOTED,
        STATE_ESCAPE_OUTER,
        STATE_ESCAPE_DOUBLEQUOTED,
        STATE_COMMAND_EXECUTED,
        STATE_COMMAND_EXECUTED_INNER
    } state = STATE_EATING_SPACES;
    std::string curarg;
    UniValue lastResult;

    std::string strCommandTerminated = strCommand;
    if (strCommandTerminated.back() != '\n')
        strCommandTerminated += "\n";
    for(char ch: strCommandTerminated)
    {
        switch(state)
        {
            case STATE_COMMAND_EXECUTED_INNER:
            case STATE_COMMAND_EXECUTED:
            {
                bool breakParsing = true;
                switch(ch)
                {
                    case '[': curarg.clear(); state = STATE_COMMAND_EXECUTED_INNER; break;
                    default:
                        if (state == STATE_COMMAND_EXECUTED_INNER)
                        {
                            if (ch != ']')
                            {
                                // append char to the current argument (which is also used for the query command)
                                curarg += ch;
                                break;
                            }
                            if (curarg.size())
                            {
                                // if we have a value query, query arrays with index and objects with a string key
                                UniValue subelement;
                                if (lastResult.isArray())
                                {
                                    for(char argch: curarg)
                                        if (!std::isdigit(argch))
                                            throw std::runtime_error("Invalid result query");
                                    subelement = lastResult[atoi(curarg.c_str())];
                                }
                                else if (lastResult.isObject())
                                    subelement = find_value(lastResult, curarg);
                                else
                                    throw std::runtime_error("Invalid result query"); //no array or object: abort
                                lastResult = subelement;
                            }

                            state = STATE_COMMAND_EXECUTED;
                            break;
                        }
                        // don't break parsing when the char is required for the next argument
                        breakParsing = false;

                        // pop the stack and return the result to the current command arguments
                        stack.pop_back();

                        // don't stringify the json in case of a string to avoid doublequotes
                        if (lastResult.isStr())
                            curarg = lastResult.get_str();
                        else
                            curarg = lastResult.write(2);

                        // if we have a non empty result, use it as stack argument otherwise as general result
                        if (curarg.size())
                        {
                            if (stack.size())
                                stack.back().push_back(curarg);
                            else
                                strResult = curarg;
                        }
                        curarg.clear();
                        // assume eating space state
                        state = STATE_EATING_SPACES;
                }
                if (breakParsing)
                    break;
            }
            case STATE_ARGUMENT: // In or after argument
            case STATE_EATING_SPACES_IN_ARG:
            case STATE_EATING_SPACES: // Handle runs of whitespace
                switch(ch)
            {
                case '"': state = STATE_DOUBLEQUOTED; break;
                case '\'': state = STATE_SINGLEQUOTED; break;
                case '\\': state = STATE_ESCAPE_OUTER; break;
                case '(': case ')': case '\n':
                    if (state == STATE_ARGUMENT)
                    {
                        if (ch == '(' && stack.size() && stack.back().size() > 0)
                            stack.push_back(std::vector<std::string>());

                        // don't allow commands after executed commands on baselevel
                        if (!stack.size())
                            throw std::runtime_error("Invalid Syntax");

                        stack.back().push_back(curarg);
                        curarg.clear();
                        state = STATE_EATING_SPACES;
                    }
                    if ((ch == ')' || ch == '\n') && stack.size() > 0)
                    {
                        std::string strPrint;
                        // Convert argument list to JSON objects in method-dependent way,
                        // and pass it along with the method name to the dispatcher.
                        JSONRPCRequest req;
                        req.params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
                        req.strMethod = stack.back()[0];
#ifdef ENABLE_WALLET
                        // TODO: Move this logic to WalletModel
                        if (!vpwallets.empty()) {
                            // in Qt, use always the wallet with index 0 when running with multiple wallets
                            QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(vpwallets[0]->GetName()));
                            req.URI = "/wallet/"+std::string(encodedName.constData(), encodedName.length());
                        }
#endif
                        lastResult = tableRPC.execute(req);
                        state = STATE_COMMAND_EXECUTED;
                        curarg.clear();
                    }
                    break;
                case ' ': case ',': case '\t':
                    if(state == STATE_ARGUMENT || (state == STATE_EATING_SPACES_IN_ARG && ch == ',')) // Space ends argument
                    {
                        stack.back().push_back(curarg);
                        curarg.clear();
                    }
                    state = (ch == ',' ? STATE_EATING_SPACES_IN_ARG : STATE_EATING_SPACES);
                    break;
                default: curarg += ch; state = STATE_ARGUMENT;
            }
                break;
            case STATE_SINGLEQUOTED: // Single-quoted string
                switch(ch)
            {
                case '\'': state = STATE_ARGUMENT; break;
                default: curarg += ch;
            }
                break;
            case STATE_DOUBLEQUOTED: // Double-quoted string
                switch(ch)
            {
                case '"': state = STATE_ARGUMENT; break;
                case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
                default: curarg += ch;
            }
                break;
            case STATE_ESCAPE_OUTER: // '\' outside quotes
                curarg += ch; state = STATE_ARGUMENT;
                break;
            case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
                if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
                curarg += ch; state = STATE_DOUBLEQUOTED;
                break;
        }
    }
    switch (state) // final state
    {
        case STATE_COMMAND_EXECUTED:
            if (lastResult.isStr())
                strResult = lastResult.get_str();
            else
                strResult = lastResult.write(2);
        case STATE_ARGUMENT:
        case STATE_EATING_SPACES:
            return true;
        default: // ERROR to end in one of the other states
            return false;
    }
}
<|endoftext|>


<commit_before><commit_msg>Recognize ExplicitSystem when reading in<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2017 Lanceolata

#include "log2kafka/produce.h"
#include "log2kafka/topic_conf.h"
#include "log2kafka/offset_table.h"
#include "log2kafka/errmsg_handle.h"
#include "kafka/kafka_producer.h"
#include "kafka/kafka_topic_producer.h"
#include "util/string_utils.h"
#include "util/system_utils.h"
#include "easylogging++.h"

namespace log2hdfs {

std::unique_ptr<Produce> Produce::Init(
    std::shared_ptr<KafkaProducer> producer,
    std::shared_ptr<Queue<std::string>> queue,
    std::shared_ptr<OffsetTable> table,
    std::shared_ptr<ErrmsgHandle> handle) {
  if (!producer || !queue || !table || !handle) {
    LOG(ERROR) << "Produce Init invalid parameters";
    return nullptr;
  }
  return std::unique_ptr<Produce>(new Produce(
             std::move(producer), std::move(queue),
             std::move(table), std::move(handle)));
}

bool Produce::AddTopic(std::shared_ptr<TopicConf> conf) {
  if (!conf) {
    LOG(WARNING) << "Produce AddTopic invalid parameters";
    return false;
  }

  std::unique_ptr<KafkaTopicConf> topic_conf = conf->kafka_topic_conf();
  const std::string topic = conf->topic();

  std::string errstr;
  std::shared_ptr<KafkaTopicProducer> ktp = producer_->CreateTopicProducer(
      topic, topic_conf.get(), &errstr);
  if (!ktp) {
    LOG(WARNING) << "Produce AddTopic CreateTopicProducer topic[" << topic
                 << "] failed with errstr[" << errstr << "]";
    return false;
  }

  std::lock_guard<std::mutex> guard(mutex_);
  auto it = topic_confs_.find(topic);
  if (it != topic_confs_.end()) {
    LOG(WARNING) << "Produce AddTopic topic[" << topic
                 << "] already add";
    return false;
  }

  LOG(INFO) << "Produce AddTopic topic[" << topic << "] success";
  topic_confs_[topic] = std::move(conf);
  return true;
}

bool Produce::RemoveTopic(const std::string& topic) {
  if (topic.empty()) {
    LOG(WARNING) << "Produce RemoveTopic invalid parameters";
    return false;
  }

  std::lock_guard<std::mutex> guard(mutex_);
  if (topic_confs_.erase(topic) == 1) {
    LOG(INFO) << "Produce RemoveTopic topic_confs_ erase topic[" << topic
              << "] success";
  } else {
    LOG(WARNING) << "Produce RemoveTopic topic_confs_ erase topic[" << topic
                 << "] failed";
    return false;
  }

  if (producer_->RemoveTopicProducer(topic)) {
    LOG(INFO) << "Produce RemoveTopic RemoveTopicProducer topic[" << topic
              << "] success";
  } else {
    LOG(WARNING) << "Produce RemoveTopic RemoveTopicProducer topic["
                 << topic << "] failed";
    return false;
  }
  return true;
}

void Produce::StartInternal() {
  LOG(INFO) << "Log2kafkaProduce thread created";

  while (running_.load()) {
    std::shared_ptr<std::string> record = queue_->WaitPop();
    if (!record) {
      LOG(WARNING) << "Produce StartInternal WaitPop nullptr";
      continue;
    }

    // check record
    std::vector<std::string> vec = SplitString(*record, ":",
        kTrimWhitespace, kSplitNonempty);
    if (vec.size() < 3) {
      LOG(WARNING) << "Produce StartInternal invalid record[" << *record<< "]";
      continue;
    }

    const std::string& topic = vec[0];
    const std::string& path = vec[1];
    off_t offset = atol(vec[2].c_str());
    if (topic.empty() || path.empty() || offset < 0) {
      LOG(WARNING) << "Produce StartInternal invalid record topic[" << topic
                   << "] path[" << path << "] offset[" << "offset" << "]";
      continue;
    }

    if (!IsFile(path)) {
      LOG(WARNING) << "Produce StartInternal IsFile failed topic[" << topic
                   << "] path[" << path << "] offset[" << "offset" << "]";
      continue;
    }

    // get topic producer
    std::shared_ptr<KafkaTopicProducer> ktp =
        producer_->GetTopicProducer(topic);
    if (!ktp) {
      LOG(WARNING) << "Produce StartInternal GetTopicProducer topic["
                   << topic << "] failed";
      continue;
    }

    // get topic conf
    std::unique_lock<std::mutex> guard(mutex_);
    auto it = topic_confs_.find(topic);
    if (it == topic_confs_.end()) {
      LOG(WARNING) << "Produce StartInternal invalid topic_confs topic["
                   << topic << "]";
      guard.unlock();
      continue;
    }

    std::shared_ptr<TopicConf> conf = it->second;
    guard.unlock();

    // get conf parameter
    int batch = conf->batch_num();
    int timeout = conf->poll_timeout();
    int msgs = conf->poll_messages();

    ProduceAndSave(topic, path, offset, batch, timeout, msgs, std::move(ktp));
  }

  LOG(INFO) << "Produce thread existing";
}

#define PRODUCE_TRY_NUM 3

void Produce::ProduceAndSave(
    const std::string& topic,
    const std::string& path,
    off_t offset,
    int batch,
    int timeout,
    int msgs_num,
    std::shared_ptr<KafkaTopicProducer> ktp) {
  std::string dir = DirName(path);
  std::string file = BaseName(path);
  if (dir.empty() || file.empty()) {
    LOG(WARNING) << "Produce ProduceAndSave invlaid path[" << path << "]";
    return;
  }
/*
  table_->Update(dir, file, 0);
  LOG(INFO) << "log sent topic[" << topic << "] path[" << path << "] offset["
            << offset << "] batch[" << batch << "] timeout[" << timeout
            <<"] msgs_num[" << msgs_num << "]";
*/

  std::ifstream ifs(path);
  if (!ifs.is_open()) {
    LOG(WARNING) << "Produce ProduceAndSave open path[" << path << "] failed";
    return;
  }

  if (offset == -1)
    return;

  if (offset != 0)
    ifs.seekg(offset);

  int i = 0;
  off_t num = 0;
  std::string line;
  while (std::getline(ifs, line)) {
    ++num;
    for (i = 0; i < PRODUCE_TRY_NUM; ++i) {
      int res = ktp->ProduceMessage(line);
      if (res == 0)
        break;

      if (res == -2) {
        LOG(WARNING) << "Produce ProduceAndSave path[" << path
                     << "] empty line[" << num << "]";
        break;
      }

      if (errno == 105) {
        producer_->PollOutq(msgs_num, timeout);
      } else {
        ktp->Poll(timeout);
      }
    }

    // Try ProduceMessage failed 3 times, handle line with error msg
    if (i >= 3) {
      LOG(WARNING) << "Produce ProduceAndSave failed 3 times "
                   << "topic[" << topic << "] path[" << path << "]"
                   << " errno[" << errno << "]";
      handle_->ArchiveMsg(topic, line);
    }

    if (num % batch == 0) {
      if (!table_->Update(dir, file, ifs.tellg())) {
        LOG(WARNING) << "Produce ProduceAndSave table Update failed "
                     << "topic[" << topic << "] path[" << path << "]"
                     << " offset[" << ifs.tellg() << "]";
      }
    }
  }

  if (!table_->Update(dir, file, ifs.tellg())) {
    LOG(WARNING) << "Produce ProduceAndSave table Update failed "
                 << "topic[" << topic << "] path[" << path << "]"
                 << " offset[" << ifs.tellg() << "]";
  }
  ifs.close();

  producer_->PollOutq(msgs_num, timeout);
  LOG(INFO) << "log sent[" << path << "] line[" << num << "]";

}

}   // namespace log2hdfs
<commit_msg>fix bug<commit_after>// Copyright (c) 2017 Lanceolata

#include "log2kafka/produce.h"
#include "log2kafka/topic_conf.h"
#include "log2kafka/offset_table.h"
#include "log2kafka/errmsg_handle.h"
#include "kafka/kafka_producer.h"
#include "kafka/kafka_topic_producer.h"
#include "util/string_utils.h"
#include "util/system_utils.h"
#include "easylogging++.h"

namespace log2hdfs {

std::unique_ptr<Produce> Produce::Init(
    std::shared_ptr<KafkaProducer> producer,
    std::shared_ptr<Queue<std::string>> queue,
    std::shared_ptr<OffsetTable> table,
    std::shared_ptr<ErrmsgHandle> handle) {
  if (!producer || !queue || !table || !handle) {
    LOG(ERROR) << "Produce Init invalid parameters";
    return nullptr;
  }
  return std::unique_ptr<Produce>(new Produce(
             std::move(producer), std::move(queue),
             std::move(table), std::move(handle)));
}

bool Produce::AddTopic(std::shared_ptr<TopicConf> conf) {
  if (!conf) {
    LOG(WARNING) << "Produce AddTopic invalid parameters";
    return false;
  }

  std::unique_ptr<KafkaTopicConf> topic_conf = conf->kafka_topic_conf();
  const std::string topic = conf->topic();

  std::string errstr;
  std::shared_ptr<KafkaTopicProducer> ktp = producer_->CreateTopicProducer(
      topic, topic_conf.get(), &errstr);
  if (!ktp) {
    LOG(WARNING) << "Produce AddTopic CreateTopicProducer topic[" << topic
                 << "] failed with errstr[" << errstr << "]";
    return false;
  }

  std::lock_guard<std::mutex> guard(mutex_);
  auto it = topic_confs_.find(topic);
  if (it != topic_confs_.end()) {
    LOG(WARNING) << "Produce AddTopic topic[" << topic
                 << "] already add";
    return false;
  }

  LOG(INFO) << "Produce AddTopic topic[" << topic << "] success";
  topic_confs_[topic] = std::move(conf);
  return true;
}

bool Produce::RemoveTopic(const std::string& topic) {
  if (topic.empty()) {
    LOG(WARNING) << "Produce RemoveTopic invalid parameters";
    return false;
  }

  std::lock_guard<std::mutex> guard(mutex_);
  if (topic_confs_.erase(topic) == 1) {
    LOG(INFO) << "Produce RemoveTopic topic_confs_ erase topic[" << topic
              << "] success";
  } else {
    LOG(WARNING) << "Produce RemoveTopic topic_confs_ erase topic[" << topic
                 << "] failed";
    return false;
  }

  if (producer_->RemoveTopicProducer(topic)) {
    LOG(INFO) << "Produce RemoveTopic RemoveTopicProducer topic[" << topic
              << "] success";
  } else {
    LOG(WARNING) << "Produce RemoveTopic RemoveTopicProducer topic["
                 << topic << "] failed";
    return false;
  }
  return true;
}

void Produce::StartInternal() {
  LOG(INFO) << "Log2kafkaProduce thread created";

  while (running_.load()) {
    std::shared_ptr<std::string> record = queue_->WaitPop();
    if (!record) {
      LOG(WARNING) << "Produce StartInternal WaitPop nullptr";
      continue;
    }

    // check record
    std::vector<std::string> vec = SplitString(*record, ":",
        kTrimWhitespace, kSplitNonempty);
    if (vec.size() < 3) {
      LOG(WARNING) << "Produce StartInternal invalid record[" << *record<< "]";
      continue;
    }

    const std::string& topic = vec[0];
    const std::string& path = vec[1];
    off_t offset = atol(vec[2].c_str());
    if (topic.empty() || path.empty() || offset < -1) {
      LOG(WARNING) << "Produce StartInternal invalid record topic[" << topic
                   << "] path[" << path << "] offset[" << offset << "]";
      continue;
    }

    if (!IsFile(path)) {
      LOG(WARNING) << "Produce StartInternal IsFile failed topic[" << topic
                   << "] path[" << path << "] offset[" << "offset" << "]";
      continue;
    }

    // get topic producer
    std::shared_ptr<KafkaTopicProducer> ktp =
        producer_->GetTopicProducer(topic);
    if (!ktp) {
      LOG(WARNING) << "Produce StartInternal GetTopicProducer topic["
                   << topic << "] failed";
      continue;
    }

    // get topic conf
    std::unique_lock<std::mutex> guard(mutex_);
    auto it = topic_confs_.find(topic);
    if (it == topic_confs_.end()) {
      LOG(WARNING) << "Produce StartInternal invalid topic_confs topic["
                   << topic << "]";
      guard.unlock();
      continue;
    }

    std::shared_ptr<TopicConf> conf = it->second;
    guard.unlock();

    // get conf parameter
    int batch = conf->batch_num();
    int timeout = conf->poll_timeout();
    int msgs = conf->poll_messages();

    ProduceAndSave(topic, path, offset, batch, timeout, msgs, std::move(ktp));
  }

  LOG(INFO) << "Produce thread existing";
}

#define PRODUCE_TRY_NUM 3

void Produce::ProduceAndSave(
    const std::string& topic,
    const std::string& path,
    off_t offset,
    int batch,
    int timeout,
    int msgs_num,
    std::shared_ptr<KafkaTopicProducer> ktp) {
  std::string dir = DirName(path);
  std::string file = BaseName(path);
  if (dir.empty() || file.empty()) {
    LOG(WARNING) << "Produce ProduceAndSave invlaid path[" << path << "]";
    return;
  }
/*
  table_->Update(dir, file, 0);
  LOG(INFO) << "log sent topic[" << topic << "] path[" << path << "] offset["
            << offset << "] batch[" << batch << "] timeout[" << timeout
            <<"] msgs_num[" << msgs_num << "]";
*/

  std::ifstream ifs(path);
  if (!ifs.is_open()) {
    LOG(WARNING) << "Produce ProduceAndSave open path[" << path << "] failed";
    return;
  }

  if (offset == -1)
    return;

  if (offset != 0)
    ifs.seekg(offset);

  int i = 0;
  off_t num = 0;
  std::string line;
  while (std::getline(ifs, line)) {
    ++num;
    for (i = 0; i < PRODUCE_TRY_NUM; ++i) {
      int res = ktp->ProduceMessage(line);
      if (res == 0)
        break;

      if (res == -2) {
        LOG(WARNING) << "Produce ProduceAndSave path[" << path
                     << "] empty line[" << num << "]";
        break;
      }

      if (errno == 105) {
        producer_->PollOutq(msgs_num, timeout);
      } else {
        ktp->Poll(timeout);
      }
    }

    // Try ProduceMessage failed 3 times, handle line with error msg
    if (i >= 3) {
      LOG(WARNING) << "Produce ProduceAndSave failed 3 times "
                   << "topic[" << topic << "] path[" << path << "]"
                   << " errno[" << errno << "]";
      handle_->ArchiveMsg(topic, line);
    }

    if (num % batch == 0) {
      if (!table_->Update(dir, file, ifs.tellg())) {
        LOG(WARNING) << "Produce ProduceAndSave table Update failed "
                     << "topic[" << topic << "] path[" << path << "]"
                     << " offset[" << ifs.tellg() << "]";
      }
    }
  }

  if (!table_->Update(dir, file, ifs.tellg())) {
    LOG(WARNING) << "Produce ProduceAndSave table Update failed "
                 << "topic[" << topic << "] path[" << path << "]"
                 << " offset[" << ifs.tellg() << "]";
  }
  ifs.close();

  producer_->PollOutq(msgs_num, timeout);
  LOG(INFO) << "log sent[" << path << "] line[" << num << "]";

}

}   // namespace log2hdfs
<|endoftext|>


<commit_before><commit_msg>fdo#36681: fixed view window after redoing a frame delete<commit_after><|endoftext|>


<commit_before>#include "libgame.h"
#include "sprite.h"

#define MAXLEN 64

#define LEFT BUTTON_NE
#define RIGHT BUTTON_SE

#define GAMEOVER_X 16
#define GAMEOVER_Y 24

const uint8_t gameOverLines[] DATA = {
    0x3e, 0x38, 0xc6, 0xfe,
    0x60, 0x6c, 0xee, 0xc0,
    0xc0, 0xc6, 0xfe, 0xc0,
    0xce, 0xc6, 0xfe, 0xfc,
    0xc6, 0xfe, 0xd6, 0xc0,
    0x66, 0xc6, 0xc6, 0xc0,
    0x3e, 0xc6, 0xc6, 0xfe,
    0x00, 0x00, 0x00, 0x00,
    0x7c, 0xc6, 0xfe, 0xfc,
    0xc6, 0xc6, 0xc0, 0xc6,
    0xc6, 0xc6, 0xc0, 0xc6,
    0xc6, 0xc6, 0xfc, 0xce,
    0xc6, 0x6c, 0xc0, 0xf8,
    0xc6, 0x38, 0xc0, 0xdc,
    0x7c, 0x10, 0xfe, 0xce
};

const game_sprite gameOver DATA = {
    31, 15, 4, gameOverLines
};

enum Phases
{
    PHASE_GAME,
    PHASE_GAMEOVER
};

struct SnakeData
{
    uint8_t phase;
    uint8_t snakeX[MAXLEN + 1];
    uint8_t snakeY[MAXLEN + 1];
    uint8_t snakeLen;
    uint8_t velX;
    uint8_t velY;
    uint8_t foodX;
    uint8_t foodY;
    bool leftPressed;
    bool rightPressed;
    bool half;
    uint8_t collision[128];

};
static SnakeData* data;

void generateFood()
{
    while (1)
    {
        bool ok = true;
        data->foodX = rand() % 32;
        data->foodY = rand() % 32;
        for (int i = 0; i < data->snakeLen; ++i)
        {
            if (data->snakeX[i] == data->foodX && data->snakeY[i] == data->foodY)
            {
                ok = false;
                break;
            }
        }
        if (ok)
            return;
    }
}

void Snake_prepare()
{
    game_set_ups(60);
    data->phase = PHASE_GAME;
    data->snakeLen = 3;
    data->snakeX[0] = 17;
    data->snakeY[0] = 16;
    data->snakeX[1] = 16;
    data->snakeY[1] = 16;
    data->snakeX[2] = 15;
    data->snakeY[2] = 16;
    data->velX = 1;
    data->velY = 0;
    data->leftPressed = false;
    data->rightPressed = false;
    data->half = false;
    generateFood();
}

int velsign(int x)
{
    if (x == 0) return 0;
    if (x == 1) return 1;
    return -1;
}

void Snake_render()
{
    game_draw_pixel(data->foodX * 2, data->foodY * 2, RED);
    game_draw_pixel(data->foodX * 2 + 1, data->foodY * 2, RED);
    game_draw_pixel(data->foodX * 2, data->foodY * 2 + 1, RED);
    game_draw_pixel(data->foodX * 2 + 1, data->foodY * 2 + 1, RED);
    for (int i = 0; i < data->snakeLen; ++i)
    {
        int x = data->snakeX[i] * 2 + WIDTH;
        int y = data->snakeY[i] * 2 + HEIGHT;
        if (data->half && i == data->snakeLen - 1)
        {
            x += velsign((data->snakeX[i - 1] - data->snakeX[i] + 64) % 32);
            y += velsign((data->snakeY[i - 1] - data->snakeY[i] + 64) % 32);
            game_draw_pixel(x % 64, y % 64, GREEN);
            game_draw_pixel((x + 1) % 64, y % 64, GREEN);
            game_draw_pixel(x % 64, (y + 1) % 64, GREEN);
            game_draw_pixel((x + 1) % 64, (y + 1) % 64, GREEN);
            continue;
        }
        game_draw_pixel(x % 64, y % 64, GREEN);
        game_draw_pixel((x + 1) % 64, y % 64, GREEN);
        game_draw_pixel(x % 64, (y + 1) % 64, GREEN);
        game_draw_pixel((x + 1) % 64, (y + 1) % 64, GREEN);
        if (data->half && i == 0)
        {
            x += data->velX;
            y += data->velY;
            game_draw_pixel(x % 64, y % 64, GREEN);
            game_draw_pixel((x + 1) % 64, y % 64, GREEN);
            game_draw_pixel(x % 64, (y + 1) % 64, GREEN);
            game_draw_pixel((x + 1) % 64, (y + 1) % 64, GREEN);
        }
    }

    if (data->phase == PHASE_GAMEOVER)
    {
        game_draw_sprite(&gameOver, GAMEOVER_X, GAMEOVER_Y, WHITE);
    }
}

void Snake_update(unsigned long delta)
{
    if (data->phase == PHASE_GAME) data->half = !data->half; else data->half = false;
    if (data->phase == PHASE_GAME && !data->half)
    {
        for (int i = 0; i < 128; ++i)
            data->collision[i] = 0;
        for (int i = 0; i < data->snakeLen; ++i)
        {
            int bit = data->snakeX[i] * 32 + data->snakeY[i];
            data->collision[bit / 8] |= (1 << (bit % 8));
        }
        // move snake forward
        for (int i = data->snakeLen; i >= 1; --i)
        {
            data->snakeX[i] = data->snakeX[i - 1];
            data->snakeY[i] = data->snakeY[i - 1];
        }
        data->snakeX[0] = (data->snakeX[0] + data->velX) % 32;
        data->snakeY[0] = (data->snakeY[0] + data->velY) % 32;
        if (data->snakeX[0] == data->foodX && data->snakeY[0] == data->foodY)
        {
            if (data->snakeLen < MAXLEN)
            {
                data->snakeLen++;
            }
            generateFood();
        }
        for (int i = 0; i < 128; ++i)
            data->collision[i] = 0;
        for (int i = 0; i < data->snakeLen; ++i)
        {
            int bit = data->snakeX[i] * 32 + data->snakeY[i];
            if (data->collision[bit / 8] & (1 << (bit % 8)))
            {
                // game over
                data->phase = PHASE_GAMEOVER;
            }
            data->collision[bit / 8] |= (1 << (bit % 8));
        }
    }
    if (data->phase == PHASE_GAME)
    {
        if (game_is_button_pressed(LEFT) && !data->leftPressed)
        {
            int newVelX = -data->velY;
            int newVelY = data->velX;
            data->velX = newVelX;
            data->velY = newVelY;
        }

        if (game_is_button_pressed(RIGHT) && !data->rightPressed)
        {
            int newVelX = data->velY;
            int newVelY = -data->velX;
            data->velX = newVelX;
            data->velY = newVelY;
        }
    }
    if (data->phase == PHASE_GAMEOVER)
    {
        if (game_is_button_pressed(BUTTON_NW) ||
            game_is_button_pressed(BUTTON_SW) ||
            game_is_button_pressed(BUTTON_NE) ||
            game_is_button_pressed(BUTTON_SE)) Snake_prepare();
    }
    data->leftPressed = game_is_button_pressed(LEFT);
    data->rightPressed = game_is_button_pressed(RIGHT);
}

game_instance Snake = {
    "Змейка",
    Snake_prepare,
    Snake_render,
    Snake_update,
    2,
    sizeof(SnakeData),
    (void**)(&data)
};
<commit_msg>Removed unneccessary array in Snake<commit_after>#include "libgame.h"
#include "sprite.h"

#define MAXLEN 64

#define LEFT BUTTON_NE
#define RIGHT BUTTON_SE

#define GAMEOVER_X 16
#define GAMEOVER_Y 24

const uint8_t gameOverLines[] DATA = {
    0x3e, 0x38, 0xc6, 0xfe,
    0x60, 0x6c, 0xee, 0xc0,
    0xc0, 0xc6, 0xfe, 0xc0,
    0xce, 0xc6, 0xfe, 0xfc,
    0xc6, 0xfe, 0xd6, 0xc0,
    0x66, 0xc6, 0xc6, 0xc0,
    0x3e, 0xc6, 0xc6, 0xfe,
    0x00, 0x00, 0x00, 0x00,
    0x7c, 0xc6, 0xfe, 0xfc,
    0xc6, 0xc6, 0xc0, 0xc6,
    0xc6, 0xc6, 0xc0, 0xc6,
    0xc6, 0xc6, 0xfc, 0xce,
    0xc6, 0x6c, 0xc0, 0xf8,
    0xc6, 0x38, 0xc0, 0xdc,
    0x7c, 0x10, 0xfe, 0xce
};

const game_sprite gameOver DATA = {
    31, 15, 4, gameOverLines
};

enum Phases
{
    PHASE_GAME,
    PHASE_GAMEOVER
};

struct SnakeData
{
    uint8_t phase;
    uint8_t snakeX[MAXLEN + 1];
    uint8_t snakeY[MAXLEN + 1];
    uint8_t snakeLen;
    uint8_t velX;
    uint8_t velY;
    uint8_t foodX;
    uint8_t foodY;
    bool leftPressed;
    bool rightPressed;
    bool half;

};
static SnakeData* data;

void generateFood()
{
    while (1)
    {
        bool ok = true;
        data->foodX = rand() % 32;
        data->foodY = rand() % 32;
        for (int i = 0; i < data->snakeLen; ++i)
        {
            if (data->snakeX[i] == data->foodX && data->snakeY[i] == data->foodY)
            {
                ok = false;
                break;
            }
        }
        if (ok)
            return;
    }
}

void Snake_prepare()
{
    game_set_ups(60);
    data->phase = PHASE_GAME;
    data->snakeLen = 3;
    data->snakeX[0] = 17;
    data->snakeY[0] = 16;
    data->snakeX[1] = 16;
    data->snakeY[1] = 16;
    data->snakeX[2] = 15;
    data->snakeY[2] = 16;
    data->velX = 1;
    data->velY = 0;
    data->leftPressed = false;
    data->rightPressed = false;
    data->half = false;
    generateFood();
}

int velsign(int x)
{
    if (x == 0) return 0;
    if (x == 1) return 1;
    return -1;
}

void Snake_render()
{
    game_draw_pixel(data->foodX * 2, data->foodY * 2, RED);
    game_draw_pixel(data->foodX * 2 + 1, data->foodY * 2, RED);
    game_draw_pixel(data->foodX * 2, data->foodY * 2 + 1, RED);
    game_draw_pixel(data->foodX * 2 + 1, data->foodY * 2 + 1, RED);
    for (int i = 0; i < data->snakeLen; ++i)
    {
        int x = data->snakeX[i] * 2 + WIDTH;
        int y = data->snakeY[i] * 2 + HEIGHT;
        if (data->half && i == data->snakeLen - 1)
        {
            x += velsign((data->snakeX[i - 1] - data->snakeX[i] + 64) % 32);
            y += velsign((data->snakeY[i - 1] - data->snakeY[i] + 64) % 32);
            game_draw_pixel(x % 64, y % 64, GREEN);
            game_draw_pixel((x + 1) % 64, y % 64, GREEN);
            game_draw_pixel(x % 64, (y + 1) % 64, GREEN);
            game_draw_pixel((x + 1) % 64, (y + 1) % 64, GREEN);
            continue;
        }
        game_draw_pixel(x % 64, y % 64, GREEN);
        game_draw_pixel((x + 1) % 64, y % 64, GREEN);
        game_draw_pixel(x % 64, (y + 1) % 64, GREEN);
        game_draw_pixel((x + 1) % 64, (y + 1) % 64, GREEN);
        if (data->half && i == 0)
        {
            x += data->velX;
            y += data->velY;
            game_draw_pixel(x % 64, y % 64, GREEN);
            game_draw_pixel((x + 1) % 64, y % 64, GREEN);
            game_draw_pixel(x % 64, (y + 1) % 64, GREEN);
            game_draw_pixel((x + 1) % 64, (y + 1) % 64, GREEN);
        }
    }

    if (data->phase == PHASE_GAMEOVER)
    {
        game_draw_sprite(&gameOver, GAMEOVER_X, GAMEOVER_Y, WHITE);
    }
}

void Snake_update(unsigned long delta)
{
    if (data->phase == PHASE_GAME) data->half = !data->half; else data->half = false;
    if (data->phase == PHASE_GAME && !data->half)
    {
        for (int i = 0; i < data->snakeLen; ++i)
        {
            int bit = data->snakeX[i] * 32 + data->snakeY[i];
        }
        // move snake forward
        for (int i = data->snakeLen; i >= 1; --i)
        {
            data->snakeX[i] = data->snakeX[i - 1];
            data->snakeY[i] = data->snakeY[i - 1];
        }
        data->snakeX[0] = (data->snakeX[0] + data->velX) % 32;
        data->snakeY[0] = (data->snakeY[0] + data->velY) % 32;
        if (data->snakeX[0] == data->foodX && data->snakeY[0] == data->foodY)
        {
            if (data->snakeLen < MAXLEN)
            {
                data->snakeLen++;
            }
            generateFood();
        }
        for (int i = 1; i < data->snakeLen; ++i)
        {
            if (data->snakeX[0] == data->snakeX[i] && data->snakeY[0] == data->snakeY[i])
            {
                // game over
                data->phase = PHASE_GAMEOVER;
            }
        }
    }
    if (data->phase == PHASE_GAME)
    {
        if (game_is_button_pressed(LEFT) && !data->leftPressed)
        {
            int newVelX = -data->velY;
            int newVelY = data->velX;
            data->velX = newVelX;
            data->velY = newVelY;
        }

        if (game_is_button_pressed(RIGHT) && !data->rightPressed)
        {
            int newVelX = data->velY;
            int newVelY = -data->velX;
            data->velX = newVelX;
            data->velY = newVelY;
        }
    }
    if (data->phase == PHASE_GAMEOVER)
    {
        if (game_is_button_pressed(BUTTON_NW) ||
            game_is_button_pressed(BUTTON_SW) ||
            game_is_button_pressed(BUTTON_NE) ||
            game_is_button_pressed(BUTTON_SE)) Snake_prepare();
    }
    data->leftPressed = game_is_button_pressed(LEFT);
    data->rightPressed = game_is_button_pressed(RIGHT);
}

game_instance Snake = {
    "Змейка",
    Snake_prepare,
    Snake_render,
    Snake_update,
    2,
    sizeof(SnakeData),
    (void**)(&data)
};
<|endoftext|>


<commit_before>/*
 * MPT C++ type identifier
 */

#include "core.h"

__MPT_NAMESPACE_BEGIN

/*!
 * \ingroup mptCore
 * \brief create type id
 *
 * Convert type code for reference element.
 *
 * \param from  base type
 *
 * \retval <0 conversion error
 * \retval >0 item type code
 */
extern int toReferenceId(int from)
{
    if (from < 0) {
        return BadValue;
    }
    if (from > _TypeGenericMax) {
        return BadType;
    }
    return _TypeReferenceBase + from;
}
/*!
 * \ingroup mptCore
 * \brief create type id
 *
 * Convert type code for item element.
 *
 * \param from  base type
 *
 * \retval <0 conversion error
 * \retval >0 item type code
 */
extern int toItemId(int from)
{
    if (from < 0) {
        return BadValue;
    }
    if (from > _TypeGenericMax) {
        return BadType;
    }
    return _TypeItemBase + from;
}
/*!
 * \ingroup mptCore
 * \brief create type code
 *
 * Create new type code in dynamic extended range.
 * To register explicit metatype, interface or
 * dynamic base type use supplied special functions.
 *
 * \return new type code
 */
extern int makeId()
{
    static int id = _TypeGenericBase;
    if (id >= _TypeGenericMax) {
        return BadValue;
    }
    return id++;
}

__MPT_NAMESPACE_END
<commit_msg>fix: add missing vector typecode registration<commit_after>/*
 * MPT C++ type identifier
 */

#include "core.h"

__MPT_NAMESPACE_BEGIN

/*!
 * \ingroup mptCore
 * \brief create type id
 *
 * Convert type code for reference element.
 *
 * \param from  base type
 *
 * \retval <0 conversion error
 * \retval >0 item type code
 */
extern int toReferenceId(int from)
{
    if (from < 0) {
        return BadValue;
    }
    if (from > _TypeGenericMax) {
        return BadType;
    }
    return _TypeReferenceBase + from;
}
/*!
 * \ingroup mptCore
 * \brief create type id
 *
 * Convert type code for item element.
 *
 * \param from  base type
 *
 * \retval <0 conversion error
 * \retval >0 item type code
 */
extern int toItemId(int from)
{
    if (from < 0) {
        return BadValue;
    }
    if (from > _TypeGenericMax) {
        return BadType;
    }
    return _TypeItemBase + from;
}
/*!
 * \ingroup mptCore
 * \brief new generic type
 *
 * Create new type code in dynamic extended range.
 * To register explicit metatype, interface or
 * dynamic base type use supplied special functions.
 *
 * \return new type code
 */
extern int makeId()
{
    static int id = _TypeGenericBase;
    if (id >= _TypeGenericMax) {
        return BadValue;
    }
    return id++;
}
/*!
 * \ingroup mptCore
 * \brief new vector type
 *
 * Create new vector type code in dynamic extended range.
 *
 * \return new type code
 */
extern int makeVectorId()
{
    // redirect to generic registration
    return makeId();
}

__MPT_NAMESPACE_END
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <iostream>
#include <vector>

#include <gflags/gflags.h>
#include <glog/logging.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>

#include "sdk/sdk.h"
#include "sdk/db.h"
#include "sdk/table.h"

#include "util/env.h"
#include "util/coding.h"

DECLARE_string(flagfile);

char* StripWhite(char* line) {
    char *s, *t;
    for (s = line; whitespace(*s); s++);
    if (*s == 0)
        return s;
    t = s + strlen(s) - 1;
    while (t > s && whitespace(*t)) {
        t--;
    }
    *++t = '\0';
    return s;
}

void HelpManue() {
    printf("========= usage ===========\n");
    printf("cmd: quit\n");
    printf("cmd: help\n");
    printf("cmd: CreateTable dbname tablename primary_key_type [index_name index_type]...\n");
    printf("cmd(TEST): Put dbname tablename value primary_key timestamp(ingore) [index_name index_key]...\n");
    printf("cmd: Get dbname tablename start_ts(ignore) end_ts(ignore) limit(ignore) "
            "[index_name cmp(=, >=, >, <=, <) index_key]...\n");
    printf("===========================\n");
}

int GetCmp(std::string& cmp_str) {
    if (cmp_str.compare(">") == 0) {
        return (int)mdt::kGreater;
    } else if (cmp_str.compare(">=") == 0) {
        return (int)mdt::kGreaterEqual;
    } else if (cmp_str.compare("<") == 0) {
        return (int)mdt::kLess;
    } else if (cmp_str.compare("<=") == 0) {
        return (int)mdt::kLessEqual;
    } else if (cmp_str.compare("==") == 0) {
        return (int)mdt::kEqualTo;
    } else {
        //std::cout << "cmp " << cmp_str << " not support\n";
        return -1;
    }
    return -1;
}

int GetOp(std::vector<std::string>& cmd_vec) {
    // create db
    std::cout << "open db ..." << std::endl;
    mdt::Database* db;
    std::string db_name = cmd_vec[1];
    db = mdt::OpenDatabase(db_name);

    std::cout << "open table ..." << std::endl;
    mdt::Table* table;
    std::string table_name = cmd_vec[2];
    table = OpenTable(db, table_name);

    // search test
    mdt::SearchRequest* search_req = new mdt::SearchRequest;
    //search_req->primary_key = cmd_vec[];
    search_req->limit = 10;
    search_req->start_timestamp = 0;
    search_req->end_timestamp = time(NULL);
    int num_index = cmd_vec.size() - 6;
    if (num_index % 3 != 0) {
        std::cout << "num of condition index not match\n";
        return 0;
    }
    for (int i = 0; i < num_index; i += 3) {
        mdt::IndexCondition index;
        int cmp;
        index.index_name = cmd_vec[i + 6];
        cmp = GetCmp(cmd_vec[i + 7]);
        if (cmp == -1) {
            std::cout << "cmp " << cmd_vec[i + 7] << " not support\n";
            return 0;
        }
        index.comparator = (mdt::COMPARATOR)cmp;
        index.compare_value = cmd_vec[i + 8];
        search_req->index_condition_list.push_back(index);
    }

    mdt::SearchResponse* search_resp = new mdt::SearchResponse;

    std::cout << "get ..." << std::endl;
    table->Get(search_req, search_resp);
    for (uint32_t i = 0; i < search_resp->result_stream.size(); i++) {
        const mdt::ResultStream& result = search_resp->result_stream[i];
        std::cout << "primary key: " << result.primary_key << std::endl;
        for (uint32_t j = 0; j < result.result_data_list.size(); j++) {
            std::cout << "        data: " << result.result_data_list[j] << std::endl;
        }
    }
    return 0;
}

void StoreCallback_Test(mdt::Table* table, mdt::StoreRequest* request,
                        mdt::StoreResponse* response,
                        void* callback_param) {
    bool* store_finish = (bool*)callback_param;
    *store_finish = true;
}

int PutOp(std::vector<std::string>& cmd_vec) {
    // create db
    std::cout << "open db ..." << std::endl;
    mdt::Database* db;
    std::string db_name = cmd_vec[1];
    db = mdt::OpenDatabase(db_name);

    std::cout << "open table ..." << std::endl;
    mdt::Table* table;
    std::string table_name = cmd_vec[2];
    table = OpenTable(db, table_name);

    if (cmd_vec[3].compare("1") != 0) {
        std::cout << "value type not support, now support value=1\n";
        return 0;
    }

    // insert data
    mdt::StoreRequest* store_req = new mdt::StoreRequest();
    store_req->primary_key = cmd_vec[4];
    store_req->timestamp = time(NULL);

    int num_index = cmd_vec.size() - 6;
    if (num_index % 2 != 0) {
        std::cout << "put fail, [index_name index_type] not match!\n";
        return 0;
    }
    for (int i = 0; i < num_index; i += 2) {
        mdt::Index index;
        index.index_name = cmd_vec[i + 6];
        index.index_key = cmd_vec[i + 7];
        store_req->index_list.push_back(index);
    }

    if (cmd_vec[3].compare("1") != 0) {
        std::string str(10240, 'y');
        store_req->data = str;
    }
    mdt::StoreResponse* store_resp = new mdt::StoreResponse();
    mdt::StoreCallback callback = StoreCallback_Test;

    bool store_finish = false;
    std::cout << "put ..." << std::endl;
    table->Put(store_req, store_resp, callback, &store_finish);
    return 0;
}

int CreateTableOp(std::vector<std::string>& cmd_vec) {
    // create db
    std::cout << "open db ..." << std::endl;
    mdt::Database* db;
    std::string db_name = cmd_vec[1];
    db = mdt::OpenDatabase(db_name);

    // create table
    std::cout << "create table ..." << std::endl;
    mdt::TableDescription table_desc;
    table_desc.table_name = cmd_vec[2];
    if (cmd_vec[3].compare("kBytes") != 0) {
        std::cout << "create table fail, primary key type not support!\n";
        return 0;
    }
    table_desc.primary_key_type = mdt::kBytes;

    int num_index = cmd_vec.size() - 4;
    if (num_index % 2 != 0) {
        std::cout << "create table fail, [index_name index_type] not match!\n";
        return 0;
    }
    for (int i = 0; i < num_index; i += 2) {
        mdt::IndexDescription table_index;
        table_index.index_name = cmd_vec[i + 4];
        if (cmd_vec[i + 5].compare("kBytes") != 0) {
            std::cout << "create table fail, index key: " << cmd_vec[i + 4]
                << ", key type not support!\n";
            return 0;
        }
        table_index.index_key_type = mdt::kBytes;
        table_desc.index_descriptor_list.push_back(table_index);
    }
    CreateTable(db, table_desc);
    return 0;
}

void ParseFlagFile(const std::string& flagfile) {
    int ac = 1;
    char** av = new char*[2];
    av[0] = (char*)"dummy";
    av[1] = NULL;
    std::string local_flagfile = FLAGS_flagfile;
    FLAGS_flagfile = flagfile;
    ::google::ParseCommandLineFlags(&ac, &av, true);
    delete av;
    FLAGS_flagfile = local_flagfile;
    return;
}

int main(int ac, char* av[]) {
    // Parse flagfile
    std::cout << "default configure path, ../conf/mdt.flag\n";
    ParseFlagFile("../conf/mdt.flag");
    while (1) {
        char *line = readline("mdt:");
        char *cmd = StripWhite(line);
        std::string command(cmd, strlen(cmd));

        // split cmd
        std::vector<std::string> cmd_vec;
        boost::split(cmd_vec, command, boost::is_any_of(" "), boost::token_compress_on);
        if (cmd_vec.size() == 0) {
            free(line);
            continue;
        } else if (cmd_vec[0].compare("quit") == 0) {
            std::cout << "bye\n";
            return 0;
        } else if (cmd_vec[0].compare("help") == 0) {
            HelpManue();
            free(line);
            continue;
        } else if (cmd_vec[0].compare("CreateTable") == 0 && cmd_vec.size() >= 4) {
            // cmd: CreateTable dbname tablename primary_key_type [index_name index_type]...
            std::cout << "create table: dbname " << cmd_vec[1]
                << "tablename " << cmd_vec[2]
                << "\n";
            CreateTableOp(cmd_vec);
            free(line);
            continue;
        } else if (cmd_vec[0].compare("Put") == 0 && cmd_vec.size() >= 6) {
            // cmd: Put dbname tablename value primary_key timestamp [index_name index_key]
            PutOp(cmd_vec);
            free(line);
            continue;
        } else if (cmd_vec[0].compare("Get") == 0 && cmd_vec.size() >= 6) {
            // cmd: Get dbname tablename start_ts(ignore) end_ts(ignore) limit(ignore) [index_name cmp(=, >=, >, <=, <) index_key]
            GetOp(cmd_vec);
            free(line);
            continue;
        } else {
            std::cout << "cmd not known\n";
            free(line);
            continue;
        }

        std::cout << command
            << ", size " << cmd_vec.size()
            << ", cmd " << cmd_vec[0]
            << "\n";
        free(line);
    }
    return 0;
}
<commit_msg>#64: add type support<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <iostream>
#include <vector>

#include <gflags/gflags.h>
#include <glog/logging.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>

#include "sdk/sdk.h"
#include "sdk/db.h"
#include "sdk/table.h"

#include "util/env.h"
#include "util/coding.h"

DECLARE_string(flagfile);

char* StripWhite(char* line) {
    char *s, *t;
    for (s = line; whitespace(*s); s++);
    if (*s == 0)
        return s;
    t = s + strlen(s) - 1;
    while (t > s && whitespace(*t)) {
        t--;
    }
    *++t = '\0';
    return s;
}

void HelpManue() {
    printf("========= usage ===========\n");
    printf("cmd: quit\n");
    printf("cmd: help\n");
    printf("cmd: CreateTable dbname tablename primary_key_type [index_name index_type]...\n");
    printf("cmd(TEST): Put dbname tablename value primary_key timestamp(ingore) [index_name index_key]...\n");
    printf("cmd: Get dbname tablename start_ts(ignore) end_ts(ignore) limit(ignore) "
            "[index_name cmp(=, >=, >, <=, <) index_key]...\n");
    printf("===========================\n");
}

int GetCmp(std::string& cmp_str) {
    if (cmp_str.compare(">") == 0) {
        return (int)mdt::kGreater;
    } else if (cmp_str.compare(">=") == 0) {
        return (int)mdt::kGreaterEqual;
    } else if (cmp_str.compare("<") == 0) {
        return (int)mdt::kLess;
    } else if (cmp_str.compare("<=") == 0) {
        return (int)mdt::kLessEqual;
    } else if (cmp_str.compare("==") == 0) {
        return (int)mdt::kEqualTo;
    } else {
        //std::cout << "cmp " << cmp_str << " not support\n";
        return -1;
    }
    return -1;
}

int GetOp(std::vector<std::string>& cmd_vec) {
    // create db
    std::cout << "open db ..." << std::endl;
    mdt::Database* db;
    std::string db_name = cmd_vec[1];
    db = mdt::OpenDatabase(db_name);

    std::cout << "open table ..." << std::endl;
    mdt::Table* table;
    std::string table_name = cmd_vec[2];
    table = OpenTable(db, table_name);

    // search test
    mdt::SearchRequest* search_req = new mdt::SearchRequest;
    //search_req->primary_key = cmd_vec[];
    search_req->limit = 10;
    search_req->start_timestamp = 0;
    search_req->end_timestamp = time(NULL);
    int num_index = cmd_vec.size() - 6;
    if (num_index % 3 != 0) {
        std::cout << "num of condition index not match\n";
        return 0;
    }
    for (int i = 0; i < num_index; i += 3) {
        mdt::IndexCondition index;
        int cmp;
        index.index_name = cmd_vec[i + 6];
        cmp = GetCmp(cmd_vec[i + 7]);
        if (cmp == -1) {
            std::cout << "cmp " << cmd_vec[i + 7] << " not support\n";
            return 0;
        }
        index.comparator = (mdt::COMPARATOR)cmp;
        index.compare_value = cmd_vec[i + 8];
        search_req->index_condition_list.push_back(index);
    }

    mdt::SearchResponse* search_resp = new mdt::SearchResponse;

    std::cout << "get ..." << std::endl;
    table->Get(search_req, search_resp);
    for (uint32_t i = 0; i < search_resp->result_stream.size(); i++) {
        const mdt::ResultStream& result = search_resp->result_stream[i];
        std::cout << "primary key: " << result.primary_key << std::endl;
        for (uint32_t j = 0; j < result.result_data_list.size(); j++) {
            std::cout << "        data: " << result.result_data_list[j] << std::endl;
        }
    }
    return 0;
}

void StoreCallback_Test(mdt::Table* table, mdt::StoreRequest* request,
                        mdt::StoreResponse* response,
                        void* callback_param) {
    bool* store_finish = (bool*)callback_param;
    *store_finish = true;
}

int PutOp(std::vector<std::string>& cmd_vec) {
    // create db
    std::cout << "open db ..." << std::endl;
    mdt::Database* db;
    std::string db_name = cmd_vec[1];
    db = mdt::OpenDatabase(db_name);

    std::cout << "open table ..." << std::endl;
    mdt::Table* table;
    std::string table_name = cmd_vec[2];
    table = OpenTable(db, table_name);

    if (cmd_vec[3].compare("1") != 0) {
        std::cout << "value type not support, now support value=1\n";
        return 0;
    }

    // insert data
    mdt::StoreRequest* store_req = new mdt::StoreRequest();
    store_req->primary_key = cmd_vec[4];
    store_req->timestamp = time(NULL);

    int num_index = cmd_vec.size() - 6;
    if (num_index % 2 != 0) {
        std::cout << "put fail, [index_name index_type] not match!\n";
        return 0;
    }
    for (int i = 0; i < num_index; i += 2) {
        mdt::Index index;
        index.index_name = cmd_vec[i + 6];
        index.index_key = cmd_vec[i + 7];
        store_req->index_list.push_back(index);
    }

    if (cmd_vec[3].compare("1") != 0) {
        std::string str(10240, 'y');
        store_req->data = str;
    }
    mdt::StoreResponse* store_resp = new mdt::StoreResponse();
    mdt::StoreCallback callback = StoreCallback_Test;

    bool store_finish = false;
    std::cout << "put ..." << std::endl;
    table->Put(store_req, store_resp, callback, &store_finish);
    return 0;
}

int CreateTableOp(std::vector<std::string>& cmd_vec) {
    // create db
    std::cout << "open db ..." << std::endl;
    mdt::Database* db;
    std::string db_name = cmd_vec[1];
    db = mdt::OpenDatabase(db_name);

    // create table
    std::cout << "create table ..." << std::endl;
    mdt::TableDescription table_desc;
    table_desc.table_name = cmd_vec[2];
    if (cmd_vec[3].compare("kBytes") == 0) {
        table_desc.primary_key_type = mdt::kBytes;
    } else if (cmd_vec[3].compare("kUInt64") == 0) {
        table_desc.primary_key_type = mdt::kUInt64;
    } else if (cmd_vec[3].compare("kInt64") == 0) {
        table_desc.primary_key_type = mdt::kInt64;
    } else if (cmd_vec[3].compare("kUInt32") == 0) {
        table_desc.primary_key_type = mdt::kUInt32;
    } else if (cmd_vec[3].compare("kInt32") == 0) {
        table_desc.primary_key_type = mdt::kInt32;
    } else {
        std::cout << "create table fail, primary key type not support!, support kBytes, kUInt64...\n";
        return 0;
    }

    int num_index = cmd_vec.size() - 4;
    if (num_index % 2 != 0) {
        std::cout << "create table fail, [index_name index_type] not match!\n";
        return 0;
    }
    for (int i = 0; i < num_index; i += 2) {
        mdt::IndexDescription table_index;
        table_index.index_name = cmd_vec[i + 4];
        if (cmd_vec[i + 5].compare("kBytes") == 0) {
            table_index.index_key_type = mdt::kBytes;
        } else if (cmd_vec[i + 5].compare("kUInt64") == 0) {
            table_index.index_key_type = mdt::kUInt64;
        } else if (cmd_vec[i + 5].compare("kInt64") == 0) {
            table_index.index_key_type = mdt::kInt64;
        } else if (cmd_vec[i + 5].compare("kUInt32") == 0) {
            table_index.index_key_type = mdt::kUInt32;
        } else if (cmd_vec[i + 5].compare("kInt32") == 0) {
            table_index.index_key_type = mdt::kInt32;
        } else {
            std::cout << "create table fail, index key: " << cmd_vec[i + 4]
                << ", key type not support!\n";
            return 0;
        }
        table_desc.index_descriptor_list.push_back(table_index);
    }
    CreateTable(db, table_desc);
    return 0;
}

void ParseFlagFile(const std::string& flagfile) {
    int ac = 1;
    char** av = new char*[2];
    av[0] = (char*)"dummy";
    av[1] = NULL;
    std::string local_flagfile = FLAGS_flagfile;
    FLAGS_flagfile = flagfile;
    ::google::ParseCommandLineFlags(&ac, &av, true);
    delete av;
    FLAGS_flagfile = local_flagfile;
    return;
}

int main(int ac, char* av[]) {
    // Parse flagfile
    std::cout << "default configure path, ../conf/mdt.flag\n";
    ParseFlagFile("../conf/mdt.flag");
    while (1) {
        char *line = readline("mdt:");
        char *cmd = StripWhite(line);
        std::string command(cmd, strlen(cmd));

        // split cmd
        std::vector<std::string> cmd_vec;
        boost::split(cmd_vec, command, boost::is_any_of(" "), boost::token_compress_on);
        if (cmd_vec.size() == 0) {
            free(line);
            continue;
        } else if (cmd_vec[0].compare("quit") == 0) {
            std::cout << "bye\n";
            return 0;
        } else if (cmd_vec[0].compare("help") == 0) {
            HelpManue();
            free(line);
            continue;
        } else if (cmd_vec[0].compare("CreateTable") == 0 && cmd_vec.size() >= 4) {
            // cmd: CreateTable dbname tablename primary_key_type [index_name index_type]...
            std::cout << "create table: dbname " << cmd_vec[1]
                << "tablename " << cmd_vec[2]
                << "\n";
            CreateTableOp(cmd_vec);
            free(line);
            continue;
        } else if (cmd_vec[0].compare("Put") == 0 && cmd_vec.size() >= 6) {
            // cmd: Put dbname tablename value primary_key timestamp [index_name index_key]
            PutOp(cmd_vec);
            free(line);
            continue;
        } else if (cmd_vec[0].compare("Get") == 0 && cmd_vec.size() >= 6) {
            // cmd: Get dbname tablename start_ts(ignore) end_ts(ignore) limit(ignore) [index_name cmp(=, >=, >, <=, <) index_key]
            GetOp(cmd_vec);
            free(line);
            continue;
        } else {
            std::cout << "cmd not known\n";
            free(line);
            continue;
        }

        std::cout << command
            << ", size " << cmd_vec.size()
            << ", cmd " << cmd_vec[0]
            << "\n";
        free(line);
    }
    return 0;
}
<|endoftext|>


<commit_before>/**
    This file is part of Deformable Shape Tracking (DEST).

    Copyright(C) 2015/2016 Christoph Heindl
    All rights reserved.

    This software may be modified and distributed under the terms
    of the BSD license.See the LICENSE file for details.
*/

#include <dest/core/tester.h>
#include <dest/util/log.h>

namespace dest {
    namespace core {

        ConstantDistanceNormalizer::ConstantDistanceNormalizer(float c)
        :_c(c)
        {}

        float ConstantDistanceNormalizer::operator()(const SampleData::Sample &s) const {
            return _c;
        }

        LandmarkDistanceNormalizer::LandmarkDistanceNormalizer(int landmarkId0, int landmarkId1)
        :_l0(landmarkId0), _l1(landmarkId1)
        {}

        LandmarkDistanceNormalizer::LandmarkDistanceNormalizer()
        :_l0(0), _l1(0)
        {}

        float LandmarkDistanceNormalizer::operator()(const SampleData::Sample &s) const {
            return 1.f / (s.target.col(_l0) - s.target.col(_l1)).norm();
        }

        LandmarkDistanceNormalizer LandmarkDistanceNormalizer::createInterocularNormalizerIBug() {
            /*  The average point-to-point Euclidean error normalized by the inter-ocular distance
                (measured as the Euclidean distance between the outer corners of the eyes) will be
                used as the error measure.
                See http://ibug.doc.ic.ac.uk/resources/300-W/
             */
            return LandmarkDistanceNormalizer(36, 45);
        }

        LandmarkDistanceNormalizer LandmarkDistanceNormalizer::createInterocularNormalizerIMM() {
            // http://doi.ieeecomputersociety.org/cms/Computer.org/dl/trans/tp/2008/03/figures/ttp20080305411.gif
            return LandmarkDistanceNormalizer(21, 13);
        }

        TestResult testTracker(SampleData &td, const Tracker &t, const DistanceNormalizer &norm) {
            TestResult r;
            r.meanNormalizedDistance = 0.f;
            r.medianNormalizedDistance = 0.f;
            r.stddevNormalizedDistance = 0.f;
            r.worstNormalizedDistance = 0.f;

            const int nLandmarks = static_cast<int>(td.samples.front().target.cols());
            std::vector<float> d;

            for (size_t i = 0; i < td.samples.size(); ++i) {

                dest::core::Shape estimateInImageSpace = t.predict(td.input->images[td.samples[i].inputIdx], td.samples[i].shapeToImage);
                td.samples[i].estimate = td.samples[i].shapeToImage.inverse() * estimateInImageSpace.colwise().homogeneous();

                const float normalizer = norm(td.samples[i]);
                Eigen::VectorXf dev = (td.samples[i].target - td.samples[i].estimate).colwise().norm() * normalizer;
                for (int j  = 0; j < nLandmarks; ++j) {
                    if (dev(j) > 1.9f)
                        std::cout << i << std::endl;
                    d.push_back(dev(j));
                }

                if (i % 100 == 0)
                    DEST_LOG("Processing " << i << "/" << td.samples.size() << " elements.\r" << std::flush);
            }

            std::sort(d.begin(), d.end());

            r.meanNormalizedDistance = std::accumulate(d.begin(), d.end(), 0.f) / (float)(d.size());
            r.medianNormalizedDistance = (d.size() % 2 == 0) ? d[d.size() / 2] : (d[d.size()/2-1] + d[d.size()/2]) * 0.5f;

            float var = 0.f;
            for (size_t i = 0; i < d.size(); ++i) {
                var += (d[i] - r.meanNormalizedDistance) * (d[i] - r.meanNormalizedDistance);
            }
            r.stddevNormalizedDistance = std::sqrt(var / (float)(d.size()));

            r.worstNormalizedDistance = d.back();

            return r;
        }

    }
}
<commit_msg>Added missing include.<commit_after>/**
    This file is part of Deformable Shape Tracking (DEST).

    Copyright(C) 2015/2016 Christoph Heindl
    All rights reserved.

    This software may be modified and distributed under the terms
    of the BSD license.See the LICENSE file for details.
*/

#include <dest/core/tester.h>
#include <dest/util/log.h>
#include <numeric>

namespace dest {
    namespace core {

        ConstantDistanceNormalizer::ConstantDistanceNormalizer(float c)
        :_c(c)
        {}

        float ConstantDistanceNormalizer::operator()(const SampleData::Sample &s) const {
            return _c;
        }

        LandmarkDistanceNormalizer::LandmarkDistanceNormalizer(int landmarkId0, int landmarkId1)
        :_l0(landmarkId0), _l1(landmarkId1)
        {}

        LandmarkDistanceNormalizer::LandmarkDistanceNormalizer()
        :_l0(0), _l1(0)
        {}

        float LandmarkDistanceNormalizer::operator()(const SampleData::Sample &s) const {
            return 1.f / (s.target.col(_l0) - s.target.col(_l1)).norm();
        }

        LandmarkDistanceNormalizer LandmarkDistanceNormalizer::createInterocularNormalizerIBug() {
            /*  The average point-to-point Euclidean error normalized by the inter-ocular distance
                (measured as the Euclidean distance between the outer corners of the eyes) will be
                used as the error measure.
                See http://ibug.doc.ic.ac.uk/resources/300-W/
             */
            return LandmarkDistanceNormalizer(36, 45);
        }

        LandmarkDistanceNormalizer LandmarkDistanceNormalizer::createInterocularNormalizerIMM() {
            // http://doi.ieeecomputersociety.org/cms/Computer.org/dl/trans/tp/2008/03/figures/ttp20080305411.gif
            return LandmarkDistanceNormalizer(21, 13);
        }

        TestResult testTracker(SampleData &td, const Tracker &t, const DistanceNormalizer &norm) {
            TestResult r;
            r.meanNormalizedDistance = 0.f;
            r.medianNormalizedDistance = 0.f;
            r.stddevNormalizedDistance = 0.f;
            r.worstNormalizedDistance = 0.f;

            const int nLandmarks = static_cast<int>(td.samples.front().target.cols());
            std::vector<float> d;

            for (size_t i = 0; i < td.samples.size(); ++i) {

                dest::core::Shape estimateInImageSpace = t.predict(td.input->images[td.samples[i].inputIdx], td.samples[i].shapeToImage);
                td.samples[i].estimate = td.samples[i].shapeToImage.inverse() * estimateInImageSpace.colwise().homogeneous();

                const float normalizer = norm(td.samples[i]);
                Eigen::VectorXf dev = (td.samples[i].target - td.samples[i].estimate).colwise().norm() * normalizer;
                for (int j  = 0; j < nLandmarks; ++j) {
                    if (dev(j) > 1.9f)
                        std::cout << i << std::endl;
                    d.push_back(dev(j));
                }

                if (i % 100 == 0)
                    DEST_LOG("Processing " << i << "/" << td.samples.size() << " elements.\r" << std::flush);
            }

            std::sort(d.begin(), d.end());

            r.meanNormalizedDistance = std::accumulate(d.begin(), d.end(), 0.f) / (float)(d.size());
            r.medianNormalizedDistance = (d.size() % 2 == 0) ? d[d.size() / 2] : (d[d.size()/2-1] + d[d.size()/2]) * 0.5f;

            float var = 0.f;
            for (size_t i = 0; i < d.size(); ++i) {
                var += (d[i] - r.meanNormalizedDistance) * (d[i] - r.meanNormalizedDistance);
            }
            r.stddevNormalizedDistance = std::sqrt(var / (float)(d.size()));

            r.worstNormalizedDistance = d.back();

            return r;
        }

    }
}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes
#include <ctime>
#include <iomanip>
#include <iostream>
#include <sstream>

// Local includes
#include "libmesh/postscript_io.h"
#include "libmesh/mesh_tools.h"
#include "libmesh/elem.h"

namespace libMesh
{

// Transformation map between monomial (physical space) and Bezier bases.
const float PostscriptIO::_bezier_transform[3][3] =
{
  {-1./6., 1./6.,    1.},
  {-1./6.,   0.5, 1./6.},
  {    0.,    1.,    0.}
};

PostscriptIO::PostscriptIO (const MeshBase& mesh)
  : MeshOutput<MeshBase> (mesh),
    shade_value(0.0),
    line_width(0.5),
    //_M(3,3),
    _offset(0., 0.),
    _scale(1.0),
    _current_point(0., 0.)
{
  // This code is still undergoing some development.
  libmesh_experimental();

  // Entries of transformation matrix from physical to Bezier coords.
  // _M(0,0) = -1./6.;    _M(0,1) = 1./6.;    _M(0,2) = 1.;
  // _M(1,0) = -1./6.;    _M(1,1) = 0.5  ;    _M(1,2) = 1./6.;
  // _M(2,0) = 0.    ;    _M(2,1) = 1.   ;    _M(2,2) = 0.;

  // Make sure there is enough room to store Bezier coefficients.
  _bezier_coeffs.resize(3);
}

PostscriptIO::~PostscriptIO ()
{
}

void PostscriptIO::write (const std::string& fname)
{
  // We may need to gather a ParallelMesh to output it, making that
  // const qualifier in our constructor a dirty lie
  MeshSerializer serialize(const_cast<MeshBase&>(this->mesh()), !_is_parallel_format);

  if (libMesh::processor_id() == 0)
    {
      // Get a constant reference to the mesh.
      const MeshBase& mesh = MeshOutput<MeshBase>::mesh();

      // Only works in 2D
      libmesh_assert_equal_to (mesh.mesh_dimension(), 2);

      // Create output file stream.
      // _out is now a private member of the class.
      _out.open(fname.c_str());

      // Make sure it opened correctly
      if (!_out.good())
        libmesh_file_error(fname.c_str());

      // The mesh bounding box gives us info about what the
      // Postscript bounding box should be.
      MeshTools::BoundingBox bbox = MeshTools::bounding_box(mesh);

      // Add a little extra padding to the "true" bounding box so
      // that we can still see the boundary
      const Real percent_padding = 0.01;
      const Real dx=bbox.second(0)-bbox.first(0); libmesh_assert_greater (dx, 0.0);
      const Real dy=bbox.second(1)-bbox.first(1); libmesh_assert_greater (dy, 0.0);

      const Real x_min = bbox.first(0)  - percent_padding*dx;
      const Real y_min = bbox.first(1)  - percent_padding*dy;
      const Real x_max = bbox.second(0) + percent_padding*dx;
      const Real y_max = bbox.second(1) + percent_padding*dy;

      // Width of the output as given in postscript units.
      // This usually is given by the strange unit 1/72 inch.
      // A width of 300 represents a size of roughly 10 cm.
      const Real width = 300;
      _scale = width / (x_max-x_min);
      _offset(0) = x_min;
      _offset(1) = y_min;

      // Header writing stuff stolen from Deal.II
      std::time_t  time1= std::time (0);
      std::tm     *time = std::localtime(&time1);
      _out << "%!PS-Adobe-2.0 EPSF-1.2" << '\n'
	//<< "%!PS-Adobe-1.0" << '\n' // Lars' PS version
	  << "%%Filename: " << fname << '\n'
	  << "%%Title: LibMesh Output" << '\n'
	  << "%%Creator: LibMesh: A C++ finite element library" << '\n'
	  << "%%Creation Date: "
	  << time->tm_year+1900 << "/"
	  << time->tm_mon+1 << "/"
	  << time->tm_mday << " - "
	  << time->tm_hour << ":"
	  << std::setw(2) << time->tm_min << ":"
	  << std::setw(2) << time->tm_sec << '\n'
	  << "%%BoundingBox: "
	// lower left corner
	  << "0 0 "
	// upper right corner
	  << static_cast<unsigned int>( rint((x_max-x_min) * _scale ))
	  << ' '
	  << static_cast<unsigned int>( rint((y_max-y_min) * _scale ))
	  << '\n';

      // define some abbreviations to keep
      // the output small:
      // m=move turtle to
      // l=define a line
      // s=set rgb color
      // sg=set gray value
      // lx=close the line and plot the line
      // lf=close the line and fill the interior
      _out << "/m {moveto} bind def"      << '\n'
	  << "/l {lineto} bind def"      << '\n'
	  << "/s {setrgbcolor} bind def" << '\n'
	  << "/sg {setgray} bind def"    << '\n'
	  << "/cs {curveto stroke} bind def" << '\n'
	  << "/lx {lineto closepath stroke} bind def" << '\n'
	  << "/lf {lineto closepath fill} bind def"   << '\n';

      _out << "%%EndProlog" << '\n';
      //	  << '\n';

      // Set line width in the postscript file.
      _out << line_width << " setlinewidth" << '\n';

      // Set line cap and join options
      _out << "1 setlinecap" << '\n';
      _out << "1 setlinejoin" << '\n';

      // allow only five digits for output (instead of the default
      // six); this should suffice even for fine grids, but reduces
      // the file size significantly
      _out << std::setprecision (5);

      // Loop over the active elements, draw lines for the edges.  We
      // draw even quadratic elements with straight sides, i.e. a straight
      // line sits between each pair of vertices.  Also we draw every edge
      // for an element regardless of the fact that it may overlap with
      // another.  This would probably be a useful optimization...
      MeshBase::const_element_iterator       el     = mesh.active_elements_begin();
      const MeshBase::const_element_iterator end_el = mesh.active_elements_end();
      for ( ; el != end_el; ++el)
	{
	  //const Elem* elem = *el;

	  this->plot_linear_elem(*el);
	  //this->plot_quadratic_elem(*el); // Experimental
	}

      // Issue the showpage command, and we're done.
      _out << "showpage" << std::endl;

    } // end if (libMesh::processor_id() == 0)
}

void PostscriptIO::plot_linear_elem(const Elem* elem)
{
  // Clear the string contents.  Yes, this really is how you do that...
  _cell_string.str("");

  // The general strategy is:
  // 1.) Use m  := {moveto} to go to vertex 0.
  // 2.) Use l  := {lineto} commands to draw lines to vertex 1, 2, ... N-1.
  // 3a.) Use lx := {lineto closepath stroke} command at  vertex N to draw the last line.
  // 3b.)     lf := {lineto closepath fill} command to shade the cell just drawn
  // All of our 2D elements' vertices are numbered in counterclockwise order,
  // so we can just draw them in the same order.

  // 1.)
  _current_point = (elem->point(0) - _offset) * _scale;
  _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y
  _cell_string << "m ";

  // 2.)
  const unsigned int nv=elem->n_vertices();
  for (unsigned int v=1; v<nv-1; ++v)
    {
      _current_point = (elem->point(v) - _offset) * _scale;
      _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y
      _cell_string << "l ";
    }

  // 3.)
  _current_point = (elem->point(nv-1) - _offset) * _scale;
  _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y

  // We draw the shaded (interior) parts first, if applicable.
  if (shade_value > 0.0)
    _out << shade_value << " sg " << _cell_string.str() << "lf\n";

  // Draw the black lines (I guess we will always do this)
  _out << "0 sg " << _cell_string.str() << "lx\n";
}

void PostscriptIO::plot_quadratic_elem(const Elem* elem)
{
  for (unsigned int ns=0; ns<elem->n_sides(); ++ns)
    {
      // Build the quadratic side
      AutoPtr<Elem> side = elem->build_side(ns);

      // Be sure it's quadratic (Edge2).  Eventually we could
      // handle cubic elements as well...
      libmesh_assert_equal_to ( side->type(), EDGE3 );

      _out << "0 sg ";

      // Move to the first point on this side.
      _current_point = (side->point(0) - _offset) * _scale;
      _out << _current_point(0) << " " << _current_point(1) << " "; // write x y
      _out << "m ";

      // Compute _bezier_coeffs for this edge.  This fills up
      // the _bezier_coeffs vector.
      this->_compute_edge_bezier_coeffs(side.get());

      // Print curveto path to file
      for (unsigned int i=0; i<_bezier_coeffs.size(); ++i)
	_out << _bezier_coeffs[i](0) << " " << _bezier_coeffs[i](1) << " ";
      _out << " cs\n";
    }
}

void PostscriptIO::_compute_edge_bezier_coeffs(const Elem* elem)
{
  // I only know how to do this for an Edge3!
  libmesh_assert_equal_to (elem->type(), EDGE3);

  // Get x-coordinates into an array, transform them,
  // and repeat for y.
  float
    phys_coords[3] = {0., 0., 0.},
    bez_coords[3]  = {0., 0., 0.};

  for (unsigned int i=0; i<2; ++i)
    {
      // Initialize vectors.  Physical coordinates are initialized
      // by their postscript-scaled values.
      for (unsigned int j=0; j<3; ++j)
	{
	  phys_coords[j] = (elem->point(j)(i) - _offset(i)) * _scale;
	  bez_coords[j] = 0.; // zero out result vector
	}

      // Multiply matrix times vector
      for (unsigned int j=0; j<3; ++j)
	for (unsigned int k=0; k<3; ++k)
	  bez_coords[j] += _bezier_transform[j][k]*phys_coords[k];

      // Store result in _bezier_coeffs
      for (unsigned int j=0; j<3; ++j)
	_bezier_coeffs[j](i) = phys_coords[j];
    }
}

} // namespace libMesh
<commit_msg>Changes in postscript_io.C for -Wshadow.<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes
#include <ctime>
#include <iomanip>
#include <iostream>
#include <sstream>

// Local includes
#include "libmesh/postscript_io.h"
#include "libmesh/mesh_tools.h"
#include "libmesh/elem.h"

namespace libMesh
{

// Transformation map between monomial (physical space) and Bezier bases.
const float PostscriptIO::_bezier_transform[3][3] =
{
  {-1./6., 1./6.,    1.},
  {-1./6.,   0.5, 1./6.},
  {    0.,    1.,    0.}
};

PostscriptIO::PostscriptIO (const MeshBase& mesh_in)
  : MeshOutput<MeshBase> (mesh_in),
    shade_value(0.0),
    line_width(0.5),
    //_M(3,3),
    _offset(0., 0.),
    _scale(1.0),
    _current_point(0., 0.)
{
  // This code is still undergoing some development.
  libmesh_experimental();

  // Entries of transformation matrix from physical to Bezier coords.
  // _M(0,0) = -1./6.;    _M(0,1) = 1./6.;    _M(0,2) = 1.;
  // _M(1,0) = -1./6.;    _M(1,1) = 0.5  ;    _M(1,2) = 1./6.;
  // _M(2,0) = 0.    ;    _M(2,1) = 1.   ;    _M(2,2) = 0.;

  // Make sure there is enough room to store Bezier coefficients.
  _bezier_coeffs.resize(3);
}

PostscriptIO::~PostscriptIO ()
{
}

void PostscriptIO::write (const std::string& fname)
{
  // We may need to gather a ParallelMesh to output it, making that
  // const qualifier in our constructor a dirty lie
  MeshSerializer serialize(const_cast<MeshBase&>(this->mesh()), !_is_parallel_format);

  if (libMesh::processor_id() == 0)
    {
      // Get a constant reference to the mesh.
      const MeshBase& the_mesh = MeshOutput<MeshBase>::mesh();

      // Only works in 2D
      libmesh_assert_equal_to (the_mesh.mesh_dimension(), 2);

      // Create output file stream.
      // _out is now a private member of the class.
      _out.open(fname.c_str());

      // Make sure it opened correctly
      if (!_out.good())
        libmesh_file_error(fname.c_str());

      // The mesh bounding box gives us info about what the
      // Postscript bounding box should be.
      MeshTools::BoundingBox bbox = MeshTools::bounding_box(the_mesh);

      // Add a little extra padding to the "true" bounding box so
      // that we can still see the boundary
      const Real percent_padding = 0.01;
      const Real dx=bbox.second(0)-bbox.first(0); libmesh_assert_greater (dx, 0.0);
      const Real dy=bbox.second(1)-bbox.first(1); libmesh_assert_greater (dy, 0.0);

      const Real x_min = bbox.first(0)  - percent_padding*dx;
      const Real y_min = bbox.first(1)  - percent_padding*dy;
      const Real x_max = bbox.second(0) + percent_padding*dx;
      const Real y_max = bbox.second(1) + percent_padding*dy;

      // Width of the output as given in postscript units.
      // This usually is given by the strange unit 1/72 inch.
      // A width of 300 represents a size of roughly 10 cm.
      const Real width = 300;
      _scale = width / (x_max-x_min);
      _offset(0) = x_min;
      _offset(1) = y_min;

      // Header writing stuff stolen from Deal.II
      std::time_t  time1= std::time (0);
      std::tm     *time = std::localtime(&time1);
      _out << "%!PS-Adobe-2.0 EPSF-1.2" << '\n'
	//<< "%!PS-Adobe-1.0" << '\n' // Lars' PS version
	  << "%%Filename: " << fname << '\n'
	  << "%%Title: LibMesh Output" << '\n'
	  << "%%Creator: LibMesh: A C++ finite element library" << '\n'
	  << "%%Creation Date: "
	  << time->tm_year+1900 << "/"
	  << time->tm_mon+1 << "/"
	  << time->tm_mday << " - "
	  << time->tm_hour << ":"
	  << std::setw(2) << time->tm_min << ":"
	  << std::setw(2) << time->tm_sec << '\n'
	  << "%%BoundingBox: "
	// lower left corner
	  << "0 0 "
	// upper right corner
	  << static_cast<unsigned int>( rint((x_max-x_min) * _scale ))
	  << ' '
	  << static_cast<unsigned int>( rint((y_max-y_min) * _scale ))
	  << '\n';

      // define some abbreviations to keep
      // the output small:
      // m=move turtle to
      // l=define a line
      // s=set rgb color
      // sg=set gray value
      // lx=close the line and plot the line
      // lf=close the line and fill the interior
      _out << "/m {moveto} bind def"      << '\n'
	  << "/l {lineto} bind def"      << '\n'
	  << "/s {setrgbcolor} bind def" << '\n'
	  << "/sg {setgray} bind def"    << '\n'
	  << "/cs {curveto stroke} bind def" << '\n'
	  << "/lx {lineto closepath stroke} bind def" << '\n'
	  << "/lf {lineto closepath fill} bind def"   << '\n';

      _out << "%%EndProlog" << '\n';
      //	  << '\n';

      // Set line width in the postscript file.
      _out << line_width << " setlinewidth" << '\n';

      // Set line cap and join options
      _out << "1 setlinecap" << '\n';
      _out << "1 setlinejoin" << '\n';

      // allow only five digits for output (instead of the default
      // six); this should suffice even for fine grids, but reduces
      // the file size significantly
      _out << std::setprecision (5);

      // Loop over the active elements, draw lines for the edges.  We
      // draw even quadratic elements with straight sides, i.e. a straight
      // line sits between each pair of vertices.  Also we draw every edge
      // for an element regardless of the fact that it may overlap with
      // another.  This would probably be a useful optimization...
      MeshBase::const_element_iterator       el     = the_mesh.active_elements_begin();
      const MeshBase::const_element_iterator end_el = the_mesh.active_elements_end();
      for ( ; el != end_el; ++el)
	{
	  //const Elem* elem = *el;

	  this->plot_linear_elem(*el);
	  //this->plot_quadratic_elem(*el); // Experimental
	}

      // Issue the showpage command, and we're done.
      _out << "showpage" << std::endl;

    } // end if (libMesh::processor_id() == 0)
}

void PostscriptIO::plot_linear_elem(const Elem* elem)
{
  // Clear the string contents.  Yes, this really is how you do that...
  _cell_string.str("");

  // The general strategy is:
  // 1.) Use m  := {moveto} to go to vertex 0.
  // 2.) Use l  := {lineto} commands to draw lines to vertex 1, 2, ... N-1.
  // 3a.) Use lx := {lineto closepath stroke} command at  vertex N to draw the last line.
  // 3b.)     lf := {lineto closepath fill} command to shade the cell just drawn
  // All of our 2D elements' vertices are numbered in counterclockwise order,
  // so we can just draw them in the same order.

  // 1.)
  _current_point = (elem->point(0) - _offset) * _scale;
  _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y
  _cell_string << "m ";

  // 2.)
  const unsigned int nv=elem->n_vertices();
  for (unsigned int v=1; v<nv-1; ++v)
    {
      _current_point = (elem->point(v) - _offset) * _scale;
      _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y
      _cell_string << "l ";
    }

  // 3.)
  _current_point = (elem->point(nv-1) - _offset) * _scale;
  _cell_string << _current_point(0) << " " << _current_point(1) << " "; // write x y

  // We draw the shaded (interior) parts first, if applicable.
  if (shade_value > 0.0)
    _out << shade_value << " sg " << _cell_string.str() << "lf\n";

  // Draw the black lines (I guess we will always do this)
  _out << "0 sg " << _cell_string.str() << "lx\n";
}

void PostscriptIO::plot_quadratic_elem(const Elem* elem)
{
  for (unsigned int ns=0; ns<elem->n_sides(); ++ns)
    {
      // Build the quadratic side
      AutoPtr<Elem> side = elem->build_side(ns);

      // Be sure it's quadratic (Edge2).  Eventually we could
      // handle cubic elements as well...
      libmesh_assert_equal_to ( side->type(), EDGE3 );

      _out << "0 sg ";

      // Move to the first point on this side.
      _current_point = (side->point(0) - _offset) * _scale;
      _out << _current_point(0) << " " << _current_point(1) << " "; // write x y
      _out << "m ";

      // Compute _bezier_coeffs for this edge.  This fills up
      // the _bezier_coeffs vector.
      this->_compute_edge_bezier_coeffs(side.get());

      // Print curveto path to file
      for (unsigned int i=0; i<_bezier_coeffs.size(); ++i)
	_out << _bezier_coeffs[i](0) << " " << _bezier_coeffs[i](1) << " ";
      _out << " cs\n";
    }
}

void PostscriptIO::_compute_edge_bezier_coeffs(const Elem* elem)
{
  // I only know how to do this for an Edge3!
  libmesh_assert_equal_to (elem->type(), EDGE3);

  // Get x-coordinates into an array, transform them,
  // and repeat for y.
  float
    phys_coords[3] = {0., 0., 0.},
    bez_coords[3]  = {0., 0., 0.};

  for (unsigned int i=0; i<2; ++i)
    {
      // Initialize vectors.  Physical coordinates are initialized
      // by their postscript-scaled values.
      for (unsigned int j=0; j<3; ++j)
	{
	  phys_coords[j] = (elem->point(j)(i) - _offset(i)) * _scale;
	  bez_coords[j] = 0.; // zero out result vector
	}

      // Multiply matrix times vector
      for (unsigned int j=0; j<3; ++j)
	for (unsigned int k=0; k<3; ++k)
	  bez_coords[j] += _bezier_transform[j][k]*phys_coords[k];

      // Store result in _bezier_coeffs
      for (unsigned int j=0; j<3; ++j)
	_bezier_coeffs[j](i) = phys_coords[j];
    }
}

} // namespace libMesh
<|endoftext|>