<commit_before>/*

Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

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 HOLDER 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 "Extractor.h"

#include "ExtractionContainers.h"
#include "ExtractionNode.h"
#include "ExtractionWay.h"
#include "ExtractorCallbacks.h"
#include "RestrictionParser.h"
#include "ScriptingEnvironment.h"

#include "../Util/GitDescription.h"
#include "../Util/IniFileUtil.h"
#include "../Util/OSRMException.h"
#include "../Util/simple_logger.hpp"
#include "../Util/TimingUtil.h"
#include "../Util/make_unique.hpp"
#include "../typedefs.h"

#include <boost/program_options.hpp>

#include <luabind/luabind.hpp>

#include <tbb/task_scheduler_init.h>

#include <osmium/io/any_input.hpp>

#include <cstdlib>

#include <chrono>
#include <fstream>
#include <iostream>
#include <thread>
#include <unordered_map>

Extractor::Extractor() : requested_num_threads(0), file_has_pbf_format(false)
{
}

int lua_error_callback(lua_State *L) // This is so I can use my own function as an
// exception handler, pcall_log()
{
    luabind::object error_msg(luabind::from_stack(L, -1));
    std::ostringstream error_stream;
    error_stream << error_msg;
    throw OSRMException("ERROR occured in profile script:\n" + error_stream.str());
}

bool Extractor::ParseArguments(int argc, char *argv[])
{
    // declare a group of options that will be allowed only on command line
    boost::program_options::options_description generic_options("Options");
    generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
        "config,c",
        boost::program_options::value<boost::filesystem::path>(&config_file_path)
            ->default_value("extractor.ini"),
        "Path to a configuration file.");

    // declare a group of options that will be allowed both on command line and in config file
    boost::program_options::options_description config_options("Configuration");
    config_options.add_options()("profile,p",
                                 boost::program_options::value<boost::filesystem::path>(
                                     &profile_path)->default_value("profile.lua"),
                                 "Path to LUA routing profile")(
        "threads,t",
        boost::program_options::value<unsigned int>(&requested_num_threads)
            ->default_value(tbb::task_scheduler_init::default_num_threads()),
        "Number of threads to use");

    // hidden options, will be allowed both on command line and in config file, but will not be
    // shown to the user
    boost::program_options::options_description hidden_options("Hidden options");
    hidden_options.add_options()(
        "input,i",
        boost::program_options::value<boost::filesystem::path>(&input_path),
        "Input file in .osm, .osm.bz2 or .osm.pbf format");

    // positional option
    boost::program_options::positional_options_description positional_options;
    positional_options.add("input", 1);

    // combine above options for parsing
    boost::program_options::options_description cmdline_options;
    cmdline_options.add(generic_options).add(config_options).add(hidden_options);

    boost::program_options::options_description config_file_options;
    config_file_options.add(config_options).add(hidden_options);

    boost::program_options::options_description visible_options(
        boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
    visible_options.add(generic_options).add(config_options);

    // parse command line options
    boost::program_options::variables_map option_variables;
    boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
                                      .options(cmdline_options)
                                      .positional(positional_options)
                                      .run(),
                                  option_variables);

    if (option_variables.count("version"))
    {
        SimpleLogger().Write() << g_GIT_DESCRIPTION;
        return false;
    }

    if (option_variables.count("help"))
    {
        SimpleLogger().Write() << visible_options;
        return false;
    }

    boost::program_options::notify(option_variables);

    // parse config file
    if (boost::filesystem::is_regular_file(config_file_path))
    {
        SimpleLogger().Write() << "Reading options from: " << config_file_path.string();
        std::string ini_file_contents = ReadIniFileAndLowerContents(config_file_path);
        std::stringstream config_stream(ini_file_contents);
        boost::program_options::store(parse_config_file(config_stream, config_file_options),
                                      option_variables);
        boost::program_options::notify(option_variables);
    }

    if (!option_variables.count("input"))
    {
        SimpleLogger().Write() << visible_options;
        return false;
    }

    return true;
}

void Extractor::GenerateOutputFilesNames()
{
    output_file_name = input_path.string();
    restriction_file_name = input_path.string();
    std::string::size_type pos = output_file_name.find(".osm.bz2");
    if (pos == std::string::npos)
    {
        pos = output_file_name.find(".osm.pbf");
        if (pos != std::string::npos)
        {
            file_has_pbf_format = true;
        }
        else
        {
            pos = output_file_name.find(".osm.xml");
        }
    }
    if (pos == std::string::npos)
    {
        pos = output_file_name.find(".pbf");
        if (pos != std::string::npos)
        {
            file_has_pbf_format = true;
        }
    }
    if (pos == std::string::npos)
    {
        pos = output_file_name.find(".osm");
        if (pos == std::string::npos)
        {
            output_file_name.append(".osrm");
            restriction_file_name.append(".osrm.restrictions");
            timestamp_file_name.append(".osrm.timestamp");
        }
        else
        {
            output_file_name.replace(pos, 5, ".osrm");
            restriction_file_name.replace(pos, 5, ".osrm.restrictions");
            timestamp_file_name.replace(pos, 5, ".osrm.timestamp");
        }
    }
    else
    {
        output_file_name.replace(pos, 8, ".osrm");
        restriction_file_name.replace(pos, 8, ".osrm.restrictions");
        timestamp_file_name.replace(pos, 8, ".osrm.timestamp");
    }
}

int Extractor::Run(int argc, char *argv[])
{
    try
    {
        LogPolicy::GetInstance().Unmute();

        TIMER_START(extracting);

        if (!ParseArguments(argc, argv))
            return 0;

        if (1 > requested_num_threads)
        {
            SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
            return 1;
        }

        if (!boost::filesystem::is_regular_file(input_path))
        {
            SimpleLogger().Write(logWARNING) << "Input file " << input_path.string()
                                             << " not found!";
            return 1;
        }

        if (!boost::filesystem::is_regular_file(profile_path))
        {
            SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string()
                                             << " not found!";
            return 1;
        }

        const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();

        SimpleLogger().Write() << "Input file: " << input_path.filename().string();
        SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
        SimpleLogger().Write() << "Threads: " << requested_num_threads;
        if (recommended_num_threads != requested_num_threads)
        {
            SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
                                             << recommended_num_threads
                                             << "! This setting may have performance side-effects.";
        }

        tbb::task_scheduler_init init(requested_num_threads);

        /*** Setup Scripting Environment ***/
        ScriptingEnvironment scripting_environment(profile_path.string().c_str());

        GenerateOutputFilesNames();

        std::unordered_map<std::string, NodeID> string_map;
        ExtractionContainers extraction_containers;

        string_map[""] = 0;
        auto extractor_callbacks = osrm::make_unique<ExtractorCallbacks>(extraction_containers, string_map);

        osmium::io::File infile(input_path.string());
        osmium::io::Reader reader(infile);
        osmium::io::Header header = reader.header();

        unsigned number_of_nodes = 0;
        unsigned number_of_ways = 0;
        unsigned number_of_relations = 0;
        unsigned number_of_others = 0;

        SimpleLogger().Write() << "Parsing in progress..";
        TIMER_START(parsing);

        std::string generator = header.get("generator");
        if (generator.empty())
        {
            generator = "unknown tool";
        }
        SimpleLogger().Write() << "input file generated by " << generator;

        // TODO: write timestamp if non-empty
        std::string timestamp = header.get("osmosis_replication_timestamp");
        if (timestamp.empty())
        {
            timestamp = "n/a";
        }
        SimpleLogger().Write() << "timestamp: " << timestamp;

        boost::filesystem::ofstream timestamp_out(timestamp_file_name);
        timestamp_out.write(timestamp.c_str(), timestamp.length());
        timestamp_out.close();

        lua_State *lua_state = scripting_environment.getLuaState();
        luabind::set_pcall_callback(&lua_error_callback);

        RestrictionParser restriction_parser(scripting_environment);

        ExtractionNode result_node;
        ExtractionWay result_way;

        while (osmium::memory::Buffer buffer = reader.read()) {
            for (osmium::OSMEntity &entity : buffer)
            {
                switch (entity.type())
                {
                case osmium::item_type::node:
                    ++number_of_nodes;
                    result_node.Clear();
                    luabind::call_function<void>(
                        lua_state,
                        "node_function",
                        boost::cref(static_cast<osmium::Node &>(entity)),
                        boost::ref(result_node));
                    extractor_callbacks->ProcessNode(static_cast<osmium::Node &>(entity),
                                                     result_node);
                    break;
                case osmium::item_type::way:
                    ++number_of_ways;
                    result_way.Clear();
                    luabind::call_function<void>(
                        lua_state,
                        "way_function",
                        boost::cref(static_cast<osmium::Way &>(entity)),
                        boost::ref(result_way));
                    extractor_callbacks->ProcessWay(static_cast<osmium::Way &>(entity),
                                                    result_way);
                    break;
                case osmium::item_type::relation:
                    ++number_of_relations;
                    extractor_callbacks->ProcessRestriction(
                        restriction_parser.TryParse(static_cast<osmium::Relation &>(entity)));
                    break;
                default:
                    ++number_of_others;
                    break;
                }
            }
        }
        TIMER_STOP(parsing);
        SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
        extractor_callbacks.reset();

        if (extraction_containers.all_edges_list.empty())
        {
            SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
            return 1;
        }

        extraction_containers.PrepareData(output_file_name, restriction_file_name);

        TIMER_STOP(extracting);
        SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
        SimpleLogger().Write() << "To prepare the data for routing, run: "
                               << "./osrm-prepare " << output_file_name << std::endl;
    }
    catch (boost::program_options::too_many_positional_options_error &)
    {
        SimpleLogger().Write(logWARNING) << "Only one input file can be specified";
        return 1;
    }
    catch (std::exception &e)
    {
        SimpleLogger().Write(logWARNING) << e.what();
        return 1;
    }
    return 0;
}
<commit_msg>fix generation of file names<commit_after>/*

Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

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 HOLDER 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 "Extractor.h"

#include "ExtractionContainers.h"
#include "ExtractionNode.h"
#include "ExtractionWay.h"
#include "ExtractorCallbacks.h"
#include "RestrictionParser.h"
#include "ScriptingEnvironment.h"

#include "../Util/GitDescription.h"
#include "../Util/IniFileUtil.h"
#include "../Util/OSRMException.h"
#include "../Util/simple_logger.hpp"
#include "../Util/TimingUtil.h"
#include "../Util/make_unique.hpp"
#include "../typedefs.h"

#include <boost/program_options.hpp>

#include <luabind/luabind.hpp>

#include <tbb/task_scheduler_init.h>

#include <osmium/io/any_input.hpp>

#include <cstdlib>

#include <chrono>
#include <fstream>
#include <iostream>
#include <thread>
#include <unordered_map>

Extractor::Extractor() : requested_num_threads(0), file_has_pbf_format(false)
{
}

int lua_error_callback(lua_State *L) // This is so I can use my own function as an
// exception handler, pcall_log()
{
    luabind::object error_msg(luabind::from_stack(L, -1));
    std::ostringstream error_stream;
    error_stream << error_msg;
    throw OSRMException("ERROR occured in profile script:\n" + error_stream.str());
}

bool Extractor::ParseArguments(int argc, char *argv[])
{
    // declare a group of options that will be allowed only on command line
    boost::program_options::options_description generic_options("Options");
    generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
        "config,c",
        boost::program_options::value<boost::filesystem::path>(&config_file_path)
            ->default_value("extractor.ini"),
        "Path to a configuration file.");

    // declare a group of options that will be allowed both on command line and in config file
    boost::program_options::options_description config_options("Configuration");
    config_options.add_options()("profile,p",
                                 boost::program_options::value<boost::filesystem::path>(
                                     &profile_path)->default_value("profile.lua"),
                                 "Path to LUA routing profile")(
        "threads,t",
        boost::program_options::value<unsigned int>(&requested_num_threads)
            ->default_value(tbb::task_scheduler_init::default_num_threads()),
        "Number of threads to use");

    // hidden options, will be allowed both on command line and in config file, but will not be
    // shown to the user
    boost::program_options::options_description hidden_options("Hidden options");
    hidden_options.add_options()(
        "input,i",
        boost::program_options::value<boost::filesystem::path>(&input_path),
        "Input file in .osm, .osm.bz2 or .osm.pbf format");

    // positional option
    boost::program_options::positional_options_description positional_options;
    positional_options.add("input", 1);

    // combine above options for parsing
    boost::program_options::options_description cmdline_options;
    cmdline_options.add(generic_options).add(config_options).add(hidden_options);

    boost::program_options::options_description config_file_options;
    config_file_options.add(config_options).add(hidden_options);

    boost::program_options::options_description visible_options(
        boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
    visible_options.add(generic_options).add(config_options);

    // parse command line options
    boost::program_options::variables_map option_variables;
    boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
                                      .options(cmdline_options)
                                      .positional(positional_options)
                                      .run(),
                                  option_variables);

    if (option_variables.count("version"))
    {
        SimpleLogger().Write() << g_GIT_DESCRIPTION;
        return false;
    }

    if (option_variables.count("help"))
    {
        SimpleLogger().Write() << visible_options;
        return false;
    }

    boost::program_options::notify(option_variables);

    // parse config file
    if (boost::filesystem::is_regular_file(config_file_path))
    {
        SimpleLogger().Write() << "Reading options from: " << config_file_path.string();
        std::string ini_file_contents = ReadIniFileAndLowerContents(config_file_path);
        std::stringstream config_stream(ini_file_contents);
        boost::program_options::store(parse_config_file(config_stream, config_file_options),
                                      option_variables);
        boost::program_options::notify(option_variables);
    }

    if (!option_variables.count("input"))
    {
        SimpleLogger().Write() << visible_options;
        return false;
    }

    return true;
}

void Extractor::GenerateOutputFilesNames()
{
    output_file_name = input_path.string();
    restriction_file_name = input_path.string();
    timestamp_file_name = input_path.string();
    std::string::size_type pos = output_file_name.find(".osm.bz2");
    if (pos == std::string::npos)
    {
        pos = output_file_name.find(".osm.pbf");
        if (pos != std::string::npos)
        {
            file_has_pbf_format = true;
        }
        else
        {
            pos = output_file_name.find(".osm.xml");
        }
    }
    if (pos == std::string::npos)
    {
        pos = output_file_name.find(".pbf");
        if (pos != std::string::npos)
        {
            file_has_pbf_format = true;
        }
    }
    if (pos == std::string::npos)
    {
        pos = output_file_name.find(".osm");
        if (pos == std::string::npos)
        {
            output_file_name.append(".osrm");
            restriction_file_name.append(".osrm.restrictions");
            timestamp_file_name.append(".osrm.timestamp");
        }
        else
        {
            output_file_name.replace(pos, 5, ".osrm");
            restriction_file_name.replace(pos, 5, ".osrm.restrictions");
            timestamp_file_name.replace(pos, 5, ".osrm.timestamp");
        }
    }
    else
    {
        output_file_name.replace(pos, 8, ".osrm");
        restriction_file_name.replace(pos, 8, ".osrm.restrictions");
        timestamp_file_name.replace(pos, 8, ".osrm.timestamp");
    }
}

int Extractor::Run(int argc, char *argv[])
{
    try
    {
        LogPolicy::GetInstance().Unmute();

        TIMER_START(extracting);

        if (!ParseArguments(argc, argv))
            return 0;

        if (1 > requested_num_threads)
        {
            SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
            return 1;
        }

        if (!boost::filesystem::is_regular_file(input_path))
        {
            SimpleLogger().Write(logWARNING) << "Input file " << input_path.string()
                                             << " not found!";
            return 1;
        }

        if (!boost::filesystem::is_regular_file(profile_path))
        {
            SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string()
                                             << " not found!";
            return 1;
        }

        const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();

        SimpleLogger().Write() << "Input file: " << input_path.filename().string();
        SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
        SimpleLogger().Write() << "Threads: " << requested_num_threads;
        if (recommended_num_threads != requested_num_threads)
        {
            SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
                                             << recommended_num_threads
                                             << "! This setting may have performance side-effects.";
        }

        tbb::task_scheduler_init init(requested_num_threads);

        /*** Setup Scripting Environment ***/
        ScriptingEnvironment scripting_environment(profile_path.string().c_str());

        GenerateOutputFilesNames();

        std::unordered_map<std::string, NodeID> string_map;
        ExtractionContainers extraction_containers;

        string_map[""] = 0;
        auto extractor_callbacks = osrm::make_unique<ExtractorCallbacks>(extraction_containers, string_map);

        osmium::io::File infile(input_path.string());
        osmium::io::Reader reader(infile);
        osmium::io::Header header = reader.header();

        unsigned number_of_nodes = 0;
        unsigned number_of_ways = 0;
        unsigned number_of_relations = 0;
        unsigned number_of_others = 0;

        SimpleLogger().Write() << "Parsing in progress..";
        TIMER_START(parsing);

        std::string generator = header.get("generator");
        if (generator.empty())
        {
            generator = "unknown tool";
        }
        SimpleLogger().Write() << "input file generated by " << generator;

        // TODO: write timestamp if non-empty
        std::string timestamp = header.get("osmosis_replication_timestamp");
        if (timestamp.empty())
        {
            timestamp = "n/a";
        }
        SimpleLogger().Write() << "timestamp: " << timestamp;

        boost::filesystem::ofstream timestamp_out(timestamp_file_name);
        timestamp_out.write(timestamp.c_str(), timestamp.length());
        timestamp_out.close();

        lua_State *lua_state = scripting_environment.getLuaState();
        luabind::set_pcall_callback(&lua_error_callback);

        RestrictionParser restriction_parser(scripting_environment);

        ExtractionNode result_node;
        ExtractionWay result_way;

        while (osmium::memory::Buffer buffer = reader.read()) {
            for (osmium::OSMEntity &entity : buffer)
            {
                switch (entity.type())
                {
                case osmium::item_type::node:
                    ++number_of_nodes;
                    result_node.Clear();
                    // luabind::call_function<void>(
                    //     lua_state,
                    //     "node_function",
                    //     boost::cref(static_cast<osmium::Node &>(entity)),
                    //     boost::ref(result_node));
                    // extractor_callbacks->ProcessNode(static_cast<osmium::Node &>(entity),
                    //                                  result_node);
                    break;
                case osmium::item_type::way:
                    ++number_of_ways;
                    result_way.Clear();
                    // luabind::call_function<void>(
                    //     lua_state,
                    //     "way_function",
                    //     boost::cref(static_cast<osmium::Way &>(entity)),
                    //     boost::ref(result_way));
                    // extractor_callbacks->ProcessWay(static_cast<osmium::Way &>(entity),
                    //                                 result_way);
                    break;
                case osmium::item_type::relation:
                    ++number_of_relations;
                    extractor_callbacks->ProcessRestriction(
                        restriction_parser.TryParse(static_cast<osmium::Relation &>(entity)));
                    break;
                default:
                    ++number_of_others;
                    break;
                }
            }
        }
        TIMER_STOP(parsing);
        SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
        SimpleLogger().Write() << "Raw input contains " << number_of_nodes << " nodes, " << number_of_ways << " ways, and " << number_of_relations << " relations";

        extractor_callbacks.reset();

        if (extraction_containers.all_edges_list.empty())
        {
            SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
            return 1;
        }

        extraction_containers.PrepareData(output_file_name, restriction_file_name);

        TIMER_STOP(extracting);
        SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
        SimpleLogger().Write() << "To prepare the data for routing, run: "
                               << "./osrm-prepare " << output_file_name << std::endl;
    }
    catch (boost::program_options::too_many_positional_options_error &)
    {
        SimpleLogger().Write(logWARNING) << "Only one input file can be specified";
        return 1;
    }
    catch (std::exception &e)
    {
        SimpleLogger().Write(logWARNING) << e.what();
        return 1;
    }
    return 0;
}
<|endoftext|>


