<commit_before>#include "scriptparser.hpp"

//----------------------------------------------------------
ScriptParser::ScriptParser()
{

}

//----------------------------------------------------------
ScriptParser::ScriptParser(const yampt::rec_type type,
                           DictMerger &merger,
                           const std::string &prefix,
                           const std::string &friendly_text,
                           const std::string &compiled_data)
    : type(type),
      merger(&merger),
      prefix(prefix),
      friendly_text(friendly_text),
      compiled_data(compiled_data),
      pos_in_compiled(0)
{
    convertScript();
    stripLastNewLineChars();
}

//----------------------------------------------------------
void ScriptParser::convertScript()
{
    std::istringstream ss(friendly_text);
    std::string line;
    std::string line_lc;
    std::string new_line;

    while(std::getline(ss, line))
    {
        is_done = false;
        line = tools.eraseCarriageReturnChar(line);
        line_lc = line;
        transform(line_lc.begin(), line_lc.end(),
                  line_lc.begin(), ::tolower);

        if(is_done == false)
        {
            new_line = checkLine(line, line_lc, "addtopic", 0, yampt::rec_type::DIAL, false);
        }
        if(is_done == false)
        {
            new_line = checkLine(line, line_lc, "showmap", 0, yampt::rec_type::CELL, false);
        }
        if(is_done == false)
        {
            new_line = checkLine(line, line_lc, "centeroncell", 0, yampt::rec_type::CELL, false);
        }
        if(is_done == false)
        {
            new_line = checkLine(line, line_lc, "getpccell", 0, yampt::rec_type::CELL, true);
        }
        if(is_done == false)
        {
            new_line = checkLine(line, line_lc, "aifollowcell", 1, yampt::rec_type::CELL, false);
        }
        if(is_done == false)
        {
            new_line = checkLine(line, line_lc, "aiescortcell", 1, yampt::rec_type::CELL, false);
        }
        if(is_done == false)
        {
            new_line = checkLine(line, line_lc, "placeitemcell", 1, yampt::rec_type::CELL, false);
        }
        if(is_done == false)
        {
            new_line = checkLine(line, line_lc, "positioncell", 4, yampt::rec_type::CELL, false);
        }
        if(is_done == false)
        {
            new_line = checkLine(line, line_lc);
        }
        new_friendly += new_line + "\r\n";
    }
}

//----------------------------------------------------------
void ScriptParser::stripLastNewLineChars()
{
    // Check if last 2 chars are newline and strip them if necessary
    size_t last_nl_pos = friendly_text.rfind("\r\n");
    if(last_nl_pos != friendly_text.size() - 2 ||
       last_nl_pos == std::string::npos)
    {
        new_friendly.resize(new_friendly.size() - 2);
    }
}

//----------------------------------------------------------
std::string ScriptParser::checkLine(const std::string &line,
                                    const std::string &line_lc)
{
    std::string new_line = line;
    std::map<size_t, std::string> keyword_pos_coll;
    std::string keyword;
    size_t keyword_pos;

    // Create keyword collection from first to last occurrence in line
    for(size_t i = 0; i < yampt::keyword_list.size(); ++i)
    {
        keyword_pos = line_lc.find(yampt::keyword_list[i]);
        keyword_pos_coll.insert({keyword_pos, yampt::keyword_list[i]});
    }

    keyword = keyword_pos_coll.begin()->second;
    keyword_pos = keyword_pos_coll.begin()->first;

    if(keyword_pos != std::string::npos &&
       line.rfind(";", keyword_pos) == std::string::npos &&
       line.find("\"", keyword_pos) != std::string::npos) // Convert only if message line is valid
    {
        DEBUG_MSG("---");
        DEBUG_MSG("Old line: " << line);
        new_line = convertLine(line);
        DEBUG_MSG("New line: " << new_line);
        if (!compiled_data.empty())
        {
            if (keyword == "say " ||
                keyword == "say,")
            {
                convertLineInCompiledScriptData(line, new_line, keyword_pos, true);
            }
            else if (keyword == "messagebox" ||
                keyword == "choice")
            {
                convertLineInCompiledScriptData(line, new_line, keyword_pos, false);
            }
        }
        is_done = true;
    }

    return new_line;
}

//----------------------------------------------------------
std::string ScriptParser::checkLine(const std::string &line,
                                    const std::string &line_lc,
                                    const std::string &keyword,
                                    const int pos_in_expression,
                                    const yampt::rec_type text_type,
                                    const bool is_getpccell)
{
    std::string new_line = line;
    std::pair<std::string, size_t> extracted;
    std::string new_text;
    size_t keyword_pos = line_lc.find(keyword);

    if(keyword_pos != std::string::npos &&
       line.rfind(";", keyword_pos) == std::string::npos)
    {
        DEBUG_MSG("---");
        DEBUG_MSG("Old line: " << line);
        DEBUG_MSG("Extraction:");
        extracted = extractInnerTextFromLine(line, keyword_pos, pos_in_expression);

        // Convert only if extracted text is valid
        if(extracted.second != std::string::npos)
        {
            new_text = findInnerTextInDict(extracted.first, text_type);
            DEBUG_MSG("Found: " << new_text);
            new_line = convertInnerTextInLine(line, extracted.first, extracted.second, new_text);
            DEBUG_MSG("New line: " << new_line);
            if (!compiled_data.empty())
            {
                convertInnerTextInCompiledScriptData(extracted.first, new_text, is_getpccell);
            }
        }
        is_done = true;
    }
    return new_line;
}

//----------------------------------------------------------
std::string ScriptParser::convertLine(const std::string &line)
{
    std::string new_line = line;
    auto search = merger->getDict(type).find(prefix + line);
    if(search != merger->getDict(type).end())
    {
        if(line != search->second.substr(prefix.size()))
        {
            new_line = search->second.substr(prefix.size());
        }
    }
    return new_line;
}

//----------------------------------------------------------
std::string ScriptParser::findInnerTextInDict(const std::string &text,
                                              const yampt::rec_type text_type)
{
    // Fast search in map
    auto search = merger->getDict(text_type).find(text);
    if(search != merger->getDict(text_type).end())
    {
        return search->second;
    }
    else // Slow search case aware
    {
        for(auto &elem : merger->getDict(text_type))
        {
            if(tools.caseInsensitiveStringCmp(text, elem.first) == true)
            {
                return elem.second;
            }
        }
    }
    return text;
}

//----------------------------------------------------------
std::string ScriptParser::convertInnerTextInLine(const std::string &line,
                                                 const std::string &text,
                                                 const size_t text_pos,
                                                 const std::string &new_text)
{
    std::string new_line = line;
    new_line.erase(text_pos, text.size());
    if(new_line.substr(text_pos - 1, 1) == "\"")
    {
        new_line.insert(text_pos, new_text);
    }
    else
    {
        new_line.insert(text_pos, "\"" + new_text + "\"");
    }
    return new_line;
}

//----------------------------------------------------------
void ScriptParser::convertLineInCompiledScriptData(const std::string &line,
                                                   const std::string &new_line,
                                                   const size_t keyword_pos,
                                                   const bool is_say)
{
    std::vector<std::string> splitted_line = splitLine(line, keyword_pos, is_say);
    std::vector<std::string> splitted_new_line = splitLine(new_line, keyword_pos, is_say);

    if(splitted_line.size() == splitted_new_line.size())
    {
        for(size_t i = 0; i < splitted_line.size(); i++)
        {
            pos_in_compiled = compiled_data.find(splitted_line[i], pos_in_compiled);
            if(pos_in_compiled != std::string::npos)
            {
                if(i == 0)
                {
                    pos_in_compiled -= 2;
                    compiled_data.erase(pos_in_compiled, 2);
                    compiled_data.insert(pos_in_compiled, tools.convertUIntToStringByteArray(splitted_new_line[i].size()).substr(0, 2));
                    pos_in_compiled += 2;
                    compiled_data.erase(pos_in_compiled, splitted_line[i].size());
                    compiled_data.insert(pos_in_compiled, splitted_new_line[i]);
                    pos_in_compiled += splitted_new_line[i].size();
                }
                else
                {
                    pos_in_compiled -= 1;
                    compiled_data.erase(pos_in_compiled, 1);
                    compiled_data.insert(pos_in_compiled, tools.convertUIntToStringByteArray(splitted_new_line[i].size() + 1).substr(0, 1));
                    pos_in_compiled += 1;
                    compiled_data.erase(pos_in_compiled, splitted_line[i].size());
                    compiled_data.insert(pos_in_compiled, splitted_new_line[i]);
                    pos_in_compiled += splitted_new_line[i].size();
                }
            }
        }
    }
}

//----------------------------------------------------------
void ScriptParser::convertInnerTextInCompiledScriptData(const std::string &text,
                                                        const std::string &new_text,
                                                        const bool is_getpccell)
{
    pos_in_compiled = compiled_data.find(text, pos_in_compiled);
    if(pos_in_compiled != std::string::npos)
    {
        pos_in_compiled -= 1;
        compiled_data.erase(pos_in_compiled, 1);
        compiled_data.insert(pos_in_compiled, tools.convertUIntToStringByteArray(new_text.size()).substr(0, 1));
        pos_in_compiled += 1;
        compiled_data.erase(pos_in_compiled, text.size());
        compiled_data.insert(pos_in_compiled, new_text);

        if(is_getpccell == true)
        {
            // Additional GETPCCELL size byte determines
            // how many bytes from that byte to the end of expression
            size_t end_of_expr;
            size_t expr_size;

            if(compiled_data.substr(pos_in_compiled + new_text.size(), 1) != " ")
            {
                // If expression ends exactly when inner text ends
                end_of_expr = pos_in_compiled + new_text.size();
                pos_in_compiled = compiled_data.rfind('X', pos_in_compiled) - 2;
                expr_size = end_of_expr - pos_in_compiled;
            }
            else
            {
                // If expression ends with equals or inequal signs
                end_of_expr = pos_in_compiled + new_text.size() + 5; // +5 because of " == 1" size
                pos_in_compiled = compiled_data.rfind('X', pos_in_compiled) - 2;
                expr_size = end_of_expr - pos_in_compiled - 1;
            }

            compiled_data.erase(pos_in_compiled, 1);
            compiled_data.insert(pos_in_compiled, tools.convertUIntToStringByteArray(expr_size).substr(0, 1));
            pos_in_compiled += expr_size;
        }
        else
        {
            pos_in_compiled += new_text.size();
        }
    }
}

//----------------------------------------------------------
std::pair<std::string, size_t> ScriptParser::extractInnerTextFromLine(const std::string &line,
                                                                      const size_t keyword_pos,
                                                                      const int pos_in_expression)
{
    size_t cur_pos = keyword_pos;
    std::string cur_text;

    std::smatch found;
    int ctr = -1;

    // Find begin of searched inner text
    cur_pos = line.find_first_of(" \t,\"", cur_pos);
    cur_pos = line.find_first_not_of(" \t,", cur_pos);
    if(cur_pos != std::string::npos)
    {
        cur_text = line.substr(cur_pos);
    }
    else
    {
        // If begin of searched text not found
        // or keyword was found inside other string
        // e.g. name of the script
        cur_text = "Inner text not found!";
    }

    DEBUG_MSG("\tStep 1: " << cur_text);

    if(pos_in_expression == 0)
    {
        // Find end of searched text if keyword is not in quotes
        // Strip whitespaces
        if(cur_text.find_last_not_of(" \t") != std::string::npos)
        {
            cur_text.erase(cur_text.find_last_not_of(" \t") + 1);
        }
    }
    else
    {
        // Usually all searched texts are in quotes, but other variables don't
        std::regex r1("(([\\w\\.]+)|(\".*?\"))", std::regex::optimize);
        std::sregex_iterator next(cur_text.begin(), cur_text.end(), r1);
        std::sregex_iterator end;
        while(next != end && ctr != pos_in_expression)
        {
            found = *next;
            next++;
            ctr++;
        }
        cur_text = found[1].str();
        cur_pos = found.position(1) + cur_pos;
    }

    DEBUG_MSG("\tStep 2: " << cur_text);

    // Strip quotes if exist
    std::regex r2("\"(.*?)\"", std::regex::optimize);
    std::regex_search(cur_text, found, r2);
    if(!found.empty())
    {
        cur_text = found[1].str();
        cur_pos += 1;
    }

    DEBUG_MSG("\tStep 3: " << cur_text);

    return std::make_pair(cur_text, cur_pos);
}

//----------------------------------------------------------
std::vector<std::string> ScriptParser::splitLine(const std::string &line,
                                                 const size_t keyword_pos,
                                                 const bool is_say)
{
    // We only need parameters after keyword
    std::string cur_line = line.substr(keyword_pos);
    std::vector<std::string> splitted_line;
    std::smatch found;
    std::regex re("\"(.*?)\"", std::regex::optimize);
    std::sregex_iterator next(cur_line.begin(), cur_line.end(), re);
    std::sregex_iterator end;
    while(next != end)
    {
        found = *next;
        splitted_line.push_back(found[1].str());
        next++;
    }

    // Special case if SAY keyword
    // First parameter is sound file name, so we don't need it
    if(is_say == true && splitted_line.size() > 0)
    {
        splitted_line.erase(splitted_line.begin());
    }

    return splitted_line;
}
<commit_msg>reformat<commit_after>#include "scriptparser.hpp"

//----------------------------------------------------------
ScriptParser::ScriptParser()
{

}

//----------------------------------------------------------
ScriptParser::ScriptParser(
    const yampt::rec_type type,
    DictMerger & merger,
    const std::string & prefix,
    const std::string & friendly_text,
    const std::string & compiled_data
)
    : type(type)
    , merger(&merger)
    , prefix(prefix)
    , friendly_text(friendly_text)
    , compiled_data(compiled_data)
    , pos_in_compiled(0)
{
    convertScript();
    stripLastNewLineChars();
}

//----------------------------------------------------------
void ScriptParser::convertScript()
{
    std::istringstream ss(friendly_text);
    std::string line;
    std::string line_lc;
    std::string new_line;

    while (std::getline(ss, line))
    {
        is_done = false;
        line = tools.eraseCarriageReturnChar(line);
        line_lc = line;
        transform(line_lc.begin(), line_lc.end(),
            line_lc.begin(), ::tolower);

        if (is_done == false)
        {
            new_line = checkLine(line, line_lc, "addtopic", 0, yampt::rec_type::DIAL, false);
        }
        if (is_done == false)
        {
            new_line = checkLine(line, line_lc, "showmap", 0, yampt::rec_type::CELL, false);
        }
        if (is_done == false)
        {
            new_line = checkLine(line, line_lc, "centeroncell", 0, yampt::rec_type::CELL, false);
        }
        if (is_done == false)
        {
            new_line = checkLine(line, line_lc, "getpccell", 0, yampt::rec_type::CELL, true);
        }
        if (is_done == false)
        {
            new_line = checkLine(line, line_lc, "aifollowcell", 1, yampt::rec_type::CELL, false);
        }
        if (is_done == false)
        {
            new_line = checkLine(line, line_lc, "aiescortcell", 1, yampt::rec_type::CELL, false);
        }
        if (is_done == false)
        {
            new_line = checkLine(line, line_lc, "placeitemcell", 1, yampt::rec_type::CELL, false);
        }
        if (is_done == false)
        {
            new_line = checkLine(line, line_lc, "positioncell", 4, yampt::rec_type::CELL, false);
        }
        if (is_done == false)
        {
            new_line = checkLine(line, line_lc);
        }
        new_friendly += new_line + "\r\n";
    }
}

//----------------------------------------------------------
void ScriptParser::stripLastNewLineChars()
{
    // Check if last 2 chars are newline and strip them if necessary
    size_t last_nl_pos = friendly_text.rfind("\r\n");
    if (last_nl_pos != friendly_text.size() - 2 ||
        last_nl_pos == std::string::npos)
    {
        new_friendly.resize(new_friendly.size() - 2);
    }
}

//----------------------------------------------------------
std::string ScriptParser::checkLine(
    const std::string & line,
    const std::string & line_lc)
{
    std::string new_line = line;
    std::map<size_t, std::string> keyword_pos_coll;
    std::string keyword;
    size_t keyword_pos;

    // Create keyword collection from first to last occurrence in line
    for (size_t i = 0; i < yampt::keyword_list.size(); ++i)
    {
        keyword_pos = line_lc.find(yampt::keyword_list[i]);
        keyword_pos_coll.insert({ keyword_pos, yampt::keyword_list[i] });
    }

    keyword = keyword_pos_coll.begin()->second;
    keyword_pos = keyword_pos_coll.begin()->first;

    if (keyword_pos != std::string::npos &&
        line.rfind(";", keyword_pos) == std::string::npos &&
        line.find("\"", keyword_pos) != std::string::npos) // Convert only if message line is valid
    {
        DEBUG_MSG("---");
        DEBUG_MSG("Old line: " << line);
        new_line = convertLine(line);
        DEBUG_MSG("New line: " << new_line);
        if (!compiled_data.empty())
        {
            if (keyword == "say " ||
                keyword == "say,")
            {
                convertLineInCompiledScriptData(line, new_line, keyword_pos, true);
            }
            else if (keyword == "messagebox" ||
                keyword == "choice")
            {
                convertLineInCompiledScriptData(line, new_line, keyword_pos, false);
            }
        }
        is_done = true;
    }

    return new_line;
}

//----------------------------------------------------------
std::string ScriptParser::checkLine(
    const std::string & line,
    const std::string & line_lc,
    const std::string & keyword,
    const int pos_in_expression,
    const yampt::rec_type text_type,
    const bool is_getpccell)
{
    std::string new_line = line;
    std::pair<std::string, size_t> extracted;
    std::string new_text;
    size_t keyword_pos = line_lc.find(keyword);

    if (keyword_pos != std::string::npos &&
        line.rfind(";", keyword_pos) == std::string::npos)
    {
        DEBUG_MSG("---");
        DEBUG_MSG("Old line: " << line);
        DEBUG_MSG("Extraction:");
        extracted = extractInnerTextFromLine(line, keyword_pos, pos_in_expression);

        // Convert only if extracted text is valid
        if (extracted.second != std::string::npos)
        {
            new_text = findInnerTextInDict(extracted.first, text_type);
            DEBUG_MSG("Found: " << new_text);
            new_line = convertInnerTextInLine(line, extracted.first, extracted.second, new_text);
            DEBUG_MSG("New line: " << new_line);
            if (!compiled_data.empty())
            {
                convertInnerTextInCompiledScriptData(extracted.first, new_text, is_getpccell);
            }
        }
        is_done = true;
    }
    return new_line;
}

//----------------------------------------------------------
std::string ScriptParser::convertLine(const std::string & line)
{
    std::string new_line = line;
    auto search = merger->getDict(type).find(prefix + line);
    if (search != merger->getDict(type).end())
    {
        if (line != search->second.substr(prefix.size()))
        {
            new_line = search->second.substr(prefix.size());
        }
    }
    return new_line;
}

//----------------------------------------------------------
std::string ScriptParser::findInnerTextInDict(
    const std::string & text,
    const yampt::rec_type text_type)
{
    // Fast search in map
    auto search = merger->getDict(text_type).find(text);
    if (search != merger->getDict(text_type).end())
    {
        return search->second;
    }
    else // Slow search case aware
    {
        for (auto & elem : merger->getDict(text_type))
        {
            if (tools.caseInsensitiveStringCmp(text, elem.first) == true)
            {
                return elem.second;
            }
        }
    }
    return text;
}

//----------------------------------------------------------
std::string ScriptParser::convertInnerTextInLine(
    const std::string & line,
    const std::string & text,
    const size_t text_pos,
    const std::string & new_text)
{
    std::string new_line = line;
    new_line.erase(text_pos, text.size());
    if (new_line.substr(text_pos - 1, 1) == "\"")
    {
        new_line.insert(text_pos, new_text);
    }
    else
    {
        new_line.insert(text_pos, "\"" + new_text + "\"");
    }
    return new_line;
}

//----------------------------------------------------------
void ScriptParser::convertLineInCompiledScriptData(
    const std::string & line,
    const std::string & new_line,
    const size_t keyword_pos,
    const bool is_say)
{
    std::vector<std::string> splitted_line = splitLine(line, keyword_pos, is_say);
    std::vector<std::string> splitted_new_line = splitLine(new_line, keyword_pos, is_say);

    if (splitted_line.size() == splitted_new_line.size())
    {
        for (size_t i = 0; i < splitted_line.size(); i++)
        {
            pos_in_compiled = compiled_data.find(splitted_line[i], pos_in_compiled);
            if (pos_in_compiled != std::string::npos)
            {
                if (i == 0)
                {
                    pos_in_compiled -= 2;
                    compiled_data.erase(pos_in_compiled, 2);
                    compiled_data.insert(pos_in_compiled, tools.convertUIntToStringByteArray(splitted_new_line[i].size()).substr(0, 2));
                    pos_in_compiled += 2;
                    compiled_data.erase(pos_in_compiled, splitted_line[i].size());
                    compiled_data.insert(pos_in_compiled, splitted_new_line[i]);
                    pos_in_compiled += splitted_new_line[i].size();
                }
                else
                {
                    pos_in_compiled -= 1;
                    compiled_data.erase(pos_in_compiled, 1);
                    compiled_data.insert(pos_in_compiled, tools.convertUIntToStringByteArray(splitted_new_line[i].size() + 1).substr(0, 1));
                    pos_in_compiled += 1;
                    compiled_data.erase(pos_in_compiled, splitted_line[i].size());
                    compiled_data.insert(pos_in_compiled, splitted_new_line[i]);
                    pos_in_compiled += splitted_new_line[i].size();
                }
            }
        }
    }
}

//----------------------------------------------------------
void ScriptParser::convertInnerTextInCompiledScriptData(
    const std::string & text,
    const std::string & new_text,
    const bool is_getpccell)
{
    pos_in_compiled = compiled_data.find(text, pos_in_compiled);
    if (pos_in_compiled != std::string::npos)
    {
        pos_in_compiled -= 1;
        compiled_data.erase(pos_in_compiled, 1);
        compiled_data.insert(pos_in_compiled, tools.convertUIntToStringByteArray(new_text.size()).substr(0, 1));
        pos_in_compiled += 1;
        compiled_data.erase(pos_in_compiled, text.size());
        compiled_data.insert(pos_in_compiled, new_text);

        if (is_getpccell == true)
        {
            // Additional GETPCCELL size byte determines
            // how many bytes from that byte to the end of expression
            size_t end_of_expr;
            size_t expr_size;

            if (compiled_data.substr(pos_in_compiled + new_text.size(), 1) != " ")
            {
                // If expression ends exactly when inner text ends
                end_of_expr = pos_in_compiled + new_text.size();
                pos_in_compiled = compiled_data.rfind('X', pos_in_compiled) - 2;
                expr_size = end_of_expr - pos_in_compiled;
            }
            else
            {
                // If expression ends with equals or inequal signs
                end_of_expr = pos_in_compiled + new_text.size() + 5; // +5 because of " == 1" size
                pos_in_compiled = compiled_data.rfind('X', pos_in_compiled) - 2;
                expr_size = end_of_expr - pos_in_compiled - 1;
            }

            compiled_data.erase(pos_in_compiled, 1);
            compiled_data.insert(pos_in_compiled, tools.convertUIntToStringByteArray(expr_size).substr(0, 1));
            pos_in_compiled += expr_size;
        }
        else
        {
            pos_in_compiled += new_text.size();
        }
    }
}