<commit_before><commit_msg>AliFITv8: Remove old containing volumes and some of the screws, rods, which cause overlaps<commit_after><|endoftext|>


<commit_before>/*
 * File:   Network.cpp
 * Author: janvojt
 *
 * Created on May 30, 2014, 12:17 AM
 */

#include "Network.h"

#include <cstring>
#include <string>

Network::Network(NetworkConfiguration *conf) {
    this->conf = conf;
    this->noLayers = conf->getLayers();
    this->bias = 0;
    initWeights();
    initInputs();
}

Network::Network(const Network& orig) {
}

Network::~Network() {
    delete weights;
    delete inputs;
}

NetworkConfiguration* Network::getConfiguration() {
    return conf;
}

void Network::initWeights() {
    int noWeights = 0;
    int pLayer = 1; // neurons in previous layer
    for (int i = 0; i<noLayers; i++) {
        int tLayer = this->conf->getNeurons(i);
        noWeights += pLayer * tLayer;
        pLayer = tLayer;
    }
    weights = new float[noWeights];

    // initialize weights for input layer to 1
    for (int i = 0; i<getInputNeurons(); i++) {
        weights[i] = 1;
    }
}

void Network::initInputs() {
    int noNeurons = 0;
    for (int i = 0; i<noLayers; i++) {
        noNeurons += conf->getNeurons(i);
    }
    this->noNeurons = noNeurons;
    inputs = new float[noNeurons];
}

void Network::setInput(float* input) {
    std::memcpy(inputs, input, sizeof(float) * getInputNeurons());
}

void Network::run() {
    // number of neurons in so far processed layers
    int nPrevLayers = 0;
    // for every layer
    for (int l = 0; l<noLayers; l++) {
        int nThisLayer = conf->getNeurons(l);
        int nNextLayer = conf->getNeurons(l+1);
        clearLayer(inputs + nPrevLayers + nThisLayer, nNextLayer);
        // for every neuron in (l)th layer
        for (int i = 0; i<nThisLayer; i++) {
            // for every neuron in (l+1)th layer
            for (int j = 0; j<nNextLayer; j++) {
                int indexFrom = nPrevLayers + i;
                int indexTo = nPrevLayers + nThisLayer + j;
                inputs[indexTo] += inputs[indexFrom];
            }
        }
        nPrevLayers += nThisLayer;
    }
}

void Network::clearLayer(float *inputPtr, int layerSize) {
    std::fill_n(inputPtr, layerSize, 0);
}

float* Network::getOutput() {
    return inputs + noNeurons - getOutputNeurons();
}

int Network::getInputNeurons() {
    return conf->getNeurons(0);
}

int Network::getOutputNeurons() {
    return conf->getNeurons(noLayers-1);
}
<commit_msg>Using weights when computing output.<commit_after>/*
 * File:   Network.cpp
 * Author: janvojt
 *
 * Created on May 30, 2014, 12:17 AM
 */

#include "Network.h"