//----------------------------------------------------------
std::pair<std::string, size_t> ScriptParser::extractInnerTextFromLine(
    const std::string & line,
    const size_t keyword_pos,
    const int pos_in_expression)
{
    size_t cur_pos = keyword_pos;
    std::string cur_text;

    std::smatch found;
    int ctr = -1;

    // Find begin of searched inner text
    cur_pos = line.find_first_of(" \t,\"", cur_pos);
    cur_pos = line.find_first_not_of(" \t,", cur_pos);
    if (cur_pos != std::string::npos)
    {
        cur_text = line.substr(cur_pos);
    }
    else
    {
        // If begin of searched text not found
        // or keyword was found inside other string
        // e.g. name of the script
        cur_text = "Inner text not found!";
    }

    DEBUG_MSG("\tStep 1: " << cur_text);

    if (pos_in_expression == 0)
    {
        // Find end of searched text if keyword is not in quotes
        // Strip whitespaces
        if (cur_text.find_last_not_of(" \t") != std::string::npos)
        {
            cur_text.erase(cur_text.find_last_not_of(" \t") + 1);
        }
    }
    else
    {
        // Usually all searched texts are in quotes, but other variables don't
        std::regex r1("(([\\w\\.]+)|(\".*?\"))", std::regex::optimize);
        std::sregex_iterator next(cur_text.begin(), cur_text.end(), r1);
        std::sregex_iterator end;
        while (next != end && ctr != pos_in_expression)
        {
            found = *next;
            next++;
            ctr++;
        }
        cur_text = found[1].str();
        cur_pos = found.position(1) + cur_pos;
    }

    DEBUG_MSG("\tStep 2: " << cur_text);

    // Strip quotes if exist
    std::regex r2("\"(.*?)\"", std::regex::optimize);
    std::regex_search(cur_text, found, r2);
    if (!found.empty())
    {
        cur_text = found[1].str();
        cur_pos += 1;
    }

    DEBUG_MSG("\tStep 3: " << cur_text);

    return std::make_pair(cur_text, cur_pos);
}

//----------------------------------------------------------
std::vector<std::string> ScriptParser::splitLine(
    const std::string & line,
    const size_t keyword_pos,
    const bool is_say)
{
    // We only need parameters after keyword
    std::string cur_line = line.substr(keyword_pos);
    std::vector<std::string> splitted_line;
    std::smatch found;
    std::regex re("\"(.*?)\"", std::regex::optimize);
    std::sregex_iterator next(cur_line.begin(), cur_line.end(), re);
    std::sregex_iterator end;
    while (next != end)
    {
        found = *next;
        splitted_line.push_back(found[1].str());
        next++;
    }

    // Special case if SAY keyword
    // First parameter is sound file name, so we don't need it
    if (is_say == true && splitted_line.size() > 0)
    {
        splitted_line.erase(splitted_line.begin());
    }

    return splitted_line;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef AST_RETURN_H
#define AST_RETURN_H

#include <memory>

#include <boost/intrusive_ptr.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

#include "ast/Deferred.hpp"
#include "ast/Value.hpp"

namespace eddic {

class Context;

namespace ast {

struct ASTReturn {
    Value value;

    mutable long references;
    ASTReturn() : references(0) {}
};

typedef Deferred<ASTReturn, boost::intrusive_ptr<ASTReturn>> Return;

} //end of ast

} //end of eddic

//Adapt the struct for the AST
BOOST_FUSION_ADAPT_STRUCT(
    eddic::ast::Assignment,
    (eddic::ast::Value, Content->value)
)

#endif
<commit_msg>Fix the name of the struct in the struct adaptation<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef AST_RETURN_H
#define AST_RETURN_H

#include <memory>

#include <boost/intrusive_ptr.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

#include "ast/Deferred.hpp"
#include "ast/Value.hpp"

namespace eddic {

class Context;

namespace ast {

struct ASTReturn {
    Value value;

    mutable long references;
    ASTReturn() : references(0) {}
};

typedef Deferred<ASTReturn, boost::intrusive_ptr<ASTReturn>> Return;

} //end of ast

} //end of eddic

//Adapt the struct for the AST
BOOST_FUSION_ADAPT_STRUCT(
    eddic::ast::Return,
    (eddic::ast::Value, Content->value)
)

#endif
<|endoftext|>


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

#include "PreSieve.h"
#include "SieveOfEratosthenes.h"

#include <stdexcept>
#include <cstdlib>
#include <cstring>
#include <cassert>

const uint32_t PreSieve::smallPrimes_[9] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };

/**
 * Pre-sieve multiples of small primes <= limit to speed up the sieve
 * of Eratosthenes.
 * @pre limit >= 11 && limit <= 23
 * @see SieveOfEratosthenes::sieve(uint32_t)
 */
PreSieve::PreSieve(uint32_t limit) : wheelArray_(NULL), size_(0) {
  // limit <= 23 prevents 32 bit overflows
  if (limit < 11 || limit > 23)
    throw std::overflow_error("PreSieve: limit must be >= 11 && <= 23.");
  limit_ = limit;
  primeProduct_ = this->getPrimeProduct(limit_);
  size_ = primeProduct_ / SieveOfEratosthenes::NUMBERS_PER_BYTE;
  this->initWheelArray();
}

PreSieve::~PreSieve() {
  delete[] wheelArray_;
}

uint32_t PreSieve::getPrimeProduct(uint32_t limit) const {
  assert(limit <= 23);
  uint32_t pp = 1;
  for (int i = 0; i < 9 && smallPrimes_[i] <= limit; i++)
    pp *= smallPrimes_[i];
  return pp;
}

/**
 * Allocate the wheelArray_ and remove the multiples of small
 * primes <= limit_ from it.
 */
void PreSieve::initWheelArray() {
  assert(SieveOfEratosthenes::NUMBERS_PER_BYTE == 30);
  assert(size_ > 0);
  const uint32_t unsetBit[30] = {
      BIT0, 0xff, 0xff, 0xff, BIT1, 0xff,
      BIT2, 0xff, 0xff, 0xff, BIT3, 0xff,
      BIT4, 0xff, 0xff, 0xff, BIT5, 0xff,
      0xff, 0xff, 0xff, 0xff, BIT6, 0xff,
      BIT7, 0xff, 0xff, 0xff, 0xff, 0xff };

  wheelArray_ = new uint8_t[size_];
  // initialization, set bits of the first byte to 1
  wheelArray_[0] = 0xff;
  uint32_t primeProduct = 2 * 3 * 5;

  for (int i = 3; i < 9 && smallPrimes_[i] <= limit_; i++) {
    // cross off the multiples of primes < smallPrimes_[i]
    // up to the current prime product
    uint32_t pp30 = primeProduct / SieveOfEratosthenes::NUMBERS_PER_BYTE;
    for (uint32_t j = 1; j < smallPrimes_[i]; j++) {
      assert((j + 1) * pp30 <= size_);
      std::memcpy(&wheelArray_[j * pp30], wheelArray_, pp30);
    }
    primeProduct *= smallPrimes_[i];
    // '- 7' is a correction for primes of type i*30 + 31
    uint32_t multiple = smallPrimes_[i] - 7;
    // cross off the multiples of smallPrimes_[i] up to the current
    // prime product
    while (multiple < primeProduct) {
      uint32_t multipleIndex = multiple / SieveOfEratosthenes::NUMBERS_PER_BYTE;
      uint32_t bitPosition = multiple % SieveOfEratosthenes::NUMBERS_PER_BYTE;
      assert(multipleIndex < size_);
      wheelArray_[multipleIndex] &= unsetBit[bitPosition];
      multiple += smallPrimes_[i] * 2;
    }
  }
}

/**
 * Pre-sieve multiples of small primes <= limit_ (e.g. 19).
 * Resets the sieve array (resets bits to 1) of SieveOfEratosthenes
 * objects after each sieved segment and removes the multiples of
 * small primes without sieving.
 * @see SieveOfEratosthenes::sieve(uint32_t)
 */
void PreSieve::doIt(uint8_t* sieve,
                    uint32_t sieveSize,
                    uint64_t segmentLow) const
{
  // calculate the position of segmentLow within the wheelArray_
  uint32_t sieveOffset = static_cast<uint32_t> (
      segmentLow % primeProduct_) / SieveOfEratosthenes::NUMBERS_PER_BYTE;
  uint32_t sizeLeft = size_ - sieveOffset;

  if (sizeLeft > sieveSize) {
    // copy a chunk of sieveSize bytes to the sieve array
    std::memcpy(sieve, &wheelArray_[sieveOffset], sieveSize);
  } else {
    // copy the last remaining bytes at the end of wheelArray_ to the
    // beginning of the sieve array
    std::memcpy(sieve, &wheelArray_[sieveOffset], sizeLeft);
    // restart copying at the beginning of wheelArray_
    sieveOffset = sizeLeft;
    while (sieveOffset + size_ < sieveSize) {
      std::memcpy(&sieve[sieveOffset], wheelArray_, size_);
      sieveOffset += size_;
    }
    std::memcpy(&sieve[sieveOffset], wheelArray_, sieveSize - sieveOffset);
  }
}
<commit_msg>unsigned int<commit_after>//
// Copyright (c) 2011 Kim Walisch, <kim.walisch@gmail.com>.
// All rights reserved.
//
// This file is part of primesieve.
// Visit: http://primesieve.googlecode.com
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//   * Redistributions of source code must retain the above copyright
//     notice, this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above
//     copyright notice, this list of conditions and the following
//     disclaimer in the documentation and/or other materials provided
//     with the distribution.
//   * Neither the name of the modp.com nor the names of its
//     contributors may be used to endorse or promote products derived
//     from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

#include "PreSieve.h"
#include "SieveOfEratosthenes.h"

#include <stdexcept>
#include <cstdlib>
#include <cstring>
#include <cassert>

const uint32_t PreSieve::smallPrimes_[9] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };

/**
 * Pre-sieve multiples of small primes <= limit to speed up the sieve
 * of Eratosthenes.
 * @pre limit >= 11 && limit <= 23
 * @see SieveOfEratosthenes::sieve(uint32_t)
 */
PreSieve::PreSieve(uint32_t limit) : wheelArray_(NULL), size_(0) {
  // limit <= 23 prevents 32 bit overflows
  if (limit < 11 || limit > 23)
    throw std::overflow_error("PreSieve: limit must be >= 11 && <= 23.");
  limit_ = limit;
  primeProduct_ = this->getPrimeProduct(limit_);
  size_ = primeProduct_ / SieveOfEratosthenes::NUMBERS_PER_BYTE;
  this->initWheelArray();
}