#include <cstring>
#include <string>

Network::Network(NetworkConfiguration *conf) {
    this->conf = conf;
    this->noLayers = conf->getLayers();
    this->bias = 0;
    initWeights();
    initInputs();
}

Network::Network(const Network& orig) {
}

Network::~Network() {
    delete weights;
    delete inputs;
}

NetworkConfiguration* Network::getConfiguration() {
    return conf;
}

void Network::initWeights() {
    int noWeights = 0;
    int pLayer = 1; // neurons in previous layer
    for (int i = 0; i<noLayers; i++) {
        int tLayer = this->conf->getNeurons(i);
        noWeights += pLayer * tLayer;
        pLayer = tLayer;
    }
    weights = new float[noWeights];

    // initialize weights for input layer to 1
    for (int i = 0; i<getInputNeurons(); i++) {
        weights[i] = 1;
    }
}

void Network::initInputs() {
    int noNeurons = 0;
    for (int i = 0; i<noLayers; i++) {
        noNeurons += conf->getNeurons(i);
    }
    this->noNeurons = noNeurons;
    inputs = new float[noNeurons];
}

void Network::setInput(float* input) {
    std::memcpy(inputs, input, sizeof(float) * getInputNeurons());
}

void Network::run() {
    // number of neurons in so far processed layers
    int nPrevLayers = 0;
    float *weighPtr = weights + getInputNeurons();
    // for every layer
    for (int l = 0; l<noLayers; l++) {
        int nThisLayer = conf->getNeurons(l);
        int nNextLayer = conf->getNeurons(l+1);
        clearLayer(inputs + nPrevLayers + nThisLayer, nNextLayer);
        // for every neuron in (l)th layer
        for (int i = 0; i<nThisLayer; i++) {
            // for every neuron in (l+1)th layer
            for (int j = 0; j<nNextLayer; j++) {
                int indexFrom = nPrevLayers + i;
                int indexTo = nPrevLayers + nThisLayer + j;
                inputs[indexTo] += *weighPtr * inputs[indexFrom];
                weighPtr++;
            }
        }
        nPrevLayers += nThisLayer;
    }
}

void Network::clearLayer(float *inputPtr, int layerSize) {
    std::fill_n(inputPtr, layerSize, 0);
}

float* Network::getOutput() {
    return inputs + noNeurons - getOutputNeurons();
}

int Network::getInputNeurons() {
    return conf->getNeurons(0);
}

int Network::getOutputNeurons() {
    return conf->getNeurons(noLayers-1);
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2019 The nanoFramework project contributors
// See LICENSE file in the project root for full license information.
//

#include "sys_dev_dac_native.h"

static const CLR_RT_MethodHandler method_lookup[] =
{
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    Library_sys_dev_dac_native_System_Devices_Dac_DacChannel::NativeWriteValue___VOID__U2,
    Library_sys_dev_dac_native_System_Devices_Dac_DacChannel::NativeDispose___VOID__BOOLEAN,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    Library_sys_dev_dac_native_System_Devices_Dac_DacController::NativeOpenChannel___VOID__I4,
    Library_sys_dev_dac_native_System_Devices_Dac_DacController::NativeGetChannelCount___I4,
    Library_sys_dev_dac_native_System_Devices_Dac_DacController::NativeGetResolutionInBits___I4,
    Library_sys_dev_dac_native_System_Devices_Dac_DacController::NativeInit___VOID,
    NULL,
    Library_sys_dev_dac_native_System_Devices_Dac_DacController::GetDeviceSelector___STATIC__STRING,
    NULL,
    NULL,
    NULL,
};

const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_System_Devices_Dac =
{
    "System.Devices.Dac",
    0x12640AF3,
    method_lookup,
    { 100, 0, 0, 4 }
};
<commit_msg>Update declaration of Devices.Dac (#1479)<commit_after>//
// Copyright (c) 2019 The nanoFramework project contributors
// See LICENSE file in the project root for full license information.
//

#include "sys_dev_dac_native.h"

static const CLR_RT_MethodHandler method_lookup[] =
{
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    Library_sys_dev_dac_native_System_Devices_Dac_DacChannel::NativeWriteValue___VOID__U2,
    Library_sys_dev_dac_native_System_Devices_Dac_DacChannel::NativeDispose___VOID__BOOLEAN,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    Library_sys_dev_dac_native_System_Devices_Dac_DacController::NativeOpenChannel___VOID__I4,
    Library_sys_dev_dac_native_System_Devices_Dac_DacController::NativeGetChannelCount___I4,
    Library_sys_dev_dac_native_System_Devices_Dac_DacController::NativeGetResolutionInBits___I4,
    Library_sys_dev_dac_native_System_Devices_Dac_DacController::NativeInit___VOID,
    NULL,
    NULL,
    Library_sys_dev_dac_native_System_Devices_Dac_DacController::GetDeviceSelector___STATIC__STRING,
    NULL,
    NULL,
    NULL,
};

const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_System_Devices_Dac =
{
    "System.Devices.Dac",
    0x9B932004,
    method_lookup,
    { 100, 0, 0, 5 }
};
<|endoftext|>


<commit_before>#include "IHMD.hpp"
#include <bx/fpumath.h>
#include <SDL.h>
#include "Registry.hpp"

namespace xveearr
{

namespace
{

const unsigned int gViewportWidth = 1280 / 2;
const unsigned int gViewportHeight = 720;
const float gLeftEye[] = { -50.0f, 0.0f, 0.f };
const float gRightEye[] = { 50.0f, 0.0f, 0.f };
float gLookAt[] = { 0.f, 0.0f, -10.f };

}

class NullHMD: public IHMD
{
public:
	NullHMD()
	{
		mRenderData[Eye::Left].mFrameBuffer = BGFX_INVALID_HANDLE;
		mRenderData[Eye::Right].mFrameBuffer = BGFX_INVALID_HANDLE;
	}

	bool init(const ApplicationContext&)
	{
		bx::mtxSRT(mHeadTransform,
			1.f, 1.f, 1.f,
			0.f, 0.f, 0.f,
			0.f, 0.f, 600.f);

		return true;
	}

	void shutdown()
	{
	}

	void initRenderer()
	{
	}

	void shutdownRenderer()
	{
	}

	void beginRender()
	{
	}

	void endRender()
	{
	}

	void prepareResources()
	{
		mRenderData[Eye::Left].mFrameBuffer = createEyeFB();
		mRenderData[Eye::Right].mFrameBuffer = createEyeFB();
	}

	void releaseResources()
	{
		if(bgfx::isValid(mRenderData[Eye::Left].mFrameBuffer))
		{
			bgfx::destroyFrameBuffer(mRenderData[Eye::Left].mFrameBuffer);
		}

		if(bgfx::isValid(mRenderData[Eye::Right].mFrameBuffer))
		{
			bgfx::destroyFrameBuffer(mRenderData[Eye::Right].mFrameBuffer);
		}
	}

	void getViewportSize(unsigned int& width, unsigned int& height)
	{
		width = gViewportWidth;
		height = gViewportHeight;
	}

	const char* getName() const
	{
		return "null";
	}

	void update()
	{
		const Uint8* keyStates = SDL_GetKeyboardState(NULL);
		float translation[3] = {};
		float rotation[3] = {};

		if(keyStates[SDL_SCANCODE_A]) { translation[0] = -4.f; }
		if(keyStates[SDL_SCANCODE_D]) { translation[0] =  4.f; }
		if(keyStates[SDL_SCANCODE_W]) { translation[2] = -4.f; }
		if(keyStates[SDL_SCANCODE_S]) { translation[2] =  4.f; }
		if(keyStates[SDL_SCANCODE_Q]) { rotation[1] = -0.01f; }
		if(keyStates[SDL_SCANCODE_E]) { rotation[1] =  0.01f; }
		if(keyStates[SDL_SCANCODE_R]) { rotation[0] = -0.01f; }
		if(keyStates[SDL_SCANCODE_F]) { rotation[0] =  0.01f; }

		float move[16];
		bx::mtxSRT(move,
			1.f, 1.f, 1.f,
			rotation[0], rotation[1], rotation[2],
			translation[0], translation[1], translation[2]
		);
		float tmp[16];
		memcpy(tmp, mHeadTransform, sizeof(tmp));
		bx::mtxMul(mHeadTransform, move, tmp);

		float leftEye[3];
		float leftLookAt[3];
		float leftRelLookat[3];
		bx::vec3MulMtx(leftEye, gLeftEye, mHeadTransform);
		bx::vec3Add(leftRelLookat, gLeftEye, gLookAt);
		bx::vec3MulMtx(leftLookAt, leftRelLookat, mHeadTransform);
		bx::mtxLookAtRh(
			mRenderData[Eye::Left].mViewTransform, leftEye, leftLookAt
		);
		bx::mtxProjRh(mRenderData[Eye::Left].mViewProjection,
			50.0f,
			(float)gViewportWidth / (float)gViewportHeight,
			1.f, 100000.f
		);

		float rightEye[3];
		float rightLookAt[3];
		float rightRelLookat[3];
		bx::vec3MulMtx(rightEye, gRightEye, mHeadTransform);
		bx::vec3Add(rightRelLookat, gRightEye, gLookAt);
		bx::vec3MulMtx(rightLookAt, rightRelLookat, mHeadTransform);
		bx::mtxLookAtRh(
			mRenderData[Eye::Right].mViewTransform, rightEye, rightLookAt
		);
		bx::mtxProjRh(mRenderData[Eye::Right].mViewProjection,
			50.0f,
			(float)gViewportWidth / (float)gViewportHeight,
			1.f, 100000.f
		);
	}

	const RenderData& getRenderData(Eye::Enum eye)
	{
		return mRenderData[eye];
	}

private:
	bgfx::FrameBufferHandle createEyeFB()
	{
		bgfx::TextureHandle textures[] = {
			bgfx::createTexture2D(
				gViewportWidth, gViewportHeight, 1,
				bgfx::TextureFormat::BGRA8,
				BGFX_TEXTURE_RT|BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP
			),
			bgfx::createTexture2D(
				gViewportWidth, gViewportHeight, 1,
				bgfx::TextureFormat::D16,
				BGFX_TEXTURE_RT_WRITE_ONLY
			)
		};

		return bgfx::createFrameBuffer(BX_COUNTOF(textures), textures, true);
	}

	float mHeadTransform[16];
	RenderData mRenderData[Eye::Count];
};

NullHMD gNullHMDInstance;
Registry<IHMD>::Entry gFakeHMDEntry(&gNullHMDInstance);

}
<commit_msg>Use floating point format for eye framebuffer's depth texture<commit_after>#include "IHMD.hpp"
#include <bx/fpumath.h>
#include <SDL.h>
#include "Registry.hpp"

namespace xveearr
{

namespace
{

const unsigned int gViewportWidth = 1280 / 2;
const unsigned int gViewportHeight = 720;
const float gLeftEye[] = { -50.0f, 0.0f, 0.f };
const float gRightEye[] = { 50.0f, 0.0f, 0.f };
float gLookAt[] = { 0.f, 0.0f, -10.f };

}

class NullHMD: public IHMD
{
public:
	NullHMD()
	{
		mRenderData[Eye::Left].mFrameBuffer = BGFX_INVALID_HANDLE;
		mRenderData[Eye::Right].mFrameBuffer = BGFX_INVALID_HANDLE;
	}

	bool init(const ApplicationContext&)
	{
		bx::mtxSRT(mHeadTransform,
			1.f, 1.f, 1.f,
			0.f, 0.f, 0.f,
			0.f, 0.f, 600.f);

		return true;
	}

	void shutdown()
	{
	}

	void initRenderer()
	{
	}

	void shutdownRenderer()
	{
	}

	void beginRender()
	{
	}

	void endRender()
	{
	}

	void prepareResources()
	{
		mRenderData[Eye::Left].mFrameBuffer = createEyeFB();
		mRenderData[Eye::Right].mFrameBuffer = createEyeFB();
	}

	void releaseResources()
	{
		if(bgfx::isValid(mRenderData[Eye::Left].mFrameBuffer))
		{
			bgfx::destroyFrameBuffer(mRenderData[Eye::Left].mFrameBuffer);
		}

		if(bgfx::isValid(mRenderData[Eye::Right].mFrameBuffer))
		{
			bgfx::destroyFrameBuffer(mRenderData[Eye::Right].mFrameBuffer);
		}
	}

	void getViewportSize(unsigned int& width, unsigned int& height)
	{
		width = gViewportWidth;
		height = gViewportHeight;
	}

	const char* getName() const
	{
		return "null";
	}

	void update()
	{
		const Uint8* keyStates = SDL_GetKeyboardState(NULL);
		float translation[3] = {};
		float rotation[3] = {};

		if(keyStates[SDL_SCANCODE_A]) { translation[0] = -4.f; }
		if(keyStates[SDL_SCANCODE_D]) { translation[0] =  4.f; }
		if(keyStates[SDL_SCANCODE_W]) { translation[2] = -4.f; }
		if(keyStates[SDL_SCANCODE_S]) { translation[2] =  4.f; }
		if(keyStates[SDL_SCANCODE_Q]) { rotation[1] = -0.01f; }
		if(keyStates[SDL_SCANCODE_E]) { rotation[1] =  0.01f; }
		if(keyStates[SDL_SCANCODE_R]) { rotation[0] = -0.01f; }
		if(keyStates[SDL_SCANCODE_F]) { rotation[0] =  0.01f; }

		float move[16];
		bx::mtxSRT(move,
			1.f, 1.f, 1.f,
			rotation[0], rotation[1], rotation[2],
			translation[0], translation[1], translation[2]
		);
		float tmp[16];
		memcpy(tmp, mHeadTransform, sizeof(tmp));
		bx::mtxMul(mHeadTransform, move, tmp);

		float leftEye[3];
		float leftLookAt[3];
		float leftRelLookat[3];
		bx::vec3MulMtx(leftEye, gLeftEye, mHeadTransform);
		bx::vec3Add(leftRelLookat, gLeftEye, gLookAt);
		bx::vec3MulMtx(leftLookAt, leftRelLookat, mHeadTransform);
		bx::mtxLookAtRh(
			mRenderData[Eye::Left].mViewTransform, leftEye, leftLookAt
		);
		bx::mtxProjRh(mRenderData[Eye::Left].mViewProjection,
			50.0f,
			(float)gViewportWidth / (float)gViewportHeight,
			1.f, 100000.f
		);

		float rightEye[3];
		float rightLookAt[3];
		float rightRelLookat[3];
		bx::vec3MulMtx(rightEye, gRightEye, mHeadTransform);
		bx::vec3Add(rightRelLookat, gRightEye, gLookAt);
		bx::vec3MulMtx(rightLookAt, rightRelLookat, mHeadTransform);
		bx::mtxLookAtRh(
			mRenderData[Eye::Right].mViewTransform, rightEye, rightLookAt
		);
		bx::mtxProjRh(mRenderData[Eye::Right].mViewProjection,
			50.0f,
			(float)gViewportWidth / (float)gViewportHeight,
			1.f, 100000.f
		);
	}

	const RenderData& getRenderData(Eye::Enum eye)
	{
		return mRenderData[eye];
	}

private:
	bgfx::FrameBufferHandle createEyeFB()
	{
		bgfx::TextureHandle textures[] = {
			bgfx::createTexture2D(
				gViewportWidth, gViewportHeight, 1,
				bgfx::TextureFormat::BGRA8,
				BGFX_TEXTURE_RT|BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP
			),
			bgfx::createTexture2D(
				gViewportWidth, gViewportHeight, 1,
				bgfx::TextureFormat::D16F,
				BGFX_TEXTURE_RT_WRITE_ONLY
			)
		};

		return bgfx::createFrameBuffer(BX_COUNTOF(textures), textures, true);
	}

	float mHeadTransform[16];
	RenderData mRenderData[Eye::Count];
};

NullHMD gNullHMDInstance;
Registry<IHMD>::Entry gFakeHMDEntry(&gNullHMDInstance);

}
<|endoftext|>


<commit_before>#include <Process.h>
#include <boost/interprocess/sync/named_semaphore.hpp>
#include <unistd.h>

namespace Interprocess
{

using Semaphore = boost::interprocess::named_semaphore;
boost::interprocess::open_or_create_t OpenCreate = boost::interprocess::open_or_create;
using namespace std;

Process::Process(Process&& otherProcess)
  : _processId(otherProcess._processId), _mainFunction(otherProcess._mainFunction)
{
  otherProcess._processId = -1;
}

Process& Process::operator=(Process&& otherProcess)
{
  _processId = otherProcess._processId;
  _mainFunction = otherProcess._mainFunction;
  return *this;
}

void Process::startProcess() const
{
  auto pIDString = to_string(_processId);
  Semaphore semaphore(OpenCreate, pIDString.c_str(), 0);
  semaphore.post();
}

void Process::childProcessRunner()
{
  _processId = fork();
  if( ! _processId)
  {
    auto pIDString = to_string(getpid());
    Semaphore semaphore(OpenCreate, pIDString.c_str(), 0);
    semaphore.wait();
    _mainFunction();
    exit(0);
  }
}

}
<commit_msg>Removed global open or create variable, fixed move constructor.<commit_after>#include <Process.h>
#include <boost/interprocess/sync/named_semaphore.hpp>
#include <unistd.h>

namespace Interprocess
{

using Semaphore = boost::interprocess::named_semaphore;
using namespace boost::interprocess;
using namespace std;

Process::Process(Process&& otherProcess)
  : _processId(otherProcess._processId), _mainFunction(otherProcess._mainFunction)
{
  otherProcess._processId = -1;
}

Process& Process::operator=(Process&& otherProcess)
{
  _processId = otherProcess._processId;
  _mainFunction = otherProcess._mainFunction;
  otherProcess._processId = -1;
  return *this;
}

void Process::startProcess() const
{
  auto pIDString = to_string(_processId);
  Semaphore semaphore(open_or_create, pIDString.c_str(), 0);
  semaphore.post();
}

void Process::childProcessRunner()
{
  _processId = fork();
  if( ! _processId)
  {
    auto pIDString = to_string(getpid());
    Semaphore semaphore(open_or_create, pIDString.c_str(), 0);
    semaphore.wait();
    _mainFunction();
    exit(0);
  }
}

}
<|endoftext|>


<commit_before>// Program.cpp

#include "stdafx.h"
#include "Program.h"
#include "PythonStuff.h"
#include "../../tinyxml/tinyxml.h"
#include "ProgramCanvas.h"
#include "NCCode.h"
#include "../../interface/MarkedObject.h"
#include "../../interface/PropertyString.h"
#include "Profile.h"
#include "Pocket.h"
#include "ZigZag.h"

bool COperations::CanAdd(HeeksObj* object)
{
	return object->GetType() == ProfileType || object->GetType() == PocketType || object->GetType() == ZigZagType;
}

void COperations::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "Operations" );
	root->LinkEndChild( element );
	WriteBaseXML(element);
}