PreSieve::~PreSieve() {
  delete[] wheelArray_;
}

uint32_t PreSieve::getPrimeProduct(uint32_t limit) const {
  assert(limit <= 23);
  uint32_t pp = 1;
  for (int i = 0; i < 9 && smallPrimes_[i] <= limit; i++)
    pp *= smallPrimes_[i];
  return pp;
}

/**
 * Allocate the wheelArray_ and remove the multiples of small
 * primes <= limit_ from it.
 */
void PreSieve::initWheelArray() {
  assert(SieveOfEratosthenes::NUMBERS_PER_BYTE == 30);
  assert(size_ > 0);
  const unsigned int unsetBit[30] = {
      BIT0, 0xff, 0xff, 0xff, BIT1, 0xff,
      BIT2, 0xff, 0xff, 0xff, BIT3, 0xff,
      BIT4, 0xff, 0xff, 0xff, BIT5, 0xff,
      0xff, 0xff, 0xff, 0xff, BIT6, 0xff,
      BIT7, 0xff, 0xff, 0xff, 0xff, 0xff };

  wheelArray_ = new uint8_t[size_];
  // initialization, set bits of the first byte to 1
  wheelArray_[0] = 0xff;
  uint32_t primeProduct = 2 * 3 * 5;

  for (int i = 3; i < 9 && smallPrimes_[i] <= limit_; i++) {
    // cross off the multiples of primes < smallPrimes_[i]
    // up to the current prime product
    uint32_t pp30 = primeProduct / SieveOfEratosthenes::NUMBERS_PER_BYTE;
    for (uint32_t j = 1; j < smallPrimes_[i]; j++) {
      assert((j + 1) * pp30 <= size_);
      std::memcpy(&wheelArray_[j * pp30], wheelArray_, pp30);
    }
    primeProduct *= smallPrimes_[i];
    // '- 7' is a correction for primes of type i*30 + 31
    uint32_t multiple = smallPrimes_[i] - 7;
    // cross off the multiples of smallPrimes_[i] up to the current
    // prime product
    while (multiple < primeProduct) {
      uint32_t multipleIndex = multiple / SieveOfEratosthenes::NUMBERS_PER_BYTE;
      uint32_t bitPosition = multiple % SieveOfEratosthenes::NUMBERS_PER_BYTE;
      assert(multipleIndex < size_);
      wheelArray_[multipleIndex] &= unsetBit[bitPosition];
      multiple += smallPrimes_[i] * 2;
    }
  }
}

/**
 * Pre-sieve multiples of small primes <= limit_ (e.g. 19).
 * Resets the sieve array (resets bits to 1) of SieveOfEratosthenes
 * objects after each sieved segment and removes the multiples of
 * small primes without sieving.
 * @see SieveOfEratosthenes::sieve(uint32_t)
 */
void PreSieve::doIt(uint8_t* sieve,
                    uint32_t sieveSize,
                    uint64_t segmentLow) const
{
  // calculate the position of segmentLow within the wheelArray_
  uint32_t sieveOffset = static_cast<uint32_t> (
      segmentLow % primeProduct_) / SieveOfEratosthenes::NUMBERS_PER_BYTE;
  uint32_t sizeLeft = size_ - sieveOffset;

  if (sizeLeft > sieveSize) {
    // copy a chunk of sieveSize bytes to the sieve array
    std::memcpy(sieve, &wheelArray_[sieveOffset], sieveSize);
  } else {
    // copy the last remaining bytes at the end of wheelArray_ to the
    // beginning of the sieve array
    std::memcpy(sieve, &wheelArray_[sieveOffset], sizeLeft);
    // restart copying at the beginning of wheelArray_
    sieveOffset = sizeLeft;
    while (sieveOffset + size_ < sieveSize) {
      std::memcpy(&sieve[sieveOffset], wheelArray_, size_);
      sieveOffset += size_;
    }
    std::memcpy(&sieve[sieveOffset], wheelArray_, sieveSize - sieveOffset);
  }
}
<|endoftext|>


<commit_before>/******************************************************************************
  This source file is part of the Avogadro project.
  This source code is released under the 3-Clause BSD License, (see "LICENSE").
******************************************************************************/

#include "copypaste.h"

#include <avogadro/io/cjsonformat.h>
#include <avogadro/io/fileformatmanager.h>

#include <avogadro/qtgui/molecule.h>
#include <avogadro/qtgui/rwmolecule.h>

#include <QtCore/QMimeData>

#include <QtGui/QClipboard>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMessageBox>

#include <string>
#include <vector>

namespace Avogadro {
namespace QtPlugins {

using namespace Avogadro::QtGui;

CopyPaste::CopyPaste(QObject* parent_)
  : Avogadro::QtGui::ExtensionPlugin(parent_), m_pastedFormat(nullptr),
    m_copyAction(new QAction(tr("Copy"), this)),
    m_cutAction(new QAction(tr("Cut"), this)),
    m_clearAction(new QAction(tr("Clear"), this)),
    m_pasteAction(new QAction(tr("Paste"), this))
{
  m_copyAction->setShortcut(QKeySequence::Copy);
  m_copyAction->setIcon(QIcon::fromTheme("edit-copy"));
  connect(m_copyAction, SIGNAL(triggered()), SLOT(copy()));

  m_cutAction->setShortcut(QKeySequence::Cut);
  m_cutAction->setIcon(QIcon::fromTheme("edit-cut"));
  connect(m_cutAction, SIGNAL(triggered()), SLOT(cut()));

  m_pasteAction->setShortcut(QKeySequence::Paste);
  m_pasteAction->setIcon(QIcon::fromTheme("edit-paste"));
  connect(m_pasteAction, SIGNAL(triggered()), SLOT(paste()));

  m_clearAction->setShortcut(QKeySequence::Delete);
  m_clearAction->setIcon(QIcon::fromTheme("edit-clear"));
  connect(m_clearAction, SIGNAL(triggered()), SLOT(clear()));
}

CopyPaste::~CopyPaste()
{
  delete m_pastedFormat;
}

QList<QAction*> CopyPaste::actions() const
{
  QList<QAction*> result;
  return result << m_copyAction << m_cutAction << m_pasteAction
                << m_clearAction;
}

QStringList CopyPaste::menuPath(QAction*) const
{
  return QStringList() << tr("&Edit");
}

void CopyPaste::setMolecule(QtGui::Molecule* mol)
{
  m_molecule = mol;
}

bool CopyPaste::copy()
{
  if (!m_molecule)
    return false;

  std::string output;
  QtGui::Molecule* copy = m_molecule;

  if (!m_molecule->isSelectionEmpty()) {
    // create a copy of the selected atoms only
    copy = new QtGui::Molecule(m_molecule->parent());

    // go through the selected atoms and add them
    // make sure to track the new index
    std::vector atomIndex(m_molecule->atomCount(), 0);
    for (Index i = 0; i < m_molecule->atomCount(); ++i)
      if (m_molecule->atomSelected(i)) {
        auto a = copy->addAtom(m_molecule->atomicNumber(i));
        a.setPosition3d(m_molecule->atomPosition3d(i));

        // track the index
        atomIndex[i] = a.index();
      }

    for (Index i = 0; i < m_molecule->bondCount(); ++i) {
      Core::Bond bond = m_molecule->bond(i);
      Index start = bond.atom1().index();
      Index end = bond.atom2().index();
      if (m_molecule->atomSelected(start) && m_molecule->atomSelected(start)) {
        copy->addBond(atomIndex[start], atomIndex[end], bond.order());
      }
    }
  }

  Io::CjsonFormat cjson;
  if (!cjson.writeString(output, *copy)) {
    QMessageBox::warning(
      qobject_cast<QWidget*>(this->parent()), tr("Error Clipping Molecule"),
      tr("Error generating clipboard data.") + "\n" +
        tr("Output format: %1\n%2", "file format")
          .arg(QString::fromStdString(m_pastedFormat->name()))
          .arg(QString::fromStdString(m_pastedFormat->description())) +
        "\n\n" +
        tr("Reader error:\n%1")
          .arg(QString::fromStdString(m_pastedFormat->error())));
    return false;
  }

  QByteArray outputBA(output.c_str(), static_cast<int>(output.length()));

  QMimeData* mimeData(new QMimeData);

  std::vector<std::string> mimeTypes(cjson.mimeTypes());
  for (size_t i = 0; i < mimeTypes.size(); ++i)
    mimeData->setData(QString::fromStdString(mimeTypes[i]), outputBA);

  mimeData->setData("text/plain", outputBA);
  QApplication::clipboard()->setMimeData(mimeData);

  if (!m_molecule->isSelectionEmpty())
    copy->deleteLater(); // don't leak our copy

  return true;
}

void CopyPaste::cut()
{
  if (!copy())
    return;

  if (m_molecule->isSelectionEmpty())
    m_molecule->undoMolecule()->clearAtoms();
  else {
    // Remove atoms from the largest to the smallest index
    // (that way, the index doesn't change)
    for (Index i = m_molecule->atomCount(); i > 0; --i)
      if (m_molecule->atomSelected(i))
        m_molecule->undoMolecule()->removeAtom(i);
  }

  m_molecule->emitChanged(QtGui::Molecule::Atoms | QtGui::Molecule::Bonds |
                          QtGui::Molecule::Removed);
}

void CopyPaste::clear()
{
  if (m_molecule->isSelectionEmpty())
    m_molecule->undoMolecule()->clearAtoms();
  else {
    // Remove atoms from the largest to the smallest index
    // (that way, the index doesn't change)
    for (Index i = m_molecule->atomCount(); i > 0; --i)
      if (m_molecule->atomSelected(i))
        m_molecule->undoMolecule()->removeAtom(i);
  }
  m_molecule->emitChanged(QtGui::Molecule::Atoms | QtGui::Molecule::Bonds |
                          QtGui::Molecule::Removed);
}

void CopyPaste::paste()
{
  // Delete any old clipboard data.
  if (m_pastedFormat) {
    delete m_pastedFormat;
    m_pastedFormat = nullptr;
    m_pastedData.clear();
  }

  if (!m_molecule)
    return; // nothing to do

  // make sure we clear the current selection
  for (Index i = 0; i < m_molecule->atomCount(); ++i)
    m_molecule->setAtomSelected(i, false);

  const QMimeData* mimeData(QApplication::clipboard()->mimeData());

  if (!mimeData) {
    QMessageBox::warning(qobject_cast<QWidget*>(this->parent()),
                         tr("Error Pasting Molecule"),
                         tr("Cannot paste molecule: Clipboard empty!"));
    return;
  }

  // Try to find a reader that can handle the available mime-types.
  Io::FileFormatManager& mgr = Io::FileFormatManager::instance();
  QStringList mimeTypes(mimeData->formats());
  Io::FileFormat::Operations ops(Io::FileFormat::Read | Io::FileFormat::String);
  foreach (const QString& mimeType, mimeTypes) {
    if ((m_pastedFormat =
           mgr.newFormatFromMimeType(mimeType.toStdString(), ops))) {
      m_pastedData = mimeData->data(mimeType);
      break;
    }
  }

  // No mime-type match, default to cjson.
  if (!m_pastedFormat && mimeData->hasText()) {
    m_pastedFormat = new Io::CjsonFormat;
    m_pastedData = mimeData->text().toLatin1();
  }

  if (!m_pastedFormat)
    return;

  // we have a format, so try to insert the new bits into m_molecule
  Avogadro::QtGui::Molecule mol(m_molecule->parent());
  bool success = m_pastedFormat->readString(
    std::string(m_pastedData.constData(), m_pastedData.size()), mol);

  if (!success) {
    QMessageBox::warning(
      qobject_cast<QWidget*>(this->parent()), tr("Error Pasting Molecule"),
      tr("Error reading clipboard data.") + "\n" +
        tr("Detected format: %1\n%2", "file format description")
          .arg(QString::fromStdString(m_pastedFormat->name()))
          .arg(QString::fromStdString(m_pastedFormat->description())) +
        "\n\n" +
        tr("Reader error:\n%1")
          .arg(QString::fromStdString(m_pastedFormat->error())));
  }

  // insert mol into m_molecule
  m_molecule->undoMolecule()->appendMolecule(mol, "Paste Molecule");
  emit requestActiveTool("Manipulator");

  delete m_pastedFormat;
  m_pastedFormat = nullptr;
  m_pastedData.clear();
}

} // namespace QtPlugins
} // namespace Avogadro
<commit_msg>Fix "delete last atom" bug #683<commit_after>/******************************************************************************
  This source file is part of the Avogadro project.
  This source code is released under the 3-Clause BSD License, (see "LICENSE").