//static
HeeksObj* COperations::ReadFromXMLElement(TiXmlElement* pElem)
{
	COperations* new_object = new COperations;
	new_object->ReadBaseXML(pElem);
	return new_object;
}

CProgram::CProgram():m_machine(_T("nc.iso")), m_output_file(_T("test.tap")), m_nc_code(NULL), m_operations(NULL), m_script_edited(false)
{
}

HeeksObj *CProgram::MakeACopy(void)const
{
	return new CProgram(*this);
}

void CProgram::CopyFrom(const HeeksObj* object)
{
	operator=(*((CProgram*)object));
}

static void on_set_machine(const wxChar* value, HeeksObj* object){((CProgram*)object)->m_machine = value;}
static void on_set_output_file(const wxChar* value, HeeksObj* object){((CProgram*)object)->m_output_file = value;}

void CProgram::GetProperties(std::list<Property *> *list)
{
	list->push_back(new PropertyString(_("machine"), m_machine, this, on_set_machine));
	list->push_back(new PropertyString(_("output file"), m_output_file, this, on_set_output_file));
	HeeksObj::GetProperties(list);
}

bool CProgram::CanAdd(HeeksObj* object)
{
	return object->GetType() == NCCodeType || object->GetType() == OperationsType;
}

bool CProgram::CanAddTo(HeeksObj* owner)
{
	return owner->GetType() == DocumentType;
}

void CProgram::SetClickMarkPoint(MarkedObject* marked_object, const double* ray_start, const double* ray_direction)
{
	if(marked_object->m_map.size() > 0)
	{
		MarkedObject* sub_marked_object = marked_object->m_map.begin()->second;
		if(sub_marked_object)
		{
			HeeksObj* object = sub_marked_object->m_map.begin()->first;
			if(object && object->GetType() == NCCodeType)
			{
				((CNCCode*)object)->SetClickMarkPoint(sub_marked_object, ray_start, ray_direction);
			}
		}
	}
}

void CProgram::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "Program" );
	root->LinkEndChild( element );
	element->SetAttribute("machine", Ttc(m_machine.c_str()));
	element->SetAttribute("output_file", Ttc(m_output_file.c_str()));
	element->SetAttribute("program", Ttc(theApp.m_program_canvas->m_textCtrl->GetValue()));

	WriteBaseXML(element);
}

bool CProgram::Add(HeeksObj* object, HeeksObj* prev_object)
{
	if(object->GetType() == NCCodeType)m_nc_code = (CNCCode*)object;
	if(object->GetType() == OperationsType)m_operations = (COperations*)object;
	return ObjList::Add(object, prev_object);
}

void CProgram::Remove(HeeksObj* object)
{
	 // these shouldn't happen, though
	if(object == m_nc_code)m_nc_code = NULL;
	else if(object == m_operations)m_operations = NULL;

	ObjList::Remove(object);
}

// static member function
HeeksObj* CProgram::ReadFromXMLElement(TiXmlElement* pElem)
{
	CProgram* new_object = new CProgram;

	// get the attributes
	for(TiXmlAttribute* a = pElem->FirstAttribute(); a; a = a->Next())
	{
		std::string name(a->Name());
		if(name == "machine"){new_object->m_machine.assign(Ctt(a->Value()));}
		else if(name == "output_file"){new_object->m_output_file.assign(Ctt(a->Value()));}
		else if(name == "program"){theApp.m_program_canvas->m_textCtrl->SetValue(Ctt(a->Value()));}
	}

	new_object->ReadBaseXML(pElem);
	theApp.m_program = new_object;

	return new_object;
}

void CProgram::RewritePythonProgram()
{
	theApp.m_program_canvas->m_textCtrl->Clear();
	CZigZag::number_for_stl_file = 1;

	bool profile_op_exists = false;
	bool pocket_op_exists = false;
	bool zigzag_op_exists = false;
	for(HeeksObj* object = m_operations->GetFirstChild(); object; object = m_operations->GetNextChild())
	{
		if(object->GetType() == ProfileType)
		{
			profile_op_exists = true;
		}
		else if(object->GetType() == PocketType)
		{
			pocket_op_exists = true;
		}
		else if(object->GetType() == ZigZagType)
		{
			zigzag_op_exists = true;
		}
	}

	// add standard stuff at the top

	// kurve related things
	if(profile_op_exists)
	{
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("import kurve\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("import kurve_funcs\n"));
	}

	// area related things
	if(pocket_op_exists)
	{
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("import area\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("import area_funcs\n"));
	}

	// pycam stuff
	if(zigzag_op_exists)
	{
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("import sys\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("sys.path.insert(0,'PyCam/trunk')\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from pycam.Geometry import *\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from pycam.Cutters.SphericalCutter import *\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from pycam.Cutters.CylindricalCutter import *\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from pycam.Importers.STLImporter import ImportModel\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from pycam.PathGenerators.DropCutter import DropCutter\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from PyCamToHeeks import HeeksCNCExporter\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("\n"));
	}

	// machine general stuff
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("from nc.nc import *\n"));

	// specific machine
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("import ") + m_machine + _T("\n"));
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("\n"));

	// output file
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("output('") + m_output_file + _T("')\n"));

	// begin program
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("program_begin(123, 'Test program')\n"));
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("absolute()\n"));
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("metric()\n"));
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("set_plane(0)\n"));
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("\n"));

	// write the operations
	for(HeeksObj* object = m_operations->GetFirstChild(); object; object = m_operations->GetNextChild())
	{
		switch(object->GetType())
		{
		case ProfileType:
			((CProfile*)object)->AppendTextToProgram();
			break;
		case PocketType:
			((CPocket*)object)->AppendTextToProgram();
			break;
		case ZigZagType:
			((CZigZag*)object)->AppendTextToProgram();
			break;
		}
	}

}

ProgramUserType CProgram::GetUserType()
{
	if(m_nc_code->m_user_edited)return ProgramUserTypeNC;
	if(m_script_edited)return ProgramUserTypeScript;
	if(m_operations->GetFirstChild())return ProgramUserTypeTree;
	return ProgramUserTypeUnkown;
}

void CProgram::UpdateFromUserType()
{
#if 0
	switch(GetUserType())
	{
	case ProgramUserTypeUnkown:

	case tree:
   Enable "Operations" icon in tree
     editing the tree, recreates the python script
   Read only "Program" window
     pressing "Post-process" creates the NC code ( and backplots it )
   Read only "Output" window
   Disable all buttons on "Output" window

	}
#endif
}<commit_msg>import pycam.Cutters.ToroidalCutter<commit_after>// Program.cpp

#include "stdafx.h"
#include "Program.h"
#include "PythonStuff.h"
#include "../../tinyxml/tinyxml.h"
#include "ProgramCanvas.h"
#include "NCCode.h"
#include "../../interface/MarkedObject.h"
#include "../../interface/PropertyString.h"
#include "Profile.h"
#include "Pocket.h"
#include "ZigZag.h"

bool COperations::CanAdd(HeeksObj* object)
{
	return object->GetType() == ProfileType || object->GetType() == PocketType || object->GetType() == ZigZagType;
}

void COperations::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "Operations" );
	root->LinkEndChild( element );
	WriteBaseXML(element);
}

//static
HeeksObj* COperations::ReadFromXMLElement(TiXmlElement* pElem)
{
	COperations* new_object = new COperations;
	new_object->ReadBaseXML(pElem);
	return new_object;
}

CProgram::CProgram():m_machine(_T("nc.iso")), m_output_file(_T("test.tap")), m_nc_code(NULL), m_operations(NULL), m_script_edited(false)
{
}

HeeksObj *CProgram::MakeACopy(void)const
{
	return new CProgram(*this);
}

void CProgram::CopyFrom(const HeeksObj* object)
{
	operator=(*((CProgram*)object));
}

static void on_set_machine(const wxChar* value, HeeksObj* object){((CProgram*)object)->m_machine = value;}
static void on_set_output_file(const wxChar* value, HeeksObj* object){((CProgram*)object)->m_output_file = value;}

void CProgram::GetProperties(std::list<Property *> *list)
{
	list->push_back(new PropertyString(_("machine"), m_machine, this, on_set_machine));
	list->push_back(new PropertyString(_("output file"), m_output_file, this, on_set_output_file));
	HeeksObj::GetProperties(list);
}

bool CProgram::CanAdd(HeeksObj* object)
{
	return object->GetType() == NCCodeType || object->GetType() == OperationsType;
}

bool CProgram::CanAddTo(HeeksObj* owner)
{
	return owner->GetType() == DocumentType;
}

void CProgram::SetClickMarkPoint(MarkedObject* marked_object, const double* ray_start, const double* ray_direction)
{
	if(marked_object->m_map.size() > 0)
	{
		MarkedObject* sub_marked_object = marked_object->m_map.begin()->second;
		if(sub_marked_object)
		{
			HeeksObj* object = sub_marked_object->m_map.begin()->first;
			if(object && object->GetType() == NCCodeType)
			{
				((CNCCode*)object)->SetClickMarkPoint(sub_marked_object, ray_start, ray_direction);
			}
		}
	}
}

void CProgram::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "Program" );
	root->LinkEndChild( element );
	element->SetAttribute("machine", Ttc(m_machine.c_str()));
	element->SetAttribute("output_file", Ttc(m_output_file.c_str()));
	element->SetAttribute("program", Ttc(theApp.m_program_canvas->m_textCtrl->GetValue()));

	WriteBaseXML(element);
}

bool CProgram::Add(HeeksObj* object, HeeksObj* prev_object)
{
	if(object->GetType() == NCCodeType)m_nc_code = (CNCCode*)object;
	if(object->GetType() == OperationsType)m_operations = (COperations*)object;
	return ObjList::Add(object, prev_object);
}

void CProgram::Remove(HeeksObj* object)
{
	 // these shouldn't happen, though
	if(object == m_nc_code)m_nc_code = NULL;
	else if(object == m_operations)m_operations = NULL;

	ObjList::Remove(object);
}

// static member function
HeeksObj* CProgram::ReadFromXMLElement(TiXmlElement* pElem)
{
	CProgram* new_object = new CProgram;

	// get the attributes
	for(TiXmlAttribute* a = pElem->FirstAttribute(); a; a = a->Next())
	{
		std::string name(a->Name());
		if(name == "machine"){new_object->m_machine.assign(Ctt(a->Value()));}
		else if(name == "output_file"){new_object->m_output_file.assign(Ctt(a->Value()));}
		else if(name == "program"){theApp.m_program_canvas->m_textCtrl->SetValue(Ctt(a->Value()));}
	}

	new_object->ReadBaseXML(pElem);
	theApp.m_program = new_object;

	return new_object;
}

void CProgram::RewritePythonProgram()
{
	theApp.m_program_canvas->m_textCtrl->Clear();
	CZigZag::number_for_stl_file = 1;

	bool profile_op_exists = false;
	bool pocket_op_exists = false;
	bool zigzag_op_exists = false;
	for(HeeksObj* object = m_operations->GetFirstChild(); object; object = m_operations->GetNextChild())
	{
		if(object->GetType() == ProfileType)
		{
			profile_op_exists = true;
		}
		else if(object->GetType() == PocketType)
		{
			pocket_op_exists = true;
		}
		else if(object->GetType() == ZigZagType)
		{
			zigzag_op_exists = true;
		}
	}

	// add standard stuff at the top

	// kurve related things
	if(profile_op_exists)
	{
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("import kurve\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("import kurve_funcs\n"));
	}

	// area related things
	if(pocket_op_exists)
	{
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("import area\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("import area_funcs\n"));
	}

	// pycam stuff
	if(zigzag_op_exists)
	{
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("import sys\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("sys.path.insert(0,'PyCam/trunk')\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from pycam.Geometry import *\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from pycam.Cutters.SphericalCutter import *\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from pycam.Cutters.CylindricalCutter import *\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from pycam.Cutters.ToroidalCutter import *\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from pycam.Importers.STLImporter import ImportModel\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from pycam.PathGenerators.DropCutter import DropCutter\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("from PyCamToHeeks import HeeksCNCExporter\n"));
		theApp.m_program_canvas->m_textCtrl->AppendText(_T("\n"));
	}

	// machine general stuff
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("from nc.nc import *\n"));

	// specific machine
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("import ") + m_machine + _T("\n"));
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("\n"));

	// output file
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("output('") + m_output_file + _T("')\n"));

	// begin program
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("program_begin(123, 'Test program')\n"));
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("absolute()\n"));
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("metric()\n"));
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("set_plane(0)\n"));
	theApp.m_program_canvas->m_textCtrl->AppendText(_T("\n"));

	// write the operations
	for(HeeksObj* object = m_operations->GetFirstChild(); object; object = m_operations->GetNextChild())
	{
		switch(object->GetType())
		{
		case ProfileType:
			((CProfile*)object)->AppendTextToProgram();
			break;
		case PocketType:
			((CPocket*)object)->AppendTextToProgram();
			break;
		case ZigZagType:
			((CZigZag*)object)->AppendTextToProgram();
			break;
		}
	}

}

ProgramUserType CProgram::GetUserType()
{
	if(m_nc_code->m_user_edited)return ProgramUserTypeNC;
	if(m_script_edited)return ProgramUserTypeScript;
	if(m_operations->GetFirstChild())return ProgramUserTypeTree;
	return ProgramUserTypeUnkown;
}

void CProgram::UpdateFromUserType()
{
#if 0
	switch(GetUserType())
	{
	case ProgramUserTypeUnkown:

	case tree:
   Enable "Operations" icon in tree
     editing the tree, recreates the python script
   Read only "Program" window
     pressing "Post-process" creates the NC code ( and backplots it )
   Read only "Output" window
   Disable all buttons on "Output" window

	}
#endif
}
<|endoftext|>


<commit_before>/****************************************************************************
 **
 ** Copyright (C) 2013 Jolla Ltd.
 ** Contact: Chris Adams <chris.adams@jollamobile.com>
 **
 ****************************************************************************/

#include "facebooknotificationsyncadaptor.h"
#include "trace.h"

#include <QUrlQuery>
#include <QDebug>

static const int OLD_NOTIFICATION_LIMIT_IN_DAYS = 21;

FacebookNotificationSyncAdaptor::FacebookNotificationSyncAdaptor(QObject *parent)
    : FacebookDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::Notifications, parent)
{
    setInitialActive(true);
}

FacebookNotificationSyncAdaptor::~FacebookNotificationSyncAdaptor()
{
}

QString FacebookNotificationSyncAdaptor::syncServiceName() const
{
    return QStringLiteral("facebook-microblog");
}

void FacebookNotificationSyncAdaptor::purgeDataForOldAccounts(const QList<int> &purgeIds)
{
    if (purgeIds.size()) {
        foreach (int accountIdentifier, purgeIds) {
            m_db.removeNotifications(accountIdentifier);
        }
        m_db.sync();
        m_db.wait();
    }
}

void FacebookNotificationSyncAdaptor::beginSync(int accountId, const QString &accessToken)
{
    requestNotifications(accountId, accessToken);
}

void FacebookNotificationSyncAdaptor::finalize(int accountId)
{
    Q_UNUSED(accountId)
    m_db.purgeOldNotifications(OLD_NOTIFICATION_LIMIT_IN_DAYS);
    m_db.sync();
    m_db.wait();
}