******************************************************************************/

#include "copypaste.h"

#include <avogadro/io/cjsonformat.h>
#include <avogadro/io/fileformatmanager.h>

#include <avogadro/qtgui/molecule.h>
#include <avogadro/qtgui/rwmolecule.h>

#include <QtCore/QMimeData>

#include <QtGui/QClipboard>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMessageBox>

#include <QDebug>

#include <string>
#include <vector>

namespace Avogadro {
namespace QtPlugins {

using namespace Avogadro::QtGui;

CopyPaste::CopyPaste(QObject* parent_)
  : Avogadro::QtGui::ExtensionPlugin(parent_), m_pastedFormat(nullptr),
    m_copyAction(new QAction(tr("Copy"), this)),
    m_cutAction(new QAction(tr("Cut"), this)),
    m_clearAction(new QAction(tr("Clear"), this)),
    m_pasteAction(new QAction(tr("Paste"), this))
{
  m_copyAction->setShortcut(QKeySequence::Copy);
  m_copyAction->setIcon(QIcon::fromTheme("edit-copy"));
  connect(m_copyAction, SIGNAL(triggered()), SLOT(copy()));

  m_cutAction->setShortcut(QKeySequence::Cut);
  m_cutAction->setIcon(QIcon::fromTheme("edit-cut"));
  connect(m_cutAction, SIGNAL(triggered()), SLOT(cut()));

  m_pasteAction->setShortcut(QKeySequence::Paste);
  m_pasteAction->setIcon(QIcon::fromTheme("edit-paste"));
  connect(m_pasteAction, SIGNAL(triggered()), SLOT(paste()));

  m_clearAction->setShortcut(QKeySequence::Delete);
  m_clearAction->setIcon(QIcon::fromTheme("edit-clear"));
  connect(m_clearAction, SIGNAL(triggered()), SLOT(clear()));
}

CopyPaste::~CopyPaste()
{
  delete m_pastedFormat;
}

QList<QAction*> CopyPaste::actions() const
{
  QList<QAction*> result;
  return result << m_copyAction << m_cutAction << m_pasteAction
                << m_clearAction;
}

QStringList CopyPaste::menuPath(QAction*) const
{
  return QStringList() << tr("&Edit");
}

void CopyPaste::setMolecule(QtGui::Molecule* mol)
{
  m_molecule = mol;
}

bool CopyPaste::copy()
{
  if (!m_molecule)
    return false;

  std::string output;
  QtGui::Molecule* copy = m_molecule;

  if (!m_molecule->isSelectionEmpty()) {
    // create a copy of the selected atoms only
    copy = new QtGui::Molecule(m_molecule->parent());

    // go through the selected atoms and add them
    // make sure to track the new index
    std::vector atomIndex(m_molecule->atomCount(), 0);
    for (Index i = 0; i < m_molecule->atomCount(); ++i)
      if (m_molecule->atomSelected(i)) {
        auto a = copy->addAtom(m_molecule->atomicNumber(i));
        a.setPosition3d(m_molecule->atomPosition3d(i));

        // track the index
        atomIndex[i] = a.index();
      }

    for (Index i = 0; i < m_molecule->bondCount(); ++i) {
      Core::Bond bond = m_molecule->bond(i);
      Index start = bond.atom1().index();
      Index end = bond.atom2().index();
      if (m_molecule->atomSelected(start) && m_molecule->atomSelected(start)) {
        copy->addBond(atomIndex[start], atomIndex[end], bond.order());
      }
    }
  }

  Io::CjsonFormat cjson;
  if (!cjson.writeString(output, *copy)) {
    QMessageBox::warning(
      qobject_cast<QWidget*>(this->parent()), tr("Error Clipping Molecule"),
      tr("Error generating clipboard data.") + "\n" +
        tr("Output format: %1\n%2", "file format")
          .arg(QString::fromStdString(m_pastedFormat->name()))
          .arg(QString::fromStdString(m_pastedFormat->description())) +
        "\n\n" +
        tr("Reader error:\n%1")
          .arg(QString::fromStdString(m_pastedFormat->error())));
    return false;
  }

  QByteArray outputBA(output.c_str(), static_cast<int>(output.length()));

  QMimeData* mimeData(new QMimeData);

  std::vector<std::string> mimeTypes(cjson.mimeTypes());
  for (size_t i = 0; i < mimeTypes.size(); ++i)
    mimeData->setData(QString::fromStdString(mimeTypes[i]), outputBA);

  mimeData->setData("text/plain", outputBA);
  QApplication::clipboard()->setMimeData(mimeData);

  if (!m_molecule->isSelectionEmpty())
    copy->deleteLater(); // don't leak our copy

  return true;
}

void CopyPaste::cut()
{
  if (!copy())
    return;

  if (m_molecule->isSelectionEmpty())
    m_molecule->undoMolecule()->clearAtoms();
  else {
    // Remove atoms from the largest to the smallest index
    // (that way, the index doesn't change)
    for (Index i = m_molecule->atomCount(); i > 0; --i)
      // atoms go from 0 to atomCount()-1
      if (m_molecule->atomSelected(i-1))
        m_molecule->undoMolecule()->removeAtom(i-1);
  }

  m_molecule->emitChanged(QtGui::Molecule::Atoms | QtGui::Molecule::Bonds |
                          QtGui::Molecule::Removed);
}

void CopyPaste::clear()
{
  if (m_molecule->isSelectionEmpty())
    m_molecule->undoMolecule()->clearAtoms();
  else {
    // Remove atoms from the largest to the smallest index
    // (that way, the index doesn't change)
    for (Index i = m_molecule->atomCount(); i > 0; --i) {
      // atoms go from 0 to atomCount()-1
      if (m_molecule->atomSelected(i-1))
        m_molecule->undoMolecule()->removeAtom(i-1);
    }
  }
  m_molecule->emitChanged(QtGui::Molecule::Atoms | QtGui::Molecule::Bonds |
                          QtGui::Molecule::Removed);
}

void CopyPaste::paste()
{
  // Delete any old clipboard data.
  if (m_pastedFormat) {
    delete m_pastedFormat;
    m_pastedFormat = nullptr;
    m_pastedData.clear();
  }

  if (!m_molecule)
    return; // nothing to do

  // make sure we clear the current selection
  for (Index i = 0; i < m_molecule->atomCount(); ++i)
    m_molecule->setAtomSelected(i, false);

  const QMimeData* mimeData(QApplication::clipboard()->mimeData());

  if (!mimeData) {
    QMessageBox::warning(qobject_cast<QWidget*>(this->parent()),
                         tr("Error Pasting Molecule"),
                         tr("Cannot paste molecule: Clipboard empty!"));
    return;
  }

  // Try to find a reader that can handle the available mime-types.
  Io::FileFormatManager& mgr = Io::FileFormatManager::instance();
  QStringList mimeTypes(mimeData->formats());
  Io::FileFormat::Operations ops(Io::FileFormat::Read | Io::FileFormat::String);
  foreach (const QString& mimeType, mimeTypes) {
    if ((m_pastedFormat =
           mgr.newFormatFromMimeType(mimeType.toStdString(), ops))) {
      m_pastedData = mimeData->data(mimeType);
      break;
    }
  }

  // No mime-type match, default to cjson.
  if (!m_pastedFormat && mimeData->hasText()) {
    m_pastedFormat = new Io::CjsonFormat;
    m_pastedData = mimeData->text().toLatin1();
  }

  if (!m_pastedFormat)
    return;

  // we have a format, so try to insert the new bits into m_molecule
  Avogadro::QtGui::Molecule mol(m_molecule->parent());
  bool success = m_pastedFormat->readString(
    std::string(m_pastedData.constData(), m_pastedData.size()), mol);

  if (!success) {
    QMessageBox::warning(
      qobject_cast<QWidget*>(this->parent()), tr("Error Pasting Molecule"),
      tr("Error reading clipboard data.") + "\n" +
        tr("Detected format: %1\n%2", "file format description")
          .arg(QString::fromStdString(m_pastedFormat->name()))
          .arg(QString::fromStdString(m_pastedFormat->description())) +
        "\n\n" +
        tr("Reader error:\n%1")
          .arg(QString::fromStdString(m_pastedFormat->error())));
  }

  // insert mol into m_molecule
  m_molecule->undoMolecule()->appendMolecule(mol, "Paste Molecule");
  emit requestActiveTool("Manipulator");

  delete m_pastedFormat;
  m_pastedFormat = nullptr;
  m_pastedData.clear();
}

} // namespace QtPlugins
} // namespace Avogadro
<|endoftext|>