void FacebookNotificationSyncAdaptor::requestNotifications(int accountId, const QString &accessToken, const QString &until, const QString &pagingToken)
{
    // TODO: continuation requests need these two.  if exists, also set limit = 5000.
    // if not set, set "since" to the timestamp value.
    Q_UNUSED(until);
    Q_UNUSED(pagingToken);

    QList<QPair<QString, QString> > queryItems;
    queryItems.append(QPair<QString, QString>(QString(QLatin1String("include_read")), QString(QLatin1String("true"))));
    queryItems.append(QPair<QString, QString>(QString(QLatin1String("access_token")), accessToken));
    queryItems.append(QPair<QString, QString>(QString(QLatin1String("locale")), QLocale::system().name()));
    QUrl url(QLatin1String("https://graph.facebook.com/me/notifications"));
    QUrlQuery query(url);
    query.setQueryItems(queryItems);
    url.setQuery(query);
    QNetworkReply *reply = networkAccessManager->get(QNetworkRequest(url));

    if (reply) {
        reply->setProperty("accountId", accountId);
        reply->setProperty("accessToken", accessToken);
        connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(errorHandler(QNetworkReply::NetworkError)));
        connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrorsHandler(QList<QSslError>)));
        connect(reply, SIGNAL(finished()), this, SLOT(finishedHandler()));

        // we're requesting data.  Increment the semaphore so that we know we're still busy.
        incrementSemaphore(accountId);
        setupReplyTimeout(accountId, reply);
    } else {
        TRACE(SOCIALD_ERROR,
                QString(QLatin1String("error: unable to request notifications from Facebook account with id %1"))
                .arg(accountId));
    }
}

void FacebookNotificationSyncAdaptor::finishedHandler()
{
    QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
    bool isError = reply->property("isError").toBool();
    int accountId = reply->property("accountId").toInt();
    QByteArray replyData = reply->readAll();
    disconnect(reply);
    reply->deleteLater();
    removeReplyTimeout(accountId, reply);

    bool ok = false;
    int sinceSpan = m_accountSyncProfile
                  ? m_accountSyncProfile->key(Buteo::KEY_SYNC_SINCE_DAYS_PAST, QStringLiteral("7")).toInt()
                  : 7;
    QJsonObject parsed = parseJsonObjectReplyData(replyData, &ok);
    if (!isError && ok && parsed.contains(QLatin1String("summary"))) {
        QJsonArray data = parsed.value(QLatin1String("data")).toArray();

        foreach (const QJsonValue &entry, data) {
            QJsonObject object = entry.toObject();
            QDateTime createdTime = QDateTime::fromString(object.value(QLatin1String("created_time")).toString(), Qt::ISODate);
            createdTime.setTimeSpec(Qt::UTC);
            QDateTime updatedTime = QDateTime::fromString(object.value(QLatin1String("updated_time")).toString(), Qt::ISODate);
            updatedTime.setTimeSpec(Qt::UTC);

            if (createdTime.daysTo(QDateTime::currentDateTime()) > sinceSpan
                    && updatedTime.daysTo(QDateTime::currentDateTime()) > sinceSpan) {
                TRACE(SOCIALD_DEBUG,
                        QString(QLatin1String("notification for account %1 is more than %2 days old:\n    %3 - %4 - %5"))
                        .arg(accountId)
                        .arg(sinceSpan)
                        .arg(createdTime.toString(Qt::ISODate))
                        .arg(updatedTime.toString(Qt::ISODate))
                        .arg(object.value(QLatin1String("title")).toString()));
                continue;
            }

            QJsonObject sender = object.value(QLatin1String("from")).toObject();
            QJsonObject receiver = object.value(QLatin1String("to")).toObject();
            QJsonObject application = object.value(QLatin1String("application")).toObject();
            QJsonObject notificationObject = object.value(QLatin1String("object")).toObject();

            m_db.addFacebookNotification(object.value(QLatin1String("id")).toString(),
                                         sender.value(QLatin1String("id")).toString(),
                                         receiver.value(QLatin1String("id")).toString(),
                                         createdTime,
                                         updatedTime,
                                         object.value(QLatin1String("title")).toString(),
                                         object.value(QLatin1String("link")).toString(),
                                         application.value(QLatin1String("id")).toString(),
                                         notificationObject.value(QLatin1String("id")).toString(),
                                         object.value(QLatin1String("unread")).toDouble() != 0,
                                         accountId,
                                         clientId());
        }
    } else {
        // error occurred during request.
        TRACE(SOCIALD_ERROR,
                QString(QLatin1String("error: unable to parse notification data from request with account %1; got: %2"))
                .arg(accountId).arg(QString::fromLatin1(replyData.constData())));
    }

    // we're finished this request.  Decrement our busy semaphore.
    decrementSemaphore(accountId);
}
<commit_msg>[sociald] Ignore result pagination in FB Notif sync.<commit_after>/****************************************************************************
 **
 ** Copyright (C) 2013 Jolla Ltd.
 ** Contact: Chris Adams <chris.adams@jollamobile.com>
 **
 ****************************************************************************/

#include "facebooknotificationsyncadaptor.h"
#include "trace.h"

#include <QUrlQuery>
#include <QDebug>

static const int OLD_NOTIFICATION_LIMIT_IN_DAYS = 21;
static const int NOTIFICATIONS_LIMIT = 30;

FacebookNotificationSyncAdaptor::FacebookNotificationSyncAdaptor(QObject *parent)
    : FacebookDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::Notifications, parent)
{
    setInitialActive(true);
}

FacebookNotificationSyncAdaptor::~FacebookNotificationSyncAdaptor()
{
}

QString FacebookNotificationSyncAdaptor::syncServiceName() const
{
    return QStringLiteral("facebook-microblog");
}

void FacebookNotificationSyncAdaptor::purgeDataForOldAccounts(const QList<int> &purgeIds)
{
    if (purgeIds.size()) {
        foreach (int accountIdentifier, purgeIds) {
            m_db.removeNotifications(accountIdentifier);
        }
        m_db.sync();
        m_db.wait();
    }
}

void FacebookNotificationSyncAdaptor::beginSync(int accountId, const QString &accessToken)
{
    requestNotifications(accountId, accessToken);
}

void FacebookNotificationSyncAdaptor::finalize(int accountId)
{
    Q_UNUSED(accountId)
    m_db.purgeOldNotifications(OLD_NOTIFICATION_LIMIT_IN_DAYS);
    m_db.sync();
    m_db.wait();
}

void FacebookNotificationSyncAdaptor::requestNotifications(int accountId, const QString &accessToken, const QString &until, const QString &pagingToken)
{
    // continuation requests require until+paging token.
    // if not set, set "since" to the timestamp value.

    QList<QPair<QString, QString> > queryItems;
    queryItems.append(QPair<QString, QString>(QString(QLatin1String("include_read")), QString(QLatin1String("true"))));
    queryItems.append(QPair<QString, QString>(QString(QLatin1String("access_token")), accessToken));
    queryItems.append(QPair<QString, QString>(QString(QLatin1String("locale")), QLocale::system().name()));
    QUrl url(QLatin1String("https://graph.facebook.com/me/notifications"));
    if (pagingToken.isEmpty()) {
        int sinceSpan = m_accountSyncProfile
                      ? m_accountSyncProfile->key(Buteo::KEY_SYNC_SINCE_DAYS_PAST, QStringLiteral("7")).toInt()
                      : 7;
        queryItems.append(QPair<QString, QString>(QString(QLatin1String("since")),
                          QString::number(QDateTime::currentDateTime().addDays(-1 * sinceSpan).toTime_t())));
        queryItems.append(QPair<QString, QString>(QString(QLatin1String("limit")), QString::number(NOTIFICATIONS_LIMIT)));
    } else {
        queryItems.append(QPair<QString, QString>(QString(QLatin1String("limit")), QString::number(NOTIFICATIONS_LIMIT)));
        queryItems.append(QPair<QString, QString>(QString(QLatin1String("until")), until));
        queryItems.append(QPair<QString, QString>(QString(QLatin1String("__paging_token")), pagingToken));
    }

    QUrlQuery query(url);
    query.setQueryItems(queryItems);
    url.setQuery(query);
    QNetworkReply *reply = networkAccessManager->get(QNetworkRequest(url));

    if (reply) {
        reply->setProperty("accountId", accountId);
        reply->setProperty("accessToken", accessToken);
        connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(errorHandler(QNetworkReply::NetworkError)));
        connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrorsHandler(QList<QSslError>)));
        connect(reply, SIGNAL(finished()), this, SLOT(finishedHandler()));

        // we're requesting data.  Increment the semaphore so that we know we're still busy.
        incrementSemaphore(accountId);
        setupReplyTimeout(accountId, reply);
    } else {
        TRACE(SOCIALD_ERROR,
                QString(QLatin1String("error: unable to request notifications from Facebook account with id %1"))
                .arg(accountId));
    }
}

void FacebookNotificationSyncAdaptor::finishedHandler()
{
    QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
    bool isError = reply->property("isError").toBool();
    int accountId = reply->property("accountId").toInt();
    QString accessToken = reply->property("accessToken").toString();
    QByteArray replyData = reply->readAll();
    disconnect(reply);
    reply->deleteLater();
    removeReplyTimeout(accountId, reply);

    bool ok = false;
    int sinceSpan = m_accountSyncProfile
                  ? m_accountSyncProfile->key(Buteo::KEY_SYNC_SINCE_DAYS_PAST, QStringLiteral("7")).toInt()
                  : 7;
    QJsonObject parsed = parseJsonObjectReplyData(replyData, &ok);
    if (!isError && ok && parsed.contains(QLatin1String("summary"))) {
        QJsonArray data = parsed.value(QLatin1String("data")).toArray();

        bool needNextPage = false;
        bool seenOldNotification = false;
        foreach (const QJsonValue &entry, data) {
            QJsonObject object = entry.toObject();
            QDateTime createdTime = QDateTime::fromString(object.value(QLatin1String("created_time")).toString(), Qt::ISODate);
            createdTime.setTimeSpec(Qt::UTC);
            QDateTime updatedTime = QDateTime::fromString(object.value(QLatin1String("updated_time")).toString(), Qt::ISODate);
            updatedTime.setTimeSpec(Qt::UTC);

            if (createdTime.daysTo(QDateTime::currentDateTime()) > sinceSpan
                    && updatedTime.daysTo(QDateTime::currentDateTime()) > sinceSpan) {
                TRACE(SOCIALD_DEBUG,
                        QString(QLatin1String("notification for account %1 is more than %2 days old:\n    %3 - %4 - %5"))
                        .arg(accountId)
                        .arg(sinceSpan)
                        .arg(createdTime.toString(Qt::ISODate))
                        .arg(updatedTime.toString(Qt::ISODate))
                        .arg(object.value(QLatin1String("title")).toString()));
                seenOldNotification = true;
                needNextPage = false;
                continue;
            }

            QJsonObject sender = object.value(QLatin1String("from")).toObject();
            QJsonObject receiver = object.value(QLatin1String("to")).toObject();
            QJsonObject application = object.value(QLatin1String("application")).toObject();
            QJsonObject notificationObject = object.value(QLatin1String("object")).toObject();

            m_db.addFacebookNotification(object.value(QLatin1String("id")).toString(),
                                         sender.value(QLatin1String("id")).toString(),
                                         receiver.value(QLatin1String("id")).toString(),
                                         createdTime,
                                         updatedTime,
                                         object.value(QLatin1String("title")).toString(),
                                         object.value(QLatin1String("link")).toString(),
                                         application.value(QLatin1String("id")).toString(),
                                         notificationObject.value(QLatin1String("id")).toString(),
                                         object.value(QLatin1String("unread")).toDouble() != 0,
                                         accountId,
                                         clientId());

            if (!seenOldNotification) {
                needNextPage = true;
            }
        }

        if (needNextPage && parsed.contains(QLatin1String("paging"))) {
            // we don't actually request the next page of results
            // since the sync schedule has such a small interval,
            // 30 notifications at a time should be plenty,
            // and we want to avoid performing spurious network activity.
            Q_UNUSED(accessToken)
            /*
            QString nextPage = parsed.value(QLatin1String("paging")).toObject().value(QLatin1String("next")).toString();
            QUrl nextPageUrl(nextPage);

            // instead of doing this, we could just pass the nextPageUrl directly to the requestNotifications function
            QUrlQuery npuQuery(nextPageUrl.query());
            QString until = npuQuery.queryItemValue(QStringLiteral("until"));
            QString pagingToken = npuQuery.queryItemValue(QStringLiteral("__paging_token"));

            if (!nextPage.isEmpty() && !until.isEmpty() && !pagingToken.isEmpty()) {
                TRACE(SOCIALD_DEBUG,
                        QString(QLatin1String("another page of notifications exists for account %1: %2"))
                        .arg(accountId).arg(nextPage));
                requestNotifications(accountId, accessToken, until, pagingToken);
            }
            */
        }
    } else {
        // error occurred during request.
        TRACE(SOCIALD_ERROR,
                QString(QLatin1String("error: unable to parse notification data from request with account %1; got: %2"))
                .arg(accountId).arg(QString::fromLatin1(replyData.constData())));
    }

    // we're finished this request.  Decrement our busy semaphore.
    decrementSemaphore(accountId);
}
<|endoftext|>


<commit_before>#ifndef SAPLIST_HPP
#define SAPLIST_HPP 1

#include <functional>
#include <map>
#include <typeinfo>
#include <climits>
#include <iostream>
#include "CollisionManager.hpp"

class ActionManager;
class Collisionable;
class SAPList;

class Collisionable {

protected:
    /* (void *) because AABB type is hidden */
    void * boundingBox;

public:
    /**
     * @return a pointer to Collisionable's bouding box (it needs cast).
     */
    void * getBoundingBox() { return boundingBox; }

    /**
     * Change the boundingBox of a Collisionable
     * @param b new bounding box
     */
    void setBoundingBox(void * b) { boundingBox = b; }

    /** @return the smallest value of a Collisionable on X axis */
    virtual int getXMin() = 0;

    /** @return the smallest value of a Collisionable on Y axis */
    virtual int getYMin() = 0;

    /** @return the greatest value of a Collisionable on X axis */
    virtual int getXMax() = 0;

    /** @return the greatest value of a Collisionable on Y axis */
    virtual int getYMax() = 0;

    virtual ~Collisionable() {};
};

class ActionManager {

public:
    /**
     * Function to call on collision
     * @param o1 first object which collide
     * @param o2 second object which collide
     */
    virtual void onCollision(Collisionable * o1, Collisionable * o2) = 0;

    /**
     * @param o1 first object which do not collide
     * @param o2 second object which do not collide
     */
    virtual void onSeparation(Collisionable * o1, Collisionable * o2) = 0;

    virtual ~ActionManager() {};

};

class SAPList : virtual public CollisionManager<Collisionable> {

private:

    /* BEGIN: private classes for SAPList collision manager */

    class AABB;

    class EndPoint {

        /**
         * TODO:
         * - Optimize merging isMin boolean into another member
         *   (as a flag)
         * - Using doubly-linked list could waste memory but is easier to
         *   implement than arrays.
         */

    public:

        AABB * owner;
        /** Value used to sort EndPoint list */
        int value;

        /** Flag to indicate if this EndPoint is minimum of a AABB or not */
        bool isMin;

        /** Previous EndPoint in the list */
        EndPoint * prev;

        /** Next EndPoint in the list */
        EndPoint * next;

        EndPoint (AABB* o,int v,bool m,EndPoint* p=NULL,EndPoint* n=NULL) :
            owner(o), value(v), isMin(m), prev(p), next(n) {}

        /** When and EndPoint is destroyed, it updates prev and next */
        ~EndPoint () {
            if (this->prev != NULL) {
                this->prev->next = this->next;
            }
            if (this->next != NULL)
                this->next->prev = this->prev;
        }
    };

    class AABB {

    public:

        /** First minimum EndPoint is on x axis, second one is on y */
        EndPoint * min[2];

        /** Second minimum EndPoint is on x axis, second one is on y */
        EndPoint * max[2];

        /** Object the box is attached to */
        Collisionable * owner;

        /**
         * Create the AABB corresponding to a collisionable object
         * @param c the object used to create the corresponding AABB
         */
        AABB(Collisionable * c) : owner(c) {
            min[0] = new EndPoint(this, c->getXMin(), true);
            min[1] = new EndPoint(this, c->getYMin(), true);
            max[0] = new EndPoint(this, c->getXMax(), false);
            max[1] = new EndPoint(this, c->getYMax(), false);
            c->setBoundingBox(this);
        }

        ~AABB ()
        { delete min[0]; delete min[1]; delete max[0]; delete max[1]; }

        /**
         * Update EndPoints values according to information provided by
         * owner and Collisionable API
         */
        void updateEPValues() {
            min[0]->value = owner->getXMin();
            min[1]->value = owner->getYMin();
            max[0]->value = owner->getXMax();
            max[1]->value = owner->getYMax();
        }

    };

    /* END: private classes for SAPList collision manager */

private:

    /** First EndPoint on xAxis (not a real point, but a sentinel)*/
    EndPoint * xAxis;

    /** Second EndPoint on xAxis (not a real point, but a sentinel)*/
    EndPoint * yAxis;

    /** Action manager used on collision/separation */
    ActionManager * actionManager;

    /** Swap two EndPoint.
     * **p2 has to be the direct next EndPoint after p1**
     * @param p1 first EndPoint
     * @param p2 second EndPoint
     */
    void swap(EndPoint * p1, EndPoint * p2) {
        if (p2->next != NULL) p2->next->prev = p1;
        if (p1->prev != NULL) p1->prev->next = p2;
        p1->next = p2->next;
        p2->next = p1;
        p2->prev = p1->prev;
        p1->prev = p2;
    }

    /**
     * A collision between two AABB on one axis
     * no collision on equality (>/<)
     */
    inline bool partialCollisionCheck(const AABB & a,
                                      const AABB & b,
                                      int dim) {
        return !(a.min[dim]->value > b.max[dim]->value
                 || a.max[dim]->value < b.min[dim]->value);
    }

    /**
     * Check if two AABB collide using 2 axises
     * @see partialCollisionCheck
     */
    bool collisionCheck(const AABB & b1, const AABB & b2) {
        return partialCollisionCheck (b1, b2, 0)
            && partialCollisionCheck (b1, b2, 1);
    }

    /** Update EndPoint place and call the appropriate function in case
     * of collision/separation. Does not affect the EndPoint.value, which must
     * be updated before calling updateEndPoint.
     * @param pt the EndPoint to update
     */
    void updateAxis(EndPoint * min, EndPoint * max) {

        auto update =
            [this]
            (EndPoint * pt,
             std::function<EndPoint*(EndPoint*)>succ,
             std::function<bool(EndPoint*pt,EndPoint*succ)>loop_cond,
             std::function<void(EndPoint*pt,EndPoint*succ)>swap_fun,
             std::function<bool(EndPoint*pt,EndPoint*succ)>doCollide,
             std::function<bool(EndPoint*pt,EndPoint*succ)>doSeparate) {

            EndPoint * tmp = succ(pt);
            if (!loop_cond(pt, tmp))
                { return false; }

            do {
                swap_fun(pt, tmp);

                if (doCollide(pt, tmp)) {
                    if (this->collisionCheck(*(pt->owner), *(tmp->owner))) {
                        this->actionManager->onCollision(pt->owner->owner,
                                                         tmp->owner->owner);
                    }
                } else if (doSeparate(pt, tmp)) {
                    this->actionManager->onSeparation(pt->owner->owner,
                                                      tmp->owner->owner);
                }

                tmp = succ(pt);
            } while (loop_cond(pt, tmp));

            return true;
        };

        /* No collision detected on equality (<=/>=). */

        auto prev = [](EndPoint *p)
            { return p->prev;};
        auto prev_cond = [](EndPoint * pt, EndPoint * succ)
            { return pt->value < succ->value; };
        auto prev_swap = [this](EndPoint * pt, EndPoint * succ)
            { swap(succ, pt); };
        auto prev_col = [](EndPoint *pt, EndPoint *succ)
            { return pt->isMin && !succ->isMin; };
        auto prev_sep = [](EndPoint *pt, EndPoint *succ)
            { return !pt->isMin && succ->isMin; };

        auto next = [](EndPoint *p)
            { return p->next; };
        auto next_cond = [](EndPoint * pt, EndPoint * succ)
            { return pt->value > succ->value; };
        auto next_swap = [this](EndPoint * pt, EndPoint * succ)
            { swap(pt, succ); };
        auto next_col = [](EndPoint *pt, EndPoint *succ)
            { return !pt->isMin && succ->isMin; };
        auto next_sep = [](EndPoint *pt, EndPoint *succ)
            { return pt->isMin && !succ->isMin; };

        /* BINOR force update and allow to use a boolean test */
        if(!(update(max, next, next_cond, next_swap, next_col, next_sep) |
             update(min, next, next_cond, next_swap, next_col, next_sep))) {
               update(min, prev, prev_cond, prev_swap, prev_col, prev_sep);
               update(max, prev, prev_cond, prev_swap, prev_col, prev_sep);
           }

    }

public:

    SAPList (ActionManager * am) {
        this->actionManager = am;
        /* not sure about the true/false values */
        xAxis = new EndPoint(NULL, INT_MIN, true, NULL, NULL);
        xAxis->next = new EndPoint(NULL, INT_MAX, false, xAxis, NULL);
        yAxis = new EndPoint(NULL, INT_MIN, true, NULL, NULL);
        yAxis->next = new EndPoint(NULL, INT_MAX, false, yAxis, NULL);
    }

    ~SAPList () {

        /* delete all AABB will delete EndPoints */
        while (xAxis->next != NULL && xAxis->next->owner != NULL) {
            delete xAxis->next->owner;
        }
        /* delete all sentinels */
        delete xAxis->next;
        delete xAxis;
        delete yAxis->next;
        delete yAxis;
    }

    /**
     * Create a bounding box attached to a Collisionable and insert its
     * points in xAxis and yAxis (keep it sorted)
     * @param c Object (Collisionable) attached to the new bounding box
     *          to insert in the list
     */
    void addObject(Collisionable * c) {

        AABB * aabb = new AABB(c);

        aabb->min[0]->next = aabb->max[0];
        aabb->max[0]->prev = aabb->min[0];
        aabb->min[0]->prev = xAxis;
        aabb->max[0]->next = xAxis->next;
        xAxis->next->prev = aabb->max[0];
        xAxis->next = aabb->min[0];

        aabb->min[1]->next = aabb->max[1];
        aabb->max[1]->prev = aabb->min[1];
        aabb->min[1]->prev = yAxis;
        aabb->max[1]->next = yAxis->next;
        yAxis->next->prev = aabb->max[1];
        yAxis->next = aabb->min[1];

        updateObject(c);
    }