<commit_before>/******************************************************************************

  This source file is part of the Avogadro project.

  Copyright 2012-13 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/

#include "navigator.h"

#include <avogadro/core/vector.h>

#include <avogadro/qtopengl/glwidget.h>

#include <avogadro/rendering/camera.h>
#include <avogadro/rendering/glrenderer.h>
#include <avogadro/rendering/scene.h>

#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
#include <QtGui/QWheelEvent>
#include <QtWidgets/QAction>

#include <Eigen/Geometry>

namespace Avogadro {
namespace QtPlugins {

const float ZOOM_SPEED = 0.02f;
const float ROTATION_SPEED = 0.005f;

Navigator::Navigator(QObject* parent_)
  : QtGui::ToolPlugin(parent_), m_activateAction(new QAction(this)),
    m_molecule(nullptr), m_glWidget(nullptr), m_renderer(nullptr),
    m_pressedButtons(Qt::NoButton), m_currentAction(Nothing)
{
  m_activateAction->setText(tr("Navigate"));
  m_activateAction->setIcon(QIcon(":/icons/navigator.png"));
}

Navigator::~Navigator()
{
}

QWidget* Navigator::toolWidget() const
{
  return nullptr;
}

QUndoCommand* Navigator::mousePressEvent(QMouseEvent* e)
{
  updatePressedButtons(e, false);
  m_lastMousePosition = e->pos();
  e->accept();

  // Figure out what type of navigation has been requested.
  if (e->buttons() & Qt::LeftButton && e->modifiers() == Qt::NoModifier) {
    m_currentAction = Rotation;
  } else if (e->buttons() & Qt::MidButton ||
             (e->buttons() & Qt::LeftButton &&
              e->modifiers() == Qt::ShiftModifier)) {
    m_currentAction = ZoomTilt;
  } else if (e->buttons() & Qt::RightButton ||
             (e->buttons() & Qt::LeftButton &&
              (e->modifiers() == Qt::ControlModifier ||
               e->modifiers() == Qt::MetaModifier))) {
    m_currentAction = Translation;
  }

  return nullptr;
}

QUndoCommand* Navigator::mouseReleaseEvent(QMouseEvent* e)
{
  updatePressedButtons(e, true);
  m_lastMousePosition = QPoint();
  m_currentAction = Nothing;
  e->accept();
  return nullptr;
}

QUndoCommand* Navigator::mouseMoveEvent(QMouseEvent* e)
{
  switch (m_currentAction) {
    case Rotation: {
      QPoint delta = e->pos() - m_lastMousePosition;
      rotate(m_renderer->scene().center(), delta.y(), delta.x(), 0);
      e->accept();
      break;
    }
    case Translation: {
      Vector2f fromScreen(m_lastMousePosition.x(), m_lastMousePosition.y());
      Vector2f toScreen(e->localPos().x(), e->localPos().y());
      translate(m_renderer->scene().center(), fromScreen, toScreen);
      e->accept();
      break;
    }
    case ZoomTilt: {
      QPoint delta = e->pos() - m_lastMousePosition;
      // Tilt
      rotate(m_renderer->scene().center(), 0, 0, delta.x());
      // Zoom
      zoom(m_renderer->scene().center(), delta.y());
      e->accept();
      break;
    }
    default:;
  }

  m_lastMousePosition = e->pos();

  if (e->isAccepted())
    emit updateRequested();

  return nullptr;
}

QUndoCommand* Navigator::mouseDoubleClickEvent(QMouseEvent* e)
{
  // Reset
  if (e->button() == Qt::MiddleButton) {
    if (m_glWidget) {
      m_glWidget->resetCamera();
      e->accept();
      emit updateRequested();
    }
  }
  return nullptr;
}

QUndoCommand* Navigator::wheelEvent(QWheelEvent* e)
{
  /// @todo Use scale for orthographic projections
  // Zoom
  zoom(m_renderer->scene().center(), e->delta() * 0.1);

  e->accept();
  emit updateRequested();
  return nullptr;
}

QUndoCommand* Navigator::keyPressEvent(QKeyEvent* e)
{
  Vector3f ref = m_renderer->scene().center();
  switch (e->key()) {
    case Qt::Key_Left:
    case Qt::Key_H:
    case Qt::Key_A:
      if (e->modifiers() == Qt::NoModifier ||
          e->modifiers() == Qt::KeypadModifier)
        rotate(ref, 0, -5, 0);
      else if (e->modifiers() == Qt::ShiftModifier)
        rotate(ref, 0, 0, -5);
      else if (e->modifiers() == Qt::ControlModifier)
        translate(ref, -5, 0);
      e->accept();
      break;
    case Qt::Key_Right:
    case Qt::Key_L:
    case Qt::Key_D:
      if (e->modifiers() == Qt::NoModifier ||
          e->modifiers() == Qt::KeypadModifier)
        rotate(ref, 0, 5, 0);
      else if (e->modifiers() == Qt::ShiftModifier)
        rotate(ref, 0, 0, 5);
      else if (e->modifiers() == Qt::ControlModifier)
        translate(ref, 5, 0);
      e->accept();
      break;
    case Qt::Key_Up:
    case Qt::Key_K:
    case Qt::Key_W:
      if (e->modifiers() == Qt::NoModifier ||
          e->modifiers() == Qt::KeypadModifier)
        rotate(ref, -5, 0, 0);
      else if (e->modifiers() == Qt::ShiftModifier)
        zoom(ref, -2);
      else if (e->modifiers() == Qt::ControlModifier)
        translate(ref, 0, -5);
      e->accept();
      break;
    case Qt::Key_Down:
    case Qt::Key_J:
    case Qt::Key_S:
      if (e->modifiers() == Qt::NoModifier ||
          e->modifiers() == Qt::KeypadModifier)
        rotate(ref, 5, 0, 0);
      else if (e->modifiers() == Qt::ShiftModifier)
        zoom(ref, 2);
      else if (e->modifiers() == Qt::ControlModifier)
        translate(ref, 0, 5);
      e->accept();
      break;
    default:
      e->ignore();
  }
  emit updateRequested();
  return nullptr;
}

QUndoCommand* Navigator::keyReleaseEvent(QKeyEvent* e)
{
  /// @todo
  e->ignore();
  return nullptr;
}

inline void Navigator::updatePressedButtons(QMouseEvent* e, bool release)
{
  /// @todo Use modifier keys on mac
  if (release)
    m_pressedButtons &= e->buttons();
  else
    m_pressedButtons |= e->buttons();
}

inline void Navigator::rotate(const Vector3f& ref, float x, float y, float z)
{
  const Eigen::Affine3f& modelView = m_renderer->camera().modelView();
  Vector3f xAxis = modelView.linear().row(0).transpose().normalized();
  Vector3f yAxis = modelView.linear().row(1).transpose().normalized();
  Vector3f zAxis = modelView.linear().row(2).transpose().normalized();
  m_renderer->camera().translate(ref);
  m_renderer->camera().rotate(x * ROTATION_SPEED, xAxis);
  m_renderer->camera().rotate(y * ROTATION_SPEED, yAxis);
  m_renderer->camera().rotate(z * ROTATION_SPEED, zAxis);
  m_renderer->camera().translate(-ref);
}

inline void Navigator::zoom(const Vector3f& ref, float d)
{
  const Eigen::Affine3f& modelView = m_renderer->camera().modelView();
  Vector3f transformedCenter = modelView * ref;
  float distance = transformedCenter.norm();
  float t = d * ZOOM_SPEED;
  float u = 2.0f / distance - 1.0f;
  if (t < u)
    t = u;
  if (m_renderer->camera().projectionType() == Rendering::Perspective)
    m_renderer->camera().preTranslate(transformedCenter * t);
  else
    m_renderer->camera().scale(t + 1.0f);
}

inline void Navigator::translate(const Vector3f& ref, float x, float y)
{
  Vector2f fromScreen(0, 0);
  Vector2f toScreen(x, y);
  translate(ref, fromScreen, toScreen);
}

inline void Navigator::translate(const Vector3f& ref, const Vector2f& fromScr,
                                 const Vector2f& toScr)
{
  Vector3f from(m_renderer->camera().unProject(fromScr, ref));
  Vector3f to(m_renderer->camera().unProject(toScr, ref));
  m_renderer->camera().translate(to - from);
}

} // namespace QtPlugins
} // namespace Avogadro
<commit_msg>Reverse direction of zoom with scrolling<commit_after>/******************************************************************************

  This source file is part of the Avogadro project.

  Copyright 2012-13 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/

#include "navigator.h"

#include <avogadro/core/vector.h>

#include <avogadro/qtopengl/glwidget.h>

#include <avogadro/rendering/camera.h>
#include <avogadro/rendering/glrenderer.h>
#include <avogadro/rendering/scene.h>

#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
#include <QtGui/QWheelEvent>
#include <QtWidgets/QAction>

#include <Eigen/Geometry>

namespace Avogadro {
namespace QtPlugins {

const float ZOOM_SPEED = 0.02f;
const float ROTATION_SPEED = 0.005f;

Navigator::Navigator(QObject* parent_)
  : QtGui::ToolPlugin(parent_), m_activateAction(new QAction(this)),
    m_molecule(nullptr), m_glWidget(nullptr), m_renderer(nullptr),
    m_pressedButtons(Qt::NoButton), m_currentAction(Nothing)
{
  m_activateAction->setText(tr("Navigate"));
  m_activateAction->setIcon(QIcon(":/icons/navigator.png"));
}

Navigator::~Navigator()
{
}

QWidget* Navigator::toolWidget() const
{
  return nullptr;
}

QUndoCommand* Navigator::mousePressEvent(QMouseEvent* e)
{
  updatePressedButtons(e, false);
  m_lastMousePosition = e->pos();
  e->accept();

  // Figure out what type of navigation has been requested.
  if (e->buttons() & Qt::LeftButton && e->modifiers() == Qt::NoModifier) {
    m_currentAction = Rotation;
  } else if (e->buttons() & Qt::MidButton ||
             (e->buttons() & Qt::LeftButton &&
              e->modifiers() == Qt::ShiftModifier)) {
    m_currentAction = ZoomTilt;
  } else if (e->buttons() & Qt::RightButton ||
             (e->buttons() & Qt::LeftButton &&
              (e->modifiers() == Qt::ControlModifier ||
               e->modifiers() == Qt::MetaModifier))) {
    m_currentAction = Translation;
  }

  return nullptr;
}

QUndoCommand* Navigator::mouseReleaseEvent(QMouseEvent* e)
{
  updatePressedButtons(e, true);
  m_lastMousePosition = QPoint();
  m_currentAction = Nothing;
  e->accept();
  return nullptr;
}

QUndoCommand* Navigator::mouseMoveEvent(QMouseEvent* e)
{
  switch (m_currentAction) {
    case Rotation: {
      QPoint delta = e->pos() - m_lastMousePosition;
      rotate(m_renderer->scene().center(), delta.y(), delta.x(), 0);
      e->accept();
      break;
    }
    case Translation: {
      Vector2f fromScreen(m_lastMousePosition.x(), m_lastMousePosition.y());
      Vector2f toScreen(e->localPos().x(), e->localPos().y());
      translate(m_renderer->scene().center(), fromScreen, toScreen);
      e->accept();
      break;
    }
    case ZoomTilt: {
      QPoint delta = e->pos() - m_lastMousePosition;
      // Tilt
      rotate(m_renderer->scene().center(), 0, 0, delta.x());
      // Zoom
      zoom(m_renderer->scene().center(), delta.y());
      e->accept();
      break;
    }
    default:;
  }

  m_lastMousePosition = e->pos();

  if (e->isAccepted())
    emit updateRequested();

  return nullptr;
}

QUndoCommand* Navigator::mouseDoubleClickEvent(QMouseEvent* e)
{
  // Reset
  if (e->button() == Qt::MiddleButton) {
    if (m_glWidget) {
      m_glWidget->resetCamera();
      e->accept();
      emit updateRequested();
    }
  }
  return nullptr;
}

QUndoCommand* Navigator::wheelEvent(QWheelEvent* e)
{
  /// @todo Use scale for orthographic projections
  // Zoom
  zoom(m_renderer->scene().center(), -e->angleDelta() * 0.125);

  e->accept();
  emit updateRequested();
  return nullptr;
}

QUndoCommand* Navigator::keyPressEvent(QKeyEvent* e)
{
  Vector3f ref = m_renderer->scene().center();
  switch (e->key()) {
    case Qt::Key_Left:
    case Qt::Key_H:
    case Qt::Key_A:
      if (e->modifiers() == Qt::NoModifier ||
          e->modifiers() == Qt::KeypadModifier)
        rotate(ref, 0, -5, 0);
      else if (e->modifiers() == Qt::ShiftModifier)
        rotate(ref, 0, 0, -5);
      else if (e->modifiers() == Qt::ControlModifier)
        translate(ref, -5, 0);
      e->accept();
      break;
    case Qt::Key_Right:
    case Qt::Key_L:
    case Qt::Key_D:
      if (e->modifiers() == Qt::NoModifier ||
          e->modifiers() == Qt::KeypadModifier)
        rotate(ref, 0, 5, 0);
      else if (e->modifiers() == Qt::ShiftModifier)
        rotate(ref, 0, 0, 5);
      else if (e->modifiers() == Qt::ControlModifier)
        translate(ref, 5, 0);
      e->accept();
      break;
    case Qt::Key_Up:
    case Qt::Key_K:
    case Qt::Key_W:
      if (e->modifiers() == Qt::NoModifier ||
          e->modifiers() == Qt::KeypadModifier)
        rotate(ref, -5, 0, 0);
      else if (e->modifiers() == Qt::ShiftModifier)
        zoom(ref, -2);
      else if (e->modifiers() == Qt::ControlModifier)
        translate(ref, 0, -5);
      e->accept();
      break;
    case Qt::Key_Down:
    case Qt::Key_J:
    case Qt::Key_S:
      if (e->modifiers() == Qt::NoModifier ||
          e->modifiers() == Qt::KeypadModifier)
        rotate(ref, 5, 0, 0);
      else if (e->modifiers() == Qt::ShiftModifier)
        zoom(ref, 2);
      else if (e->modifiers() == Qt::ControlModifier)
        translate(ref, 0, 5);
      e->accept();
      break;
    default:
      e->ignore();
  }
  emit updateRequested();
  return nullptr;
}

QUndoCommand* Navigator::keyReleaseEvent(QKeyEvent* e)
{
  /// @todo
  e->ignore();
  return nullptr;
}

inline void Navigator::updatePressedButtons(QMouseEvent* e, bool release)
{
  /// @todo Use modifier keys on mac
  if (release)
    m_pressedButtons &= e->buttons();
  else
    m_pressedButtons |= e->buttons();
}

inline void Navigator::rotate(const Vector3f& ref, float x, float y, float z)
{
  const Eigen::Affine3f& modelView = m_renderer->camera().modelView();
  Vector3f xAxis = modelView.linear().row(0).transpose().normalized();
  Vector3f yAxis = modelView.linear().row(1).transpose().normalized();
  Vector3f zAxis = modelView.linear().row(2).transpose().normalized();
  m_renderer->camera().translate(ref);
  m_renderer->camera().rotate(x * ROTATION_SPEED, xAxis);
  m_renderer->camera().rotate(y * ROTATION_SPEED, yAxis);
  m_renderer->camera().rotate(z * ROTATION_SPEED, zAxis);
  m_renderer->camera().translate(-ref);
}

inline void Navigator::zoom(const Vector3f& ref, float d)
{
  const Eigen::Affine3f& modelView = m_renderer->camera().modelView();
  Vector3f transformedCenter = modelView * ref;
  float distance = transformedCenter.norm();
  float t = d * ZOOM_SPEED;
  float u = 2.0f / distance - 1.0f;
  if (t < u)
    t = u;
  if (m_renderer->camera().projectionType() == Rendering::Perspective)
    m_renderer->camera().preTranslate(transformedCenter * t);
  else
    m_renderer->camera().scale(t + 1.0f);
}

inline void Navigator::translate(const Vector3f& ref, float x, float y)
{
  Vector2f fromScreen(0, 0);
  Vector2f toScreen(x, y);
  translate(ref, fromScreen, toScreen);
}

inline void Navigator::translate(const Vector3f& ref, const Vector2f& fromScr,
                                 const Vector2f& toScr)
{
  Vector3f from(m_renderer->camera().unProject(fromScr, ref));
  Vector3f to(m_renderer->camera().unProject(toScr, ref));
  m_renderer->camera().translate(to - from);
}

} // namespace QtPlugins
} // namespace Avogadro
<|endoftext|>


<commit_before>#define DS_IMPLEMENTATION
#include "..\..\diesel.h"
#define STB_IMAGE_IMPLEMENTATION
#include "..\common\stb_image.h"
#include "AmbientLightning_PS_Main.h"
#include "AmbientLightning_VS_Main.h"
#include "WaveFrontReader.h"

struct PNCVertex {
	ds::vec3 p;
	ds::vec3 n;
	ds::Color c;
};

struct LightBuffer {
	ds::matrix viewProjectionMatrix;
	ds::matrix worldMatrix;
	ds::Color ambientColor;
	ds::vec3 lightDirection;
	float more;
	ds::Color diffuseColor;
};

RID buildTigreDrawItem(RID lightBufferID) {
	WaveFrontFormat format;
	format.topology = WFT_TRIANGLE;
	format.formats = WFI_NORMALS;
	WaveFrontReader objReader;
	ds::vec3 positions[10000];
	ds::vec3 normals[10000];
	ds::Color colors[10000];
	int num = objReader.load("tigre_sumatra.obj", format, positions, 0, normals, colors, 10000);

	PNCVertex* v = new PNCVertex[num];
	for (int i = 0; i < num; ++i) {
		v[i] = PNCVertex{ positions[i],normals[i], colors[i] };
	}

	ds::ShaderInfo vsInfo = { 0, AmbientLightning_VS_Main, sizeof(AmbientLightning_VS_Main), ds::ShaderType::ST_VERTEX_SHADER };
	RID vertexShader = ds::createShader(vsInfo);
	ds::ShaderInfo psInfo = { 0, AmbientLightning_PS_Main, sizeof(AmbientLightning_PS_Main), ds::ShaderType::ST_PIXEL_SHADER };
	RID pixelShader = ds::createShader(psInfo);

	ds::InputLayoutDefinition tigreDecl[] = {
		{ ds::BufferAttribute::POSITION,ds::BufferAttributeType::FLOAT,3 },
		{ ds::BufferAttribute::NORMAL,ds::BufferAttributeType::FLOAT,3 },
		{ ds::BufferAttribute::COLOR,ds::BufferAttributeType::FLOAT,4 }
	};
	ds::InputLayoutInfo tigreLayoutInfo = { tigreDecl, 3, vertexShader };
	RID nid = ds::createInputLayout(tigreLayoutInfo);

	ds::VertexBufferInfo cbInfo = { ds::BufferType::STATIC, num, sizeof(PNCVertex), v };
	RID cubeBuffer = ds::createVertexBuffer(cbInfo);

	delete[] v;

	RID basicGroup = ds::StateGroupBuilder()
		.inputLayout(nid)
		.constantBuffer(lightBufferID, vertexShader, 0)
		.constantBuffer(lightBufferID, pixelShader, 0)
		.vertexShader(vertexShader)
		.pixelShader(pixelShader)
		.vertexBuffer(cubeBuffer)
		.build();

	ds::DrawCommand drawCmd = { num, ds::DrawType::DT_VERTICES, ds::PrimitiveTypes::TRIANGLE_LIST };

	RID cubeStack[] = { basicGroup };
	RID cubeItem = ds::compile(drawCmd, cubeStack, 1);
	return cubeItem;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow) {
	float t = 0.0f;
	ds::RenderSettings rs;
	rs.width = 1024;
	rs.height = 768;
	rs.title = "Hello world";
	rs.clearColor = ds::Color(0.2f, 0.2f, 0.2f, 1.0f);
	rs.multisampling = 4;
	ds::init(rs);

	LightBuffer lightBuffer;
	lightBuffer.ambientColor = ds::Color(0.15f, 0.15f, 0.15f, 1.0f);
	lightBuffer.diffuseColor = ds::Color(1.0f, 1.0f, 1.0f, 1.0f);
	lightBuffer.more = 0.0f;
	ds::vec3 lightPos = ds::vec3(1.0f, -0.5f, 1.0f);
	lightBuffer.lightDirection = normalize(lightPos);

	ds::matrix viewMatrix = ds::matLookAtLH(ds::vec3(0.0f, 1.0f, -2.0f), ds::vec3(0, 0, 0), ds::vec3(0, 1, 0));
	ds::matrix projectionMatrix = ds::matPerspectiveFovLH(ds::PI / 4.0f, ds::getScreenAspectRatio(), 0.01f, 100.0f);
	ds::Camera camera = {
		viewMatrix,
		projectionMatrix,
		viewMatrix * projectionMatrix,
		ds::vec3(0,1,-2),
		ds::vec3(0,0,1),
		ds::vec3(0,1,0),
		ds::vec3(1,0,0)
	};
	ds::RenderPassInfo rpInfo = { &camera,ds::DepthBufferState::ENABLED, 0, 0 };
	RID basicPass = ds::createRenderPass(rpInfo, "BasicPass");

	RID lightBufferID = ds::createConstantBuffer(sizeof(LightBuffer), &lightBuffer);

	RID tigreDrawItem = buildTigreDrawItem(lightBufferID);

	ds::vec3 scale(1.0f, 1.0f, 1.0f);
	ds::vec3 rotation(0.0f, 0.0f, 0.0f);
	ds::vec3 pos(0.0f, 0.0f, 0.0f);

	while (ds::isRunning()) {
		ds::begin();

		t += static_cast<float>(ds::getElapsedSeconds());

		lightBuffer.viewProjectionMatrix = ds::matTranspose(camera.viewProjectionMatrix);
		ds::matrix world = ds::matIdentity();
		rotation.y += 2.0f  * static_cast<float>(ds::getElapsedSeconds());
		//rotation.x += 1.0f  * static_cast<float>(ds::getElapsedSeconds());
		ds::matrix rotY = ds::matRotationY(rotation.y);
		ds::matrix rotX = ds::matRotationX(rotation.x);
		ds::matrix rotZ = ds::matRotationZ(rotation.z);
		ds::matrix s = ds::matScale(scale);
		ds::matrix w = rotZ * rotY * rotX * s * world;
		lightBuffer.worldMatrix = ds::matTranspose(w);
		ds::submit(basicPass, tigreDrawItem);

		ds::end();
	}
	ds::shutdown();
}<commit_msg>Added copyright notic to the tigre<commit_after>#define DS_IMPLEMENTATION
#include "..\..\diesel.h"
#define STB_IMAGE_IMPLEMENTATION
#include "..\common\stb_image.h"
#include "AmbientLightning_PS_Main.h"
#include "AmbientLightning_VS_Main.h"
#include "WaveFrontReader.h"

// The tigre https://sketchfab.com/models/95c4008c4c764c078f679d4c320e7b18# is taken from https://sketchfab.com/jeremielouvetz
struct PNCVertex {
	ds::vec3 p;
	ds::vec3 n;
	ds::Color c;
};

struct LightBuffer {
	ds::matrix viewProjectionMatrix;
	ds::matrix worldMatrix;
	ds::Color ambientColor;
	ds::vec3 lightDirection;
	float more;
	ds::Color diffuseColor;
};

RID buildTigreDrawItem(RID lightBufferID) {
	WaveFrontFormat format;
	format.topology = WFT_TRIANGLE;
	format.formats = WFI_NORMALS;
	WaveFrontReader objReader;
	ds::vec3 positions[10000];
	ds::vec3 normals[10000];
	ds::Color colors[10000];
	int num = objReader.load("tigre_sumatra.obj", format, positions, 0, normals, colors, 10000);

	PNCVertex* v = new PNCVertex[num];
	for (int i = 0; i < num; ++i) {
		v[i] = PNCVertex{ positions[i],normals[i], colors[i] };
	}

	ds::ShaderInfo vsInfo = { 0, AmbientLightning_VS_Main, sizeof(AmbientLightning_VS_Main), ds::ShaderType::ST_VERTEX_SHADER };
	RID vertexShader = ds::createShader(vsInfo);
	ds::ShaderInfo psInfo = { 0, AmbientLightning_PS_Main, sizeof(AmbientLightning_PS_Main), ds::ShaderType::ST_PIXEL_SHADER };
	RID pixelShader = ds::createShader(psInfo);

	ds::InputLayoutDefinition tigreDecl[] = {
		{ ds::BufferAttribute::POSITION,ds::BufferAttributeType::FLOAT,3 },
		{ ds::BufferAttribute::NORMAL,ds::BufferAttributeType::FLOAT,3 },
		{ ds::BufferAttribute::COLOR,ds::BufferAttributeType::FLOAT,4 }
	};
	ds::InputLayoutInfo tigreLayoutInfo = { tigreDecl, 3, vertexShader };
	RID nid = ds::createInputLayout(tigreLayoutInfo);

	ds::VertexBufferInfo cbInfo = { ds::BufferType::STATIC, num, sizeof(PNCVertex), v };
	RID cubeBuffer = ds::createVertexBuffer(cbInfo);

	delete[] v;

	RID basicGroup = ds::StateGroupBuilder()
		.inputLayout(nid)
		.constantBuffer(lightBufferID, vertexShader, 0)
		.constantBuffer(lightBufferID, pixelShader, 0)
		.vertexShader(vertexShader)
		.pixelShader(pixelShader)
		.vertexBuffer(cubeBuffer)
		.build();

	ds::DrawCommand drawCmd = { num, ds::DrawType::DT_VERTICES, ds::PrimitiveTypes::TRIANGLE_LIST };

	RID cubeStack[] = { basicGroup };
	RID cubeItem = ds::compile(drawCmd, cubeStack, 1);
	return cubeItem;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow) {
	float t = 0.0f;
	ds::RenderSettings rs;
	rs.width = 1024;
	rs.height = 768;
	rs.title = "Hello world";
	rs.clearColor = ds::Color(0.2f, 0.2f, 0.2f, 1.0f);
	rs.multisampling = 4;
	ds::init(rs);

	LightBuffer lightBuffer;
	lightBuffer.ambientColor = ds::Color(0.15f, 0.15f, 0.15f, 1.0f);
	lightBuffer.diffuseColor = ds::Color(1.0f, 1.0f, 1.0f, 1.0f);
	lightBuffer.more = 0.0f;
	ds::vec3 lightPos = ds::vec3(1.0f, -0.5f, 1.0f);
	lightBuffer.lightDirection = normalize(lightPos);

	ds::matrix viewMatrix = ds::matLookAtLH(ds::vec3(0.0f, 1.0f, -2.0f), ds::vec3(0, 0, 0), ds::vec3(0, 1, 0));
	ds::matrix projectionMatrix = ds::matPerspectiveFovLH(ds::PI / 4.0f, ds::getScreenAspectRatio(), 0.01f, 100.0f);
	ds::Camera camera = {
		viewMatrix,
		projectionMatrix,
		viewMatrix * projectionMatrix,
		ds::vec3(0,1,-2),
		ds::vec3(0,0,1),
		ds::vec3(0,1,0),
		ds::vec3(1,0,0)
	};
	ds::RenderPassInfo rpInfo = { &camera,ds::DepthBufferState::ENABLED, 0, 0 };
	RID basicPass = ds::createRenderPass(rpInfo, "BasicPass");

	RID lightBufferID = ds::createConstantBuffer(sizeof(LightBuffer), &lightBuffer);

	RID tigreDrawItem = buildTigreDrawItem(lightBufferID);

	ds::vec3 scale(1.0f, 1.0f, 1.0f);
	ds::vec3 rotation(0.0f, 0.0f, 0.0f);
	ds::vec3 pos(0.0f, 0.0f, 0.0f);

	while (ds::isRunning()) {
		ds::begin();

		t += static_cast<float>(ds::getElapsedSeconds());

		lightBuffer.viewProjectionMatrix = ds::matTranspose(camera.viewProjectionMatrix);
		ds::matrix world = ds::matIdentity();
		rotation.y += 2.0f  * static_cast<float>(ds::getElapsedSeconds());
		//rotation.x += 1.0f  * static_cast<float>(ds::getElapsedSeconds());
		ds::matrix rotY = ds::matRotationY(rotation.y);
		ds::matrix rotX = ds::matRotationX(rotation.x);
		ds::matrix rotZ = ds::matRotationZ(rotation.z);
		ds::matrix s = ds::matScale(scale);
		ds::matrix w = rotZ * rotY * rotX * s * world;
		lightBuffer.worldMatrix = ds::matTranspose(w);
		ds::submit(basicPass, tigreDrawItem);

		ds::end();
	}
	ds::shutdown();
}<|endoftext|>


<commit_before>///
/// @file  primecount.hpp
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef PRIMECOUNT_HPP
#define PRIMECOUNT_HPP

#include <stdint.h>

#define PRIMECOUNT_VERSION "0.17"
#define PRIMECOUNT_VERSION_MAJOR 0
#define PRIMECOUNT_VERSION_MINOR 17

namespace primecount {

class PhiCache;

enum {
  /// Uses all CPU cores.
  MAX_THREADS = -1
};

/// This is an alias for the fastest prime counting implementation
/// within primecount.
///
int64_t pi(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using an optimized
/// segmented sieve of Eratosthenes implementation.
/// Run time: O(x log log x) operations, O(x^0.5) space.
///
int64_t pi_primesieve(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using Legendre's formula.
/// Run time: O(x) operations, O(x^0.5) space.
///
int64_t pi_legendre(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using Meissel's formula.
/// Run time: O(x/(log x)^3) operations, O(x^0.5) space.
///
int64_t pi_meissel(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using Lehmer's formula.
/// Run time: O(x/(log x)^4) operations, O(x^0.5) space.
///
int64_t pi_lehmer(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3)) operations, O(x^0.5) space.
///
int64_t pi_lmo(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm. This implementation uses the
/// recursive phi formula with caching to calculate S2(x).
/// Run time: O(x^(2/3)) operations, O(x^0.5) space.
///
int64_t pi_lmo1(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm. This implementation uses
/// the sieve of Eratosthenes to calculate S2(x).
/// Run time: O(x^(2/3)) operations, O(x^(2/3)) space.
///
int64_t pi_lmo2(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm. This implementation uses
/// the segmented sieve of Eratosthenes to calculate S2(x).
/// Run time: O(x^(2/3)) operations, O(x^0.5) space.
///
int64_t pi_lmo3(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm. This implementation uses
/// the segmented sieve of Eratosthenes and a special data structure
/// for counting to calculate S2(x).
/// Run time: O(x^(2/3)) operations, O(x^0.5) space.
///
int64_t pi_lmo4(int64_t x, int threads = MAX_THREADS);

/// Calculate the nth prime using a combination of an efficient prime
/// counting function implementation and the sieve of Eratosthenes.
/// Run time: O(x/(log x)^4) operations, O(x^0.5) space.
///
int64_t nth_prime(int64_t n, int threads = MAX_THREADS);

/// Partial sieve function (a.k.a. Legendre-sum).
/// phi(x, a) counts the numbers <= x that are not divisible
/// by any of the first a primes.
///
int64_t phi(int64_t x, int64_t a, int threads = MAX_THREADS);

/// Partial sieve function (a.k.a. Legendre-sum).
/// phi(x, a) counts the numbers <= x that are not divisible
/// by any of the first a primes.
///
int64_t phi(int64_t x, int64_t a, PhiCache* phiCache);

/// Calculate the offset logarithmic integral which is a very
/// accurate approximation of the number of primes below x.
/// @post Li(x) > pi(x) for 24 <= x <= ~ 10^316
///
int64_t Li(int64_t);

/// Calculate the inverse logarithmic integral Li^-1(x) which is
/// a very accurate approximation of the nth prime.
/// @post Li_inverse(x) < nth_prime(x) for 7 <= x <= ~ 10^316
///
int64_t Li_inverse(int64_t);

/// Test all prime counting function implementations.
/// @return true if success else false.
///
bool test();

} // namespace primecount

#endif
<commit_msg>Update algorithm complexity<commit_after>///
/// @file  primecount.hpp
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef PRIMECOUNT_HPP
#define PRIMECOUNT_HPP

#include <stdint.h>

#define PRIMECOUNT_VERSION "0.17"
#define PRIMECOUNT_VERSION_MAJOR 0
#define PRIMECOUNT_VERSION_MINOR 17

namespace primecount {

class PhiCache;

enum {
  /// Uses all CPU cores.
  MAX_THREADS = -1
};

/// This is an alias for the fastest prime counting implementation
/// within primecount.
///
int64_t pi(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using an optimized
/// segmented sieve of Eratosthenes implementation.
/// Run time: O(x log log x) operations, O(x^0.5) space.
///
int64_t pi_primesieve(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using Legendre's formula.
/// Run time: O(x) operations, O(x^0.5) space.
///
int64_t pi_legendre(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using Meissel's formula.
/// Run time: O(x/(log x)^3) operations, O(x^0.5) space.
///
int64_t pi_meissel(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using Lehmer's formula.
/// Run time: O(x/(log x)^4) operations, O(x^0.5) space.
///
int64_t pi_lehmer(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3)) operations, O(x^0.5) space.
///
int64_t pi_lmo(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm. This implementation uses the
/// recursive phi formula with caching to calculate S2(x).
/// Run time: O(x^(2/3)) operations, O(x^0.5) space.
///
int64_t pi_lmo1(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm. This implementation uses
/// the sieve of Eratosthenes to calculate S2(x).
/// Run time: O(x^(2/3)) operations, O(x^(2/3) / log log x) space.
///
int64_t pi_lmo2(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm. This implementation uses
/// the segmented sieve of Eratosthenes to calculate S2(x).
/// Run time: O(x^(2/3)) operations, O(x^0.5) space.
///
int64_t pi_lmo3(int64_t x, int threads = MAX_THREADS);

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm. This implementation uses
/// the segmented sieve of Eratosthenes and a special data structure
/// for counting to calculate S2(x).
/// Run time: O(x^(2/3) / log x) operations, O(x^0.5) space.
///
int64_t pi_lmo4(int64_t x, int threads = MAX_THREADS);

/// Calculate the nth prime using a combination of an efficient prime
/// counting function implementation and the sieve of Eratosthenes.
/// Run time: O(x/(log x)^4) operations, O(x^0.5) space.
///
int64_t nth_prime(int64_t n, int threads = MAX_THREADS);

/// Partial sieve function (a.k.a. Legendre-sum).
/// phi(x, a) counts the numbers <= x that are not divisible
/// by any of the first a primes.
///
int64_t phi(int64_t x, int64_t a, int threads = MAX_THREADS);

/// Partial sieve function (a.k.a. Legendre-sum).
/// phi(x, a) counts the numbers <= x that are not divisible
/// by any of the first a primes.
///
int64_t phi(int64_t x, int64_t a, PhiCache* phiCache);

/// Calculate the offset logarithmic integral which is a very
/// accurate approximation of the number of primes below x.
/// @post Li(x) > pi(x) for 24 <= x <= ~ 10^316
///
int64_t Li(int64_t);

/// Calculate the inverse logarithmic integral Li^-1(x) which is
/// a very accurate approximation of the nth prime.
/// @post Li_inverse(x) < nth_prime(x) for 7 <= x <= ~ 10^316
///
int64_t Li_inverse(int64_t);

/// Test all prime counting function implementations.
/// @return true if success else false.
///
bool test();

} // namespace primecount

#endif
<|endoftext|>