    /**
     * Update Collisionable's EndPoints position in CollisionManger. Detect
     * collisions and separation and act according to actionManager. Should
     * be called as soon as an object moves.
     * @param c Object to update
     */
    void updateObject(Collisionable * c) {
        AABB * aabb = static_cast<AABB *>(c->getBoundingBox());
        updateAxis(aabb->min[0], aabb->max[0]);
        updateAxis(aabb->min[1], aabb->max[1]);
    }

    void removeObject(Collisionable * c) {
        delete static_cast<AABB *>(c->getBoundingBox());
    }
};

#endif
<commit_msg>AABB's owner **SHOULD** be set to NULL when AABB is destroyed. doc++<commit_after>#ifndef SAPLIST_HPP
#define SAPLIST_HPP 1

#include <functional>
#include <map>
#include <typeinfo>
#include <climits>
#include <iostream>
#include "CollisionManager.hpp"

class ActionManager;
class Collisionable;
class SAPList;

class Collisionable {

protected:
    /* (void *) because AABB type is hidden */
    void * boundingBox;

public:
    /**
     * @return a pointer to Collisionable's bouding box (it needs cast).
     */
    void * getBoundingBox() { return boundingBox; }

    /**
     * Change the boundingBox of a Collisionable
     * @param b new bounding box
     */
    void setBoundingBox(void * b) { boundingBox = b; }

    /** @return the smallest value of a Collisionable on X axis */
    virtual int getXMin() = 0;

    /** @return the smallest value of a Collisionable on Y axis */
    virtual int getYMin() = 0;

    /** @return the greatest value of a Collisionable on X axis */
    virtual int getXMax() = 0;

    /** @return the greatest value of a Collisionable on Y axis */
    virtual int getYMax() = 0;

    virtual ~Collisionable() {};
};

class ActionManager {

public:
    /**
     * Function to call on collision
     * @param o1 first object which collide
     * @param o2 second object which collide
     */
    virtual void onCollision(Collisionable * o1, Collisionable * o2) = 0;

    /**
     * @param o1 first object which do not collide
     * @param o2 second object which do not collide
     */
    virtual void onSeparation(Collisionable * o1, Collisionable * o2) = 0;

    virtual ~ActionManager() {};

};

class SAPList : virtual public CollisionManager<Collisionable> {

private:

    /* BEGIN: private classes for SAPList collision manager */

    class AABB;

    class EndPoint {

        /**
         * TODO:
         * - Optimize merging isMin boolean into another member
         *   (as a flag)
         * - Using doubly-linked list could waste memory but is easier to
         *   implement than arrays.
         */

    public:

        AABB * owner;
        /** Value used to sort EndPoint list */
        int value;

        /** Flag to indicate if this EndPoint is minimum of a AABB or not */
        bool isMin;

        /** Previous EndPoint in the list */
        EndPoint * prev;

        /** Next EndPoint in the list */
        EndPoint * next;

        EndPoint (AABB* o,int v,bool m,EndPoint* p=NULL,EndPoint* n=NULL) :
            owner(o), value(v), isMin(m), prev(p), next(n) {}

        /** When and EndPoint is destroyed, it updates prev and next */
        ~EndPoint () {
            if (this->prev != NULL) {
                this->prev->next = this->next;
            }
            if (this->next != NULL) {
                this->next->prev = this->prev;
            }
        }
    };

    class AABB {

    public:

        /** First minimum EndPoint is on x axis, second one is on y */
        EndPoint * min[2];

        /** Second minimum EndPoint is on x axis, second one is on y */
        EndPoint * max[2];

        /** Object the box is attached to */
        Collisionable * owner;

        /**
         * Create the AABB corresponding to a collisionable object
         * @param c the object used to create the corresponding AABB
         */
        AABB(Collisionable * c) : owner(c) {
            min[0] = new EndPoint(this, c->getXMin(), true);
            min[1] = new EndPoint(this, c->getYMin(), true);
            max[0] = new EndPoint(this, c->getXMax(), false);
            max[1] = new EndPoint(this, c->getYMax(), false);
            c->setBoundingBox(this);
        }

        /**
         * When a AABB is destroyed, its owner bounding box is set to NULL
         */
        ~AABB () {
            delete min[0];
            delete min[1];
            delete max[0];
            delete max[1];
            if (owner) {
                //   owner->setBoundingBox(NULL); <- segfault in unit tests.
            }
        }

        /**
         * Update EndPoints values according to information provided by
         * owner and Collisionable API
         */
        void updateEPValues() {
            min[0]->value = owner->getXMin();
            min[1]->value = owner->getYMin();
            max[0]->value = owner->getXMax();
            max[1]->value = owner->getYMax();
        }

    };

    /* END: private classes for SAPList collision manager */

private:

    /** First EndPoint on xAxis (not a real point, but a sentinel)*/
    EndPoint * xAxis;

    /** Second EndPoint on xAxis (not a real point, but a sentinel)*/
    EndPoint * yAxis;

    /** Action manager used on collision/separation */
    ActionManager * actionManager;

    /** Swap two EndPoint.
     * **p2 has to be the direct next EndPoint after p1**
     * @param p1 first EndPoint
     * @param p2 second EndPoint
     */
    void swap(EndPoint * p1, EndPoint * p2) {
        if (p2->next != NULL) p2->next->prev = p1;
        if (p1->prev != NULL) p1->prev->next = p2;
        p1->next = p2->next;
        p2->next = p1;
        p2->prev = p1->prev;
        p1->prev = p2;
    }

    /**
     * A collision between two AABB on one axis
     * no collision on equality (>/<)
     */
    inline bool partialCollisionCheck(const AABB & a,
                                      const AABB & b,
                                      int dim) {
        return !(a.min[dim]->value > b.max[dim]->value
                 || a.max[dim]->value < b.min[dim]->value);
    }

    /**
     * Check if two AABB collide using 2 axises
     * @see partialCollisionCheck
     */
    bool collisionCheck(const AABB & b1, const AABB & b2) {
        return partialCollisionCheck (b1, b2, 0)
            && partialCollisionCheck (b1, b2, 1);
    }

    /** Update EndPoint place and call the appropriate function in case
     * of collision/separation. Does not affect the EndPoint.value, which must
     * be updated before calling updateEndPoint.
     * @param pt the EndPoint to update
     */
    void updateAxis(EndPoint * min, EndPoint * max) {

        auto update =
            [this]
            (EndPoint * pt,
             std::function<EndPoint*(EndPoint*)>succ,
             std::function<bool(EndPoint*pt,EndPoint*succ)>loop_cond,
             std::function<void(EndPoint*pt,EndPoint*succ)>swap_fun,
             std::function<bool(EndPoint*pt,EndPoint*succ)>doCollide,
             std::function<bool(EndPoint*pt,EndPoint*succ)>doSeparate) {

            EndPoint * tmp = succ(pt);
            if (!loop_cond(pt, tmp))
                { return false; }

            do {
                swap_fun(pt, tmp);

                if (doCollide(pt, tmp)) {
                    if (this->collisionCheck(*(pt->owner), *(tmp->owner))) {
                        this->actionManager->onCollision(pt->owner->owner,
                                                         tmp->owner->owner);
                    }
                } else if (doSeparate(pt, tmp)) {
                    this->actionManager->onSeparation(pt->owner->owner,
                                                      tmp->owner->owner);
                }

                tmp = succ(pt);
            } while (loop_cond(pt, tmp));

            return true;
        };

        /* No collision detected on equality (<=/>=). */

        auto prev = [](EndPoint *p)
            { return p->prev;};
        auto prev_cond = [](EndPoint * pt, EndPoint * succ)
            { return pt->value < succ->value; };
        auto prev_swap = [this](EndPoint * pt, EndPoint * succ)
            { swap(succ, pt); };
        auto prev_col = [](EndPoint *pt, EndPoint *succ)
            { return pt->isMin && !succ->isMin; };
        auto prev_sep = [](EndPoint *pt, EndPoint *succ)
            { return !pt->isMin && succ->isMin; };

        auto next = [](EndPoint *p)
            { return p->next; };
        auto next_cond = [](EndPoint * pt, EndPoint * succ)
            { return pt->value > succ->value; };
        auto next_swap = [this](EndPoint * pt, EndPoint * succ)
            { swap(pt, succ); };
        auto next_col = [](EndPoint *pt, EndPoint *succ)
            { return !pt->isMin && succ->isMin; };
        auto next_sep = [](EndPoint *pt, EndPoint *succ)
            { return pt->isMin && !succ->isMin; };

        /* BINOR force update and allow to use a boolean test */
        if(!(update(max, next, next_cond, next_swap, next_col, next_sep) |
             update(min, next, next_cond, next_swap, next_col, next_sep))) {
               update(min, prev, prev_cond, prev_swap, prev_col, prev_sep);
               update(max, prev, prev_cond, prev_swap, prev_col, prev_sep);
           }

    }

public:

    SAPList (ActionManager * am) {
        this->actionManager = am;
        /* not sure about the true/false values */
        xAxis = new EndPoint(NULL, INT_MIN, true, NULL, NULL);
        xAxis->next = new EndPoint(NULL, INT_MAX, false, xAxis, NULL);
        yAxis = new EndPoint(NULL, INT_MIN, true, NULL, NULL);
        yAxis->next = new EndPoint(NULL, INT_MAX, false, yAxis, NULL);
    }

    ~SAPList () {

        /* delete all AABB will delete EndPoints */
        while (xAxis->next != NULL && xAxis->next->owner != NULL) {
            delete xAxis->next->owner;
        }
        /* delete all sentinels */
        delete xAxis->next;
        delete xAxis;
        delete yAxis->next;
        delete yAxis;
    }

    /**
     * Create a bounding box attached to a Collisionable and insert its
     * points in xAxis and yAxis (keep it sorted)
     * @param c Object (Collisionable) attached to the new bounding box
     *          to insert in the list
     */
    void addObject(Collisionable * c) {

        AABB * aabb = new AABB(c);

        aabb->min[0]->next = aabb->max[0];
        aabb->max[0]->prev = aabb->min[0];
        aabb->min[0]->prev = xAxis;
        aabb->max[0]->next = xAxis->next;
        xAxis->next->prev = aabb->max[0];
        xAxis->next = aabb->min[0];

        aabb->min[1]->next = aabb->max[1];
        aabb->max[1]->prev = aabb->min[1];
        aabb->min[1]->prev = yAxis;
        aabb->max[1]->next = yAxis->next;
        yAxis->next->prev = aabb->max[1];
        yAxis->next = aabb->min[1];

        updateObject(c);
    }

    /**
     * Update Collisionable's EndPoints position in CollisionManger. Detect
     * collisions and separation and act according to actionManager. Should
     * be called as soon as an object moves.
     * @param c Object to update
     */
    void updateObject(Collisionable * c) {
        AABB * aabb = static_cast<AABB *>(c->getBoundingBox());
        updateAxis(aabb->min[0], aabb->max[0]);
        updateAxis(aabb->min[1], aabb->max[1]);
    }

    /**
     * Remove a bounding box attached to a Collisionable
     * @param c Object attached to the bounding box to remove
     */
    void removeObject(Collisionable * c) {
        delete static_cast<AABB *>(c->getBoundingBox());
    }
};

#endif
<|endoftext|>